//--------------------------------------------------------------------------------------------------------------
// MICHAL SCHORM - xschor02@stud.fit.vutbr.cz
// IPK - 2. projekt - klient
// Klient server přenos souborů
//--------------------------------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <limits.h>
#include <netdb.h>
#include <arpa/inet.h> //inet_addr
//--------------------------------------------------------------------------------------------------------------
// MAKRA A HLAVIČKY FCÍ
#define DEBUG 1 // 1=true, 0=false
#define DEBUG_DATA 0
#define ASCII_0 48
#define CHYBA_ARGC -1
#define CHYBA_SOCKET -2
#define CHYBA_CONNECT -3
#define CHYBA_SEND -4
#define CHYBA_RECEIVE -5
#define CHYBA_GETHOSTBYNAME -6
#define SERVER_ERR -7
#define CHYBA_ARGV -8
#define CHYBA_BAD_HEAD -9
#define CHYBA_UNKNOWN_DEMAND -10
#define CHYBA_NO_FILE -11
#define CHYBA_IO_FILE_ERR -12
#define UPLOAD 100
#define DOWNLOAD 101
void error_processing(int error_code);
int get_ip_servername_file_from_hostname(char url[128], char * ip_adresa);
int check_connection(int socket_fd, struct sockaddr_in server, int index_operation, char * requested_file);
//--------------------------------------------------------------------------------------------------------------
// MAIN
int main (int argc, char *argv[])
{
// --------------- arguments check
if(argc != 7) error_processing(CHYBA_ARGC);
int port = -1;
int index_host = -1;
int index_operation = -1;
char requested_file[128];
char save_file_name[128];
if( strcmp(argv[1], "-p")==0) port = atoi(argv[2]);
else if( strcmp(argv[3], "-p")==0) port = atoi(argv[4]);
else if( strcmp(argv[5], "-p")==0) port = atoi(argv[6]);
else error_processing(CHYBA_ARGV);
if( strcmp(argv[1], "-h")==0) index_host=2;
else if( strcmp(argv[3], "-h")==0) index_host=4;
else if( strcmp(argv[5], "-h")==0) index_host=6;
else error_processing(CHYBA_ARGV);
if( strcmp(argv[1], "-d")==0 ){ index_operation=DOWNLOAD; strcpy(requested_file, argv[2]); strcpy(save_file_name, argv[2]);}
else if( strcmp(argv[3], "-d")==0 ){ index_operation=DOWNLOAD; strcpy(requested_file, argv[4]); strcpy(save_file_name, argv[4]);}
else if( strcmp(argv[5], "-d")==0 ){ index_operation=DOWNLOAD; strcpy(requested_file, argv[6]); strcpy(save_file_name, argv[6]);}
else if( strcmp(argv[1], "-u")==0 ){ index_operation=UPLOAD; strcpy(requested_file, argv[2]); strcpy(save_file_name, argv[2]);}
else if( strcmp(argv[3], "-u")==0 ){ index_operation=UPLOAD; strcpy(requested_file, argv[4]); strcpy(save_file_name, argv[4]);}
else if( strcmp(argv[5], "-u")==0 ){ index_operation=UPLOAD; strcpy(requested_file, argv[6]); strcpy(save_file_name, argv[6]);}
else error_processing(CHYBA_ARGV);
// --------------- arguments check
int socket_fd;
struct sockaddr_in server;
char server_address[128];
// char http_head_buffer[1024];
get_ip_servername_file_from_hostname(argv[index_host], server_address);
//if(DEBUG) printf("\n\nserver:'%s'\nfile:'%s'\n\n", server_address, requested_file);
// --------------- příprava socketu
socket_fd = socket(AF_INET , SOCK_STREAM , 0);
if(socket_fd == -1) error_processing(CHYBA_SOCKET);
if(DEBUG) puts("Socket created");
server.sin_addr.s_addr = inet_addr(server_address);
server.sin_family = AF_INET;
server.sin_port = htons(port);
if(server.sin_port == htons(port)){} //compiler
// --------------- test spojení, protokolu, atd
int protocol_error = check_connection(socket_fd, server, index_operation, requested_file);
// ---------------
if(protocol_error == SERVER_ERR) error_processing(SERVER_ERR);
if(DEBUG) puts("Socket closed");
close(socket_fd);
return 0;
}
//--------------------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------------------
// FCE ERROR PROCESSING
void error_processing(int error_code)
{
fprintf(stderr, "\nChyba: ");
switch(error_code)
{
case CHYBA_ARGC :
fprintf(stderr, "\n\tNeplatný počet argumentů! \n\n");
break;
case CHYBA_SOCKET :
fprintf(stderr, "\n\tNelze vytvořit socket! \n\n");
break;
case CHYBA_CONNECT :
fprintf(stderr, "\n\tNelze navázat spojení se serverem! \n\n");
break;
case CHYBA_SEND :
fprintf(stderr, "\n\tNelze odeslat data serveru! \n\n");
break;
case CHYBA_RECEIVE :
fprintf(stderr, "\n\tNepodařilo se získat data ze serveru! \n\n");
break;
case CHYBA_GETHOSTBYNAME :
fprintf(stderr, "\n\tNepodařilo se převést URL na IP adresu! \n\n");
break;
case SERVER_ERR :
fprintf(stderr, "\n\tChyba serveru \n\n");
break;
case CHYBA_ARGV :
fprintf(stderr, "\n\tChybně zadané parametry! \n\n");
break;
case CHYBA_BAD_HEAD :
fprintf(stderr, "\n\tChybná hlavička! \n\n");
break;
case CHYBA_UNKNOWN_DEMAND :
fprintf(stderr, "\n\tChybný požadavek! \n\n");
break;
case CHYBA_NO_FILE :
fprintf(stderr, "\n\tPožadovaný soubor neexistuje nebo je prázdný! \n\n"); // a prázdné soubory nemá smysl přenášet
break;
case CHYBA_IO_FILE_ERR :
fprintf(stderr, "\n\tChyba při prci se souborem! \n\n");
break;
default :
fprintf(stderr, "UNKNOWN ERROR\n\n");
}
exit(1);
}
//--------------------------------------------------------------------------------------------------------------
// FCE GET_IP_SERVERNAME_FILE_FROM_HOSTNAME
int get_ip_servername_file_from_hostname(char url[128], char * ip_adresa)
{
struct hostent *he;
struct in_addr **addr_list;
// check for IP
int count_dots = 0;
int chars = 0;
int last_num = 1;
unsigned int i;
for(i=0; i<strlen(url); i++)
{
if( url[i]=='.' && last_num==1)
{
count_dots++;
last_num=0;
}
else if( url[i]=='.' && last_num==0) break;
else if( isdigit(url[i])==0 )
{
chars++;
break;
}
else last_num = 1;
}
if( last_num==1 && chars==0 && (count_dots==3 || count_dots==5) )
{
strcpy(ip_adresa, url);
return 0;
}
// ------------------------------------
if ( (he = gethostbyname( url )) == NULL ) error_processing(CHYBA_GETHOSTBYNAME);
addr_list = (struct in_addr **) he->h_addr_list;
strcpy(ip_adresa, inet_ntoa(*addr_list[0]) );
return 0;
}
//--------------------------------------------------------------------------------------------------------------
// FCE CHECK_CONNECTION
//int check_connection(int socket_fd, struct sockaddr_in server, char * server_reply, char * http_head_buffer, char * method, char * requested_file, char * protocol, char * server_name)
int check_connection(int socket_fd, struct sockaddr_in server, int index_operation, char * requested_file)
{
FILE * fp;
char server_state[30];
server_state[0] = '\0';
char bufferIn[1025];
bufferIn[0] = '\0';
char filename[1025];
filename[0] = '\0';
int bytesread, i, size, size2;
char bufferOut[1024];
for(i=0; (unsigned int)i<strlen(bufferOut); i++){ bufferOut[i]='\0'; }
if (connect(socket_fd , (struct sockaddr *)&server , sizeof(server)) < 0) error_processing(CHYBA_CONNECT);
if(DEBUG) puts("Connected");
// Comm via protocol -----------------------------------------------------
strcpy(bufferOut, "PROTOCOL XSCHOR02-IPK-FIT-2016 CLIENT\n"); // PROTOCOL
if(index_operation==DOWNLOAD){strcat(bufferOut, "DW_LOAD");}
else {strcat(bufferOut, "UP_LOAD");} // OPERATION
strcat(bufferOut, "\n");
strcat(bufferOut, requested_file); // FILENAME
strcat(bufferOut, "\n");
if(index_operation==DOWNLOAD){strcat(bufferOut, "?");} // FILE SIZE
else
{
fp = fopen(requested_file, "r");
if(fp==NULL){error_processing(CHYBA_NO_FILE);}
fseek(fp, 0L, SEEK_END);
size = size2 = ftell(fp);
for(i=0; (unsigned int)i<strlen(bufferIn); i++){ bufferIn[i]='\0'; }
sprintf(bufferIn, "%d", size);
strcat(bufferOut, bufferIn);
bufferIn[0]='\0';
fclose(fp);
}
strcat(bufferOut, "\n");
if( send(socket_fd , bufferOut , strlen(bufferOut) , 0) < 0) error_processing(CHYBA_SEND);
int result, znak;
// READ PROTOCOL HEAD
bytesread = read(socket_fd, bufferIn, strlen("PROTOCOL XSCHOR02-IPK-FIT-2016 SERVER\n"));
if(bytesread <= 0) error_processing(CHYBA_CONNECT);
bufferIn[bytesread] = '\0';
if(strcmp(bufferIn,"PROTOCOL XSCHOR02-IPK-FIT-2016 SERVER\n")!=0) error_processing(CHYBA_BAD_HEAD);
if(DEBUG) printf(" > Comm with server established\n");
// READ DEMAND
bytesread = read(socket_fd, server_state, strlen("DW_LOAD\n"));
if(bytesread <= 0) error_processing(CHYBA_CONNECT);
server_state[bytesread] = '\0';
if(strcmp(server_state,"DW_LOAD\n")==0) {if(DEBUG) printf(" > Server want to DOWN-load file\n"); }
else if(strcmp(server_state,"UP_LOAD\n")==0) {if(DEBUG) printf(" > Server want to UP-load file\n"); }
else error_processing(CHYBA_UNKNOWN_DEMAND);
server_state[bytesread-1] = '\0';
// READ FILE NAME
for(bytesread=0, i=0 ; 1 ; i++)
{
bytesread = read(socket_fd, (char *)(filename+i*sizeof(char)), sizeof(char));
if(bytesread <= 0) error_processing(CHYBA_CONNECT);
else if( *(filename+i*sizeof(char))=='\n' ){filename[i] = '\0'; break;}
}
if(DEBUG) printf(" > Filename: \"%s\"\n", filename);
// READ FILE SIZE
for(bytesread=0, i=0 ; 1 ; i++)
{
bytesread = read(socket_fd, (char *)(bufferIn+i*sizeof(char)), sizeof(char));
if(bytesread <= 0) error_processing(CHYBA_CONNECT);
else if( *(bufferIn+i*sizeof(char))=='\n' ){bufferIn[i] = '\0'; break;}
}
if(bufferIn[0]=='?') size = 0;
else { size=atoi(bufferIn); if(size==0){error_processing(CHYBA_NO_FILE);} }
if(DEBUG) printf(" > Size: \"%d\"\n", size);
// --------------------------
if( strcmp(server_state, "DW_LOAD")==0 )
{
fp = fopen("temorary-file-for-client-content.txt", "w");
while(1)
{
result = recv(socket_fd , (int *)(& znak) , sizeof(int) , 0);
if( result < 0) error_processing(CHYBA_RECEIVE);
if( result == 0) break;
fputc(znak, fp);
}
fclose(fp);
if( access( requested_file, F_OK ) != -1 ) remove(requested_file);
rename("temorary-file-for-client-content.txt", requested_file);
}
else if( strcmp(server_state, "UP_LOAD")==0 )
{
fp = fopen(filename, "r");
for(i=0; i<size2; i++)
{
znak = fgetc(fp);
if( send(socket_fd , (char *)(& znak) , sizeof(int) , 0) < 0) error_processing(CHYBA_SEND);
}
fclose(fp);
}
else error_processing(SERVER_ERR);
return 0;
}