Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.11 ]​[ nginx-1.14.2 ]​

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 /*
0014  * Although FreeBSD sendfile() allows to pass a header and a trailer,
0015  * it cannot send a header with a part of the file in one packet until
0016  * FreeBSD 5.3.  Besides, over the fast ethernet connection sendfile()
0017  * may send the partially filled packets, i.e. the 8 file pages may be sent
0018  * as the 11 full 1460-bytes packets, then one incomplete 324-bytes packet,
0019  * and then again the 11 full 1460-bytes packets.
0020  *
0021  * Therefore we use the TCP_NOPUSH option (similar to Linux's TCP_CORK)
0022  * to postpone the sending - it not only sends a header and the first part of
0023  * the file in one packet, but also sends the file pages in the full packets.
0024  *
0025  * But until FreeBSD 4.5 turning TCP_NOPUSH off does not flush a pending
0026  * data that less than MSS, so that data may be sent with 5 second delay.
0027  * So we do not use TCP_NOPUSH on FreeBSD prior to 4.5, although it can be used
0028  * for non-keepalive HTTP connections.
0029  */
0030 
0031 
0032 ngx_chain_t *
0033 ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
0034 {
0035     int               rc, flags;
0036     off_t             send, prev_send, sent;
0037     size_t            file_size;
0038     ssize_t           n;
0039     ngx_uint_t        eintr, eagain;
0040     ngx_err_t         err;
0041     ngx_buf_t        *file;
0042     ngx_event_t      *wev;
0043     ngx_chain_t      *cl;
0044     ngx_iovec_t       header, trailer;
0045     struct sf_hdtr    hdtr;
0046     struct iovec      headers[NGX_IOVS_PREALLOCATE];
0047     struct iovec      trailers[NGX_IOVS_PREALLOCATE];
0048 #if (NGX_HAVE_AIO_SENDFILE)
0049     ngx_uint_t        ebusy;
0050     ngx_event_aio_t  *aio;
0051 #endif
0052 
0053     wev = c->write;
0054 
0055     if (!wev->ready) {
0056         return in;
0057     }
0058 
0059 #if (NGX_HAVE_KQUEUE)
0060 
0061     if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) {
0062         (void) ngx_connection_error(c, wev->kq_errno,
0063                                "kevent() reported about an closed connection");
0064         wev->error = 1;
0065         return NGX_CHAIN_ERROR;
0066     }
0067 
0068 #endif
0069 
0070     /* the maximum limit size is the maximum size_t value - the page size */
0071 
0072     if (limit == 0 || limit > (off_t) (NGX_MAX_SIZE_T_VALUE - ngx_pagesize)) {
0073         limit = NGX_MAX_SIZE_T_VALUE - ngx_pagesize;
0074     }
0075 
0076     send = 0;
0077     eagain = 0;
0078     flags = 0;
0079 
0080 #if (NGX_HAVE_AIO_SENDFILE && NGX_SUPPRESS_WARN)
0081     aio = NULL;
0082     file = NULL;
0083 #endif
0084 
0085     header.iovs = headers;
0086     header.nalloc = NGX_IOVS_PREALLOCATE;
0087 
0088     trailer.iovs = trailers;
0089     trailer.nalloc = NGX_IOVS_PREALLOCATE;
0090 
0091     for ( ;; ) {
0092         eintr = 0;
0093 #if (NGX_HAVE_AIO_SENDFILE)
0094         ebusy = 0;
0095 #endif
0096         prev_send = send;
0097 
0098         /* create the header iovec and coalesce the neighbouring bufs */
0099 
0100         cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log);
0101 
0102         if (cl == NGX_CHAIN_ERROR) {
0103             return NGX_CHAIN_ERROR;
0104         }
0105 
0106         send += header.size;
0107 
0108         if (cl && cl->buf->in_file && send < limit) {
0109             file = cl->buf;
0110 
0111             /* coalesce the neighbouring file bufs */
0112 
0113             file_size = (size_t) ngx_chain_coalesce_file(&cl, limit - send);
0114 
0115             send += file_size;
0116 
0117             if (send < limit) {
0118 
0119                 /*
0120                  * create the trailer iovec and coalesce the neighbouring bufs
0121                  */
0122 
0123                 cl = ngx_output_chain_to_iovec(&trailer, cl, limit - send,
0124                                                c->log);
0125                 if (cl == NGX_CHAIN_ERROR) {
0126                     return NGX_CHAIN_ERROR;
0127                 }
0128 
0129                 send += trailer.size;
0130 
0131             } else {
0132                 trailer.count = 0;
0133             }
0134 
0135             if (ngx_freebsd_use_tcp_nopush
0136                 && c->tcp_nopush == NGX_TCP_NOPUSH_UNSET)
0137             {
0138                 if (ngx_tcp_nopush(c->fd) == -1) {
0139                     err = ngx_socket_errno;
0140 
0141                     /*
0142                      * there is a tiny chance to be interrupted, however,
0143                      * we continue a processing without the TCP_NOPUSH
0144                      */
0145 
0146                     if (err != NGX_EINTR) {
0147                         wev->error = 1;
0148                         (void) ngx_connection_error(c, err,
0149                                                     ngx_tcp_nopush_n " failed");
0150                         return NGX_CHAIN_ERROR;
0151                     }
0152 
0153                 } else {
0154                     c->tcp_nopush = NGX_TCP_NOPUSH_SET;
0155 
0156                     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
0157                                    "tcp_nopush");
0158                 }
0159             }
0160 
0161             /*
0162              * sendfile() does unneeded work if sf_hdtr's count is 0,
0163              * but corresponding pointer is not NULL
0164              */
0165 
0166             hdtr.headers = header.count ? header.iovs : NULL;
0167             hdtr.hdr_cnt = header.count;
0168             hdtr.trailers = trailer.count ? trailer.iovs : NULL;
0169             hdtr.trl_cnt = trailer.count;
0170 
0171             /*
0172              * the "nbytes bug" of the old sendfile() syscall:
0173              * http://bugs.freebsd.org/33771
0174              */
0175 
0176             if (!ngx_freebsd_sendfile_nbytes_bug) {
0177                 header.size = 0;
0178             }
0179 
0180             sent = 0;
0181 
0182 #if (NGX_HAVE_AIO_SENDFILE)
0183             aio = file->file->aio;
0184             flags = (aio && aio->preload_handler) ? SF_NODISKIO : 0;
0185 #endif
0186 
0187             rc = sendfile(file->file->fd, c->fd, file->file_pos,
0188                           file_size + header.size, &hdtr, &sent, flags);
0189 
0190             if (rc == -1) {
0191                 err = ngx_errno;
0192 
0193                 switch (err) {
0194                 case NGX_EAGAIN:
0195                     eagain = 1;
0196                     break;
0197 
0198                 case NGX_EINTR:
0199                     eintr = 1;
0200                     break;
0201 
0202 #if (NGX_HAVE_AIO_SENDFILE)
0203                 case NGX_EBUSY:
0204                     ebusy = 1;
0205                     break;
0206 #endif
0207 
0208                 default:
0209                     wev->error = 1;
0210                     (void) ngx_connection_error(c, err, "sendfile() failed");
0211                     return NGX_CHAIN_ERROR;
0212                 }
0213 
0214                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, err,
0215                                "sendfile() sent only %O bytes", sent);
0216 
0217             /*
0218              * sendfile() in FreeBSD 3.x-4.x may return value >= 0
0219              * on success, although only 0 is documented
0220              */
0221 
0222             } else if (rc >= 0 && sent == 0) {
0223 
0224                 /*
0225                  * if rc is OK and sent equal to zero, then someone
0226                  * has truncated the file, so the offset became beyond
0227                  * the end of the file
0228                  */
0229 
0230                 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
0231                          "sendfile() reported that \"%s\" was truncated at %O",
0232                          file->file->name.data, file->file_pos);
0233 
0234                 return NGX_CHAIN_ERROR;
0235             }
0236 
0237             ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
0238                            "sendfile: %d, @%O %O:%uz",
0239                            rc, file->file_pos, sent, file_size + header.size);
0240 
0241         } else {
0242             n = ngx_writev(c, &header);
0243 
0244             if (n == NGX_ERROR) {
0245                 return NGX_CHAIN_ERROR;
0246             }
0247 
0248             sent = (n == NGX_AGAIN) ? 0 : n;
0249         }
0250 
0251         c->sent += sent;
0252 
0253         in = ngx_chain_update_sent(in, sent);
0254 
0255 #if (NGX_HAVE_AIO_SENDFILE)
0256 
0257         if (ebusy) {
0258             if (aio->event.active) {
0259                 /*
0260                  * tolerate duplicate calls; they can happen due to subrequests
0261                  * or multiple calls of the next body filter from a filter
0262                  */
0263 
0264                 if (sent) {
0265                     c->busy_count = 0;
0266                 }
0267 
0268                 return in;
0269             }
0270 
0271             if (sent == 0) {
0272                 c->busy_count++;
0273 
0274                 if (c->busy_count > 2) {
0275                     ngx_log_error(NGX_LOG_ALERT, c->log, 0,
0276                                   "sendfile(%V) returned busy again",
0277                                   &file->file->name);
0278 
0279                     c->busy_count = 0;
0280                     aio->preload_handler = NULL;
0281 
0282                     send = prev_send;
0283                     continue;
0284                 }
0285 
0286             } else {
0287                 c->busy_count = 0;
0288             }
0289 
0290             n = aio->preload_handler(file);
0291 
0292             if (n > 0) {
0293                 send = prev_send + sent;
0294                 continue;
0295             }
0296 
0297             return in;
0298         }
0299 
0300         if (flags == SF_NODISKIO) {
0301             c->busy_count = 0;
0302         }
0303 
0304 #endif
0305 
0306         if (eagain) {
0307 
0308             /*
0309              * sendfile() may return EAGAIN, even if it has sent a whole file
0310              * part, it indicates that the successive sendfile() call would
0311              * return EAGAIN right away and would not send anything.
0312              * We use it as a hint.
0313              */
0314 
0315             wev->ready = 0;
0316             return in;
0317         }
0318 
0319         if (eintr) {
0320             send = prev_send + sent;
0321             continue;
0322         }
0323 
0324         if (send - prev_send != sent) {
0325             wev->ready = 0;
0326             return in;
0327         }
0328 
0329         if (send >= limit || in == NULL) {
0330             return in;
0331         }
0332     }
0333 }