libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit 6f646947421e41312def7555408184cd7dec0a3c
parent f2f1d659156666b61c2f4198c88a3ceaf88ce9f5
Author: Evgeny Grin <k2k@narod.ru>
Date:   Sun,  1 Oct 2017 23:02:55 +0300

Added support for sendfile() on FreeBSD

Diffstat:
Mconfigure.ac | 41+++++++++++++++++++++++++++++++++++++++++
Msrc/microhttpd/connection.c | 73++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Msrc/microhttpd/internal.h | 4++--
3 files changed, 99 insertions(+), 19 deletions(-)

diff --git a/configure.ac b/configure.ac @@ -1267,6 +1267,47 @@ ssize_t sendfile(int, int, off_t*, size_t); [AC_MSG_RESULT([[no]]) ] ) +AS_VAR_IF([[found_sendfile]], [["no"]], + [ + AC_MSG_CHECKING([[for FreeBSD-style sendfile(2)]]) + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> + +static void empty_func(void) +{ +/* Check for declaration */ + (void)sendfile; +} +/* Declare again to check form match */ +int sendfile(int, int, off_t, size_t, + struct sf_hdtr*, off_t*, int); + ]], + [[ + int fd1=0, fd2=1; + off_t o = 0; + size_t s = 5; + off_t r1; + int r2; + r2 = sendfile (fd1, fd2, o, s, (void*)0, &r1, 0); + if (r2) + empty_func(); + ]] + ) + ], + [ + AC_DEFINE([HAVE_FREEBSD_SENDFILE], [1], [Define to 1 if you have FreeBSD-style sendfile(2).]) + found_sendfile="yes, FreeBSD-style" + AC_MSG_RESULT([[yes]]) + ], + [AC_MSG_RESULT([[no]]) + ] + ) + ] +) # optional: have error messages ? AC_MSG_CHECKING([[whether to generate error messages]]) diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c @@ -39,6 +39,11 @@ #ifdef HAVE_LINUX_SENDFILE #include <sys/sendfile.h> #endif /* HAVE_LINUX_SENDFILE */ +#ifdef HAVE_FREEBSD_SENDFILE +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> +#endif /* HAVE_FREEBSD_SENDFILE */ #ifdef HTTPS_SUPPORT #include "connection_https.h" #endif /* HTTPS_SUPPORT */ @@ -219,7 +224,7 @@ send_param_adapter (struct MHD_Connection *connection, } -#ifdef HAVE_LINUX_SENDFILE +#if defined(HAVE_LINUX_SENDFILE) || defined(HAVE_FREEBSD_SENDFILE) /** * Function for sending responses backed by file FD. * @@ -234,13 +239,23 @@ sendfile_adapter (struct MHD_Connection *connection) uint64_t left; uint64_t offsetu64; #ifndef HAVE_SENDFILE64 + const uint64_t max_off_t = (uint64_t)OFF_T_MAX; +#else /* HAVE_SENDFILE64 */ + const uint64_t max_off_t = (uint64_t)OFF64_T_MAX; +#endif /* HAVE_SENDFILE64 */ +#ifdef HAVE_LINUX_SENDFILE +#ifndef HAVE_SENDFILE64 off_t offset; #else /* HAVE_SENDFILE64 */ off64_t offset; #endif /* HAVE_SENDFILE64 */ +#endif /* HAVE_LINUX_SENDFILE */ +#ifdef HAVE_FREEBSD_SENDFILE + off_t sent_bytes; +#endif const bool used_thr_p_c = (0 != (connection->daemon->options & MHD_USE_THREAD_PER_CONNECTION)); const size_t chunk_size = used_thr_p_c ? 0x200000 : 0x20000; - size_t send_size; + size_t send_size = 0; mhd_assert (MHD_resp_sender_sendfile == connection->resp_sender); offsetu64 = connection->response_write_position + connection->response->fd_off; @@ -248,23 +263,19 @@ sendfile_adapter (struct MHD_Connection *connection) /* Do not allow system to stick sending on single fast connection: * use 128KiB chunks (2MiB for thread-per-connection). */ send_size = (left > chunk_size) ? chunk_size : (size_t) left; -#ifndef HAVE_SENDFILE64 - if ((uint64_t)OFF_T_MAX < offsetu64) + if (max_off_t < offsetu64) { /* Retry to send with standard 'send()'. */ connection->resp_sender = MHD_resp_sender_std; return MHD_ERR_AGAIN_; } +#ifdef HAVE_LINUX_SENDFILE +#ifndef HAVE_SENDFILE64 offset = (off_t) offsetu64; ret = sendfile (connection->socket_fd, file_fd, &offset, send_size); #else /* HAVE_SENDFILE64 */ - if ((uint64_t)OFF64_T_MAX < offsetu64) - { /* Retry to send with standard 'send()'. */ - connection->resp_sender = MHD_resp_sender_std; - return MHD_ERR_AGAIN_; - } offset = (off64_t) offsetu64; ret = sendfile64 (connection->socket_fd, file_fd, @@ -299,9 +310,37 @@ sendfile_adapter (struct MHD_Connection *connection) else if (send_size > (size_t)ret) connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY; #endif /* EPOLL_SUPPORT */ +#elif defined(HAVE_FREEBSD_SENDFILE) + if (0 != sendfile (file_fd, + connection->socket_fd, + (off_t) offsetu64, + send_size, + NULL, + &sent_bytes, + 0)) + { + const int err = MHD_socket_get_error_(); + if (MHD_SCKT_ERR_IS_EAGAIN_(err) || + MHD_SCKT_ERR_IS_EINTR_(err) || + EBUSY == err) + { + mhd_assert (SSIZE_MAX >= sent_bytes); + if (0 != sent_bytes) + return (ssize_t)sent_bytes; + + return MHD_ERR_AGAIN_; + } + /* Some unrecoverable error. Possibly file FD is not suitable + * for sendfile(). Retry with standard send(). */ + connection->resp_sender = MHD_resp_sender_std; + return MHD_ERR_AGAIN_; + } + mhd_assert (0 < sent_bytes); + ret = (ssize_t)sent_bytes; +#endif /* HAVE_FREEBSD_SENDFILE */ return ret; } -#endif /* HAVE_LINUX_SENDFILE */ +#endif /* HAVE_LINUX_SENDFILE || HAVE_FREEBSD_SENDFILE */ /** @@ -933,13 +972,13 @@ try_ready_normal_body (struct MHD_Connection *connection) (response->data_size + response->data_start > connection->response_write_position) ) return MHD_YES; /* response already ready */ -#if defined(HAVE_LINUX_SENDFILE) +#if defined(HAVE_LINUX_SENDFILE) || defined (HAVE_FREEBSD_SENDFILE) if (MHD_resp_sender_sendfile == connection->resp_sender) { /* will use sendfile, no need to bother response crc */ return MHD_YES; } -#endif +#endif /* HAVE_LINUX_SENDFILE || HAVE_FREEBSD_SENDFILE */ ret = response->crc (response->crc_cls, connection->response_write_position, @@ -2875,15 +2914,15 @@ MHD_connection_handle_write (struct MHD_Connection *connection) /* mutex was already unlocked by try_ready_normal_body */ return; } -#if defined(HAVE_LINUX_SENDFILE) +#if defined(HAVE_LINUX_SENDFILE) || defined(HAVE_FREEBSD_SENDFILE) if (MHD_resp_sender_sendfile == connection->resp_sender) { ret = sendfile_adapter (connection); } else -#else /* ! HAVE_LINUX_SENDFILE */ +#else /* ! (HAVE_LINUX_SENDFILE || HAVE_FREEBSD_SENDFILE) */ if (1) -#endif /* ! HAVE_LINUX_SENDFILE */ +#endif /* ! (HAVE_LINUX_SENDFILE || HAVE_FREEBSD_SENDFILE) */ { data_write_offset = connection->response_write_position - response->data_start; @@ -3819,13 +3858,13 @@ MHD_queue_response (struct MHD_Connection *connection, MHD_increment_response_rc (response); connection->response = response; connection->responseCode = status_code; -#if defined(HAVE_LINUX_SENDFILE) +#if defined(HAVE_LINUX_SENDFILE) || defined(HAVE_FREEBSD_SENDFILE) if ( (response->fd == -1) || (0 != (connection->daemon->options & MHD_USE_TLS)) ) connection->resp_sender = MHD_resp_sender_std; else connection->resp_sender = MHD_resp_sender_sendfile; -#endif /* HAVE_LINUX_SENDFILE */ +#endif /* HAVE_LINUX_SENDFILE || HAVE_FREEBSD_SENDFILE */ if ( ( (NULL != connection->method) && (MHD_str_equal_caseless_ (connection->method, diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h @@ -806,13 +806,13 @@ struct MHD_Connection */ uint64_t response_write_position; -#if defined(HAVE_LINUX_SENDFILE) +#if defined(HAVE_LINUX_SENDFILE) || defined(HAVE_FREEBSD_SENDFILE) enum MHD_resp_sender_ { MHD_resp_sender_std = 0, MHD_resp_sender_sendfile } resp_sender; -#endif /* HAVE_LINUX_SENDFILE */ +#endif /* HAVE_LINUX_SENDFILE || HAVE_FREEBSD_SENDFILE */ /** * Position in the 100 CONTINUE message that