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

Functions defined

Macros 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. /*
  9. * On Linux up to 2.4.21 sendfile() (syscall #187) works with 32-bit
  10. * offsets only, and the including <sys/sendfile.h> breaks the compiling,
  11. * if off_t is 64 bit wide.  So we use own sendfile() definition, where offset
  12. * parameter is int32_t, and use sendfile() for the file parts below 2G only,
  13. * see src/os/unix/ngx_linux_config.h
  14. *
  15. * Linux 2.4.21 has the new sendfile64() syscall #239.
  16. *
  17. * On Linux up to 2.6.16 sendfile() does not allow to pass the count parameter
  18. * more than 2G-1 bytes even on 64-bit platforms: it returns EINVAL,
  19. * so we limit it to 2G-1 bytes.
  20. */

  21. #define NGX_SENDFILE_MAXSIZE  2147483647L


  22. ngx_chain_t *
  23. ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
  24. {
  25.     int            tcp_nodelay;
  26.     off_t          send, prev_send, sent;
  27.     size_t         file_size;
  28.     ssize_t        n;
  29.     ngx_err_t      err;
  30.     ngx_buf_t     *file;
  31.     ngx_uint_t     eintr;
  32.     ngx_event_t   *wev;
  33.     ngx_chain_t   *cl;
  34.     ngx_iovec_t    header;
  35.     struct iovec   headers[NGX_IOVS_PREALLOCATE];
  36. #if (NGX_HAVE_SENDFILE64)
  37.     off_t          offset;
  38. #else
  39.     int32_t        offset;
  40. #endif

  41.     wev = c->write;

  42.     if (!wev->ready) {
  43.         return in;
  44.     }


  45.     /* the maximum limit size is 2G-1 - the page size */

  46.     if (limit == 0 || limit > (off_t) (NGX_SENDFILE_MAXSIZE - ngx_pagesize)) {
  47.         limit = NGX_SENDFILE_MAXSIZE - ngx_pagesize;
  48.     }


  49.     send = 0;

  50.     header.iovs = headers;
  51.     header.nalloc = NGX_IOVS_PREALLOCATE;

  52.     for ( ;; ) {
  53.         eintr = 0;
  54.         prev_send = send;

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

  56.         cl = ngx_output_chain_to_iovec(&header, in, limit - send, c->log);

  57.         if (cl == NGX_CHAIN_ERROR) {
  58.             return NGX_CHAIN_ERROR;
  59.         }

  60.         send += header.size;

  61.         /* set TCP_CORK if there is a header before a file */

  62.         if (c->tcp_nopush == NGX_TCP_NOPUSH_UNSET
  63.             && header.count != 0
  64.             && cl
  65.             && cl->buf->in_file)
  66.         {
  67.             /* the TCP_CORK and TCP_NODELAY are mutually exclusive */

  68.             if (c->tcp_nodelay == NGX_TCP_NODELAY_SET) {

  69.                 tcp_nodelay = 0;

  70.                 if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY,
  71.                                (const void *) &tcp_nodelay, sizeof(int)) == -1)
  72.                 {
  73.                     err = ngx_socket_errno;

  74.                     /*
  75.                      * there is a tiny chance to be interrupted, however,
  76.                      * we continue a processing with the TCP_NODELAY
  77.                      * and without the TCP_CORK
  78.                      */

  79.                     if (err != NGX_EINTR) {
  80.                         wev->error = 1;
  81.                         ngx_connection_error(c, err,
  82.                                              "setsockopt(TCP_NODELAY) failed");
  83.                         return NGX_CHAIN_ERROR;
  84.                     }

  85.                 } else {
  86.                     c->tcp_nodelay = NGX_TCP_NODELAY_UNSET;

  87.                     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
  88.                                    "no tcp_nodelay");
  89.                 }
  90.             }

  91.             if (c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {

  92.                 if (ngx_tcp_nopush(c->fd) == NGX_ERROR) {
  93.                     err = ngx_socket_errno;

  94.                     /*
  95.                      * there is a tiny chance to be interrupted, however,
  96.                      * we continue a processing without the TCP_CORK
  97.                      */

  98.                     if (err != NGX_EINTR) {
  99.                         wev->error = 1;
  100.                         ngx_connection_error(c, err,
  101.                                              ngx_tcp_nopush_n " failed");
  102.                         return NGX_CHAIN_ERROR;
  103.                     }

  104.                 } else {
  105.                     c->tcp_nopush = NGX_TCP_NOPUSH_SET;

  106.                     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
  107.                                    "tcp_nopush");
  108.                 }
  109.             }
  110.         }

  111.         /* get the file buf */

  112.         if (header.count == 0 && cl && cl->buf->in_file && send < limit) {
  113.             file = cl->buf;

  114.             /* coalesce the neighbouring file bufs */

  115.             file_size = (size_t) ngx_chain_coalesce_file(&cl, limit - send);

  116.             send += file_size;
  117. #if 1
  118.             if (file_size == 0) {
  119.                 ngx_debug_point();
  120.                 return NGX_CHAIN_ERROR;
  121.             }
  122. #endif
  123. #if (NGX_HAVE_SENDFILE64)
  124.             offset = file->file_pos;
  125. #else
  126.             offset = (int32_t) file->file_pos;
  127. #endif

  128.             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
  129.                            "sendfile: @%O %uz", file->file_pos, file_size);

  130.             n = sendfile(c->fd, file->file->fd, &offset, file_size);

  131.             if (n == -1) {
  132.                 err = ngx_errno;

  133.                 switch (err) {
  134.                 case NGX_EAGAIN:
  135.                     break;

  136.                 case NGX_EINTR:
  137.                     eintr = 1;
  138.                     break;

  139.                 default:
  140.                     wev->error = 1;
  141.                     ngx_connection_error(c, err, "sendfile() failed");
  142.                     return NGX_CHAIN_ERROR;
  143.                 }

  144.                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
  145.                                "sendfile() is not ready");
  146.             }

  147.             sent = n > 0 ? n : 0;

  148.             ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
  149.                            "sendfile: %z, @%O %O:%uz",
  150.                            n, file->file_pos, sent, file_size);

  151.         } else {
  152.             n = ngx_writev(c, &header);

  153.             if (n == NGX_ERROR) {
  154.                 return NGX_CHAIN_ERROR;
  155.             }

  156.             sent = (n == NGX_AGAIN) ? 0 : n;
  157.         }

  158.         c->sent += sent;

  159.         in = ngx_chain_update_sent(in, sent);

  160.         if (eintr) {
  161.             send = prev_send;
  162.             continue;
  163.         }

  164.         if (send - prev_send != sent) {
  165.             wev->ready = 0;
  166.             return in;
  167.         }

  168.         if (send >= limit || in == NULL) {
  169.             return in;
  170.         }
  171.     }
  172. }