gnunet-svn
[Top][All Lists]
Advanced

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

[libmicrohttpd] branch master updated (a19df909 -> 38c06b6a)


From: gnunet
Subject: [libmicrohttpd] branch master updated (a19df909 -> 38c06b6a)
Date: Fri, 24 Nov 2023 19:53:55 +0100

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

karlson2k pushed a change to branch master
in repository libmicrohttpd.

    from a19df909 Officially support zero for MHD_OPTION_THREAD_POOL_SIZE
     new 0ddd04b4 mhd_sockets: fixed error code for W32
     new 1cf76efe test_upgrade{,_large}: minor improvements
     new 90b2bab0 test_upgrade: used sized send and receive, removed VLA, other 
improvements
     new 80ecc6d3 test_upgrade: added initial support for timeout detection
     new 53e1e486 test_upgrade: set TCP_NODELAY unconditionally on used sockets
     new 7d7d9bc6 test_upgrade: added timeout detection on send/recv operations
     new 1070d24a test_upgrade: fixed timeout value for external select
     new b3c1e629 test_upgrade: merged similar code paths
     new 38c06b6a test_upgrade: implemented timeouts for all socket operations

The 9 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/mhd_sockets.h        |   2 +-
 src/microhttpd/test_upgrade.c       | 846 ++++++++++++++++++++++++++----------
 src/microhttpd/test_upgrade_large.c |  27 +-
 3 files changed, 652 insertions(+), 223 deletions(-)

diff --git a/src/microhttpd/mhd_sockets.h b/src/microhttpd/mhd_sockets.h
index 3b953c3f..02e3ebec 100644
--- a/src/microhttpd/mhd_sockets.h
+++ b/src/microhttpd/mhd_sockets.h
@@ -648,7 +648,7 @@ typedef int MHD_SCKT_SEND_SIZE_;
 #  define MHD_SCKT_EACCESS_       WSAEACCES
 #  define MHD_SCKT_ENETDOWN_      WSAENETDOWN
 #  define MHD_SCKT_EALREADY_      WSAEALREADY
-#  define MHD_SCKT_EINPROGRESS_   WSAEACCES
+#  define MHD_SCKT_EINPROGRESS_   WSAEINPROGRESS
 #  define MHD_SCKT_EISCONN_       WSAEISCONN
 #endif
 
diff --git a/src/microhttpd/test_upgrade.c b/src/microhttpd/test_upgrade.c
index 22b15090..b30ad64b 100644
--- a/src/microhttpd/test_upgrade.c
+++ b/src/microhttpd/test_upgrade.c
@@ -33,6 +33,7 @@
 #include <pthread.h>
 #include <stdlib.h>
 #include <stddef.h>
+#include <stdint.h>
 #include <errno.h>
 #ifndef WINDOWS
 #include <unistd.h>
@@ -61,6 +62,22 @@
 #endif /* HAVE_FORK && HAVE_WAITPID */
 #endif /* HTTPS_SUPPORT */
 
+#if defined(MHD_POSIX_SOCKETS)
+#  ifdef MHD_WINSOCK_SOCKETS
+#    error Both MHD_POSIX_SOCKETS and MHD_WINSOCK_SOCKETS are defined
+#  endif /* MHD_WINSOCK_SOCKETS */
+#elif ! defined(MHD_WINSOCK_SOCKETS)
+#  error Neither MHD_POSIX_SOCKETS nor MHD_WINSOCK_SOCKETS are defined
+#endif /* MHD_WINSOCK_SOCKETS */
+
+
+#ifndef MHD_STATICSTR_LEN_
+/**
+ * Determine length of static string / macro strings at compile time.
+ */
+#define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1)
+#endif /* ! MHD_STATICSTR_LEN_ */
+
 
 _MHD_NORETURN static void
 _externalErrorExit_func (const char *errDesc, const char *funcName, int 
lineNum)
@@ -128,33 +145,20 @@ _testErrorLog_func (const char *errDesc, const char 
*funcName, int lineNum)
 }
 
 
-#if defined(HAVE___FUNC__)
-#define externalErrorExit(ignore) \
-    _externalErrorExit_func(NULL, __func__, __LINE__)
-#define externalErrorExitDesc(errDesc) \
-    _externalErrorExit_func(errDesc, __func__, __LINE__)
-#define mhdErrorExit(ignore) \
-    _mhdErrorExit_func(NULL, __func__, __LINE__)
-#define mhdErrorExitDesc(errDesc) \
-    _mhdErrorExit_func(errDesc, __func__, __LINE__)
-#define testErrorLog(ignore) \
-    _testErrorLog_func(NULL, __func__, __LINE__)
-#define testErrorLogDesc(errDesc) \
-    _testErrorLog_func(errDesc, __func__, __LINE__)
-#elif defined(HAVE___FUNCTION__)
+#ifdef MHD_HAVE_MHD_FUNC_
 #define externalErrorExit(ignore) \
-    _externalErrorExit_func(NULL, __FUNCTION__, __LINE__)
+    _externalErrorExit_func(NULL, MHD_FUNC_, __LINE__)
 #define externalErrorExitDesc(errDesc) \
-    _externalErrorExit_func(errDesc, __FUNCTION__, __LINE__)
+    _externalErrorExit_func(errDesc, MHD_FUNC_, __LINE__)
 #define mhdErrorExit(ignore) \
-    _mhdErrorExit_func(NULL, __FUNCTION__, __LINE__)
+    _mhdErrorExit_func(NULL, MHD_FUNC_, __LINE__)
 #define mhdErrorExitDesc(errDesc) \
-    _mhdErrorExit_func(errDesc, __FUNCTION__, __LINE__)
+    _mhdErrorExit_func(errDesc, MHD_FUNC_, __LINE__)
 #define testErrorLog(ignore) \
