summaryrefslogtreecommitdiff
path: root/data/lighttpd/lighttpd-1.4.53/src/network_write.c
diff options
context:
space:
mode:
Diffstat (limited to 'data/lighttpd/lighttpd-1.4.53/src/network_write.c')
-rw-r--r--data/lighttpd/lighttpd-1.4.53/src/network_write.c738
1 files changed, 738 insertions, 0 deletions
diff --git a/data/lighttpd/lighttpd-1.4.53/src/network_write.c b/data/lighttpd/lighttpd-1.4.53/src/network_write.c
new file mode 100644
index 000000000..325546bbf
--- /dev/null
+++ b/data/lighttpd/lighttpd-1.4.53/src/network_write.c
@@ -0,0 +1,738 @@
+#include "first.h"
+
+#include "network_write.h"
+
+#include "base.h"
+#include "log.h"
+
+#include <sys/types.h>
+#include "sys-socket.h"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+
+/* on linux 2.4.x you get either sendfile or LFS */
+#if defined HAVE_SYS_SENDFILE_H && defined HAVE_SENDFILE \
+ && (!defined _LARGEFILE_SOURCE || defined HAVE_SENDFILE64) \
+ && defined(__linux__) && !defined HAVE_SENDFILE_BROKEN
+# ifdef NETWORK_WRITE_USE_SENDFILE
+# error "can't have more than one sendfile implementation"
+# endif
+# define NETWORK_WRITE_USE_SENDFILE "linux-sendfile"
+# define NETWORK_WRITE_USE_LINUX_SENDFILE
+#endif
+
+#if defined HAVE_SENDFILE && (defined(__FreeBSD__) || defined(__DragonFly__))
+# ifdef NETWORK_WRITE_USE_SENDFILE
+# error "can't have more than one sendfile implementation"
+# endif
+# define NETWORK_WRITE_USE_SENDFILE "freebsd-sendfile"
+# define NETWORK_WRITE_USE_FREEBSD_SENDFILE
+#endif
+
+#if defined HAVE_SENDFILE && defined(__APPLE__)
+# ifdef NETWORK_WRITE_USE_SENDFILE
+# error "can't have more than one sendfile implementation"
+# endif
+# define NETWORK_WRITE_USE_SENDFILE "darwin-sendfile"
+# define NETWORK_WRITE_USE_DARWIN_SENDFILE
+#endif
+
+#if defined HAVE_SYS_SENDFILE_H && defined HAVE_SENDFILEV && defined(__sun)
+# ifdef NETWORK_WRITE_USE_SENDFILE
+# error "can't have more than one sendfile implementation"
+# endif
+# define NETWORK_WRITE_USE_SENDFILE "solaris-sendfilev"
+# define NETWORK_WRITE_USE_SOLARIS_SENDFILEV
+#endif
+
+/* not supported so far
+#if defined HAVE_SEND_FILE && defined(__aix)
+# ifdef NETWORK_WRITE_USE_SENDFILE
+# error "can't have more than one sendfile implementation"
+# endif
+# define NETWORK_WRITE_USE_SENDFILE "aix-sendfile"
+# define NETWORK_WRITE_USE_AIX_SENDFILE
+#endif
+*/
+
+#if defined HAVE_SYS_UIO_H && defined HAVE_WRITEV
+# define NETWORK_WRITE_USE_WRITEV
+#endif
+
+#if defined HAVE_SYS_MMAN_H && defined HAVE_MMAP && defined ENABLE_MMAP
+# define NETWORK_WRITE_USE_MMAP
+#endif
+
+
+static int network_write_error(server *srv, int fd) {
+ #if defined(__WIN32)
+ int lastError = WSAGetLastError();
+ switch (lastError) {
+ case WSAEINTR:
+ case WSAEWOULDBLOCK:
+ return -3;
+ case WSAECONNRESET:
+ case WSAETIMEDOUT:
+ case WSAECONNABORTED:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sdd",
+ "send failed: ", lastError, fd);
+ return -1;
+ }
+ #else /* __WIN32 */
+ switch (errno) {
+ case EAGAIN:
+ case EINTR:
+ return -3;
+ case EPIPE:
+ case ECONNRESET:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "write failed:", strerror(errno), fd);
+ return -1;
+ }
+ #endif /* __WIN32 */
+}
+
+inline
+static ssize_t network_write_data_len(int fd, const char *data, off_t len) {
+ #if defined(__WIN32)
+ return send(fd, data, len, 0);
+ #else /* __WIN32 */
+ return write(fd, data, len);
+ #endif /* __WIN32 */
+}
+
+
+
+
+/* write next chunk(s); finished chunks are removed afterwards after successful writes.
+ * return values: similar as backends (0 succes, -1 error, -2 remote close, -3 try again later (EINTR/EAGAIN)) */
+/* next chunk must be MEM_CHUNK. use write()/send() */
+static int network_write_mem_chunk(server *srv, int fd, chunkqueue *cq, off_t *p_max_bytes) {
+ chunk* const c = cq->first;
+ ssize_t wr;
+ off_t c_len = (off_t)buffer_string_length(c->mem);
+ force_assert(c->offset >= 0 && c->offset <= c_len);
+ c_len -= c->offset;
+ if (c_len > *p_max_bytes) c_len = *p_max_bytes;
+
+ if (0 == c_len) {
+ chunkqueue_remove_finished_chunks(cq);
+ return 0;
+ }
+
+ wr = network_write_data_len(fd, c->mem->ptr + c->offset, c_len);
+ if (wr >= 0) {
+ *p_max_bytes -= wr;
+ chunkqueue_mark_written(cq, wr);
+ return (wr > 0 && wr == c_len) ? 0 : -3;
+ } else {
+ return network_write_error(srv, fd);
+ }
+}
+
+
+
+
+#if !defined(NETWORK_WRITE_USE_MMAP)
+
+static int network_write_file_chunk_no_mmap(server *srv, int fd, chunkqueue *cq, off_t *p_max_bytes) {
+ chunk* const c = cq->first;
+ off_t offset, toSend;
+ ssize_t wr;
+
+ force_assert(c->offset >= 0 && c->offset <= c->file.length);
+
+ offset = c->file.start + c->offset;
+ toSend = c->file.length - c->offset;
+ if (toSend > *p_max_bytes) toSend = *p_max_bytes;
+
+ if (0 == toSend) {
+ chunkqueue_remove_finished_chunks(cq);
+ return 0;
+ }
+
+ if (0 != chunkqueue_open_file_chunk(srv, cq)) return -1;
+
+ if (toSend > 64*1024) toSend = 64*1024; /* max read 64kb in one step */
+ buffer_string_prepare_copy(srv->tmp_buf, toSend);
+
+ if (-1 == lseek(c->file.fd, offset, SEEK_SET)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss","lseek:",strerror(errno));
+ return -1;
+ }
+ if (-1 == (toSend = read(c->file.fd, srv->tmp_buf->ptr, toSend))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss","read:",strerror(errno));
+ return -1;
+ }
+
+ wr = network_write_data_len(fd, srv->tmp_buf->ptr, toSend);
+ if (wr >= 0) {
+ *p_max_bytes -= wr;
+ chunkqueue_mark_written(cq, wr);
+ return (wr > 0 && wr == toSend) ? 0 : -3;
+ } else {
+ return network_write_error(srv, fd);
+ }
+}
+
+#endif
+
+
+
+
+#if defined(NETWORK_WRITE_USE_MMAP)
+
+#include "sys-mmap.h"
+
+#include <setjmp.h>
+#include <signal.h>
+
+#define MMAP_CHUNK_SIZE (512*1024)
+
+static off_t mmap_align_offset(off_t start) {
+ static long pagesize = 0;
+ if (0 == pagesize) {
+ pagesize = sysconf(_SC_PAGESIZE);
+ force_assert(pagesize < MMAP_CHUNK_SIZE);
+ }
+ force_assert(start >= (start % pagesize));
+ return start - (start % pagesize);
+}
+
+static volatile int sigbus_jmp_valid;
+static sigjmp_buf sigbus_jmp;
+
+static void sigbus_handler(int sig) {
+ UNUSED(sig);
+ if (sigbus_jmp_valid) siglongjmp(sigbus_jmp, 1);
+ log_failed_assert(__FILE__, __LINE__, "SIGBUS");
+}
+
+/* next chunk must be FILE_CHUNK. send mmap()ed file with write() */
+static int network_write_file_chunk_mmap(server *srv, int fd, chunkqueue *cq, off_t *p_max_bytes) {
+ chunk* const c = cq->first;
+ off_t offset, toSend, file_end;
+ ssize_t r;
+ size_t mmap_offset, mmap_avail;
+ const char *data;
+
+ force_assert(c->offset >= 0 && c->offset <= c->file.length);
+
+ offset = c->file.start + c->offset;
+ toSend = c->file.length - c->offset;
+ if (toSend > *p_max_bytes) toSend = *p_max_bytes;
+ file_end = c->file.start + c->file.length; /*file end offset in this chunk*/
+
+ if (0 == toSend) {
+ chunkqueue_remove_finished_chunks(cq);
+ return 0;
+ }
+
+ if (0 != chunkqueue_open_file_chunk(srv, cq)) return -1;
+
+ /* mmap buffer if offset is outside old mmap area or not mapped at all */
+ if (MAP_FAILED == c->file.mmap.start
+ || offset < c->file.mmap.offset
+ || offset >= (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
+
+ if (MAP_FAILED != c->file.mmap.start) {
+ munmap(c->file.mmap.start, c->file.mmap.length);
+ c->file.mmap.start = MAP_FAILED;
+ }
+
+ /* Optimizations for the future:
+ *
+ * adaptive mem-mapping
+ * the problem:
+ * we mmap() the whole file. If someone has alot large files and
+ * 32-bit machine the virtual address area will be unrun and we
+ * will have a failing mmap() call.
+ * solution:
+ * only mmap 16M in one chunk and move the window as soon as we have
+ * finished the first 8M
+ *
+ * read-ahead buffering
+ * the problem:
+ * sending out several large files in parallel trashes read-ahead
+ * of the kernel leading to long wait-for-seek times.
+ * solutions: (increasing complexity)
+ * 1. use madvise
+ * 2. use a internal read-ahead buffer in the chunk-structure
+ * 3. use non-blocking IO for file-transfers
+ * */
+
+ c->file.mmap.offset = mmap_align_offset(offset);
+
+ /* all mmap()ed areas are MMAP_CHUNK_SIZE
+ * except the last which might be smaller */
+ c->file.mmap.length = MMAP_CHUNK_SIZE;
+ if (c->file.mmap.offset > file_end - (off_t)c->file.mmap.length) {
+ c->file.mmap.length = file_end - c->file.mmap.offset;
+ }
+
+ c->file.mmap.start = mmap(NULL, c->file.mmap.length, PROT_READ,
+ MAP_SHARED, c->file.fd, c->file.mmap.offset);
+ if (MAP_FAILED == c->file.mmap.start) {
+ log_error_write(srv, __FILE__, __LINE__, "ssbdoo", "mmap failed:",
+ strerror(errno), c->mem, c->file.fd,
+ c->file.mmap.offset, (off_t) c->file.mmap.length);
+ return -1;
+ }
+
+ #if defined(HAVE_MADVISE)
+ /* don't advise files < 64Kb */
+ if (c->file.mmap.length > (64*1024)) {
+ /* darwin 7 is returning EINVAL all the time and I don't know how to
+ * detect this at runtime.
+ *
+ * ignore the return value for now */
+ madvise(c->file.mmap.start, c->file.mmap.length, MADV_WILLNEED);
+ }
+ #endif
+ }
+
+ force_assert(offset >= c->file.mmap.offset);
+ mmap_offset = offset - c->file.mmap.offset;
+ force_assert(c->file.mmap.length > mmap_offset);
+ mmap_avail = c->file.mmap.length - mmap_offset;
+ if (toSend > (off_t) mmap_avail) toSend = mmap_avail;
+
+ data = c->file.mmap.start + mmap_offset;
+
+ /* setup SIGBUS handler, but don't activate sigbus_jmp_valid yet */
+ if (0 == sigsetjmp(sigbus_jmp, 1)) {
+ signal(SIGBUS, sigbus_handler);
+
+ sigbus_jmp_valid = 1;
+ r = network_write_data_len(fd, data, toSend);
+ sigbus_jmp_valid = 0;
+ } else {
+ sigbus_jmp_valid = 0;
+
+ log_error_write(srv, __FILE__, __LINE__, "sbd", "SIGBUS in mmap:",
+ c->mem, c->file.fd);
+
+ munmap(c->file.mmap.start, c->file.mmap.length);
+ c->file.mmap.start = MAP_FAILED;
+ return -1;
+ }
+
+ if (r >= 0) {
+ *p_max_bytes -= r;
+ chunkqueue_mark_written(cq, r);
+ return (r > 0 && r == toSend) ? 0 : -3;
+ } else {
+ return network_write_error(srv, fd);
+ }
+}
+
+#endif /* NETWORK_WRITE_USE_MMAP */
+
+
+
+
+#if defined(NETWORK_WRITE_USE_WRITEV)
+
+#if defined(HAVE_SYS_UIO_H)
+# include <sys/uio.h>
+#endif
+
+#if defined(UIO_MAXIOV)
+# define SYS_MAX_CHUNKS UIO_MAXIOV
+#elif defined(IOV_MAX)
+/* new name for UIO_MAXIOV since IEEE Std 1003.1-2001 */
+# define SYS_MAX_CHUNKS IOV_MAX
+#elif defined(_XOPEN_IOV_MAX)
+/* minimum value for sysconf(_SC_IOV_MAX); posix requires this to be at least 16, which is good enough - no need to call sysconf() */
+# define SYS_MAX_CHUNKS _XOPEN_IOV_MAX
+#else
+# error neither UIO_MAXIOV nor IOV_MAX nor _XOPEN_IOV_MAX are defined
+#endif
+
+/* allocate iovec[MAX_CHUNKS] on stack, so pick a sane limit:
+ * - each entry will use 1 pointer + 1 size_t
+ * - 32 chunks -> 256 / 512 bytes (32-bit/64-bit pointers)
+ */
+#define STACK_MAX_ALLOC_CHUNKS 32
+#if SYS_MAX_CHUNKS > STACK_MAX_ALLOC_CHUNKS
+# define MAX_CHUNKS STACK_MAX_ALLOC_CHUNKS
+#else
+# define MAX_CHUNKS SYS_MAX_CHUNKS
+#endif
+
+/* next chunk must be MEM_CHUNK. send multiple mem chunks using writev() */
+static int network_writev_mem_chunks(server *srv, int fd, chunkqueue *cq, off_t *p_max_bytes) {
+ struct iovec chunks[MAX_CHUNKS];
+ size_t num_chunks = 0;
+ off_t max_bytes = *p_max_bytes;
+ off_t toSend = 0;
+ ssize_t r;
+
+ for (const chunk *c = cq->first;
+ NULL != c && MEM_CHUNK == c->type
+ && num_chunks < MAX_CHUNKS && toSend < max_bytes;
+ c = c->next) {
+ size_t c_len = buffer_string_length(c->mem);
+ force_assert(c->offset >= 0 && c->offset <= (off_t)c_len);
+ c_len -= c->offset;
+ if (c_len > 0) {
+ toSend += c_len;
+
+ chunks[num_chunks].iov_base = c->mem->ptr + c->offset;
+ chunks[num_chunks].iov_len = c_len;
+
+ ++num_chunks;
+ }
+ }
+
+ if (0 == num_chunks) {
+ chunkqueue_remove_finished_chunks(cq);
+ return 0;
+ }
+
+ r = writev(fd, chunks, num_chunks);
+
+ if (r < 0) switch (errno) {
+ case EAGAIN:
+ case EINTR:
+ break;
+ case EPIPE:
+ case ECONNRESET:
+ return -2;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssd",
+ "writev failed:", strerror(errno), fd);
+ return -1;
+ }
+
+ if (r >= 0) {
+ *p_max_bytes -= r;
+ chunkqueue_mark_written(cq, r);
+ }
+
+ return (r > 0 && r == toSend) ? 0 : -3;
+}
+
+#endif /* NETWORK_WRITE_USE_WRITEV */
+
+
+
+
+#if defined(NETWORK_WRITE_USE_SENDFILE)
+
+#if defined(NETWORK_WRITE_USE_LINUX_SENDFILE) \
+ || defined(NETWORK_WRITE_USE_SOLARIS_SENDFILEV)
+#include <sys/sendfile.h>
+#endif
+
+#if defined(NETWORK_WRITE_USE_FREEBSD_SENDFILE) \
+ || defined(NETWORK_WRITE_USE_DARWIN_SENDFILE)
+#include <sys/uio.h>
+#endif
+
+static int network_write_file_chunk_sendfile(server *srv, int fd, chunkqueue *cq, off_t *p_max_bytes) {
+ chunk * const c = cq->first;
+ ssize_t r;
+ off_t offset;
+ off_t toSend;
+ off_t written = 0;
+
+ force_assert(c->offset >= 0 && c->offset <= c->file.length);
+
+ offset = c->file.start + c->offset;
+ toSend = c->file.length - c->offset;
+ if (toSend > *p_max_bytes) toSend = *p_max_bytes;
+
+ if (0 == toSend) {
+ chunkqueue_remove_finished_chunks(cq);
+ return 0;
+ }
+
+ if (0 != chunkqueue_open_file_chunk(srv, cq)) return -1;
+
+ /* Darwin, FreeBSD, and Solaris variants support iovecs and could
+ * be optimized to send more than just file in single syscall */
+
+ #if defined(NETWORK_WRITE_USE_LINUX_SENDFILE)
+
+ r = sendfile(fd, c->file.fd, &offset, toSend);
+ if (r > 0) written = (off_t)r;
+
+ #elif defined(NETWORK_WRITE_USE_DARWIN_SENDFILE)
+
+ written = toSend;
+ r = sendfile(c->file.fd, fd, offset, &written, NULL, 0);
+ /* (for EAGAIN/EINTR written still contains the sent bytes) */
+
+ #elif defined(NETWORK_WRITE_USE_FREEBSD_SENDFILE)
+
+ r = sendfile(c->file.fd, fd, offset, toSend, NULL, &written, 0);
+ /* (for EAGAIN/EINTR written still contains the sent bytes) */
+
+ #elif defined(NETWORK_WRITE_USE_SOLARIS_SENDFILEV)
+ {
+ sendfilevec_t fvec;
+ fvec.sfv_fd = c->file.fd;
+ fvec.sfv_flag = 0;
+ fvec.sfv_off = offset;
+ fvec.sfv_len = toSend;
+
+ /* Solaris sendfilev() */
+ r = sendfilev(fd, &fvec, 1, (size_t *)&written);
+ /* (for EAGAIN/EINTR written still contains the sent bytes) */
+ }
+ #else
+
+ r = -1;
+ errno = ENOSYS;
+
+ #endif
+
+ if (-1 == r) {
+ switch(errno) {
+ case EAGAIN:
+ case EINTR:
+ break; /* try again later */
+ case EPIPE:
+ case ECONNRESET:
+ case ENOTCONN:
+ return -2;
+ case EINVAL:
+ case ENOSYS:
+ #if defined(ENOTSUP) && (!defined(EOPNOTSUPP) || EOPNOTSUPP != ENOTSUP)
+ case ENOTSUP:
+ #endif
+ #ifdef EOPNOTSUPP
+ case EOPNOTSUPP:
+ #endif
+ #ifdef ESOCKTNOSUPPORT
+ case ESOCKTNOSUPPORT:
+ #endif
+ #ifdef EAFNOSUPPORT
+ case EAFNOSUPPORT:
+ #endif
+ #ifdef NETWORK_WRITE_USE_MMAP
+ return network_write_file_chunk_mmap(srv, fd, cq, p_max_bytes);
+ #else
+ return network_write_file_chunk_no_mmap(srv, fd, cq, p_max_bytes);
+ #endif
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssdSd",
+ "sendfile():", strerror(errno), errno, "fd:", fd);
+ return -1;
+ }
+ }
+
+ if (written >= 0) { /*(always true)*/
+ chunkqueue_mark_written(cq, written);
+ *p_max_bytes -= written;
+ }
+
+ return (r >= 0 && written == toSend) ? 0 : -3;
+}
+
+#endif
+
+
+
+
+/* return values:
+ * >= 0 : no error
+ * -1 : error (on our side)
+ * -2 : remote close
+ */
+
+static int network_write_chunkqueue_write(server *srv, int fd, chunkqueue *cq, off_t max_bytes) {
+ while (max_bytes > 0 && NULL != cq->first) {
+ int r = -1;
+
+ switch (cq->first->type) {
+ case MEM_CHUNK:
+ r = network_write_mem_chunk(srv, fd, cq, &max_bytes);
+ break;
+ case FILE_CHUNK:
+ #ifdef NETWORK_WRITE_USE_MMAP
+ r = network_write_file_chunk_mmap(srv, fd, cq, &max_bytes);
+ #else
+ r = network_write_file_chunk_no_mmap(srv, fd, cq, &max_bytes);
+ #endif
+ break;
+ }
+
+ if (-3 == r) return 0;
+ if (0 != r) return r;
+ }
+
+ return 0;
+}
+
+#if defined(NETWORK_WRITE_USE_WRITEV)
+static int network_write_chunkqueue_writev(server *srv, int fd, chunkqueue *cq, off_t max_bytes) {
+ while (max_bytes > 0 && NULL != cq->first) {
+ int r = -1;
+
+ switch (cq->first->type) {
+ case MEM_CHUNK:
+ #if defined(NETWORK_WRITE_USE_WRITEV)
+ r = network_writev_mem_chunks(srv, fd, cq, &max_bytes);
+ #else
+ r = network_write_mem_chunk(srv, fd, cq, &max_bytes);
+ #endif
+ break;
+ case FILE_CHUNK:
+ #ifdef NETWORK_WRITE_USE_MMAP
+ r = network_write_file_chunk_mmap(srv, fd, cq, &max_bytes);
+ #else
+ r = network_write_file_chunk_no_mmap(srv, fd, cq, &max_bytes);
+ #endif
+ break;
+ }
+
+ if (-3 == r) return 0;
+ if (0 != r) return r;
+ }
+
+ return 0;
+}
+#endif
+
+#if defined(NETWORK_WRITE_USE_SENDFILE)
+static int network_write_chunkqueue_sendfile(server *srv, int fd, chunkqueue *cq, off_t max_bytes) {
+ while (max_bytes > 0 && NULL != cq->first) {
+ int r = -1;
+
+ switch (cq->first->type) {
+ case MEM_CHUNK:
+ #if defined(NETWORK_WRITE_USE_WRITEV)
+ r = network_writev_mem_chunks(srv, fd, cq, &max_bytes);
+ #else
+ r = network_write_mem_chunk(srv, fd, cq, &max_bytes);
+ #endif
+ break;
+ case FILE_CHUNK:
+ #if defined(NETWORK_WRITE_USE_SENDFILE)
+ r = network_write_file_chunk_sendfile(srv, fd, cq, &max_bytes);
+ #elif defined(NETWORK_WRITE_USE_MMAP)
+ r = network_write_file_chunk_mmap(srv, fd, cq, &max_bytes);
+ #else
+ r = network_write_file_chunk_no_mmap(srv, fd, cq, &max_bytes);
+ #endif
+ break;
+ }
+
+ if (-3 == r) return 0;
+ if (0 != r) return r;
+ }
+
+ return 0;
+}
+#endif
+
+int network_write_init(server *srv) {
+ typedef enum {
+ NETWORK_BACKEND_UNSET,
+ NETWORK_BACKEND_WRITE,
+ NETWORK_BACKEND_WRITEV,
+ NETWORK_BACKEND_SENDFILE,
+ } network_backend_t;
+
+ network_backend_t backend;
+
+ struct nb_map {
+ network_backend_t nb;
+ const char *name;
+ } network_backends[] = {
+ /* lowest id wins */
+ { NETWORK_BACKEND_SENDFILE, "sendfile" },
+ { NETWORK_BACKEND_SENDFILE, "linux-sendfile" },
+ { NETWORK_BACKEND_SENDFILE, "freebsd-sendfile" },
+ { NETWORK_BACKEND_SENDFILE, "solaris-sendfilev" },
+ { NETWORK_BACKEND_WRITEV, "writev" },
+ { NETWORK_BACKEND_WRITE, "write" },
+ { NETWORK_BACKEND_UNSET, NULL }
+ };
+
+ /* get a useful default */
+ backend = network_backends[0].nb;
+
+ /* match name against known types */
+ if (!buffer_string_is_empty(srv->srvconf.network_backend)) {
+ const char *name;
+ for (size_t i = 0; NULL != (name = network_backends[i].name); ++i) {
+ if (0 == strcmp(srv->srvconf.network_backend->ptr, name)) {
+ backend = network_backends[i].nb;
+ break;
+ }
+ }
+ if (NULL == name) {
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "server.network-backend has an unknown value:",
+ srv->srvconf.network_backend);
+ return -1;
+ }
+ }
+
+ switch(backend) {
+ case NETWORK_BACKEND_SENDFILE:
+ #if defined(NETWORK_WRITE_USE_SENDFILE)
+ srv->network_backend_write = network_write_chunkqueue_sendfile;
+ break;
+ #endif
+ case NETWORK_BACKEND_WRITEV:
+ #if defined(NETWORK_WRITE_USE_WRITEV)
+ srv->network_backend_write = network_write_chunkqueue_writev;
+ break;
+ #endif
+ case NETWORK_BACKEND_WRITE:
+ srv->network_backend_write = network_write_chunkqueue_write;
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+const char * network_write_show_handlers(void) {
+ return
+ "\nNetwork handler:\n\n"
+ #if defined NETWORK_WRITE_USE_LINUX_SENDFILE
+ "\t+ linux-sendfile\n"
+ #else
+ "\t- linux-sendfile\n"
+ #endif
+ #if defined NETWORK_WRITE_USE_FREEBSD_SENDFILE
+ "\t+ freebsd-sendfile\n"
+ #else
+ "\t- freebsd-sendfile\n"
+ #endif
+ #if defined NETWORK_WRITE_USE_DARWIN_SENDFILE
+ "\t+ darwin-sendfile\n"
+ #else
+ "\t- darwin-sendfile\n"
+ #endif
+ #if defined NETWORK_WRITE_USE_SOLARIS_SENDFILEV
+ "\t+ solaris-sendfilev\n"
+ #else
+ "\t- solaris-sendfilev\n"
+ #endif
+ #if defined NETWORK_WRITE_USE_WRITEV
+ "\t+ writev\n"
+ #else
+ "\t- writev\n"
+ #endif
+ "\t+ write\n"
+ #ifdef NETWORK_WRITE_USE_MMAP
+ "\t+ mmap support\n"
+ #else
+ "\t- mmap support\n"
+ #endif
+ ;
+}