From 159ca0c15d71355457337d859aea2c3fc6ccb2ca Mon Sep 17 00:00:00 2001 From: "Kyle J. McKay" Date: Fri, 4 Dec 2015 20:48:21 +0000 Subject: [PATCH] [network] add darwin-sendfile backend (fixes #2687) The FreeBSD version of sendfile is already supported. Starting with OS X 10.5, Darwin also supports sendfile, but using a slightly different argument list even though much of the implementation is likely taken from FreeBSD just like the man page is. Add support for darwin's sendfile by introducing a new network_darwin_sendfile.c file that's just a copy of the network_freebsd_sendfile.c file except with the arguments adjusted to compensate for the minor API difference (FreeBSD has separate in and out byte count arguments whereas Darwin has a combined in/out byte count argument). Signed-off-by: Kyle J. McKay git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@3060 152afb58-edef-0310-8abb-c4023f1b3aa9 --- NEWS | 1 + src/CMakeLists.txt | 2 +- src/Makefile.am | 2 +- src/SConscript | 2 +- src/network_backends.h | 8 +++++ src/network_darwin_sendfile.c | 61 +++++++++++++++++++++++++++++++++++ src/server.c | 5 +++ 7 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 src/network_darwin_sendfile.c diff --git a/NEWS b/NEWS index 9486efc4..9340d289 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,7 @@ NEWS * [core] encode path with ENCODING_REL_URI in redirect to directory (fixes #2661, thx gstrauss) * [mod_secdownload] add required algorithm option; old behaviour available as "md5", new options "hmac-sha1" and "hmac-sha256" * [mod_fastcgi/mod_scgi] zero sockaddr structs before use (fixes #2691, thx Kyle J. McKay) + * [network] add darwin-sendfile backend (fixes #2687, thx Kyle J. McKay) - 1.4.37 - 2015-08-30 * [mod_proxy] remove debug log line from error log (fixes #2659) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4f574d9f..a4deeba8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -494,7 +494,7 @@ set(COMMON_SRC network_write.c network_linux_sendfile.c network_freebsd_sendfile.c network_solaris_sendfilev.c network_openssl.c - status_counter.c safe_memclear.c + status_counter.c safe_memclear.c network_darwin_sendfile.c ) if(WIN32) diff --git a/src/Makefile.am b/src/Makefile.am index e7b24440..906823ec 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -76,7 +76,7 @@ common_src=base64.c buffer.c log.c \ network_freebsd_sendfile.c network_writev.c \ network_solaris_sendfilev.c network_openssl.c \ splaytree.c status_counter.c \ - safe_memclear.c + safe_memclear.c network_darwin_sendfile.c src = server.c response.c connections.c network.c \ configfile.c configparser.c request.c proc_open.c diff --git a/src/SConscript b/src/SConscript index 3d873e8d..b29f4c07 100644 --- a/src/SConscript +++ b/src/SConscript @@ -28,7 +28,7 @@ common_src = Split("base64.c buffer.c log.c \ network_write.c network_linux_sendfile.c \ network_freebsd_sendfile.c \ network_solaris_sendfilev.c network_openssl.c \ - status_counter.c safe_memclear.c \ + status_counter.c safe_memclear.c network_darwin_sendfile.c \ ") src = Split("server.c response.c connections.c network.c \ diff --git a/src/network_backends.h b/src/network_backends.h index 8233c488..b1ff6088 100644 --- a/src/network_backends.h +++ b/src/network_backends.h @@ -25,6 +25,14 @@ # define USE_FREEBSD_SENDFILE #endif +#if defined HAVE_SENDFILE && defined(__APPLE__) +# ifdef USE_SENDFILE +# error "can't have more than one sendfile implementation" +# endif +# define USE_SENDFILE "darwin-sendfile" +# define USE_DARWIN_SENDFILE +#endif + #if defined HAVE_SYS_SENDFILE_H && defined HAVE_SENDFILEV && defined(__sun) # ifdef USE_SENDFILE # error "can't have more than one sendfile implementation" diff --git a/src/network_darwin_sendfile.c b/src/network_darwin_sendfile.c new file mode 100644 index 00000000..a249d72a --- /dev/null +++ b/src/network_darwin_sendfile.c @@ -0,0 +1,61 @@ +#include "network_backends.h" + +#if defined(USE_DARWIN_SENDFILE) + +#include "network.h" +#include "log.h" + +#include +#include +#include + +#include +#include + +int network_write_file_chunk_sendfile(server *srv, connection *con, int fd, chunkqueue *cq, off_t *p_max_bytes) { + chunk* const c = cq->first; + off_t offset, written = 0; + off_t toSend; + int r; + + force_assert(NULL != c); + force_assert(FILE_CHUNK == c->type); + 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 != network_open_file_chunk(srv, con, cq)) return -1; + + /* Darwin sendfile() */ + written = toSend; + if (-1 == (r = sendfile(c->file.fd, fd, offset, &written, NULL, 0))) { + switch(errno) { + case EAGAIN: + case EINTR: + /* for EAGAIN/EINTR written still contains the sent bytes */ + break; /* try again later */ + case EPIPE: + case ENOTCONN: + return -2; + default: + log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno); + return -1; + } + } + + if (written >= 0) { + chunkqueue_mark_written(cq, written); + *p_max_bytes -= written; + } + + return (r >= 0 && written == toSend) ? 0 : -3; +} + +#endif /* USE_DARWIN_SENDFILE */ diff --git a/src/server.c b/src/server.c index d79594cd..8a563b6a 100644 --- a/src/server.c +++ b/src/server.c @@ -422,6 +422,11 @@ static void show_features (void) { #else "\t- freebsd-sendfile\n" #endif +#if defined USE_DARWIN_SENDFILE + "\t+ darwin-sendfile\n" +#else + "\t- darwin-sendfile\n" +#endif #if defined USE_SOLARIS_SENDFILEV "\t+ solaris-sendfilev\n" #else