-    _testErrorLog_func(NULL, __FUNCTION__, __LINE__)
+    _testErrorLog_func(NULL, MHD_FUNC_, __LINE__)
 #define testErrorLogDesc(errDesc) \
-    _testErrorLog_func(errDesc, __FUNCTION__, __LINE__)
-#else
+    _testErrorLog_func(errDesc, MHD_FUNC_, __LINE__)
+#else  /* ! MHD_HAVE_MHD_FUNC_ */
 #define externalErrorExit(ignore) _externalErrorExit_func(NULL, NULL, __LINE__)
 #define externalErrorExitDesc(errDesc) \
   _externalErrorExit_func(errDesc, NULL, __LINE__)
@@ -162,16 +166,11 @@ _testErrorLog_func (const char *errDesc, const char 
*funcName, int lineNum)
 #define mhdErrorExitDesc(errDesc) _mhdErrorExit_func(errDesc, NULL, __LINE__)
 #define testErrorLog(ignore) _testErrorLog_func(NULL, NULL, __LINE__)
 #define testErrorLogDesc(errDesc) _testErrorLog_func(errDesc, NULL, __LINE__)
-#endif
+#endif /* ! MHD_HAVE_MHD_FUNC_ */
 
 
-static void
-fflush_allstd (void)
-{
-  fflush (stderr);
-  fflush (stdout);
-}
-
+/* Could be increased to facilitate debugging */
+static int test_timeout = 5;
 
 static int verbose = 0;
 
@@ -187,6 +186,14 @@ enum tls_tool
 
 static enum tls_tool use_tls_tool;
 
+static void
+fflush_allstd (void)
+{
+  fflush (stderr);
+  fflush (stdout);
+}
+
+
 #if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
 /**
  * Fork child that connects via GnuTLS-CLI to our @a port.  Allows us to
@@ -263,6 +270,92 @@ gnutlscli_connect (int *sock,
 #endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */
 
 
+#if 0 /* Unused code */
+/**
+ * Change socket to blocking.
+ *
+ * @param fd the socket to manipulate
+ */
+static void
+make_blocking (MHD_socket fd)
+{
+#if defined(MHD_POSIX_SOCKETS)
+  int flags;
+
+  flags = fcntl (fd, F_GETFL);
+  if (-1 == flags)
+    externalErrorExitDesc ("fcntl() failed");
+  if ((flags & ~O_NONBLOCK) != flags)
+    if (-1 == fcntl (fd, F_SETFL, flags & ~O_NONBLOCK))
+      externalErrorExitDesc ("fcntl() failed");
+#elif defined(MHD_WINSOCK_SOCKETS)
+  unsigned long flags = 0;
+
+  if (0 != ioctlsocket (fd, (int) FIONBIO, &flags))
+    externalErrorExitDesc ("ioctlsocket() failed");
+#endif /* MHD_WINSOCK_SOCKETS */
+}
+
+
+#endif /* Unused code */
+
+
+/**
+ * Change socket to non-blocking.
+ *
+ * @param fd the socket to manipulate
+ */
+static void
+make_nonblocking (MHD_socket fd)
+{
+#if defined(MHD_POSIX_SOCKETS)
+  int flags;
+
+  flags = fcntl (fd, F_GETFL);
+  if (-1 == flags)
+    externalErrorExitDesc ("fcntl() failed");
+  if (O_NONBLOCK != (flags & O_NONBLOCK))
+    if (-1 == fcntl (fd, F_SETFL, flags | O_NONBLOCK))
+      externalErrorExitDesc ("fcntl() failed");
+#elif defined(MHD_WINSOCK_SOCKETS)
+  unsigned long flags = 1;
+
+  if (0 != ioctlsocket (fd, (int) FIONBIO, &flags))
+    externalErrorExitDesc ("ioctlsocket() failed");
+#endif /* MHD_WINSOCK_SOCKETS */
+}
+
+
+/**
+ * Enable TCP_NODELAY on TCP/IP socket.
+ *
+ * @param fd the socket to manipulate
+ */
+static void
+make_nodelay (MHD_socket fd)
+{
+#ifdef TCP_NODELAY
+  const MHD_SCKT_OPT_BOOL_ on_val = 1;
+
+  if (0 == setsockopt (fd,
+                       IPPROTO_TCP,
+                       TCP_NODELAY,
+                       (const void *) &on_val,
+                       sizeof (on_val)))
+    return; /* Success exit point */
+
+#ifndef MHD_WINSOCK_SOCKETS
+  fprintf (stderr, "Failed to enable TCP_NODELAY on socket (ignored). "
+           "errno: %d (%s)\n", (int) errno, strerror (errno));
+#else /* MHD_WINSOCK_SOCKETS */
+  fprintf (stderr, "Failed to enable TCP_NODELAY on socket (ignored). "
+           "WSAGetLastError() value: %d\n", (int) WSAGetLastError ());
+#endif /* MHD_WINSOCK_SOCKETS */
+  fflush (stderr);
+#endif /* TCP_NODELAY */
+}
+
+
 /**
  * Wrapper structure for plain&TLS sockets
  */
@@ -282,6 +375,8 @@ struct wr_socket
     wr_plain = 1,
     wr_tls = 2
   } t;
+
+  bool is_nonblocking;
 #ifdef HTTPS_SUPPORT
   /**
    * TLS credentials
@@ -308,6 +403,28 @@ struct wr_socket
 #define wr_fd(s) ((s)->fd)
 
 
+#if 0 /* Unused code */
+static void
+wr_make_blocking  (struct wr_socket *s)
+{
+  if (s->is_nonblocking)
+    make_blocking (s->fd);
+  s->is_nonblocking = false;
+}
+
+
+#endif /* Unused code */
+
+
+static void
+wr_make_nonblocking  (struct wr_socket *s)
+{
+  if (! s->is_nonblocking)
+    make_nonblocking (s->fd);
+  s->is_nonblocking = true;
+}
+
+
 /**
  * Create wr_socket with plain TCP underlying socket
  * @return created socket on success, NULL otherwise
@@ -323,8 +440,12 @@ wr_create_plain_sckt (void)
   }
   s->t = wr_plain;
   s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  s->is_nonblocking = false;
   if (MHD_INVALID_SOCKET != s->fd)
+  {
+    make_nodelay (s->fd);
     return s; /* Success */
