Spring 2021 CSE30264 Programming Assignment 2 - File Transfer Protocol (FTP)


Total Points: 100 points
Goal: Program a Prototype of a FTP application using TCP
Assigned: March 3, 2021
Due: March 17, 2021 by the end of day (11:59 pm Eastern).
Grouping: To be completed by a group.
Note: This instruction is based on C/C++. The Python version is available at here.

Background

In this programming assignment, you will implement the client and server sides of a simple File Transfer Protocol (FTP) application. The file transfer itself will take place using TCP with the client determining the operation to be performed (requesting/downloading a particular file, uploading a file, showing first few lines of a file, deleting a file, creating a new directory, removing a directory, changing to a different directory, obtaining a directory listing, or closing the connection). The server should respond appropriately to the specific command. The specifics of the protocol are detailed in this document. Note: please refer to appendix A for the port number assigned to you (the same as PG1).

Protocol - Simple File Transfer

  1. Server opens the port, and goes into "wait for connection" state.
  2. Client connects to the server on the appropriate port.
  3. Server goes into "wait for operation from client" state and waits for operation command from the client.
  4. Client goes into "prompt user for operation" state and prompts user for operation.
  5. Client passes operation (DN: Download, UP: Upload, HEAD: Head of File, RM: Remove File, LS: List, MKDIR: Make Directory, RMDIR: Remove Directory, CD: Change Directory, QUIT: Quit) to server.
  6. Operation is executed as follows:
    1. DN:
      Note: Please test DN with the three test files (i.e., LargeFile.mp4, MediumFile.pdf, SmallFile.txt) discussed in the general notes.
      1. Client sends operation (DN) to download a file from the server.
      2. Client sends the length of the filename (short int) followed by the filename (character string).
      3. Server decodes what it receives, and checks to see if the file exists in its local directory.
        1. If the file exists:
          1. Server first calculates the md5 hash of the file using md5sum system utility and returns the md5 hash to the client. (Please refer to the general notes for more details about MD5 Hash.)
          2. Server also returns the size of the file to the client as a 32-bit integer in another message.
        2. If the file does not exist, server will return a negative confirmation (32-bit integer value -1). After that, the server should return to the "wait for operation from client" state.
      4. Client receives the 32-bit file length from server.
        1. Client should decode the 32-bit value.
          1. If the value is -1, user should be informed that the file does not exist on the server. Client should return to "prompt user for operation" state.
          2. If the value is not -1, save the value as the file size for later use.
      5. Server sends the file to client.
        1. Client reads md5 hash from server.
        2. Client reads "file size" bytes from server.
        3. The client saves the file to disk as "filename".
        4. The client calculates the md5 hash of the file received (using the md5sum system utility), compares it to the hash the server sent, and displays a confirmation if they match or an error if they do not.
        5. Inform user that the transfer was successful, and return to "prompt user for operation" state. The client displays throughput results and md5 hash for the transfer.

    2. UP:
      1. Client sends operation (UP) to upload a local file to a server.
      2. Client sends the length of the filename which will be sent (short int) followed by the filename (character string). Note: you can create a local file called "upload.txt" with random strings to test the UP operation.
      3. Server receives the above information, decodes filename size and filename, and acknowledges that it is ready to receive (it is up to you how to do the acknowledgment).
      4. Client replies with a 32-bit value which is the size of the file (in bytes).
      5. Server receives and decodes the 32-bit value.
        1. Server enters the loop to receive file
        2. Client sends file to server. Server reads "file size" bytes from client and saves them to disk as "filename".
        3. Server computes throughput results for the transfer and the md5 hash of the file.
        4. Server sends the throughput results and hash to the client. This information should be used by the client to inform user that the transfer was successful or not (i.e., if the hash from the server matches the hash of the local file). If the transfer was successful, client displays the throughput information and md5 hash of the transfer. Otherwise, client informs the user the transfer failed. Finally, client returns to "prompt user for operation" state.

    3. HEAD:
      1. Client sends operation (HEAD) to show the first ten lines of a file on the server.
      2. Client sends the length of the filename which will be sent (short int) followed by the filename (character string).
      3. Server receives the above information, decodes filename size and filename, and checks to see if the file exists in its local directory.
        1. If the file exists:
          1. Server reads the first ten lines of the file, and computes the size of it.
          2. Server sends the size to client as a 32-bit integer.
        2. If the file does not exist, server will return a negative confirmation (32-bit integer value -1). After that, the server should return to the "wait for operation from client" state.
      4. Client receives the 32-bit integer from server.
        1. If the value is positive, the client saves the value for later use.
        2. If the value is negative, it should inform the user that the file does not exist on the server, and return to "prompt user for operation" state.
      5. Server sends the content of the first ten lines of file to the client.
        1. Client goes into a loop to read the content of the first ten lines of the file.
        2. Client displays the content to the user, and returns to "prompt user for operation" state.

    4. RM:
      1. Client sends operation (RM) to delete a file from the server. Note: you can create a test file called "delete.txt" in the server directory to test the RM operation.
      2. Client sends the length of the filename which will be sent (short int) followed by the filename (character string).
      3. Server receives the above information, decodes filename size and filename, and checks if the file to be deleted exists or not.
        1. If the file exists, the server sends a positive confirmation (integer value 1) back to the client.
        2. If the file does not exit, the server sends a negative confirmation (integer value -1) back to the client.
      4. Client receives the confirmation from the server.
        1. If the confirmation is negative, it should inform the user that the file does not exist on the server and return to "prompt user for operation" state.
        2. If the confirmation is positive, the client further confirms if the user wants to delete the file: "Yes" to delete, "No" to ignore. The client then sends the user's confirmation (i.e., "Yes" or "No") back to the server.
          1. If the user's confirmation is "Yes", the client waits for the server to send the confirmation of file deletion.
          2. If the user's confirmation is "No", the client prints out "Delete abandoned by the user!" and returns to "prompt user for operation" state.
      5. The server waits for the delete confirmation sent by the client.
        1. If the confirmation is "Yes", the server deletes the requested file and returns an acknowledgment to the client to indicate the success or failure of file deletion operation.
        2. If the confirmation is "No", the server returns to "wait for operation from client" state.

    5. LS:
      1. Client sends operation (LS) to list the directory at the server.
      2. Server obtains listing of it's directory, including both the permission settings and the name of each file (e.g., "-rwxr-xr-x 1 netid dip 21K Aug 22 12:58 test.txt" or simply "-rwxr-xr-x test.txt" )
      3. Server computes the size of directory listing and sends the size to client as a 32-bit integer.
        1. Client receives the size, and goes into a loop to read directory listing.
        2. Once the listing is received, client displays the listing to user.
        3. Client and server return to "prompt user for operation" and "wait for operation from client" state respectively.

    6. MKDIR:
      1. Client sends operation (MKDIR) to make a directory on the server.
      2. Client sends the length of the directory name which will be sent (short int) followed by the directory name (character string).
      3. Server receives the above information, decodes directory name size and directory name, and checks if the directory to be created exists or not.
        1. If the directory exists, the server sends a negative confirmation (integer value -2) back to the client.
        2. If the directory does not exit, the server sends a positive confirmation (integer value 1) back to the client if the directory is successfully created; otherwise, the server sends a negative confirmation (integer value -1) back to the client.
      4. Client receives the confirmation from the server.
        1. If the confirmation is negative (-2), it prints out "The directory already exists on server" and returns to "prompt user for operation/wait for operation" state.
        2. If the confirmation is negative (-1), it prints out "Error in making directory" and returns to "prompt user for operation/wait for operation" state.
        3. If the confirmation is positive, the client prints out "The directory was successfully made" and returns to "prompt user for operation/wait for operation" state.

    7. RMDIR:
      1. Client sends operation (RMDIR) to remove a directory on the server. Note: Directory must be empty for RMDIR to work.
      2. Client sends the length of the directory name which will be sent (short int) followed by the directory name (character string).
      3. Server receives the above information, decodes directory name size and directory name, and checks if the directory to be deleted exists or not.
        1. If the directory exists and is empty, the server sends a positive confirmation (integer value 1) back to the client.
        2. If the directory does not exit, the server sends a negative confirmation (integer value -1) back to the client.
        3. If the directory exists and is not empty, the server sends a negative confirmation (integer value -2) back to the client.
      4. Client receives the confirmation from the server.
        1. If the confirmation is negative (-1), it prints out "The directory does not exist on server" and returns to "prompt user for operation/wait for operation" state.
        2. If the confirmation is negative (-2), it prints out "The directory is not empty" and returns to "prompt user for operation/wait for operation" state.
        3. If the confirmation is positive, the client further confirms if the user wants to delete the directory: "Yes" to delete, "No" to ignore. The client then sends the user's confirmation (i.e., "Yes" or "No") back to the server.
          1. If the user's confirmation is "Yes" the client waits for the server to send the confirmation of directory deletion.
          2. If the user's confirmation is "No" the client prints out "Delete abandoned by the user!" and returns to prompt user for operation/wait for operation state.
      5. The server waits for the delete confirmation sent by the client.
        1. If the confirmation is "Yes" the server deletes the requested directory and returns an acknowledgment to the client to indicate the success or failure of file deletion operation. (Directory must be empty in order for deletion to occur).
          1. If the acknowledgment is positive, the client prints out "Directory deleted" and returns to "prompt user for operation" state.
          2. If the acknowledgment is negative, the client prints out "Failed to delete directory" and returns to "prompt user for operation" state.
        2. If the confirmation is "No" the server returns to "wait for operation" state.

    8. CD:
      1. Client sends operation (CD) to change to a different directory on the server. Note: You can use CD followed by LS to verify that CD worked successfully.
      2. Client sends the length of the directory name which will be sent (short int) followed by the directory name (character string).
      3. Server receives the above information, decodes directory name size and directory name, and checks if the directory to be changed to exists or not.
        1. If the directory exists, the server sends a positive confirmation (integer value 1) back to the client if it successfully changed directories; otherwise, the server sends a negative confirmation (integer value -1) back to the client.
        2. If the directory does not exist, the server sends a negative confirmation (integer value -2) back to the client.
      4. Client receives the confirmation from the server.
        1. If the confirmation is negative (-2), it prints out "The directory does not exist on server" and returns to "prompt user for operation/wait for operation" state.
        2. If the confirmation is negative (-1), it prints out "Error in changing directory" and returns to "prompt user for operation/wait for operation" state.
        3. If the confirmation is positive, the client prints out "Changed current directory" and returns to "prompt user for operation/wait for operation" state.

    9. QUIT:
      1. Client sends operation (QUIT) to exit.
      2. Client closes the socket, and exits.
      3. Server closes the socket and goes back to the "wait for connection" state.
      4. Client informs user that the session has been closed.

    Note: If it is not explicitly specified, the client and server will return to "prompt user for operation" and "wait for operation from client" state respectively after a successful operation and wait for the next operation.
Important Hint: When uploading and downloading large files, make sure to take into consideration the return value from reading the socket. The system may not provide the same number of bytes as you requested to fill the buffer!

General Notes