- 19 November 2018: add reminder that QUIT should not quit the server and cleanup hint about CRLF
- 28 November 2018: add note about type support for LIST; we do not require transforming newlines into CRLFs for this
- 2 December 2018: Edit hints to point to sockets slides, add general note on what I’d do first/last
Late policy note: In order to ensure that we can get this assignment graded in time, late submissions after the final exam will not be accepted.
Download the skeleton code that includes a Makefile template that produces an
ftp-serverbinary that does nothing but accept a port number from the command-line and print out a message about nothing being implemented. (The skeleton also includes a test program for a particular corner case, described below.)
- In C or C++, implement an FTP server that supports FTP as described in RFC 959 implementing
at least the following commands:
- USER (which should not require a password or any particular user name)
(Note that your implementation of some of these commands may be trivial.)
If you choose, you may implement additional commands. For any command you do not implement, you must return a response indicating that the command is not implemented.
- Your server must bind to the port number specified on the command line and always bind to 127.0.0.1 (IPv4 localhost).
- The root directory and default directory of your server should be the current working directory when it is executed, so storing or retrieving either
fooshould access the
foofile in the server’s current working directory.
LISTcommand should send the result of running
ls -lon the given directory if it exists or result in an error otherwise.
- You do not need to support RECORD or PAGE structure (only FILE). A client using the
STRU Rcommand to change from FILE mode should result in the response “504 Command not implemented for that parameter”.
- You do not need to support any transmission mode besides STREAM. (You may give an error if a client tries to set another transmission mode.)
- Except for the
LISTcommand, you only need to support the Image file type (“binary mode”); that is, you will return byte-for-byte copies of files, rather than havdling the
NVT-ASCII(“text mode”) representation. If a client attempts at
RETRwithout first switching the binary mode, it should result in the response “451 Requested action aborted: local error in processing”. (For
LIST, you need to allow transfers with the ASCII Non-print type, but we will not check whether you transform newlines into CRLFs.)
- Your server only needs to handle one active client at a time.
- You server only needs to support IPv4. When/if using
getaddrinfo, I’d recommend setting
AF_INETin the hints.
- You may assume that FTP commands are no longer than 4096 bytes.
- You may reject any pathnames containing “..” to prevent clients from accessing things outside the server’s current working directory. (It is okay if you reject pathnames which have “..” in the middle of a filename like “/foo..bar”.)
- Create a .tar.gz archive, like the one
make submitwould create and submit via the usual submission site.
RFC 959 — the official specification. Sections 4, 5 and 6 are most useful. Section 7 has examples.
List of raw FTP commands at http://www.nsftools.com/tips/RawFTP.htm
the POSIX documentation — search for individual functions like
We suggest primarily testing with an FTP client like the
ftpcommand in your VM. You can run a command line
ftp 127.0.0.1 PORT-NUMBER
where PORT-NUMBER is the same value you passed as an argument to your server program.
You should be able to do at least the following in the FTP client: (This list may not be exhaustive.)
- Create a directory
- Get an error when trying to create a directory that already exists.
- After setting binary mode, store a file
- After setting binary mode, store a file that contains NUL characters in its contents
- After setting binary mode, retrieve a file
- After setting binary mode, retrieve a file that contains NUL characters in its contents
- After setting binary mode, fail to retrieve a file that doesn’t exist
- List the root directory by running
lswithout an argument
- List the root directory by running
- List a subdirectory by running
- Restart the client and connect again to the server after quitting (without restarting the server)
Note that you will need to test your server with a port number higher than 1024.
We have supplied, with the skeleton code, a test-partial-reads program which connects to your server and sends the following commands
USER foo MKD testSplitName QUIT
MKDcommand is written by writing
MKD testSplit, waiting one second, then writing
Name<CRLF>. This can help test whether your server handles the case where
readreturns less than expected in the control channel. (In practice, this would probably only be a problem for much longer commands or if someone were manually typing in commands or if you wanted to add support for a client sending multiple commands without waiting for replies to those commands.)
General advice on order of implementation
(This does not represent the only, nor perhaps the best approach.)
I would suggest first getting the server working enough that the FTP client can connect and you can parse and reply to the commands it sends with a not implemented message.
Commands that require a data connection are probably the hardest to implement, so I would save them for last.
LISTis probably the most complex command to implement.
Dealing with partial reads
- When using
read, it is possible that you will read less than a line or parts of multiple lines. To deal with this, I recommend keeping a buffer of bytes you’ve read but not processed, searching that buffer for the newline character sequence, and, as long newlines aren’t present, calling read again to add to the buffer.
Select specification details
- Note that lines sent over the network typically end with a CRLF, which is a two byte sequence.
mkdir()is the POSIX functions creating and removing directories respectively
- QUIT should not exit the server, only close the current connection.