src/os/unix/ngx_readv_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. ssize_t
  9. ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit)
  10. {
  11.     u_char        *prev;
  12.     ssize_t        n, size;
  13.     ngx_err_t      err;
  14.     ngx_array_t    vec;
  15.     ngx_event_t   *rev;
  16.     struct iovec  *iov, iovs[NGX_IOVS_PREALLOCATE];

  17.     rev = c->read;

  18. #if (NGX_HAVE_KQUEUE)

  19.     if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
  20.         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
  21.                        "readv: eof:%d, avail:%d, err:%d",
  22.                        rev->pending_eof, rev->available, rev->kq_errno);

  23.         if (rev->available == 0) {
  24.             if (rev->pending_eof) {
  25.                 rev->ready = 0;
  26.                 rev->eof = 1;

  27.                 ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno,
  28.                               "kevent() reported about an closed connection");

  29.                 if (rev->kq_errno) {
  30.                     rev->error = 1;
  31.                     ngx_set_socket_errno(rev->kq_errno);
  32.                     return NGX_ERROR;
  33.                 }

  34.                 return 0;

  35.             } else {
  36.                 rev->ready = 0;
  37.                 return NGX_AGAIN;
  38.             }
  39.         }
  40.     }

  41. #endif

  42. #if (NGX_HAVE_EPOLLRDHUP)

  43.     if ((ngx_event_flags & NGX_USE_EPOLL_EVENT)
  44.         && ngx_use_epoll_rdhup)
  45.     {
  46.         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
  47.                        "readv: eof:%d, avail:%d",
  48.                        rev->pending_eof, rev->available);

  49.         if (rev->available == 0 && !rev->pending_eof) {
  50.             rev->ready = 0;
  51.             return NGX_AGAIN;
  52.         }
  53.     }

  54. #endif

  55.     prev = NULL;
  56.     iov = NULL;
  57.     size = 0;

  58.     vec.elts = iovs;
  59.     vec.nelts = 0;
  60.     vec.size = sizeof(struct iovec);
  61.     vec.nalloc = NGX_IOVS_PREALLOCATE;
  62.     vec.pool = c->pool;

  63.     /* coalesce the neighbouring bufs */

  64.     while (chain) {
  65.         n = chain->buf->end - chain->buf->last;

  66.         if (limit) {
  67.             if (size >= limit) {
  68.                 break;
  69.             }

  70.             if (size + n > limit) {
  71.                 n = (ssize_t) (limit - size);
  72.             }
  73.         }

  74.         if (prev == chain->buf->last) {
  75.             iov->iov_len += n;

  76.         } else {
  77.             if (vec.nelts == vec.nalloc) {
  78.                 break;
  79.             }

  80.             iov = ngx_array_push(&vec);
  81.             if (iov == NULL) {
  82.                 return NGX_ERROR;
  83.             }

  84.             iov->iov_base = (void *) chain->buf->last;
  85.             iov->iov_len = n;
  86.         }

  87.         size += n;
  88.         prev = chain->buf->end;
  89.         chain = chain->next;
  90.     }

  91.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
  92.                    "readv: %ui, last:%uz", vec.nelts, iov->iov_len);

  93.     do {
  94.         n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts);

  95.         if (n == 0) {
  96.             rev->ready = 0;
  97.             rev->eof = 1;

  98. #if (NGX_HAVE_KQUEUE)

  99.             /*
  100.              * on FreeBSD readv() may return 0 on closed socket
  101.              * even if kqueue reported about available data
  102.              */

  103.             if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
  104.                 rev->available = 0;
  105.             }

  106. #endif

  107.             return 0;
  108.         }

  109.         if (n > 0) {

  110. #if (NGX_HAVE_KQUEUE)

  111.             if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
  112.                 rev->available -= n;

  113.                 /*
  114.                  * rev->available may be negative here because some additional
  115.                  * bytes may be received between kevent() and readv()
  116.                  */

  117.                 if (rev->available <= 0) {
  118.                     if (!rev->pending_eof) {
  119.                         rev->ready = 0;
  120.                     }

  121.                     rev->available = 0;
  122.                 }

  123.                 return n;
  124.             }

  125. #endif

  126. #if (NGX_HAVE_FIONREAD)

  127.             if (rev->available >= 0) {
  128.                 rev->available -= n;

  129.                 /*
  130.                  * negative rev->available means some additional bytes
  131.                  * were received between kernel notification and readv(),
  132.                  * and therefore ev->ready can be safely reset even for
  133.                  * edge-triggered event methods
  134.                  */

  135.                 if (rev->available < 0) {
  136.                     rev->available = 0;
  137.                     rev->ready = 0;
  138.                 }

  139.                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
  140.                                "readv: avail:%d", rev->available);

  141.             } else if (n == size) {

  142.                 if (ngx_socket_nread(c->fd, &rev->available) == -1) {
  143.                     n = ngx_connection_error(c, ngx_socket_errno,
  144.                                              ngx_socket_nread_n " failed");
  145.                     break;
  146.                 }

  147.                 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
  148.                                "readv: avail:%d", rev->available);
  149.             }

  150. #endif

  151. #if (NGX_HAVE_EPOLLRDHUP)

  152.             if ((ngx_event_flags & NGX_USE_EPOLL_EVENT)
  153.                 && ngx_use_epoll_rdhup)
  154.             {
  155.                 if (n < size) {
  156.                     if (!rev->pending_eof) {
  157.                         rev->ready = 0;
  158.                     }

  159.                     rev->available = 0;
  160.                 }

  161.                 return n;
  162.             }

  163. #endif

  164.             if (n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) {
  165.                 rev->ready = 0;
  166.             }

  167.             return n;
  168.         }

  169.         err = ngx_socket_errno;

  170.         if (err == NGX_EAGAIN || err == NGX_EINTR) {
  171.             ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
  172.                            "readv() not ready");
  173.             n = NGX_AGAIN;

  174.         } else {
  175.             n = ngx_connection_error(c, err, "readv() failed");
  176.             break;
  177.         }

  178.     } while (err == NGX_EINTR);

  179.     rev->ready = 0;

  180.     if (n == NGX_ERROR) {
  181.         c->read->error = 1;
  182.     }

  183.     return n;
  184. }