From fb04203b721f0f6eefb3b054396a115e05d71195 Mon Sep 17 00:00:00 2001
From: Ruslan Valiullin <r.valiullin77@gmail.com>
Date: Sun, 9 Apr 2017 16:57:34 +0100
Subject: [PATCH] Fix eintr, zombie

PUBLISHED_FROM=f6d7d0f9c6de8ffeeb3bcd8aace6c1434281ddf7
---
 mongoose.c | 61 +++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 44 insertions(+), 17 deletions(-)

diff --git a/mongoose.c b/mongoose.c
index c7056262f..6345501f7 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -3582,9 +3582,7 @@ void mg_socket_if_init(struct mg_iface *iface) {
   (void) iface;
   DBG(("%p using select()", iface->mgr));
 #if MG_ENABLE_BROADCAST
-  do {
-    mg_socketpair(iface->mgr->ctl, SOCK_DGRAM);
-  } while (iface->mgr->ctl[0] == INVALID_SOCKET);
+  mg_socketpair(iface->mgr->ctl, SOCK_DGRAM);
 #endif
 }
 
@@ -3742,6 +3740,27 @@ time_t mg_socket_if_poll(struct mg_iface *iface, int timeout_ms) {
 }
 
 #if MG_ENABLE_BROADCAST
+MG_INTERNAL void mg_socketpair_close(sock_t *sock) {
+  while (1) {
+    if (closesocket(*sock) == -1 && errno == EINTR)
+      continue;
+    break;
+  }
+  *sock = INVALID_SOCKET;
+}
+
+MG_INTERNAL sock_t mg_socketpair_accept(sock_t sock, 
+                                     union socket_address *sa,
+                                     socklen_t sa_len) {
+  sock_t rc;
+  while(1) {
+    if ((rc = accept(sock, &sa->sa, &sa_len)) == INVALID_SOCKET && errno == EINTR)
+        continue;
+    break;
+  }
+  return rc;
+}
+
 int mg_socketpair(sock_t sp[2], int sock_type) {
   union socket_address sa;
   sock_t sock;
@@ -3765,20 +3784,19 @@ int mg_socketpair(sock_t sp[2], int sock_type) {
              (getsockname(sp[0], &sa.sa, &len) != 0 ||
               connect(sock, &sa.sa, len) != 0)) {
   } else if ((sp[1] = (sock_type == SOCK_DGRAM ? sock
-                                               : accept(sock, &sa.sa, &len))) ==
+                                               : mg_socketpair_accept(sock, &sa, len))) ==
              INVALID_SOCKET) {
   } else {
     mg_set_close_on_exec(sp[0]);
     mg_set_close_on_exec(sp[1]);
-    if (sock_type == SOCK_STREAM) closesocket(sock);
+    if (sock_type == SOCK_STREAM) mg_socketpair_close(&sock);
     ret = 1;
   }
 
   if (!ret) {
-    if (sp[0] != INVALID_SOCKET) closesocket(sp[0]);
-    if (sp[1] != INVALID_SOCKET) closesocket(sp[1]);
-    if (sock != INVALID_SOCKET) closesocket(sock);
-    sock = sp[0] = sp[1] = INVALID_SOCKET;
+    if (sp[0] != INVALID_SOCKET) mg_socketpair_close(&sp[0]);
+    if (sp[1] != INVALID_SOCKET) mg_socketpair_close(&sp[1]);
+    if (sock != INVALID_SOCKET) mg_socketpair_close(&sock);
   }
 
   return ret;
@@ -7929,6 +7947,10 @@ void mg_register_http_endpoint(struct mg_connection *nc, const char *uri_path,
  * All rights reserved
  */
 
+#ifndef _WIN32
+#include <signal.h>
+#endif
+
 #if MG_ENABLE_HTTP && MG_ENABLE_HTTP_CGI
 
 #ifndef MG_MAX_CGI_ENVIR_VARS
@@ -8379,14 +8401,19 @@ MG_INTERNAL void mg_handle_cgi(struct mg_connection *nc, const char *prog,
     prog = p + 1;
   }
 
-  /*
-   * Try to create socketpair in a loop until success. mg_socketpair()
-   * can be interrupted by a signal and fail.
-   * TODO(lsm): use sigaction to restart interrupted syscall
-   */
-  do {
-    mg_socketpair(fds, SOCK_STREAM);
-  } while (fds[0] == INVALID_SOCKET);
+  if (!mg_socketpair(fds, SOCK_STREAM)) {
+    nc->flags |= MG_F_CLOSE_IMMEDIATELY;
+    return;
+  }
+
+#ifndef _WIN32
+  struct sigaction sa;
+
+  sigemptyset(&sa.sa_mask);
+  sa.sa_handler = SIG_IGN;
+  sa.sa_flags = 0;
+  sigaction(SIGCHLD, &sa, NULL);
+#endif
 
   if (mg_start_process(opts->cgi_interpreter, prog, blk.buf, blk.vars, dir,
                        fds[1]) != 0) {
-- 
GitLab