+  }
   testErrorLogDesc ("socket() failed");
   free (s);
   return NULL;
@@ -348,8 +469,10 @@ wr_create_tls_sckt (void)
   s->t = wr_tls;
   s->tls_connected = 0;
   s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  s->is_nonblocking = false;
   if (MHD_INVALID_SOCKET != s->fd)
   {
+    make_nodelay (s->fd);
     if (GNUTLS_E_SUCCESS == gnutls_init (&(s->tls_s), GNUTLS_CLIENT))
     {
       if (GNUTLS_E_SUCCESS == gnutls_set_default_priority (s->tls_s))
@@ -410,26 +533,133 @@ wr_create_from_plain_sckt (MHD_socket plain_sk)
   }
   s->t = wr_plain;
   s->fd = plain_sk;
+  s->is_nonblocking = false; /* The actual mode is unknown */
+  wr_make_nonblocking (s);   /* Force set mode to have correct status */
+  make_nodelay (s->fd);
   return s;
 }
 
 
+enum wr_wait_for_type
+{
+  WR_WAIT_FOR_RECV = 0,
+  WR_WAIT_FOR_SEND = 1
+};
+
+static bool
+wr_wait_socket_ready_noabort_ (struct wr_socket *s,
+                               int timeout_ms,
+                               enum wr_wait_for_type wait_for)
+{
+  fd_set fds;
+  int sel_res;
+  struct timeval tmo;
+  struct timeval *tmo_ptr;
+
+#ifndef MHD_WINSOCK_SOCKETS
+  if (FD_SETSIZE <= s->fd)
+    externalErrorExitDesc ("Too large FD value");
+#endif /* ! MHD_WINSOCK_SOCKETS */
+  FD_ZERO (&fds);
+  FD_SET (s->fd, &fds);
+  if (0 <= timeout_ms)
+  {
+#if ! defined(_WIN32) || defined(__CYGWIN__)
+    tmo.tv_sec = (time_t) (timeout_ms / 1000);
+#else  /* Native W32 */
+    tmo.tv_sec = (long) (timeout_ms / 1000);
+#endif /* Native W32 */
+    tmo.tv_usec = ((long) (timeout_ms % 1000)) * 1000;
+    tmo_ptr = &tmo;
+  }
+  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);
+
+  if (1 == sel_res)
+    return true;
+
+  if (0 == sel_res)
+    fprintf (stderr, "Timeout");
+  else
+  {
+#ifndef MHD_WINSOCK_SOCKETS
+    fprintf (stderr, "Error %d (%s)", (int) errno, strerror (errno));
+#else /* MHD_WINSOCK_SOCKETS */
+    fprintf (stderr, "Error (WSAGetLastError code: %d)",
+             (int) WSAGetLastError ());
+#endif /* MHD_WINSOCK_SOCKETS */
+  }
+  fprintf (stderr, " waiting for socket to be available for %s.\n",
+           (WR_WAIT_FOR_RECV == wait_for) ? "receiving" : "sending");
+  return false;
+}
+
+
+static void
+wr_wait_socket_ready_ (struct wr_socket *s,
+                       int timeout_ms,
+                       enum wr_wait_for_type wait_for)
+{
+  if (wr_wait_socket_ready_noabort_ (s, timeout_ms, wait_for))
+    return;
+
+  if (WR_WAIT_FOR_RECV == wait_for)
+    mhdErrorExitDesc ("Client or application failed to receive the data");
+  else
+    mhdErrorExitDesc ("Client or application failed to send the data");
+}
+
+
 /**
  * Connect socket to specified address.
  * @param s socket to use
  * @param addr address to connect
  * @param length of structure pointed by @a addr
+ * @param timeout_ms the maximum wait time in milliseconds to send the data,
+ *                   no limit if negative value is used
  * @return zero on success, -1 otherwise.
  */
 static int
-wr_connect (struct wr_socket *s,
-            const struct sockaddr *addr,
-            unsigned int length)
+wr_connect_tmo (struct wr_socket *s,
+                const struct sockaddr *addr,
+                unsigned int length,
+                int timeout_ms)
 {
   if (0 != connect (s->fd, addr, (socklen_t) length))
   {
-    testErrorLogDesc ("connect() failed");
-    return -1;
+    int err;
+    bool connect_completed = false;
+
+    err = MHD_socket_get_error_ ();
+#if defined(MHD_POSIX_SOCKETS)
+    while (! connect_completed && (EINTR == err))
+    {
+      connect_completed = (0 == connect (s->fd, addr, (socklen_t) length));
+      if (! connect_completed)
+      {
+        err = errno;
+        if (EALREADY == err)
+          err = EINPROGRESS;
+        else if (EISCONN == err)
+          connect_completed = true;
+      }
+    }
+#endif /* MHD_POSIX_SOCKETS */
+    if (! connect_completed &&
+        (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EINPROGRESS_)
+         || MHD_SCKT_ERR_IS_EAGAIN_ (err))) /* No modern system uses EAGAIN, 
except W32 */
+      connect_completed =
+        wr_wait_socket_ready_noabort_ (s, timeout_ms, WR_WAIT_FOR_SEND);
+    if (! connect_completed)
+    {
+      testErrorLogDesc ("connect() failed");
+      return -1;
+    }
   }
   if (wr_plain == s->t)
     return 0;
