//--------------------------------------------------------------------------------------------------------------
// MICHAL SCHORM - xschor02@stud.fit.vutbr.cz
// IPK - 2. projekt - server
// 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 CHYBA_ARGV -7
#define CHYBA_BAD_HEAD -8
#define CHYBA_UNKNOWN_DEMAND -9
#define CHYBA_NO_FILE -10
#define CHYBA_IO_FILE_ERR -11
#define UPLOAD 100
#define DOWNLOAD 101
void error_processing(int error_code);
void comm_service(int socket_fd);
//--------------------------------------------------------------------------------------------------------------
// MAIN
int main (int argc, char *argv[])
{
int port;
// ------ arguments check ------------------
if(argc != 3) error_processing(CHYBA_ARGC);
if( strcmp(argv[1], "-p")==0) port = atoi(argv[2]);
else error_processing(CHYBA_ARGV);
// -----------------------------------------
struct sockaddr_in serv_addr, cli_addr;
int socket_fd = 0;
int newsockfd = 0;
socklen_t clilen;
if(DEBUG) printf("\nStarting server ...\n");
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
memset((char *) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(port);
bind(socket_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
//----------------------------
while(1)
{
listen(socket_fd, 50); // může postupně obsloužit až 50 klientů
if(DEBUG) printf("Listenning ... \n");
clilen = sizeof(cli_addr);
newsockfd = accept(socket_fd, (struct sockaddr *) &cli_addr, &clilen);
if(DEBUG) printf("Connection accepted ... \n");
comm_service(newsockfd);
close(newsockfd);
}
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 nebo udržet spojení s klientem! \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 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 COMM SERVICE
void comm_service(int socket_fd)
{
// -1 Socket closed
// -2 Socket read error
char bufferIn[1025];
bufferIn[0] = '\0';
char bufferOut[1025];
bufferOut[0] = '\0';
char filename[1025];
filename[0] = '\0';
int bytesread, i, size, operation;
// READ PROTOCOL HEAD
bytesread = read(socket_fd, bufferIn, strlen("PROTOCOL XSCHOR02-IPK-FIT-2016 CLIENT\n"));
if(bytesread <= 0) error_processing(CHYBA_CONNECT);
bufferIn[bytesread] = '\0';
if(strcmp(bufferIn,"PROTOCOL XSCHOR02-IPK-FIT-2016 CLIENT\n")!=0) error_processing(CHYBA_BAD_HEAD);
if(DEBUG) printf(" > Comm with client established\n");
// READ DEMAND
bytesread = read(socket_fd, bufferIn, strlen("DW_LOAD\n"));
if(bytesread <= 0) error_processing(CHYBA_CONNECT);
bufferIn[bytesread] = '\0';
if(strcmp(bufferIn,"DW_LOAD\n")==0) {operation=DOWNLOAD; if(DEBUG) printf(" > Client want to DOWN-load file\n"); }
else if(strcmp(bufferIn,"UP_LOAD\n")==0) {operation=UPLOAD; if(DEBUG) printf(" > Client want to UP-load file\n"); }
else error_processing(CHYBA_UNKNOWN_DEMAND);
// 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);
// --------------------------
int znak, result;
FILE * fp;
// -------------------- DOWNLOAD ----------------------------
if(operation==DOWNLOAD)
{
fp = fopen(filename, "r");
if(fp==NULL){error_processing(CHYBA_IO_FILE_ERR);}
fseek(fp, 0L, SEEK_END);
size = ftell(fp);
rewind(fp);
for(i=0; (unsigned int)i<strlen(bufferIn); i++){ bufferIn[i]='\0'; }
sprintf(bufferIn, "%d", size);
strcpy(bufferOut, "PROTOCOL XSCHOR02-IPK-FIT-2016 SERVER\n"); // PROTOCOL
strcat(bufferOut, "DW_LOAD"); // OPERATION
strcat(bufferOut, "\n");
strcat(bufferOut, filename); // FILENAME
strcat(bufferOut, "\n");
strcat(bufferOut, bufferIn); // FILE SIZE
strcat(bufferOut, "\n\0");
if( send(socket_fd , bufferOut , strlen(bufferOut) , 0) < 0) error_processing(CHYBA_SEND);
for(i=0; i<size; i++)
{
znak = fgetc(fp);
if( send(socket_fd , (char *)(& znak) , sizeof(int) , 0) < 0) error_processing(CHYBA_SEND);
}
fclose(fp);
}
// -------------------- UPLOAD ----------------------------
else if(operation==UPLOAD)
{
strcpy(bufferOut, "PROTOCOL XSCHOR02-IPK-FIT-2016 SERVER\n"); // PROTOCOL
strcat(bufferOut, "UP_LOAD"); // OPERATION
strcat(bufferOut, "\n");
strcat(bufferOut, filename); // FILENAME
strcat(bufferOut, "\n");
strcat(bufferOut, "?"); // FILE SIZE
strcat(bufferOut, "\n\0");
if( send(socket_fd , bufferOut , strlen(bufferOut) , 0) < 0) error_processing(CHYBA_SEND);
fp = fopen("temorary-file-for-server-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( filename, F_OK ) != -1 ) remove(filename);
rename("temorary-file-for-server-content.txt", filename);
}
else {error_processing(CHYBA_UNKNOWN_DEMAND);}
if(DEBUG) printf("\n\n");
}