Contents
Changelog:
- 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.
Your Task
-
Download the skeleton code that includes a Makefile template that produces an
ftp-server
binary 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)
- QUIT
- PORT
- TYPE
- MODE
- STRU
- STOR
- RETR
- NOOP
- LIST
- MKD
(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.
In addition:
- 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
/foo
orfoo
should access thefoo
file in the server’s current working directory. - The
LIST
command should send the result of runningls -l
on 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 R
command 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
LIST
command, 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 theNVT-ASCII
(“text mode”) representation. If a client attempts atSTOR
orRETR
without first switching the binary mode, it should result in the response “451 Requested action aborted: local error in processing”. (ForLIST
, 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 settingai_family
toAF_INET
in 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 submit
would create and submit via the usual submission site.
FTP References
-
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
Sockets References
-
the POSIX documentation — search for individual functions like
socket
,getaddrinfo
,bind
,accept
,listen
. -
this example echo server and example echo client.
-
the slides and lecture recording from 15 November
Hints
Testing
-
We suggest primarily testing with an FTP client like the
ftp
command in your VM. You can run a command lineftp 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
ls
without an argument - List the root directory by running
ls /
- List a subdirectory by running
ls the-subdir
orls /the-subdir
- Quit
- 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.
test-partial-reads
-
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
but the
MKD
command is written by writingMKD testSplit
, waiting one second, then writingName<CRLF>
. This can help test whether your server handles the case whereread
returns 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.
LIST
is 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.
make directory
mkdir()
is the POSIX functions creating and removing directories respectively
on QUIT
- QUIT should not exit the server, only close the current connection.