@@ -437,7 +667,7 @@ wr_connect (struct wr_socket *s,
   if (wr_tls == s->t)
   {
     /* Do not try handshake here as
-     * it require processing on MHD side and
+     * it requires processing on MHD side and
      * when testing with "external" polling,
      * test will call MHD processing only
      * after return from wr_connect(). */
@@ -451,18 +681,48 @@ wr_connect (struct wr_socket *s,
 }
 
 
+/**
+ * Connect socket to specified address.
+ * @param s socket to use
+ * @param addr address to connect
+ * @param length of structure pointed by @a addr
+ * @return zero on success, -1 otherwise.
+ */
+static int
+wr_connect (struct wr_socket *s,
+            const struct sockaddr *addr,
+            unsigned int length)
+{
+  return wr_connect_tmo (s, addr, length, test_timeout * 1000);
+}
+
+
 #ifdef HTTPS_SUPPORT
 /* Only to be called from wr_send() and wr_recv() ! */
 static bool
-wr_handshake (struct wr_socket *s)
+wr_handshake_tmo_ (struct wr_socket *s,
+                   int timeout_ms)
 {
   int res = gnutls_handshake (s->tls_s);
+
+  while ((GNUTLS_E_AGAIN == res) || (GNUTLS_E_INTERRUPTED  == res))
+  {
+    wr_wait_socket_ready_ (s, timeout_ms,
+                           gnutls_record_get_direction (s->tls_s) ?
+                           WR_WAIT_FOR_SEND : WR_WAIT_FOR_RECV);
+    res = gnutls_handshake (s->tls_s);
+  }
   if (GNUTLS_E_SUCCESS == res)
     s->tls_connected = true;
-  else if (GNUTLS_E_AGAIN == res)
-    MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
   else
   {
+    fprintf (stderr, "The error returned by gnutls_handshake() is "
+             "'%s' ", gnutls_strerror ((int) res));
+#if GNUTLS_VERSION_NUMBER >= 0x020600
+    fprintf (stderr, "(%s)\n", gnutls_strerror_name ((int) res));
+#else  /* GNUTLS_VERSION_NUMBER < 0x020600 */
+    fprintf (stderr, "(%d)\n", (int) res);
+#endif /* GNUTLS_VERSION_NUMBER < 0x020600 */
     testErrorLogDesc ("gnutls_handshake() failed with hard error");
     MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */
   }
@@ -470,6 +730,17 @@ wr_handshake (struct wr_socket *s)
 }
 
 
+#if 0 /* Unused function */
+/* Only to be called from wr_send() and wr_recv() ! */
+static bool
+wr_handshake_ (struct wr_socket *s)
+{
+  return wr_handshake_tmo_ (s, test_timeout * 1000);
+}
+
+
+#endif /* Unused function */
+
 #endif /* HTTPS_SUPPORT */
 
 
@@ -478,35 +749,58 @@ wr_handshake (struct wr_socket *s)
  * @param s the socket to use
  * @param buf the buffer with data to send
  * @param len the length of data in @a buf
+ * @param timeout_ms the maximum wait time in milliseconds to send the data,
+ *                   no limit if negative value is used
  * @return number of bytes were sent if succeed,
  *         -1 if failed. Use #MHD_socket_get_error_()
  *         to get socket error.
  */
 static ssize_t
-wr_send (struct wr_socket *s,
-         const void *buf,
-         size_t len)
+wr_send_tmo (struct wr_socket *s,
+             const void *buf,
+             size_t len,
+             int timeout_ms)
 {
   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);
+  }
 #ifdef HTTPS_SUPPORT
-  if (wr_tls == s->t)
+  else if (wr_tls == s->t)
   {
     ssize_t ret;
-    if (! s->tls_connected && ! wr_handshake (s))
+    if (! s->tls_connected && ! wr_handshake_tmo_ (s, timeout_ms))
       return -1;
 
-    ret = gnutls_record_send (s->tls_s, buf, len);
-    if (ret > 0)
-      return ret;
-    if (GNUTLS_E_AGAIN == ret)
-      MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
-    else
+    while (1)
     {
-      testErrorLogDesc ("gnutls_record_send() failed with hard error");
-      MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_);   /* hard error */
-      return -1;
+      ret = gnutls_record_send (s->tls_s, buf, len);
+      if (ret >= 0)
+        return ret;
+      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_record_send() 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_record_send() failed with hard error");
+    MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_);   /* hard error */
+    return -1;
   }
 #endif /* HTTPS_SUPPORT */
   testErrorLogDesc ("HTTPS socket send called, but code does not support" \
@@ -515,46 +809,106 @@ wr_send (struct wr_socket *s,
 }
 
 
+/**
+ * Send data to remote by socket.
+ * @param s the socket to use
+ * @param buf the buffer with data to send
+ * @param len the length of data in @a buf
+ * @return number of bytes were sent if succeed,
+ *         -1 if failed. Use #MHD_socket_get_error_()
+ *         to get socket error.
+ */
+static ssize_t
+wr_send (struct wr_socket *s,
+         const void *buf,
+         size_t len)
+{
+  return wr_send_tmo (s, buf, len, test_timeout * 1000);
+}
+
+
 /**
  * Receive data from remote by socket.
  * @param s the socket to use
  * @param buf the buffer to store received data
  * @param len the length of @a buf
+ * @param timeout_ms the maximum wait time in milliseconds to receive the data,
+ *                   no limit if negative value is used
  * @return number of bytes were received if succeed,
  *         -1 if failed. Use #MHD_socket_get_error_()
  *         to get socket error.
  */
 static ssize_t
-wr_recv (struct wr_socket *s,
-         void *buf,
-         size_t len)
+wr_recv_tmo (struct wr_socket *s,
+             void *buf,
+             size_t len,
+             int timeout_ms)
 {
   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);
+  }
 #ifdef HTTPS_SUPPORT
   if (wr_tls == s->t)
   {
     ssize_t ret;
-    if (! s->tls_connected && ! wr_handshake (s))
+    if (! s->tls_connected && ! wr_handshake_tmo_ (s, timeout_ms))
       return -1;
 
-    ret = gnutls_record_recv (s->tls_s, buf, len);
-    if (ret > 0)
-      return ret;
-    if (GNUTLS_E_AGAIN == ret)
-      MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
-    else
+    while (1)
     {
-      testErrorLogDesc ("gnutls_record_recv() failed with hard error");
-      MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_);   /* hard error */
-      return -1;
+      ret = gnutls_record_recv (s->tls_s, buf, len);
+      if (ret >= 0)
+        return ret;
+      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_record_recv() 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_record_recv() failed with hard error");
+    MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_);   /* hard error */
+    return -1;
   }
 #endif /* HTTPS_SUPPORT */
   return -1;
 }
 
 
