sending works
parent
1c942c3f05
commit
df019f8eab
2
README
2
README
|
@ -3,7 +3,7 @@ Andrew Coleman
|
||||||
CSC-4200
|
CSC-4200
|
||||||
|
|
||||||
To compile:
|
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:
|
For explanation on running:
|
||||||
./cftp -h
|
./cftp -h
|
||||||
|
|
58
cftp.c
58
cftp.c
|
@ -28,15 +28,15 @@ int validate_command(const char *msg)
|
||||||
char errmsg[ERRMSGLEN];
|
char errmsg[ERRMSGLEN];
|
||||||
|
|
||||||
/* GET file command */
|
/* GET file command */
|
||||||
if(!strcmp(msg, "get"))
|
if(!strncmp(msg, "get", 3))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* PUT file command */
|
/* PUT file command */
|
||||||
if(!strcmp(msg, "put"))
|
if(!strncmp(msg, "put", 3))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* PING send back the time stamp of right now */
|
/* PING send back the time stamp of right now */
|
||||||
if(!strcmp(msg, "ping"))
|
if(!strncmp(msg, "ping", 4))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* nothing else was found, so clearly this is not true */
|
/* 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.
|
* 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;
|
int c = 0, d = 0;
|
||||||
memset(command, '\0', CMDLEN);
|
memset(command, '\0', CMDLEN);
|
||||||
|
@ -94,6 +94,43 @@ void debug(const char *prefix, const char *msg)
|
||||||
printf("%s: %s\n", prefix, 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
|
* 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
|
* 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)
|
void send_message(int skt, char *msg)
|
||||||
{
|
{
|
||||||
char errmsg[ERRMSGLEN];
|
if(send_packet(skt, msg))
|
||||||
memset(errmsg, '\0', ERRMSGLEN);
|
|
||||||
|
|
||||||
if(send(skt, msg, strlen(msg), 0) < 0)
|
|
||||||
{
|
{
|
||||||
sprintf(errmsg, "Send Error: %s", strerror(errno));
|
receive_packet(skt, msg);
|
||||||
error(errmsg);
|
|
||||||
}
|
|
||||||
else if(recv(skt, msg, MSGLEN, 0) < 0)
|
|
||||||
{
|
|
||||||
sprintf(errmsg, "Receive Error: %s", strerror(errno));
|
|
||||||
error(errmsg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4
cftp.h
4
cftp.h
|
@ -10,9 +10,11 @@
|
||||||
#define ERRMSGLEN 256
|
#define ERRMSGLEN 256
|
||||||
#define CMDLEN 5
|
#define CMDLEN 5
|
||||||
int validate_command(const char *);
|
int validate_command(const char *);
|
||||||
void split_command(char *, char *, char *);
|
void split_command(const char *, char *, char *);
|
||||||
void error(const char *);
|
void error(const char *);
|
||||||
void debug(const char *, const char *);
|
void debug(const char *, const char *);
|
||||||
|
int send_packet(int, const char *);
|
||||||
|
int receive_packet(int, char *);
|
||||||
void send_message(int, char *);
|
void send_message(int, char *);
|
||||||
|
|
||||||
#endif
|
#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);
|
skt = connect_to_server(address, portnum);
|
||||||
split_command(msg, cmd, argument);
|
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);
|
receive_file(skt, argument, 0);
|
||||||
cdebug(msg);
|
|
||||||
}
|
}
|
||||||
close(skt);
|
close(skt);
|
||||||
}
|
}
|
||||||
|
@ -111,7 +115,7 @@ void run_client(const char *address, int portnum)
|
||||||
memset(msg, '\0', MSGLEN);
|
memset(msg, '\0', MSGLEN);
|
||||||
printf("> ");
|
printf("> ");
|
||||||
scanf("%s", msg);
|
scanf("%s", msg);
|
||||||
} while(strcmp(msg, "quit") != 0);
|
} while(strcmp(msg, "quit"));
|
||||||
|
|
||||||
/* cleanup and quit */
|
/* cleanup and quit */
|
||||||
cdebug("Bye!");
|
cdebug("Bye!");
|
||||||
|
|
190
filesystem.c
190
filesystem.c
|
@ -7,6 +7,7 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "cftp.h"
|
#include "cftp.h"
|
||||||
#include "filesystem.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
|
* This function will receive a packet and send a response back. Backwards of
|
||||||
* and a string containing the full path to the local file name. File cannot
|
* send_message. Takes an integer for the socket and a buffer to write the
|
||||||
* exceed MAXFILE definition.
|
* 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 response[CMDLEN];
|
||||||
char *basefname;
|
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;
|
int fsize = 0, segments = 0, cur_segment;
|
||||||
FILE *infile;
|
FILE *infile;
|
||||||
|
|
||||||
memset(errmsg, '\0', ERRMSGLEN);
|
memset(errmsg, '\0', ERRMSGLEN);
|
||||||
memset(cmd, '\0', CMDLEN);
|
|
||||||
memset(arg, '\0', MSGLEN);
|
|
||||||
memset(msg, '\0', MSGLEN);
|
memset(msg, '\0', MSGLEN);
|
||||||
|
|
||||||
/* file must exist */
|
/* file must exist */
|
||||||
if(!exist(filename))
|
if(!exist(filename))
|
||||||
{
|
{
|
||||||
|
if(server)
|
||||||
|
{
|
||||||
|
send_packet(skt, "err:That file does not exist");
|
||||||
|
}
|
||||||
error("The file does not exist!");
|
error("The file does not exist!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -69,65 +94,50 @@ void send_file(int skt, const char *filename)
|
||||||
fsize = filesize(filename);
|
fsize = filesize(filename);
|
||||||
if(fsize <= 0 || fsize >= MAXFILE)
|
if(fsize <= 0 || fsize >= MAXFILE)
|
||||||
{
|
{
|
||||||
error("That file is inappropriately sized!");
|
if(server)
|
||||||
return;
|
{
|
||||||
}
|
send_packet(skt, "err:File is too big");
|
||||||
segments = MAXFILE / MSGLEN;
|
}
|
||||||
|
error("File is too big");
|
||||||
/* 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);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
segments = (int) ceil(fsize / MSGLEN);
|
||||||
|
|
||||||
/* open file or die */
|
/* open file or die */
|
||||||
infile = fopen(filename, "r");
|
infile = fopen(filename, "r");
|
||||||
if(infile == NULL)
|
if(infile == NULL)
|
||||||
{
|
{
|
||||||
|
if(server)
|
||||||
|
{
|
||||||
|
send_packet(skt, "err:File could not be read");
|
||||||
|
}
|
||||||
sprintf(errmsg, "File could not be read: %s", strerror(errno));
|
sprintf(errmsg, "File could not be read: %s", strerror(errno));
|
||||||
error(errmsg);
|
error(errmsg);
|
||||||
return;
|
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);
|
send_packet(skt, "cts");
|
||||||
sprintf(errmsg, "\rFilesystem: Sending file %.2f%%", (cur_segment / segments * 100.0));
|
sleep(1);
|
||||||
printf(errmsg);
|
|
||||||
send_message(skt, msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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);
|
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.
|
* 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;
|
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
|
#define MAXFILE 1279872
|
||||||
void send_file(int, const char *);
|
void send_file(int, const char *, int);
|
||||||
void receive_file(int, const char *);
|
void receive_file(int, const char *, int);
|
||||||
|
|
||||||
#endif
|
#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.
|
* 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];
|
char command[CMDLEN], argument[MSGLEN];
|
||||||
time_t pong;
|
time_t pong;
|
||||||
memset(command, '\0', CMDLEN);
|
|
||||||
memset(argument, '\0', MSGLEN);
|
|
||||||
|
|
||||||
/* get individual command and argument for processing */
|
/* get individual command and argument for processing */
|
||||||
split_command(msg, command, argument);
|
split_command(msg, command, argument);
|
||||||
|
|
||||||
/* now check each command and perform the expected results */
|
/* now check each command and perform the expected results */
|
||||||
if(!strcmp(command, "ping"))
|
if(!strncmp(msg, "ping", 4))
|
||||||
{
|
{
|
||||||
pong = time(NULL);
|
pong = time(NULL);
|
||||||
sprintf(msg, "pong:%llud", (uintmax_t)pong);
|
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);
|
memset(msg, '\0', ERRMSGLEN);
|
||||||
|
|
||||||
/* figure out what to do */
|
/* 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)
|
else if(errno)
|
||||||
{
|
{
|
||||||
sprintf(buffer, "err:%s", strerror(errno));
|
sprintf(buffer, "err:%s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
/* regular fail */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprintf(buffer, "err:Invalid Command");
|
sprintf(buffer, "err:Invalid Command");
|
||||||
|
@ -74,12 +84,10 @@ void handle_client(int skt, const char *clientip)
|
||||||
/* send message to client */
|
/* send message to client */
|
||||||
if(strlen(buffer) > 0)
|
if(strlen(buffer) > 0)
|
||||||
{
|
{
|
||||||
sprintf(msg, "%s: %s", clientip, buffer);
|
sprintf(msg, "Response to %s: %s", clientip, buffer);
|
||||||
sdebug(msg);
|
sdebug(msg);
|
||||||
send(skt, buffer, strlen(buffer), 0);
|
send_packet(skt, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* cleanup */
|
|
||||||
close(skt);
|
close(skt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue