[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] [libmicrohttpd] 86/154: initial move code sendfile.
From: |
gnunet |
Subject: |
[GNUnet-SVN] [libmicrohttpd] 86/154: initial move code sendfile. |
Date: |
Mon, 19 Aug 2019 10:16:38 +0200 |
This is an automated email from the git hooks/post-receive script.
ng0 pushed a commit to branch master
in repository libmicrohttpd.
commit 5bfd85fc577faa16598d2d6602057644d3d8e088
Author: ng0 <address@hidden>
AuthorDate: Thu Jul 25 17:33:14 2019 +0000
initial move code sendfile.
---
src/microhttpd/mhd_send.c | 288 ++++++++++++++++++++++++++++++++++++++++++++++
src/microhttpd/mhd_send.h | 14 +++
2 files changed, 302 insertions(+)
diff --git a/src/microhttpd/mhd_send.c b/src/microhttpd/mhd_send.c
index b22313df..4758b502 100644
--- a/src/microhttpd/mhd_send.c
+++ b/src/microhttpd/mhd_send.c
@@ -655,3 +655,291 @@ MHD_send_on_connection2_ (struct MHD_Connection
*connection,
MHD_SSO_HDR_CORK);
#endif
}
+
+/**
+ * sendfile() chuck size
+ */
+#define MHD_SENFILE_CHUNK_ (0x20000)
+
+/**
+ * sendfile() chuck size for thread-per-connection
+ */
+#define MHD_SENFILE_CHUNK_THR_P_C_ (0x200000)
+
+#ifdef HAVE_FREEBSD_SENDFILE
+#ifdef SF_FLAGS
+/**
+ * FreeBSD sendfile() flags
+ */
+static int freebsd_sendfile_flags_;
+
+/**
+ * FreeBSD sendfile() flags for thread-per-connection
+ */
+static int freebsd_sendfile_flags_thd_p_c_;
+#endif /* SF_FLAGS */
+/**
+ * Initialises static variables
+ */
+void
+MHD_conn_init_static_ (void)
+{
+/* FreeBSD 11 and later allow to specify read-ahead size
+ * and handles SF_NODISKIO differently.
+ * SF_FLAGS defined only on FreeBSD 11 and later. */
+#ifdef SF_FLAGS
+ long sys_page_size = sysconf (_SC_PAGESIZE);
+ if (0 > sys_page_size)
+ { /* Failed to get page size. */
+ freebsd_sendfile_flags_ = SF_NODISKIO;
+ freebsd_sendfile_flags_thd_p_c_ = SF_NODISKIO;
+ }
+ else
+ {
+ freebsd_sendfile_flags_ =
+ SF_FLAGS((uint16_t)(MHD_SENFILE_CHUNK_ / sys_page_size),
SF_NODISKIO);
+ freebsd_sendfile_flags_thd_p_c_ =
+ SF_FLAGS((uint16_t)(MHD_SENFILE_CHUNK_THR_P_C_ / sys_page_size),
SF_NODISKIO);
+ }
+#endif /* SF_FLAGS */
+}
+#endif /* HAVE_FREEBSD_SENDFILE */
+
+#if defined(_MHD_HAVE_SENDFILE)
+/**
+ * Function for sending responses backed by file FD.
+ *
+ * @param connection the MHD connection structure
+ * @return actual number of bytes sent
+ */
+static ssize_t
+sendfile_adapter (struct MHD_Connection *connection)
+{
+ bool want_cork = false;
+ bool have_cork;
+ bool have_more;
+ bool use_corknopush;
+ bool using_tls = false;
+
+ ssize_t ret;
+ ssize_t lo_ret;
+ const int file_fd = connection->response->fd;
+ 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 MHD_LINUX_SOLARIS_SENDFILE
+#ifndef HAVE_SENDFILE64
+ off_t offset;
+#else /* HAVE_SENDFILE64 */
+ off64_t offset;
+#endif /* HAVE_SENDFILE64 */
+#endif /* MHD_LINUX_SOLARIS_SENDFILE */
+#ifdef HAVE_FREEBSD_SENDFILE
+ off_t sent_bytes;
+ int flags = 0;
+#endif
+#ifdef HAVE_DARWIN_SENDFILE
+ off_t len;
+#endif /* HAVE_DARWIN_SENDFILE */
+ const bool used_thr_p_c = (0 != (connection->daemon->options &
MHD_USE_THREAD_PER_CONNECTION));
+ const size_t chunk_size = used_thr_p_c ? MHD_SENFILE_CHUNK_THR_P_C_ :
MHD_SENFILE_CHUNK_;
+ size_t send_size = 0;
+ mhd_assert (MHD_resp_sender_sendfile == connection->resp_sender);
+
+ offsetu64 = connection->response_write_position +
connection->response->fd_off;
+ left = connection->response->total_size -
connection->response_write_position;
+ /* 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;
+ if (max_off_t < offsetu64)
+ { /* Retry to send with standard 'send()'. */
+ connection->resp_sender = MHD_resp_sender_std;
+ return MHD_ERR_AGAIN_;
+ }
+#ifdef MHD_LINUX_SOLARIS_SENDFILE
+#ifndef HAVE_SENDFILE64
+ offset = (off_t) offsetu64;
+ ret = sendfile (connection->socket_fd,
+ file_fd,
+ &offset,
+ send_size);
+#else /* HAVE_SENDFILE64 */
+ offset = (off64_t) offsetu64;
+ ret = sendfile64 (connection->socket_fd,
+ file_fd,
+ &offset,
+ send_size);
+#endif /* HAVE_SENDFILE64 */
+ if (0 > ret)
+ {
+ const int err = MHD_socket_get_error_();
+ if (MHD_SCKT_ERR_IS_EAGAIN_(err))
+ {
+#ifdef EPOLL_SUPPORT
+ /* EAGAIN --- no longer write-ready */
+ connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
+#endif /* EPOLL_SUPPORT */
+ return MHD_ERR_AGAIN_;
+ }
+ if (MHD_SCKT_ERR_IS_EINTR_ (err))
+ return MHD_ERR_AGAIN_;
+#ifdef HAVE_LINUX_SENDFILE
+ if (MHD_SCKT_ERR_IS_(err,
+ MHD_SCKT_EBADF_))
+ return MHD_ERR_BADF_;
+ /* sendfile() failed with EINVAL if mmap()-like operations are not
+ supported for FD or other 'unusual' errors occurred, so we should try
+ to fall back to 'SEND'; see also this thread for info on
+ odd libc/Linux behavior with sendfile:
+ http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html
*/
+ connection->resp_sender = MHD_resp_sender_std;
+ return MHD_ERR_AGAIN_;
+#else /* HAVE_SOLARIS_SENDFILE */
+ if ( (EAFNOSUPPORT == err) ||
+ (EINVAL == err) ||
+ (EOPNOTSUPP == err) )
+ { /* Retry with standard file reader. */
+ connection->resp_sender = MHD_resp_sender_std;
+ return MHD_ERR_AGAIN_;
+ }
+ if ( (ENOTCONN == err) ||
+ (EPIPE == err) )
+ {
+ return MHD_ERR_CONNRESET_;
+ }
+ return MHD_ERR_BADF_; /* Fail hard */
+#endif /* HAVE_SOLARIS_SENDFILE */
+ }
+#ifdef EPOLL_SUPPORT
+ else if (send_size > (size_t)ret)
+ connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
+#endif /* EPOLL_SUPPORT */
+#elif defined(HAVE_FREEBSD_SENDFILE)
+#ifdef SF_FLAGS
+ flags = used_thr_p_c ?
+ freebsd_sendfile_flags_thd_p_c_ : freebsd_sendfile_flags_;
+#endif /* SF_FLAGS */
+ if (0 != sendfile (file_fd,
+ connection->socket_fd,
+ (off_t) offsetu64,
+ send_size,
+ NULL,
+ &sent_bytes,
+ flags))
+ {
+ 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);
+ mhd_assert (SSIZE_MAX >= sent_bytes);
+ ret = (ssize_t)sent_bytes;
+#elif defined(HAVE_DARWIN_SENDFILE)
+ len = (off_t)send_size; /* chunk always fit */
+ if (0 != sendfile (file_fd,
+ connection->socket_fd,
+ (off_t) offsetu64,
+ &len,
+ NULL,
+ 0))
+ {
+ const int err = MHD_socket_get_error_();
+ if (MHD_SCKT_ERR_IS_EAGAIN_(err) ||
+ MHD_SCKT_ERR_IS_EINTR_(err))
+ {
+ mhd_assert (0 <= len);
+ mhd_assert (SSIZE_MAX >= len);
+ mhd_assert (send_size >= (size_t)len);
+ if (0 != len)
+ return (ssize_t)len;
+
+ return MHD_ERR_AGAIN_;
+ }
+ if (ENOTCONN == err ||
+ EPIPE == err)
+ return MHD_ERR_CONNRESET_;
+ if (ENOTSUP == err ||
+ EOPNOTSUPP == err)
+ { /* This file FD is not suitable for sendfile().
+ * Retry with standard send(). */
+ connection->resp_sender = MHD_resp_sender_std;
+ return MHD_ERR_AGAIN_;
+ }
+ return MHD_ERR_BADF_; /* Return hard error. */
+ }
+ mhd_assert (0 <= len);
+ mhd_assert (SSIZE_MAX >= len);
+ mhd_assert (send_size >= (size_t)len);
+ ret = (ssize_t)len;
+#endif /* HAVE_FREEBSD_SENDFILE */
+
+ ret = lo_ret;
+ if (0 > ret)
+ {
+ /* ! could be avoided by redefining the variable. */
+ have_cork = ! connection->sk_tcp_nodelay_on;
+
+#ifdef MSG_MORE
+ have_more = true;
+#else
+ have_more = false;
+#endif
+
+#if TCP_NODELAY
+ use_corknopush = false;
+#elif TCP_CORK
+ use_corknopush = true;
+#elif TCP_NOPUSH
+ use_corknopush = true;
+#endif
+
+#ifdef HTTPS_SUPPORT
+ using_tls = (0 != (connection->daemon->options & MHD_USE_TLS));
+#endif
+
+#if TCP_CORK
+ /* When we have CORK, we can have NODELAY on the same system,
+ * at least since Linux 2.2 and both can be combined since
+ * Linux 2.5.71. For more details refer to tcp(7) on Linux.
+ * No other system in 2019-06 has TCP_CORK. */
+ if ((! using_tls) && (use_corknopush) && (have_cork && ! want_cork))
+ {
+ MHD_send_socket_state_cork_nodelay_ (connection,
+ false,
+ true,
+ true,
+ true);
+ }
+#elif TCP_NOPUSH
+ /* TCP_NOPUSH on FreeBSD is equal to cork on Linux, with the
+ * exception that we know that TCP_NOPUSH will definitely
+ * exist and we can disregard TCP_NODELAY unless requested. */
+ if ((! using_tls) && (use_corknopush) && (have_cork && ! want_cork))
+ {
+ MHD_send_socket_state_nopush_ (connection, true, false);
+ }
+#endif
+ return lo_ret;
+ }
+ else
+ {
+ return ret;
+ }
+}
+#endif /* _MHD_HAVE_SENDFILE */
diff --git a/src/microhttpd/mhd_send.h b/src/microhttpd/mhd_send.h
index 78edc9de..20a054d3 100644
--- a/src/microhttpd/mhd_send.h
+++ b/src/microhttpd/mhd_send.h
@@ -37,6 +37,20 @@
#include "connection.h"
#include "connection_https.h"
+#ifdef MHD_LINUX_SOLARIS_SENDFILE
+#include <sys/sendfile.h>
+#endif /* MHD_LINUX_SOLARIS_SENDFILE */
+#if defined(HAVE_FREEBSD_SENDFILE) || defined(HAVE_DARWIN_SENDFILE)
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#endif /* HAVE_FREEBSD_SENDFILE || HAVE_DARWIN_SENDFILE */
+
+#ifdef HAVE_SYS_PARAM_H
+/* For FreeBSD version identification */
+#include <sys/param.h>
+#endif /* HAVE_SYS_PARAM_H */
+
/**
* The enumeration of send socket options.
*/
--
To stop receiving notification emails like this one, please contact
address@hidden.
- [GNUnet-SVN] [libmicrohttpd] 75/154: switch functions., (continued)
- [GNUnet-SVN] [libmicrohttpd] 75/154: switch functions., gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 95/154: simplify, gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 68/154: Add MHD_send_socket_state_cork_nodelay_ and use it., gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 65/154: remove old function name., gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 94/154: simplify, gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 89/154: attempt fix, gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 97/154: simplify, gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 108/154: have_cork->want_cork, gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 91/154: show not tell, gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 102/154: for tests, gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 86/154: initial move code sendfile.,
gnunet <=
- [GNUnet-SVN] [libmicrohttpd] 100/154: incomplete, gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 111/154: synt, gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 105/154: remove commented code, gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 99/154: remove dead code, comment new code., gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 109/154: declare ret, gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 120/154: configure, gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 119/154: attempt configure fix, gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 116/154: ack other authors, gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 98/154: simplify, gnunet, 2019/08/19
- [GNUnet-SVN] [libmicrohttpd] 104/154: skcork, gnunet, 2019/08/19