gnunet-svn
[Top][All Lists]
Advanced

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

[libmicrohttpd] branch master updated (1497b774 -> 73c43a7e)


From: gnunet
Subject: [libmicrohttpd] branch master updated (1497b774 -> 73c43a7e)
Date: Sun, 26 Dec 2021 10:43:01 +0100

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

karlson2k pushed a change to branch master
in repository libmicrohttpd.

    from 1497b774 connection: mute compiler warning for some platforms
     new 8140b9e7 test_client_put_stop: added detection of unexpected 
connection shut down
     new 005d1f25 test_client_put_stop: ensure that some data will be received 
by MHD before closing
     new 430d7251 Reduced maximum possible connection timeout
     new 0dd7f173 mhd_mono_clock: fixed comment
     new 73c43a7e Added workaround for system clock jumps back

The 5 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/connection.c           |  79 ++++++++++++++++------
 src/microhttpd/daemon.c               | 123 ++++++++++++++++++----------------
 src/microhttpd/mhd_mono_clock.c       |   5 +-
 src/microhttpd/test_client_put_stop.c |  68 +++++++++++++++----
 4 files changed, 184 insertions(+), 91 deletions(-)

diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index 79014352..84bfc662 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -4180,6 +4180,56 @@ MHD_connection_handle_write (struct MHD_Connection 
*connection)
 }
 
 
+/**
+ * Check whether connection has timed out.
+ * @param c the connection to check
+ * @return true if connection has timeout and needs to be closed,
+ *         false otherwise.
+ */
+static bool
+connection_check_timedout (struct MHD_Connection *c)
+{
+  const uint64_t timeout = c->connection_timeout_ms;
+  uint64_t now;
+  uint64_t since_actv;
+
+  if (c->suspended)
+    return false;
+  if (0 == timeout)
+    return false;
+  now = MHD_monotonic_msec_counter ();
+  since_actv = now - c->last_activity;
+  /* Keep the next lines in sync with #connection_get_wait() to avoid
+   * undesired side-effects like busy-waiting. */
+  if (timeout < since_actv)
+  {
+    if (UINT64_MAX / 2 < since_actv)
+    {
+      const uint64_t jump_back = c->last_activity - now;
+      /* Very unlikely that it is more than quarter-million years pause.
+       * More likely that system clock jumps back. */
+      if (5000 >= jump_back)
+      {
+#ifdef HAVE_MESSAGES
+        MHD_DLOG (c->daemon,
+                  _ ("Detected system clock %u milliseconds jump back.\n"),
+                  (unsigned int) jump_back);
+#endif
+        return false;
+      }
+#ifdef HAVE_MESSAGES
+      MHD_DLOG (c->daemon,
+                _ ("Detected too large system clock %" PRIu64 " milliseconds "
+                   "jump back.\n"),
+                jump_back);
+#endif
+    }
+    return true;
+  }
+  return false;
+}
+
+
 /**
  * Clean up the state of the given connection and move it into the
  * clean up queue for final disposal.
@@ -4799,21 +4849,12 @@ MHD_connection_handle_idle (struct MHD_Connection 
*connection)
     }
     break;
   }
-  if (! connection->suspended)
+  if (connection_check_timedout (connection))
   {
-    uint64_t timeout;
-    timeout = connection->connection_timeout_ms;
-    /* Keep the next lines in sync with #MHD_get_timeout() to avoid
-     * undesired side-effects like busy-waiting. */
-    if ( (0 != timeout) &&
-         (timeout < (MHD_monotonic_msec_counter ()
-                     - connection->last_activity)) )
-    {
-      MHD_connection_close_ (connection,
-                             MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
-      connection->in_idle = false;
-      return MHD_YES;
-    }
+    MHD_connection_close_ (connection,
+                           MHD_REQUEST_TERMINATED_TIMEOUT_REACHED);
+    connection->in_idle = false;
+    return MHD_YES;
   }
   MHD_connection_update_event_loop_info (connection);
   ret = MHD_YES;
@@ -4999,8 +5040,8 @@ MHD_set_connection_option (struct MHD_Connection 
*connection,
     va_start (ap, option);
     ui_val = va_arg (ap, unsigned int);
     va_end (ap);
-#if (SIZEOF_UINT64_T - 1) <= SIZEOF_UNSIGNED_INT
-    if ((UINT64_MAX / 2000 - 1) < ui_val)
+#if (SIZEOF_UINT64_T - 2) <= SIZEOF_UNSIGNED_INT
+    if ((UINT64_MAX / 4000 - 1) < ui_val)
     {
 #ifdef HAVE_MESSAGES
       MHD_DLOG (connection->daemon,
@@ -5008,12 +5049,12 @@ MHD_set_connection_option (struct MHD_Connection 
*connection,
                    "large. Maximum allowed value (%" PRIu64 ") will be used " \
                    "instead.\n"),
                 ui_val,
-                (UINT64_MAX / 2000 - 1));
+                (UINT64_MAX / 4000 - 1));
 #endif
-      ui_val = UINT64_MAX / 2000 - 1;
+      ui_val = UINT64_MAX / 4000 - 1;
     }
     else
-#endif /* (SIZEOF_UINT64_T - 1) <= SIZEOF_UNSIGNED_INT */
+#endif /* (SIZEOF_UINT64_T - 2) <= SIZEOF_UNSIGNED_INT */
     connection->connection_timeout_ms = ui_val * 1000;
     if ( (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
          (! connection->suspended) )
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index 9f220263..5ca612ea 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -1857,6 +1857,54 @@ thread_main_connection_upgrade (struct MHD_Connection 
*con)
 #endif /* UPGRADE_SUPPORT */
 
 
+/**
+ * Get maximum wait period for the connection (the amount of time left before
+ * connection time out)
+ * @param c the connection to check
+ * @return the maximum wait period before the connection must be processed
+ *         again.
+ */
+static uint64_t
+connection_get_wait (struct MHD_Connection *c)
+{
+  const uint64_t now = MHD_monotonic_msec_counter ();
+  const uint64_t since_actv = now - c->last_activity;
+  const uint64_t timeout = c->connection_timeout_ms;
+  uint64_t mseconds_left;
+
+  mhd_assert (0 != timeout);
+  /* Keep the next lines in sync with #connection_check_timedout() to avoid
+   * undesired side-effects like busy-waiting. */
+  if (timeout < since_actv)
+  {
+    if (UINT64_MAX / 2 < since_actv)
+    {
+      const uint64_t jump_back = c->last_activity - now;
+      /* Very unlikely that it is more than quarter-million years pause.
+       * More likely that system clock jumps back. */
+      if (5000 >= jump_back)
+      { /* Jump back is less than 5 seconds, try to recover. */
+        return 100; /* Set wait time to 0.1 seconds */
+      }
+      /* Too large jump back */
+    }
+    return 0; /* Connection has timed out */
+  }
+  else if (since_actv == timeout)
+  {
+    /* Exact match for timeout and time from last activity.
+     * Maybe this is just a precise match or this happens because the timer
+     * resolution is too low.
+     * Set wait time to 0.1 seconds to avoid busy-waiting with low
+     * timer resolution as connection is not timed-out yet. */
+    return 100;
+  }
+  mseconds_left = timeout - since_actv;
+
+  return mseconds_left;
+}
+
+
 /**
  * Main function of the thread that handles an individual
  * connection when #MHD_USE_THREAD_PER_CONNECTION is set.
@@ -1995,35 +2043,16 @@ thread_main_handle_connection (void *data)
     if ( (NULL == tvp) &&
          (timeout > 0) )
     {
-      const uint64_t since_actv = MHD_monotonic_msec_counter ()
-                                  - con->last_activity;
-      if (since_actv > timeout)
-      {
-        tv.tv_sec = 0;
-        tv.tv_usec = 0;
-      }
-      else if (since_actv == timeout)
-      {
-        /* Exact match for timeout and time from last activity.
-         * Maybe this is just a precise match or this happens because the timer
-         * resolution is too low.
-         * Set wait time to 0.1 seconds to avoid busy-waiting with low
-         * timer resolution as connection is not yet timed-out */
-        tv.tv_sec = 0;
-        tv.tv_usec = 100 * 1000;
-      }
+      const uint64_t mseconds_left = connection_get_wait (con);
+#if (SIZEOF_UINT64_T - 2) >= SIZEOF_STRUCT_TIMEVAL_TV_SEC
+      if (mseconds_left / 1000 > TIMEVAL_TV_SEC_MAX)
+        tv.tv_sec = TIMEVAL_TV_SEC_MAX;
       else
