Mercurial > hg > nginx
view src/os/unix/ngx_readv_chain.c @ 7278:eca3e054e978
Removed glibc crypt_r() bug workaround (ticket #1469).
The bug in question was fixed in glibc 2.3.2 and is no longer expected
to manifest itself on real servers. On the other hand, the workaround
causes compilation problems on various systems. Previously, we've
already fixed the code to compile with musl libc (fd6fd02f6a4d), and
now it is broken on Fedora 28 where glibc's crypt library was replaced
by libxcrypt. So the workaround was removed.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Wed, 23 May 2018 16:38:16 +0300 |
parents | f7849bfb6d21 |
children | efd71d49bde0 |
line wrap: on
line source
/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #include <ngx_config.h> #include <ngx_core.h> #include <ngx_event.h> ssize_t ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) { u_char *prev; ssize_t n, size; ngx_err_t err; ngx_array_t vec; ngx_event_t *rev; struct iovec *iov, iovs[NGX_IOVS_PREALLOCATE]; rev = c->read; #if (NGX_HAVE_KQUEUE) if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "readv: eof:%d, avail:%d, err:%d", rev->pending_eof, rev->available, rev->kq_errno); if (rev->available == 0) { if (rev->pending_eof) { rev->ready = 0; rev->eof = 1; ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno, "kevent() reported about an closed connection"); if (rev->kq_errno) { rev->error = 1; ngx_set_socket_errno(rev->kq_errno); return NGX_ERROR; } return 0; } else { return NGX_AGAIN; } } } #endif #if (NGX_HAVE_EPOLLRDHUP) if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "readv: eof:%d, avail:%d", rev->pending_eof, rev->available); if (!rev->available && !rev->pending_eof) { return NGX_AGAIN; } } #endif prev = NULL; iov = NULL; size = 0; vec.elts = iovs; vec.nelts = 0; vec.size = sizeof(struct iovec); vec.nalloc = NGX_IOVS_PREALLOCATE; vec.pool = c->pool; /* coalesce the neighbouring bufs */ while (chain) { n = chain->buf->end - chain->buf->last; if (limit) { if (size >= limit) { break; } if (size + n > limit) { n = (ssize_t) (limit - size); } } if (prev == chain->buf->last) { iov->iov_len += n; } else { if (vec.nelts >= IOV_MAX) { break; } iov = ngx_array_push(&vec); if (iov == NULL) { return NGX_ERROR; } iov->iov_base = (void *) chain->buf->last; iov->iov_len = n; } size += n; prev = chain->buf->end; chain = chain->next; } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "readv: %ui, last:%uz", vec.nelts, iov->iov_len); do { n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts); if (n == 0) { rev->ready = 0; rev->eof = 1; #if (NGX_HAVE_KQUEUE) /* * on FreeBSD readv() may return 0 on closed socket * even if kqueue reported about available data */ if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { rev->available = 0; } #endif return 0; } if (n > 0) { #if (NGX_HAVE_KQUEUE) if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { rev->available -= n; /* * rev->available may be negative here because some additional * bytes may be received between kevent() and readv() */ if (rev->available <= 0) { if (!rev->pending_eof) { rev->ready = 0; } rev->available = 0; } return n; } #endif #if (NGX_HAVE_EPOLLRDHUP) if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ngx_use_epoll_rdhup) { if (n < size) { if (!rev->pending_eof) { rev->ready = 0; } rev->available = 0; } return n; } #endif if (n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) { rev->ready = 0; } return n; } err = ngx_socket_errno; if (err == NGX_EAGAIN || err == NGX_EINTR) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, "readv() not ready"); n = NGX_AGAIN; } else { n = ngx_connection_error(c, err, "readv() failed"); break; } } while (err == NGX_EINTR); rev->ready = 0; if (n == NGX_ERROR) { c->read->error = 1; } return n; }