The recently added support of IP_RECVERR (#2646) has an unintended impact on the normal operation of the socket: when an error is received on the socket, the next syscall (recvmmsg or sendmsg for quinn) will ignore the data and return this error (once for each enqueued error).
This is described (although quite discreetly I think) in the recv(2) manpage:
After an error has been passed, the pending socket error is regenerated based on the next queued error and will be passed on the next socket operation.
In practice, this does not have a huge functional impact since reads and writes are retried in quinn.
However, we stumbled upon this when chasing a lost CONNECTION_CLOSE frame that should have been sent when closing the Connection. It turned out the packet containing this frame was absorbed by sendmsg, since an ICMP error had occured right before it was called. This error is only meant to be a notification that an error was enqueued and is not related to the packet we're trying to sent (the syscall returns an error even if the error was for a different remote address). Because close notifications are not retried, the remote peer never gets it.
I believe this was understood in a previous implementation, since this comment hints at a refactor from a design that pulled errors immediately to the external getter design : https://github.com/quinn-rs/quinn/pull/2421/changes#r2450585268
To move forward, we would like to suggest adding an option to let users choose if the IP_RECVERR flag is passed on the socket.
Additionally, we think both recvmmsg and sendmsg calls should be wrapped to capture such errors and emit a notification that the user could receive to know if they should call the new recv_transport_error method. Then, the syscall should be retried (and that would fix the silently dropped CONNECTION_CLOSE).
The recently added support of
IP_RECVERR(#2646) has an unintended impact on the normal operation of the socket: when an error is received on the socket, the next syscall (recvmmsgorsendmsgforquinn) will ignore the data and return this error (once for each enqueued error).This is described (although quite discreetly I think) in the
recv(2)manpage:In practice, this does not have a huge functional impact since reads and writes are retried in
quinn.However, we stumbled upon this when chasing a lost
CONNECTION_CLOSEframe that should have been sent when closing theConnection. It turned out the packet containing this frame was absorbed bysendmsg, since an ICMP error had occured right before it was called. This error is only meant to be a notification that an error was enqueued and is not related to the packet we're trying to sent (the syscall returns an error even if the error was for a different remote address). Because close notifications are not retried, the remote peer never gets it.I believe this was understood in a previous implementation, since this comment hints at a refactor from a design that pulled errors immediately to the external getter design : https://github.com/quinn-rs/quinn/pull/2421/changes#r2450585268
To move forward, we would like to suggest adding an option to let users choose if the
IP_RECVERRflag is passed on the socket.Additionally, we think both
recvmmsgandsendmsgcalls should be wrapped to capture such errors and emit a notification that the user could receive to know if they should call the newrecv_transport_errormethod. Then, the syscall should be retried (and that would fix the silently droppedCONNECTION_CLOSE).