[Disclaimer: This code is provided for educational purposes, you are responsible of how you use this code and this code is provided ‘as is’. Meaning that I do not take responsibility of any harm that this code may or not produce]
The following is an example of a client and server that let you transfer a file from the client to the server by encrypting and then decrypting the packages using Vigenere Cipher.
Test file content example:
Note: This program is designed only to send files that are alphabetic in lower case, without spaces, and only one line.
abcdefghijklmnopqrstuvwxyzaabcdefghijklmnopqrstuvwxyzaabcdefghijklmnopqrstuvwxyza
Makefile:
As a good policy, always add your name, short description, and any other information that could help a user that doesn’t know as you the content of your code and its behaviour.
Note: In the server, there must be a subdirectory named cli_serv in which ssh and scp can access after loading.
######################################################################### # Author: Alejandro G. Carlstein Ramos Mejia # Description: Client/Server File Transfer using Vergene Cipher # # # make <= compile all files # make build <= compile all files # make all <= clean and compile all files # make ssh <= Connect to server and go to folder cli_serv # make upload <= Upload files on SRC_FILES list to server # make uploadssh <= Upload files on SRC_FILES list to server and connect to server # make submit <= Tar files on SRC_FILES list # make zipsubmit <= Tar files on SRC_FILES list and gzip them # make clean <= Clean all executable and *.o files # make debug_server <= Debug server using dbg # make debug_client <= Debug client using dbg # make ldebug_server <= Debug for leaks on server # make ldebug_client <= Debug for leaks on client ########################################################################## ########################################################################## # Variables ########################################################################## # PROJECT is the name used when preparing for sumit/ # The tar and/or zip file will be using this name PROJECT = server_client_vergene # SRC_FILES are list of files in the project. # This list is used when uploading files to the server. # Also, this list is used when tar/zipped for submit SRC_FILES = \ cli.c \ serv.c\ default.h \ default.c \ text.txt\ Makefile \ README # OpenSSH SSH client (remote login program) SSH = ssh # secure copy (remote file copy program) # SCP is used for uploading files to the server in secure mode SCP = scp # FOLDER_SERVER is the folder that SSH and SCP will try to access after login FOLDER_SERVER = server_client_vergene # SSH_SERVER is the hostname of the server SSH_SERVER = bingsuns2.cc.binghamton.edu # SSH_OPTION # -t opens a pseudo-tty with in the current session. # This flag is required to execute the commands on SSH_CD_FOLDER SSH_OPTION = -t # SSH_CD_FOLDER executes cd # Then change the prompt to show the number of bash in the server SSH_CD_FOLDER = 'cd $(FOLDER_SERVER); bash; echo $PS1' # CC indicates which compiler is going to be used CC = gcc # Files required for compiling the server CODE_SERVER_FILE = serv.c default.c # Files required for compiling the client CODE_CLIENT_FILE = cli.c default.c # Name of the executable file for the server EXEC_SERVER_FILE = serv # Name for the executable file for the client EXEC_CLIENT_FILE = cli # Flags for the compiler # -g indicate to provide debuggin information # -Wall activates the warnings. # -lm indicate the compiler to add basic mathematics libraries CFLAGS = -g -Wall -lm # COMPILE is the combination of the compiler with the flags COMPILE = $(CC) $(CFLAGS) # MFLAGS are flags that require to be added at the end MFLAGS = # USERNAME is used later when required to do an upload followed with ssh USERNAME = # Detect if the computer is SunOS to add flags needed for compiling UNAME := $(shell uname) ifeq ($(UNAME), SunOS) MFLAGS := -lsocket -lnsl endif ########################################################################## # 'make' options ########################################################################## # Clean all files and compile client and server all: clean compile_server compile_client # Just build server and client build: compile_server compile_client # Compile server compile_server: $(CODE_SERVER_FILE) $(CC) $(CFLAGS) -o $(EXEC_SERVER_FILE) $(CODE_SERVER_FILE) $(MFLAGS) # Compile client compile_client: $(CODE_CLIENT_FILE) $(CC) $(CFLAGS) -o $(EXEC_CLIENT_FILE) $(CODE_CLIENT_FILE) $(MFLAGS) # Debug server debug_server: gdb $(EXEC_SERVER_FILE) # Debug client debug_client: gdb $(EXEC_CLIENT_FILE) # Leak debug server ldebug_server: valgrind --leak-check=full --show-reachable=yes -v $(EXEC_SERVER_FILE) # Leak debug client ldebug_client: valgrind --leak-check=full --show-reachable=yes -v $(EXEC_CLIENT_FILE) # Upload files and connect to server uploadssh: @echo -n 'Upload and connect to $(SSH_SERVER)- USERNAME: ';\ read user_name;\ $(SCP) $(SRC_FILES) $$user_name@$(SSH_SERVER):./$(FOLDER_SERVER);\ $(SSH) $(SSH_OPTION) $$user_name@$(SSH_SERVER) $(SSH_CD_FOLDER);\ # Upload files to server upload: @echo -n 'Upload to $(SSH_SERVER)- USERNAME: ';\ read user_name;\ $(SCP) $(SRC_FILES) $$user_name@$(SSH_SERVER):./$(FOLDER_SERVER);\ # Connect to server ssh: @echo -n 'Connect to $(SSH_SERVER)- USERNAME: ';\ read user_name;\ $(SSH) $(SSH_OPTION) $$user_name@$(SSH_SERVER) $(SSH_CD_FOLDER);\ # Makes a archive containing all the project source files for submission. submit: $(SRC_FILES) tar -cvf $(PROJECT).tar $(SRC_FILES) # Makes a archive containing all the project source files for submission # and zip them zipsubmit: $(SRC_FILES) tar cvfz $(PROJECT).tar.gz $(SRC_FILES) # Clean files .PHONY: clean clean: rm -f *~ *.o $(EXEC_SERVER_FILE) $(EXEC_CLIENT_FILE)
Default file is required for both the server and the client. It holds the libraries and definitions shared by both programs.
Default.h file:
/** * Author: Alejandro G. Carlstein * Description: File Transfer Client/Server */ #ifndef ACARLS_DEFAULT_H #define ACARLS_DEFAULT_H #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <errno.h> #include <unistd.h> #include <dirent.h> /* Required for linux */ #include <string.h> /* Required for SunOS */ #include <strings.h> #include <ctype.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netdb.h> #define DEFAULT_PORT 8414 #define DATA_PACKET_SIZE 1024 #define NUM_BYTES 8 #define ENCRYPTION_KEY 'security' #define CHAR_KEY_A 97 #define CHAR_PLAIN_A 97 #define CHAR_CIPHER_A 65 #define DBG_LV0 0 #define DBG_LV1 0 #define DBG_LV2 0 #define DBG_LV3 0 #define TRUE 1 #define FALSE 0 #define QUIT_TRUE 0 #define QUIT_FALSE 1 #define CODE_FAIL '0FAIL' #define CODE_OK '1OK' #define CODE_HELLO '100HELLO' #define CODE_WELCOME '101WELCOME' #define CODE_REQ_SERVER_NAME '102REQ_SERVER_NAME' #define CODE_MSG '200MSG' #define CODE_DATA '300DATA' #define CODE_EOF '301EOF' #define CODE_PUT '302PUT' #define CODE_REQUEST_FILENAME '303REQ_FILENAME' #define CODE_REQUEST_ENCRYPT '304REQ_ENCRYPT' #define CODE_ENCRYPT '305ENCRYPT' #define CODE_REQUEST_FILE '306REQUEST_FILE' #define CODE_CMD '400CMD' #define CODE_LS '401LS' #define CODE_ERROR '500ERROR' #define CODE_ERROR_LS '501ERROR_LS' #define CODE_ERROR_CREAT_FILE '502ERROR_CREAT_FILE' #define CODE_EXIT '600EXIT' #define MSG_ERR_WRONG_PROTOCOL 'Wrong protocol!' #define MSG_ERROR_CREAT_FILE 'Couldn't create file' #define MSG_PORT_NUMBER_ONLY 'Need port number only! \n%s <Port Number>' #define MSG_ERR_COULDNT_SOCKET 'Couldn't obtain socket - %d' #define MSG_ERR_COULDNT_CONNECT 'Couldn't connect!' #define MSG_ERR_SENDING_DATA 'Couldn't send data!' #define MSG_ERR_RECEIVING_DATA 'Couln't recieve data!' #define MSG_ERR_CONNECTION_FAIL 'Connection failed.' #define MSG_ERR_NO_DIR_STREAM 'Could not obtain the directory stream' void debug(int debugLevel, char *fmt, ...); void errorDoExit(char *fmt, ...); #endif
Default.c:
/** * Author: Alejandro G. Carlstein * Description: File Transfer Client/Server */ #include 'default.h' void debug(int debugLevel, char *fmt, ...){ if (debugLevel == 1){ va_list argp; fprintf(stdout, '[DBG] '); va_start(argp, fmt); vfprintf(stdout, fmt, argp); va_end(argp); fprintf(stdout, '\n'); } } void errorDoExit(char *fmt, ...){ va_list argp; fprintf(stderr, '[Error] '); va_start(argp, fmt); vfprintf(stderr, fmt, argp); va_end(argp); if (errno){ fprintf(stderr, '=> %s\n', strerror(errno)); }else{ fprintf(stderr, '\n'); } exit(1); }
The following is the code for the server.
serv.c:
/** * Assignment: 1 * Course: CS458 * Author: Alejandro G. Carlstein * Description: FTP Server */ #include 'default.h' /*max. length queue of pending connections may grow. */ #define MAX_BACKLOG 5 #define SETSOCKOPT_VAL 1 #define MSG_SERVER_NAME 'Server Name: ACARLSTEIN Server Version 1.0' #define MSG_WAIT_CLIENT 'Waiting client...\n' #define MSG_WAIT_CLIENT_ON_PORT '\nTCPServer Waiting for client on port %d\n' #define MSG_ERR_NO_SOCKET_OPT 'Couldn't set and/or get socket options' #define MSG_ERR_UNABLE_BIND 'Unable to bind' #define MSG_ERR_UNABLE_LISTEN 'Unable to Listen' #define MSG_ERR_CANT_SEND_LIST 'Can't send server list\n' struct Connection{ int sock; int bytes_recieved; int port_number; int socket_descriptor; char send_data[DATA_PACKET_SIZE]; char recv_data[DATA_PACKET_SIZE]; struct sockaddr_in server_addr; struct sockaddr_in client_addr; }; void setUpConnection(struct Connection *new_connection, int port_number); int menuDriver(struct Connection *new_connection); void sendData(struct Connection *new_connection, const char* data); int recieveData(struct Connection *new_connection); void handShake(struct Connection* new_connection); void sendListDirectoryContents(struct Connection* new_connection); int receiveFileFromClient(struct Connection* new_connection); int strdecrypt(const char* str_in, char* str_out); /** * MAIN */ int main(int argc, char *argv[]){ debug(DBG_LV0, 'argc: %d', argc); short DO_QUIT_PROGRAM; int i; int port_number; socklen_t sin_size = sizeof(struct sockaddr_in); struct Connection connection; for(i = 0; DBG_LV1 && i < argc; ++i) debug(DBG_LV1, 'argv[%d]: %s', i, argv[i]); if (argc > 2) errorDoExit(MSG_PORT_NUMBER_ONLY, argv[0]); port_number = (argc == 2) ? atoi(argv[1]) : DEFAULT_PORT; DO_QUIT_PROGRAM = QUIT_FALSE; while(DO_QUIT_PROGRAM){ fflush(stdout); setUpConnection(&connection, port_number); printf(MSG_WAIT_CLIENT_ON_PORT, port_number); connection.socket_descriptor = accept(connection.sock, (struct sockaddr *)&connection.client_addr, &sin_size); if (connection.socket_descriptor == -1) errorDoExit(MSG_ERR_COULDNT_CONNECT); handShake(&connection); menuDriver(&connection); close(connection.sock); } return 0; } /** * Menu driver waiting for instructions */ int menuDriver(struct Connection *new_connection){ short DO_QUIT_CONNECTION; int bytes_received = 1; DO_QUIT_CONNECTION = QUIT_FALSE; while (DO_QUIT_CONNECTION){ if(bytes_received == 0){ DO_QUIT_CONNECTION = QUIT_TRUE; }else{ printf(MSG_WAIT_CLIENT); bytes_received = recieveData(new_connection); if (strcmp(new_connection->recv_data, CODE_LS) == 0){ sendListDirectoryContents(new_connection); }else if (strcmp(new_connection->recv_data, CODE_PUT) == 0){ bytes_received = receiveFileFromClient(new_connection); }else{ close(new_connection->sock); fprintf(stderr, MSG_ERR_WRONG_PROTOCOL ' - PUT\n'); DO_QUIT_CONNECTION = QUIT_TRUE; } } } return 0; } /** * Set up connection with the client */ void setUpConnection(struct Connection *new_connection, int port_number){ debug(DBG_LV0, 'setUpConnection(port_number: %d)', port_number); int opt_val = SETSOCKOPT_VAL; new_connection->port_number = port_number; if ((new_connection->sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) errorDoExit(MSG_ERR_COULDNT_SOCKET, new_connection->sock); if (setsockopt(new_connection->sock, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof(int)) == -1) errorDoExit(MSG_ERR_NO_SOCKET_OPT); debug(DBG_LV1, 'Got socket!'); new_connection->server_addr.sin_family = AF_INET; debug(DBG_LV1,'sin_family'); new_connection->server_addr.sin_port = htons(port_number); debug(DBG_LV1,'sin_port'); new_connection->server_addr.sin_addr.s_addr = INADDR_ANY; debug(DBG_LV1, 'sin_addr'); bzero(&(new_connection->server_addr.sin_zero), NUM_BYTES); debug(DBG_LV1,'sin_zero'); // bind a name to a socket if (bind(new_connection->sock, (struct sockaddr *)&new_connection->server_addr, sizeof(struct sockaddr)) == -1){ close(new_connection->sock); errorDoExit(MSG_ERR_UNABLE_BIND); } // Listen for connection on the socket if (listen(new_connection->sock, MAX_BACKLOG) == -1){ close(new_connection->sock); errorDoExit(MSG_ERR_UNABLE_LISTEN); } debug(DBG_LV1, 'Listening...'); } /** * Send data to client */ void sendData(struct Connection *new_connection, const char* data){ debug(DBG_LV0, 'sendData(data: %s)', data); int data_length; bzero(new_connection->send_data, DATA_PACKET_SIZE); strcpy(new_connection->send_data, data); data_length = strlen(new_connection->send_data); debug(DBG_LV1, 'new_connection->send_data: %s', new_connection->send_data); if (send(new_connection->socket_descriptor, new_connection->send_data, data_length, 0) != data_length){ close(new_connection->sock); fprintf(stderr, MSG_ERR_SENDING_DATA '\n'); } } /** * Receive data from client */ int recieveData(struct Connection *new_connection){ debug(DBG_LV0, 'recieveData()'); bzero(new_connection->recv_data, DATA_PACKET_SIZE); int bytes_recieved = recv(new_connection->socket_descriptor, new_connection->recv_data, DATA_PACKET_SIZE, 0); debug(DBG_LV1, 'Check bytes received'); if(bytes_recieved < 1){ close(new_connection->sock); if(bytes_recieved == 0){ fprintf(stderr, MSG_ERR_CONNECTION_FAIL '\n'); }else{ fprintf(stderr,MSG_ERR_RECEIVING_DATA '\n'); } }else{ debug(DBG_LV1, 'Received: %s', new_connection->recv_data); new_connection->bytes_recieved = bytes_recieved; new_connection->recv_data[bytes_recieved] = '\0'; } return bytes_recieved; } /** * Hand shake with client to test own protocol */ void handShake(struct Connection* new_connection){ debug(DBG_LV0, 'handShake()'); printf('Connection from (%s , %d)...\n', inet_ntoa(new_connection->client_addr.sin_addr), ntohs(new_connection->client_addr.sin_port)); debug(DBG_LV1,' If client say HELLO, Greed client with WELCOME'); recieveData(new_connection); if (strcmp(new_connection->recv_data, CODE_HELLO) == 0){ debug(DBG_LV1, 'Client handshake with server'); sendData(new_connection, CODE_WELCOME); }else{ close(new_connection->sock); fprintf(stderr, MSG_ERR_WRONG_PROTOCOL ' - HELLO/WELCOME \n'); } debug(DBG_LV0,'If client ask for server name send server name to client'); recieveData(new_connection); if (strcmp(new_connection->recv_data, CODE_REQ_SERVER_NAME) == 0){ debug(DBG_LV1, 'Client asking for server name'); sendData(new_connection, MSG_SERVER_NAME); }else{ close(new_connection->sock); fprintf(stderr, MSG_ERR_WRONG_PROTOCOL ' - SERVER NAME\n'); } } /** * Send list of directory contents to client */ void sendListDirectoryContents(struct Connection* new_connection){ debug(DBG_LV0, 'void displayLocalListDirectoryContents()'); int bytes_received; struct dirent *dirent_struct_ptr; DIR *directory_stream_ptr; if ((directory_stream_ptr = opendir('./')) != NULL){ while ((dirent_struct_ptr = readdir(directory_stream_ptr))){ sendData(new_connection, dirent_struct_ptr->d_name); bytes_received = recieveData(new_connection); if (strcmp(new_connection->recv_data, CODE_OK) != 0){ fprintf(stderr, MSG_ERR_CANT_SEND_LIST); } } sendData(new_connection, CODE_EOF); }else{ sendData(new_connection, CODE_ERROR_LS); errorDoExit(MSG_ERR_NO_DIR_STREAM); } } /** * Receive encrypted file from client */ int receiveFileFromClient(struct Connection* new_connection){ debug(DBG_LV0, 'void receiveFileFromClient(is_encrypted: %s)'); int bytes_received; char filename[DATA_PACKET_SIZE]; char filename_se[DATA_PACKET_SIZE]; char filename_sd[DATA_PACKET_SIZE]; char str_unencrypted[DATA_PACKET_SIZE]; FILE *fp_se, *fp_sd; /* Request filename */ debug(DBG_LV1, 'Request filename from client'); sendData(new_connection, CODE_REQUEST_FILENAME); /* receive filename */ bytes_received = recieveData(new_connection); strcpy(filename, new_connection->recv_data); sprintf(filename_se, '%s_se', filename); sprintf(filename_sd, '%s_sd', filename); debug(DBG_LV1, 'filename: %s', filename); debug(DBG_LV1, 'filename_se: %s', filename_se); debug(DBG_LV1, 'filename_sd: %s', filename_sd); fp_se = fopen(filename_se, 'w'); fp_sd = fopen(filename_sd, 'w'); debug(DBG_LV1, 'Files open'); if (fp_se == NULL || fp_sd == NULL){ debug(DBG_LV1, 'Error, closing files'); fclose(fp_se); fclose(fp_sd); errorDoExit(MSG_ERROR_CREAT_FILE); }else{ debug(DBG_LV1, 'Download file...'); /* Send code request file */ sendData(new_connection, CODE_REQUEST_FILE); bytes_received = recieveData(new_connection); /* while loop until eof */ while (strcmp(new_connection->recv_data, CODE_EOF) != 0){ debug(DBG_LV1, 'Saving: %s', new_connection->recv_data); /* save encrypted package */ fprintf(fp_se, '%s', new_connection->recv_data); /* Decencrypt package */ bzero(str_unencrypted, DATA_PACKET_SIZE); strdecrypt(new_connection->recv_data, str_unencrypted); debug(DBG_LV1, 'Decrypt: %s\n', new_connection->recv_data); /* Save unecrypted package */ debug(DBG_LV1, 'DECRYPT: %s', str_unencrypted); fprintf(fp_sd, '%s', str_unencrypted); debug(DBG_LV1, 'Sending OK...'); /*send ok */ sendData(new_connection, CODE_OK); bytes_received = recieveData(new_connection); } } fclose(fp_se); fclose(fp_sd); return 0; } /** * Decrypt string */ int strdecrypt(const char* str_in, char* str_out){ debug(DBG_LV0, 'strdencrypt(str_in: %s)', str_in); int i, j; int i_cipher, i_key, i_temp; char str_key[DATA_PACKET_SIZE]; strcpy(str_key, ENCRYPTION_KEY); char char_temp; for (i = 0, j = 0; i < strlen(str_in); ++i, ++j){ i_cipher = str_in[i] - CHAR_CIPHER_A; i_key = str_key[j] - CHAR_KEY_A; i_temp = i_cipher - i_key; debug(DBG_LV1, 'Ci([%c]%d): %d, Ki([%c]%d): %d, Ci - Ki: %d', str_in[i], i, i_cipher, str_key[j], j, i_key, i_temp); if (i_temp > -1){ //COMMON KNOWN DECRYPT ALGORIGHTM i_temp = ((i_temp) % 26); }else{ //DECRYPT ALGORITHM FOR UNCOMMON CASES WHERE I_TEMP IS NEGATIVE i_temp = ((i_temp + 26) % 26); } char_temp = i_temp + CHAR_PLAIN_A; if (isalpha(char_temp)){ str_out[i] = char_temp; }else{ str_out[i] = '\0'; } if ( (j + 1) >= strlen(str_key)) j = -1; } return 0; }
The following is the code for the client.
cli.c
/** * Assignment: 1 * Course: CS458 * Author: Alejandro G. Carlstein * Description: Transfer Encrypted File Client */ #include 'default.h' #define DEFAULT_HOST 'localhost' #define EXIT_PROGRAM 0 #define DONT_EXIT_PROGRAM 1 #define CMD_QUIT 'quit' #define CMD_HELP 'help' #define CMD_LS 'ls' #define CMD_LLS 'lls' #define CMD_LPWD 'lpwd' #define CMD_PUT 'put' #define MSG_DISPLAY_MENU 'User help:\n'\ 'help - Display help option\n'\ 'lls - Display local directory list contents\n'\ 'lpwd - Display local current directory\n'\ 'put - Transfer local file to server\n'\ ' put <file to transfer>\n'\ 'quit - Quit program\n' #define MSG_ERROR_UNKNOWN_COMMAND '[X] Command not recognized: %s\n' #define MSG_ERROR_GETTING_HOSTNAME 'Couln't get hostname!' #define MSG_ERROR_SERVER_DISCONNECTED 'Server disconnected...\n' enum TOKENS{ TOKEN_COMMAND, TOKEN_FILENAME, MAX_TOKENS }; struct Connection{ int sock; int bytes_received; int port_number; char send_data[DATA_PACKET_SIZE]; char recv_data[DATA_PACKET_SIZE]; struct hostent *host; struct sockaddr_in server_addr; }; void getConnection(struct Connection *new_connection, char *hostname, int port_number); void menuDriver(struct Connection *new_connection); int receiveData(struct Connection *new_connection); int sendData(struct Connection* new_connection, const char* data); void handShake(struct Connection* new_connection); void promptUser(char* tokens[]); void displayHelp(void); void displayLocalListDirectoryContents(void); void printNameCurrentDirectory(void); void receiveListDirectoryContents(struct Connection *new_connection); void putFileOnServer(struct Connection *new_connection, const char* filename); int strencrypt(const char* str_in, char* str_out); /** * MAIN */ int main(int argc, char* argv[]){ debug(DBG_LV0, 'argc: %d', argc); int i; int port_number = (argc >= 3 ) ? atoi(argv[2]) : DEFAULT_PORT; char* host_name = (argc >= 2) ? argv[1] : DEFAULT_HOST; struct Connection connection; for(i = 0; i < argc; ++i) debug(DBG_LV0, 'argv[%d]: %s', i, argv[i]); if (argc > 3) errorDoExit(MSG_PORT_NUMBER_ONLY, argv[0]); debug(DBG_LV1, 'host: %s', host_name); getConnection(&connection, host_name, port_number); handShake(&connection); menuDriver(&connection); return 0; } /** * Driver menu */ void menuDriver(struct Connection *new_connection){ debug(DBG_LV0, 'menuDriver()'); short doExit = DONT_EXIT_PROGRAM; int i; char* tokens[MAX_TOKENS] = {NULL, NULL}; char command[DATA_PACKET_SIZE]; char filename[DATA_PACKET_SIZE]; while(doExit){ promptUser(tokens); for (i = 0; DBG_LV1 && i < MAX_TOKENS; ++i) debug(DBG_LV1, 'TOKEN[%d]: %s', i, tokens[i]); /* Must copy string to work on SunOS */ if (tokens[TOKEN_COMMAND] != NULL){ strcpy(command, tokens[TOKEN_COMMAND]); debug(DBG_LV1, '[Command: %s]', command); } if (tokens[TOKEN_FILENAME] != NULL){ strcpy(filename, tokens[TOKEN_FILENAME]); debug(DBG_LV1, '[Filename: %s]', filename); } /* MENU */ if (strcmp(command, CMD_QUIT) == 0){ debug(DBG_LV1, 'COMMAND> %s: ', CMD_QUIT); close(new_connection->sock); printf('Bye Bye\n'); doExit = EXIT_PROGRAM; }else if (strcmp(command, 'help') == 0){ debug(DBG_LV1, 'COMMAND> %s ', CMD_HELP); displayHelp(); }else if (strcmp(command, CMD_LLS) == 0){ debug(DBG_LV1, 'COMMAND> %s ', CMD_LLS); displayLocalListDirectoryContents(); }else if (strcmp(command, CMD_LLS) == 0){ debug(DBG_LV1, 'COMMAND> %s ', CMD_LLS); displayLocalListDirectoryContents(); }else if (strcmp(command, CMD_LS) == 0){ debug(DBG_LV1, 'COMMAND> %s ', CMD_LS); receiveListDirectoryContents(new_connection); }else if (strcmp(command, CMD_LPWD) == 0){ debug(DBG_LV1, 'COMMAND> %s ', CMD_LPWD); printNameCurrentDirectory(); }else if (strcmp(command, CMD_PUT) == 0){ debug(DBG_LV1, 'COMMAND> %s ', CMD_PUT); putFileOnServer(new_connection, filename); }else{ printf(MSG_ERROR_UNKNOWN_COMMAND, command); } } } /** * Obtain connection with server */ void getConnection(struct Connection *new_connection, char *hostname, int port_number){ debug(DBG_LV0, 'getConnection(hostname: %s, port_number: %d)', hostname, port_number); if ((new_connection->host = gethostbyname(hostname)) == NULL) errorDoExit(MSG_ERROR_GETTING_HOSTNAME); new_connection->port_number = port_number; if ((new_connection->sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) errorDoExit(MSG_ERR_COULDNT_SOCKET, new_connection->sock); debug(DBG_LV1, 'Got socket!'); new_connection->server_addr.sin_family = AF_INET; debug(DBG_LV1,'sin_family'); new_connection->server_addr.sin_port = htons(port_number); debug(DBG_LV1,'sin_port'); new_connection->server_addr.sin_addr = *((struct in_addr *)new_connection->host->h_addr); debug(DBG_LV1, 'sin_addr'); // bzero() is used only for setting the values to zero bzero(&(new_connection->server_addr.sin_zero), NUM_BYTES); debug(DBG_LV1,'sin_zero'); if (connect(new_connection->sock, (struct sockaddr *)&new_connection->server_addr, sizeof(struct sockaddr)) == -1) errorDoExit(MSG_ERR_COULDNT_CONNECT); debug(DBG_LV1, 'Got connection!'); } /** * Receive data * @Return: Number of bytes received */ int receiveData(struct Connection *new_connection){ debug(DBG_LV0, 'receiveData()'); bzero(new_connection->recv_data, DATA_PACKET_SIZE); int bytes_received = recv(new_connection->sock, new_connection->recv_data, DATA_PACKET_SIZE, 0); if(bytes_received < 1){ close(new_connection->sock); if(bytes_received == 0){ close(new_connection->sock); printf(MSG_ERROR_SERVER_DISCONNECTED); errorDoExit(MSG_ERR_CONNECTION_FAIL); }else{ errorDoExit(MSG_ERR_RECEIVING_DATA); } } debug(DBG_LV1, 'Received (%d): %s', strlen(new_connection->recv_data), new_connection->recv_data); new_connection->bytes_received = bytes_received; new_connection->recv_data[bytes_received] = '\0'; return bytes_received; } /** * Send data * @Return: Number of bytes sended */ int sendData(struct Connection* new_connection, const char* data){ debug(DBG_LV0, 'sendData(%s)', data); int data_length; bzero(new_connection->send_data, DATA_PACKET_SIZE); strcpy(new_connection->send_data, data); data_length = strlen(new_connection->send_data); if (send(new_connection->sock, new_connection->send_data, data_length, 0) != data_length){ close(new_connection->sock); errorDoExit(MSG_ERR_SENDING_DATA); } return data_length; } /** * Hand shake with the server to verify own protocol */ void handShake(struct Connection* new_connection){ debug(DBG_LV0, 'handShake()'); debug(DBG_LV1, 'Sending HELLO message...'); sendData(new_connection, CODE_HELLO); debug(DBG_LV1, 'Getting WELCOME message...'); receiveData(new_connection); if (strcmp(new_connection->recv_data, CODE_WELCOME) > -1){ debug(DBG_LV1, 'Got WELCOME!'); debug(DBG_LV1, 'Request server name'); sendData(new_connection, CODE_REQ_SERVER_NAME); receiveData(new_connection); printf('Server Name: %s\n', new_connection->recv_data); }else{ errorDoExit(MSG_ERR_WRONG_PROTOCOL); } } /** * Prompt user for input */ void promptUser(char* tokens[]){ char str_input[DATA_PACKET_SIZE]; char *p; int i; printf('\nftp> '); fgets(str_input, DATA_PACKET_SIZE, stdin); p = strtok(str_input, ' \n'); for (i = 0; p != NULL; (p = strtok(NULL, ' \n')), i++) tokens[i] = p; } /** * Display help message */ void displayHelp(void){ debug(DBG_LV0, 'displayHelp()'); printf(MSG_DISPLAY_MENU); } /** * Display local list directory contents */ void displayLocalListDirectoryContents(void){ debug(DBG_LV0, 'void displayLocalListDirectoryContents()'); struct dirent *dirent_struct_ptr; DIR *directory_stream_ptr; if ((directory_stream_ptr = opendir('./')) != NULL){ printNameCurrentDirectory(); while ((dirent_struct_ptr = readdir(directory_stream_ptr))){ printf(' %s\n',dirent_struct_ptr->d_name); } }else{ errorDoExit(MSG_ERR_NO_DIR_STREAM); } } /** * Print the name of the current directory */ void printNameCurrentDirectory(void){ debug(DBG_LV0, 'void printNameCurrentDirectory()'); long size; char *buf; char *ptr; size = pathconf('.', _PC_PATH_MAX); if ((buf = (char *)malloc((size_t)size)) != NULL){ ptr = getcwd(buf, (size_t)size); }else{ errorDoExit('Could not obtain the current directory'); } printf('Current Directory: %s\n', ptr); } /** * Receive the list of directory contents from the server */ void receiveListDirectoryContents(struct Connection *new_connection){ debug(DBG_LV0, 'receiveListDirectoryContents()'); sendData(new_connection, CODE_LS); receiveData(new_connection); while (strcmp(new_connection->recv_data, CODE_EOF) != 0){ if (strcmp(new_connection->recv_data, CODE_ERROR_LS) == 0){ fprintf(stderr, 'Couldn't read list directory contents!\n'); break; }else{ printf('%s\n', new_connection->recv_data); sendData(new_connection, CODE_OK); } receiveData(new_connection); } } /** * Put an encrypted file on the server */ void putFileOnServer(struct Connection *new_connection, const char* filename){ debug(DBG_LV0, 'void putFileOnServer(filename: %s)', filename); char str_filename[DATA_PACKET_SIZE]; char filename_ce[DATA_PACKET_SIZE]; char str_in_file[DATA_PACKET_SIZE]; char str_in_file_encrypt[DATA_PACKET_SIZE]; FILE *fp, *fp_ce; strcpy(str_filename, filename); debug(DBG_LV1, 'str_filename: %s', str_filename); sprintf(filename_ce, '%s_ce', str_filename); debug(DBG_LV1, 'filename_ce: %s', filename_ce); debug(DBG_LV1, 'OPEN FILE TO READ'); fp = fopen(str_filename, 'r'); debug(DBG_LV1, 'OPEN FILE TO WRITE'); fp_ce = fopen(filename_ce, 'w'); if (fp == NULL || fp_ce == NULL){ fclose(fp_ce); fclose(fp); errorDoExit('Couldn't open file'); }else{ /* Send PUT code to server */ sendData(new_connection, CODE_PUT); debug(DBG_LV0, 'Waiting for CODE_REQUEST_FILENAME'); /* Receive filename request form server */ receiveData(new_connection); if (strcmp(new_connection->recv_data, CODE_REQUEST_FILENAME) == 0){ debug(DBG_LV0, 'Send filename'); /* Send filename to server */ sendData(new_connection, str_filename); /* Receive request to send file */ receiveData(new_connection); if (strcmp(new_connection->recv_data, CODE_REQUEST_FILE) == 0){ printf('Sending file: %s.\n', filename); /* Encrypt file */ while(fgets(str_in_file, DATA_PACKET_SIZE, fp) != NULL){ debug(DBG_LV2, 'Reading (Len: %d): %s', strlen(str_in_file), str_in_file); /* encrypt package */ strencrypt(str_in_file, str_in_file_encrypt); /* Save it in <filename>_ce */ fprintf(fp_ce, '%s', str_in_file_encrypt); /* send packages */ sendData(new_connection, str_in_file_encrypt); /* Waiting for ok */ receiveData(new_connection); if (strcmp(new_connection->recv_data, CODE_OK) == 0){ printf('OK'); }else{ errorDoExit('Wrong protocol - Waiting OK'); } } sendData(new_connection, CODE_EOF); }else{ errorDoExit('Wrong protocol - Waiting request for file '); } }else{ errorDoExit('Wrong protocol - Waiting for request of filename'); } } fclose(fp); fclose(fp_ce); } /** * Encrypt the string using key * @Return: Number of bytes encrypted */ int strencrypt(const char* str_in, char* str_out){ debug(DBG_LV0, 'strencrypt(str_in: %s)', str_in); int i, j; int i_plain, i_key; char str_key[DATA_PACKET_SIZE]; strcpy(str_key, ENCRYPTION_KEY); for (i = 0, j = 0; i < strlen(str_in) - 1; ++i, ++j){ i_plain = (unsigned int)str_in[i] - CHAR_PLAIN_A; i_key = (unsigned int)str_key[j] - CHAR_KEY_A; str_out[i] = (char)((i_plain + i_key) % 26 + CHAR_CIPHER_A); debug(DBG_LV1, '(str_out: %d) [%c:%d] = (str_in:%d)[%c:%d], (key:%d)[%c:%d]', i, str_out[i], (int)str_out[i], i, str_in[i], (int) str_in[i], j, str_key[j], (int)str_key[j]); if ( (j + 1) >= strlen(str_key)) j = -1; } return strlen(str_in); }
When I wrote the code, I was following certain guidelines. As you may think the code could be written better. I agree.
In case you have any questions about the code please post them. I will try to answer you as soon as possible.
© 2010, Alejandro G. Carlstein Ramos Mejia. All rights reserved.