diff options
author | Daniel Stenberg <daniel@haxx.se> | 2007-09-05 21:41:07 +0000 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2007-09-05 21:41:07 +0000 |
commit | 73e91ce20cb76df8b617c8e97974d7c15a0fa590 (patch) | |
tree | c1983ac7362143fc56f3b7ca57d17404a5419384 | |
parent | 8780ff879c1dea904902c43bfabff34325391949 (diff) |
Curl_GetFTPResponse() now checks and properly deals with the fact that the
underlying ftp_readresp() function has a separate "cache" where there might
in fact be leftover data...
-rw-r--r-- | CHANGES | 6 | ||||
-rw-r--r-- | lib/ftp.c | 63 |
2 files changed, 54 insertions, 15 deletions
@@ -6,6 +6,12 @@ Changelog +Daniel S (5 September 2007) +- Continued the work on a fix for #1779054 + (http://curl.haxx.se/bug/view.cgi?id=1779054). My previous fix from August + 24 was not complete (either) but could accidentally "forget" parts of a + server response which led to faulty server response time-out errors. + Dan F (5 September 2007) - Minix doesn't support getsockopt on UDP sockets or send/recv on TCP sockets. @@ -537,6 +537,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ struct ftp_conn *ftpc = &conn->proto.ftpc; struct timeval now = Curl_tvnow(); size_t nread; + int cache_skip=0; if (ftpcode) *ftpcode = 0; /* 0 for errors */ @@ -572,27 +573,59 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ if(timeout < interval_ms) interval_ms = timeout; - switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, (int)interval_ms)) { - case -1: /* select() error, stop reading */ - failf(data, "FTP response aborted due to select/poll error: %d", - SOCKERRNO); - return CURLE_RECV_ERROR; - - case 0: /* timeout */ - if(Curl_pgrsUpdate(conn)) - return CURLE_ABORTED_BY_CALLBACK; - continue; /* just continue in our loop for the timeout duration */ - - default: /* for clarity */ - break; - } + /* + * Since this function is blocking, we need to wait here for input on the + * connection and only then we call the response reading function. We do + * timeout at least every second to make the timeout check run. + * + * A caution here is that the ftp_readresp() function has a cache that may + * contain pieces of a response from the previous invoke and we need to + * make sure we don't just wait for input while there is unhandled data in + * that cache. But also, if the cache is there, we call ftp_readresp() and + * the cache wasn't good enough to continue we must not just busy-loop + * around this function. + * + */ + if(ftpc->cache && (cache_skip < 2)) { + /* + * There's a cache left since before. We then skipping the wait for + * socket action, unless this is the same cache like the previous round + * as then the cache was deemed not enough to act on and we then need to + * wait for more data anyway. + */ + } + else { + switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, (int)interval_ms)) { + case -1: /* select() error, stop reading */ + failf(data, "FTP response aborted due to select/poll error: %d", + SOCKERRNO); + return CURLE_RECV_ERROR; + + case 0: /* timeout */ + if(Curl_pgrsUpdate(conn)) + return CURLE_ABORTED_BY_CALLBACK; + continue; /* just continue in our loop for the timeout duration */ + + default: /* for clarity */ + break; + } + } result = ftp_readresp(sockfd, conn, ftpcode, &nread); if(result) break; + if(!nread && ftpc->cache) + /* bump cache skip counter as on repeated skips we must wait for more + data */ + cache_skip++; + else + /* when we got data or there is no cache left, we reset the cache skip + counter */ + cache_skip=0; + *nreadp += nread; - + } /* while there's buffer left and loop is requested */ return result; |