Problems with the (new) implementation of AF_UNIX datagram sockets
Ken Brown
kbrown@cornell.edu
Thu Apr 15 13:16:56 GMT 2021
On 4/15/2021 7:49 AM, Corinna Vinschen wrote:
> Hi Ken,
>
> On Apr 14 12:15, Ken Brown wrote:
>> Hi Corinna,
>>
>> This is a follow-up to
>>
>> https://cygwin.com/pipermail/cygwin/2021-April/248284.html
>>
>> I don't know if you've been following that thread, but two serious problems
>> with datagram sockets (on the topic/af_unix branch) have shown up.
>>
>> 1. Writing will block until a connection to the peer's pipe can be made. In
>> particular, if there are two consecutive writes with the same peer, the
>> second one will block until the peer reads the first message. This happens
>> because the peer's pipe is not available for the second connection until the
>> peer disconnects the first connection. This is currently done in recvmsg,
>> and I don't see a straightforward way to do it anywhere else.
>
> I'm a bit puzzeled. The idea for datagrams was to call open/send/close
> in each invocation of sendmsg. Therefore the pipe should become
> available as soon as the other peer has sent it's data block. The time
> a sendmsg has to wait for the pipe being available should be quite short!
Unfortunately, the pipe isn't available until the server disconnects. I
observed this in practice, and it's also documented at
https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-disconnectnamedpipe
"The server process must call DisconnectNamedPipe to disconnect a pipe handle
from its previous client before the handle can be connected to another client by
using the ConnectNamedPipe function."
>> 2. There's no way for select to test whether a datagram socket is ready for
>> writing. That's because we can't know whether a connection to a
>> hypothetical peer's pipe will be possible. According to Stevens, the issue
>> *should* be whether there's space in the socket's send buffer. But our
>> sockets don't have a send buffer until they connect to a pipe.
>
> Even then, there's no guarantee a send will succeed, given that
> select/send are not running atomically. However, we *could* for a start
> always return success from select for this scenario. If we have a
> nonblocking socket, it should fail opening the pipe and return EGAIN,
> which is perfectly fine. If we have a blocking socket, it could block
> on send, which is perfectly valid, too, because of the non-atomicity.
>
> Or am I missing something?
No, I was missing the non-atomicity. So maybe that's OK.
>> I think the solution to both problems is for Cygwin to maintain a send
>> buffer for datagram sockets. Does that seem right, or do you have another
>> idea?
>
> In theory the send buffer should be a shared buffer between all peers,
> so this could be constructed as a shared ring buffer, accessible from
> af_unix_shmem_t. But then again, this introduces a security problem,
> so that's not a good idea. So, process-local buffers.
>
> But you also have the problem how to empty the buffer. Do you start a
> new thread which checks if the pipe is getting available and if so,
> sends the buffer content? In which process? And what do you do if
> there's still data in the send buffer when the process exits? This is
> annoyingly complicated and error-prone.
Agreed.
> Another idea might be to implement send/recv on a DGRAM socket a bit
> like accept. Rather than creating a single_instance socket, we create a
> max_instance socket as for STREAM socket listeners. The server side
> accepts the connection at recv and immediately opens another pipe
> instance, so we always have at least one dangling instance for the next
> peer.
I thought about that, but you would still have the problem (as in 1 above) that
the pipe instance isn't available until recv is called.
>
> Corinna
>
>
> P.S.: Idle musings...
>
> The only other implementation of AF_UNIX sockets using named pipes on
> Windows I know of (U/WIN) implements the gory details as part of their
> priviledged server process, i. e., their equivalent of cygserver. The
> difference is that the entire system is based on this server process, so
> the U/WIN processes don't run at all if that service isn't running,
> quite unlike Cygwin. Requiring a server running just to allow AF_UNIX
> sockets to work seems a bit off for us...
>
> Having said that, maybe the idea to implement AF_UNIX sockets as named
> pipes is... outdated? Roughly 90% of our users are running a W10
> version supporting AF_UNIX sockets natively (albeit missing native
> SOCK_DGRAM support). Perhaps it's time to switch...?
Maybe so.
Ken
More information about the Cygwin-developers
mailing list