-      {
-        const uint64_t mseconds_left = timeout - since_actv;
-#if (SIZEOF_UINT64_T - 1) >= SIZEOF_STRUCT_TIMEVAL_TV_SEC
-        if (mseconds_left / 1000 > TIMEVAL_TV_SEC_MAX)
-          tv.tv_sec = TIMEVAL_TV_SEC_MAX;
-        else
-#endif /* (SIZEOF_UINT64_T - 1) >= SIZEOF_STRUCT_TIMEVAL_TV_SEC */
-        tv.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE) mseconds_left / 1000;
+#endif /* (SIZEOF_UINT64_T - 2) >= SIZEOF_STRUCT_TIMEVAL_TV_SEC */
+      tv.tv_sec = (_MHD_TIMEVAL_TV_SEC_TYPE) mseconds_left / 1000;
+
+      tv.tv_usec = (mseconds_left % 1000) * 1000;
 
-        tv.tv_usec = (mseconds_left % 1000) * 1000;
-      }
       tvp = &tv;
     }
     if (! use_poll)
@@ -3930,33 +3959,13 @@ MHD_get_timeout (struct MHD_Daemon *daemon,
 
   if (NULL != earliest_tmot_conn)
   {
-    const uint64_t since_actv = MHD_monotonic_msec_counter ()
-                                - earliest_tmot_conn->last_activity;
-    /* Keep the next lines in sync with #MHD_connection_handle_idle() and
-     * with #thread_main_handle_connection(). */
-    if (since_actv > earliest_tmot_conn->connection_timeout_ms)
-      *timeout = 0;
-    else if (since_actv == earliest_tmot_conn->connection_timeout_ms)
-    {
-      /* Exact match for timeout and time from last activity.
-       * Maybe this is just a precise match or this happens because the timer
-       * resolution is too low.
-       * Set wait time to 0.1 seconds to avoid busy-waiting with low
-       * timer resolution as connection is not yet timed-out */
-      *timeout = 100;
-    }
-    else
-    {
-      const uint64_t mssecond_left = earliest_tmot_conn->connection_timeout_ms
-                                     - since_actv;
-
+    const uint64_t mssecond_left = connection_get_wait (earliest_tmot_conn);
 #if SIZEOF_UINT64_T > SIZEOF_UNSIGNED_LONG_LONG
-      if (mssecond_left > ULLONG_MAX)
-        *timeout = ULLONG_MAX;
-      else
+    if (mssecond_left > ULLONG_MAX)
+      *timeout = ULLONG_MAX;
+    else
 #endif /* UINT64 != ULLONG_MAX */
-      *timeout = (unsigned long long) mssecond_left;
-    }
+    *timeout = (unsigned long long) mssecond_left;
     return MHD_YES;
   }
   return MHD_NO;
@@ -5658,8 +5667,8 @@ parse_options_va (struct MHD_Daemon *daemon,
     case MHD_OPTION_CONNECTION_TIMEOUT:
       uv = va_arg (ap,
                    unsigned int);
-#if (SIZEOF_UINT64_T - 1) <= SIZEOF_UNSIGNED_INT
-      if ((UINT64_MAX / 2000 - 1) < uv)
+#if (SIZEOF_UINT64_T - 2) <= SIZEOF_UNSIGNED_INT
+      if ((UINT64_MAX / 4000 - 1) < uv)
       {
 #ifdef HAVE_MESSAGES
         MHD_DLOG (daemon,
@@ -5667,11 +5676,11 @@ parse_options_va (struct MHD_Daemon *daemon,
                      "Maximum allowed value (%" PRIu64 ") will be used " \
                      "instead.\n"),
                   uv,
-                  (UINT64_MAX / 2000 - 1));
+                  (UINT64_MAX / 4000 - 1));
 #endif
-        uv = UINT64_MAX / 2000 - 1;
+        uv = UINT64_MAX / 4000 - 1;
       }
-#endif /* (SIZEOF_UINT64_T - 1) <= SIZEOF_UNSIGNED_INT */
+#endif /* (SIZEOF_UINT64_T - 2) <= SIZEOF_UNSIGNED_INT */
       daemon->connection_timeout_ms = uv * 1000;
       break;
     case MHD_OPTION_NOTIFY_COMPLETED:
diff --git a/src/microhttpd/mhd_mono_clock.c b/src/microhttpd/mhd_mono_clock.c
index e06f6d16..b04153f8 100644
--- a/src/microhttpd/mhd_mono_clock.c
+++ b/src/microhttpd/mhd_mono_clock.c
@@ -215,8 +215,7 @@ MHD_monotonic_sec_counter_init (void)
   else
 #endif /* CLOCK_MONOTONIC_RAW */
 #ifdef CLOCK_BOOTTIME
-  /* Linux-specific clock */
-  /* Count time in suspend so it's real monotonic on Linux, */
+  /* Count time in suspend on Linux so it's real monotonic, */
   /* but can be slower value-getting than other clocks */
   if (0 == clock_gettime (CLOCK_BOOTTIME,
                           &ts))
@@ -239,7 +238,7 @@ MHD_monotonic_sec_counter_init (void)
     mono_clock_source = _MHD_CLOCK_GETTIME;
   }
   else