+/**
+ * Receive data from remote by socket.
+ * @param s the socket to use
+ * @param buf the buffer to store received data
+ * @param len the length of @a buf
+ * @return number of bytes were received if succeed,
+ *         -1 if failed. Use #MHD_socket_get_error_()
+ *         to get socket error.
+ */
+static ssize_t
+wr_recv (struct wr_socket *s,
+         void *buf,
+         size_t len)
+{
+  return wr_recv_tmo (s, buf, len, test_timeout * 1000);
+}
+
+
 /**
  * Close socket and release allocated resourced
  * @param s the socket to close
@@ -592,9 +946,14 @@ static struct wr_socket *volatile usock;
 static pthread_t pt_client;
 
 /**
- * Flag set to 1 once the test is finished.
+ * Flag set to true once the client is finished.
+ */
+static volatile bool client_done;
+
+/**
+ * Flag set to true once the app is finished.
  */
-static volatile bool done;
+static volatile bool app_done;
 
 
 static const char *
@@ -741,47 +1100,21 @@ notify_connection_cb (void *cls,
 }
 
 
-/**
- * Change socket to blocking.
- *
- * @param fd the socket to manipulate
- */
-static void
-make_blocking (MHD_socket fd)
-{
-#if defined(MHD_POSIX_SOCKETS)
-  int flags;
-
-  flags = fcntl (fd, F_GETFL);
-  if (-1 == flags)
-    externalErrorExitDesc ("fcntl() failed");
-  if ((flags & ~O_NONBLOCK) != flags)
-    if (-1 == fcntl (fd, F_SETFL, flags & ~O_NONBLOCK))
-      externalErrorExitDesc ("fcntl() failed");
-#elif defined(MHD_WINSOCK_SOCKETS)
-  unsigned long flags = 0;
-
-  if (0 != ioctlsocket (fd, (int) FIONBIO, &flags))
-    externalErrorExitDesc ("ioctlsocket() failed");
-#endif /* MHD_WINSOCK_SOCKETS */
-
-}
-
-
 static void
 send_all (struct wr_socket *sock,
-          const char *text)
+          const void *data,
+          size_t data_size)
 {
-  size_t len = strlen (text);
   ssize_t ret;
-  size_t off;
+  size_t sent;
+  const uint8_t *const buf = (const uint8_t *) data;
 
-  make_blocking (wr_fd (sock));
-  for (off = 0; off < len; off += (size_t) ret)
+  wr_make_nonblocking (sock);
+  for (sent = 0; sent < data_size; sent += (size_t) ret)
   {
     ret = wr_send (sock,
-                   &text[off],
-                   len - off);
+                   buf + sent,
+                   data_size - sent);
     if (0 > ret)
     {
       if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()) ||
@@ -796,6 +1129,9 @@ send_all (struct wr_socket *sock,
 }
 
 
+#define send_all_stext(sk,st) send_all(sk,st,MHD_STATICSTR_LEN_(st))
+
+
 /**
  * Read character-by-character until we
  * get 'CRLNCRLN'.
@@ -808,7 +1144,7 @@ recv_hdr (struct wr_socket *sock)
   char c;
   ssize_t ret;
 
-  make_blocking (wr_fd (sock));
+  wr_make_nonblocking (sock);
   next = '\r';
   i = 0;
   while (i < 4)
@@ -849,19 +1185,23 @@ recv_hdr (struct wr_socket *sock)
 
 static void
 recv_all (struct wr_socket *sock,
-          const char *text)
+          const void *data,
+          size_t data_size)
 {
-  size_t len = strlen (text);
-  char buf[len];
+  uint8_t *buf;
   ssize_t ret;
-  size_t off;
+  size_t rcvd;
 
-  make_blocking (wr_fd (sock));
-  for (off = 0; off < len; off += (size_t) ret)
+  buf = (uint8_t *) malloc (data_size);
+  if (NULL == buf)
+    externalErrorExitDesc ("malloc() failed");
+
+  wr_make_nonblocking (sock);
+  for (rcvd = 0; rcvd < data_size; rcvd += (size_t) ret)
   {
     ret = wr_recv (sock,
-                   &buf[off],
-                   len - off);
+                   buf + rcvd,
+                   data_size - rcvd);
     if (0 > ret)
     {
       if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()) ||
@@ -872,18 +1212,40 @@ recv_all (struct wr_socket *sock,
       }
       externalErrorExitDesc ("recv() failed");
     }
-    if (0 == ret)
+    else if (0 == ret)
+    {
+      fprintf (stderr, "Partial only received text. Expected: '%.*s' "
+               "(length: %ud). Got: '%.*s' (length: %ud). ",
+               (int) data_size, (const char *) data, (unsigned int) data_size,
+               (int) rcvd, (const char *) buf, (unsigned int) rcvd);
       mhdErrorExitDesc ("The server unexpectedly closed connection");
+    }
+    if ((data_size - rcvd) < (size_t) ret)
+      externalErrorExitDesc ("recv() returned excessive amount of data");
+    if (0 != memcmp (data, buf, rcvd + (size_t) ret))
+    {
+      fprintf (stderr, "Wrong received text. Expected: '%.*s'. "
+               "Got: '%.*s'. ",
+               (int) (rcvd + (size_t) ret), (const char *) data,
+               (int) (rcvd + (size_t) ret), (const char *) buf);
+      mhdErrorExit ();
+    }
   }
-  if (0 != strncmp (text, buf, len))
+  if (0 != memcmp (data, buf, data_size))
   {
-    fprintf (stderr, "Wrong received text. Expected: '%s' ."
-             "Got: '%.*s'. ", text, (int) len, buf);
+    fprintf (stderr, "Wrong received text. Expected: '%.*s'. "
+             "Got: '%.*s'. ",
+             (int) data_size, (const char *) data,
+             (int) data_size, (const char *) buf);
     mhdErrorExit ();
   }
+  free (buf);
 }
 
 
+#define recv_all_stext(sk,st) recv_all(sk,st,MHD_STATICSTR_LEN_(st))
+
+
 /**
  * Main function for the thread that runs the interaction with
  * the upgraded socket.
@@ -895,16 +1257,17 @@ run_usock (void *cls)
 {
   struct MHD_UpgradeResponseHandle *urh = cls;
 
-  send_all (usock,
-            "Hello");
-  recv_all (usock,
-            "World");
-  send_all (usock,
-            "Finished");
+  send_all_stext (usock,
+                  "Hello");
+  recv_all_stext (usock,
+                  "World");
+  send_all_stext (usock,
+                  "Finished");
   MHD_upgrade_action (urh,
                       MHD_UPGRADE_ACTION_CLOSE);
   free (usock);
   usock = NULL;
+  app_done = true;
   return NULL;
 }
 
@@ -920,17 +1283,17 @@ run_usock_client (void *cls)
 {
   struct wr_socket *sock = cls;
 
-  send_all (sock,
-            "GET / HTTP/1.1\r\nHost: localhost\r\nConnection: 
Upgrade\r\n\r\n");
+  send_all_stext (sock,
+                  "GET / HTTP/1.1\r\nHost: localhost\r\nConnection: 
Upgrade\r\n\r\n");
   recv_hdr (sock);
-  recv_all (sock,
-            "Hello");
-  send_all (sock,
-            "World");
-  recv_all (sock,
-            "Finished");
+  recv_all_stext (sock,
+                  "Hello");
+  send_all_stext (sock,
+                  "World");
+  recv_all_stext (sock,
+                  "Finished");
   wr_close (sock);
-  done = true;
+  client_done = true;
   return NULL;
 }
 
@@ -994,6 +1357,7 @@ upgrade_cb (void *cls,
   (void) extra_in; /* Unused. Silent compiler warning. */
 
   usock = wr_create_from_plain_sckt (sock);
+  wr_make_nonblocking (usock);
   if (0 != extra_in_size)
     mhdErrorExitDesc ("'extra_in_size' is not zero");
   if (0 != pthread_create (&pt,
@@ -1085,27 +1449,75 @@ ahc_upgrade (void *cls,
 
 
 /**
- * Run the MHD external event loop using select.
+ * Run the MHD external event loop using select or epoll.
+ *
+ * select/epoll modes are used automatically based on daemon's flags.
  *
  * @param daemon daemon to run it for
  */
 static void
 run_mhd_select_loop (struct MHD_Daemon *daemon)
 {
-  fd_set rs;
-  fd_set ws;
-  fd_set es;
-  MHD_socket max_fd;
-  uint64_t to64;
-  struct timeval tv;
-
-  while (! done)
+  const time_t start_time = time (NULL);
+  const union MHD_DaemonInfo *pdinfo;
+  bool connection_was_accepted;
+  bool connection_has_finished;
+#ifdef EPOLL_SUPPORT
+  bool use_epoll = false;
+  int ep = -1;
+
+  pdinfo = MHD_get_daemon_info (daemon,
+                                MHD_DAEMON_INFO_FLAGS);
+  if (NULL == pdinfo)
+    mhdErrorExitDesc ("MHD_get_daemon_info() failed");
+  else
+    use_epoll = (0 != (pdinfo->flags & MHD_USE_EPOLL));
+  if (use_epoll)
+  {
+    pdinfo = MHD_get_daemon_info (daemon,
+                                  MHD_DAEMON_INFO_EPOLL_FD);
+    if (NULL == pdinfo)
+      mhdErrorExitDesc ("MHD_get_daemon_info() failed");
+    ep = pdinfo->listen_fd;
+    if (0 > ep)
+      mhdErrorExitDesc ("Invalid epoll FD value");
+  }
+#endif /* EPOLL_SUPPORT */
+
+  connection_was_accepted = false;
+  connection_has_finished = false;
+  while (1)
   {
+    fd_set rs;
+    fd_set ws;
+    fd_set es;
+    MHD_socket max_fd;
+    struct timeval tv;
+    uint64_t to64;
+    bool has_mhd_timeout;
+
     FD_ZERO (&rs);
     FD_ZERO (&ws);
     FD_ZERO (&es);
     max_fd = MHD_INVALID_SOCKET;
-    to64 = 1000;
+
+    if (time (NULL) - start_time > ((time_t) test_timeout))
+      mhdErrorExitDesc ("Test timeout");
+
+    pdinfo = MHD_get_daemon_info (daemon, MHD_DAEMON_INFO_CURRENT_CONNECTIONS);
+
+    if (NULL == pdinfo)
+      mhdErrorExitDesc ("MHD_get_daemon_info() failed");
+
+    if (0 != pdinfo->num_connections)
+      connection_was_accepted = true;
+    else
+    {
+      if (connection_was_accepted)
+        connection_has_finished = true;
+    }
+    if (connection_has_finished)
+      return;
 
     if (MHD_YES !=
         MHD_get_fdset (daemon,
@@ -1114,31 +1526,63 @@ run_mhd_select_loop (struct MHD_Daemon *daemon)
                        &es,
                        &max_fd))
       mhdErrorExitDesc ("MHD_get_fdset() failed");
-    (void) MHD_get_timeout64 (daemon,
-                              &to64);
-    if (1000 < to64)
-      to64 = 1000;
+
+#ifdef EPOLL_SUPPORT
+    if (use_epoll)
+    {
+      if (ep != max_fd)
+        mhdErrorExitDesc ("Wrong 'max_fd' value");
+      if (! FD_ISSET (ep, &rs))
+        mhdErrorExitDesc ("Epoll FD is NOT set in read fd_set");
+    }
+#endif /* EPOLL_SUPPORT */
+
+    has_mhd_timeout = (MHD_NO != MHD_get_timeout64 (daemon,
+                                                    &to64));
+    if (has_mhd_timeout)
+    {
 #if ! defined(_WIN32) || defined(__CYGWIN__)
-    tv.tv_sec = (time_t) (to64 / 1000);
+      tv.tv_sec = (time_t) (to64 / 1000);
 #else  /* Native W32 */
-    tv.tv_sec = (long) (to64 / 1000);
+      tv.tv_sec = (long) (to64 / 1000);
 #endif /* Native W32 */
-    tv.tv_usec = (long) (1000 * (to64 % 1000));
-    if (0 > MHD_SYS_select_ (max_fd + 1,
-                             &rs,
-                             &ws,
-                             &es,
-                             &tv))
+      tv.tv_usec = (long) (1000 * (to64 % 1000));
+    }
+    else
     {
-#ifdef MHD_POSIX_SOCKETS
-      if (EINTR != errno)
-        externalErrorExitDesc ("Unexpected select() error");
-#else
-      if ((WSAEINVAL != WSAGetLastError ()) ||
-          (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) )
-        externalErrorExitDesc ("Unexpected select() error");
+#if ! defined(_WIN32) || defined(__CYGWIN__)
+      tv.tv_sec = (time_t) test_timeout;
+#else  /* Native W32 */
+      tv.tv_sec = (long) test_timeout;
+#endif /* Native W32 */
+      tv.tv_usec = 0;
+    }
+
+#ifdef MHD_WINSOCK_SOCKETS
+    if ((0 == rs.fd_count) && (0 == ws.fd_count) && (0 != es.fd_count))
       Sleep ((DWORD) (tv.tv_sec * 1000 + tv.tv_usec / 1000));
+    else /* Combined with the next 'if' */
 #endif
+    if (1)
+    {
+      int sel_res;
+      sel_res = MHD_SYS_select_ (max_fd + 1,
+                                 &rs,
+                                 &ws,
+                                 &es,
+                                 &tv);
+      if (0 == sel_res)
+      {
+        if (! has_mhd_timeout)
+          mhdErrorExitDesc ("Timeout waiting for data on sockets");
+      }
+      else if (0 > sel_res)
+      {
+#ifdef MHD_POSIX_SOCKETS
+        if (EINTR != errno)
+#endif /* MHD_POSIX_SOCKETS */
+        mhdErrorExitDesc ("Unexpected select() error");
+      }
     }
     MHD_run_from_select (daemon,
                          &rs,
@@ -1166,67 +1610,6 @@ run_mhd_poll_loop (struct MHD_Daemon *daemon)
 #endif /* HAVE_POLL */
 
 
-#ifdef EPOLL_SUPPORT
-/**
- * Run the MHD external event loop using select.
- *
- * @param daemon daemon to run it for
- */
-static void
-run_mhd_epoll_loop (struct MHD_Daemon *daemon)
-{
-  const union MHD_DaemonInfo *di;
-  MHD_socket ep;
-  fd_set rs;
-  uint64_t to64;
-  struct timeval tv;
-  int ret;
-
-  di = MHD_get_daemon_info (daemon,
-                            MHD_DAEMON_INFO_EPOLL_FD);
-  if (NULL == di)
-    mhdErrorExitDesc ("MHD_get_daemon_info() failed");
-  ep = di->listen_fd;
-  while (! done)
-  {
-    FD_ZERO (&rs);
-    to64 = 1000;
-
-    FD_SET (ep, &rs);
-    (void) MHD_get_timeout64 (daemon,
-                              &to64);
-    if (1000 < to64)
-      to64 = 1000;
-#if ! defined(_WIN32) || defined(__CYGWIN__)
-    tv.tv_sec = (time_t) (to64 / 1000);
-#else  /* Native W32 */
-    tv.tv_sec = (long) (to64 / 1000);
-#endif /* Native W32 */
-    tv.tv_usec = (int) (1000 * (to64 % 1000));
-    ret = select (ep + 1,
-                  &rs,
-                  NULL,
-                  NULL,
-                  &tv);
-    if (0 > ret)
-    {
-#ifdef MHD_POSIX_SOCKETS
-      if (EINTR != errno)
-        externalErrorExitDesc ("Unexpected select() error");
-#else
-      if ((WSAEINVAL != WSAGetLastError ()) ||
-          (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) )
-        externalErrorExitDesc ("Unexpected select() error");
-      Sleep ((DWORD) (tv.tv_sec * 1000 + tv.tv_usec / 1000));
-#endif
-    }
-    MHD_run (daemon);
-  }
-}
-
-
-#endif /* EPOLL_SUPPORT */
-
 /**
  * Run the MHD external event loop using select.
  *
@@ -1244,7 +1627,7 @@ run_mhd_loop (struct MHD_Daemon *daemon,
 #endif /* HAVE_POLL */
 #ifdef EPOLL_SUPPORT
   else if (0 != (flags & MHD_USE_EPOLL))
-    run_mhd_epoll_loop (daemon);
+    run_mhd_select_loop (daemon);
 #endif
   else
     externalErrorExitDesc ("Wrong 'flags' value");
@@ -1272,7 +1655,8 @@ test_upgrade (unsigned int flags,
   pid_t pid = -1;
 #endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */
 
-  done = false;
+  client_done = false;
+  app_done = false;
 
   if (! test_tls)
     d = MHD_start_daemon (flags | MHD_USE_ERROR_LOG | MHD_ALLOW_UPGRADE
@@ -1286,6 +1670,7 @@ test_upgrade (unsigned int flags,
                           MHD_OPTION_NOTIFY_CONNECTION, &notify_connection_cb,
                           NULL,
                           MHD_OPTION_THREAD_POOL_SIZE, pool,
+                          MHD_OPTION_CONNECTION_TIMEOUT, test_timeout,
                           MHD_OPTION_END);
 #ifdef HTTPS_SUPPORT
   else
@@ -1302,6 +1687,7 @@ test_upgrade (unsigned int flags,
                           MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
                           MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
                           MHD_OPTION_THREAD_POOL_SIZE, pool,
+                          MHD_OPTION_CONNECTION_TIMEOUT, test_timeout,
                           MHD_OPTION_END);
 #endif /* HTTPS_SUPPORT */
   if (NULL == d)
@@ -1322,6 +1708,7 @@ test_upgrade (unsigned int flags,
     sock = test_tls ? wr_create_tls_sckt () : wr_create_plain_sckt ();
     if (NULL == sock)
       externalErrorExitDesc ("Create socket failed");
+    wr_make_nonblocking (sock);
     sa.sin_family = AF_INET;
     sa.sin_port = htons (dinfo->port);
     sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
@@ -1344,6 +1731,8 @@ test_upgrade (unsigned int flags,
     sock =  wr_create_from_plain_sckt (tls_fork_sock);
     if (NULL == sock)
       externalErrorExitDesc ("wr_create_from_plain_sckt() failed");
+
+    wr_make_nonblocking (sock);
 #else  /* !HTTPS_SUPPORT || !HAVE_FORK || !HAVE_WAITPID */
     externalErrorExitDesc ("Unsupported 'use_tls_tool' value");
 #endif /* !HTTPS_SUPPORT || !HAVE_FORK || !HAVE_WAITPID */
@@ -1369,6 +1758,12 @@ test_upgrade (unsigned int flags,
       externalErrorExitDesc ("waitpid() failed");
   }
 #endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */
+  if (! client_done)
+    externalErrorExitDesc ("The client thread has not signalled " \
+                           "successful finish");
+  if (! app_done)
+    externalErrorExitDesc ("The application thread has not signalled " \
+                           "successful finish");
   MHD_stop_daemon (d);
   return 0;
 }
@@ -1389,6 +1784,15 @@ main (int argc,
                has_param (argc, argv, "-s") ||
                has_param (argc, argv, "--silent"));
 
+  if ((((int) ((~((unsigned int) 0U)) >> 1)) / 1000) < test_timeout)
+  {
+    fprintf (stderr, "The test timeout value (%d) is too large.\n"
+             "The test cannot run.\n", test_timeout);
+    fprintf (stderr, "The maximum allowed timeout value is %d.\n",
+             (((int) ((~((unsigned int) 0U)) >> 1)) / 1000));
+    return 3;
+  }
+
   if (test_tls)
   {
     use_tls_tool = TLS_LIB_GNUTLS;   /* Should be always available as MHD uses 
it. */
diff --git a/src/microhttpd/test_upgrade_large.c 
b/src/microhttpd/test_upgrade_large.c
index 9a99c6d4..e7f842d1 100644
--- a/src/microhttpd/test_upgrade_large.c
+++ b/src/microhttpd/test_upgrade_large.c
@@ -629,6 +629,13 @@ wr_handshake (struct wr_socket *s)
     MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
   else
   {
+    fprintf (stderr, "The error returned by gnutls_handshake() is "
+             "'%s' ", gnutls_strerror ((int) res));
+#if GNUTLS_VERSION_NUMBER >= 0x020600
+    fprintf (stderr, "(%s)\n", gnutls_strerror_name ((int) res));
+#else  /* GNUTLS_VERSION_NUMBER < 0x020600 */
+    fprintf (stderr, "(%d)\n", (int) res);
+#endif /* GNUTLS_VERSION_NUMBER < 0x020600 */
     testErrorLogDesc ("gnutls_handshake() failed with hard error");
     MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */
   }
@@ -671,6 +678,13 @@ wr_send (struct wr_socket *s,
       MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
     else
     {
+      fprintf (stderr, "The error returned by gnutls_record_send() 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_record_send() failed with hard error");
       MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_);  /* hard error */
       return -1;
@@ -707,12 +721,19 @@ wr_recv (struct wr_socket *s,
       return -1;
 
     ret = gnutls_record_recv (s->tls_s, buf, len);
-    if (ret > 0)
+    if (ret >= 0)
       return ret;
     if (GNUTLS_E_AGAIN == ret)
       MHD_socket_set_error_ (MHD_SCKT_EAGAIN_);
     else
     {
+      fprintf (stderr, "The error returned by gnutls_record_recv() 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_record_recv() failed with hard error");
       MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_);  /* hard error */
       return -1;
@@ -1050,7 +1071,11 @@ recv_all (struct wr_socket *sock,
       externalErrorExitDesc ("recv() failed");
     }
     if (0 == ret)
+    {
+      fprintf (stderr, "Partial only received text. Expected: '%s' ."
+               "Got: '%.*s'. ", text, (int) (off + (size_t) ret), buf);
       mhdErrorExitDesc ("The server unexpectedly closed connection");
+    }
     if (0 != strncmp (text, buf, off + (size_t) ret))
     {
       fprintf (stderr, "Wrong received text. Expected: '%s' ."

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