Background
On Linux or BSD, it is possible to send handles to open files or sockets between unrelated processes with SCM_RIGHTS
, and I have this working, such that on process is listening for connections, and then forwards the handles to a process that performs the communication.
Problem
I am unable to figure out how to free the socket handle from the listening process without shutting down the socket.
There are two conflicting descriptions in man close(3)
:
When all file descriptors associated with an open file description have been closed, the open file description shall be freed.
And
If fildes refers to a socket, close() shall cause the socket to be destroyed.
I originally thought that this means that calling close()
will just decrement the reference count for the kernel object that has the socket, such that the last description from man close(3)
meant "destroy when the last descriptor is closed".
EDIT: This is how it is supposed to work, and also how it works.
But, when I run tests, it appears that as soon as I call close()
on the socket descriptor in the listening process, it will start closing the socket, sending either RST
or FIN
, depending on what the other process is doing with the socket at the time.
One solution would be to have a callback from the handing process with "you can now close socket nnn", but this would keep a number of socket descriptors open in the listening process and add some overhead as well.
I know I can force the socket to start the shutdown process by calling shutdown()
directly from either process, but I want to prevent it.
I assume there exists a simple solution, but I cannot find it.
Question
Is there a way to de-register the socket descriptor from the listening process such that it is no longer in the file descriptor table of the process, but without activating the socket shutdown?
Source code
The SCM_RIGHTS
implementation used to send the socket is here (send_fds
and native_close
):
The code that sends the socket and then closes it is here:
If I comment out line 497 everything works, but obviously get a large file descriptors leak.
The receiving end of SCM_RIGHTS
is here:
tl;dr: The socket is closed when the last reference is closed.
The answer to my question is most likely:
No, there is no way to prevent the socket shutdown, but it is not needed as the socket will not close until the last descriptor has closed.
The answer from Andrew was correct, and got me on track: it makes no sense, others do the same all the time.
In the end, the problem was a timeout in the handler process that closed the socket, but that made it look like the close()
call from the listener was the problem.
When I stopped the close()
call from the listening process, it started working. This happens because then the timeout correctly closes the handle, but there is still a reference (in the listening process) so the socket stays open.