On Tue, 26 Jul 2016, Dan Donahue wrote:
If it helps, email me the patch and I'll test it and report back to you.
How about the attached patch?
--
/ daniel.haxx.se
From ec2f1b0046d77cbcfd2ef920d1666e2f8dcd6fc8 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <[email protected]>
Date: Tue, 2 Aug 2016 00:48:23 +0200
Subject: [PATCH] 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
Fixes #933
---
lib/multi.c | 5 ++++-
lib/transfer.c | 21 ++++++++++++++++++---
lib/transfer.h | 5 ++---
3 files changed, 24 insertions(+), 7 deletions(-)
diff --git a/lib/multi.c b/lib/multi.c
index 9ee3523..539b9c6 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -1808,10 +1808,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case CURLM_STATE_PERFORM:
{
char *newurl = NULL;
bool retry = FALSE;
+ bool comeback = FALSE;
/* check if over send speed */
if((data->set.max_send_speed > 0) &&
(data->progress.ulspeed > data->set.max_send_speed)) {
int buffersize;
@@ -1842,11 +1843,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
Curl_expire_latest(data, timeout_ms);
break;
}
/* read/write data if it is ready to do so */
- result = Curl_readwrite(data->easy_conn, data, &done);
+ result = Curl_readwrite(data->easy_conn, data, &done, &comeback);
k = &data->req;
if(!(k->keepon & KEEP_RECV))
/* We're done receiving */
@@ -1948,10 +1949,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
multistate(data, CURLM_STATE_DONE);
rc = CURLM_CALL_MULTI_PERFORM;
}
}
+ else if(comeback)
+ rc = CURLM_CALL_MULTI_PERFORM;
free(newurl);
break;
}
diff --git a/lib/transfer.c b/lib/transfer.c
index f5987fe..82a961f 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -382,24 +382,29 @@ 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 */
size_t excess = 0; /* excess bytes read */
bool is_empty_data = FALSE;
bool readmore = FALSE; /* used by RTP to signal for more 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 */
do {
size_t buffersize = data->set.buffer_size?
@@ -802,10 +807,16 @@ static CURLcode readwrite_data(struct Curl_easy *data,
k->keepon &= ~KEEP_RECV;
}
} 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
may now close the connection. If there's now any kind of sending going
on from our side, we need to stop that immediately. */
@@ -1027,14 +1038,18 @@ 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;
int didwhat=0;
@@ -1075,11 +1090,11 @@ CURLcode Curl_readwrite(struct connectdata *conn,
the stream was rewound (in which case we have data in a
buffer) */
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;
}
/* If we still have writing to do, we check if we have a writable socket. */
diff --git a/lib/transfer.h b/lib/transfer.h
index 0e253e3..0058f8c 100644
--- a/lib/transfer.h
+++ b/lib/transfer.h
@@ -38,14 +38,13 @@ typedef enum {
FOLLOW_LAST /* never used */
} followtype;
CURLcode Curl_follow(struct Curl_easy *data, char *newurl,
followtype type);
-
-
CURLcode Curl_readwrite(struct connectdata *conn,
- struct Curl_easy *data, bool *done);
+ struct Curl_easy *data, bool *done,
+ bool *comeback);
int Curl_single_getsock(const struct connectdata *conn,
curl_socket_t *socks,
int numsocks);
CURLcode Curl_readrewind(struct connectdata *conn);
CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp);
--
2.8.1
-------------------------------------------------------------------
List admin: https://cool.haxx.se/list/listinfo/curl-library
Etiquette: https://curl.haxx.se/mail/etiquette.html