multi: avoid sending multiple complete messages
I fell over this bug report that mentioned that libcurl could wrongly send more than one complete messages at the end of a transfer. Reading the code confirmed this, so I've added a new multi state to make it not happen. The mentioned bug report was made by Brad Jorsch but is (oddly enough) filed in Debian's bug tracker for the "wmweather+" tool. Bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=593390
This commit is contained in:
parent
ac20f52ed3
commit
280d2cff2e
17
lib/multi.c
17
lib/multi.c
@ -83,7 +83,7 @@ typedef enum {
|
|||||||
CURLM_STATE_TOOFAST, /* wait because limit-rate exceeded */
|
CURLM_STATE_TOOFAST, /* wait because limit-rate exceeded */
|
||||||
CURLM_STATE_DONE, /* post data transfer operation */
|
CURLM_STATE_DONE, /* post data transfer operation */
|
||||||
CURLM_STATE_COMPLETED, /* operation complete */
|
CURLM_STATE_COMPLETED, /* operation complete */
|
||||||
|
CURLM_STATE_MSGSENT, /* the operation complete message is sent */
|
||||||
CURLM_STATE_LAST /* not a true state, never use this */
|
CURLM_STATE_LAST /* not a true state, never use this */
|
||||||
} CURLMstate;
|
} CURLMstate;
|
||||||
|
|
||||||
@ -211,6 +211,7 @@ static const char * const statename[]={
|
|||||||
"TOOFAST",
|
"TOOFAST",
|
||||||
"DONE",
|
"DONE",
|
||||||
"COMPLETED",
|
"COMPLETED",
|
||||||
|
"MSGSENT",
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -622,7 +623,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
|
|||||||
easy = data->multi_pos;
|
easy = data->multi_pos;
|
||||||
|
|
||||||
if(easy) {
|
if(easy) {
|
||||||
bool premature = (bool)(easy->state != CURLM_STATE_COMPLETED);
|
bool premature = (bool)(easy->state < CURLM_STATE_COMPLETED);
|
||||||
bool easy_owns_conn = (bool)(easy->easy_conn &&
|
bool easy_owns_conn = (bool)(easy->easy_conn &&
|
||||||
(easy->easy_conn->data == easy->easy_handle));
|
(easy->easy_conn->data == easy->easy_handle));
|
||||||
|
|
||||||
@ -837,6 +838,7 @@ static int multi_getsock(struct Curl_one_easy *easy,
|
|||||||
to be present */
|
to be present */
|
||||||
case CURLM_STATE_TOOFAST: /* returns 0, so will not select. */
|
case CURLM_STATE_TOOFAST: /* returns 0, so will not select. */
|
||||||
case CURLM_STATE_COMPLETED:
|
case CURLM_STATE_COMPLETED:
|
||||||
|
case CURLM_STATE_MSGSENT:
|
||||||
case CURLM_STATE_INIT:
|
case CURLM_STATE_INIT:
|
||||||
case CURLM_STATE_CONNECT:
|
case CURLM_STATE_CONNECT:
|
||||||
case CURLM_STATE_WAITDO:
|
case CURLM_STATE_WAITDO:
|
||||||
@ -952,7 +954,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
infof(data, "Pipe broke: handle 0x%p, url = %s\n",
|
infof(data, "Pipe broke: handle 0x%p, url = %s\n",
|
||||||
easy, data->state.path);
|
easy, data->state.path);
|
||||||
|
|
||||||
if(easy->state != CURLM_STATE_COMPLETED) {
|
if(easy->state < CURLM_STATE_COMPLETED) {
|
||||||
/* Head back to the CONNECT state */
|
/* Head back to the CONNECT state */
|
||||||
multistate(easy, CURLM_STATE_CONNECT);
|
multistate(easy, CURLM_STATE_CONNECT);
|
||||||
result = CURLM_CALL_MULTI_PERFORM;
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
@ -1563,11 +1565,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
easy->easy_conn = NULL;
|
easy->easy_conn = NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CURLM_STATE_MSGSENT:
|
||||||
|
return CURLM_OK; /* do nothing */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return CURLM_INTERNAL_ERROR;
|
return CURLM_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(CURLM_STATE_COMPLETED != easy->state) {
|
if(CURLM_STATE_COMPLETED > easy->state) {
|
||||||
if(CURLE_OK != easy->result) {
|
if(CURLE_OK != easy->result) {
|
||||||
/*
|
/*
|
||||||
* If an error was returned, and we aren't in completed state now,
|
* If an error was returned, and we aren't in completed state now,
|
||||||
@ -1625,6 +1630,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
msg->extmsg.data.result = easy->result;
|
msg->extmsg.data.result = easy->result;
|
||||||
|
|
||||||
result = multi_addmsg(multi, msg);
|
result = multi_addmsg(multi, msg);
|
||||||
|
|
||||||
|
multistate(easy, CURLM_STATE_MSGSENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -2686,7 +2693,7 @@ void Curl_multi_dump(const struct Curl_multi *multi_handle)
|
|||||||
fprintf(stderr, "* Multi status: %d handles, %d alive\n",
|
fprintf(stderr, "* Multi status: %d handles, %d alive\n",
|
||||||
multi->num_easy, multi->num_alive);
|
multi->num_easy, multi->num_alive);
|
||||||
for(easy=multi->easy.next; easy != &multi->easy; easy = easy->next) {
|
for(easy=multi->easy.next; easy != &multi->easy; easy = easy->next) {
|
||||||
if(easy->state != CURLM_STATE_COMPLETED) {
|
if(easy->state < CURLM_STATE_COMPLETED) {
|
||||||
/* only display handles that are not completed */
|
/* only display handles that are not completed */
|
||||||
fprintf(stderr, "handle %p, state %s, %d sockets\n",
|
fprintf(stderr, "handle %p, state %s, %d sockets\n",
|
||||||
(void *)easy->easy_handle,
|
(void *)easy->easy_handle,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user