Buy commercial curl support. We
help you work out your issues, debug your libcurl applications, use the API,
port to new platforms, add new features and more. With a team lead by the
curl founder Daniel himself.
Re: CLOSESOCKETFUNCTION not always called in multi
- Contemporary messages sorted: [ by date ] [ by thread ] [ by subject ] [ by author ] [ by messages with attachments ]
From: Malcolm Matalka via curl-library <curl-library_at_lists.haxx.se>
Date: Tue, 18 Feb 2025 08:40:36 +0100
Luke Palmer via curl-library <curl-library_at_lists.haxx.se> writes:
> Hi all,
>
> I have exactly the same problem as Malcolm Matalka: I'm using libcurl with an event framework that insists on being
> responsible for closing an FD that it was previously told to watch. CLOSESOCKETFUNCTION doesn't always apply to watched
> FDs at present because not every watched FD is a socket.
>
> I have found that if I build with '--disable-socketpair' that I no longer have problems with this. I wanted to both share this as a
> potential solution and also to ask two questions:
>
> Does this seem like a reasonable workaround? Might there be other potential pitfalls?
>
> What might the downsides be to using '--disable-socketpair'? I can't find much information about why internal socketpair
> communication is good to have.
>
> Apologies for not threading: I just subscribed. Thanks all!
> Luke
Hey Luke,
After this thread I talked to Daniel and your analysis is exactly correct. These are other sockets that the multi interface is working with, not sockets associated with an handle. One solution is to "--disable-socketpair", as you said, which rather than use those sockets ends up switching to a polling mechanism for those sockets.
For myself, I haven't decided how best to approach this in my codebase yet.
1. A custom compilation of libcurl adds a management cost and requirement on users that I don't really want to impose or manage.
2. Handling the de-registering of the socket in socketfunction POLL_REMOVE is both difficult in the codebase I have and also imposes an extra syscall. I am using kqueue so I would have to perform a kqueue call in every socketfunction call with POLL_REMOVE to ensure the socket is removed from the queue, rather than accumulate all of them in do a batch kqueue.
3. I *could* handle the "deleted" event in kqueue however this cuts through a few abstractions and also I think depending on kqueue to tell me that a socket was deleted is going to be error prone because a new socket could be made in the mean time, etc etc.
4. I could run the multi interface in a thread with a kqueue devoted just to the multi interface, this lets me bypass all the abstractions I have. The downside there is that it's another event loop to manage and by avoiding the framework I'm using I don't get access to all the OS abstraction event loop stuff in the framework.
So far, I think (4) is the most viable solution for me.
Other solutions discussed with the libcurl team were
1. Adding a new "close socket" call back to the multi interface.
2. Add an option making the POLL_REMOVE interface asynchronous in the same way POLL_IN/POLL_OUT are. In that you would get a POLL_REMOVE request, and then perform multi_action call on the FD once you've done the work to remove it from management, and then libcurl could finish up closing it.
My understanding is that both of these are kind of a big lift and would require a pretty big motivation to support.
I'm in no position to know how complicated either solution is, but personally I really like (2) in that it fits how I think about the socketfunction callback. To me, socketfunction is transferring "ownership" of the socket. POLL_IN/POLL_OUT is moving ownership from libcurl to whatever is managing the event loop, and POLL_REMOVE is request ownership back. So it would make sense that each of these would require an "action" call to tell libcurl when the fd is ready for it to be processed again. So it makes these "symmetrical". In thinking about how I am using closefunction, it's not that I care about how a socket is closed, but rather I care about when it is closed. So in a sense, my current solution of using closefunction is a cheap workaround and not really semantically correct.
The libcurl team took the time to look at the problem and evaluation some options and decided that there needs to be a stronger motivation than my weird-o framework to change behaviour, which I get, and appreciate that they took the time to seriously consider the options. Anyone in this situation has some options available to them (and maybe I missed some options).
Date: Tue, 18 Feb 2025 08:40:36 +0100
Luke Palmer via curl-library <curl-library_at_lists.haxx.se> writes:
> Hi all,
>
> I have exactly the same problem as Malcolm Matalka: I'm using libcurl with an event framework that insists on being
> responsible for closing an FD that it was previously told to watch. CLOSESOCKETFUNCTION doesn't always apply to watched
> FDs at present because not every watched FD is a socket.
>
> I have found that if I build with '--disable-socketpair' that I no longer have problems with this. I wanted to both share this as a
> potential solution and also to ask two questions:
>
> Does this seem like a reasonable workaround? Might there be other potential pitfalls?
>
> What might the downsides be to using '--disable-socketpair'? I can't find much information about why internal socketpair
> communication is good to have.
>
> Apologies for not threading: I just subscribed. Thanks all!
> Luke
Hey Luke,
After this thread I talked to Daniel and your analysis is exactly correct. These are other sockets that the multi interface is working with, not sockets associated with an handle. One solution is to "--disable-socketpair", as you said, which rather than use those sockets ends up switching to a polling mechanism for those sockets.
For myself, I haven't decided how best to approach this in my codebase yet.
1. A custom compilation of libcurl adds a management cost and requirement on users that I don't really want to impose or manage.
2. Handling the de-registering of the socket in socketfunction POLL_REMOVE is both difficult in the codebase I have and also imposes an extra syscall. I am using kqueue so I would have to perform a kqueue call in every socketfunction call with POLL_REMOVE to ensure the socket is removed from the queue, rather than accumulate all of them in do a batch kqueue.
3. I *could* handle the "deleted" event in kqueue however this cuts through a few abstractions and also I think depending on kqueue to tell me that a socket was deleted is going to be error prone because a new socket could be made in the mean time, etc etc.
4. I could run the multi interface in a thread with a kqueue devoted just to the multi interface, this lets me bypass all the abstractions I have. The downside there is that it's another event loop to manage and by avoiding the framework I'm using I don't get access to all the OS abstraction event loop stuff in the framework.
So far, I think (4) is the most viable solution for me.
Other solutions discussed with the libcurl team were
1. Adding a new "close socket" call back to the multi interface.
2. Add an option making the POLL_REMOVE interface asynchronous in the same way POLL_IN/POLL_OUT are. In that you would get a POLL_REMOVE request, and then perform multi_action call on the FD once you've done the work to remove it from management, and then libcurl could finish up closing it.
My understanding is that both of these are kind of a big lift and would require a pretty big motivation to support.
I'm in no position to know how complicated either solution is, but personally I really like (2) in that it fits how I think about the socketfunction callback. To me, socketfunction is transferring "ownership" of the socket. POLL_IN/POLL_OUT is moving ownership from libcurl to whatever is managing the event loop, and POLL_REMOVE is request ownership back. So it would make sense that each of these would require an "action" call to tell libcurl when the fd is ready for it to be processed again. So it makes these "symmetrical". In thinking about how I am using closefunction, it's not that I care about how a socket is closed, but rather I care about when it is closed. So in a sense, my current solution of using closefunction is a cheap workaround and not really semantically correct.
The libcurl team took the time to look at the problem and evaluation some options and decided that there needs to be a stronger motivation than my weird-o framework to change behaviour, which I get, and appreciate that they took the time to seriously consider the options. Anyone in this situation has some options available to them (and maybe I missed some options).
-- Malcolm Matalka Terrateam -- Unsubscribe: https://lists.haxx.se/mailman/listinfo/curl-library Etiquette: https://curl.se/mail/etiquette.htmlReceived on 2025-02-18