summaryrefslogtreecommitdiffstats
path: root/usr.sbin/nginx/src/os/unix/ngx_readv_chain.c
diff options
context:
space:
mode:
authorrobert <robert@openbsd.org>2011-09-22 23:32:10 +0000
committerrobert <robert@openbsd.org>2011-09-22 23:32:10 +0000
commit40ffe171a7951d3019b3c8b488be87bfad405509 (patch)
tree7634bff211814a539a15e4e34db747e4d7b46006 /usr.sbin/nginx/src/os/unix/ngx_readv_chain.c
parentAlways install all manuals on all architectures. (diff)
downloadwireguard-openbsd-40ffe171a7951d3019b3c8b488be87bfad405509.tar.xz
wireguard-openbsd-40ffe171a7951d3019b3c8b488be87bfad405509.zip
import of nginx 1.0.6 with a bundled libpcre needed for pcre to work
properly. this is not yet linked to the build but we would like to work on it in tree to provide an apache replacement for base
Diffstat (limited to 'usr.sbin/nginx/src/os/unix/ngx_readv_chain.c')
-rw-r--r--usr.sbin/nginx/src/os/unix/ngx_readv_chain.c257
1 files changed, 257 insertions, 0 deletions
diff --git a/usr.sbin/nginx/src/os/unix/ngx_readv_chain.c b/usr.sbin/nginx/src/os/unix/ngx_readv_chain.c
new file mode 100644
index 00000000000..b65a0d7b85e
--- /dev/null
+++ b/usr.sbin/nginx/src/os/unix/ngx_readv_chain.c
@@ -0,0 +1,257 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+#define NGX_IOVS 16
+
+
+#if (NGX_HAVE_KQUEUE)
+
+ssize_t
+ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain)
+{
+ 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];
+
+ rev = c->read;
+
+ 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;
+ }
+ }
+ }
+
+ prev = NULL;
+ iov = NULL;
+ size = 0;
+
+ vec.elts = iovs;
+ vec.nelts = 0;
+ vec.size = sizeof(struct iovec);
+ vec.nalloc = NGX_IOVS;
+ vec.pool = c->pool;
+
+ /* coalesce the neighbouring bufs */
+
+ while (chain) {
+ if (prev == chain->buf->last) {
+ iov->iov_len += chain->buf->end - chain->buf->last;
+
+ } else {
+ iov = ngx_array_push(&vec);
+ if (iov == NULL) {
+ return NGX_ERROR;
+ }
+
+ iov->iov_base = (void *) chain->buf->last;
+ iov->iov_len = chain->buf->end - chain->buf->last;
+ }
+
+ size += chain->buf->end - chain->buf->last;
+ prev = chain->buf->end;
+ chain = chain->next;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "readv: %d, last:%d", vec.nelts, iov->iov_len);
+
+ rev = c->read;
+
+ do {
+ n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts);
+
+ if (n >= 0) {
+ 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 recv()
+ */
+
+ if (rev->available <= 0) {
+ if (!rev->pending_eof) {
+ rev->ready = 0;
+ }
+
+ if (rev->available < 0) {
+ rev->available = 0;
+ }
+ }
+
+ if (n == 0) {
+
+ /*
+ * on FreeBSD recv() may return 0 on closed socket
+ * even if kqueue reported about available data
+ */
+
+#if 0
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+ "readv() returned 0 while kevent() reported "
+ "%d available bytes", rev->available);
+#endif
+
+ rev->eof = 1;
+ rev->available = 0;
+ }
+
+ return n;
+ }
+
+ if (n < size) {
+ rev->ready = 0;
+ }
+
+ if (n == 0) {
+ rev->eof = 1;
+ }
+
+ 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;
+}
+
+#else /* ! NGX_HAVE_KQUEUE */
+
+ssize_t
+ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain)
+{
+ 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];
+
+ prev = NULL;
+ iov = NULL;
+ size = 0;
+
+ vec.elts = iovs;
+ vec.nelts = 0;
+ vec.size = sizeof(struct iovec);
+ vec.nalloc = NGX_IOVS;
+ vec.pool = c->pool;
+
+ /* coalesce the neighbouring bufs */
+
+ while (chain) {
+ if (prev == chain->buf->last) {
+ iov->iov_len += chain->buf->end - chain->buf->last;
+
+ } else {
+ iov = ngx_array_push(&vec);
+ if (iov == NULL) {
+ return NGX_ERROR;
+ }
+
+ iov->iov_base = (void *) chain->buf->last;
+ iov->iov_len = chain->buf->end - chain->buf->last;
+ }
+
+ size += chain->buf->end - chain->buf->last;
+ prev = chain->buf->end;
+ chain = chain->next;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "readv: %d:%d", vec.nelts, iov->iov_len);
+
+ rev = c->read;
+
+ do {
+ n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts);
+
+ if (n == 0) {
+ rev->ready = 0;
+ rev->eof = 1;
+
+ return n;
+
+ } else if (n > 0) {
+
+ 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;
+}
+
+#endif /* NGX_HAVE_KQUEUE */