-#endif /* CLOCK_BOOTTIME */
+#endif /* CLOCK_MONOTONIC */
 #ifdef CLOCK_UPTIME
   /* non-Linux clock */
   /* Doesn't count time in suspend */
diff --git a/src/microhttpd/test_client_put_stop.c 
b/src/microhttpd/test_client_put_stop.c
index e2689ec3..c1707c5c 100644
--- a/src/microhttpd/test_client_put_stop.c
+++ b/src/microhttpd/test_client_put_stop.c
@@ -710,6 +710,8 @@ _MHD_dumbClient_send_req (struct _MHD_dumbClient *clnt)
       return;
     if (MHD_SCKT_ERR_IS_REMOTE_DISCNN_ (err))
       mhdErrorExitDesc ("The connection was aborted by MHD");
+    if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EPIPE_))
+      mhdErrorExitDesc ("The connection was shut down on MHD side");
     externalErrorExitDesc ("Unexpected network error");
   }
   clnt->send_off += (size_t) res;
@@ -1374,6 +1376,7 @@ performQueryExternal (struct MHD_Daemon *d, struct 
_MHD_dumbClient *clnt)
   int client_accepted;
   int full_req_recieved;
   int full_req_sent;
+  int some_data_recieved;
 
   di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD);
   if (NULL == di)
@@ -1386,6 +1389,7 @@ performQueryExternal (struct MHD_Daemon *d, struct 
_MHD_dumbClient *clnt)
   _MHD_dumbClient_start_connect (clnt);
 
   full_req_recieved = 0;
+  some_data_recieved = 0;
   start = time (NULL);
   do
   {
@@ -1394,6 +1398,7 @@ performQueryExternal (struct MHD_Daemon *d, struct 
_MHD_dumbClient *clnt)
     fd_set es;
     MHD_socket maxMhdSk;
     int num_ready;
+    int do_client; /**< Process data in client */
 
     maxMhdSk = MHD_INVALID_SOCKET;
     FD_ZERO (&rs);
@@ -1405,6 +1410,7 @@ performQueryExternal (struct MHD_Daemon *d, struct 
_MHD_dumbClient *clnt)
        * processing any connections */
       unsigned long long to;
       full_req_sent = 1;
+      do_client = 0;
       if (client_accepted && (MHD_YES != MHD_get_timeout (d, &to)))
       {
         ret = 0;
@@ -1414,12 +1420,36 @@ performQueryExternal (struct MHD_Daemon *d, struct 
_MHD_dumbClient *clnt)
     else
     {
       full_req_sent = _MHD_dumbClient_is_req_sent (clnt);
-      if ((! full_req_sent) || full_req_recieved || (0 == rate_limiter))
+      if (! full_req_sent)
+        do_client = 1; /* Request hasn't been sent yet, send the data */
+      else
+      {
+        /* All request data has been sent.
+         * Client will close the socket as the next step. */
+        if (full_req_recieved)
+          do_client = 1; /* All data has been received by the MHD */
+        else if ((0 == rate_limiter) && some_data_recieved)
+        {
+          /* No RST rate limiter, no need to avoid extra RST
+           * and at least something was received by the MHD */
+          do_client = 1;
+        }
+        else
+        {
+          /* When rate limiter is enabled, all sent packets must be received
+           * before client close connection to avoid RST for every ACK.
+           * When rate limiter is not enabled, the MHD must receive at
+           * least something before closing the connection. */
+          do_client = 0;
+        }
+      }
+
+      if (do_client)
         _MHD_dumbClient_get_fdsets (clnt, &maxMhdSk, &rs, &ws, &es);
     }
     if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxMhdSk))
       mhdErrorExitDesc ("MHD_get_fdset() failed");
-    if ((! full_req_sent) || full_req_recieved || (0 == rate_limiter))
+    if (do_client)
     {
       tv.tv_sec = 1;
       tv.tv_usec = 250 * 1000;
@@ -1445,6 +1475,8 @@ performQueryExternal (struct MHD_Daemon *d, struct 
_MHD_dumbClient *clnt)
     }
     if (0 == num_ready)
     { /* select() finished by timeout, looks like no more packets are pending 
*/
+      if (do_client)
+        externalErrorExitDesc ("Timeout waiting for sockets");
       if (full_req_sent && (! full_req_recieved))
         full_req_recieved = 1;
     }
@@ -1452,21 +1484,33 @@ performQueryExternal (struct MHD_Daemon *d, struct 
_MHD_dumbClient *clnt)
       mhdErrorExitDesc ("MHD_run_from_select() failed");
     if (! client_accepted)
       client_accepted = FD_ISSET (lstn_sk, &rs);
-    if (NULL != clnt)
-    {
-      /* Do not close the socket on client side until
-       * MHD is accepted and processed the socket. */
-      if (! full_req_sent || (client_accepted && ! FD_ISSET (lstn_sk, &rs)))
+    else
+    { /* Client connection was already accepted by MHD */
+      if (! some_data_recieved)
       {
-        if ((! full_req_sent) || full_req_recieved || (0 == rate_limiter))
+        if (! do_client)
         {
-          /* When rate limiter is enabled, all sent packets must be received
-           * before client close connection to avoid RST for every ACK. */
-          if (_MHD_dumbClient_process_from_fdsets (clnt, &rs, &ws, &es))
-            clnt = NULL;
+          if (0 != num_ready)
+          { /* Connection was accepted before, "ready" socket means data */
+            some_data_recieved = 1;
+          }
+        }
+        else
+        {
+          if (2 == num_ready)
+            some_data_recieved = 1;
+          else if ((1 == num_ready) &&
+                   ((MHD_INVALID_SOCKET == clnt->sckt) ||
+                    ! FD_ISSET (clnt->sckt, &ws)))
+            some_data_recieved = 1;
         }
       }
     }
+    if (do_client)
+    {
+      if (_MHD_dumbClient_process_from_fdsets (clnt, &rs, &ws, &es))
+        clnt = NULL;
+    }
     /* Use double timeout value here so MHD would be able to catch timeout
      * internally */
   } while (time (NULL) - start <= (TIMEOUTS_VAL * 2));

-- 
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]