aboutsummaryrefslogtreecommitdiff
path: root/lib/transfer.c
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2016-08-02 00:48:23 +0200
committerDaniel Stenberg <daniel@haxx.se>2016-08-04 00:23:27 +0200
commit6eb60c2dc589a15ff8a3aa5961745d86044a9b78 (patch)
tree8d0df4b11585a8b02b60e9e2d042158461c3fa53 /lib/transfer.c
parent497e7c9d3460566712b3cd81b272cde7826f264c (diff)
transfer: return without select when the read loop reached maxcount
Regression added in 790d6de48515. The was then added to avoid one particular transfer to starve out others. But when aborting due to reading the maxcount, the connection must be marked to be read from again without first doing a select as for some protocols (like SFTP/SCP) the data may already have been read off the socket. Reported-by: Dan Donahue Bug: https://curl.haxx.se/mail/lib-2016-07/0057.html
Diffstat (limited to 'lib/transfer.c')
-rw-r--r--lib/transfer.c21
1 files changed, 18 insertions, 3 deletions
diff --git a/lib/transfer.c b/lib/transfer.c
index f5987feb2..82a961f0e 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -384,11 +384,15 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc)
* Go ahead and do a read if we have a readable socket or if
* the stream was rewound (in which case we have data in a
* buffer)
+ *
+ * return '*comeback' TRUE if we didn't properly drain the socket so this
+ * function should get called again without select() or similar in between!
*/
static CURLcode readwrite_data(struct Curl_easy *data,
struct connectdata *conn,
struct SingleRequest *k,
- int *didwhat, bool *done)
+ int *didwhat, bool *done,
+ bool *comeback)
{
CURLcode result = CURLE_OK;
ssize_t nread; /* number of bytes read */
@@ -398,6 +402,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
int maxloops = 100;
*done = FALSE;
+ *comeback = FALSE;
/* This is where we loop until we have read everything there is to
read or we get a CURLE_AGAIN */
@@ -804,6 +809,12 @@ static CURLcode readwrite_data(struct Curl_easy *data,
} while(data_pending(conn) && maxloops--);
+ if(maxloops <= 0) {
+ /* we mark it as read-again-please */
+ conn->cselect_bits = CURL_CSELECT_IN;
+ *comeback = TRUE;
+ }
+
if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) &&
conn->bits.close) {
/* When we've read the entire thing and the close bit is set, the server
@@ -1029,10 +1040,14 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
/*
* Curl_readwrite() is the low-level function to be called when data is to
* be read and written to/from the connection.
+ *
+ * return '*comeback' TRUE if we didn't properly drain the socket so this
+ * function should get called again without select() or similar in between!
*/
CURLcode Curl_readwrite(struct connectdata *conn,
struct Curl_easy *data,
- bool *done)
+ bool *done,
+ bool *comeback)
{
struct SingleRequest *k = &data->req;
CURLcode result;
@@ -1077,7 +1092,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if((k->keepon & KEEP_RECV) &&
((select_res & CURL_CSELECT_IN) || conn->bits.stream_was_rewound)) {
- result = readwrite_data(data, conn, k, &didwhat, done);
+ result = readwrite_data(data, conn, k, &didwhat, done, comeback);
if(result || *done)
return result;
}