This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 4d525505e47 net/udp: Support zero-length UDP datagrams
4d525505e47 is described below

commit 4d525505e47585419dcc0f5fd3b0c6a40f073d10
Author: gaohedong <[email protected]>
AuthorDate: Fri Sep 5 16:31:40 2025 +0800

    net/udp: Support zero-length UDP datagrams
    
    According to RFC768 page2 and referring to the Linux implementation, the 
message with udp length of 0 is supported.
    
    Signed-off-by: gaohedong <[email protected]>
---
 net/socket/sendmsg.c            |   3 +-
 net/udp/udp_devpoll.c           |   2 +-
 net/udp/udp_send.c              |   2 +-
 net/udp/udp_sendto_buffered.c   | 236 ++++++++++++++++++++--------------------
 net/udp/udp_sendto_unbuffered.c |  26 ++++-
 5 files changed, 142 insertions(+), 127 deletions(-)

diff --git a/net/socket/sendmsg.c b/net/socket/sendmsg.c
index cbcc647ebbf..7cf4b23c8aa 100644
--- a/net/socket/sendmsg.c
+++ b/net/socket/sendmsg.c
@@ -74,7 +74,8 @@ ssize_t psock_sendmsg(FAR struct socket *psock, FAR struct 
msghdr *msg,
 {
   /* Verify that non-NULL pointers were passed */
 
-  if (msg == NULL || msg->msg_iov == NULL || msg->msg_iov->iov_base == NULL)
+  if (msg == NULL || msg->msg_iov == NULL ||
+      (psock->s_type != SOCK_DGRAM && msg->msg_iov->iov_base == NULL))
     {
       return -EINVAL;
     }
diff --git a/net/udp/udp_devpoll.c b/net/udp/udp_devpoll.c
index e35bc789349..4ff4994c4e7 100644
--- a/net/udp/udp_devpoll.c
+++ b/net/udp/udp_devpoll.c
@@ -103,7 +103,7 @@ void udp_poll(FAR struct net_driver_s *dev, FAR struct 
udp_conn_s *conn)
 
       /* If the application has data to send, setup the UDP/IP header */
 
-      if (dev->d_sndlen > 0)
+      if (dev->d_len > 0)
         {
           udp_send(dev, conn);
           return;
diff --git a/net/udp/udp_send.c b/net/udp/udp_send.c
index f4f4539f99d..8b59be7fb2f 100644
--- a/net/udp/udp_send.c
+++ b/net/udp/udp_send.c
@@ -155,7 +155,7 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct 
udp_conn_s *conn)
 
   ninfo("UDP payload: %d (%d) bytes\n", dev->d_sndlen, dev->d_len);
 
-  if (dev->d_sndlen > 0)
+  if (dev->d_len > 0)
     {
 #ifdef CONFIG_NET_IPv4
 #ifdef CONFIG_NET_IPv6
diff --git a/net/udp/udp_sendto_buffered.c b/net/udp/udp_sendto_buffered.c
index 5aae170076b..e9c95038b5e 100644
--- a/net/udp/udp_sendto_buffered.c
+++ b/net/udp/udp_sendto_buffered.c
@@ -687,136 +687,134 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR 
const void *buf,
 
   BUF_DUMP("psock_udp_sendto", buf, len);
 
-  if (len > 0)
-    {
-      net_lock();
+  net_lock();
 
 #if CONFIG_NET_SEND_BUFSIZE > 0
-      /* If the send buffer size exceeds the send limit,
-       * wait for the write buffer to be released
-       */
+  /* If the send buffer size exceeds the send limit,
+   * wait for the write buffer to be released
+   */
 
-      while (udp_wrbuffer_inqueue_size(conn) + len > conn->sndbufs)
+  while (udp_wrbuffer_inqueue_size(conn) + len > conn->sndbufs)
+    {
+      if (nonblock)
+        {
+          ret = -EAGAIN;
+          goto errout_with_lock;
+        }
+
+      ret = net_sem_timedwait_uninterruptible(&conn->sndsem,
+                            udp_send_gettimeout(start, timeout));
+      if (ret < 0)
         {
-          if (nonblock)
+          if (ret == -ETIMEDOUT)
             {
               ret = -EAGAIN;
-              goto errout_with_lock;
             }
 
-          ret = net_sem_timedwait_uninterruptible(&conn->sndsem,
-            udp_send_gettimeout(start, timeout));
-          if (ret < 0)
-            {
-              if (ret == -ETIMEDOUT)
-                {
-                  ret = -EAGAIN;
-                }
-
-              goto errout_with_lock;
-            }
+          goto errout_with_lock;
         }
+    }
 #endif /* CONFIG_NET_SEND_BUFSIZE */
 
-      /* Allocate a write buffer.  Careful, the network will be momentarily
-       * unlocked here.
-       */
+  /* Allocate a write buffer.  Careful, the network will be momentarily
+   * unlocked here.
+   */
 
 #ifdef CONFIG_NET_JUMBO_FRAME
 
-      /* alloc iob of gso pkt for udp data */
+  /* alloc iob of gso pkt for udp data */
 
-      wrb = udp_wrbuffer_tryalloc(len + udpip_hdrsize(conn) +
-                                  CONFIG_NET_LL_GUARDSIZE);
+  wrb = udp_wrbuffer_tryalloc(len + udpip_hdrsize(conn) +
+                              CONFIG_NET_LL_GUARDSIZE);
 #else
-      if (nonblock)
+  if (nonblock)
+    {
+      wrb = udp_wrbuffer_tryalloc();
+    }
+  else
+    {
+      wrb = udp_wrbuffer_timedalloc(udp_send_gettimeout(start, timeout));
+    }
+#endif
+
+  if (wrb == NULL)
+    {
+      /* A buffer allocation error occurred */
+
+      nerr("ERROR: Failed to allocate write buffer\n");
+
+      if (nonblock || timeout != UINT_MAX)
         {
-          wrb = udp_wrbuffer_tryalloc();
+          ret = -EAGAIN;
         }
       else
         {
-          wrb = udp_wrbuffer_timedalloc(udp_send_gettimeout(start,
-                                                            timeout));
+          ret = -ENOMEM;
         }
-#endif
-
-      if (wrb == NULL)
-        {
-          /* A buffer allocation error occurred */
 
-          nerr("ERROR: Failed to allocate write buffer\n");
-
-          if (nonblock || timeout != UINT_MAX)
-            {
-              ret = -EAGAIN;
-            }
-          else
-            {
-              ret = -ENOMEM;
-            }
-
-          goto errout_with_lock;
-        }
+      goto errout_with_lock;
+    }
 
-      /* Initialize the write buffer
-       *
-       * Check if the socket is connected
-       */
+  /* Initialize the write buffer
+   *
+   * Check if the socket is connected
+   */
 
-      if (_SS_ISCONNECTED(conn->sconn.s_flags))
-        {
-          /* Yes.. get the connection address from the connection structure */
+  if (_SS_ISCONNECTED(conn->sconn.s_flags))
+    {
+      /* Yes.. get the connection address from the connection structure */
 
 #ifdef CONFIG_NET_IPv4
 #ifdef CONFIG_NET_IPv6
-          if (conn->domain == PF_INET)
+      if (conn->domain == PF_INET)
 #endif
-            {
-              FAR struct sockaddr_in *addr4 =
-                (FAR struct sockaddr_in *)&wrb->wb_dest;
+        {
+          FAR struct sockaddr_in *addr4 =
+            (FAR struct sockaddr_in *)&wrb->wb_dest;
 
-              addr4->sin_family = AF_INET;
-              addr4->sin_port   = conn->rport;
-              net_ipv4addr_copy(addr4->sin_addr.s_addr, conn->u.ipv4.raddr);
-              memset(addr4->sin_zero, 0, sizeof(addr4->sin_zero));
-            }
+          addr4->sin_family = AF_INET;
+          addr4->sin_port   = conn->rport;
+          net_ipv4addr_copy(addr4->sin_addr.s_addr, conn->u.ipv4.raddr);
+          memset(addr4->sin_zero, 0, sizeof(addr4->sin_zero));
+        }
 #endif /* CONFIG_NET_IPv4 */
 
 #ifdef CONFIG_NET_IPv6
 #ifdef CONFIG_NET_IPv4
-          else
+      else
 #endif
-            {
-              FAR struct sockaddr_in6 *addr6 =
-                (FAR struct sockaddr_in6 *)&wrb->wb_dest;
+        {
+          FAR struct sockaddr_in6 *addr6 =
+            (FAR struct sockaddr_in6 *)&wrb->wb_dest;
 
-              addr6->sin6_family = AF_INET6;
-              addr6->sin6_port   = conn->rport;
-              net_ipv6addr_copy(addr6->sin6_addr.s6_addr,
-                                conn->u.ipv6.raddr);
-            }
-#endif /* CONFIG_NET_IPv6 */
+          addr6->sin6_family = AF_INET6;
+          addr6->sin6_port   = conn->rport;
+          net_ipv6addr_copy(addr6->sin6_addr.s6_addr, conn->u.ipv6.raddr);
         }
+#endif /* CONFIG_NET_IPv6 */
+    }
 
-      /* Not connected.  Use the provided destination address */
+  /* Not connected.  Use the provided destination address */
 
-      else
-        {
-          memcpy(&wrb->wb_dest, to, tolen);
-          udp_connect(conn, to);
-        }
+  else
+    {
+      memcpy(&wrb->wb_dest, to, tolen);
+      udp_connect(conn, to);
+    }
 
-      /* Skip l2/l3/l4 offset before copy */
+  /* Skip l2/l3/l4 offset before copy */
 
-      udpiplen = udpip_hdrsize(conn);
+  udpiplen = udpip_hdrsize(conn);
 
-      iob_reserve(wrb->wb_iob, CONFIG_NET_LL_GUARDSIZE);
-      iob_update_pktlen(wrb->wb_iob, udpiplen, false);
+  iob_reserve(wrb->wb_iob, CONFIG_NET_LL_GUARDSIZE);
+  iob_update_pktlen(wrb->wb_iob, udpiplen, false);
 
-      /* Copy the user data into the write buffer.  We cannot wait for
-       * buffer space if the socket was opened non-blocking.
-       */
+  /* Copy the user data into the write buffer.  We cannot wait for
+   * buffer space if the socket was opened non-blocking.
+   */
 
+  if (len > 0)
+    {
       if (nonblock)
         {
           ret = iob_trycopyin(wrb->wb_iob, (FAR uint8_t *)buf,
@@ -845,48 +843,48 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR 
const void *buf,
         {
           goto errout_with_wrb;
         }
+    }
 
-      /* Dump I/O buffer chain */
+  /* Dump I/O buffer chain */
 
-      UDP_WBDUMP("I/O buffer chain", wrb, wrb->wb_iob->io_pktlen, 0);
+  UDP_WBDUMP("I/O buffer chain", wrb, wrb->wb_iob->io_pktlen, 0);
 
-      /* sendto_eventhandler() will send data in FIFO order from the
-       * conn->write_q.
-       *
-       * REVISIT:  Why FIFO order?  Because it is easy.  In a real world
-       * environment where there are multiple network devices this might
-       * be inefficient because we could be sending data to different
-       * device out-of-queued-order to optimize performance.  Sending
-       * data to different networks from a single UDP socket is probably
-       * not a very common use case, however.
-       */
+  /* sendto_eventhandler() will send data in FIFO order from the
+   * conn->write_q.
+   *
+   * REVISIT:  Why FIFO order?  Because it is easy.  In a real world
+   * environment where there are multiple network devices this might
+   * be inefficient because we could be sending data to different
+   * device out-of-queued-order to optimize performance.  Sending
+   * data to different networks from a single UDP socket is probably
+   * not a very common use case, however.
+   */
 
-      empty = sq_empty(&conn->write_q);
+  empty = sq_empty(&conn->write_q);
 
-      sq_addlast(&wrb->wb_node, &conn->write_q);
-      ninfo("Queued WRB=%p pktlen=%u write_q(%p,%p)\n",
-            wrb, wrb->wb_iob->io_pktlen,
-            conn->write_q.head, conn->write_q.tail);
+  sq_addlast(&wrb->wb_node, &conn->write_q);
+  ninfo("Queued WRB=%p pktlen=%u write_q(%p,%p)\n",
+        wrb, wrb->wb_iob->io_pktlen,
+        conn->write_q.head, conn->write_q.tail);
 
-      if (empty)
-        {
-          /* The new write buffer lies at the head of the write queue.  Set
-           * up for the next packet transfer by setting the connection
-           * address to the address of the next packet now at the header of
-           * the write buffer queue.
-           */
+  if (empty)
+    {
+      /* The new write buffer lies at the head of the write queue.  Set
+       * up for the next packet transfer by setting the connection
+       * address to the address of the next packet now at the header of
+       * the write buffer queue.
+       */
 
-          ret = sendto_next_transfer(conn);
-          if (ret < 0)
-            {
-              sq_remlast(&conn->write_q);
-              goto errout_with_wrb;
-            }
+      ret = sendto_next_transfer(conn);
+      if (ret < 0)
+        {
+          sq_remlast(&conn->write_q);
+          goto errout_with_wrb;
         }
-
-      net_unlock();
     }
 
+  net_unlock();
+
   /* Return the number of bytes that will be sent */
 
   return len;
diff --git a/net/udp/udp_sendto_unbuffered.c b/net/udp/udp_sendto_unbuffered.c
index 13460e8f23b..5248b5dc153 100644
--- a/net/udp/udp_sendto_unbuffered.c
+++ b/net/udp/udp_sendto_unbuffered.c
@@ -197,12 +197,28 @@ static uint16_t sendto_eventhandler(FAR struct 
net_driver_s *dev,
         {
           /* Copy the user data into d_appdata and send it */
 
-          int ret = devif_send(dev, pstate->st_buffer, pstate->st_buflen,
-                               udpip_hdrsize(pstate->st_conn));
-          if (ret <= 0)
+          if (pstate->st_buflen > 0)
             {
-              pstate->st_sndlen = ret;
-              goto end_wait;
+              int ret = devif_send(dev, pstate->st_buffer, pstate->st_buflen,
+                                   udpip_hdrsize(pstate->st_conn));
+              if (ret <= 0)
+                {
+                  pstate->st_sndlen = ret;
+                  goto end_wait;
+                }
+            }
+          else
+            {
+              if (netdev_iob_prepare(dev, false, 0) != OK)
+                {
+                  pstate->st_sndlen = -ENOMEM;
+                  goto end_wait;
+                }
+
+                iob_update_pktlen(dev->d_iob, udpip_hdrsize(pstate->st_conn),
+                                  false);
+                dev->d_sndlen = 0;
+                dev->d_len = dev->d_iob->io_pktlen;
             }
 
 #ifdef NEED_IPDOMAIN_SUPPORT

Reply via email to