-
-
Notifications
You must be signed in to change notification settings - Fork 6.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
timeouts are lost (not taken into account) during the disconnection step in pingpong protocols #739
Comments
I agree that this is a problem we need to address. However, the |
Yeah, ok by copying the timeout values like that we would at least get the values from the most recently added handle and that seems deterministic and fine enough to me, we should even document it once done and I would expect that applications will usually use the same timeout values for all handles anyway. Would you be so kind and make a pull request with this for us? |
OK, sorry for the slow response, so did we decide to copy |
I'm fine with doing that for the multi interface as well, which then makes it use the timeout values for the last added easy handles but I think that's still more sensible than just using the defaults like now. |
so @nick309h, I got the impression you worked on a fix/work-around for this? Any chance you can post it for us as a patch or pull-request? |
I had the same problem in SMTP application and the application got stuck 30 minutes long. I use multi interface in the application. and applied the nick309h's change to curl_multi_perform() as adding
before multi_runsingle(multi,now,data); Up to now, we didn't observe the problem after the modification. Is it a proper way to fix the problem on multi_interface? |
Everything is "the multi interface" since the easy interface is implemented as a wrapper around the multi interface. I'd still appreciate a full patch/pull-request for this change so that I know I'm understanding it properly and can consider it for merging and shipping in a future release. |
How about doing that operation when a handle is added to the multi handle instead? Seems to be a more controlled moment and will work for all APIs etc. See my patch here: diff --git a/lib/multi.c b/lib/multi.c
index 8e40916..cac1d44 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -460,10 +460,18 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
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
handle is added */
memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
+ /* the closure handle only has default timeouts set, but to improve the
+ state somewhat we clone the timeouts from each added handle so that the
+ closure handle's timeout always have timeouts of the most recently added
+ handle */
+ multi->closure_handle->set.timeout = data->set.timeout;
+ multi->closure_handle->set.server_response_timeout =
+ data->set.server_response_timeout;
+
update_timer(multi);
return CURLM_OK;
}
#if 0 |
libcurl version: 7.48.0, OS: Windows (but I think the problem will appear in all systems).
I've explored the source code after I got this issue so I will describe the sequence of steps leading to it with the explanation of how the issue occurs. It is as follows:
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10);
curl_easy_setopt(curl, CURLOPT_SERVER_RESPONSE_TIMEOUT, 10);
and other parameters such as URL, login, password, etc.
What happens: this function calls easy_perform which calls Curl_multi_handle (easy.c, line 789) and the latter creates another easy handle (multi.c, line 326), named closure_handle with all the settings default including timeouts.
Then some protocol-depending work is executed.
What happens: the first part of the call stack is as follows: curl_easy_cleanup->Curl_close->curl_multi_cleanup->close_all_connections . This function takes the closure_handle (multi.c, line 1876) and tries to disconnect it (line 1880). Please take into account that closure_handle->set which contains all the settings is still set to defaults unlike curl->set which was tuned by previous curl_easy_setopt calls. The following part of the call stack is (I used SMTP in this example) : close_all_connections->Curl_disconnect->smtp_disconnect->smtp_block_statemach->Curl_pp_statemach->Curl_pp_state_timeout. This function tries to calculate timeout but can not do it correctly since it is actually working with closure_handle which settings were not tuned. So data->set.server_response_timeout (pingpong.c, line 53) and data->set.timeout (pingpong.c, line 66) are always zero and default value RESP_TIMEOUT is used. It is set to 1800 seconds so the application may hang for a half of an hour despite the timeouts were set to 10 seconds. The real reason of it may be different, for example remote server or proxy hangs or some packets are lost in an unreliable network.
Possible solution: copy some timeout settings to closure_handle from the main one in easy_perform after Curl_multi_handle was called (easy.c, line 789) or even somewhere in disconnection call stack (to avoid affecting not-pingpong protocols). For example, adding the following in easy.c starting from line 793 (after
data->multi_easy = multi;
) solves the problem:data->multi_easy->closure_handle->set.timeout = data->set.timeout; data->multi_easy->closure_handle->set.server_response_timeout = data->set.server_response_timeout;
The text was updated successfully, but these errors were encountered: