Description
Objective: In this assignment, you have to implement a simplified version of the file transfer protocol. The subset of the commands that you have to implement is small, FTP has a much richer functionality. Even within this subset, we have modified them to make things easily understandable and simpler. However, the focus in this assignment is to implement something exactly from the specifications given. Problem Statement: In FTP, there are two separate connections made – a control connection used to send FTP commands and responses, and a data connection for sending and receiving data. The server waits on a predefined control port, and the control connection is made by the client. There are default data ports defined for both server and client; connections can be made to these ports to transfer data. The client side default data port can be changed to any port by the client and the server can be informed about this by the FTP PORT command (Recollect the concept of Active FTP connections that we had discussed in the class). However, to keep things simple, we will not allow the default port to be changed in the middle of a FTP session when data transfer is going on. The control connection is kept open until the FTP session is over; however, the data connection can be created and destroyed by the server for each file transfer. More details of FTP are available in RFC 959. You have to write two C files – the FTP server ftpS.c, and the FTP client ftpC.c. The FTP server is an iterative TCP server, so it can handle only one client at a time. The server will have two processes, SC (the server’s control process) and SD (the server’s data process). The process SC will create a TCP socket S1, bind S1 to port X (to be specified later), and then wait on S1. The process SD will be forked by the process SC when a data transfer has to be made. The process SD will create a TCP socket S2 and connect to the client’s data port using it. S1 will be the control port for the server and S2 will be the data port for the server. After each transfer is over, it will close S2. S2 will be created again for the next transfer. The client will also have two processes, CC (the client’s control process) and CD (the client’s data process). The process CC will create a TCP socket C1, which will then connect to port X of the server (recall that the server’s control process SC is waiting on port X). The process CD will create a TCP socket C2, bind C2 to port Y, and then wait on C2. C1 will be the control port for the client and C2 will be the data port for the client. The basic flow of operation will be as follows. The client’s control process CC will send a command to the server’s control process SC . Each command is a text word followed by zero or more text arguments. The command and the arguments are separated by one or more spaces, and the entire string is terminated by ‘\0’. The length of the string cannot be greater than 80 characters. In response, the server’s control process will send a 3-digit integer reply code (this is the only thing sent by the server in response, no string is sent. Also, it is sent as an integer, and not as, for example, ASCII code of the digits etc.). Based on the command, the server’s control process SC may fork the server’s data process SD , which may then connect to port Y of the client (recall that the client’s data process CD is waiting on port Y), and some data transfer may take place. The server will close the data connection after every transfer is over. The details of the commands and replies are described next. Your ftpC.c should connect to the server’s control port, and just give a prompt “>” and wait for user commands. The user will type the commands (shown below) just like you do for a normal FTP client, and the commands below will be sent over the control connection. If the client receives an error code, it should print the code, along with some meaningful text message. If the client receives a non-error reply code, it should also print the code and a meaningful text message. The following commands need to be implemented. The command is shown in bold, and the arguments in italics. 1. port Y – this must be the first command sent to the server. Y is the port number of the data port at which the client waits. If any other command is sent as the first command, the server sends an error code 503, closes the connection, and returns to wait on socket S1. If the server receives it properly (checks that Y is between 1024 and 65535), it sends a reply code 200. Otherwise it sends an error code 550, closes the connection, and returns to wait on socket S1. If the client receives any error code from the server, it closes all connections and exits. 2. cd dir_name – this can be sent any time. It changes the server side directory to dir_name. If the directory change is successful, the server returns a reply code 200. Otherwise it sends an error code 501. If an error code is received, the client just prompts for the next command from the user (but does not exit). Note that the server also does not close the control connection, it just waits for the next command. 3. get file_name – This can be sent anytime after the port command. It gets the file named file_name from the server. file_name can be just a file name, in which case it must exist on the current directory in the server. Or file_name can be an absolute path name to a file (ex. /usr/home/agupta/myfile.txt). The file_name cannot be relative to the current directory or parent directory (i.e., cannot start with . or ..). The file is stored with the same name in the local directory on the client side. If any such file already exists, it is overwritten. Before the client sends the get command to the server, it should notify the process CD about the filename and the command name (get). You need to design some appropriate way of implementing this. On receiving the get command, the server first checks if the file exists and whether it can be opened for read. If the file does not exist, or if it cannot be opened for read, an error code 550 is sent to the client. If the file exists, the server first forks the process SD with the command name (get), the filename and the port Y received from the client earlier. The process SD then creates a socket S2 and opens a data connection to port Y of client using socket S2, transfers the file, closes the connection and exits. It then notifies the server process SC that the transfer is over. It should also notify the process SC if some error occurs during transmission. You need to design some appropriate way of implementing this communication between the two processes. If the transfer is successful, the server sends the reply code 250 to the client over the control connection; else it sends an error code 550. The server waits for the next command after sending the reply/error code. The client’s CD process, on finding that the server’s SD process has closed the connection, closes its end of the connection and exits (you will need to design some appropriate way of implementing this communication between the two processes so that the client process closes the connection and exits only after the server process has done so). If an error code is received, the client just prompts for the next command from the user (and does not exit). 4. put file_name – This can be sent anytime after the port command. It puts the file named file_name from the local directory of the client to the local directory of the server. The file_name can be just a file name, no path is allowed; so the file must exist on the local directory of the client. The file is stored with the same name in the local directory on the server side. If any such file already exists, it is overwritten. Before the client sends the put command to the server, it should notify the process CD about the file name and the command name (put). You need to design some appropriate way of implementing this. On receiving the put command, the server first forks the process SD of the command name (put), the filename and the port Y received from the client earlier. The process SD then creates a socket S2 and then opens a data connection to port Y of client using socket S2, and waits to read the file. On the client side, the process CD , which was waiting on the socket C2, now comes out of the accept call (as the server has connected to it). It then sees the command is put, reads the file and sends it to the server over the data connection. The server’s SD process, on receiving the file, stores it with the same name in the local directory and closes the data connection. It then notifies the server process SC that the transfer is over and exits. It should also notify the process SC if some error occurs during transmission. You need to design some appropriate way of implementing this communication between the two processes. If the transfer is successful, the server sends the reply code 250 to the client over the control connection; else it sends an error code 550. The server’s control process waits for the next command after sending the reply/error code. The client’s CD process, on finding that the server’s SD process has closed the connection, closes its end of the connection and exits. (you will need to design some appropriate way of implementing this communication between the two processes so that the client process closes the connection only after the server process has done so). If an error code is received, the client just prompts for the next command from the user (and does not exit). 5. quit – The server, on receiving this command, sends a reply code 421 and closes the connections with the client, and goes back to wait on the socket S1 for the next client. The client, on receiving this reply code, closes connections and exits. In addition to the above, the following two checks are always done by the server. If a command is received that is not one of the above commands, the server sends an error code 502. It will then wait for the next command from the client. Also, if a server receives a valid command, but an invalid argument (for ex., the get command is sent with two filenames etc.), it sends the error code 501 and then waits for the next command from the client. Also remember that if the client receives an error code, it should print the code, along with some meaningful text message, before it does anything else (for ex., closing a connection, or sending the next command etc.). Similarly, if the client receives a non-error reply code, it should also print the code and a meaningful txt message before it does anything else. You can also assume that the port command is not sent more than once by the client. So you do not need to check for this. The file transfer does not happen in one step, as the file may be arbitrarily long. The file is sent in binary mode as a sequence of bytes, block by block. Each block is prefixed with a header containing two fields, a character (‘L’ indicates it is the last block of the file, any other character indicates it is not the last block of the file), and a 16-bit integer (short) indicating the length in bytes of the data in this block sent (not including the header bytes). So a file transfer is over after a block with ‘L’ in the character field is received. Note that this check is sufficient for detecting the end of the file, as TCP ensures that data bytes are received in order. Thus, the sender of the file will read the file block by block (what will be the block size?), prefix it with the header, and send it. Use port X = 50000, and Y = 55000. Submit only the two C files. Submission Instruction: As discussed in the problem statement, you should write twq C programs. Keep these two files in a single compressed folder (zip or tar.gz) having the name _Assignment4.zip or _Assignment4.tar.gz. Upload this compressed folder at Moodle course page by the deadline (07 Feb 2019 2:00 PM).