gnunet-svn
[Top][All Lists]
Advanced

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

[libmicrohttpd] branch master updated: Fixed: avoided SIGPIPE if possiib


From: gnunet
Subject: [libmicrohttpd] branch master updated: Fixed: avoided SIGPIPE if possiible
Date: Mon, 21 Dec 2020 11:29:17 +0100

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

karlson2k pushed a commit to branch master
in repository libmicrohttpd.

The following commit(s) were added to refs/heads/master by this push:
     new 7c735289 Fixed: avoided SIGPIPE if possiible
7c735289 is described below

commit 7c735289338a3cd9bfd7afa4131153a9d113b7ea
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
AuthorDate: Mon Dec 21 13:28:32 2020 +0300

    Fixed: avoided SIGPIPE if possiible
    
    Added blocking of SIGPIPE on daemon threads.
    Added tracking of SIGPIPE suppressions on sockets.
    Added fallback to normal send() instead of sendfile() and writev() if
    SIGPIPE is not blocked.
---
 configure.ac                 |  22 ++++++-
 src/microhttpd/connection.c  |   6 +-
 src/microhttpd/daemon.c      | 144 +++++++++++++++++++++++++++++++++++--------
 src/microhttpd/internal.h    |  10 +++
 src/microhttpd/mhd_send.c    |  16 +++--
 src/microhttpd/mhd_sockets.h |  18 +++++-
 6 files changed, 182 insertions(+), 34 deletions(-)

diff --git a/configure.ac b/configure.ac
index 456650c5..2011dc30 100644
--- a/configure.ac
+++ b/configure.ac
@@ -556,11 +556,30 @@ AS_CASE([[$with_threads]],
 )
 
 # Check for posix threads support, regardless of configure parameters as
-# testsuite use only posix threads.
+# testsuite uses only posix threads.
 AX_PTHREAD(
   [
     mhd_have_posix_threads='yes'
     AC_DEFINE([[HAVE_PTHREAD_H]],[[1]],[Define to 1 if you have the 
<pthread.h> header file.])
+       AC_CACHE_CHECK([[whether pthread_sigmask(3) is available]],
+         [[mhd_cv_func_pthread_sigmask]], [dnl
+         save_LIBS="$LIBS"
+         save_CFLAGS="$CFLAGS"
+         LIBS="$PTHREAD_LIBS $LIBS"
+         CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+         AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <signal.h>]],
+           [[
+             sigset_t nset, oset;
+             sigemptyset (&nset);
+             sigaddset (&nset, SIGPIPE);
+             if (0 != pthread_sigmask(SIG_BLOCK, &nset, &oset)) return 1;
+           ]])],
+           
[[mhd_cv_func_pthread_sigmask="yes"]],[[mhd_cv_func_pthread_sigmask="no"]])
+         LIBS="${save_LIBS}"
+         CFLAGS="${save_CFLAGS}"
+       ])
+       AS_VAR_IF([mhd_cv_func_pthread_sigmask],["yes"],
+         [AC_DEFINE([[HAVE_PTHREAD_SIGMASK]],[[1]],[Define to 1 if you have 
the pthread_sigmask(3) function.])])
   ],[[mhd_have_posix_threads='no']])
 AM_CONDITIONAL([HAVE_POSIX_THREADS],[test "x$mhd_have_posix_threads" = "xyes"])
 
