HW 3: ftpread
Ftpread
CS 494/594 Homework Bart Massey
In this assignment, you will write ftpread
, an FTP reader
client in C in the style of the tftpread
program written
in class.
FTP is described in RFC 959. You should start by reading and thoroughly understanding the relevant portions of this RFC.
Your client will start by making a TCP "control" connection
to the FTP daemon on a host specified on the command line.
You will then establish a TCP "data" connection to retrieve
a file at a path specified on the command line, writing the
retrieved file to standard output as tftpread
does.
Your client must authenticate itself with username "anonymous" (spelled correctly) and your email address as the "password", as per the specifications for anonymous FTP.
Your client must be able to retrieve a file in binary stream mode. There are two basic types of retrieve: "active" and "passive". In an active FTP retrieve, you listen for a data connection, then retrieve the file from that data connection when the server connects to you. In a passive FTP retrieve, you connect to a port specified by the server and retrieve the data from there.
For the purposes of this assignment, you are successful when
your ftpread
program can retrieve the file hello.txt
from the host svcs.cs.pdx.edu
using FTP. CS 494 students
may choose to do only an active retrieve. The tftpread
of
CS 594 students must be able to do either an active or
passive retrieve, as specified on the command line.
Hints
This is a fairly challenging assignment. Here's some hints to make it easier.
tftpread
You may want to start with
tftpread,
available on my Github
(https://github.com/BartMassey/).
It contains a bunch of code that is similar to code you will
need for ftpread
. If you cannot use git, note that there is
a "ZIP" button near the top left of the page that will create
a ZIP archive to download.
fdopen()
You will be sending a lot of commands, and parsing a lot of
responses. One good trick is to use fdopen()
to turn the
file descriptor of your socket into a FILE *
suitable for
use with standard IO functions such as printf()
and scanf()
.
Note that you need to fdopen()
the input and output
of the socket separately, else you may get confusion with buffering.
FILE *s_in = fdopen(s, "r");
FILE *s_out = fdopen(s, "w");
expect / send
Parsing response codes gets pretty tedious too, so you will want some code to handle that. I recommend my "expect / send" library, also available on my GitHub. This (documented) C library provides simple functions for sending commands and dealing with expected responses.
You will probably want to just hardwire your client to not handle unexpected response codes gracefully: just exit. That's what my expect / send library does, and it's fine for this assignment. The easiest way to discover what response codes to expect is via experimentation.
The PORT command
Whether doing an active or passive transfer, you will need
to use the PORT
command to inform the server of the IP
address and port number of your end of the socket. The best
way to get this information is via the getsockname()
call.
Make sure you send the PORT
bytes in network order.
Passive transfers
The order of operations for a passive transfer is pretty
specific: you must send PORT
, then PASV
, then connect()
the data socket, then RETR
. Any other order is unlikely
to work.
Debugging
You will want to get a real FTP client and try retrieving the specified file that way. Use wireshark / tshark to watch the flow of commands and responses during the transaction; this is basically what you are trying to duplicate.
Make sure you turn on the cexpect_verbose
variable in
my expect / send library if you are using that library; it
is really useful to see what your program is doing.
Misc Hints
It is really easy to get host and network byte-order
problems. The routines htonl()
, ntohl()
, htons()
and
ntohs()
do conversions between host and network byte order
for short (16-bit, like port numbers) and long (32-bit, like
IP addresses) integers.
The routine inet_ntoa()
will convert a 32-bit IPv4 address
into a string for printing purposes.
Submission
You must submit the following:
Your C source code, together with any other files needed to try it out.
A README.homework file containing a writeup in plain text of not more than 1000 words describing what you did, how it worked, and anything else you think we should know.