gnunet-svn
[Top][All Lists]
Advanced

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

[libmicrohttpd] 01/04: test_upgrade: added checking of socket shutdown s


From: gnunet
Subject: [libmicrohttpd] 01/04: test_upgrade: added checking of socket shutdown status
Date: Sat, 02 Dec 2023 18:17:03 +0100

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

karlson2k pushed a commit to branch master
in repository libmicrohttpd.

commit f09bf9eafdcb4b2bad82a62500be79a0b9ce3b22
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
AuthorDate: Sun Nov 26 13:31:05 2023 +0300

    test_upgrade: added checking of socket shutdown status
    
    Currently enabled only for non-TLS connections
---
 src/microhttpd/test_upgrade.c | 243 +++++++++++++++++++++++++++++++++++++-----
 1 file changed, 219 insertions(+), 24 deletions(-)

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]