Last active
August 24, 2022 16:49
-
-
Save blrB/609ee93015008f6dde9a1c7593f58ff8 to your computer and use it in GitHub Desktop.
Downloader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <sys/socket.h> | |
#include <sys/types.h> | |
#include <netinet/in.h> | |
#include <netdb.h> | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <errno.h> | |
#include <string.h> | |
#include <errno.h> | |
#include <arpa/inet.h> | |
#include <pthread.h> | |
#include <time.h> | |
struct readThreadParams { | |
char *domain; | |
char *path; | |
}; | |
struct readThreadIdtfParams { | |
char *file_name; | |
double *progress; | |
}; | |
void download_from_input(); | |
void download_from_file(char *file_name); | |
int read_http_status(int sock); | |
int parse_header(int sock); | |
void *download(void *context); | |
int download_by_url(char *url); | |
void *printf_indicator(void *arg); | |
int main(int argc , char *argv[]){ | |
if (argc == 1) { | |
download_from_input(); | |
} else if (argc == 2) { | |
download_from_file(strdup(argv[1])); | |
} else { | |
printf("Not correct argument\n"); | |
exit(1); | |
} | |
pthread_exit(0); | |
} | |
void download_from_input(char *file_name){ | |
char *exit_string = "n"; | |
char url[256]; | |
do{ | |
printf("Input url image for download or \"n\" for exit\n"); | |
scanf("%s", url); | |
if (strcmp(url, exit_string) == 0){ | |
break; | |
} | |
download_by_url(url); | |
} while (true); | |
} | |
void download_from_file(char *file_name){ | |
FILE* fp; | |
char buf[256]; | |
if((fp = fopen(file_name, "r")) == NULL) { | |
printf("Error opening test file - download.txt\n"); | |
return -1; | |
} | |
while(fgets(buf, sizeof(buf), fp) != NULL) { | |
download_by_url(buf); | |
} | |
} | |
int download_by_url(char *url){ | |
char domain[64]; | |
char page[192]; | |
if (strstr(url, "https")){ | |
sscanf(url, "https://%99[^/]/%99[^\n]", domain, page); | |
} else if(strstr(url, "http")){ | |
sscanf(url, "http://%99[^/]/%99[^\n]", domain, page); | |
} else { | |
printf("It is support only http/https url"); | |
return 1; | |
} | |
struct readThreadParams *readParams; | |
readParams = malloc(sizeof(readParams)); | |
readParams->domain = strdup(domain); | |
readParams->path = strdup(page); | |
pthread_t download_thread; | |
if( pthread_create( &download_thread , NULL , &download , (void*)readParams) < 0){ | |
perror("could not create thread"); | |
return -1; | |
} | |
pthread_detach(download_thread); | |
} | |
int read_http_status(int sock){ | |
char buff[1024] = ""; | |
char *ptr = buff; | |
int bytes_received, status; | |
while(bytes_received = recv(sock, ptr, 1, 0)){ | |
if(bytes_received==-1){ | |
perror("ReadHttpStatus"); | |
exit(1); | |
} | |
if((ptr[-1]=='\r') && (*ptr=='\n' )){ | |
break; | |
} | |
ptr++; | |
} | |
*ptr = 0; | |
ptr = buff; | |
sscanf(ptr,"%*s %d ", &status); | |
return (bytes_received > 0) ? status : 0; | |
} | |
int parse_header(int sock){ | |
char buff[1024] = ""; | |
char *ptr=buff; | |
int bytes_received; | |
while(bytes_received = recv(sock, ptr, 1, 0)){ | |
if(bytes_received==-1){ | |
perror("Parse Header"); | |
exit(1); | |
} | |
if((ptr[-3]=='\r') && (ptr[-2]=='\n' ) && (ptr[-1]=='\r') && (*ptr=='\n' )) break; | |
ptr++; | |
} | |
*ptr = 0; | |
ptr = buff; | |
if (bytes_received){ | |
ptr = strstr(ptr,"Content-Length:"); | |
if (ptr){ | |
sscanf(ptr,"%*s %d",&bytes_received); | |
} else { | |
bytes_received=-1; //unknown size | |
} | |
} | |
return bytes_received ; | |
} | |
void *printf_indicator(void *arg){ | |
struct readThreadIdtfParams *readParams = (struct readThreadIdtfParams *)arg; | |
char *file_name = readParams->file_name; | |
double *progress = readParams->progress; | |
while(*progress < 1){ | |
sleep(1); | |
int percent = *progress * 100.0; | |
printf("[ %i% ] - %s\n", percent, file_name); | |
} | |
return 0; | |
} | |
void *download(void *context) { | |
struct readThreadParams *readParams = (struct readThreadParams *)context; | |
char *domain = readParams->domain; | |
char *path = readParams->path; | |
char *file; | |
file = strrchr(path,'/'); | |
file++; | |
int sock, bytes_received; | |
char send_data[1024],recv_data[1024]; | |
struct sockaddr_in server_addr; | |
struct hostent *host; | |
host = gethostbyname(domain); | |
if (host == NULL){ | |
herror("gethostbyname"); | |
exit(1); | |
} | |
if ((sock = socket(AF_INET, SOCK_STREAM, 0))== -1){ | |
perror("Socket"); | |
exit(1); | |
} | |
server_addr.sin_family = AF_INET; | |
server_addr.sin_port = htons(80); | |
server_addr.sin_addr = *((struct in_addr *)host->h_addr); | |
bzero(&(server_addr.sin_zero),8); | |
if (connect(sock, (struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1){ | |
perror("Connect"); | |
exit(1); | |
} | |
snprintf(send_data, sizeof(send_data), "GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n", path, domain); | |
if(send(sock, send_data, strlen(send_data), 0)==-1){ | |
perror("send"); | |
exit(2); | |
} | |
int contentlengh; | |
int status = read_http_status(sock); | |
contentlengh = parse_header(sock); | |
if(status == 200 && contentlengh > 0){ | |
double percent = 0; | |
double *progress = &percent; | |
int bytes=0; | |
char file_name[256]; | |
struct tm *t; | |
time_t now = time(NULL); | |
t = gmtime(&now); | |
strftime(file_name, sizeof(file_name), "%Y-%m-%d_%H:%M:%S_", t); | |
strcat(file_name, file); | |
FILE* fd=fopen(file_name,"wb"); | |
struct readThreadIdtfParams *readParamsIdtf; | |
readParamsIdtf = malloc(sizeof(readParamsIdtf)); | |
readParamsIdtf->file_name = strdup(file_name); | |
readParamsIdtf->progress = progress; | |
pthread_t indicator; | |
pthread_create(&indicator, NULL, &printf_indicator, (void*)readParamsIdtf); | |
while(bytes_received = recv(sock, recv_data, 1024, 0)){ | |
if(bytes_received==-1){ | |
perror("recieve"); | |
exit(3); | |
} | |
fwrite(recv_data,1,bytes_received,fd); | |
bytes+=bytes_received; | |
percent = 1.0 * bytes/contentlengh; | |
if(bytes==contentlengh){ | |
break; | |
} | |
} | |
printf("[ %i% ] - %s\n", 100, file_name); | |
pthread_cancel(indicator); | |
free(readParamsIdtf); | |
} else { | |
printf ("Status: %i\nContent-Length: %i\n", status, contentlengh); | |
} | |
free(readParams); | |
close(sock); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment