From 076e17cb6d5541bc2cc63d49d3882cc4a6f95507 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Mon, 11 Mar 2013 00:39:52 +0100
Subject: [PATCH] SIGPIPE: ignore it while inside the library

... and restore the ordinary handling again when it returns. This is
done for curl_easy_perform() and curl_easy_cleanup() only for now.
---
 lib/easy.c |   54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

diff --git a/lib/easy.c b/lib/easy.c
index c27deff..8fae5f9 100644
--- a/lib/easy.c
+++ b/lib/easy.c
@@ -42,6 +42,11 @@
 #include <sys/param.h>
 #endif
 
+#if defined(HAVE_SIGNAL_H) && defined(HAVE_SIGACTION)
+#define SIGPIPE_IGNORE 1
+#include <signal.h>
+#endif
+
 #include "strequal.h"
 #include "urldata.h"
 #include <curl/curl.h>
@@ -72,6 +77,47 @@
 /* The last #include file should be: */
 #include "memdebug.h"
 
+#ifdef SIGPIPE_IGNORE
+struct sigpipe {
+  struct sigaction action;
+};
+
+#define SIGPIPE_VARIABLE(x) struct sigpipe x
+
+/*
+ * sigpipe_ignore() makes sure we ignore SIGPIPE while running libcurl
+ * internals, and then sigpipe_restore() will restore the situation when we
+ * return from libcurl again.
+ */
+static void sigpipe_ignore(struct sigpipe *pipe)
+{
+  struct sigaction action;
+  /* first, extract the existing situation */
+  sigaction(SIGPIPE, NULL, &pipe->action);
+  action = pipe->action;
+  /* ignore this signal */
+  action.sa_handler = SIG_IGN;
+  sigaction(SIGPIPE, &action, NULL);
+}
+
+/*
+ * sigpipe_restore() puts back the outside world's opinion of signal handler
+ * and SIGPIPE handling. It MUST only be called after a corresponding
+ * sigpipe_ignore() was used.
+ */
+static void sigpipe_restore(struct sigpipe *pipe)
+{
+  /* restore the outside state */
+  sigaction(SIGPIPE, &pipe->action, NULL);
+}
+
+#else
+/* for systems without sigaction */
+#define sigpipe_ignore(x)
+#define sigpipe_restore(x)
+#define SIGPIPE_VARIABLE(x)
+#endif
+
 /* win32_cleanup() is for win32 socket cleanup functionality, the opposite
    of win32_init() */
 static void win32_cleanup(void)
@@ -408,6 +454,7 @@ CURLcode curl_easy_perform(CURL *easy)
   bool done = FALSE;
   int rc;
   struct SessionHandle *data = easy;
+  SIGPIPE_VARIABLE(pipe);
 
   if(!easy)
     return CURLE_BAD_FUNCTION_ARGUMENT;
@@ -435,6 +482,8 @@ CURLcode curl_easy_perform(CURL *easy)
       return CURLE_FAILED_INIT;
   }
 
+  sigpipe_ignore(&pipe);
+
   /* assign this after curl_multi_add_handle() since that function checks for
      it and rejects this handle otherwise */
   data->multi = multi;
@@ -461,6 +510,8 @@ CURLcode curl_easy_perform(CURL *easy)
      a failure here, room for future improvement! */
   (void)curl_multi_remove_handle(multi, easy);
 
+  sigpipe_restore(&pipe);
+
   /* The multi handle is kept alive, owned by the easy handle */
   return code;
 }
@@ -472,11 +523,14 @@ CURLcode curl_easy_perform(CURL *easy)
 void curl_easy_cleanup(CURL *curl)
 {
   struct SessionHandle *data = (struct SessionHandle *)curl;
+  SIGPIPE_VARIABLE(pipe);
 
   if(!data)
     return;
 
+  sigpipe_ignore(&pipe);
   Curl_close(data);
+  sigpipe_restore(&pipe);
 }
 
 /*
-- 
1.7.10.4

