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/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 143d1322ea Added handling of MSG_WAITALL flag in TCP recv.
143d1322ea is described below

commit 143d1322eab11062da12fb0d5ebc246bea96a01f
Author: Fotis Panagiotopoulos <f.j.pa...@gmail.com>
AuthorDate: Tue Oct 11 20:40:56 2022 +0300

    Added handling of MSG_WAITALL flag in TCP recv.
---
 net/devif/devif.h      |  1 +
 net/tcp/tcp_recvfrom.c | 41 ++++++++++++++++++-----------------------
 2 files changed, 19 insertions(+), 23 deletions(-)

diff --git a/net/devif/devif.h b/net/devif/devif.h
index e78f7b5b4e..4393e4be1a 100644
--- a/net/devif/devif.h
+++ b/net/devif/devif.h
@@ -188,6 +188,7 @@
 #define TCP_ABORT          (1 << 7)
 #define TCP_CONNECTED      (1 << 8)
 #define TCP_TIMEDOUT       (1 << 9)
+#define TCP_WAITALL        (1 << 10)
 
 /* Bits 10-11: Unused, available */
 
diff --git a/net/tcp/tcp_recvfrom.c b/net/tcp/tcp_recvfrom.c
index a32a7fef71..c217ea6596 100644
--- a/net/tcp/tcp_recvfrom.c
+++ b/net/tcp/tcp_recvfrom.c
@@ -412,7 +412,8 @@ static uint16_t tcp_recvhandler(FAR struct net_driver_s 
*dev,
            * next receive is performed.
            */
 
-          if (pstate->ir_recvlen > 0)
+          if ((pstate->ir_recvlen > 0 && (flags & TCP_WAITALL) == 0) ||
+              pstate->ir_buflen == 0)
             {
               ninfo("TCP resume\n");
 
@@ -556,30 +557,20 @@ static void tcp_recvfrom_initialize(FAR struct tcp_conn_s 
*conn,
 
 static ssize_t tcp_recvfrom_result(int result, struct tcp_recvfrom_s *pstate)
 {
-  /* Check for a error/timeout detected by the event handler.  Errors are
-   * signaled by negative errno values for the rcv length
+  /* Check if any data were received. If so, then return their length and
+   * ignore any error codes.
    */
 
-  if (pstate->ir_result < 0)
+  if (pstate->ir_recvlen > 0)
     {
-      /* This might return EAGAIN on a timeout or ENOTCONN on loss of
-       * connection (TCP only)
-       */
-
-      return pstate->ir_result;
+      return pstate->ir_recvlen;
     }
 
-  /* If net_timedwait failed, then we were probably reawakened by a signal.
-   * In this case, net_timedwait will have returned negated errno
-   * appropriately.
+  /* If no data were received, return the error code instead. The event
+   * handler error is prioritized over any previous error.
    */
 
-  if (result < 0)
-    {
-      return result;
-    }
-
-  return pstate->ir_recvlen;
+  return (pstate->ir_result <= 0) ? pstate->ir_result : result;
 }
 
 /****************************************************************************
@@ -698,15 +689,18 @@ ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR 
struct msghdr *msg,
   /* We get here when we we decide that we need to setup the wait for
    * incoming TCP/IP data.  Just a few more conditions to check:
    *
-   * 1) Make sure thet there is buffer space to receive additional data
+   * 1) Make sure that there is buffer space to receive additional data
    *    (state.ir_buflen > 0).  This could be zero, for example,  we filled
    *    the user buffer with data from the read-ahead buffers.  And
    * 2) then we not want to wait if we already obtained some data from the
    *    read-ahead buffer.  In that case, return now with what we have (don't
    *    want for more because there may be no timeout).
+   * 3) If however MSG_WAITALL flag is set, block here till all requested
+   *    data are received (or there is a timeout / error).
    */
 
-  if (state.ir_recvlen == 0 && state.ir_buflen > 0)
+  if (((flags & MSG_WAITALL) != 0 || state.ir_recvlen == 0) &&
+      state.ir_buflen > 0)
     {
       /* Set up the callback in the connection */
 
@@ -714,16 +708,17 @@ ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR 
struct msghdr *msg,
       if (state.ir_cb)
         {
           state.ir_cb->flags   = (TCP_NEWDATA | TCP_DISCONN_EVENTS);
+          state.ir_cb->flags  |= (flags & MSG_WAITALL) ? TCP_WAITALL : 0;
           state.ir_cb->priv    = (FAR void *)&state;
           state.ir_cb->event   = tcp_recvhandler;
 
           /* Wait for either the receive to complete or for an error/timeout
-           * to occur.  net_timedwait will also terminate if a signal isi
+           * to occur.  net_timedwait will also terminate if a signal is
            * received.
            */
 
           ret = net_timedwait(&state.ir_sem,
-                              _SO_TIMEOUT(conn->sconn.s_rcvtimeo));
+                               _SO_TIMEOUT(conn->sconn.s_rcvtimeo));
           if (ret == -ETIMEDOUT)
             {
               ret = -EAGAIN;
@@ -734,7 +729,7 @@ ssize_t psock_tcp_recvfrom(FAR struct socket *psock, FAR 
struct msghdr *msg,
           tcp_callback_free(conn, state.ir_cb);
           ret = tcp_recvfrom_result(ret, &state);
         }
-      else
+      else if (ret <= 0)
         {
           ret = -EBUSY;
         }

Reply via email to