Skip to content

Instantly share code, notes, and snippets.

@blrB
Last active August 24, 2022 16:49
Show Gist options
  • Save blrB/609ee93015008f6dde9a1c7593f58ff8 to your computer and use it in GitHub Desktop.
Save blrB/609ee93015008f6dde9a1c7593f58ff8 to your computer and use it in GitHub Desktop.
Downloader
#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