sending works
parent
1c942c3f05
commit
df019f8eab
2
README
2
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
|
||||
|
|
58
cftp.c
58
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
4
cftp.h
4
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
|
||||
|
|
16
client.c
16
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!");
|
||||
|
|
190
filesystem.c
190
filesystem.c
|
@ -7,6 +7,7 @@
|
|||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <math.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
28
server.c
28
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);
|
||||
}
|
||||
|
||||
|
|
Reference in New Issue