0

We have a FTP Active client class we are using but we are trying to reuse the same data socket when transferring more than 1 file. To understand the behavior, I just used the ftp.exe (Active) client from Microsoft and then I uploaded 2 files as you can see below.

When using (Active) FTP client, the client issues a command PORT such as 192,168,150,80,14,178 (port 3762) for instance. Then the server on port 20 connects back to the client on its local port 3762 and the file is uploaded.

The problem is when I send the second file, the client issues another PORT command and it uses another local port such as 3763 for instance. This is the behavior of the Microsoft FTP client though.

However in our FTP class we have more control since we are doing all the bindings on all ports. I did manage to transfer the second 2 file using the same client local port but at some point the server sends info to client to close that port and the second file transfer then fails.

Is there a way to go around that behavior? we cannot use PASSIVE ftp at this point.

Thanks

C:\>ftp
ftp> open 10.10.10.10
Connected to 10.10.10.10.
220 Microsoft FTP Service
User (10.10.10.10:(none)): USER01
331 Password required for USER01.
Password:
230 User logged in.
ftp> cd test
250 CWD command successful.
ftp> put c:\temp\test1.docx
c:\temp\test1.docx: File not found
ftp> put c:\temp\test1.docx
200 PORT command successful.
125 Data connection already open; Transfer starting.
226 Transfer complete.
ftp: 13097 bytes sent in 0.42Seconds 31.11Kbytes/sec.
ftp> put c:\temp\test2.docx
200 PORT command successful.
125 Data connection already open; Transfer starting.
226 Transfer complete.
ftp: 13095 bytes sent in 0.61Seconds 21.54Kbytes/sec.
ftp> quit
221 Goodbye.

Basically in C# this is what we do:

System.Net.IPEndPoint localEP = new IPEndPoint(IPAddress.Parse(sIPAddr), 4900); listening_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); listening_sock.Bind(localEP); ... listening_sock.Listen(1); ... //send PORT command //send STOR command listening_sock.Accept(); ... //transfer file (via stream); ... //then try to issue another STOR command to transfer the file //if the port is still open it will transfer some data but eventually the ports closes itself.

Max
  • 1,289
  • 3
  • 26
  • 50
  • Why can't you use `PASV`? Just about every FTP server supports it, and it is friendlier to both clients and firewalls/routers than `PORT` is. – Remy Lebeau Mar 30 '14 at 17:07
  • cant use PASV because our IT department determined we need to use FTP Active, period. That way they can easily control their firewall to accept a range of 100 ports only. In our scenario, our client will always pick a port between 4000 - 4999 to connect to port 20. – Max Mar 31 '14 at 16:19
  • Most FTP servers that support `PASV` also support port ranges for Passive connections, so they could have easily allowed 100 inbound Passive ports instead of 100 outbound Active ports. Your IT dept needs to get with the times. – Remy Lebeau Mar 31 '14 at 19:05
  • Possible duplicate of [FTP data connections reuse](http://stackoverflow.com/questions/31560701/ftp-data-connections-reuse) – ivan_pozdeev Dec 13 '16 at 17:15

1 Answers1

0

In active mode the server side of the data connection is on port 20. If the client reuses the same IP and Port on its side you have the same connection tuple (e.g. client_ip,client_port,server_ip,server_port) for consecutive connections. But, with TCP you have to wait some time before you can reuse the same tuple. This means, that in active mode the client needs to announce a new port for each new data transfer.

See also the RFC959 (FTP) section 3.3 "Data Connection Management".

Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • What you say is true. However, if you really want the client to reuse the same port, try enabling the `SO_REUSEADDR` option on the client's listening socket before binding it to a port. This can cause side effects on slow networks, so better to use a different port each time. – Remy Lebeau Mar 30 '14 at 17:01
  • This would not help. In the given scenario the client is binding and listening only once, but tries to accept multiple connections from the same server (and same port, e.g. 20) which might fail for the reasons I described. REUSEADDR only applies if you try to bind to the same local address multiple times which is not the case here on the client side. – Steffen Ullrich Mar 30 '14 at 18:16
  • It is not unheard of for an FTP client to create a new socket for each transfer, rather than reuse an existing listening socket each time. In that case, `SO_REUSEADDR` does become useful. We do not know Max's actual implementation. – Remy Lebeau Mar 30 '14 at 20:12
  • so now I am confused. Can I reuse the port or not? if stream wont work the FTP RFC959 mentions: 3.4.2. BLOCK MODE; would that be the solution? My implementation is as follows: send PORT command using a local port 4000 (for instance), bind to that port, send STOR command to transfer the file (stream bytes) and do not close any ports; send another STOR command to transfer another file (I see the second file being transferred but the client closes the connection from transfer one). Not sure if this is a normal behavior described anywhere in the RFC. – Max Mar 31 '14 at 16:27
  • As I described in the answer: it will not work reliably if you reuse the same port within a short time. What an implementation usually does is the following: bind to the IP, but leave the port undefined, then use getsockname to find out the (kind of random) port the system used in the binding. After then send this IP,port inside the PORT command to the server, wait for connection from server (accept), transfer file and close both listening socket and connection socket. Repeat this for every data transfer. – Steffen Ullrich Mar 31 '14 at 16:41
  • so there is no way to keep the listening sock open? what is actually closing the socket? does the STOR command actually does that after the client sends its last byte during the transfer? sorry, I am not trying to beat a dead horse here but closing the port and opening a new one seems stupid. So I am trying to find out how not to initiate a closure that leads to a TIME_WAIT. – Max Mar 31 '14 at 19:14
  • Nothing is closing the listener socket by itself. Its only, that the listener socket defines a fixed endpoint (IP,port). But, the server also defines a fixed endpoint by using port 20 as local port as defined in the RFC. And having two TCP connections with the same endpoints (the whole quadruple, e.g. not only IP but same IP and port on both sides) within a short time is just asking for trouble. For more details I would refer you to the description of TCP (like in http://en.wikipedia.org/wiki/Transmission_Control_Protocol) and the reasons for the TIME_WAIT state. – Steffen Ullrich Mar 31 '14 at 19:53
  • I also found this: "using SO_REUSEADDR can actually lead to more difficult "address already in use" errors. SO_REUSADDR permits you to use a port that is stuck in TIME_WAIT, but you still can not use that port to establish a connection to the last place it connected to. What? Suppose I pick local port 1010, and connect to foobar.com port 300, and then close locally, leaving that port in TIME_WAIT. I can reuse local port 1010 right away to connect to anywhere except for foobar.com port 300." http://hea-www.harvard.edu/~fine/Tech/addrinuse.html which WON'T help in my scenario. Bummer. Thank you! – Max Mar 31 '14 at 20:15