Skip to content

Commit

Permalink
ftp: Close passive port on failure
Browse files Browse the repository at this point in the history
globus-url-copy hangs on proxied passive mode connections for which
the mover is killed. Although the proxy adapter is shut down and an
error is reported on the control channel, the fact that the server
socket for the passive mode is not closed and thus has an unaccepted
connection causes globus-url-copy to hang.

This patch closes the passive port on transfer failure. The mode state
is set to an invalid state to force the client to reset the data
channel using either PORT or PASV (or one of the variations).

I am not request backport further than 2.9 as I expect that we will
soon backport the entire door to get delayed passive and IPv6 functionality
in older releases.

Target: trunk
Request: 2.9
Require-notes: yes
Require-book: no
Acked-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
Patch: https://rb.dcache.org/r/7079/
  • Loading branch information
gbehrmann committed Jun 17, 2014
1 parent 44ecaa3 commit 6a6fcfd
Showing 1 changed file with 22 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -292,14 +292,16 @@ public abstract class AbstractFtpDoorV1
*
* For ACTIVE transfers dCache establishes the data connection.
*
* When INVALID, the client most reset the mode.
*
* Depending on the values of _isProxyRequiredOnActive and
* _isProxyRequiredOnPassive, the data connection with the client
* will be established either to an adapter (proxy) at the FTP
* door, or to the pool directly.
*/
protected enum Mode
{
PASSIVE, ACTIVE
PASSIVE, ACTIVE, INVALID
}


Expand Down Expand Up @@ -1193,6 +1195,11 @@ protected synchronized void onFailure(Exception exception)
if (_adapter != null) {
_adapter.close();
_adapter = null;

if (_mode == Mode.PASSIVE) {
closePassiveModeServerSocket();
AbstractFtpDoorV1.this._mode = Mode.INVALID;
}
}

if (isWrite()) {
Expand Down Expand Up @@ -3145,6 +3152,9 @@ private void retrieve(String file, long offset, long size,
if (xferMode.equals("X") && mode == Mode.PASSIVE && _isProxyRequiredOnPassive) {
throw new FTPCommandException(504, "Cannot use passive X mode");
}
if (mode == Mode.INVALID) {
throw new FTPCommandException(425, "Issue PASV or PORT to reset data channel.");
}
if (_checkSumFactory != null || _checkSum != null) {
throw new FTPCommandException(503,"Expecting STOR ESTO PUT commands");
}
Expand Down Expand Up @@ -3270,6 +3280,9 @@ private void store(String file, Mode mode, String xferMode,
if (xferMode.equals("X") && mode == Mode.PASSIVE && _isProxyRequiredOnPassive) {
throw new FTPCommandException(504, "Cannot use passive X mode");
}
if (mode == Mode.INVALID) {
throw new FTPCommandException(425, "Issue PASV or PORT to reset data channel.");
}

FtpTransfer transfer =
new FtpTransfer(absolutePath(file),
Expand Down Expand Up @@ -3402,19 +3415,24 @@ public void ftp_mdtm(String arg)
}

private void openDataSocket()
throws IOException
throws IOException, FTPCommandException
{
/* Mode being PASSIVE means the client did a PASV. Otherwise
* we establish the data connection to the client.
*/
if (_mode == Mode.PASSIVE) {
switch (_mode) {
case PASSIVE:
replyDelayedPassive(_delayedPassive, (InetSocketAddress) _passiveModeServerSocket.getLocalAddress());
reply("150 Ready to accept ASCII mode data connection", false);
_dataSocket = _passiveModeServerSocket.accept().socket();
} else {
break;
case ACTIVE:
reply("150 Opening ASCII mode data connection", false);
_dataSocket = new Socket();
_dataSocket.connect(_clientDataAddress);
break;
default:
throw new FTPCommandException(425, "Issue PASV or PORT to reset data channel.");
}
}

Expand Down

0 comments on commit 6a6fcfd

Please sign in to comment.