Loading CHANGES +7 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,13 @@ 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) - Changed NSS code to not ignore the value of ssl.verifyhost and produce more verbose error messages. Originally reported at: Loading RELEASE-NOTES +5 −1 Original line number Diff line number Diff line Loading @@ -14,6 +14,10 @@ This release includes the following changes: This release includes the following bugfixes: 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: Loading @@ -22,6 +26,6 @@ This release includes the following known bugs: This release would not have looked like this without help, code, reports and advice from friends like these: Karl Moerder Karl Moerder, Kamil Dudka, Krister Johansen, Thanks! (and sorry if I forgot to mention someone) TODO-RELEASE +0 −3 Original line number Diff line number Diff line Loading @@ -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 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" http://curl.haxx.se/mail/lib-2009-08/0012.html Loading docs/KNOWN_BUGS +0 −3 Original line number Diff line number Diff line Loading @@ -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 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". http://curl.haxx.se/mail/lib-2009-08/0012.html Loading lib/multi.c +102 −25 Original line number Diff line number Diff line Loading @@ -192,7 +192,9 @@ static int update_timer(struct Curl_multi *multi); static CURLcode addHandleToSendOrPendPipeline(struct SessionHandle *handle, 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); static bool isHandleAtHead(struct SessionHandle *handle, struct curl_llist *pipeline); Loading Loading @@ -233,6 +235,7 @@ static void multistate(struct Curl_one_easy *easy, CURLMstate state) easy->state = state; #ifdef DEBUGBUILD if(easy->easy_conn) { if(easy->state > CURLM_STATE_CONNECT && easy->state < CURLM_STATE_COMPLETED) connectindex = easy->easy_conn->connectindex; Loading @@ -241,6 +244,7 @@ static void multistate(struct Curl_one_easy *easy, CURLMstate state) "STATE: %s => %s handle %p; (connection #%ld) \n", statename[oldstate], statename[easy->state], (char *)easy, connectindex); } #endif if(state == CURLM_STATE_COMPLETED) /* changing to COMPLETED means there's one less easy handle 'alive' */ Loading Loading @@ -925,7 +929,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, break; } if(easy->state > CURLM_STATE_CONNECT && if(easy->easy_conn && easy->state > CURLM_STATE_CONNECT && easy->state < CURLM_STATE_COMPLETED) /* Make sure we set the connection's current owner */ easy->easy_conn->data = easy->easy_handle; Loading Loading @@ -1149,7 +1153,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, &dophase_done); if(CURLE_OK == easy->result) { if(!dophase_done) { /* DO was not completed in one function call, we must continue DOING... */ Loading @@ -1170,6 +1173,49 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, 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 { /* failure detected */ Curl_posttransfer(easy->easy_handle); Loading Loading @@ -1331,8 +1377,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, Curl_posttransfer(easy->easy_handle); /* we're no longer receving */ Curl_removeHandleFromPipeline(easy->easy_handle, easy->easy_conn->recv_pipe); moveHandleFromRecvToDonePipeline(easy->easy_handle, easy->easy_conn); /* expire the new receiving pipeline head */ if(easy->easy_conn->recv_pipe->head) Loading Loading @@ -1386,21 +1432,35 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, break; case CURLM_STATE_DONE: /* Remove ourselves from the receive pipeline */ if(easy->easy_conn) { /* Remove ourselves from the receive and done pipelines. Handle should be on one of these lists, depending upon how we got here. */ Curl_removeHandleFromPipeline(easy->easy_handle, 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 */ /* 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; } /* after we have DONE what we're supposed to do, go COMPLETED, and it doesn't matter what the Curl_done() returned! */ Loading Loading @@ -1443,6 +1503,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, easy->easy_conn->send_pipe); Curl_removeHandleFromPipeline(easy->easy_handle, 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); } Loading Loading @@ -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, struct curl_llist *pipeline) { Loading Loading
CHANGES +7 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,13 @@ 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) - Changed NSS code to not ignore the value of ssl.verifyhost and produce more verbose error messages. Originally reported at: Loading
RELEASE-NOTES +5 −1 Original line number Diff line number Diff line Loading @@ -14,6 +14,10 @@ This release includes the following changes: This release includes the following bugfixes: 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: Loading @@ -22,6 +26,6 @@ This release includes the following known bugs: This release would not have looked like this without help, code, reports and advice from friends like these: Karl Moerder Karl Moerder, Kamil Dudka, Krister Johansen, Thanks! (and sorry if I forgot to mention someone)
TODO-RELEASE +0 −3 Original line number Diff line number Diff line Loading @@ -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 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" http://curl.haxx.se/mail/lib-2009-08/0012.html Loading
docs/KNOWN_BUGS +0 −3 Original line number Diff line number Diff line Loading @@ -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 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". http://curl.haxx.se/mail/lib-2009-08/0012.html Loading
lib/multi.c +102 −25 Original line number Diff line number Diff line Loading @@ -192,7 +192,9 @@ static int update_timer(struct Curl_multi *multi); static CURLcode addHandleToSendOrPendPipeline(struct SessionHandle *handle, 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); static bool isHandleAtHead(struct SessionHandle *handle, struct curl_llist *pipeline); Loading Loading @@ -233,6 +235,7 @@ static void multistate(struct Curl_one_easy *easy, CURLMstate state) easy->state = state; #ifdef DEBUGBUILD if(easy->easy_conn) { if(easy->state > CURLM_STATE_CONNECT && easy->state < CURLM_STATE_COMPLETED) connectindex = easy->easy_conn->connectindex; Loading @@ -241,6 +244,7 @@ static void multistate(struct Curl_one_easy *easy, CURLMstate state) "STATE: %s => %s handle %p; (connection #%ld) \n", statename[oldstate], statename[easy->state], (char *)easy, connectindex); } #endif if(state == CURLM_STATE_COMPLETED) /* changing to COMPLETED means there's one less easy handle 'alive' */ Loading Loading @@ -925,7 +929,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, break; } if(easy->state > CURLM_STATE_CONNECT && if(easy->easy_conn && easy->state > CURLM_STATE_CONNECT && easy->state < CURLM_STATE_COMPLETED) /* Make sure we set the connection's current owner */ easy->easy_conn->data = easy->easy_handle; Loading Loading @@ -1149,7 +1153,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, &dophase_done); if(CURLE_OK == easy->result) { if(!dophase_done) { /* DO was not completed in one function call, we must continue DOING... */ Loading @@ -1170,6 +1173,49 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, 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 { /* failure detected */ Curl_posttransfer(easy->easy_handle); Loading Loading @@ -1331,8 +1377,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, Curl_posttransfer(easy->easy_handle); /* we're no longer receving */ Curl_removeHandleFromPipeline(easy->easy_handle, easy->easy_conn->recv_pipe); moveHandleFromRecvToDonePipeline(easy->easy_handle, easy->easy_conn); /* expire the new receiving pipeline head */ if(easy->easy_conn->recv_pipe->head) Loading Loading @@ -1386,21 +1432,35 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, break; case CURLM_STATE_DONE: /* Remove ourselves from the receive pipeline */ if(easy->easy_conn) { /* Remove ourselves from the receive and done pipelines. Handle should be on one of these lists, depending upon how we got here. */ Curl_removeHandleFromPipeline(easy->easy_handle, 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 */ /* 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; } /* after we have DONE what we're supposed to do, go COMPLETED, and it doesn't matter what the Curl_done() returned! */ Loading Loading @@ -1443,6 +1503,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, easy->easy_conn->send_pipe); Curl_removeHandleFromPipeline(easy->easy_handle, 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); } Loading Loading @@ -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, struct curl_llist *pipeline) { Loading