Subject: bug#62990: 30.0.50; UDP server closes connection upon receiving an empty packet

From: Robert Pluim <[email-masked]>
Date: Tue, 25 Apr 2023 10:07:59 +0200

>>>>> On Mon, 24 Apr 2023 23:04:34 +0200, Vasilij Schneidermann <[email-masked]> said:

    >> Empty TCP messages are perfectly valid, but they should be hidden from
    >> you. recvfrom returning 0 means the connection has been closed, but
    >> thatʼs a separate thing.

    Vasilij> I suspect there's a missing ifdef in the code which ends up terminating
    Vasilij> the process on such a condition, for both TCP and UDP.

Yes, although in a different place than I expected. Patch below. The
end result is to ignore the zero length message, getting it delivered
to the process would involve considerably bigger changes.

    >> Could you show how youʼre generating the empty packets?

    Vasilij> Download the attachments from my previous email, launch the server with
    Vasilij> `emacs --batch -l bug-server.el`, then the client with `guile
    Vasilij> fixed-client.scm`. Swap out the server with `guile fixed-server.scm`.

I was hoping to avoid installing guile :-)

The client works, but the server gets me this, which means Iʼm missing
some bits somewhere:

    Backtrace:
               6 (primitive-load "/home/rpluim/repos/fixed-server.scm")
    In ice-9/eval.scm:
       721:20  5 (primitive-eval (import (rnrs bytevectors gnu)))
    In ice-9/psyntax.scm:
      1241:36  4 (expand-top-sequence ((import (rnrs bytevectors gnu))) _ …)
      1233:19  3 (parse _ (("placeholder" placeholder)) ((top) #(# # …)) …)
       285:10  2 (parse _ (("placeholder" placeholder)) (()) _ c&e (eval) …)
    In ice-9/eval.scm:
       293:34  1 (_ #<directory (guile-user) 7ff24fdbec80>)
    In ice-9/boot-9.scm:
       3300:6  0 (resolve-interface (rnrs bytevectors gnu) #:select _ # _ …)

    ice-9/boot-9.scm:3300:6: In procedure resolve-interface:
    no code for module (rnrs bytevectors gnu)

Does guile deliver the empty message?

    >> Itʼs allowed by the protocol. I guess it could be useful for people
    >> wanting to implement their own keep-alive protocol over UDP.

    Vasilij> I think so as well.

Iʼll look into it. I suspect it wonʼt be a small change.

Robert
-- 

diff --git a/src/process.c b/src/process.c
index 8e467ff7511..babe926ca5b 100644
--- a/src/process.c
+++ b/src/process.c
@@ -5947,6 +5947,11 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
 #endif /* HAVE_PTYS */
 	      /* If we can detect process termination, don't consider the
 		 process gone just because its pipe is closed.  */
+#ifdef DATAGRAM_SOCKETS
+	      /* A zero byte read on a UDP socket is not an error.  */
+	      else if (nread == 0 && DATAGRAM_CHAN_P (channel))
+		;
+#endif
 	      else if (nread == 0 && !NETCONN_P (proc) && !SERIALCONN_P (proc)
 		       && !PIPECONN_P (proc))
 		;