changeset 2111:4300c587db9e stable-0.5

r1901, r1902, r2032 merge: bugfixes in channel: *) avoid endless loop if epoll is used *) use CMSG_LEN(), this fixes an alert "sendmsg() failed (9: Bad file descriptor)" on some 64-bit platforms *) read channel until EAGAIN
author Igor Sysoev <igor@sysoev.ru>
date Mon, 07 Jul 2008 11:58:55 +0000
parents aeeb3ca9de06
children 4c30d2380d81
files src/os/unix/ngx_channel.c src/os/unix/ngx_freebsd_config.h src/os/unix/ngx_posix_config.h src/os/unix/ngx_process_cycle.c
diffstat 4 files changed, 66 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/src/os/unix/ngx_channel.c
+++ b/src/os/unix/ngx_channel.c
@@ -33,7 +33,7 @@ ngx_write_channel(ngx_socket_t s, ngx_ch
         msg.msg_control = (caddr_t) &cmsg;
         msg.msg_controllen = sizeof(cmsg);
 
-        cmsg.cm.cmsg_len = sizeof(cmsg);
+        cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int));
         cmsg.cm.cmsg_level = SOL_SOCKET;
         cmsg.cm.cmsg_type = SCM_RIGHTS;
         *(int *) CMSG_DATA(&cmsg.cm) = ch->fd;
@@ -138,7 +138,7 @@ ngx_read_channel(ngx_socket_t s, ngx_cha
 
     if (ch->command == NGX_CMD_OPEN_CHANNEL) {
 
-        if (cmsg.cm.cmsg_len < (socklen_t) sizeof(cmsg)) {
+        if (cmsg.cm.cmsg_len < (socklen_t) CMSG_LEN(sizeof(int))) {
             ngx_log_error(NGX_LOG_ALERT, log, 0,
                           "recvmsg() returned too small ancillary data");
             return NGX_ERROR;
--- a/src/os/unix/ngx_freebsd_config.h
+++ b/src/os/unix/ngx_freebsd_config.h
@@ -48,11 +48,16 @@
 
 #if __FreeBSD_version < 400017
 
-/* FreeBSD 3.x has no CMSG_SPACE() at all and has the broken CMSG_DATA() */
+/*
+ * FreeBSD 3.x has no CMSG_SPACE() and CMSG_LEN() and has the broken CMSG_DATA()
+ */
 
 #undef  CMSG_SPACE
 #define CMSG_SPACE(l)       (ALIGN(sizeof(struct cmsghdr)) + ALIGN(l))
 
+#undef  CMSG_LEN
+#define CMSG_LEN(l)         (ALIGN(sizeof(struct cmsghdr)) + (l))
+
 #undef  CMSG_DATA
 #define CMSG_DATA(cmsg)     ((u_char *)(cmsg) + ALIGN(sizeof(struct cmsghdr)))
 
--- a/src/os/unix/ngx_posix_config.h
+++ b/src/os/unix/ngx_posix_config.h
@@ -110,11 +110,16 @@
 
 #include <sys/param.h>          /* ALIGN() */
 
-/* FreeBSD 3.x has no CMSG_SPACE() at all and has the broken CMSG_DATA() */
+/* 
+ * FreeBSD 3.x has no CMSG_SPACE() and CMSG_LEN() and has the broken CMSG_DATA()
+ */
 
 #undef  CMSG_SPACE
 #define CMSG_SPACE(l)       (ALIGN(sizeof(struct cmsghdr)) + ALIGN(l))
 
+#undef  CMSG_LEN
+#define CMSG_LEN(l)         (ALIGN(sizeof(struct cmsghdr)) + (l))
+
 #undef  CMSG_DATA
 #define CMSG_DATA(cmsg)     ((u_char *)(cmsg) + ALIGN(sizeof(struct cmsghdr)))
 
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -1055,65 +1055,74 @@ ngx_channel_handler(ngx_event_t *ev)
 
     ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel handler");
 
-    n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log);
+    for ( ;; ) {
+
+        n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log);
+
+        ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n);
 
-    ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n);
+        if (n == NGX_ERROR) {
+
+            if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
+                ngx_del_conn(c, 0);
+            }
 
-    if (n == NGX_ERROR) {
-        ngx_close_connection(c);
-        return;
-    }
+            ngx_close_connection(c);
+            return;
+        }
 
-    if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) {
-        if (ngx_add_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) {
+        if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) {
+            if (ngx_add_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) {
+                return;
+            }
+        }
+
+        if (n == NGX_AGAIN) {
             return;
         }
-    }
+
+        ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0,
+                       "channel command: %d", ch.command);
 
-    if (n == NGX_AGAIN) {
-        return;
-    }
+        switch (ch.command) {
 
-    ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0,
-                   "channel command: %d", ch.command);
-
-    switch (ch.command) {
+        case NGX_CMD_QUIT:
+            ngx_quit = 1;
+            break;
 
-    case NGX_CMD_QUIT:
-        ngx_quit = 1;
-        break;
+        case NGX_CMD_TERMINATE:
+            ngx_terminate = 1;
+            break;
 
-    case NGX_CMD_TERMINATE:
-        ngx_terminate = 1;
-        break;
+        case NGX_CMD_REOPEN:
+            ngx_reopen = 1;
+            break;
 
-    case NGX_CMD_REOPEN:
-        ngx_reopen = 1;
-        break;
+        case NGX_CMD_OPEN_CHANNEL:
 
-    case NGX_CMD_OPEN_CHANNEL:
-
-        ngx_log_debug3(NGX_LOG_DEBUG_CORE, ev->log, 0,
-                       "get channel s:%i pid:%P fd:%d", ch.slot, ch.pid, ch.fd);
+            ngx_log_debug3(NGX_LOG_DEBUG_CORE, ev->log, 0,
+                           "get channel s:%i pid:%P fd:%d",
+                           ch.slot, ch.pid, ch.fd);
 
-        ngx_processes[ch.slot].pid = ch.pid;
-        ngx_processes[ch.slot].channel[0] = ch.fd;
-        break;
+            ngx_processes[ch.slot].pid = ch.pid;
+            ngx_processes[ch.slot].channel[0] = ch.fd;
+            break;
 
-    case NGX_CMD_CLOSE_CHANNEL:
+        case NGX_CMD_CLOSE_CHANNEL:
 
-        ngx_log_debug4(NGX_LOG_DEBUG_CORE, ev->log, 0,
-                       "close channel s:%i pid:%P our:%P fd:%d",
-                       ch.slot, ch.pid, ngx_processes[ch.slot].pid,
-                       ngx_processes[ch.slot].channel[0]);
+            ngx_log_debug4(NGX_LOG_DEBUG_CORE, ev->log, 0,
+                           "close channel s:%i pid:%P our:%P fd:%d",
+                           ch.slot, ch.pid, ngx_processes[ch.slot].pid,
+                           ngx_processes[ch.slot].channel[0]);
 
-        if (close(ngx_processes[ch.slot].channel[0]) == -1) {
-            ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
-                          "close() channel failed");
+            if (close(ngx_processes[ch.slot].channel[0]) == -1) {
+                ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
+                              "close() channel failed");
+            }
+
+            ngx_processes[ch.slot].channel[0] = -1;
+            break;
         }
-
-        ngx_processes[ch.slot].channel[0] = -1;
-        break;
     }
 }