axboe / liburing

Library providing helpers for the Linux kernel io_uring support
MIT License
2.77k stars 398 forks source link

Weird RECV_MULTISHOT behavior on close #1048

Closed SUPERCILEX closed 7 months ago

SUPERCILEX commented 7 months ago

As far as I can tell, close doesn't seem to do anything at all? If the client connection is still open, I'll continue to receive messages even after the close syscall successfully returns. This is extremely surprising behavior and I couldn't find any docs mentioning this.

It seems like the only way to correctly close a client connection is to first perform an async cancellation (which errors out the recv) and then do the close.

I can see how being able to immediately close the fd would be useful, so I'm guessing this is expected behavior, but it should definitely be documented somewhere as it's pretty confusing to debug.

DylanZA commented 7 months ago

It is more likely documented in close(2), as this is where the issue lies, although this page was written before the concept of io_uring.

The section about " Multithreaded processes and close()" hints at it

       On Linux (and possibly some other systems), the behavior is
       different: the blocking I/O system call holds a reference to the
       underlying open file description, and this reference keeps the
       description open until the I/O system call completes.  (See
       [open(2)](https://man7.org/linux/man-pages/man2/open.2.html) for a discussion of open file descriptions.)  Thus, the
       blocking system call in the first thread may successfully
       complete after the close() in the second thread.
ammarfaizi2 commented 7 months ago

Since the fd is ref counted, you may want to consider using shutdown(2) before close(2).

https://man7.org/linux/man-pages/man2/shutdown.2.html:

SYNOPSIS
       #include <sys/socket.h>

       int shutdown(int sockfd, int how);

DESCRIPTION
       The shutdown() call causes all or part of a full-duplex
       connection on the socket associated with sockfd to be shut down.
       If how is SHUT_RD, further receptions will be disallowed.  If how
       is SHUT_WR, further transmissions will be disallowed.  If how is
       SHUT_RDWR, further receptions and transmissions will be
       disallowed.
SUPERCILEX commented 7 months ago

Fascinating, I had no idea this was a kernel wide thing. This issue is probably good enough documentation then.

Thanks for the shutdown tip! For folks wondering, that will automatically cancel the multi recv and fixes a bug where clients stay blocked on a recvmsg even though the server closed the connection.