@@ -966,6 +985,7 @@ AC_CHECK_HEADERS_ONCE([fcntl.h math.h errno.h limits.h 
stdio.h locale.h sys/stat
 AC_CHECK_HEADERS([sys/types.h sys/time.h sys/msg.h time.h sys/mman.h 
sys/ioctl.h \
   sys/socket.h sys/select.h netdb.h netinet/in.h netinet/ip.h netinet/tcp.h 
arpa/inet.h \
   endian.h machine/endian.h sys/endian.h sys/param.h sys/machine.h 
sys/byteorder.h machine/param.h sys/isa_defs.h \
+  signal.h \
   inttypes.h stddef.h unistd.h \
   sockLib.h inetLib.h net/if.h], [], [], [AC_INCLUDES_DEFAULT])
 
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index 65431f96..7562ba52 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -3964,7 +3964,11 @@ MHD_queue_response (struct MHD_Connection *connection,
 #if defined(_MHD_HAVE_SENDFILE)
   if ( (response->fd == -1) ||
        (response->is_pipe) ||
-       (0 != (connection->daemon->options & MHD_USE_TLS)) )
+       (0 != (connection->daemon->options & MHD_USE_TLS))
+#if ! defined(MHD_WINSOCK_SOCKETS) && defined(HAVE_SEND_SIGPIPE_SUPPRESS)
+       || (! daemon->sigpipe_blocked && ! connection->sk_spipe_suppress)
+#endif /* ! MHD_WINSOCK_SOCKETS && ! HAVE_SEND_SIGPIPE_SUPPRESS */
+       )
     connection->resp_sender = MHD_resp_sender_std;
   else
     connection->resp_sender = MHD_resp_sender_sendfile;
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c
index 81c9d22d..e308eec4 100644
--- a/src/microhttpd/daemon.c
+++ b/src/microhttpd/daemon.c
@@ -64,6 +64,12 @@
 #include <windows.h>
 #endif
 
+#ifdef MHD_USE_POSIX_THREADS
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif /* HAVE_SIGNAL_H */
+#endif /* MHD_USE_POSIX_THREADS */
+
 /**
  * Default connection limit.
  */
@@ -2359,6 +2365,8 @@ psk_gnutls_adapter (gnutls_session_t session,
  * @param addrlen number of bytes in @a addr
  * @param external_add indicate that socket has been added externally
  * @param non_blck indicate that socket in non-blocking mode
+ * @param sk_spipe_supprs indicate that the @a client_socket has
+ *                         set SIGPIPE suppression
  * @return pointer to the connection on success, NULL if this daemon could
  *        not handle the connection (i.e. malloc failed, etc).
  *        The socket will be closed in case of error; 'errno' is
@@ -2370,30 +2378,12 @@ new_connection_prepare_ (struct MHD_Daemon *daemon,
                          const struct sockaddr *addr,
                          socklen_t addrlen,
                          bool external_add,
-                         bool non_blck)
+                         bool non_blck,
+                         bool sk_spipe_supprs)
 {
   struct MHD_Connection *connection;
   int eno = 0;
 
-#ifdef MHD_socket_nosignal_
-  if (! MHD_socket_nosignal_ (client_socket))
-  {
-#ifdef HAVE_MESSAGES
-    MHD_DLOG (daemon,
-              _ ("Failed to set SO_NOSIGPIPE on accepted socket: %s\n"),
-              MHD_socket_last_strerr_ ());
-#endif
-#ifndef MSG_NOSIGNAL
-    /* Cannot use socket as it can produce SIGPIPE. */
-#ifdef ENOTSOCK
-    errno = ENOTSOCK;
-#endif /* ENOTSOCK */
-    return NULL;
-#endif /* ! MSG_NOSIGNAL */
-  }
-#endif /* MHD_socket_nosignal_ */
-
-
 #ifdef HAVE_MESSAGES
 #if _MHD_DEBUG_CONNECT
   MHD_DLOG (daemon,
@@ -2491,6 +2481,7 @@ new_connection_prepare_ (struct MHD_Daemon *daemon,
   connection->addr_len = addrlen;
   connection->socket_fd = client_socket;
   connection->sk_nonblck = non_blck;
+  connection->sk_spipe_suppress = sk_spipe_supprs;
   connection->daemon = daemon;
   connection->last_activity = MHD_monotonic_sec_counter ();
 
@@ -2852,6 +2843,8 @@ cleanup:
  * @param external_add perform additional operations needed due
  *        to the application calling us directly
  * @param non_blck indicate that socket in non-blocking mode
+ * @param sk_spipe_supprs indicate that the @a client_socket has
+ *                         set SIGPIPE suppression
  * @return #MHD_YES on success, #MHD_NO if this daemon could
  *        not handle the connection (i.e. malloc failed, etc).
  *        The socket will be closed in any case; 'errno' is
@@ -2863,7 +2856,8 @@ internal_add_connection (struct MHD_Daemon *daemon,
                          const struct sockaddr *addr,
                          socklen_t addrlen,
                          bool external_add,
-                         bool non_blck)
+                         bool non_blck,
+                         bool sk_spipe_supprs)
 {
   struct MHD_Connection *connection;
 
@@ -2904,7 +2898,8 @@ internal_add_connection (struct MHD_Daemon *daemon,
   }
 
   connection = new_connection_prepare_ (daemon, client_socket, addr, addrlen,
-                                        external_add, non_blck);
+                                        external_add, non_blck,
+                                        sk_spipe_supprs);
   if (NULL == connection)
     return MHD_NO;
 
@@ -3327,6 +3322,7 @@ MHD_add_connection (struct MHD_Daemon *daemon,
                     socklen_t addrlen)
 {
   bool sk_nonbl;
+  bool sk_spipe_supprs;
 
   /* NOT thread safe with internal thread. TODO: fix thread safety. */
   if ((0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) &&
@@ -3357,6 +3353,38 @@ MHD_add_connection (struct MHD_Daemon *daemon,
   else
     sk_nonbl = true;
 
+#ifndef MHD_WINSOCK_SOCKETS
+  sk_spipe_supprs = false;
+#else  /* MHD_WINSOCK_SOCKETS */
+  sk_spipe_supprs = true; /* Nothing to suppress on W32 */
+#endif /* MHD_WINSOCK_SOCKETS */
+#if defined(MHD_socket_nosignal_)
+  if (! sk_spipe_supprs && ! MHD_socket_nosignal_ (s))
+  {
+#ifdef HAVE_MESSAGES
+    MHD_DLOG (daemon,
+              _ (
+                "Failed to suppress SIGPIPE on new client socket: %s\n"),
+              MHD_socket_last_strerr_ ());
+#else  /* ! HAVE_MESSAGES */
+    (void) 0; /* Mute compiler warning */
+#endif /* ! HAVE_MESSAGES */
+#ifndef MSG_NOSIGNAL
+    /* Application expects that SIGPIPE will be suppressed,
+     * but suppression failed and SIGPIPE cannot be suppressed with send(). */
+    if (! daemon->sigpipe_blocked)
+    {
+      int err = MHD_socket_get_error_ ();
+      MHD_socket_close_ (s);
+      MHD_socket_fset_error_ (err);
+      return MHD_NO;
+    }
+#endif /* MSG_NOSIGNAL */
+  }
+  else
+    sk_spipe_supprs = true;
+#endif /* MHD_socket_nosignal_ */
+
   if ( (0 != (daemon->options & MHD_USE_TURBO)) &&
        (! MHD_socket_noninheritable_ (client_socket)) )
   {
@@ -3383,7 +3411,8 @@ MHD_add_connection (struct MHD_Daemon *daemon,
                                         addr,
                                         addrlen,
                                         true,
-                                        sk_nonbl);
+                                        sk_nonbl,
+                                        sk_spipe_supprs);
     }
     /* all pools are at their connection limit, must refuse */
     MHD_socket_close_chk_ (client_socket);
@@ -3399,7 +3428,8 @@ MHD_add_connection (struct MHD_Daemon *daemon,
                                   addr,
                                   addrlen,
                                   true,
-                                  sk_nonbl);
+                                  sk_nonbl,
+                                  sk_spipe_supprs);
 }
 
 
@@ -3430,6 +3460,7 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
   MHD_socket s;
   MHD_socket fd;
   bool sk_nonbl;
+  bool sk_spipe_supprs;
 
   mhd_assert ( (0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) || \
                MHD_thread_ID_match_current_ (daemon->pid) );
@@ -3448,11 +3479,21 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
                SOCK_CLOEXEC_OR_ZERO | SOCK_NONBLOCK_OR_ZERO
                | SOCK_NOSIGPIPE_OR_ZERO);
   sk_nonbl = (SOCK_NONBLOCK_OR_ZERO != 0);
+#ifndef MHD_WINSOCK_SOCKETS
+  sk_spipe_supprs = (SOCK_NOSIGPIPE_OR_ZERO != 0);
+#else  /* MHD_WINSOCK_SOCKETS */
+  sk_spipe_supprs = true; /* Nothing to suppress on W32 */
+#endif /* MHD_WINSOCK_SOCKETS */
 #else  /* ! USE_ACCEPT4 */
   s = accept (fd,
               addr,
               &addrlen);
   sk_nonbl = false;
+#ifndef MHD_WINSOCK_SOCKETS
+  sk_spipe_supprs = false;
+#else  /* MHD_WINSOCK_SOCKETS */
+  sk_spipe_supprs = true; /* Nothing to suppress on W32 */
+#endif /* MHD_WINSOCK_SOCKETS */
 #endif /* ! USE_ACCEPT4 */
   if ( (MHD_INVALID_SOCKET == s) ||
        (addrlen <= 0) )
@@ -3531,6 +3572,30 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
 #endif
   }
 #endif /* !USE_ACCEPT4 || !SOCK_CLOEXEC */
+#if defined(MHD_socket_nosignal_)
+  if (! sk_spipe_supprs && ! MHD_socket_nosignal_ (s))
+  {
+#ifdef HAVE_MESSAGES
+    MHD_DLOG (daemon,
+              _ (
+                "Failed to suppress SIGPIPE on incoming connection socket: 
%s\n"),
+              MHD_socket_last_strerr_ ());
+#else  /* ! HAVE_MESSAGES */
+    (void) 0; /* Mute compiler warning */
+#endif /* ! HAVE_MESSAGES */
+#ifndef MSG_NOSIGNAL
+    /* Application expects that SIGPIPE will be suppressed,
+     * but suppression failed and SIGPIPE cannot be suppressed with send(). */
+    if (! daemon->sigpipe_blocked)
+    {
+      MHD_socket_close_ (s);
+      return MHD_NO;
+    }
+#endif /* MSG_NOSIGNAL */
+  }
+  else
+    sk_spipe_supprs = true;
+#endif /* MHD_socket_nosignal_ */
 #ifdef HAVE_MESSAGES
 #if _MHD_DEBUG_CONNECT
   MHD_DLOG (daemon,
@@ -3543,7 +3608,8 @@ MHD_accept_connection (struct MHD_Daemon *daemon)
                                   addr,
                                   addrlen,
                                   false,
-                                  sk_nonbl);
+                                  sk_nonbl,
+                                  sk_spipe_supprs);
   return MHD_YES;
 }
 
@@ -5022,8 +5088,29 @@ static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
 MHD_polling_thread (void *cls)
 {
   struct MHD_Daemon *daemon = cls;
+#ifdef HAVE_PTHREAD_SIGMASK
+  sigset_t s_mask;
+  int err;
+#endif /* HAVE_PTHREAD_SIGMASK */
 
   MHD_thread_init_ (&(daemon->pid));
+#ifdef HAVE_PTHREAD_SIGMASK
+  if ((0 == sigemptyset (&s_mask)) &&
+      (0 == sigaddset (&s_mask, SIGPIPE)))
+  {
+    err = pthread_sigmask (SIG_BLOCK, &s_mask, NULL);
+  }
+  else
+    err = errno;
+  if (0 == err)
+    daemon->sigpipe_blocked = true;
+#ifdef HAVE_MESSAGES
+  else
+    MHD_DLOG (daemon,
+              _ ("Failed to block SIGPIPE on daemon thread: %s\n"),
+              MHD_strerror_ (errno));
+#endif /* HAVE_MESSAGES */
+#endif /* HAVE_PTHREAD_SIGMASK */
   while (! daemon->shutdown)
   {
     if (0 != (daemon->options & MHD_USE_POLL))
@@ -6116,6 +6203,13 @@ MHD_start_daemon_va (unsigned int flags,
   daemon->custom_error_log = &MHD_default_logger_;
   daemon->custom_error_log_cls = stderr;
 #endif
+#ifndef MHD_WINSOCK_SOCKETS
+  daemon->sigpipe_blocked = false;
+#else  /* MHD_WINSOCK_SOCKETS */
+  /* There is no SIGPIPE on W32, nothing to block. */
+  daemon->sigpipe_blocked = true;
+#endif /* _WIN32 && ! __CYGWIN__ */
+
   if ( (0 != (*pflags & MHD_USE_THREAD_PER_CONNECTION)) &&
        (0 == (*pflags & MHD_USE_INTERNAL_POLLING_THREAD)) )
   {
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h
index a92f46f2..1c2496d8 100644
--- a/src/microhttpd/internal.h
+++ b/src/microhttpd/internal.h
@@ -928,6 +928,11 @@ struct MHD_Connection
    */
   bool sk_nonblck;
 
+  /**
+   * true if connection socket has set SIGPIPE suppression
+   */
+  bool sk_spipe_suppress;
+
   /**
    * Tracks TCP_CORK / TCP_NOPUSH of the connection socket.
    */
@@ -1697,6 +1702,11 @@ struct MHD_Daemon
    */
   int strict_for_client;
 
+  /**
+   * True if SIGPIPE is blocked
+   */
+  bool sigpipe_blocked;
+
 #ifdef HTTPS_SUPPORT
 #ifdef UPGRADE_SUPPORT
   /**
diff --git a/src/microhttpd/mhd_send.c b/src/microhttpd/mhd_send.c
index 38a8a499..d7129337 100644
--- a/src/microhttpd/mhd_send.c
+++ b/src/microhttpd/mhd_send.c
@@ -815,11 +815,19 @@ MHD_send_hdr_and_body_ (struct MHD_Connection *connection,
   uint32_t vec_sent;
   int err;
 #endif /* _WIN32 */
+  bool no_vec; /* Is vector-send() disallowed? */
+
+  no_vec = false;
 #ifdef HTTPS_SUPPORT
-  const bool no_vec = (connection->daemon->options & MHD_USE_TLS);
-#else  /* ! HTTPS_SUPPORT */
-  const bool no_vec = false;
-#endif /* ! HTTPS_SUPPORT */
+  no_vec = no_vec || (connection->daemon->options & MHD_USE_TLS);
+#endif /* HTTPS_SUPPORT */
+#if ! defined(MHD_WINSOCK_SOCKETS) && \
+  (! defined(HAVE_SENDMSG) || ! defined(MSG_NOSIGNAL)) && \
+  defined(HAVE_SEND_SIGPIPE_SUPPRESS)
+  no_vec = no_vec || (! connection->daemon->sigpipe_blocked &&
+                      ! connection->sk_spipe_suppress);
+#endif /* !MHD_WINSOCK_SOCKETS && (!HAVE_SENDMSG || ! MSG_NOSIGNAL)
+          && !HAVE_SEND_SIGPIPE_SUPPRESS */
 #endif /* _MHD_USE_SEND_VEC */
 
   mhd_assert ( (NULL != body) || (0 == body_size) );
diff --git a/src/microhttpd/mhd_sockets.h b/src/microhttpd/mhd_sockets.h
index e8cabc19..fbdb2f11 100644
--- a/src/microhttpd/mhd_sockets.h
+++ b/src/microhttpd/mhd_sockets.h
@@ -924,9 +924,20 @@ static const int _MHD_socket_int_one = 1;
 #define MHD_socket_nosignal_(sock) \
   (! setsockopt ((sock),SOL_SOCKET,SO_NOSIGPIPE,&_MHD_socket_int_one, \
                  sizeof(_MHD_socket_int_one)))
-#elif defined(MHD_POSIX_SOCKETS) && defined(SOCK_NOSIGPIPE) && \
-  defined(SOCK_CLOEXEC)
-#endif
+#endif /* SOL_SOCKET && SO_NOSIGPIPE */
+
+
+#if defined(MHD_WINSOCK_SOCKETS) || defined(MHD_socket_nosignal_) || \
+  defined(MSG_NOSIGNAL)
+/**
+ * Indicate that SIGPIPE can be suppressed for normal send() by flags
+ * or socket options.
+ * If this macro is undefined, MHD cannot suppress SIGPIPE for normal
+ * processing so sendfile() or writev() calls is not avoided.
+ */
+#define HAVE_SEND_SIGPIPE_SUPPRESS      1
+#endif /* MHD_WINSOCK_SOCKETS || MHD_socket_nosignal_ || MSG_NOSIGNAL */
+
 
 /**
  * Create a listen socket, with noninheritable flag if possible.
@@ -937,4 +948,5 @@ static const int _MHD_socket_int_one = 1;
 MHD_socket
 MHD_socket_create_listen_ (int pf);
 
+
 #endif /* ! MHD_SOCKETS_H */

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