Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.12 ]​[ nginx-1.16.0 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_event.h>
0011 
0012 
0013 static ngx_chain_t *ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec,
0014     ngx_chain_t *in, ngx_log_t *log);
0015 static ssize_t ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec);
0016 
0017 
0018 ngx_chain_t *
0019 ngx_udp_unix_sendmsg_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
0020 {
0021     ssize_t        n;
0022     off_t          send;
0023     ngx_chain_t   *cl;
0024     ngx_event_t   *wev;
0025     ngx_iovec_t    vec;
0026     struct iovec   iovs[NGX_IOVS_PREALLOCATE];
0027 
0028     wev = c->write;
0029 
0030     if (!wev->ready) {
0031         return in;
0032     }
0033 
0034 #if (NGX_HAVE_KQUEUE)
0035 
0036     if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) {
0037         (void) ngx_connection_error(c, wev->kq_errno,
0038                                "kevent() reported about an closed connection");
0039         wev->error = 1;
0040         return NGX_CHAIN_ERROR;
0041     }
0042 
0043 #endif
0044 
0045     /* the maximum limit size is the maximum size_t value - the page size */
0046 
0047     if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) {
0048         limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize;
0049     }
0050 
0051     send = 0;
0052 
0053     vec.iovs = iovs;
0054     vec.nalloc = NGX_IOVS_PREALLOCATE;
0055 
0056     for ( ;; ) {
0057 
0058         /* create the iovec and coalesce the neighbouring bufs */
0059 
0060         cl = ngx_udp_output_chain_to_iovec(&vec, in, c->log);
0061 
0062         if (cl == NGX_CHAIN_ERROR) {
0063             return NGX_CHAIN_ERROR;
0064         }
0065 
0066         if (cl && cl->buf->in_file) {
0067             ngx_log_error(NGX_LOG_ALERT, c->log, 0,
0068                           "file buf in sendmsg "
0069                           "t:%d r:%d f:%d %p %p-%p %p %O-%O",
0070                           cl->buf->temporary,
0071                           cl->buf->recycled,
0072                           cl->buf->in_file,
0073                           cl->buf->start,
0074                           cl->buf->pos,
0075                           cl->buf->last,
0076                           cl->buf->file,
0077                           cl->buf->file_pos,
0078                           cl->buf->file_last);
0079 
0080             ngx_debug_point();
0081 
0082             return NGX_CHAIN_ERROR;
0083         }
0084 
0085         if (cl == in) {
0086             return in;
0087         }
0088 
0089         send += vec.size;
0090 
0091         n = ngx_sendmsg(c, &vec);
0092 
0093         if (n == NGX_ERROR) {
0094             return NGX_CHAIN_ERROR;
0095         }
0096 
0097         if (n == NGX_AGAIN) {
0098             wev->ready = 0;
0099             return in;
0100         }
0101 
0102         c->sent += n;
0103 
0104         in = ngx_chain_update_sent(in, n);
0105 
0106         if (send >= limit || in == NULL) {
0107             return in;
0108         }
0109     }
0110 }
0111 
0112 
0113 static ngx_chain_t *
0114 ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, ngx_log_t *log)
0115 {
0116     size_t         total, size;
0117     u_char        *prev;
0118     ngx_uint_t     n, flush;
0119     ngx_chain_t   *cl;
0120     struct iovec  *iov;
0121 
0122     cl = in;
0123     iov = NULL;
0124     prev = NULL;
0125     total = 0;
0126     n = 0;
0127     flush = 0;
0128 
0129     for ( /* void */ ; in && !flush; in = in->next) {
0130 
0131         if (in->buf->flush || in->buf->last_buf) {
0132             flush = 1;
0133         }
0134 
0135         if (ngx_buf_special(in->buf)) {
0136             continue;
0137         }
0138 
0139         if (in->buf->in_file) {
0140             break;
0141         }
0142 
0143         if (!ngx_buf_in_memory(in->buf)) {
0144             ngx_log_error(NGX_LOG_ALERT, log, 0,
0145                           "bad buf in output chain "
0146                           "t:%d r:%d f:%d %p %p-%p %p %O-%O",
0147                           in->buf->temporary,
0148                           in->buf->recycled,
0149                           in->buf->in_file,
0150                           in->buf->start,
0151                           in->buf->pos,
0152                           in->buf->last,
0153                           in->buf->file,
0154                           in->buf->file_pos,
0155                           in->buf->file_last);
0156 
0157             ngx_debug_point();
0158 
0159             return NGX_CHAIN_ERROR;
0160         }
0161 
0162         size = in->buf->last - in->buf->pos;
0163 
0164         if (prev == in->buf->pos) {
0165             iov->iov_len += size;
0166 
0167         } else {
0168             if (n == vec->nalloc) {
0169                 ngx_log_error(NGX_LOG_ALERT, log, 0,
0170                               "too many parts in a datagram");
0171                 return NGX_CHAIN_ERROR;
0172             }
0173 
0174             iov = &vec->iovs[n++];
0175 
0176             iov->iov_base = (void *) in->buf->pos;
0177             iov->iov_len = size;
0178         }
0179 
0180         prev = in->buf->pos + size;
0181         total += size;
0182     }
0183 
0184     if (!flush) {
0185 #if (NGX_SUPPRESS_WARN)
0186         vec->size = 0;
0187         vec->count = 0;
0188 #endif
0189         return cl;
0190     }
0191 
0192     vec->count = n;
0193     vec->size = total;
0194 
0195     return in;
0196 }
0197 
0198 
0199 static ssize_t
0200 ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec)
0201 {
0202     ssize_t        n;
0203     ngx_err_t      err;
0204     struct msghdr  msg;
0205 
0206 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
0207 
0208 #if (NGX_HAVE_IP_SENDSRCADDR)
0209     u_char         msg_control[CMSG_SPACE(sizeof(struct in_addr))];
0210 #elif (NGX_HAVE_IP_PKTINFO)
0211     u_char         msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))];
0212 #endif
0213 
0214 #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
0215     u_char         msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
0216 #endif
0217 
0218 #endif
0219 
0220     ngx_memzero(&msg, sizeof(struct msghdr));
0221 
0222     if (c->socklen) {
0223         msg.msg_name = c->sockaddr;
0224         msg.msg_namelen = c->socklen;
0225     }
0226 
0227     msg.msg_iov = vec->iovs;
0228     msg.msg_iovlen = vec->count;
0229 
0230 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
0231 
0232     if (c->listening && c->listening->wildcard && c->local_sockaddr) {
0233 
0234 #if (NGX_HAVE_IP_SENDSRCADDR)
0235 
0236         if (c->local_sockaddr->sa_family == AF_INET) {
0237             struct cmsghdr      *cmsg;
0238             struct in_addr      *addr;
0239             struct sockaddr_in  *sin;
0240 
0241             msg.msg_control = &msg_control;
0242             msg.msg_controllen = sizeof(msg_control);
0243 
0244             cmsg = CMSG_FIRSTHDR(&msg);
0245             cmsg->cmsg_level = IPPROTO_IP;
0246             cmsg->cmsg_type = IP_SENDSRCADDR;
0247             cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
0248 
0249             sin = (struct sockaddr_in *) c->local_sockaddr;
0250 
0251             addr = (struct in_addr *) CMSG_DATA(cmsg);
0252             *addr = sin->sin_addr;
0253         }
0254 
0255 #elif (NGX_HAVE_IP_PKTINFO)
0256 
0257         if (c->local_sockaddr->sa_family == AF_INET) {
0258             struct cmsghdr      *cmsg;
0259             struct in_pktinfo   *pkt;
0260             struct sockaddr_in  *sin;
0261 
0262             msg.msg_control = &msg_control;
0263             msg.msg_controllen = sizeof(msg_control);
0264 
0265             cmsg = CMSG_FIRSTHDR(&msg);
0266             cmsg->cmsg_level = IPPROTO_IP;
0267             cmsg->cmsg_type = IP_PKTINFO;
0268             cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
0269 
0270             sin = (struct sockaddr_in *) c->local_sockaddr;
0271 
0272             pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
0273             ngx_memzero(pkt, sizeof(struct in_pktinfo));
0274             pkt->ipi_spec_dst = sin->sin_addr;
0275         }
0276 
0277 #endif
0278 
0279 #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
0280 
0281         if (c->local_sockaddr->sa_family == AF_INET6) {
0282             struct cmsghdr       *cmsg;
0283             struct in6_pktinfo   *pkt6;
0284             struct sockaddr_in6  *sin6;
0285 
0286             msg.msg_control = &msg_control6;
0287             msg.msg_controllen = sizeof(msg_control6);
0288 
0289             cmsg = CMSG_FIRSTHDR(&msg);
0290             cmsg->cmsg_level = IPPROTO_IPV6;
0291             cmsg->cmsg_type = IPV6_PKTINFO;
0292             cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
0293 
0294             sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
0295 
0296             pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
0297             ngx_memzero(pkt6, sizeof(struct in6_pktinfo));
0298             pkt6->ipi6_addr = sin6->sin6_addr;
0299         }
0300 
0301 #endif
0302     }
0303 
0304 #endif
0305 
0306 eintr:
0307 
0308     n = sendmsg(c->fd, &msg, 0);
0309 
0310     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
0311                    "sendmsg: %z of %uz", n, vec->size);
0312 
0313     if (n == -1) {
0314         err = ngx_errno;
0315 
0316         switch (err) {
0317         case NGX_EAGAIN:
0318             ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
0319                            "sendmsg() not ready");
0320             return NGX_AGAIN;
0321 
0322         case NGX_EINTR:
0323             ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
0324                            "sendmsg() was interrupted");
0325             goto eintr;
0326 
0327         default:
0328             c->write->error = 1;
0329             ngx_connection_error(c, err, "sendmsg() failed");
0330             return NGX_ERROR;
0331         }
0332     }
0333 
0334     return n;
0335 }