diff options
author | Daniel Stenberg <daniel@haxx.se> | 2011-10-21 23:36:54 +0200 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2011-10-21 23:36:54 +0200 |
commit | d7934b8bd49114cbb54f7401742f7fb088e2f796 (patch) | |
tree | 35beaeb7e2050d89bb2b59b85f2d25d177e63d39 /lib/ftp.c | |
parent | d67b75c9f9c59ea4adc40d0b333c6047621573ba (diff) |
curl_multi_fdset: correct fdset with FTP PORT use
After a PORT has been issued, and the multi handle would switch to the
CURLM_STATE_DO_MORE state (which is unique for FTP), libcurl would
return the wrong fdset to wait for when curl_multi_fdset() is
called. The code would blindly assume that it was waiting for a connect
of the second connection, while that isn't true immediately after the
PORT command.
Also, the function multi.c:domore_getsock() was highly FTP-centric and
therefore ugly to keep in protocol-agnostic code. I solved this problem
by introducing a new function pointer in the Curl_handler struct called
domore_getsock() which is only called during the DOMORE state for
protocols that set that pointer.
The new ftp.c:ftp_domore_getsock() function now returns fdset info about
the control connection's command/response handling while such a state is
in use, and goes over to waiting for a writable second connection first
once the commands are done.
The original problem could be seen by running test 525 and checking the
time stamps in the FTP server log. I can verify that this fix at least
fixes this problem.
Bug: http://curl.haxx.se/mail/lib-2011-10/0250.html
Reported by: Gokhan Sengun
Diffstat (limited to 'lib/ftp.c')
-rw-r--r-- | lib/ftp.c | 40 |
1 files changed, 38 insertions, 2 deletions
@@ -134,9 +134,10 @@ static CURLcode ftp_connect(struct connectdata *conn, bool *done); static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection); static CURLcode ftp_nextconnect(struct connectdata *conn); static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done); -static int ftp_getsock(struct connectdata *conn, - curl_socket_t *socks, +static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks); +static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks); static CURLcode ftp_doing(struct connectdata *conn, bool *dophase_done); static CURLcode ftp_setup_connection(struct connectdata * conn); @@ -171,6 +172,7 @@ const struct Curl_handler Curl_handler_ftp = { ftp_doing, /* doing */ ftp_getsock, /* proto_getsock */ ftp_getsock, /* doing_getsock */ + ftp_domore_getsock, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -196,6 +198,7 @@ const struct Curl_handler Curl_handler_ftps = { ftp_doing, /* doing */ ftp_getsock, /* proto_getsock */ ftp_getsock, /* doing_getsock */ + ftp_domore_getsock, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -222,6 +225,7 @@ static const struct Curl_handler Curl_handler_ftp_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -247,6 +251,7 @@ static const struct Curl_handler Curl_handler_ftps_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -634,6 +639,37 @@ static int ftp_getsock(struct connectdata *conn, return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks); } +/* For the FTP "DO_MORE" phase only */ +static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if(!numsocks) + return GETSOCK_BLANK; + + /* When in DO_MORE state, we could be either waiting for us to connect to a + remote site, or we could wait for that site to connect to us. Or just + handle ordinary commands. + + When waiting for a connect, we will be in FTP_STOP state and then we wait + for the secondary socket to become writeable. If we're in another state, + we're still handling commands on the control (primary) connection. + + */ + + switch(ftpc->state) { + case FTP_STOP: + break; + default: + return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks); + } + + socks[0] = conn->sock[SECONDARYSOCKET]; + + return GETSOCK_READSOCK(0); +} + /* This is called after the FTP_QUOTE state is passed. ftp_state_cwd() sends the range of CWD commands to the server to change to |