- Lots of good work by Krister Johansen, mostly related to pipelining:
Fix SIGSEGV on free'd easy_conn when pipe unexpectedly breaks Fix data corruption issue with re-connected transfers Fix use after free if we're completed but easy_conn not NULL
This commit is contained in:
parent
2c4fcf2ea8
commit
1048043963
7
CHANGES
7
CHANGES
@ -6,6 +6,13 @@
|
|||||||
|
|
||||||
Changelog
|
Changelog
|
||||||
|
|
||||||
|
Daniel Stenberg (21 Aug 2009)
|
||||||
|
- Lots of good work by Krister Johansen, mostly related to pipelining:
|
||||||
|
|
||||||
|
Fix SIGSEGV on free'd easy_conn when pipe unexpectedly breaks
|
||||||
|
Fix data corruption issue with re-connected transfers
|
||||||
|
Fix use after free if we're completed but easy_conn not NULL
|
||||||
|
|
||||||
Kamil Dudka (13 Aug 2009)
|
Kamil Dudka (13 Aug 2009)
|
||||||
- Changed NSS code to not ignore the value of ssl.verifyhost and produce more
|
- Changed NSS code to not ignore the value of ssl.verifyhost and produce more
|
||||||
verbose error messages. Originally reported at:
|
verbose error messages. Originally reported at:
|
||||||
|
@ -14,6 +14,10 @@ This release includes the following changes:
|
|||||||
This release includes the following bugfixes:
|
This release includes the following bugfixes:
|
||||||
|
|
||||||
o The windows makefiles work again
|
o The windows makefiles work again
|
||||||
|
o libcurl-NSS acknowledges verifyhost
|
||||||
|
o SIGSEGV when pipelined pipe unexpectedly breaks
|
||||||
|
o data corruption issue with re-connected transfers
|
||||||
|
o use after free if we're completed but easy_conn not NULL (pipelined)
|
||||||
|
|
||||||
This release includes the following known bugs:
|
This release includes the following known bugs:
|
||||||
|
|
||||||
@ -22,6 +26,6 @@ This release includes the following known bugs:
|
|||||||
This release would not have looked like this without help, code, reports and
|
This release would not have looked like this without help, code, reports and
|
||||||
advice from friends like these:
|
advice from friends like these:
|
||||||
|
|
||||||
Karl Moerder
|
Karl Moerder, Kamil Dudka, Krister Johansen,
|
||||||
|
|
||||||
Thanks! (and sorry if I forgot to mention someone)
|
Thanks! (and sorry if I forgot to mention someone)
|
||||||
|
@ -10,9 +10,6 @@ To be addressed in 7.19.7 (planned release: October 2009)
|
|||||||
254 - Problem re-using easy handle after call to curl_multi_remove_handle
|
254 - Problem re-using easy handle after call to curl_multi_remove_handle
|
||||||
http://curl.haxx.se/mail/lib-2009-07/0249.html
|
http://curl.haxx.se/mail/lib-2009-07/0249.html
|
||||||
|
|
||||||
255 - debugging a crash in Curl_pgrsTime/checkPendPipeline?
|
|
||||||
http://curl.haxx.se/mail/lib-2009-08/0066.html
|
|
||||||
|
|
||||||
256 - "More questions about ares behavior"
|
256 - "More questions about ares behavior"
|
||||||
http://curl.haxx.se/mail/lib-2009-08/0012.html
|
http://curl.haxx.se/mail/lib-2009-08/0012.html
|
||||||
|
|
||||||
|
@ -12,9 +12,6 @@ may have been fixed since this was written!
|
|||||||
70. Problem re-using easy handle after call to curl_multi_remove_handle
|
70. Problem re-using easy handle after call to curl_multi_remove_handle
|
||||||
http://curl.haxx.se/mail/lib-2009-07/0249.html
|
http://curl.haxx.se/mail/lib-2009-07/0249.html
|
||||||
|
|
||||||
69. debugging a crash in Curl_pgrsTime/checkPendPipeline?
|
|
||||||
http://curl.haxx.se/mail/lib-2009-08/0066.html
|
|
||||||
|
|
||||||
68. "More questions about ares behavior".
|
68. "More questions about ares behavior".
|
||||||
http://curl.haxx.se/mail/lib-2009-08/0012.html
|
http://curl.haxx.se/mail/lib-2009-08/0012.html
|
||||||
|
|
||||||
|
127
lib/multi.c
127
lib/multi.c
@ -192,7 +192,9 @@ static int update_timer(struct Curl_multi *multi);
|
|||||||
static CURLcode addHandleToSendOrPendPipeline(struct SessionHandle *handle,
|
static CURLcode addHandleToSendOrPendPipeline(struct SessionHandle *handle,
|
||||||
struct connectdata *conn);
|
struct connectdata *conn);
|
||||||
static int checkPendPipeline(struct connectdata *conn);
|
static int checkPendPipeline(struct connectdata *conn);
|
||||||
static void moveHandleFromSendToRecvPipeline(struct SessionHandle *habdle,
|
static void moveHandleFromSendToRecvPipeline(struct SessionHandle *handle,
|
||||||
|
struct connectdata *conn);
|
||||||
|
static void moveHandleFromRecvToDonePipeline(struct SessionHandle *handle,
|
||||||
struct connectdata *conn);
|
struct connectdata *conn);
|
||||||
static bool isHandleAtHead(struct SessionHandle *handle,
|
static bool isHandleAtHead(struct SessionHandle *handle,
|
||||||
struct curl_llist *pipeline);
|
struct curl_llist *pipeline);
|
||||||
@ -233,14 +235,16 @@ static void multistate(struct Curl_one_easy *easy, CURLMstate state)
|
|||||||
easy->state = state;
|
easy->state = state;
|
||||||
|
|
||||||
#ifdef DEBUGBUILD
|
#ifdef DEBUGBUILD
|
||||||
if(easy->state > CURLM_STATE_CONNECT &&
|
if(easy->easy_conn) {
|
||||||
easy->state < CURLM_STATE_COMPLETED)
|
if(easy->state > CURLM_STATE_CONNECT &&
|
||||||
connectindex = easy->easy_conn->connectindex;
|
easy->state < CURLM_STATE_COMPLETED)
|
||||||
|
connectindex = easy->easy_conn->connectindex;
|
||||||
|
|
||||||
infof(easy->easy_handle,
|
infof(easy->easy_handle,
|
||||||
"STATE: %s => %s handle %p; (connection #%ld) \n",
|
"STATE: %s => %s handle %p; (connection #%ld) \n",
|
||||||
statename[oldstate], statename[easy->state],
|
statename[oldstate], statename[easy->state],
|
||||||
(char *)easy, connectindex);
|
(char *)easy, connectindex);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if(state == CURLM_STATE_COMPLETED)
|
if(state == CURLM_STATE_COMPLETED)
|
||||||
/* changing to COMPLETED means there's one less easy handle 'alive' */
|
/* changing to COMPLETED means there's one less easy handle 'alive' */
|
||||||
@ -925,7 +929,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(easy->state > CURLM_STATE_CONNECT &&
|
if(easy->easy_conn && easy->state > CURLM_STATE_CONNECT &&
|
||||||
easy->state < CURLM_STATE_COMPLETED)
|
easy->state < CURLM_STATE_COMPLETED)
|
||||||
/* Make sure we set the connection's current owner */
|
/* Make sure we set the connection's current owner */
|
||||||
easy->easy_conn->data = easy->easy_handle;
|
easy->easy_conn->data = easy->easy_handle;
|
||||||
@ -1149,7 +1153,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
&dophase_done);
|
&dophase_done);
|
||||||
|
|
||||||
if(CURLE_OK == easy->result) {
|
if(CURLE_OK == easy->result) {
|
||||||
|
|
||||||
if(!dophase_done) {
|
if(!dophase_done) {
|
||||||
/* DO was not completed in one function call, we must continue
|
/* DO was not completed in one function call, we must continue
|
||||||
DOING... */
|
DOING... */
|
||||||
@ -1170,6 +1173,49 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
result = CURLM_CALL_MULTI_PERFORM;
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if ((CURLE_SEND_ERROR == easy->result) &&
|
||||||
|
easy->easy_conn->bits.reuse) {
|
||||||
|
/*
|
||||||
|
* In this situation, a connection that we were trying to use
|
||||||
|
* may have unexpectedly died. If possible, send the connection
|
||||||
|
* back to the CONNECT phase so we can try again.
|
||||||
|
*/
|
||||||
|
char *newurl;
|
||||||
|
followtype follow=FOLLOW_NONE;
|
||||||
|
CURLcode drc;
|
||||||
|
bool retry = Curl_retry_request(easy->easy_conn, &newurl);
|
||||||
|
|
||||||
|
Curl_posttransfer(easy->easy_handle);
|
||||||
|
drc = Curl_done(&easy->easy_conn, easy->result, FALSE);
|
||||||
|
|
||||||
|
/* When set to retry the connection, we must to go back to
|
||||||
|
* the CONNECT state */
|
||||||
|
if(retry) {
|
||||||
|
if ((drc == CURLE_OK) || (drc == CURLE_SEND_ERROR)) {
|
||||||
|
follow = FOLLOW_RETRY;
|
||||||
|
drc = Curl_follow(easy->easy_handle, newurl, follow);
|
||||||
|
if(drc == CURLE_OK) {
|
||||||
|
multistate(easy, CURLM_STATE_CONNECT);
|
||||||
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
|
easy->result = CURLE_OK;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Follow failed */
|
||||||
|
easy->result = drc;
|
||||||
|
free(newurl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* done didn't return OK or SEND_ERROR */
|
||||||
|
easy->result = drc;
|
||||||
|
free(newurl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Have error handler disconnect conn if we can't retry */
|
||||||
|
disconnect_conn = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
/* failure detected */
|
/* failure detected */
|
||||||
Curl_posttransfer(easy->easy_handle);
|
Curl_posttransfer(easy->easy_handle);
|
||||||
@ -1331,8 +1377,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
Curl_posttransfer(easy->easy_handle);
|
Curl_posttransfer(easy->easy_handle);
|
||||||
|
|
||||||
/* we're no longer receving */
|
/* we're no longer receving */
|
||||||
Curl_removeHandleFromPipeline(easy->easy_handle,
|
moveHandleFromRecvToDonePipeline(easy->easy_handle,
|
||||||
easy->easy_conn->recv_pipe);
|
easy->easy_conn);
|
||||||
|
|
||||||
/* expire the new receiving pipeline head */
|
/* expire the new receiving pipeline head */
|
||||||
if(easy->easy_conn->recv_pipe->head)
|
if(easy->easy_conn->recv_pipe->head)
|
||||||
@ -1386,22 +1432,36 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CURLM_STATE_DONE:
|
case CURLM_STATE_DONE:
|
||||||
/* Remove ourselves from the receive pipeline */
|
|
||||||
Curl_removeHandleFromPipeline(easy->easy_handle,
|
|
||||||
easy->easy_conn->recv_pipe);
|
|
||||||
/* Check if we can move pending requests to send pipe */
|
|
||||||
checkPendPipeline(easy->easy_conn);
|
|
||||||
|
|
||||||
if(easy->easy_conn->bits.stream_was_rewound) {
|
if(easy->easy_conn) {
|
||||||
/* This request read past its response boundary so we quickly let the
|
/* Remove ourselves from the receive and done pipelines. Handle
|
||||||
other requests consume those bytes since there is no guarantee that
|
should be on one of these lists, depending upon how we got here. */
|
||||||
the socket will become active again */
|
Curl_removeHandleFromPipeline(easy->easy_handle,
|
||||||
result = CURLM_CALL_MULTI_PERFORM;
|
easy->easy_conn->recv_pipe);
|
||||||
|
Curl_removeHandleFromPipeline(easy->easy_handle,
|
||||||
|
easy->easy_conn->done_pipe);
|
||||||
|
/* Check if we can move pending requests to send pipe */
|
||||||
|
checkPendPipeline(easy->easy_conn);
|
||||||
|
|
||||||
|
if(easy->easy_conn->bits.stream_was_rewound) {
|
||||||
|
/* This request read past its response boundary so we quickly let
|
||||||
|
the other requests consume those bytes since there is no
|
||||||
|
guarantee that the socket will become active again */
|
||||||
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* post-transfer command */
|
||||||
|
easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE);
|
||||||
|
/*
|
||||||
|
* If there are other handles on the pipeline, Curl_done won't set
|
||||||
|
* easy_conn to NULL. In such a case, curl_multi_remove_handle() can
|
||||||
|
* access free'd data, if the connection is free'd and the handle
|
||||||
|
* removed before we perform the processing in CURLM_STATE_COMPLETED
|
||||||
|
*/
|
||||||
|
if (easy->easy_conn)
|
||||||
|
easy->easy_conn = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* post-transfer command */
|
|
||||||
easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE);
|
|
||||||
|
|
||||||
/* after we have DONE what we're supposed to do, go COMPLETED, and
|
/* after we have DONE what we're supposed to do, go COMPLETED, and
|
||||||
it doesn't matter what the Curl_done() returned! */
|
it doesn't matter what the Curl_done() returned! */
|
||||||
multistate(easy, CURLM_STATE_COMPLETED);
|
multistate(easy, CURLM_STATE_COMPLETED);
|
||||||
@ -1443,6 +1503,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
easy->easy_conn->send_pipe);
|
easy->easy_conn->send_pipe);
|
||||||
Curl_removeHandleFromPipeline(easy->easy_handle,
|
Curl_removeHandleFromPipeline(easy->easy_handle,
|
||||||
easy->easy_conn->recv_pipe);
|
easy->easy_conn->recv_pipe);
|
||||||
|
Curl_removeHandleFromPipeline(easy->easy_handle,
|
||||||
|
easy->easy_conn->done_pipe);
|
||||||
/* Check if we can move pending requests to send pipe */
|
/* Check if we can move pending requests to send pipe */
|
||||||
checkPendPipeline(easy->easy_conn);
|
checkPendPipeline(easy->easy_conn);
|
||||||
}
|
}
|
||||||
@ -2173,6 +2235,21 @@ static void moveHandleFromSendToRecvPipeline(struct SessionHandle *handle,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void moveHandleFromRecvToDonePipeline(struct SessionHandle *handle,
|
||||||
|
struct connectdata *conn)
|
||||||
|
{
|
||||||
|
struct curl_llist_element *curr;
|
||||||
|
|
||||||
|
curr = conn->recv_pipe->head;
|
||||||
|
while(curr) {
|
||||||
|
if(curr->ptr == handle) {
|
||||||
|
Curl_llist_move(conn->recv_pipe, curr,
|
||||||
|
conn->done_pipe, conn->done_pipe->tail);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
curr = curr->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
static bool isHandleAtHead(struct SessionHandle *handle,
|
static bool isHandleAtHead(struct SessionHandle *handle,
|
||||||
struct curl_llist *pipeline)
|
struct curl_llist *pipeline)
|
||||||
{
|
{
|
||||||
|
@ -176,7 +176,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!data->req.forbidchunk && data->req.upload_chunky) {
|
if(!data->req.forbidchunk && data->req.upload_chunky) {
|
||||||
/* if chunked Transfer-Encoding
|
/* if chunked Transfer-Encoding
|
||||||
* build chunk:
|
* build chunk:
|
||||||
*
|
*
|
||||||
* <HEX SIZE> CRLF
|
* <HEX SIZE> CRLF
|
||||||
@ -217,9 +217,9 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
|
|||||||
/* copy the prefix to the buffer, leaving out the NUL */
|
/* copy the prefix to the buffer, leaving out the NUL */
|
||||||
memcpy(data->req.upload_fromhere, hexbuffer, hexlen);
|
memcpy(data->req.upload_fromhere, hexbuffer, hexlen);
|
||||||
|
|
||||||
/* always append ASCII CRLF to the data */
|
/* always append ASCII CRLF to the data */
|
||||||
memcpy(data->req.upload_fromhere + nread,
|
memcpy(data->req.upload_fromhere + nread,
|
||||||
endofline_network,
|
endofline_network,
|
||||||
strlen(endofline_network));
|
strlen(endofline_network));
|
||||||
|
|
||||||
#ifdef CURL_DOES_CONVERSIONS
|
#ifdef CURL_DOES_CONVERSIONS
|
||||||
@ -2495,6 +2495,61 @@ connect_host(struct SessionHandle *data,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CURLcode
|
||||||
|
Curl_reconnect_request(struct connectdata **connp)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct connectdata *conn = *connp;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
|
/* This was a re-use of a connection and we got a write error in the
|
||||||
|
* DO-phase. Then we DISCONNECT this connection and have another attempt to
|
||||||
|
* CONNECT and then DO again! The retry cannot possibly find another
|
||||||
|
* connection to re-use, since we only keep one possible connection for
|
||||||
|
* each. */
|
||||||
|
|
||||||
|
infof(data, "Re-used connection seems dead, get a new one\n");
|
||||||
|
|
||||||
|
conn->bits.close = TRUE; /* enforce close of this connection */
|
||||||
|
result = Curl_done(&conn, result, FALSE); /* we are so done with this */
|
||||||
|
|
||||||
|
/* conn may no longer be a good pointer */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* According to bug report #1330310. We need to check for CURLE_SEND_ERROR
|
||||||
|
* here as well. I figure this could happen when the request failed on a FTP
|
||||||
|
* connection and thus Curl_done() itself tried to use the connection
|
||||||
|
* (again). Slight Lack of feedback in the report, but I don't think this
|
||||||
|
* extra check can do much harm.
|
||||||
|
*/
|
||||||
|
if((CURLE_OK == result) || (CURLE_SEND_ERROR == result)) {
|
||||||
|
bool async;
|
||||||
|
bool protocol_done = TRUE;
|
||||||
|
|
||||||
|
/* Now, redo the connect and get a new connection */
|
||||||
|
result = Curl_connect(data, connp, &async, &protocol_done);
|
||||||
|
if(CURLE_OK == result) {
|
||||||
|
/* We have connected or sent away a name resolve query fine */
|
||||||
|
|
||||||
|
conn = *connp; /* setup conn to again point to something nice */
|
||||||
|
if(async) {
|
||||||
|
/* Now, if async is TRUE here, we need to wait for the name
|
||||||
|
to resolve */
|
||||||
|
result = Curl_wait_for_resolv(conn, NULL);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* Resolved, continue with the connection */
|
||||||
|
result = Curl_async_resolved(conn, &protocol_done);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* Returns TRUE and sets '*url' if a request retry is wanted.
|
/* Returns TRUE and sets '*url' if a request retry is wanted.
|
||||||
|
|
||||||
NOTE: that the *url is malloc()ed. */
|
NOTE: that the *url is malloc()ed. */
|
||||||
|
@ -46,6 +46,7 @@ int Curl_single_getsock(const struct connectdata *conn,
|
|||||||
int numsocks);
|
int numsocks);
|
||||||
CURLcode Curl_readrewind(struct connectdata *conn);
|
CURLcode Curl_readrewind(struct connectdata *conn);
|
||||||
CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp);
|
CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp);
|
||||||
|
CURLcode Curl_reconnect_request(struct connectdata **connp);
|
||||||
bool Curl_retry_request(struct connectdata *conn, char **url);
|
bool Curl_retry_request(struct connectdata *conn, char **url);
|
||||||
|
|
||||||
/* This sets up a forthcoming transfer */
|
/* This sets up a forthcoming transfer */
|
||||||
|
88
lib/url.c
88
lib/url.c
@ -146,7 +146,7 @@ void idn_free (void *ptr); /* prototype from idn-free.h, not provided by
|
|||||||
/* Local static prototypes */
|
/* Local static prototypes */
|
||||||
static long ConnectionKillOne(struct SessionHandle *data);
|
static long ConnectionKillOne(struct SessionHandle *data);
|
||||||
static void conn_free(struct connectdata *conn);
|
static void conn_free(struct connectdata *conn);
|
||||||
static void signalPipeClose(struct curl_llist *pipeline);
|
static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke);
|
||||||
|
|
||||||
#ifdef CURL_DISABLE_VERBOSE_STRINGS
|
#ifdef CURL_DISABLE_VERBOSE_STRINGS
|
||||||
#define verboseconnect(x) do { } while (0)
|
#define verboseconnect(x) do { } while (0)
|
||||||
@ -420,6 +420,16 @@ CURLcode Curl_close(struct SessionHandle *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pipeline = connptr->done_pipe;
|
||||||
|
if(pipeline) {
|
||||||
|
for (curr = pipeline->head; curr; curr=curr->next) {
|
||||||
|
if(data == (struct SessionHandle *) curr->ptr) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"MAJOR problem we %p are still in done pipe for %p done %d\n",
|
||||||
|
data, connptr, (int)connptr->bits.done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
pipeline = connptr->pend_pipe;
|
pipeline = connptr->pend_pipe;
|
||||||
if(pipeline) {
|
if(pipeline) {
|
||||||
for (curr = pipeline->head; curr; curr=curr->next) {
|
for (curr = pipeline->head; curr; curr=curr->next) {
|
||||||
@ -2316,6 +2326,7 @@ static void conn_free(struct connectdata *conn)
|
|||||||
Curl_llist_destroy(conn->send_pipe, NULL);
|
Curl_llist_destroy(conn->send_pipe, NULL);
|
||||||
Curl_llist_destroy(conn->recv_pipe, NULL);
|
Curl_llist_destroy(conn->recv_pipe, NULL);
|
||||||
Curl_llist_destroy(conn->pend_pipe, NULL);
|
Curl_llist_destroy(conn->pend_pipe, NULL);
|
||||||
|
Curl_llist_destroy(conn->done_pipe, NULL);
|
||||||
|
|
||||||
/* possible left-overs from the async name resolvers */
|
/* possible left-overs from the async name resolvers */
|
||||||
#if defined(USE_ARES)
|
#if defined(USE_ARES)
|
||||||
@ -2415,9 +2426,10 @@ CURLcode Curl_disconnect(struct connectdata *conn)
|
|||||||
|
|
||||||
/* Indicate to all handles on the pipe that we're dead */
|
/* Indicate to all handles on the pipe that we're dead */
|
||||||
if(Curl_isPipeliningEnabled(data)) {
|
if(Curl_isPipeliningEnabled(data)) {
|
||||||
signalPipeClose(conn->send_pipe);
|
signalPipeClose(conn->send_pipe, TRUE);
|
||||||
signalPipeClose(conn->recv_pipe);
|
signalPipeClose(conn->recv_pipe, TRUE);
|
||||||
signalPipeClose(conn->pend_pipe);
|
signalPipeClose(conn->pend_pipe, TRUE);
|
||||||
|
signalPipeClose(conn->done_pipe, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
conn_free(conn);
|
conn_free(conn);
|
||||||
@ -2535,9 +2547,10 @@ void Curl_getoff_all_pipelines(struct SessionHandle *data,
|
|||||||
if(Curl_removeHandleFromPipeline(data, conn->send_pipe) && send_head)
|
if(Curl_removeHandleFromPipeline(data, conn->send_pipe) && send_head)
|
||||||
conn->writechannel_inuse = FALSE;
|
conn->writechannel_inuse = FALSE;
|
||||||
Curl_removeHandleFromPipeline(data, conn->pend_pipe);
|
Curl_removeHandleFromPipeline(data, conn->pend_pipe);
|
||||||
|
Curl_removeHandleFromPipeline(data, conn->done_pipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void signalPipeClose(struct curl_llist *pipeline)
|
static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke)
|
||||||
{
|
{
|
||||||
struct curl_llist_element *curr;
|
struct curl_llist_element *curr;
|
||||||
|
|
||||||
@ -2556,7 +2569,8 @@ static void signalPipeClose(struct curl_llist *pipeline)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
data->state.pipe_broke = TRUE;
|
if (pipe_broke)
|
||||||
|
data->state.pipe_broke = TRUE;
|
||||||
Curl_multi_handlePipeBreak(data);
|
Curl_multi_handlePipeBreak(data);
|
||||||
Curl_llist_remove(pipeline, curr, NULL);
|
Curl_llist_remove(pipeline, curr, NULL);
|
||||||
curr = next;
|
curr = next;
|
||||||
@ -4217,6 +4231,7 @@ static void reuse_conn(struct connectdata *old_conn,
|
|||||||
Curl_llist_destroy(old_conn->send_pipe, NULL);
|
Curl_llist_destroy(old_conn->send_pipe, NULL);
|
||||||
Curl_llist_destroy(old_conn->recv_pipe, NULL);
|
Curl_llist_destroy(old_conn->recv_pipe, NULL);
|
||||||
Curl_llist_destroy(old_conn->pend_pipe, NULL);
|
Curl_llist_destroy(old_conn->pend_pipe, NULL);
|
||||||
|
Curl_llist_destroy(old_conn->done_pipe, NULL);
|
||||||
Curl_safefree(old_conn->master_buffer);
|
Curl_safefree(old_conn->master_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4319,7 +4334,9 @@ static CURLcode create_conn(struct SessionHandle *data,
|
|||||||
conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
|
conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
|
||||||
conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
|
conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
|
||||||
conn->pend_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
|
conn->pend_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
|
||||||
if(!conn->send_pipe || !conn->recv_pipe || !conn->pend_pipe)
|
conn->done_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
|
||||||
|
if(!conn->send_pipe || !conn->recv_pipe || !conn->pend_pipe ||
|
||||||
|
!conn->done_pipe)
|
||||||
return CURLE_OUT_OF_MEMORY;
|
return CURLE_OUT_OF_MEMORY;
|
||||||
|
|
||||||
/* This initing continues below, see the comment "Continue connectdata
|
/* This initing continues below, see the comment "Continue connectdata
|
||||||
@ -5001,53 +5018,22 @@ CURLcode Curl_do(struct connectdata **connp, bool *done)
|
|||||||
|
|
||||||
/* This was formerly done in transfer.c, but we better do it here */
|
/* This was formerly done in transfer.c, but we better do it here */
|
||||||
if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
|
if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
|
||||||
/* This was a re-use of a connection and we got a write error in the
|
/*
|
||||||
* DO-phase. Then we DISCONNECT this connection and have another attempt
|
* If the connection is using an easy handle, call reconnect
|
||||||
* to CONNECT and then DO again! The retry cannot possibly find another
|
* to re-establish the connection. Otherwise, let the multi logic
|
||||||
* connection to re-use, since we only keep one possible connection for
|
* figure out how to re-establish the connection.
|
||||||
* each. */
|
*/
|
||||||
|
if(!data->multi) {
|
||||||
|
result = Curl_reconnect_request(connp);
|
||||||
|
|
||||||
infof(data, "Re-used connection seems dead, get a new one\n");
|
if(result == CURLE_OK) {
|
||||||
|
/* ... finally back to actually retry the DO phase */
|
||||||
conn->bits.close = TRUE; /* enforce close of this connection */
|
result = conn->handler->do_it(conn, done);
|
||||||
result = Curl_done(&conn, result, FALSE); /* we are so done with this */
|
|
||||||
|
|
||||||
/* conn may no longer be a good pointer */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* According to bug report #1330310. We need to check for
|
|
||||||
* CURLE_SEND_ERROR here as well. I figure this could happen when the
|
|
||||||
* request failed on a FTP connection and thus Curl_done() itself tried
|
|
||||||
* to use the connection (again). Slight Lack of feedback in the report,
|
|
||||||
* but I don't think this extra check can do much harm.
|
|
||||||
*/
|
|
||||||
if((CURLE_OK == result) || (CURLE_SEND_ERROR == result)) {
|
|
||||||
bool async;
|
|
||||||
bool protocol_done = TRUE;
|
|
||||||
|
|
||||||
/* Now, redo the connect and get a new connection */
|
|
||||||
result = Curl_connect(data, connp, &async, &protocol_done);
|
|
||||||
if(CURLE_OK == result) {
|
|
||||||
/* We have connected or sent away a name resolve query fine */
|
|
||||||
|
|
||||||
conn = *connp; /* setup conn to again point to something nice */
|
|
||||||
if(async) {
|
|
||||||
/* Now, if async is TRUE here, we need to wait for the name
|
|
||||||
to resolve */
|
|
||||||
result = Curl_wait_for_resolv(conn, NULL);
|
|
||||||
if(result)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
/* Resolved, continue with the connection */
|
|
||||||
result = Curl_async_resolved(conn, &protocol_done);
|
|
||||||
if(result)
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ... finally back to actually retry the DO phase */
|
|
||||||
result = conn->handler->do_it(conn, done);
|
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if((result == CURLE_OK) && *done)
|
if((result == CURLE_OK) && *done)
|
||||||
|
@ -1028,6 +1028,8 @@ struct connectdata {
|
|||||||
their responses on this pipeline */
|
their responses on this pipeline */
|
||||||
struct curl_llist *pend_pipe; /* List of pending handles on
|
struct curl_llist *pend_pipe; /* List of pending handles on
|
||||||
this pipeline */
|
this pipeline */
|
||||||
|
struct curl_llist *done_pipe; /* Handles that are finished, but
|
||||||
|
still reference this connectdata */
|
||||||
#define MAX_PIPELINE_LENGTH 5
|
#define MAX_PIPELINE_LENGTH 5
|
||||||
|
|
||||||
char* master_buffer; /* The master buffer allocated on-demand;
|
char* master_buffer; /* The master buffer allocated on-demand;
|
||||||
|
Loading…
Reference in New Issue
Block a user