FTP is another commonly used application. It is the Internet standard for file transfer. We must be careful to differentiate between file transfer, which is what FTP provides, and file access, which is provided by applications such as NFS (Sun's Network File System, Chapter 29). The file transfer provided by FTP copies a complete file from one system to another system. To use FTP we need an account to login to on the server, or we need to use it with a server that allows anonymous FTP (which we show an example of in this chapter).
Like Telnet, FTP was designed from the start to work between different hosts, running different operating systems, using different file structures, and perhaps different character sets. Telnet, however, achieved heterogeneity by forcing both ends to deal with a single standard: the NVT using 7-bit ASCII. FTP handles all the differences between different systems using a different approach. FTP supports a limited number of file types (ASCII, binary, etc.) and file structures (byte stream or record oriented).
RFC 959 [Postel and Reynolds 1985] is the official
specification for FTP. This RFC contains a history of the evolution
of file transfer over the years.
27.2 FTP Protocol
FTP differs from the other applications that we've described because it uses two TCP connections to transfer a file.
The IP type-of-service for the control connection should be "minimize delay" since the commands are normally typed by a human user (Figure 3.2).
The IP type-of-service for the data connection should be "maximize throughput" since this connection is for file transfer.
Figure 27.1 shows the arrangement of the client and server and the two connections between them.
This figure shows that the interactive user normally doesn't deal with the commands and replies that are exchanged across the control connection. Those details are left to the two protocol interpreters. The box labeled "user interface" presents whatever type of interface is desired to the interactive user (full-screen menu selection, line-at-a-time commands, etc.) and converts these into FTP commands that are sent across the control connection. Similarly the replies returned by the server across the control connection can be converted to any format to present to the interactive user.
This figure also shows that it is the two protocol interpreters that invoke the two data transfer functions, when necessary.
Numerous choices are provided in the FTP protocol
specification to govern the way the
file is transferred and stored. A choice must be made in each
of four dimensions.
If we calculate the number of combinations of all these choices, there could be 72 different ways to transfer and store a file. Fortunately we can ignore many of the options, because they are either antiquated or not supported by most implementations.
Common Unix implementations of the FTP client and server restrict us to the following choices:
This limits us to one of two modes: ASCII or image (binary).
This implementation meets the minimum requirements
of the Host Requirements RFC. (This RFC also requires support
for the record structure, but only if the operating system supports
it, which Unix doesn't.)
Many non-Unix implementations provide FTP capabilities
to handle their own file formats. The Host Requirements RFC states
"The FTP protocol includes many features, some of which are
not commonly implemented. However, for every feature in FTP, there
exists at least one implementation."
The commands and replies sent across the control connection between the client and server are in NVT ASCII. This requires a CR, LF pair at the end of each line (i.e., each command or each reply).
The only Telnet commands (those that begin with IAC) that can be sent by the client to the server are interrupt process (<IAC, IP>) and the Telnet synch signal (<IAC, DM> in urgent mode). We'll see that these two Telnet commands are used to abort a file transfer that is in progress, or to query the server while a transfer is in progress. Additionally, if the server receives a Telnet option command from the client (WILL, WONT, DO, or DONT) it responds with either DONT or WONT.
The commands are 3 or 4 bytes of uppercase ASCII characters, some with optional arguments. More than 30 different FTP commands can be sent by the client to the server. Figure 27.2 shows some of the commonly used commands, most of which we'll encounter in this chapter.
ABOR
LIST filelist PASS password PORT n1,n2,n3,n4,n5,n6 QUIT RETR filename STOP filename SYST TYPE type USER username | abort previous FTP command and any data transfer list files or directories password on server client IP address (nl.n2.n3.n4) and port (n5 x 256 + n6) logoff from server retrieve (get) a file store (put) a file server returns system type specify file type: A for ASCII, I for image usemame on server |
We'll see in the examples in the next section that sometimes there is a one-to-one correspondence between what the interactive user types and the FTP command sent across the control connection, but for some operations a single user command results in multiple FTP commands across the control connection.
The replies are 3-digit numbers in ASCII, with an optional message following the number. The intent is that the software needs to look only at the number to determine how to process the reply, and the optional string is for human consumption. Since the clients normally output both the numeric reply and the message string, an interactive user can determine what the reply says by just reading the string (and not have to memorize what all the numeric reply codes mean).
Each of the three digits in the reply code has a different meaning. (We'll see in Chapter 28 that the Simple Mail Transfer Protocol, SMTP, uses the same conventions for commands and replies.)
Figure 27.3 shows the meanings of the first and second
digits of the reply code.
1yz | Positive preliminary reply. The action is being started but expect another reply before sending another command |
2yz | Positive completion reply A new command can be sent |
3yz | Positive intermediate reply. The command has been accepted but another command must be sent |
4yz | Transient negative completion reply The requested action did not take place, but the error condition is temporary so the command can be reissued later. |
5yz | Permanent negative completion reply. The command was not accepted and should not be retried. |
X0z | Syntax errors. |
x1z | Information. |
x2z | Connections. Replies referring to the control or data connections. |
x3z | Authentication and accounting. Replies for the login or accounting commands. |
x4z | Unspecified. |
x5z | Filesystem status. |
The third digit gives additional meaning to the error message. For example, here are some typical replies, along with a possible message string.
Normally each FTP command generates a one-line reply For example, the QUIT command could generate the reply:
221 Goodbye.
If a multiline reply is needed, the first line contains a hyphen instead of a space after the 3-digit reply code, and the final line contains the same 3-digit reply code, followed by a space. For example, the HELP command could generate the reply:
214- The following commands are recognized (* =>'s unimplemented). | |||||||
USER | PORT | STOR | MSAM* | RNTO | NLST | MKD | CDUP |
PASS | PASV | APPE | MRSQ* | ABOR | SITE | XMKD | XCUP |
ACCT* | TYPE | MLFL* | MRCP* | DELE | SYST | RMD | STOU |
SMNT* | STRU | MAIL* | ALLO | CWD | STAT | XRMD | SIZE |
REIN* | MODE | MSND* | REST | XCWD | HELP | PWD | MDTM |
QUIT | RETR | MSOM* | RNFR | LIST | NOOP | XPWD | |
214 Direct comments to ftp-bugs@bsdi.tuc.noao.edu. |
There are three uses for the data connection.
The FTP server sends file listings back across the data connection, rather than as multiline replies across the control connection. This avoids any line limits that restrict the size of a directory listing and makes it easier for the client to save the output of a directory listing into a file, instead of printing the listing to the terminal.
We've said that the control connection stays up for the duration of the client-server connection, but the data connection can come and go, as required. How are the port numbers chosen for the data connection, and who does the active open and passive open?
First, we said earlier that the common transmission mode (under Unix the only transmission mode) is the stream mode, and that the end-of-file is denoted by closing the data connection. This implies that a brand new data connection is required for every file transfer or directory listing. The normal procedure is as follows:
Figure 27.4 shows the state of the connections while step 3 is being performed. We assume the client's ephemeral port for the control connection is 1173, and the client's ephemeral port for the data connection is 1174. The command sent by the client is the PORT command and its arguments are six decimal numbers in ASCII, separated by commas. The first four numbers specify the IP address on the client that the server should issue the active open to (140.252.13.34 in this example), and the next two specify the 16-bit port number. Since the 16-bit port number is formed from two numbers, its value in this example is 4 x 256 +150 = 1174.
Figure 27.5 shows the state of the connection when the server issues the active open to the client's end of the data connection. The server's end point is at port 20.
The server always does the active open of the data connection. Normally the server also does the active close of the data connection, except when the client is sending a tile to the server in stream mode, which requires the client to close the connection (which gives the server the end-of-tile notification).
It is also possible for the client to not issue the
PORT command, in which case the server issues the active open
to the same port number being used by the client for its end of
the control connection (1173 in this example). This is OK, since
the server's port numbers for the two connections are different:
one is 20 and the other is 21. Nevertheless, in the next section
we'll see why current implementations normally don't do this.
27.3 FTP Examples
We now look at some examples using FTP: its management of the data connection, how text files are sent using NVT ASCII, FTP'S use of the Telnet synch signal to abort an inprogress transfer, and finally the popular "anonymous FTP."
Let's first look at FTP's connection management with a simple FTP session that just lists a file on the server. We run the client on the host svr4 with the -d flag (debug). This tells it to print the commands and replies that are exchanged across the control connection. All the lines preceded by ---> are sent by the client to the server, and the lines that begin with a 3-digit number are the server's replies. The client's interactive prompt is ftp>.
svr4 % ftp -d bsdi | -d option for debug output |
Connected to bsdi. | client does active open of control connection |
220 bsdi FTP server (Version 5.60) ready. | server responds it is ready |
Name (bsdi:rstevens): | client prompts us for a login name |
---> USER rstevens | we type RETURN, so client sends default |
331 Password required for rstevens. | |
Password: | we type our password; it's not echoed |
---> PASS XXXXXXX | client sends it as cleartext |
230 User rstevens logged in. | |
ftp> dir hello.c | ask for directory listing of a single file |
---> PORT 140,252,13,34,4,150 | see figure 27.4 |
200 PORT command successful. | |
---> LIST hello.c | |
150 Opening ASCII mode data connection for /bin/ls. | |
-rw-r--r-- 1 rstevens staff 38 Jul 17 12:47 hello.c | |
226 Transfer complete. | |
remote: hello.c | output by client |
56 bytes received in 0.03 seconds (1.8 Kbytes/s) | |
ftp> quit | we're done |
---> QUIT 221 Goodbye. |
When the FTP client prompts us for a login name, it prints the default (our login name on the client). When we type the RETURN key, this default is sent.
Asking for a directory listing of a single file causes a data connection to be established and used. This example follows the procedure we showed in Figures 27.4 and 27.5. The client asks its TCP for an ephemeral port number for its end of the data connection, and sends this port number (1174) to the server in a PORT command. We can also see that a single interactive user command (dir) becomes two FTP commands (PORT and LIST).
Figure 27.6 is the time line of the packet exchange across the control connection. (We have removed the establishment and termination of the control connection, along with all the window size advertisements.) We note in this figure where the data connection is opened, used, and then closed.
Figure 27.7 is the time line for the data connection. The times in this figure are from the same starting point as Figure 27.6. We have removed all window advertisements, but have left in the type-of-service field, to show that the data connection uses a different type-of-service (maximize throughput) than the control connection (minimize delay). (The TOS values are in Figure 3.2.)
In this time line the FTP server does the active open of the data connection, from port 20 (called ftp-data), to the port number from the PORT command (1174). Also in this example, where the server writes to the data connection, the server does the active close of the data connection, which tells the client when the listing is complete.
If the client does not send a PORT command to the server, to specify the port number for the client's end of the data connection, the server uses the same port number for the data connection that is being used for the control connection. This can cause problems for clients that use the stream mode (which the Unix FTP clients and server always use), as we show below.
The Host Requirements RFC recommends that an FTP client using the stream mode send a PORT command to use a nondefault port number before each use of the data connection.
Returning to the previous example (Figure 27.6), what if we asked for another directory listing a few seconds after the first? The client would ask its kernel to choose another ephemeral port number (perhaps 1175) and the next data connection would be between svr4 port 1175 and bsdi port 20. But in Figure 27.7 the server did the active close of the data connection, and we showed in Section 18.6 that the server won't be able to assign port 20 to the new data connection, because that local port number was used by an earlier connection that is still in the 2MSL wait state.
The server gets around this by specifying the SO_REUSEADDR option that we mentioned in Section 18.6. This lets it assign port 20 to the new connection, and the new connection will have a different foreign port number (1175) from the one that's in the 2MSL wait (1174), so everything is OK.
This scenario changes if the client does not send the PORT command, specifying an ephemeral port number on the client. We can force this to happen by executing the user command sendport to the FTP client. Unix FTP clients use this command to turn off sending PORT commands to the server before each use of a data connection.
Figure 27.8 shows the time line only for the data connections for two consecutive LIST commands. The control connection originates from port 1176 on host svr4, so in the absence of PORT commands, the client and server use this same port number for the data connection. (We have removed the window advertisements and type-of-service values.)
The sequence of events is as follows.
<svr4, 1176, bsdi, 21>
<svr4, 1176, bsdi, 20>
are different (the port numbers on bsdi are different). TCP demultiplexes incoming segments by looking at the source IP address, source port number, destination IP address, and destination port number, so as long as one of the four elements differs, all is OK.
<svr4, 1176, bsdi, 20>
in a 2MSL wait on the server.
At this point the BSD server retries the connection request every 5 seconds, up to 18 times, for a total of 90 seconds. We see that segment 9 succeeds about 1 minute later. (We mentioned in Chapter 18 that SVR4 uses an MSL of 30 seconds, for a 2MSL wait of 1 minute.) We don't see any SYNs from these failures in this time line because the active opens fail and the server's TCP doesn't even send a SYN.
The reason the Host Requirements RFC recommends using the PORT command is to avoid this 2MSL wait between successive uses of a data connection. By continually changing the port number on one end, the problem we just showed disappears.
Let's verify that the transmission of a text file uses NVT ASCII by default. This time we don't specify the -d flag, so we don't see the client commands, but notice that the client still prints the server's responses:
sun % ftp bsdi | |
Connected to bsdi. | |
220 bsdi FTP server (Version 5.60) ready. | |
Name (bsdi:rstevens): | we type RETURN |
331 Password required for rstevens. | |
Password: | we type our password |
230 User rstevens logged in. | |
ftp> get hello.c | fetch a file |
200 PORT command successful. | |
150 Opening ASCII mode data connection for hello.c (38 bytes). | |
226 Transfer complete. | server says file contains 38 bytes |
local: hello.c remote: hello.c | output by client |
42 bytes received in 0.0037 seconds (11 Kbytes/s) | 42 bytes across data connection |
ftp> quit | |
221 Goodbye. | |
sun % ls -l hello.c | |
-rw-rw-r-1 rstevens 38 Jul 18 08:48 hello.c | but file contains 38 bytes |
sun % wc -l hello.c | count the lines in the file |
4 hello.c |
Forty-two bytes are transferred across the data connection because the file contains four lines. Each Unix newline character (\n) is converted into the NVT ASCII 2-byte end-of-line sequence (\r\n) by the server for transmission, and then converted back by the client for storage.
Newer clients attempt to determine if the server is of the same system type, and if so, transfer files in binary (image file type) instead of ASCII. This helps in two ways.
We can see this optimization using a BSD/386 client and server. We'll enable the debug mode, to see the client FTP commands:
bsdi % ftp -d slip | specify -d to see client commands |
Connected to slip. | |
220 slip FTP server (Version 5.60) ready. | |
Name (slip:rstevens): | we type RETURN |
---> USER rstevens | |
331 Password required for rstevens. | |
Password: | we type our password |
---> PASS XXXX | |
230 User rstevens logged in. | |
---> SYST | this is sent automatically by client |
215 UNIX Type: L8 Version: BSD-199103 | server's reply |
Remote system type is UNIX. | information output by client |
Using binary mode to transfer files. | information output by client |
ftp> get hello.c | fetch a file |
---> TYPE I | sent automatically by client |
200 Type set to I. | |
---> PORT 140,252,13,66,4,84 | port number=4x256+84=1108 |
200 PORT command successful. | |
---> RETR hello.c | |
150 Opening BINARY mode data connection for hello.c (38 bytes). | |
226 Transfer complete. | |
38 bytes received in 0.035 seconds (1.1 Kbytes/s) | only 38 bytes this time |
ftp> quit | |
---> QUIT | |
221 Goodbye. |
After we login to the server, the client FTP automatically sends the SYST command, which the server responds to with its system type. If the reply begins with the string "215 UNIX Type: L8", and if the client is running on a Unix system with 8 bits per byte, binary mode (image) is used for all file transfers, unless changed by the user.
When we fetch the file hello.c the client automatically sends the command TYPE I to set the file type to image. Only 38 bytes are transferred across the data connection.
The Host Requirements RFC says an FTP server must support the SYST command (it was an option in RFC 959). But the only systems used in the text (see inside front cover) that support it are BSD/386 and AIX 3.2.2. SunOS 4.1.3 and Solaris 2.x reply with 500 (command not understood). SVR4 has the extremely unsocial behavior of replying with 500 and closing the control connection!
We now look at how the FTP client aborts a file transfer from the server. Aborting a file transfer from the client to the server is easy - the client stops sending data across the data connection and sends an ABOR to the server on the control connection. Aborting a receive, however, is more complicated, because the client wants to tell the server to stop sending data immediately. We mentioned earlier that the Telnet synch signal is used, as we'll see in this example.
We'll initiate a receive and type our interrupt key after it has started. Here is the interactive session, with the initial login deleted:
ftp> get a.out | fetch a large file |
---> TYPE I | client and server are both 8-bit byte Unix systems |
200 Type set to I. | |
---> PORT 140,252,13,66,4,99 | |
200 PORT command successful. | |
---> RETR a.out | |
150 Opening BINARY mode data connection for a.out (28672 bytes). | |
^? | type our interrupt key |
receive aborted | output by client |
waiting for remote to finish abort | output by client |
426 Transfer aborted. Data connection closed. | |
226 Abort successful | |
1536 bytes received in 1.7 seconds (0.89 Kbytes/s) |
After we type our interrupt key, the client immediately tells us it initiated the abort and is waiting for the server to complete. The server sends two replies: 426 and 226. Both replies are sent by the Unix server when it receives the urgent data from the client with the ABOR command.
Figures 27.9 and 27.10 show the time line for this session. We have combined the control connection (solid lines) and the data connection (dashed lines) to show the relationship between the two.
The first 12 segments in Figure 27.9 are what we expect. The commands and replies across the control connection set up the file transfer, the data connection is opened, and the first segment of data is sent from the server to the client.
In Figure 27.10, segment 13 is the receipt of the sixth data segment from the server on the data connection, followed by segment 14, which is generated by our typing the interrupt key. Ten bytes are sent by the client to abort the transfer:
<IAC, IP, IAC, DM, A, B, O, R, \r, \n>
We see two segments (14 and 15) because of the problem we detailed in Section 20.8 dealing with TCP's urgent pointer. (We saw the same handling of this problem in Figure 26.17 with Telnet.) The Host Requirements RFC says the urgent pointer should point to the last byte of urgent data, while most Berkeley-derived implementations have it point 1 byte beyond the last byte of urgent data. The FTP client purposely writes the first 3 bytes as urgent data, knowing the urgent pointer will (incorrectly) point to the next byte that is written (the data mark, DM, at sequence number 54). This first write with 3 bytes of urgent data is sent immediately, along with the urgent pointer, followed by the next 7 bytes. (The BSD FTP server does not have a problem with which interpretation of the urgent pointer is used by the client. When the server receives urgent data on the control connection it reads the next FTP command, looking for ABOR or STAT, ignoring any embedded Telnet commands.)
Notice that despite the server saying the transfer was aborted (segment 18, on the control connection), the client receives 14 more segments of data (sequence numbers 1537 through 5120) on the data connection. These segments were probably queued in the network device driver on the server when the abort was received, but the client prints "1536 bytes received" meaning it ignores all the segments of data that it receives (segments 17 and later) after sending the abort (segments 14 and 15).
In the case of a Telnet user typing the interrupt key, we saw in Figure 26.17 that by default the Unix client does not send the interrupt process command as urgent data. We said this was OK because there is little chance that the flow of data from the client to the server is stopped by flow control. With FTP the client is also sending an interrupt process command across the control connection, and since two connections are being used there is little chance that the control connection is stopped by flow control. Why does FTP send the interrupt process command as urgent data when Telnet does not? The answer is that FTP uses two connections, whereas Telnet uses one, and on some operating systems it may be hard for a process to monitor two connections for input at the same time. FTP assumes that these marginal operating systems at least provide notification that urgent data has arrived on the control connection, allowing the server to then switch from handling the data connection to the control connection.
One form of FTP is so popular that we'll show an example of it. It's called anonymous FTP, and when supported by a server, allows anyone to login and use FTP to transfer files. Vast amounts of free information are available using this technique.
How to find which site has what you're looking for is a totally different problem. We mention it briefly in Section 30.4.
We'll use anonymous FTP to the site ftp.uu.net (a popular anonymous FTP site) to fetch the errata file for this book. To use anonymous FTP we login with the username of "anonymous" (you learn to spell it correctly after a few times). When prompted for a password we type our electronic mail address.
sun % ftp ftp.uu.net | |
Connected to ftp.uu.net. | |
220 ftp.UU.NET FTP server (Version 2.0WU(13) Fri Apr 9 20:44:32 EDT 1993) ready. | |
Name (ftp.uu.net:rstevens): anonymous | |
331 Guest login ok, send your complete e-mail address as password. | |
Password: | we type rstevens@noao.edu; it's not echoed |
230- | |
230- Welcome to the UUNET archive. | |
230- A service of UUNET Technologies Inc, Falls Church, Virginia | |
230- For information about UUNET, call +1 703 204 8000, or see the files | |
230- in /uunet-info | |
more greeting lines | |
230 Guest login ok, access restrictions apply. | |
ftp> cd published/books | change to the desired directory |
250 CWD command successful. | |
ftp> binary | we'll transfer a binary file |
200 Type set to I. | |
ftp> get stevens.tcpipivl.errata.Z | fetch the file |
200 PORT command successful. | |
150 Opening BINARY mode data connection for stevens.tcpipivl.errata.Z (105 bytes). | |
226 Transfer complete, | (you may get a different file size) |
local: stevens.tcpipivl.errata.Z remote: stevens.tcpipivl.errata.Z | |
105 bytes received in 4.1 seconds (0.83 Kbytes/s) | |
ftp> quit | |
221 Goodbye. | |
sun % uncompress stevens.tcpipivl.errata.Z | |
sun % more stevens.tcpipivl.errata |
The uncompress is because many files available for anonymous FTP are compressed using the Unix compress(l) program, resulting in a file extension of .Z. These files must be transferred using the binary file type, not the ASCII file type.
We can tie together some features of routing and the Domain Name System using anonymous FTP. In Section 14.5 we talked about pointer queries in the DNS - taking an IP address and returning the hostname. Unfortunately not all system administrators set up their name servers correctly with regard to pointer queries. They often add new hosts to the file required for name-to-address mapping, but forget to add them to the file for address-to-name mapping. We often see this with traceroute, when it prints an IP address instead of a hostname.
Some anonymous FTP servers require that the client have a valid domain name. This allows the server to log the domain name of the host that's doing the transfer. Since the only client identification the server receives in the IP datagram from the client is the IP address of the client, the server can call the DNS to do a pointer query, and obtain the domain name of the client. If the name server responsible for the client host is not set up correctly, this pointer query can fail. To see this error we'll do the following steps.
Our host slip is still reachable across the Internet, because we saw in Section 10.4 that the routers gateway and netb just sent any datagram destined for the subnet 140.252.13 to the router sun. Our router sun knows what to do with these datagrams from the routing table entry we made in step 3 above. What we have created is a host with complete Internet connectivity, but without a valid domain name. That is, a pointer query for the IP address 140.252.13.67 will fail.
We now use anonymous FTP to a server that we know requires a valid domain name:
slip % ftp ftp.uu.net |
Connected to ftp.uu.net. |
220 ftp.UU.NET FTP server (Version 2.0WU(13) Fri Apr 9 20:44:32 EDT 1993) ready. |
Name (ftp.uu.net:rstevens): anonymous |
530- Sorry, we're unable to map your IP address 140.252.13.67 to a hostname |
530- in the DNS. This is probably because your nameserver does not have a |
530- PTR record for your address in its tables, or because your reverse |
530- nameservers are not registered. We refuse service to hosts whose |
530- names we cannot resolve. If this is simply because your nameserver is |
530- hard to reach or slow to respond then try again in a minute or so, and |
530- perhaps our nameserver will have your hostname in its cache by then. |
530- If not, try reaching us from a host that is in the DNS or have your |
530- system administrator fix your servers. |
530 User anonymous access denied.. |
Login failed. |
Remote system type is UNIX. |
Using binary mode to transfer files. |
ftp> quit |
221 Goodbye. |
The error reply from the server is self-explanatory.
27.4 Summary
FTP is the Internet standard for file transfer. Unlike most other TCP applications, it uses two TCP connections between the client and server-a control connection that is left up for the duration of the client-server session, and a data connection that is created and deleted as necessary.
The connection management used by FTP for the data connection has let us examine in more detail the connection management requirements of TCP. We saw the interaction of TCP's 2MSL wait state on clients that don't issue PORT commands.
FTP uses NVT ASCII from Telnet for all commands and replies across the control connection. The default data transfer mode is often NVT ASCII also. We saw that newer Unix clients automatically send a command to see if the server is an 8-bit byte Unix host, and if so, use binary mode for all file transfers, which is more efficient.
We also showed an example of anonymous FTP, a popular form of software distribution on the Internet.
27.1 In Figure 27.8, what would change if the client did the active open of the second data connection instead of the server?
27.2 In the FTP client examples in this chapter we added the notation to lines such as
local: hello.c remote: hello.c
42 bytes received in 0.0037 seconds
(11 Kbytes/s)
that the lines were output by the client. Without looking at the source code, how are we certain these are not from the server?