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.
- 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()).

On Thu, May 30, 2024 at 11:55 PM Stefan Eissing <[email protected]> wrote:

>
>
> > Am 31.05.2024 um 06:30 schrieb Cao Duc Quan via curl-library <
> [email protected]>:
> >
> > 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 <[email protected]> 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

Reply via email to