mirror of
https://github.com/moparisthebest/curl
synced 2024-12-21 23:58:49 -05:00
with pipelining disabled, the state should never be set to WAITDO but rather
go straight to DO we had multiple states for which the internal function returned no socket at all to wait for, with the effect that libcurl calls the socket callback (when curl_multi_socket() is used) with REMOVE prematurely (as it would be added again within very shortly)
This commit is contained in:
parent
3cb0dd6685
commit
ae45a462e0
79
lib/multi.c
79
lib/multi.c
@ -772,10 +772,19 @@ static int multi_getsock(struct Curl_one_easy *easy,
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch(easy->state) {
|
switch(easy->state) {
|
||||||
case CURLM_STATE_TOOFAST: /* returns 0, so will not select. */
|
|
||||||
default:
|
default:
|
||||||
|
#if 0 /* switch back on these cases to get the compiler to check for all enums
|
||||||
|
to be present */
|
||||||
|
case CURLM_STATE_TOOFAST: /* returns 0, so will not select. */
|
||||||
|
case CURLM_STATE_COMPLETED:
|
||||||
|
case CURLM_STATE_INIT:
|
||||||
|
case CURLM_STATE_CONNECT:
|
||||||
|
case CURLM_STATE_WAITDO:
|
||||||
|
case CURLM_STATE_DONE:
|
||||||
|
case CURLM_STATE_LAST:
|
||||||
/* this will get called with CURLM_STATE_COMPLETED when a handle is
|
/* this will get called with CURLM_STATE_COMPLETED when a handle is
|
||||||
removed */
|
removed */
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case CURLM_STATE_WAITRESOLVE:
|
case CURLM_STATE_WAITRESOLVE:
|
||||||
@ -784,6 +793,7 @@ static int multi_getsock(struct Curl_one_easy *easy,
|
|||||||
case CURLM_STATE_PROTOCONNECT:
|
case CURLM_STATE_PROTOCONNECT:
|
||||||
return Curl_protocol_getsock(easy->easy_conn, socks, numsocks);
|
return Curl_protocol_getsock(easy->easy_conn, socks, numsocks);
|
||||||
|
|
||||||
|
case CURLM_STATE_DO:
|
||||||
case CURLM_STATE_DOING:
|
case CURLM_STATE_DOING:
|
||||||
return Curl_doing_getsock(easy->easy_conn, socks, numsocks);
|
return Curl_doing_getsock(easy->easy_conn, socks, numsocks);
|
||||||
|
|
||||||
@ -794,6 +804,8 @@ static int multi_getsock(struct Curl_one_easy *easy,
|
|||||||
case CURLM_STATE_DO_MORE:
|
case CURLM_STATE_DO_MORE:
|
||||||
return domore_getsock(easy->easy_conn, socks, numsocks);
|
return domore_getsock(easy->easy_conn, socks, numsocks);
|
||||||
|
|
||||||
|
case CURLM_STATE_DO_DONE: /* since is set after DO is completed, we switch
|
||||||
|
to waiting for the same as the *PERFORM states */
|
||||||
case CURLM_STATE_PERFORM:
|
case CURLM_STATE_PERFORM:
|
||||||
case CURLM_STATE_WAITPERFORM:
|
case CURLM_STATE_WAITPERFORM:
|
||||||
return Curl_single_getsock(easy->easy_conn, socks, numsocks);
|
return Curl_single_getsock(easy->easy_conn, socks, numsocks);
|
||||||
@ -925,11 +937,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
else {
|
else {
|
||||||
/* after the connect has been sent off, go WAITCONNECT unless the
|
/* after the connect has been sent off, go WAITCONNECT unless the
|
||||||
protocol connect is already done and we can go directly to
|
protocol connect is already done and we can go directly to
|
||||||
WAITDO! */
|
WAITDO or DO! */
|
||||||
result = CURLM_CALL_MULTI_PERFORM;
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
|
|
||||||
if(protocol_connect)
|
if(protocol_connect)
|
||||||
multistate(easy, CURLM_STATE_WAITDO);
|
multistate(easy, multi->pipelining_enabled?
|
||||||
|
CURLM_STATE_WAITDO:CURLM_STATE_DO);
|
||||||
else {
|
else {
|
||||||
#ifndef CURL_DISABLE_HTTP
|
#ifndef CURL_DISABLE_HTTP
|
||||||
if(easy->easy_conn->bits.tunnel_connecting)
|
if(easy->easy_conn->bits.tunnel_connecting)
|
||||||
@ -965,7 +978,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
/* call again please so that we get the next socket setup */
|
/* call again please so that we get the next socket setup */
|
||||||
result = CURLM_CALL_MULTI_PERFORM;
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
if(protocol_connect)
|
if(protocol_connect)
|
||||||
multistate(easy, CURLM_STATE_WAITDO);
|
multistate(easy, multi->pipelining_enabled?
|
||||||
|
CURLM_STATE_WAITDO:CURLM_STATE_DO);
|
||||||
else {
|
else {
|
||||||
#ifndef CURL_DISABLE_HTTP
|
#ifndef CURL_DISABLE_HTTP
|
||||||
if(easy->easy_conn->bits.tunnel_connecting)
|
if(easy->easy_conn->bits.tunnel_connecting)
|
||||||
@ -1028,8 +1042,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
multistate(easy, CURLM_STATE_PROTOCONNECT);
|
multistate(easy, CURLM_STATE_PROTOCONNECT);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* after the connect has completed, go WAITDO */
|
/* after the connect has completed, go WAITDO or DO */
|
||||||
multistate(easy, CURLM_STATE_WAITDO);
|
multistate(easy, multi->pipelining_enabled?
|
||||||
|
CURLM_STATE_WAITDO:CURLM_STATE_DO);
|
||||||
|
|
||||||
result = CURLM_CALL_MULTI_PERFORM;
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
}
|
}
|
||||||
@ -1041,8 +1056,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
easy->result = Curl_protocol_connecting(easy->easy_conn,
|
easy->result = Curl_protocol_connecting(easy->easy_conn,
|
||||||
&protocol_connect);
|
&protocol_connect);
|
||||||
if((easy->result == CURLE_OK) && protocol_connect) {
|
if((easy->result == CURLE_OK) && protocol_connect) {
|
||||||
/* after the connect has completed, go WAITDO */
|
/* after the connect has completed, go WAITDO or DO */
|
||||||
multistate(easy, CURLM_STATE_WAITDO);
|
multistate(easy, multi->pipelining_enabled?
|
||||||
|
CURLM_STATE_WAITDO:CURLM_STATE_DO);
|
||||||
result = CURLM_CALL_MULTI_PERFORM;
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
}
|
}
|
||||||
else if(easy->result) {
|
else if(easy->result) {
|
||||||
@ -1712,34 +1728,39 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
|
|||||||
Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
|
Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
|
||||||
|
|
||||||
if(!entry)
|
if(!entry)
|
||||||
/* unmatched socket, major problemo! */
|
/* Unmatched socket, we can't act on it but we ignore this fact. In
|
||||||
return CURLM_BAD_SOCKET; /* better return code? */
|
real-world tests it has been proved that libevent can in fact give
|
||||||
|
the application actions even though the socket was just previously
|
||||||
|
asked to get removed, so thus we better survive stray socket actions
|
||||||
|
and just move on. */
|
||||||
|
;
|
||||||
|
else {
|
||||||
|
data = entry->easy;
|
||||||
|
|
||||||
data = entry->easy;
|
if(data->magic != CURLEASY_MAGIC_NUMBER)
|
||||||
|
/* bad bad bad bad bad bad bad */
|
||||||
|
return CURLM_INTERNAL_ERROR;
|
||||||
|
|
||||||
if(data->magic != CURLEASY_MAGIC_NUMBER)
|
if(data->set.one_easy->easy_conn) /* set socket event bitmask */
|
||||||
/* bad bad bad bad bad bad bad */
|
data->set.one_easy->easy_conn->cselect_bits = ev_bitmask;
|
||||||
return CURLM_INTERNAL_ERROR;
|
|
||||||
|
|
||||||
if(data->set.one_easy->easy_conn) /* set socket event bitmask */
|
result = multi_runsingle(multi, data->set.one_easy);
|
||||||
data->set.one_easy->easy_conn->cselect_bits = ev_bitmask;
|
|
||||||
|
|
||||||
result = multi_runsingle(multi, data->set.one_easy);
|
if(data->set.one_easy->easy_conn)
|
||||||
|
data->set.one_easy->easy_conn->cselect_bits = 0;
|
||||||
|
|
||||||
if(data->set.one_easy->easy_conn)
|
if(CURLM_OK >= result)
|
||||||
data->set.one_easy->easy_conn->cselect_bits = 0;
|
/* get the socket(s) and check if the state has been changed since
|
||||||
|
last */
|
||||||
|
singlesocket(multi, data->set.one_easy);
|
||||||
|
|
||||||
if(CURLM_OK >= result)
|
/* Now we fall-through and do the timer-based stuff, since we don't want
|
||||||
/* get the socket(s) and check if the state has been changed since
|
to force the user to have to deal with timeouts as long as at least
|
||||||
last */
|
one connection in fact has traffic. */
|
||||||
singlesocket(multi, data->set.one_easy);
|
|
||||||
|
|
||||||
/* Now we fall-through and do the timer-based stuff, since we don't want
|
data = NULL; /* set data to NULL again to avoid calling
|
||||||
to force the user to have to deal with timeouts as long as at least one
|
multi_runsingle() in case there's no need to */
|
||||||
connection in fact has traffic. */
|
}
|
||||||
|
|
||||||
data = NULL; /* set data to NULL again to avoid calling multi_runsingle()
|
|
||||||
in case there's no need to */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user