/**************** * * * Homework 2 * ********************************************************************* * Server FTP program ******************************************************************** * NOTE: Starting homework #2, add more comments here describing * the overall function performed by server ftp program * This includes, the list of ftp commands processed by server ftp. ******************************************************************** */ #include #include #include #include #include #include #include #include #define SERVER_FTP_PORT 5472 /* Error and OK codes */ #define OK 0 #define ER_INVALID_HOST_NAME -1 #define ER_CREATE_SOCKET_FAILED -2 #define ER_BIND_FAILED -3 #define ER_CONNECT_FAILED -4 #define ER_SEND_FAILED -5 #define ER_RECEIVE_FAILED -6 #define ER_ACCEPT_FAILED -7 /* Function prototypes */ int svcInitServer(int *s); int sendMessage (int s, char *msg, int msgSize); int receiveMessage(int s, char *buffer, int bufferSize, int *msgSize); /* List of all global variables */ char userCmd[1024]; char userCmdCopy[1024]; /* user typed ftp command line received from client */ char *cmd; /* ftp command (without argument) extracted from userCmd */ char *argument; /* argument (without ftp command) extracted from userCmd */ char replyMsg[1024]; /* buffer to send reply message to client */ char users[1024]; /* created list of users*/ char user[1024]; /*created user*/ char pass[1024]; /* created password*/ char *usersList[]={"Olga", "Jake", "Melissa", "Philip", "Mary"}; //the list of usernames char *passwList[]={"passw0", "passw1","passw2","passw3", "passw4"};//the list of users' passwords int loggedIn = -1; //index showed no current user is logged in int userIndex = -1;//current user char buffer[1024]; /*created buffer*/ FILE *myFile; #define NO_USER -1 #define LOGGED_IN 1 #define LOGGED_OUT 0 /* * main * * Function to listen for connection request from client * Receive ftp command one at a time from client * Process received command * Send a reply message to the client after processing the command with staus of * performing (completing) the command * On receiving QUIT ftp command, send reply to client and then close all sockets * * Parameters * argc - Count of number of arguments passed to main (input) * argv - Array of pointer to input parameters to main (input) * It is not required to pass any parameter to main * Can use it if needed. * * Return status * 0 - Successful execution until QUIT command from client * ER_ACCEPT_FAILED - Accepting client connection request failed * N - Failed stauts, value of N depends on the command processed */ int main( int argc, char *argv[] ) { /* List of local varibale */ int msgSize; /* Size of msg received in octets (bytes) */ int listenSocket; /* listening server ftp socket for client connect request */ int ccSocket; /* Control connection socket - to be used in all client communication */ int status; /* * NOTE: without \n at the end of format string in printf, * UNIX will buffer (not flush) * output to display and you will not see it on monitor. */ printf("Started execution of server ftp.\n"); /*initialize server ftp*/ printf("Initialize ftp server.\n"); /* changed text */ status=svcInitServer(&listenSocket); if(status != 0) { printf("Exiting server ftp due to svcInitServer returned error.\n"); exit(status); } printf("FTP server is waiting to accept connection.\n"); /* wait until connection request comes from client ftp */ ccSocket = accept(listenSocket, NULL, NULL); printf("Came out of accept() function \n"); if(ccSocket < 0) { perror("Cannot accept connection:"); printf("Server ftp is terminating after closing listen socket.\n"); close(listenSocket); /* close listen socket */ return (ER_ACCEPT_FAILED); // error exist } printf("Connected to client, calling receiveMsg to get ftp cmd from client.\n"); /* Receive and process ftp commands from client until quit command. * On receiving quit command, send reply to client and * then close the control connection socket "ccSocket". */ do { /* Receive client ftp commands until */ status=receiveMessage(ccSocket, userCmd, sizeof(userCmd), &msgSize); if(status < 0) { printf("Receive message failed. Closing control connection.\n"); printf("Server ftp is terminating.\n"); break; } /* * Starting Homework#2 program to process all ftp command must be added here. * See Homework#2 for list of ftp commands to implement. */ strcpy (userCmdCopy, userCmd); cmd = strtok (userCmdCopy, " "); argument = strtok (NULL, " "); printf("The user command is: %s.\n", cmd); printf("The argument of user command is: %s.\n", argument ); /******************** Implementation of all FTP Commands******************/ /************************** USER COMMAND *******************************/ if (strcmp(cmd, "user")==0) { for (int i = 0; i < sizeof(usersList)/sizeof(char*); i++) { if (strcmp(usersList[i], argument)== 0)//based on C Notes { userIndex = i; loggedIn = LOGGED_OUT;//0 strcpy (replyMsg, "331 User name Okay, need password.\n"); // from http://www.ietf.org/rfc/rfc0959.txt break; } } if (userIndex < 0) { strcpy (replyMsg, "530 User doesn't exist.\n"); } if (strcmp(cmd,"user")==0) { loggedIn = NO_USER;//-1 userIndex = -1; //no current user is logged in if (strcmp(argument, "")==0) { strcpy (replyMsg, "501 No username entered.\n"); userIndex = -1;//no current user is logged in } } } /* { if (strcmp(argument, "")==0) { loggedIn = NO_USER; userIndex = -1;//no current user is logged in strcpy (replyMsg, "501 No username entered.\n"); } else { for (int i = 0; i < sizeof(usersList)/sizeof(char*); i++) { if (strcmp(usersList[i], argument)== 0)//based on C Notes { userIndex = i; loggedIn = LOGGED_OUT; strcpy (replyMsg, "331 User name Okay, need password.\n"); // from http://www.ietf.org/rfc/rfc0959.txt break; } if (userIndex < 0) { strcpy (replyMsg, "530 User doesn't exist.\n"); } } } */ /************************* PASS COMMAND **************************/ else if (strcmp(cmd, "pass")== 0) { if (strcmp(passwList[userIndex], argument)==0) { loggedIn = LOGGED_IN; strcpy (replyMsg, "230 User is successfully logged in.\n"); //user provides a correct password } if (strcmp(argument, "")==0) //password is not provided { strcpy(replyMsg, "501 Password is not provided.\n");//good } else if (loggedIn == NO_USER || userIndex<0) { strcpy(replyMsg, "503 Wrong command usage.Type 'pass '\n");//good } else { loggedIn = LOGGED_OUT; if (userIndex >=0) { strcpy(replyMsg, "530 Invalid password.\n"); break; } } } /* else if (strcmp (cmd, "pass") == 0) { memset (replyMsg, '\0', sizeof(replyMsg)); if (pass[0]=='\0') sprintf(replyMsg, "332 Need account for login.\n");//http://www.ietf.org/rfc/rfc0959.txt if (strcmp(argument, pass) == 0) sprintf(replyMsg, "Password invalid."); } */ /*************************** HELP COMMAND ************************/ else if (strcmp(cmd, "help") ==0) { strcpy (replyMsg, "Commands\t Syntax\t\t How to use\n" "user \t log in as user \t username user\n" "pass \t log in password \t password pass\n" "mkdir \t make directories \t mkdir dir\n" "rmdir \t remove directories \t rmdir dir\n" "cd \t change directory \t cd dir\n" "dele \t remove a file \t delefile\n" "pwd \t print directory \t pwd\n" "ls \t print files in dir \t ls\n" "stat \t print stats \t stat \n" ); } /********** STAT COMMAND *********/ else if (strcmp(cmd, "stat")==0 || strcmp(cmd, "status")==0) { strcpy (replyMsg, "200 Command is Okay.Transfer mode is ASCII.\n"); } /* { memset(replyMsg, '\0', sizeof(replyMsg)); memset(buffer, '\0', sizeof(buffer)); if (strlen(argument)>0) { printf("Argument is not required for this command."); } system ("stat > /tmp/stat.txt"); myfile=fopen("/tmp/stat.txt", "r"); fread( buffer, sizeof(buffer), sizeof(char), myfile); strcpy (replyMsg, buffer); fclose(myfile); system("rm /tmp/stat.txt"); } */ /******************************* ls command ****************************/ /* List the files and subdirectories in the remote directory.*/ else if (strcmp(cmd, "ls")==0) { if (loggedIn==LOGGED_IN) { status = system("ls > /tmp/lsfile.txt"); if (status ==0) { myFile = fopen ("/tmp/lsfile.txt", "r"); } if (myFile == NULL) { strcpy (replyMsg, "451 Unable to display directory content.\n"); } else { status=fread (buffer, sizeof(buffer), sizeof(char), myFile); sprintf(replyMsg,"cmd 250 okay \n%s\n", buffer); fclose(myFile); system ("rm /tmp/lsfile.txt"); } } /******************************* pwd command **************************/ /*Print the current working directory on the remote machine*/ else if (strcmp(cmd, "pwd")==0) { if (loggedIn == LOGGED_IN) { status = system("pwd > /temp/pwdfile.txt"); if (status==0) { myFile = fopen("pwdfile.txt", "r"); if (myFile == NULL) { strcpy(replyMsg, "500 Unable to display current working directory.\n");//if file doesn't exist } else { status = fread (buffer, sizeof(buffer), sizeof(char), myFile);//read output file sprintf(replyMsg, "cmd 250 okay %s\n", buffer); fclose (myFile); //clean up system ("rm /tmp/pwd.txt"); } } } } /* else if (strcmp(cmd, "pwd")==0) { memset(buffer, '\0', sizeof(buffer));//checking if buffer is clear system ("pwd > /tmp/pwd.txt"); myFile=fopen("/tmp/pwd.txt", "r");//read the file to the buffer status=fread(buffer, sizeof(buffer), sizeof(char),myFile); sprintf(replyMsg, "cmd 250 okay %s\n", buffer); fclose(myFile); system("rm /tmp/pwd.txt"); //delete the txt file } */ /******************************* mkdir command ********************/ else if (strcmp(cmd, "mkdir")==0) { if (strcmp(argument, "")==0) //check if there is an argument { strcpy (replyMsg, "501 Syntax error in parameters or arguments.\nPlease retry with argument.\n"); } else { status=system(userCmd);//make a system call to create a new directory } if (status==0) { strcpy(replyMsg, "212 Directory status:\n The directory is successfully created.\n"); //strcat(replyMsg, argument); //strcat(replyMsg, "\".\n"); } else { strcpy(replyMsg, "500 Syntax error, command unrecognized:\n Unable to create directory.\n"); //strcat(replyMsg, argument); //strcat(replyMsg, "\".\n"); } } /****************************** rmdir command *******************************/ else if (strcmp(cmd, "rmdir") == 0) { if (strcmp(argument, "") == 0) //check if there is an argument { strcpy (replyMsg, "501 Syntax error. Change to rmdir .\n"); } else { status=system(userCmd);// make a system call to remove a directory } if (status == 0) { strcpy (replyMsg, "212 Directory status: \n The directory is successfully removed.\n"); //strcat (replyMsg, "\".\n"); } else { strcpy (replyMsg, "500 Syntax error, command unrecognized:\n Unable to remove the directory.\n"); //strcat (replyMsg, "\".\n"); } } /*********************************** dele command *************************/ /* Delete the file with the name from the remote directory.*/ else if (strcmp (cmd, "dele")== 0) { if (strcmp (argument, "")==0) //check it there is an argument { strcpy (replyMsg, "501 Syntax error in parameters or arguments.\nPlease retry: 'dele '.\n"); } else if (status == 0) // make a system call to delete the file { strcpy (replyMsg, "250 The file is successfully removed.\n" ); } else { strcpy (replyMsg, "530 Not Logged In"); } } /*********************************** cd command ***********************************/ else if (strcmp(cmd, "cd")==0) { if (loggedIn == LOGGED_IN) { if (strcmp (argument, "")==0) { status =chdir(getenv("HOME")); //getenv - get value of an environment variable strcpy(argument, "HOME directory"); strcpy(replyMsg, "250 CWD command successful. /myftpserver/dir1 is current directory.\n"); } else status=chdir(argument); if (status ==0) { strcpy (replyMsg, " 250 Current working directory changed to \""); strcat (replyMsg, argument); strcat (replyMsg, "\".\n"); } else { strcpy(replyMsg, "500 Unable to create the directory.\n"); } } } }//???? /* * ftp server sends only one reply message to the client for * each command received in this implementation. */ //strcpy(replyMsg,"200 cmd okay\n"); /* Should have appropriate reply msg starting HW2 */ status=sendMessage(ccSocket,replyMsg,strlen(replyMsg) + 1); /* Added 1 to include NULL character in */ /* the reply string strlen does not count NULL character */ if(status < 0) { break; /* exit while loop */ } } /******** QUIT COMMAND ********/ /*End the FTP session.*/ while(strcmp(cmd, "quit") != 0); printf("Closing control connection socket.\n"); close (ccSocket); /* Close client control connection socket */ printf("Closing listen socket.\n"); close(listenSocket); /*close listen socket */ printf("Exiting from server ftp main. \n"); return (status); } /* * svcInitServer * * Function to create a socket and to listen for connection request from client * using the created listen socket. * * Parameters * s - Socket to listen for connection request (output) * * Return status * OK - Successfully created listen socket and listening * ER_CREATE_SOCKET_FAILED - socket creation failed */ int svcInitServer ( int *s /*Listen socket number returned from this function */ ) { int sock; struct sockaddr_in svcAddr; int qlen; /*create a socket endpoint */ if( (sock=socket(AF_INET, SOCK_STREAM,0)) <0) { perror("cannot create socket"); return(ER_CREATE_SOCKET_FAILED); } /*initialize memory of svcAddr structure to zero. */ memset((char *)&svcAddr,0, sizeof(svcAddr)); /* initialize svcAddr to have server IP address and server listen port#. */ svcAddr.sin_family = AF_INET; svcAddr.sin_addr.s_addr=htonl(INADDR_ANY); /* server IP address */ svcAddr.sin_port=htons(SERVER_FTP_PORT); /* server listen port # */ /* bind (associate) the listen socket number with server IP and port#. * bind is a socket interface function */ if(bind(sock,(struct sockaddr *)&svcAddr,sizeof(svcAddr))<0) { perror("cannot bind"); close(sock); return(ER_BIND_FAILED); /* bind failed */ } /* * Set listen queue length to 1 outstanding connection request. * This allows 1 outstanding connect request from client to wait * while processing current connection request, which takes time. * It prevents connection request to fail and client to think server is down * when in fact server is running and busy processing connection request. */ qlen=1; /* * Listen for connection request to come from client ftp. * This is a non-blocking socket interface function call, * meaning, server ftp execution does not block by the 'listen' funcgtion call. * Call returns right away so that server can do whatever it wants. * The TCP transport layer will continuously listen for request and * accept it on behalf of server ftp when the connection requests comes. */ listen(sock,qlen); /* socket interface function call */ /* Store listen socket number to be returned in output parameter 's' */ *s=sock; return(OK); /*successful return */ } /* * sendMessage * * Function to send specified number of octet (bytes) to client ftp * * Parameters * s - Socket to be used to send msg to client (input) * msg - Pointer to character arrary containing msg to be sent (input) * msgSize - Number of bytes, including NULL, in the msg to be sent to client (input) * * Return status * OK - Msg successfully sent * ER_SEND_FAILED - Sending msg failed */ int sendMessage( int s, /* socket to be used to send msg to client */ char *msg, /* buffer having the message data */ int msgSize /* size of the message/data in bytes */ ) { int i; /* Print the message to be sent byte by byte as character */ for(i=0; i