diff --git a/README b/README index 77664c8..3fed39e 100644 --- a/README +++ b/README @@ -3,7 +3,7 @@ Andrew Coleman CSC-4200 To compile: - gcc -o cftp -Wall server.c client.c filesystem.c cftp.c + gcc -o cftp -lm -Wall server.c client.c filesystem.c cftp.c For explanation on running: ./cftp -h diff --git a/cftp.c b/cftp.c index 65ccde4..585e68e 100644 --- a/cftp.c +++ b/cftp.c @@ -28,15 +28,15 @@ int validate_command(const char *msg) char errmsg[ERRMSGLEN]; /* GET file command */ - if(!strcmp(msg, "get")) + if(!strncmp(msg, "get", 3)) return 1; /* PUT file command */ - if(!strcmp(msg, "put")) + if(!strncmp(msg, "put", 3)) return 1; /* PING send back the time stamp of right now */ - if(!strcmp(msg, "ping")) + if(!strncmp(msg, "ping", 4)) return 1; /* nothing else was found, so clearly this is not true */ @@ -49,7 +49,7 @@ int validate_command(const char *msg) * Splits a buffer into a command and argument. * */ -void split_command(char *buffer, char *command, char *argument) +void split_command(const char *buffer, char *command, char *argument) { int c = 0, d = 0; memset(command, '\0', CMDLEN); @@ -94,6 +94,43 @@ void debug(const char *prefix, const char *msg) printf("%s: %s\n", prefix, msg); } +/* + * Wrapper to send a packet to a socket given a string. Handles errors and + * returns a bool based on success. + * + */ +int send_packet(int skt, const char *msg) +{ + char errmsg[ERRMSGLEN]; + memset(errmsg, '\0', ERRMSGLEN); + if(send(skt, msg, strlen(msg), 0) < 0) + { + sprintf(errmsg, "Send Packet Error: %s", strerror(errno)); + error(errmsg); + return 0; + } + return 1; +} + +/* + * Wrapper to receive a packet from a socket and stores the result in a given + * buffer. Handles errors and returns a bool based on success. + * + */ +int receive_packet(int skt, char *msg) +{ + char errmsg[ERRMSGLEN]; + memset(errmsg, '\0', ERRMSGLEN); + memset(msg, '\0', MSGLEN); + if(recv(skt, msg, MSGLEN, 0) < 0) + { + sprintf(errmsg, "Receive Packet Error: %s", strerror(errno)); + error(errmsg); + return 0; + } + return 1; +} + /* * Sends a message to the socket. Pass in the socket and message. Expects msg * to be already validated by validate_command first! Formats response into @@ -103,18 +140,9 @@ void debug(const char *prefix, const char *msg) */ void send_message(int skt, char *msg) { - char errmsg[ERRMSGLEN]; - memset(errmsg, '\0', ERRMSGLEN); - - if(send(skt, msg, strlen(msg), 0) < 0) + if(send_packet(skt, msg)) { - sprintf(errmsg, "Send Error: %s", strerror(errno)); - error(errmsg); - } - else if(recv(skt, msg, MSGLEN, 0) < 0) - { - sprintf(errmsg, "Receive Error: %s", strerror(errno)); - error(errmsg); + receive_packet(skt, msg); } } diff --git a/cftp.h b/cftp.h index 485925e..f99680b 100644 --- a/cftp.h +++ b/cftp.h @@ -10,9 +10,11 @@ #define ERRMSGLEN 256 #define CMDLEN 5 int validate_command(const char *); -void split_command(char *, char *, char *); +void split_command(const char *, char *, char *); void error(const char *); void debug(const char *, const char *); +int send_packet(int, const char *); +int receive_packet(int, char *); void send_message(int, char *); #endif diff --git a/client.c b/client.c index 75f59a6..da11cc8 100644 --- a/client.c +++ b/client.c @@ -88,14 +88,18 @@ void run_client(const char *address, int portnum) { skt = connect_to_server(address, portnum); split_command(msg, cmd, argument); - if(!strcmp(cmd, "put")) + send_message(skt, msg); + /* response message from server, now in msg */ + cdebug(msg); + /* send file to server */ + if(!strcmp(cmd, "put") && !strncmp(msg, "cts", 3)) { - send_file(skt, argument); + send_file(skt, argument, 0); } - else + /* get file from server */ + else if(!strcmp(cmd, "get") && !strncmp(msg, "cts", 3)) { - send_message(skt, msg); - cdebug(msg); + receive_file(skt, argument, 0); } close(skt); } @@ -111,7 +115,7 @@ void run_client(const char *address, int portnum) memset(msg, '\0', MSGLEN); printf("> "); scanf("%s", msg); - } while(strcmp(msg, "quit") != 0); + } while(strcmp(msg, "quit")); /* cleanup and quit */ cdebug("Bye!"); diff --git a/filesystem.c b/filesystem.c index a550c48..fcfff44 100644 --- a/filesystem.c +++ b/filesystem.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "cftp.h" #include "filesystem.h" @@ -41,26 +42,50 @@ int filesize(const char *filename) } /* - * This function will send a file to a remote host. Expects a socket integer - * and a string containing the full path to the local file name. File cannot - * exceed MAXFILE definition. + * This function will receive a packet and send a response back. Backwards of + * send_message. Takes an integer for the socket and a buffer to write the + * message into. This is only designed to take a reponse from send_file and + * send back either "cts" or "err". * */ -void send_file(int skt, const char *filename) +void receive_message(int skt, char *buf) { - char errmsg[ERRMSGLEN], cmd[CMDLEN], arg[MSGLEN], msg[MSGLEN]; - char *basefname; + char response[CMDLEN]; + memset(response, '\0', CMDLEN); + if(!receive_packet(skt, buf)) + { + strcpy(response, "err"); + } + else + { + strcpy(response, "cts"); + } + send_packet(skt, response); +} + +/* + * This function will send a file to a remote host. Expects a socket integer + * and a string containing the full path to the local file name. File cannot + * exceed MAXFILE definition. Takes a server boolean for some additional + * checks. + * + */ +void send_file(int skt, const char *filename, int server) +{ + char errmsg[ERRMSGLEN], msg[MSGLEN]; int fsize = 0, segments = 0, cur_segment; FILE *infile; memset(errmsg, '\0', ERRMSGLEN); - memset(cmd, '\0', CMDLEN); - memset(arg, '\0', MSGLEN); memset(msg, '\0', MSGLEN); /* file must exist */ if(!exist(filename)) { + if(server) + { + send_packet(skt, "err:That file does not exist"); + } error("The file does not exist!"); return; } @@ -69,65 +94,50 @@ void send_file(int skt, const char *filename) fsize = filesize(filename); if(fsize <= 0 || fsize >= MAXFILE) { - error("That file is inappropriately sized!"); - return; - } - segments = MAXFILE / MSGLEN; - - /* make a copy then figure out just the filename */ - strcpy(msg, filename); - basefname = basename(msg); - sprintf(errmsg, "Sending file (%s) in %d segments.", basefname, segments); - debug("Filesystem", errmsg); - - /* send the command, we do not send the user command because we just want - * to send the base filename. also, we expect a response from the server, - * either cts or err. - */ - sprintf(msg, "put:%s", basefname); - send_message(skt, msg); - split_command(msg, cmd, arg); - if(!strcmp(cmd, "err")) - { - sprintf(errmsg, "ERROR Not sending the file: %s", arg); - error(errmsg); - return; - } - else if(strcmp(cmd, "cts")) - { - sprintf(errmsg, "ERROR invalid reponse from remote: %s", msg); - error(errmsg); - return; - } - - /* send number of segments and file size to the other size cmd:arg style */ - sprintf(msg, "%d:%d", segments, fsize); - /* do not expect a response, only data after this */ - if(send(skt, msg, strlen(msg), 0) < 0) - { - sprintf(errmsg, "Failed to send the number of segments: %s", strerror(errno)); - error(errmsg); + if(server) + { + send_packet(skt, "err:File is too big"); + } + error("File is too big"); return; } + segments = (int) ceil(fsize / MSGLEN); /* open file or die */ infile = fopen(filename, "r"); if(infile == NULL) { + if(server) + { + send_packet(skt, "err:File could not be read"); + } sprintf(errmsg, "File could not be read: %s", strerror(errno)); error(errmsg); return; } - /* now read in the file, MSGLEN at a time and send the chunk to the host */ - for(cur_segment = 0; cur_segment < segments; cur_segment++) + + /* send cts to client */ + if(server) { - fread(msg, MSGLEN, 1, infile); - sprintf(errmsg, "\rFilesystem: Sending file %.2f%%", (cur_segment / segments * 100.0)); - printf(errmsg); - send_message(skt, msg); + send_packet(skt, "cts"); + sleep(1); } + + /* send number of segments and file size to the other size cmd:arg style */ + sprintf(msg, "%d:%d", segments, fsize); + /* do not expect a response, only data after this */ + send_packet(skt, msg); + + /* now read in the file, MSGLEN at a time and send the chunk to the host */ + for(cur_segment = 0; cur_segment <= segments; cur_segment++) + { + memset(msg, '\0', MSGLEN); + fread(msg, MSGLEN, 1, infile); + printf("\rFilesystem: Sending file %d / %d", cur_segment, segments); + send_packet(skt, msg); + } + printf("\n"); fclose(infile); - debug("Filesystem", "File sent successfully"); } /* @@ -135,9 +145,79 @@ void send_file(int skt, const char *filename) * a filename. The file will be basename'd and saved into /tmp. * */ -void receive_file(int skt, const char *filename) +void receive_file(int skt, const char *filename, int server) { - unsigned char fbuf[MAXFILE]; + char msg[MSGLEN], cmd[CMDLEN], arg[MSGLEN], lname[MSGLEN], errmsg[ERRMSGLEN]; + char *basefname; + FILE *outfile; int fsize = 0, segments = 0, cur_segment = 0; + + /* get the local file name in /tmp */ + memset(lname, '\0', MSGLEN); + memset(errmsg, '\0', ERRMSGLEN); + strcpy(msg, filename); + basefname = basename(msg); + sprintf(lname, "/tmp/%s", basefname); + + /* if file exists, send err to remote, otherwise send cts and await size */ + if(exist(lname)) + { + debug("Filesystem", "Not receiving file since it already exists"); + if(server) + { + send_packet(skt, "err:File already exists"); + } + return; + } + + /* open file for writing */ + outfile = fopen(lname, "w"); + if(outfile == NULL) + { + sprintf(errmsg, "Could not open file for writing: %s", strerror(errno)); + debug("Filesystem", errmsg); + if(server) + { + send_packet(skt, "err:File could not be written"); + } + return; + } + + /* ready to receive file */ + if(server) + { + memset(msg, '\0', MSGLEN); + strcpy(msg, "cts"); + send_message(skt, msg); + } + else + { + receive_packet(skt, msg); + } + split_command(msg, cmd, arg); + segments = atoi(cmd); + fsize = atoi(arg); + sprintf(errmsg, "Going to receive %d bytes in %d segments", fsize, segments); + debug("Filesystem", errmsg); + + /* loop through segments packet count and get the file */ + for(cur_segment = 0; cur_segment <= segments; cur_segment++) + { + printf("\rFilesystem: Receiving File: %d / %d", cur_segment, segments); + memset(msg, '\0', MSGLEN); + receive_packet(skt, msg); + if(cur_segment == segments) + { + /* write remaining bytes */ + fwrite(msg, (fsize - (segments * MSGLEN)), 1, outfile); + } + else + { + /* write complete segment */ + fwrite(msg, MSGLEN, 1, outfile); + } + } + printf("\n"); + fclose(outfile); } diff --git a/filesystem.h b/filesystem.h index 785504b..03ba8fb 100644 --- a/filesystem.h +++ b/filesystem.h @@ -17,8 +17,8 @@ * */ #define MAXFILE 1279872 -void send_file(int, const char *); -void receive_file(int, const char *); +void send_file(int, const char *, int); +void receive_file(int, const char *, int); #endif diff --git a/server.c b/server.c index a5989fa..f6e4dc6 100644 --- a/server.c +++ b/server.c @@ -28,22 +28,30 @@ void sdebug(const char *msg) * from the client. The response is stored in the same buffer for return. * */ -void server_command(char *msg) +void server_command(int skt, char *msg) { char command[CMDLEN], argument[MSGLEN]; time_t pong; - memset(command, '\0', CMDLEN); - memset(argument, '\0', MSGLEN); /* get individual command and argument for processing */ split_command(msg, command, argument); /* now check each command and perform the expected results */ - if(!strcmp(command, "ping")) + if(!strncmp(msg, "ping", 4)) { pong = time(NULL); sprintf(msg, "pong:%llud", (uintmax_t)pong); } + else if(!strncmp(msg, "put", 3)) + { + memset(msg, '\0', MSGLEN); + receive_file(skt, argument, 1); + } + else if(!strncmp(msg, "get", 3)) + { + memset(msg, '\0', MSGLEN); + send_file(skt, argument, 1); + } } /* @@ -58,14 +66,16 @@ void handle_client(int skt, const char *clientip) memset(msg, '\0', ERRMSGLEN); /* figure out what to do */ - if(recv(skt, buffer, MSGLEN, 0) >= 0 && validate_command(buffer)) + if(receive_packet(skt, buffer) && validate_command(buffer)) { - server_command(buffer); + server_command(skt, buffer); } + /* epic fail */ else if(errno) { sprintf(buffer, "err:%s", strerror(errno)); } + /* regular fail */ else { sprintf(buffer, "err:Invalid Command"); @@ -74,12 +84,10 @@ void handle_client(int skt, const char *clientip) /* send message to client */ if(strlen(buffer) > 0) { - sprintf(msg, "%s: %s", clientip, buffer); + sprintf(msg, "Response to %s: %s", clientip, buffer); sdebug(msg); - send(skt, buffer, strlen(buffer), 0); + send_packet(skt, buffer); } - - /* cleanup */ close(skt); }