src/os/unix/ngx_channel.c - nginx-1.7.10

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_channel.h>


  8. ngx_int_t
  9. ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size,
  10.     ngx_log_t *log)
  11. {
  12.     ssize_t             n;
  13.     ngx_err_t           err;
  14.     struct iovec        iov[1];
  15.     struct msghdr       msg;

  16. #if (NGX_HAVE_MSGHDR_MSG_CONTROL)

  17.     union {
  18.         struct cmsghdr  cm;
  19.         char            space[CMSG_SPACE(sizeof(int))];
  20.     } cmsg;

  21.     if (ch->fd == -1) {
  22.         msg.msg_control = NULL;
  23.         msg.msg_controllen = 0;

  24.     } else {
  25.         msg.msg_control = (caddr_t) &cmsg;
  26.         msg.msg_controllen = sizeof(cmsg);

  27.         ngx_memzero(&cmsg, sizeof(cmsg));

  28.         cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int));
  29.         cmsg.cm.cmsg_level = SOL_SOCKET;
  30.         cmsg.cm.cmsg_type = SCM_RIGHTS;

  31.         /*
  32.          * We have to use ngx_memcpy() instead of simple
  33.          *   *(int *) CMSG_DATA(&cmsg.cm) = ch->fd;
  34.          * because some gcc 4.4 with -O2/3/s optimization issues the warning:
  35.          *   dereferencing type-punned pointer will break strict-aliasing rules
  36.          *
  37.          * Fortunately, gcc with -O1 compiles this ngx_memcpy()
  38.          * in the same simple assignment as in the code above
  39.          */

  40.         ngx_memcpy(CMSG_DATA(&cmsg.cm), &ch->fd, sizeof(int));
  41.     }

  42.     msg.msg_flags = 0;

  43. #else

  44.     if (ch->fd == -1) {
  45.         msg.msg_accrights = NULL;
  46.         msg.msg_accrightslen = 0;

  47.     } else {
  48.         msg.msg_accrights = (caddr_t) &ch->fd;
  49.         msg.msg_accrightslen = sizeof(int);
  50.     }

  51. #endif

  52.     iov[0].iov_base = (char *) ch;
  53.     iov[0].iov_len = size;

  54.     msg.msg_name = NULL;
  55.     msg.msg_namelen = 0;
  56.     msg.msg_iov = iov;
  57.     msg.msg_iovlen = 1;

  58.     n = sendmsg(s, &msg, 0);

  59.     if (n == -1) {
  60.         err = ngx_errno;
  61.         if (err == NGX_EAGAIN) {
  62.             return NGX_AGAIN;
  63.         }

  64.         ngx_log_error(NGX_LOG_ALERT, log, err, "sendmsg() failed");
  65.         return NGX_ERROR;
  66.     }

  67.     return NGX_OK;
  68. }


  69. ngx_int_t
  70. ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, ngx_log_t *log)
  71. {
  72.     ssize_t             n;
  73.     ngx_err_t           err;
  74.     struct iovec        iov[1];
  75.     struct msghdr       msg;

  76. #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
  77.     union {
  78.         struct cmsghdr  cm;
  79.         char            space[CMSG_SPACE(sizeof(int))];
  80.     } cmsg;
  81. #else
  82.     int                 fd;
  83. #endif

  84.     iov[0].iov_base = (char *) ch;
  85.     iov[0].iov_len = size;

  86.     msg.msg_name = NULL;
  87.     msg.msg_namelen = 0;
  88.     msg.msg_iov = iov;
  89.     msg.msg_iovlen = 1;

  90. #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
  91.     msg.msg_control = (caddr_t) &cmsg;
  92.     msg.msg_controllen = sizeof(cmsg);
  93. #else
  94.     msg.msg_accrights = (caddr_t) &fd;
  95.     msg.msg_accrightslen = sizeof(int);
  96. #endif

  97.     n = recvmsg(s, &msg, 0);

  98.     if (n == -1) {
  99.         err = ngx_errno;
  100.         if (err == NGX_EAGAIN) {
  101.             return NGX_AGAIN;
  102.         }

  103.         ngx_log_error(NGX_LOG_ALERT, log, err, "recvmsg() failed");
  104.         return NGX_ERROR;
  105.     }

  106.     if (n == 0) {
  107.         ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "recvmsg() returned zero");
  108.         return NGX_ERROR;
  109.     }

  110.     if ((size_t) n < sizeof(ngx_channel_t)) {
  111.         ngx_log_error(NGX_LOG_ALERT, log, 0,
  112.                       "recvmsg() returned not enough data: %z", n);
  113.         return NGX_ERROR;
  114.     }

  115. #if (NGX_HAVE_MSGHDR_MSG_CONTROL)

  116.     if (ch->command == NGX_CMD_OPEN_CHANNEL) {

  117.         if (cmsg.cm.cmsg_len < (socklen_t) CMSG_LEN(sizeof(int))) {
  118.             ngx_log_error(NGX_LOG_ALERT, log, 0,
  119.                           "recvmsg() returned too small ancillary data");
  120.             return NGX_ERROR;
  121.         }

  122.         if (cmsg.cm.cmsg_level != SOL_SOCKET || cmsg.cm.cmsg_type != SCM_RIGHTS)
  123.         {
  124.             ngx_log_error(NGX_LOG_ALERT, log, 0,
  125.                           "recvmsg() returned invalid ancillary data "
  126.                           "level %d or type %d",
  127.                           cmsg.cm.cmsg_level, cmsg.cm.cmsg_type);
  128.             return NGX_ERROR;
  129.         }

  130.         /* ch->fd = *(int *) CMSG_DATA(&cmsg.cm); */

  131.         ngx_memcpy(&ch->fd, CMSG_DATA(&cmsg.cm), sizeof(int));
  132.     }

  133.     if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) {
  134.         ngx_log_error(NGX_LOG_ALERT, log, 0,
  135.                       "recvmsg() truncated data");
  136.     }

  137. #else

  138.     if (ch->command == NGX_CMD_OPEN_CHANNEL) {
  139.         if (msg.msg_accrightslen != sizeof(int)) {
  140.             ngx_log_error(NGX_LOG_ALERT, log, 0,
  141.                           "recvmsg() returned no ancillary data");
  142.             return NGX_ERROR;
  143.         }

  144.         ch->fd = fd;
  145.     }

  146. #endif

  147.     return n;
  148. }


  149. ngx_int_t
  150. ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd, ngx_int_t event,
  151.     ngx_event_handler_pt handler)
  152. {
  153.     ngx_event_t       *ev, *rev, *wev;
  154.     ngx_connection_t  *c;

  155.     c = ngx_get_connection(fd, cycle->log);

  156.     if (c == NULL) {
  157.         return NGX_ERROR;
  158.     }

  159.     c->pool = cycle->pool;

  160.     rev = c->read;
  161.     wev = c->write;

  162.     rev->log = cycle->log;
  163.     wev->log = cycle->log;

  164.     rev->channel = 1;
  165.     wev->channel = 1;

  166.     ev = (event == NGX_READ_EVENT) ? rev : wev;

  167.     ev->handler = handler;

  168.     if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
  169.         if (ngx_add_conn(c) == NGX_ERROR) {
  170.             ngx_free_connection(c);
  171.             return NGX_ERROR;
  172.         }

  173.     } else {
  174.         if (ngx_add_event(ev, event, 0) == NGX_ERROR) {
  175.             ngx_free_connection(c);
  176.             return NGX_ERROR;
  177.         }
  178.     }

  179.     return NGX_OK;
  180. }


  181. void
  182. ngx_close_channel(ngx_fd_t *fd, ngx_log_t *log)
  183. {
  184.     if (close(fd[0]) == -1) {
  185.         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "close() channel failed");
  186.     }

  187.     if (close(fd[1]) == -1) {
  188.         ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "close() channel failed");
  189.     }
  190. }