src/os/unix/ngx_udp_sendmsg_chain.c - nginx source code

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_event.h>


  8. static ngx_chain_t *ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec,
  9.     ngx_chain_t *in, ngx_log_t *log);
  10. static ssize_t ngx_sendmsg_vec(ngx_connection_t *c, ngx_iovec_t *vec);


  11. ngx_chain_t *
  12. ngx_udp_unix_sendmsg_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
  13. {
  14.     ssize_t        n;
  15.     off_t          send;
  16.     ngx_chain_t   *cl;
  17.     ngx_event_t   *wev;
  18.     ngx_iovec_t    vec;
  19.     struct iovec   iovs[NGX_IOVS_PREALLOCATE];

  20.     wev = c->write;

  21.     if (!wev->ready) {
  22.         return in;
  23.     }

  24. #if (NGX_HAVE_KQUEUE)

  25.     if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) {
  26.         (void) ngx_connection_error(c, wev->kq_errno,
  27.                                "kevent() reported about an closed connection");
  28.         wev->error = 1;
  29.         return NGX_CHAIN_ERROR;
  30.     }

  31. #endif

  32.     /* the maximum limit size is the maximum size_t value - the page size */

  33.     if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) {
  34.         limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize;
  35.     }

  36.     send = 0;

  37.     vec.iovs = iovs;
  38.     vec.nalloc = NGX_IOVS_PREALLOCATE;

  39.     for ( ;; ) {

  40.         /* create the iovec and coalesce the neighbouring bufs */

  41.         cl = ngx_udp_output_chain_to_iovec(&vec, in, c->log);

  42.         if (cl == NGX_CHAIN_ERROR) {
  43.             return NGX_CHAIN_ERROR;
  44.         }

  45.         if (cl && cl->buf->in_file) {
  46.             ngx_log_error(NGX_LOG_ALERT, c->log, 0,
  47.                           "file buf in sendmsg "
  48.                           "t:%d r:%d f:%d %p %p-%p %p %O-%O",
  49.                           cl->buf->temporary,
  50.                           cl->buf->recycled,
  51.                           cl->buf->in_file,
  52.                           cl->buf->start,
  53.                           cl->buf->pos,
  54.                           cl->buf->last,
  55.                           cl->buf->file,
  56.                           cl->buf->file_pos,
  57.                           cl->buf->file_last);

  58.             ngx_debug_point();

  59.             return NGX_CHAIN_ERROR;
  60.         }

  61.         if (cl == in) {
  62.             return in;
  63.         }

  64.         send += vec.size;

  65.         n = ngx_sendmsg_vec(c, &vec);

  66.         if (n == NGX_ERROR) {
  67.             return NGX_CHAIN_ERROR;
  68.         }

  69.         if (n == NGX_AGAIN) {
  70.             wev->ready = 0;
  71.             return in;
  72.         }

  73.         c->sent += n;

  74.         in = ngx_chain_update_sent(in, n);

  75.         if (send >= limit || in == NULL) {
  76.             return in;
  77.         }
  78.     }
  79. }


  80. static ngx_chain_t *
  81. ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, ngx_log_t *log)
  82. {
  83.     size_t         total, size;
  84.     u_char        *prev;
  85.     ngx_uint_t     n, flush;
  86.     ngx_chain_t   *cl;
  87.     struct iovec  *iov;

  88.     cl = in;
  89.     iov = NULL;
  90.     prev = NULL;
  91.     total = 0;
  92.     n = 0;
  93.     flush = 0;

  94.     for ( /* void */ ; in && !flush; in = in->next) {

  95.         if (in->buf->flush || in->buf->last_buf) {
  96.             flush = 1;
  97.         }

  98.         if (ngx_buf_special(in->buf)) {
  99.             continue;
  100.         }

  101.         if (in->buf->in_file) {
  102.             break;
  103.         }

  104.         if (!ngx_buf_in_memory(in->buf)) {
  105.             ngx_log_error(NGX_LOG_ALERT, log, 0,
  106.                           "bad buf in output chain "
  107.                           "t:%d r:%d f:%d %p %p-%p %p %O-%O",
  108.                           in->buf->temporary,
  109.                           in->buf->recycled,
  110.                           in->buf->in_file,
  111.                           in->buf->start,
  112.                           in->buf->pos,
  113.                           in->buf->last,
  114.                           in->buf->file,
  115.                           in->buf->file_pos,
  116.                           in->buf->file_last);

  117.             ngx_debug_point();

  118.             return NGX_CHAIN_ERROR;
  119.         }

  120.         size = in->buf->last - in->buf->pos;

  121.         if (prev == in->buf->pos) {
  122.             iov->iov_len += size;

  123.         } else {
  124.             if (n == vec->nalloc) {
  125.                 ngx_log_error(NGX_LOG_ALERT, log, 0,
  126.                               "too many parts in a datagram");
  127.                 return NGX_CHAIN_ERROR;
  128.             }

  129.             iov = &vec->iovs[n++];

  130.             iov->iov_base = (void *) in->buf->pos;
  131.             iov->iov_len = size;
  132.         }

  133.         prev = in->buf->pos + size;
  134.         total += size;
  135.     }

  136.     if (!flush) {
  137. #if (NGX_SUPPRESS_WARN)
  138.         vec->size = 0;
  139.         vec->count = 0;
  140. #endif
  141.         return cl;
  142.     }

  143.     /* zero-sized datagram; pretend to have at least 1 iov */
  144.     if (n == 0) {
  145.         iov = &vec->iovs[n++];
  146.         iov->iov_base = NULL;
  147.         iov->iov_len = 0;
  148.     }

  149.     vec->count = n;
  150.     vec->size = total;

  151.     return in;
  152. }


  153. static ssize_t
  154. ngx_sendmsg_vec(ngx_connection_t *c, ngx_iovec_t *vec)
  155. {
  156.     struct msghdr    msg;

  157. #if (NGX_HAVE_ADDRINFO_CMSG)
  158.     struct cmsghdr  *cmsg;
  159.     u_char           msg_control[CMSG_SPACE(sizeof(ngx_addrinfo_t))];
  160. #endif

  161.     ngx_memzero(&msg, sizeof(struct msghdr));

  162.     if (c->socklen) {
  163.         msg.msg_name = c->sockaddr;
  164.         msg.msg_namelen = c->socklen;
  165.     }

  166.     msg.msg_iov = vec->iovs;
  167.     msg.msg_iovlen = vec->count;

  168. #if (NGX_HAVE_ADDRINFO_CMSG)
  169.     if (c->listening && c->listening->wildcard && c->local_sockaddr) {

  170.         msg.msg_control = msg_control;
  171.         msg.msg_controllen = sizeof(msg_control);
  172.         ngx_memzero(msg_control, sizeof(msg_control));

  173.         cmsg = CMSG_FIRSTHDR(&msg);

  174.         msg.msg_controllen = ngx_set_srcaddr_cmsg(cmsg, c->local_sockaddr);
  175.     }
  176. #endif

  177.     return ngx_sendmsg(c, &msg, 0);
  178. }


  179. #if (NGX_HAVE_ADDRINFO_CMSG)

  180. size_t
  181. ngx_set_srcaddr_cmsg(struct cmsghdr *cmsg, struct sockaddr *local_sockaddr)
  182. {
  183.     size_t                len;
  184. #if (NGX_HAVE_IP_SENDSRCADDR)
  185.     struct in_addr       *addr;
  186.     struct sockaddr_in   *sin;
  187. #elif (NGX_HAVE_IP_PKTINFO)
  188.     struct in_pktinfo    *pkt;
  189.     struct sockaddr_in   *sin;
  190. #endif

  191. #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
  192.     struct in6_pktinfo   *pkt6;
  193.     struct sockaddr_in6  *sin6;
  194. #endif


  195. #if (NGX_HAVE_IP_SENDSRCADDR) || (NGX_HAVE_IP_PKTINFO)

  196.     if (local_sockaddr->sa_family == AF_INET) {

  197.         cmsg->cmsg_level = IPPROTO_IP;

  198. #if (NGX_HAVE_IP_SENDSRCADDR)

  199.         cmsg->cmsg_type = IP_SENDSRCADDR;
  200.         cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
  201.         len = CMSG_SPACE(sizeof(struct in_addr));

  202.         sin = (struct sockaddr_in *) local_sockaddr;

  203.         addr = (struct in_addr *) CMSG_DATA(cmsg);
  204.         *addr = sin->sin_addr;

  205. #elif (NGX_HAVE_IP_PKTINFO)

  206.         cmsg->cmsg_type = IP_PKTINFO;
  207.         cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
  208.         len = CMSG_SPACE(sizeof(struct in_pktinfo));

  209.         sin = (struct sockaddr_in *) local_sockaddr;

  210.         pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
  211.         ngx_memzero(pkt, sizeof(struct in_pktinfo));
  212.         pkt->ipi_spec_dst = sin->sin_addr;

  213. #endif
  214.         return len;
  215.     }

  216. #endif

  217. #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
  218.     if (local_sockaddr->sa_family == AF_INET6) {

  219.         cmsg->cmsg_level = IPPROTO_IPV6;
  220.         cmsg->cmsg_type = IPV6_PKTINFO;
  221.         cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
  222.         len = CMSG_SPACE(sizeof(struct in6_pktinfo));

  223.         sin6 = (struct sockaddr_in6 *) local_sockaddr;

  224.         pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
  225.         ngx_memzero(pkt6, sizeof(struct in6_pktinfo));
  226.         pkt6->ipi6_addr = sin6->sin6_addr;

  227.         return len;
  228.     }
  229. #endif

  230.     return 0;
  231. }


  232. ngx_int_t
  233. ngx_get_srcaddr_cmsg(struct cmsghdr *cmsg, struct sockaddr *local_sockaddr)
  234. {

  235. #if (NGX_HAVE_IP_RECVDSTADDR)
  236.     struct in_addr       *addr;
  237.     struct sockaddr_in   *sin;
  238. #elif (NGX_HAVE_IP_PKTINFO)
  239.     struct in_pktinfo    *pkt;
  240.     struct sockaddr_in   *sin;
  241. #endif

  242. #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
  243.     struct in6_pktinfo   *pkt6;
  244.     struct sockaddr_in6  *sin6;
  245. #endif


  246. #if (NGX_HAVE_IP_RECVDSTADDR)

  247.     if (cmsg->cmsg_level == IPPROTO_IP
  248.         && cmsg->cmsg_type == IP_RECVDSTADDR
  249.         && local_sockaddr->sa_family == AF_INET)
  250.     {
  251.         addr = (struct in_addr *) CMSG_DATA(cmsg);
  252.         sin = (struct sockaddr_in *) local_sockaddr;
  253.         sin->sin_addr = *addr;

  254.         return NGX_OK;
  255.     }

  256. #elif (NGX_HAVE_IP_PKTINFO)

  257.     if (cmsg->cmsg_level == IPPROTO_IP
  258.         && cmsg->cmsg_type == IP_PKTINFO
  259.         && local_sockaddr->sa_family == AF_INET)
  260.     {
  261.         pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
  262.         sin = (struct sockaddr_in *) local_sockaddr;
  263.         sin->sin_addr = pkt->ipi_addr;

  264.         return NGX_OK;
  265.     }

  266. #endif

  267. #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)

  268.     if (cmsg->cmsg_level == IPPROTO_IPV6
  269.         && cmsg->cmsg_type == IPV6_PKTINFO
  270.         && local_sockaddr->sa_family == AF_INET6)
  271.     {
  272.         pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
  273.         sin6 = (struct sockaddr_in6 *) local_sockaddr;
  274.         sin6->sin6_addr = pkt6->ipi6_addr;

  275.         return NGX_OK;
  276.     }

  277. #endif

  278.     return NGX_DECLINED;
  279. }

  280. #endif


  281. ssize_t
  282. ngx_sendmsg(ngx_connection_t *c, struct msghdr *msg, int flags)
  283. {
  284.     ssize_t    n;
  285.     ngx_err_t  err;
  286. #if (NGX_DEBUG)
  287.     size_t      size;
  288.     ngx_uint_t  i;
  289. #endif

  290. eintr:

  291.     n = sendmsg(c->fd, msg, flags);

  292.     if (n == -1) {
  293.         err = ngx_errno;

  294.         switch (err) {
  295.         case NGX_EAGAIN:
  296.             ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
  297.                            "sendmsg() not ready");
  298.             return NGX_AGAIN;

  299.         case NGX_EINTR:
  300.             ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
  301.                            "sendmsg() was interrupted");
  302.             goto eintr;

  303.         default:
  304.             c->write->error = 1;
  305.             ngx_connection_error(c, err, "sendmsg() failed");
  306.             return NGX_ERROR;
  307.         }
  308.     }

  309. #if (NGX_DEBUG)
  310.     for (i = 0, size = 0; i < (size_t) msg->msg_iovlen; i++) {
  311.         size += msg->msg_iov[i].iov_len;
  312.     }

  313.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
  314.                    "sendmsg: %z of %uz", n, size);
  315. #endif

  316.     return n;
  317. }