gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libmicrohttpd] branch master updated (4e5b6570 -> f6e4e13e)


From: gnunet
Subject: [libmicrohttpd] branch master updated (4e5b6570 -> f6e4e13e)
Date: Sat, 02 Dec 2023 18:17:02 +0100

This is an automated email from the git hooks/post-receive script.

karlson2k pushed a change to branch master
in repository libmicrohttpd.

    from 4e5b6570 fix #7967
     new f09bf9ea test_upgrade: added checking of socket shutdown status
     new 38599d9f "Upgraded" TLS connections: fixed reading last chunks when 
closing
     new 6fb386ec "Upgraded" TLS connections: force processing again if 
'was_close' missed
     new f6e4e13e "Upgraded" TLS connections: fixed sending of large messages

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/microhttpd/daemon.c       |  68 +++++-------
 src/microhttpd/test_upgrade.c | 243 +++++++++++++++++++++++++++++++++++++-----
 2 files changed, 247 insertions(+), 64 deletions(-)

diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index 688d829d..1dc2a3bd 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -1461,6 +1461,9 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
   mhd_assert ( (! MHD_D_IS_USING_THREADS_ (daemon)) || \
                MHD_thread_handle_ID_is_current_thread_ (connection->tid) );
 #endif /* MHD_USE_THREADS */
+
+  mhd_assert (0 != (daemon->options & MHD_USE_TLS));
+
   if (daemon->shutdown)
   {
     /* Daemon shutting down, application will not receive any more data. */
@@ -1485,18 +1488,11 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
       MHD_DLOG (daemon,
                 _ ("Failed to forward to application %" PRIu64 \
                    " bytes of data received from remote side: " \
-                   "application shut down socket.\n"),
+                   "application closed data forwarding.\n"),
                 (uint64_t) urh->in_buffer_used);
 #endif
 
     }
-    /* If application signaled MHD about socket closure then
-     * check for any pending data even if socket is not marked
-     * as 'ready' (signal may arrive after poll()/select()).
-     * Socketpair for forwarding is always in non-blocking mode
-     * so no risk that recv() will block the thread. */
-    if (0 != urh->out_buffer_size)
-      urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY;
     /* Discard any data received form remote. */
     urh->in_buffer_used = 0;
     /* Do not try to push data to application. */
@@ -1514,17 +1510,14 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
    * last part of incoming data may be lost.  If disconnect or error was
    * detected - try to read from socket to dry data possibly pending is system
    * buffers. */
-  if (0 != (MHD_EPOLL_STATE_ERROR & urh->app.celi))
-    urh->app.celi |= MHD_EPOLL_STATE_READ_READY;
-  if (0 != (MHD_EPOLL_STATE_ERROR & urh->mhd.celi))
-    urh->mhd.celi |= MHD_EPOLL_STATE_READ_READY;
 
   /*
    * handle reading from remote TLS client
    */
-  if ( ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->app.celi)) ||
-         (connection->tls_read_ready) ) &&
-       (urh->in_buffer_used < urh->in_buffer_size) )
+  if (((0 != ((MHD_EPOLL_STATE_ERROR | MHD_EPOLL_STATE_READ_READY)
+              & urh->app.celi)) ||
+       (connection->tls_read_ready)) &&
+      (urh->in_buffer_used < urh->in_buffer_size))
   {
     ssize_t res;
     size_t buf_size;
@@ -1539,13 +1532,16 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
                               buf_size);
     if (0 >= res)
     {
+      connection->tls_read_ready = false;
       if (GNUTLS_E_INTERRUPTED != res)
       {
         urh->app.celi &= ~((enum MHD_EpollState) MHD_EPOLL_STATE_READ_READY);
-        if (GNUTLS_E_AGAIN != res)
+        if ((GNUTLS_E_AGAIN != res) ||
+            (0 != (MHD_EPOLL_STATE_ERROR & urh->app.celi)))
         {
-          /* Unrecoverable error on socket was detected or
-           * socket was disconnected/shut down. */
+          /* TLS unrecoverable error has been detected,
+             socket error was detected and all data has been read,
+             or socket was disconnected/shut down. */
           /* Stop trying to read from this TLS socket. */
           urh->in_buffer_size = 0;
         }
@@ -1557,21 +1553,20 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
       connection->tls_read_ready =
         (0 < gnutls_record_check_pending (connection->tls_session));
     }
-    if (MHD_EPOLL_STATE_ERROR ==
-        ((MHD_EPOLL_STATE_ERROR | MHD_EPOLL_STATE_READ_READY) & urh->app.celi))
-    {
-      /* Unrecoverable error on socket was detected and all
-       * pending data was read from system buffers. */
-      /* Stop trying to read from this TLS socket. */
-      urh->in_buffer_size = 0;
-    }
   }
 
   /*
    * handle reading from application
    */
-  if ( (0 != (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) &&
-       (urh->out_buffer_used < urh->out_buffer_size) )
+  /* If application signalled MHD about socket closure then
+   * check for any pending data even if socket is not marked
+   * as 'ready' (signal may arrive after poll()/select()).
+   * Socketpair for forwarding is always in non-blocking mode
+   * so no risk that recv() will block the thread. */
+  if (((0 != ((MHD_EPOLL_STATE_ERROR | MHD_EPOLL_STATE_READ_READY)
+              & urh->mhd.celi))
+       || was_closed) /* Force last reading from app if app has closed the 
connection */
+      && (urh->out_buffer_used < urh->out_buffer_size))
   {
     ssize_t res;
     size_t buf_size;
@@ -1597,7 +1592,8 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
             (! MHD_SCKT_ERR_IS_EAGAIN_ (err)))
         {
           /* Socket disconnect/shutdown was detected;
-           * Application signaled about closure of 'upgraded' socket;
+           * Application signalled about closure of 'upgraded' socket and
+           * all data has been read from application;
            * or persistent / unrecoverable error. */
           /* Do not try to pull more data from application. */
           urh->out_buffer_size = 0;
@@ -1610,15 +1606,6 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
       if (buf_size > (size_t) res)
         urh->mhd.celi &= ~((enum MHD_EpollState) MHD_EPOLL_STATE_READ_READY);
     }
-    if ( (0 == (MHD_EPOLL_STATE_READ_READY & urh->mhd.celi)) &&
-         ( (0 != (MHD_EPOLL_STATE_ERROR & urh->mhd.celi)) ||
-           (was_closed) ) )
-    {
-      /* Unrecoverable error on socket was detected and all
-       * pending data was read from system buffers. */
-      /* Do not try to pull more data from application. */
-      urh->out_buffer_size = 0;
-    }
   }
 
   /*
@@ -1669,8 +1656,6 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
         memmove (urh->out_buffer,
                  &urh->out_buffer[res],
                  next_out_buffer_used);
-        if (data_size > (size_t) res)
-          urh->app.celi &= ~((enum MHD_EpollState) 
MHD_EPOLL_STATE_WRITE_READY);
       }
       urh->out_buffer_used = next_out_buffer_used;
     }
@@ -1782,6 +1767,9 @@ process_urh (struct MHD_UpgradeResponseHandle *urh)
     urh->out_buffer_size = 0;
     urh->mhd.celi &= ~((enum MHD_EpollState) MHD_EPOLL_STATE_READ_READY);
   }
+
+  if (! was_closed && urh->was_closed)
+    daemon->data_already_pending = true; /* Force processing again */
 }
 
 
diff --git a/src/microhttpd/test_upgrade.c b/src/microhttpd/test_upgrade.c
index b30ad64b..8264e13b 100644
--- a/src/microhttpd/test_upgrade.c
+++ b/src/microhttpd/test_upgrade.c
@@ -172,6 +172,8 @@ _testErrorLog_func (const char *errDesc, const char 
*funcName, int lineNum)
 /* Could be increased to facilitate debugging */
 static int test_timeout = 5;
 
+static bool test_tls;
+
 static int verbose = 0;
 
 static uint16_t global_port;
@@ -377,6 +379,8 @@ struct wr_socket
   } t;
 
   bool is_nonblocking;
+
+  bool eof_recieved;
 #ifdef HTTPS_SUPPORT
   /**
    * TLS credentials
@@ -439,6 +443,7 @@ wr_create_plain_sckt (void)
     return NULL;
   }
   s->t = wr_plain;
+  s->eof_recieved = false;
   s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
   s->is_nonblocking = false;
   if (MHD_INVALID_SOCKET != s->fd)
@@ -467,6 +472,7 @@ wr_create_tls_sckt (void)
     return NULL;
   }
   s->t = wr_tls;
+  s->eof_recieved = false;
   s->tls_connected = 0;
   s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
   s->is_nonblocking = false;
@@ -532,6 +538,7 @@ wr_create_from_plain_sckt (MHD_socket plain_sk)
     return NULL;
   }
   s->t = wr_plain;
+  s->eof_recieved = false;
   s->fd = plain_sk;
   s->is_nonblocking = false; /* The actual mode is unknown */
   wr_make_nonblocking (s);   /* Force set mode to have correct status */
@@ -540,6 +547,19 @@ wr_create_from_plain_sckt (MHD_socket plain_sk)
 }
 
 
+/**
+ * Check whether shutdown of connection was received from remote
+ * @param s socket to check
+ * @return zero if shutdown signal has not been received,
+ *         1 if shutdown signal was already received
+ */
+static int
+wr_is_eof_received (struct wr_socket *s)
+{
+  return s->eof_recieved ? 1 : 0;
+}
+
+
 enum wr_wait_for_type
 {
   WR_WAIT_FOR_RECV = 0,
@@ -575,10 +595,13 @@ wr_wait_socket_ready_noabort_ (struct wr_socket *s,
   else
     tmo_ptr = NULL; /* No timeout */
 
-  if (WR_WAIT_FOR_RECV == wait_for)
-    sel_res = select (1 + (int) s->fd, &fds, NULL, NULL, tmo_ptr);
-  else
-    sel_res = select (1 + (int) s->fd, NULL, &fds, NULL, tmo_ptr);
+  do
+  {
+    if (WR_WAIT_FOR_RECV == wait_for)
+      sel_res = select (1 + (int) s->fd, &fds, NULL, NULL, tmo_ptr);
+    else
+      sel_res = select (1 + (int) s->fd, NULL, &fds, NULL, tmo_ptr);
+  } while (0 > sel_res && MHD_SCKT_ERR_IS_EINTR_ (MHD_socket_get_error_ ()));
 
   if (1 == sel_res)
     return true;
@@ -763,15 +786,19 @@ wr_send_tmo (struct wr_socket *s,
 {
   if (wr_plain == s->t)
   {
-    int err;
-    ssize_t res = MHD_send_ (s->fd, buf, len);
-    if (0 <= res)
-      return res;
-    err = MHD_socket_get_error_ ();
-    if (! MHD_SCKT_ERR_IS_EAGAIN_ (err) && ! MHD_SCKT_ERR_IS_EINTR_ (err))
-      return res;
-    wr_wait_socket_ready_ (s, timeout_ms, WR_WAIT_FOR_SEND);
-    return MHD_send_ (s->fd, buf, len);
+    ssize_t res;
+    while (! 0)
+    {
+      int err;
+      res = MHD_send_ (s->fd, buf, len);
+      if (0 <= res)
+        break; /* Success */
+      err = MHD_socket_get_error_ ();
+      if (! MHD_SCKT_ERR_IS_EAGAIN_ (err) && ! MHD_SCKT_ERR_IS_EINTR_ (err))
+        break; /* Failure */
+      wr_wait_socket_ready_ (s, timeout_ms, WR_WAIT_FOR_SEND);
+    }
+    return res;
   }
 #ifdef HTTPS_SUPPORT
   else if (wr_tls == s->t)
@@ -846,15 +873,21 @@ wr_recv_tmo (struct wr_socket *s,
 {
   if (wr_plain == s->t)
   {
-    int err;
-    ssize_t res = MHD_recv_ (s->fd, buf, len);
-    if (0 <= res)
-      return res;
-    err = MHD_socket_get_error_ ();
-    if (! MHD_SCKT_ERR_IS_EAGAIN_ (err) && ! MHD_SCKT_ERR_IS_EINTR_ (err))
-      return res;
-    wr_wait_socket_ready_ (s, timeout_ms, WR_WAIT_FOR_RECV);
-    return MHD_recv_ (s->fd, buf, len);
+    ssize_t res;
+    while (! 0)
+    {
+      int err;
+      res = MHD_recv_ (s->fd, buf, len);
+      if (0 == res)
+        s->eof_recieved = true;
+      if (0 <= res)
+        break; /* Success */
+      err = MHD_socket_get_error_ ();
+      if (! MHD_SCKT_ERR_IS_EAGAIN_ (err) && ! MHD_SCKT_ERR_IS_EINTR_ (err))
+        break; /* Failure */
+      wr_wait_socket_ready_ (s, timeout_ms, WR_WAIT_FOR_RECV);
+    }
+    return res;
   }
 #ifdef HTTPS_SUPPORT
   if (wr_tls == s->t)
@@ -866,6 +899,8 @@ wr_recv_tmo (struct wr_socket *s,
     while (1)
     {
       ret = gnutls_record_recv (s->tls_s, buf, len);
+      if (0 == ret)
+        s->eof_recieved = true;
       if (ret >= 0)
         return ret;
       if ((GNUTLS_E_AGAIN != ret) && (GNUTLS_E_INTERRUPTED  != ret))
@@ -909,6 +944,90 @@ wr_recv (struct wr_socket *s,
 }
 
 
+/**
+ * Shutdown send/write on the socket.
+ * @param s the socket to shutdown
+ * @param how the type of shutdown: SHUT_WR or SHUT_RDWR
+ * @param timeout_ms the maximum wait time in milliseconds to receive the data,
+ *                   no limit if negative value is used
+ * @return zero on succeed, -1 otherwise
+ */
+static int
+wr_shutdown_tmo (struct wr_socket *s, int how, int timeout_ms)
+{
+  switch (how)
+  {
+  case SHUT_WR: /* Valid value */
+    break;
+  case SHUT_RDWR: /* Valid value */
+    break;
+  case SHUT_RD:
+    externalErrorExitDesc ("Unsupported 'how' value");
+    break;
+  default:
+    externalErrorExitDesc ("Invalid 'how' value");
+    break;
+  }
+  if (wr_plain == s->t)
+  {
+    (void) timeout_ms; /* Unused parameter for plain sockets */
+    return shutdown (s->fd, how);
+  }
+#ifdef HTTPS_SUPPORT
+  if (wr_tls == s->t)
+  {
+    ssize_t ret;
+    if (! s->tls_connected && ! wr_handshake_tmo_ (s, timeout_ms))
+      return -1;
+
+    while (1)
+    {
+      ret =
+        gnutls_bye  (s->tls_s,
+                     (SHUT_WR == how) ?  GNUTLS_SHUT_WR :  GNUTLS_SHUT_RDWR);
+      if (GNUTLS_E_SUCCESS == ret)
+      {
+#if 0 /* Disabled to test pure behaviour */
+        if (SHUT_RDWR == how)
+          (void) shutdown (s->fd, how); /* Also shutdown the underlying 
transport layer */
+#endif
+        return 0;
+      }
+      if ((GNUTLS_E_AGAIN != ret) && (GNUTLS_E_INTERRUPTED  != ret))
+        break;
+      wr_wait_socket_ready_ (s, timeout_ms,
+                             gnutls_record_get_direction (s->tls_s) ?
+                             WR_WAIT_FOR_SEND : WR_WAIT_FOR_RECV);
+    }
+
+    fprintf (stderr, "The error returned by gnutls_bye() is "
+             "'%s' ", gnutls_strerror ((int) ret));
+#if GNUTLS_VERSION_NUMBER >= 0x020600
+    fprintf (stderr, "(%s)\n", gnutls_strerror_name ((int) ret));
+#else  /* GNUTLS_VERSION_NUMBER < 0x020600 */
+    fprintf (stderr, "(%d)\n", (int) ret);
+#endif /* GNUTLS_VERSION_NUMBER < 0x020600 */
+    testErrorLogDesc ("gnutls_bye() failed with hard error");
+    MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_);   /* hard error */
+    return -1;
+  }
+#endif /* HTTPS_SUPPORT */
+  return -1;
+}
+
+
+/**
+ * Shutdown the socket.
+ * @param s the socket to shutdown
+ * @return zero on succeed, -1 otherwise
+ */
+static int
+wr_shutdown (struct wr_socket *s, int how)
+{
+  return wr_shutdown_tmo (s, how, test_timeout * 1000);
+}
+
+
 /**
  * Close socket and release allocated resourced
  * @param s the socket to close
@@ -1246,6 +1365,74 @@ recv_all (struct wr_socket *sock,
 #define recv_all_stext(sk,st) recv_all(sk,st,MHD_STATICSTR_LEN_(st))
 
 
+/**
+ * Shutdown write of the connection to signal end of transmission
+ * for the remote side
+ * @param sock the socket to shutdown
+ */
+static void
+send_eof (struct wr_socket *sock)
+{
+  if (0 != wr_shutdown (sock, wr_is_eof_received (sock) ? SHUT_RDWR : SHUT_WR))
+    externalErrorExitDesc ("Failed to shutdown connection");
+}
+
+
+/**
+ * Receive end of the transmission indication from the remote side
+ * @param sock the socket to use
+ */
+static void
+receive_eof (struct wr_socket *sock)
+{
+  uint8_t buf[127];
+  ssize_t ret;
+  size_t rcvd;
+  bool got_eof = false;
+
+  wr_make_nonblocking (sock);
+  for (rcvd = 0; rcvd < sizeof(buf); rcvd += (size_t) ret)
+  {
+    ret = wr_recv (sock,
+                   buf + rcvd,
+                   sizeof(buf) - rcvd);
+    if (0 > ret)
+    {
+      if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()) ||
+          MHD_SCKT_ERR_IS_EINTR_ (MHD_socket_get_error_ ()))
+      {
+        ret = 0;
+        continue;
+      }
+      externalErrorExitDesc ("recv() failed");
+    }
+    else if (0 == ret)
+    {
+      got_eof = true;
+      break;
+    }
+  }
+  if (got_eof && (0 == rcvd))
+    return; /* Success */
+
+  if (0 != rcvd)
+  {
+    if (sizeof(buf) == rcvd)
+    {
+      fprintf (stderr, "Received at least %lu extra bytes while "
+               "end-of-file is expected.\n", (unsigned long) sizeof(buf));
+      mhdErrorExit ();
+    }
+    fprintf (stderr, "Received at %lu extra bytes and then %s"
+             "end-of-file marker.\n", (unsigned long) rcvd,
+             got_eof ? "" : "NO ");
+    mhdErrorExit ();
+  }
+  if (! got_eof)
+    mhdErrorExitDesc ("Failed to receive end-of-file marker.");
+}
+
+
 /**
  * Main function for the thread that runs the interaction with
  * the upgraded socket.
@@ -1263,6 +1450,11 @@ run_usock (void *cls)
                   "World");
   send_all_stext (usock,
                   "Finished");
+  if (! test_tls)
+  {
+    send_eof (usock);
+    receive_eof (usock);
+  }
   MHD_upgrade_action (urh,
                       MHD_UPGRADE_ACTION_CLOSE);
   free (usock);
@@ -1292,6 +1484,11 @@ run_usock_client (void *cls)
                   "World");
   recv_all_stext (sock,
                   "Finished");
+  if (! test_tls)
+  {
+    receive_eof (sock);
+    send_eof (sock);
+  }
   wr_close (sock);
   client_done = true;
   return NULL;
@@ -1634,8 +1831,6 @@ run_mhd_loop (struct MHD_Daemon *daemon,
 }
 
 
-static bool test_tls;
-
 /**
  * Test upgrading a connection.
  *

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]