1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-23 16:48:49 -05:00

unpause: trigger a timeout for event-based transfers

... so that timeouts or other state machine actions get going again
after a changing pause state. For example, if the last delivery was
paused there's no pending socket activity.

Reported-by: sstruchtrup on github
Fixes #3994
Closes #4001
This commit is contained in:
Daniel Stenberg 2019-06-08 23:03:03 +02:00
parent cf1ec70e72
commit 680f141332
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
3 changed files with 31 additions and 27 deletions

View File

@ -1038,8 +1038,11 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
to have this handle checked soon */ to have this handle checked soon */
if(!result && if(!result &&
((newstate&(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) != ((newstate&(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) ) (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) ) {
Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */ Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */
if(data->multi)
Curl_update_timer(data->multi);
}
/* This transfer may have been moved in or out of the bundle, update /* This transfer may have been moved in or out of the bundle, update
the corresponding socket callback, if used */ the corresponding socket callback, if used */

View File

@ -71,8 +71,6 @@
static CURLMcode singlesocket(struct Curl_multi *multi, static CURLMcode singlesocket(struct Curl_multi *multi,
struct Curl_easy *data); struct Curl_easy *data);
static int update_timer(struct Curl_multi *multi);
static CURLMcode add_next_timeout(struct curltime now, static CURLMcode add_next_timeout(struct curltime now,
struct Curl_multi *multi, struct Curl_multi *multi,
struct Curl_easy *d); struct Curl_easy *d);
@ -462,16 +460,16 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
/* increase the alive-counter */ /* increase the alive-counter */
multi->num_alive++; multi->num_alive++;
/* A somewhat crude work-around for a little glitch in update_timer() that /* A somewhat crude work-around for a little glitch in Curl_update_timer()
happens if the lastcall time is set to the same time when the handle is that happens if the lastcall time is set to the same time when the handle
removed as when the next handle is added, as then the check in is removed as when the next handle is added, as then the check in
update_timer() that prevents calling the application multiple times with Curl_update_timer() that prevents calling the application multiple times
the same timer info will not trigger and then the new handle's timeout with the same timer info will not trigger and then the new handle's
will not be notified to the app. timeout will not be notified to the app.
The work-around is thus simply to clear the 'lastcall' variable to force The work-around is thus simply to clear the 'lastcall' variable to force
update_timer() to always trigger a callback to the app when a new easy Curl_update_timer() to always trigger a callback to the app when a new
handle is added */ easy handle is added */
memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
/* The closure handle only ever has default timeouts set. To improve the /* The closure handle only ever has default timeouts set. To improve the
@ -484,7 +482,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
data->state.conn_cache->closure_handle->set.no_signal = data->state.conn_cache->closure_handle->set.no_signal =
data->set.no_signal; data->set.no_signal;
update_timer(multi); Curl_update_timer(multi);
return CURLM_OK; return CURLM_OK;
} }
@ -774,7 +772,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
We do not touch the easy handle here! */ We do not touch the easy handle here! */
multi->num_easy--; /* one less to care about now */ multi->num_easy--; /* one less to care about now */
update_timer(multi); Curl_update_timer(multi);
return CURLM_OK; return CURLM_OK;
} }
@ -2107,7 +2105,7 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
*running_handles = multi->num_alive; *running_handles = multi->num_alive;
if(CURLM_OK >= returncode) if(CURLM_OK >= returncode)
update_timer(multi); Curl_update_timer(multi);
return returncode; return returncode;
} }
@ -2544,9 +2542,10 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
} }
else { else {
/* Asked to run due to time-out. Clear the 'lastcall' variable to force /* Asked to run due to time-out. Clear the 'lastcall' variable to force
update_timer() to trigger a callback to the app again even if the same Curl_update_timer() to trigger a callback to the app again even if the
timeout is still the one to run after this call. That handles the case same timeout is still the one to run after this call. That handles the
when the application asks libcurl to run the timeout prematurely. */ case when the application asks libcurl to run the timeout
prematurely. */
memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
} }
@ -2664,7 +2663,7 @@ CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s,
return CURLM_RECURSIVE_API_CALL; return CURLM_RECURSIVE_API_CALL;
result = multi_socket(multi, FALSE, s, 0, running_handles); result = multi_socket(multi, FALSE, s, 0, running_handles);
if(CURLM_OK >= result) if(CURLM_OK >= result)
update_timer(multi); Curl_update_timer(multi);
return result; return result;
} }
@ -2676,7 +2675,7 @@ CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s,
return CURLM_RECURSIVE_API_CALL; return CURLM_RECURSIVE_API_CALL;
result = multi_socket(multi, FALSE, s, ev_bitmask, running_handles); result = multi_socket(multi, FALSE, s, ev_bitmask, running_handles);
if(CURLM_OK >= result) if(CURLM_OK >= result)
update_timer(multi); Curl_update_timer(multi);
return result; return result;
} }
@ -2688,7 +2687,7 @@ CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles)
return CURLM_RECURSIVE_API_CALL; return CURLM_RECURSIVE_API_CALL;
result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles); result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles);
if(CURLM_OK >= result) if(CURLM_OK >= result)
update_timer(multi); Curl_update_timer(multi);
return result; return result;
} }
@ -2748,14 +2747,14 @@ CURLMcode curl_multi_timeout(struct Curl_multi *multi,
* Tell the application it should update its timers, if it subscribes to the * Tell the application it should update its timers, if it subscribes to the
* update timer callback. * update timer callback.
*/ */
static int update_timer(struct Curl_multi *multi) void Curl_update_timer(struct Curl_multi *multi)
{ {
long timeout_ms; long timeout_ms;
if(!multi->timer_cb) if(!multi->timer_cb)
return 0; return;
if(multi_timeout(multi, &timeout_ms)) { if(multi_timeout(multi, &timeout_ms)) {
return -1; return;
} }
if(timeout_ms < 0) { if(timeout_ms < 0) {
static const struct curltime none = {0, 0}; static const struct curltime none = {0, 0};
@ -2763,9 +2762,10 @@ static int update_timer(struct Curl_multi *multi)
multi->timer_lastcall = none; multi->timer_lastcall = none;
/* there's no timeout now but there was one previously, tell the app to /* there's no timeout now but there was one previously, tell the app to
disable it */ disable it */
return multi->timer_cb(multi, -1, multi->timer_userp); multi->timer_cb(multi, -1, multi->timer_userp);
return;
} }
return 0; return;
} }
/* When multi_timeout() is done, multi->timetree points to the node with the /* When multi_timeout() is done, multi->timetree points to the node with the
@ -2773,11 +2773,11 @@ static int update_timer(struct Curl_multi *multi)
* if this is the same (fixed) time as we got in a previous call and then * if this is the same (fixed) time as we got in a previous call and then
* avoid calling the callback again. */ * avoid calling the callback again. */
if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0) if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0)
return 0; return;
multi->timer_lastcall = multi->timetree->key; multi->timer_lastcall = multi->timetree->key;
return multi->timer_cb(multi, timeout_ms, multi->timer_userp); multi->timer_cb(multi, timeout_ms, multi->timer_userp);
} }
/* /*

View File

@ -30,6 +30,7 @@ void Curl_updatesocket(struct Curl_easy *data);
void Curl_expire(struct Curl_easy *data, time_t milli, expire_id); void Curl_expire(struct Curl_easy *data, time_t milli, expire_id);
void Curl_expire_clear(struct Curl_easy *data); void Curl_expire_clear(struct Curl_easy *data);
void Curl_expire_done(struct Curl_easy *data, expire_id id); void Curl_expire_done(struct Curl_easy *data, expire_id id);
void Curl_update_timer(struct Curl_multi *multi);
void Curl_detach_connnection(struct Curl_easy *data); void Curl_detach_connnection(struct Curl_easy *data);
void Curl_attach_connnection(struct Curl_easy *data, void Curl_attach_connnection(struct Curl_easy *data,
struct connectdata *conn); struct connectdata *conn);