]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
socket: check result of SO_NOSIGPIPE
authorStefan Eissing <stefan@eissing.org>
Tue, 20 Jan 2026 10:09:58 +0000 (11:09 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 20 Jan 2026 15:38:49 +0000 (16:38 +0100)
New define USE_SO_NOSIGPIPE in curl_setup.h, for now set whenever
SO_NOSIGPIPE is defined. Maybe overridden in the future on systems where
this does not work.

With USE_SO_NOSIGPIPE defined, set SO_NOSIGPIPE on all sockets created
by libcurl and fail the creation when setsockopt() fails.

Closes #20370

docs/libcurl/libcurl-env-dbg.md
lib/cf-socket.c
lib/curl_setup.h
lib/sigpipe.h
src/tool_main.c

index ce6b480ae305e621bf1bdd69acbe3e8b81c6a6ae..2cbf1c7bcbaed34d8cb9cb1dbc63153cbbff9a18 100644 (file)
@@ -107,6 +107,11 @@ A fixed faked value to use instead of a proper random number so that functions
 in libcurl that are otherwise getting random outputs can be tested for what
 they generate.
 
+## `CURL_SIGPIPE_DEBUG`
+
+When present, `curl` does not set `SIGPIPE` to ignore. This allows
+verification that `libcurl` does not cause `SIGPIPE` to be raised.
+
 ## `CURL_SMALLREQSEND`
 
 An alternative size of HTTP data to be sent at a time only if smaller than the
index 17b1a478700d7ce2e572ce2bce94e23a60bbdbad..c1863d17de442cfee6a8342e074dc01b348e0a53 100644 (file)
@@ -97,32 +97,6 @@ static void tcpnodelay(struct Curl_cfilter *cf,
 #endif
 }
 
-#ifdef SO_NOSIGPIPE
-/* The preferred method on macOS (10.2 and later) to prevent SIGPIPEs when
-   sending data to a dead peer (instead of relying on the 4th argument to send
-   being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
-   systems? */
-static void nosigpipe(struct Curl_cfilter *cf,
-                      struct Curl_easy *data,
-                      curl_socket_t sockfd)
-{
-  int onoff = 1;
-  if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE,
-                (void *)&onoff, sizeof(onoff)) < 0) {
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
-    char buffer[STRERROR_LEN];
-    CURL_TRC_CF(data, cf, "Could not set SO_NOSIGPIPE: %s",
-                curlx_strerror(SOCKERRNO, buffer, sizeof(buffer)));
-#else
-    (void)cf;
-    (void)data;
-#endif
-  }
-}
-#else
-#define nosigpipe(x, y, z) Curl_nop_stmt
-#endif
-
 #if defined(USE_WINSOCK) || \
    (defined(__sun) && !defined(TCP_KEEPIDLE)) || \
    (defined(__DragonFly__) && __DragonFly_version < 500702) || \
@@ -358,6 +332,19 @@ static CURLcode socket_open(struct Curl_easy *data,
     return CURLE_COULDNT_CONNECT;
   }
 
+#ifdef USE_SO_NOSIGPIPE
+  {
+    int onoff = 1;
+    if(setsockopt(*sockfd, SOL_SOCKET, SO_NOSIGPIPE,
+                  (void *)&onoff, sizeof(onoff)) < 0) {
+      failf(data, "setsockopt enable SO_NOSIGPIPE: %s",
+            curlx_strerror(SOCKERRNO, errbuf, sizeof(errbuf)));
+      *sockfd = CURL_SOCKET_BAD;
+      return CURLE_COULDNT_CONNECT;
+    }
+  }
+#endif /* USE_SO_NOSIGPIPE */
+
 #ifdef HAVE_FCNTL
   if(fcntl(*sockfd, F_SETFD, FD_CLOEXEC) < 0) {
     failf(data, "fcntl set CLOEXEC: %s",
@@ -1101,8 +1088,6 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
   if(is_tcp && data->set.tcp_nodelay)
     tcpnodelay(cf, data, ctx->sock);
 
-  nosigpipe(cf, data, ctx->sock);
-
   if(is_tcp && data->set.tcp_keepalive)
     tcpkeepalive(cf, data, ctx->sock);
 
index ff991a074bdf1a8d843c12bfc28eb1b15b593555..750ba90d2d4c8f1a1d914b466659eb398ccee2f2 100644 (file)
 #define USE_EVENTFD
 #endif
 
+#ifdef SO_NOSIGPIPE
+#define USE_SO_NOSIGPIPE
+#endif
+
 #include <stdio.h>
 #include <assert.h>
 
index 9fe13af92b6431b35e095a7f1b7ab5cd24c44632..a906b27037498037864017c36d8e91e5e4b58900 100644 (file)
@@ -25,8 +25,7 @@
  ***************************************************************************/
 #include "curl_setup.h"
 
-#if defined(HAVE_SIGACTION) && \
-  (defined(USE_OPENSSL) || defined(USE_MBEDTLS) || defined(USE_WOLFSSL))
+#if defined(HAVE_SIGACTION) && !defined(USE_SO_NOSIGPIPE)
 #include <signal.h>
 
 struct Curl_sigpipe_ctx {
@@ -58,8 +57,10 @@ static CURL_INLINE void sigpipe_ignore(struct Curl_easy *data,
     action = ig->old_pipe_act;
     /* ignore this signal */
     action.sa_handler = SIG_IGN;
+#ifdef SA_SIGINFO
     /* clear SA_SIGINFO flag since we are using sa_handler */
     action.sa_flags &= ~SA_SIGINFO;
+#endif
     sigaction(SIGPIPE, &action, NULL);
   }
 }
@@ -85,8 +86,8 @@ static CURL_INLINE void sigpipe_apply(struct Curl_easy *data,
   }
 }
 
-#else
-/* for systems without sigaction */
+#else /* !HAVE_SIGACTION || USE_SO_NOSIGPIPE */
+/* for systems without sigaction or where SO_NOSIGPIPE is used. */
 #define sigpipe_ignore(x, y) do { (void)x; (void)y; } while(0)
 #define sigpipe_apply(x, y)  do { (void)x; (void)y; } while(0)
 #define sigpipe_init(x)      do { (void)x; } while(0)
@@ -96,6 +97,6 @@ struct Curl_sigpipe_ctx {
   bool dummy;
 };
 
-#endif
+#endif /* else HAVE_SIGACTION && !USE_SO_NOSIGPIPE */
 
 #endif /* HEADER_CURL_SIGPIPE_H */
index 806fbd4c0e575debf859be531b343c39c96aebe7..bb17d046b47ee3cb611e75cdf98d04d5c9ea3707 100644 (file)
@@ -172,6 +172,9 @@ int main(int argc, char *argv[])
   }
 
 #if defined(HAVE_SIGNAL) && defined(SIGPIPE)
+#ifdef DEBUGBUILD
+  if(!curl_getenv("CURL_SIGPIPE_DEBUG"))
+#endif
   (void)signal(SIGPIPE, SIG_IGN);
 #endif