> Am 31.05.2024 um 17:30 schrieb Stefan Eissing via curl-library > <curl-library@lists.haxx.se>: > > > >> Am 31.05.2024 um 16:57 schrieb Cao Duc Quan <caoducq...@gmail.com>: >> >> Hi Stefan, >> Thanks for the explanation. >> To conclude: >> - If the easy handle is not used with CURLM, the connection will be closed >> when we call curl_easy_cleanup() so I could say connection lifetime is the >> same as easy handle lifetime. > > Yes, if the easy handle ist standalone, all will be free'd at the end and the > socket closes. > >> - If the easy handle is used with CURLM, the connection lifetime will be >> longer than the easy handle. If we set the >> CURLOPT_CLOSESOCKETFUNCTION/CURLOPT_CLOSESOCKETDATA to easy handle, the >> callback could be invoked after the easy handle is destroyed (afte invoke >> curl_easy_cleanup()). > > Yes, the time after which this happens may vary with other conditions. Like > starting another transfer to the same host, or the server closing the > connection on its own. If the server closes the connection before the > transfer has ended, your closesocket function may even be called before > easy_cleanup().
Update after reading the code again, there are some exceptions here. The CURLOPT_CLOSESOCKETFUNCTION callback and DATA is only called when the transfer actually opened a new connection. If it reuses an existing connection, the CURLOPT_CLOSESOCKETFUNCTION of the transfer that opened the connection stays in place. If, as in your example, you want to log some metrics for a request, always gather those before calling easy_cleanup. In a CURLM, you cannot rely on the socketclose to make sense for this. Hope this helps, Stefan > > - Stefan > >> >> On Thu, May 30, 2024 at 11:55 PM Stefan Eissing <ste...@eissing.org> wrote: >> >> >>> Am 31.05.2024 um 06:30 schrieb Cao Duc Quan via curl-library >>> <curl-library@lists.haxx.se>: >>> >>> Hi, >>> >>> Here is the main flow in my application with CURLM >>> >>> struct Request { >>> CURL *easy; >>> // other data >>> } >>> >>> int on_close_socket(void* clientp, curl_socket_t sock) { >>> struct Request *request = (struct Request*)clientp; >>> // log some metrics for request >>> close(sock); >>> return 0; >>> } >>> >>> struct Request* alloc_request(const char* url) { >>> struct Request* request = malloc(sizeof(struct Request)); >>> >>> request->easy = curl_easy_init(); >>> curl_easy_setopt(curl, CURLOPT_CLOSESOCKETFUNCTION, on_close_socket); >>> curl_easy_setopt(curl, CURLOPT_CLOSESOCKETDATA, request); >>> // other init >>> } >>> >>> void close_request(struct Request* request) { >>> curl_easy_cleanup(request->easy); >>> free(request); >>> } >>> >>> struct Request* lkup_request(CURL *easy) { >>> // lookup request from easy in active queue >>> } >>> >>> void cleanup_finished_request(CURLM *multi) { >>> struct CURLMsg *m; >>> do { >>> int msgq = 0; >>> m = curl_multi_info_read(multi, &msgq); >>> if(m && (m->msg == CURLMSG_DONE)) { >>> CURL *e = m->easy_handle; >>> curl_multi_remove_handle(multi, e); >>> struct Request* request = lkup_request(e); >>> close_request(request); >>> } >>> } while(m); >>> } >>> >>> void deque_next_request(CURLM *multi) { >>> // get url request and construct >>> struct Request* request = alloc_request(url); >>> >>> curl_multi_add_handle(multi, request->easy); >>> // add request to active queue >>> } >>> >>> void thread_loop() { >>> CURLM *multi = curl_multi_init(); >>> int still_running = 1; >>> >>> while(still_running) { >>> deque_next_request(); >>> CURLMcode mc = curl_multi_perform(multi, &still_running); >>> >>> cleanup_finished_request(); >>> if(!mc && still_running) >>> >>> /* wait for activity, timeout or "nothing" */ >>> mc = curl_multi_poll(multi, NULL, 0, 1000, NULL); >>> >>> if(mc) { >>> fprintf(stderr, "curl_multi_poll() failed, code %d.\n", (int)mc); >>> break; >>> } >>> } >>> } >>> >>> In alloc_request() create a request object which includes an easy handler >>> and hold private data and install CURLOPT_CLOSESOCKETFUNCTION and >>> CURLOPT_CLOSESOCKETDATA. The problem is that when the request is finished >>> before the socket closes, the CLOSESOCKEDATA becomes invalid since it binds >>> to the request object which will be free when the request finishes. >>> >>> I did some checks and the curl_easy_cleanup() did not reset the socket >>> callback. It seems to me the close socket callback and its data only set >>> once in allocate_conn() function in lib/url.c and won't be updated even if >>> we recall this >>> curl_easy_setopt(curl, CURLOPT_CLOSESOCKETFUNCTION, NULL); >>> curl_easy_setopt(curl, CURLOPT_CLOSESOCKETDATA, NULL); >>> >>> Any recommendations/guidance for my use-case? >> >> Not sure I fully understand what you are trying to do. For your >> understanding: easy handles use internal connection (which own the socket). >> There can be many easy handles using the same connection. With HTTP/1.1 >> there is only one at a time, but a connection can be used again for the next >> easy handle. With HTTP/2 you can have many (commonly up to 100) easy handles >> per connection. >> >> So, when a transfer is done (easy cleanup), the connection lives on, the >> socket stays alive. >> >> Does this explain to you what you are seeing? >> >> - Stefan >> >>> >>> On Wed, May 29, 2024 at 2:53 PM Daniel Stenberg <dan...@haxx.se> wrote: >>> On Wed, 29 May 2024, Cao Duc Quan via curl-library wrote: >>> >>>> We plan to add metrics to monitor connectivities such as socket open/close. >>>> It seems to me that only CURL APIs support open/close socket callbacks >>>> CURLOPT_CLOSESOCKETFUNCTION >>>> <https://curl.se/libcurl/c/CURLOPT_CLOSESOCKETFUNCTION.html> but we do not >>>> have similar APIs for CURLM. >>> >>> Right, because the multi handle has no sockets of its own really. Sockets >>> are >>> used for transfers and the transfers are held or owned by the easy handles. >>> >>> So, those are the open/close socket callbacks libcurl provides. >>> >>>> The problem is that the lifetime of the socket in CURLM maybe longer >>>> compared with the easy handle, which means the CURL object could be >>>> finished >>>> and removed before the socket is closed. >>> >>> Why is this a problem? >>> >>> -- >>> >>> / daniel.haxx.se >>> | Commercial curl support up to 24x7 is available! >>> | Private help, bug fixes, support, ports, new features >>> | https://curl.se/support.html >>> >>> >>> -- >>> -------------------------------- >>> Watson Cao >>> VN: (+84) 0976574864 >>> CA: (+1) 2368658864 >>> -- >>> Unsubscribe: https://lists.haxx.se/mailman/listinfo/curl-library >>> Etiquette: https://curl.se/mail/etiquette.html >> >> >> >> -- >> -------------------------------- >> Watson Cao >> VN: (+84) 0976574864 >> CA: (+1) 2368658864 > > -- > Unsubscribe: https://lists.haxx.se/mailman/listinfo/curl-library > Etiquette: https://curl.se/mail/etiquette.html -- Unsubscribe: https://lists.haxx.se/mailman/listinfo/curl-library Etiquette: https://curl.se/mail/etiquette.html