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

From: Robert Pluim <[email-masked]>
Date: Wed, 26 Apr 2023 11:14:42 +0200

So allowing emacs to send 0-length UDP packets turned out to be not
too hard. Patch for both below. Eli, is this OK for master? It does
change 2 behaviours:

1. Receiving a 0-length UDP packet will no longer cause an error
2. Calling (process-send-string proc "") now actually sends out a
packet for a UDP process (an empty one).

Robert
-- 
>From 4bb6dec25ad3c3b548e18e82b2129b53c1ee1b69 Mon Sep 17 00:00:00 2001
From: Robert Pluim <[email-masked]>
Date: Tue, 25 Apr 2023 12:48:26 +0200
Subject: [PATCH] Allow zero-length UDP send/receive
To: [email-masked]

* src/process.c (wait_reading_process_output) [DATAGRAM_SOCKETS]:
Don't close the network connection if we receive a zero-length UDP
packet.
(send_process) [DATAGRAM_SOCKETS]: Allow sending a zero-length UDP
packet.

* etc/NEWS: Announce the change.
---
 etc/NEWS      |  8 ++++++++
 src/process.c | 16 ++++++++++++++--
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index ea233865f5a..4cc02d76b8f 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -82,6 +82,14 @@ The ':keepalive-idle', ':keepalive-interval', and ':keepalive-count'
 options can now be used to set the various timers and counters used
 when TCP keepalive is enabled for a connection.
 
+** Emacs can now send zero-length UDP packets.
+Previously 'process-send-string' of an empty string to a UDP process
+did nothing, now it sends out a zero-length UDP packet.
+
+** Emacs can now receive zero-length UDP packets.
+Previously, receiving a zero-length UDP packet closed the receiving
+network process. They are now silently ignored.
+
 
 * Editing Changes in Emacs 30.1
 
diff --git a/src/process.c b/src/process.c
index 8e467ff7511..e3233f5ad89 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))
+		got_some_output = 1;
+#endif
 	      else if (nread == 0 && !NETCONN_P (proc) && !SERIALCONN_P (proc)
 		       && !PIPECONN_P (proc))
 		;
@@ -6616,9 +6621,16 @@ send_process (Lisp_Object proc, const char *buf, ptrdiff_t len,
 	  cur_buf = buf;
 	  cur_object = object;
 	}
-
-      while (cur_len > 0)
+      /* UDP allows zero-length writes.  */
+      bool zero_length = false;
+#ifdef DATAGRAM_SOCKETS
+      if (cur_len == 0 && NETCONN_P (proc) && 0 <= p->outfd
+	  && DATAGRAM_CHAN_P (p->outfd))
+	zero_length = true;
+#endif
+      while (cur_len > 0 || zero_length)
 	{
+	  zero_length = false;
 	  /* Send this batch, using one or more write calls.  */
 	  ptrdiff_t written = 0;
 	  int outfd = p->outfd;
-- 
2.38.1.420.g319605f8f0