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