38#ifdef MHD_LINUX_SOLARIS_SENDFILE
39#include <sys/sendfile.h>
41#if defined(HAVE_FREEBSD_SENDFILE) || defined(HAVE_DARWIN_SENDFILE)
43#include <sys/socket.h>
46#ifdef HAVE_SYS_PARAM_H
58#if (! defined(HAVE_SENDMSG) || ! defined(MSG_NOSIGNAL)) && \
59 defined(MHD_SEND_SPIPE_SUPPRESS_POSSIBLE) && \
60 defined(MHD_SEND_SPIPE_SUPPRESS_NEEDED)
61#define _MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED 1
69#define MHD_SENFILE_CHUNK_ (0x20000)
74#define MHD_SENFILE_CHUNK_THR_P_C_ (0x200000)
76#ifdef HAVE_FREEBSD_SENDFILE
81static int freebsd_sendfile_flags_;
86static int freebsd_sendfile_flags_thd_p_c_;
93freebsd_sendfile_init_ (
void)
95 long sys_page_size = sysconf (_SC_PAGESIZE);
96 if (0 >= sys_page_size)
98 freebsd_sendfile_flags_ = SF_NODISKIO;
99 freebsd_sendfile_flags_thd_p_c_ = SF_NODISKIO;
103 freebsd_sendfile_flags_ =
105 / sys_page_size), SF_NODISKIO);
106 freebsd_sendfile_flags_thd_p_c_ =
108 / sys_page_size), SF_NODISKIO);
117#if defined(HAVE_SYSCONF) && defined(_SC_IOV_MAX)
121static unsigned long mhd_iov_max_ = 0;
126 long res = sysconf (_SC_IOV_MAX);
131 mhd_iov_max_ = IOV_MAX;
139#define _MHD_IOV_MAX mhd_iov_max_
140#elif defined(IOV_MAX)
145#define _MHD_IOV_MAX IOV_MAX
155#ifdef HAVE_FREEBSD_SENDFILE
160 freebsd_sendfile_init_ ();
163#if defined(HAVE_SYSCONF) && defined(_SC_IOV_MAX)
181 if (0 == setsockopt (connection->
socket_fd,
184 (
const void *) (nodelay_state ? &on_val : &off_val),
201 MHD_DLOG (connection->
daemon,
202 _ (
"Setting %s option to %s state failed "
203 "for TCP/IP socket %d: %s\n"),
205 nodelay_state ?
_ (
"ON") :
_ (
"OFF"),
214 MHD_DLOG (connection->
daemon,
215 _ (
"Setting %s option to %s state failed: %s\n"),
217 nodelay_state ?
_ (
"ON") :
_ (
"OFF"),
223 (void) connection; (void) nodelay_state;
243#if defined(MHD_TCP_CORK_NOPUSH)
250 if (0 == setsockopt (connection->
socket_fd,
253 (
const void *) (cork_state ? &on_val : &off_val),
270 MHD_DLOG (connection->
daemon,
271 _ (
"Setting %s option to %s state failed "
272 "for TCP/IP socket %d: %s\n"),
278 cork_state ?
_ (
"ON") :
_ (
"OFF"),
287 MHD_DLOG (connection->
daemon,
288 _ (
"Setting %s option to %s state failed: %s\n"),
294 cork_state ?
_ (
"ON") :
_ (
"OFF"),
300 (void) connection; (void) cork_state;
323 const bool buffer_data = (! push_data);
335#ifdef MHD_USE_MSG_MORE
343#ifdef MHD_TCP_CORK_NOPUSH
370#ifdef MHD_TCP_CORK_NOPUSH
371#ifdef _MHD_CORK_RESET_PUSH_DATA
372#ifdef _MHD_CORK_RESET_PUSH_DATA_ALWAYS
386#ifdef _MHD_NODELAY_SET_PUSH_DATA_ALWAYS
395#ifdef _MHD_NODELAY_SET_PUSH_DATA
422#ifdef _MHD_NODELAY_SET_PUSH_DATA
450#ifdef _MHD_NODELAY_SET_PUSH_DATA
491#ifdef _MHD_NODELAY_SET_PUSH_DATA
532#ifndef _MHD_CORK_RESET_PUSH_DATA_ALWAYS
557 MHD_DLOG (connection->
daemon,
558 _ (
"Zero-send failed: %s\n"),
579 bool plain_send_next,
584 const bool buffer_data = (! push_data);
591#ifndef MHD_USE_MSG_MORE
592 (void) plain_send_next;
596#ifdef MHD_TCP_CORK_NOPUSH
597#ifdef _MHD_CORK_RESET_PUSH_DATA_ALWAYS
598#ifdef _MHD_NODELAY_SET_PUSH_DATA_ALWAYS
599#ifdef MHD_USE_MSG_MORE
691#ifdef _MHD_CORK_RESET_PUSH_DATA
698#ifdef _MHD_CORK_RESET_PUSH_DATA
739 MHD_DLOG (connection->
daemon,
740 _ (
"Failed to push the data from buffers to the network. "
741 "Client may experience some delay "
742 "(usually in range 200ms - 5 sec).\n"));
759 const bool tls_conn =
false;
778 ret = gnutls_record_send (connection->tls_session,
781 if (GNUTLS_E_AGAIN == ret)
784 connection->epoll_state &=
789 if (GNUTLS_E_INTERRUPTED == ret)
791 if ( (GNUTLS_E_ENCRYPTION_FAILED == ret) ||
792 (GNUTLS_E_INVALID_SESSION == ret) ||
793 (GNUTLS_E_COMPRESSION_FAILED == ret) ||
794 (GNUTLS_E_EXPIRED == ret) ||
795 (GNUTLS_E_HASH_FAILED == ret) )
797 if ( (GNUTLS_E_PUSH_ERROR == ret) ||
798 (GNUTLS_E_INTERNAL_ERROR == ret) ||
799 (GNUTLS_E_CRYPTODEV_IOCTL_ERROR == ret) ||
800 (GNUTLS_E_CRYPTODEV_DEVICE_ERROR == ret) )
802#if defined(GNUTLS_E_PREMATURE_TERMINATION)
803 if (GNUTLS_E_PREMATURE_TERMINATION == ret)
805#elif defined(GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
806 if (GNUTLS_E_UNEXPECTED_PACKET_LENGTH == ret)
809 if (GNUTLS_E_MEMORY_ERROR == ret)
835#ifdef MHD_USE_MSG_MORE
839 push_data ? 0 : MSG_MORE);
855 connection->epoll_state &=
880 else if (buffer_size > (
size_t) ret)
881 connection->epoll_state &=
893 (buffer_size == (size_t) ret) )
907 bool complete_response)
914#define _MHD_SEND_VEC_MAX MHD_SCKT_SEND_MAX_SIZE_
916#define _MHD_SEND_VEC_MAX UINT32_MAX
919#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
920 struct iovec vector[2];
935#if (! defined(HAVE_SENDMSG) || ! defined(MSG_NOSIGNAL) ) && \
936 defined(MHD_SEND_SPIPE_SEND_SUPPRESS_POSSIBLE) && \
937 defined(MHD_SEND_SPIPE_SUPPRESS_NEEDED)
953 push_body = complete_response;
955 if (! never_push_hdr)
957 if (! complete_response)
963 if (1400 > (header_size + body_size))
976 if (complete_response && (0 == body_size))
986 || ((
size_t)
UINT_MAX < header_size)
998 if ( (header_size == (
size_t) ret) &&
1009 if ( (((
size_t)
SSIZE_MAX) - ((
size_t) ret)) < body_size)
1011 body_size = (((size_t)
SSIZE_MAX) - ((size_t) ret));
1012 complete_response =
false;
1013 push_body = complete_response;
1031 if ( ((
size_t)
SSIZE_MAX <= body_size) ||
1032 ((
size_t)
SSIZE_MAX < (header_size + body_size)) )
1036 complete_response =
false;
1037 push_body = complete_response;
1039#if (SSIZE_MAX != _MHD_SEND_VEC_MAX) || (_MHD_SEND_VEC_MAX + 0 == 0)
1045 complete_response =
false;
1046 push_body = complete_response;
1056 push_hdr || push_body);
1057#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
1058 vector[0].iov_base = (
void *) header;
1059 vector[0].iov_len = header_size;
1060 vector[1].iov_base = (
void *) body;
1061 vector[1].iov_len = body_size;
1063#if defined(HAVE_SENDMSG)
1064 memset (&msg, 0,
sizeof(msg));
1065 msg.msg_iov = vector;
1069#elif defined(HAVE_WRITEV)
1070 ret = writev (s, vector, 2);
1078 complete_response =
false;
1079 push_body = complete_response;
1081 vector[0].buf = (
char *) header;
1082 vector[0].len = (
unsigned long) header_size;
1083 vector[1].buf = (
char *) body;
1084 vector[1].len = (
unsigned long) body_size;
1086 ret = WSASend (s, vector, 2, &vec_sent, 0,
NULL,
NULL);
1088 ret = (ssize_t) vec_sent;
1101 connection->epoll_state &=
1126 else if ((header_size + body_size) > (size_t) ret)
1127 connection->epoll_state &=
1134 ((header_size + body_size) == (
size_t) ret) )
1150 else if ( (push_hdr) &&
1151 (header_size <= (
size_t) ret))
1157#
if defined(_MHD_HAVE_SENDFILE)
1158 MHD_resp_sender_std == connection->resp_sender,
1173#if defined(_MHD_HAVE_SENDFILE)
1178 const int file_fd = connection->
response->
fd;
1181#ifndef HAVE_SENDFILE64
1182 const uint64_t max_off_t = (uint64_t)
OFF_T_MAX;
1184 const uint64_t max_off_t = (uint64_t) OFF64_T_MAX;
1186#ifdef MHD_LINUX_SOLARIS_SENDFILE
1187#ifndef HAVE_SENDFILE64
1193#ifdef HAVE_FREEBSD_SENDFILE
1197#ifdef HAVE_DARWIN_SENDFILE
1200 const bool used_thr_p_c = (0 != (connection->
daemon->
options
1204 size_t send_size = 0;
1206 mhd_assert (MHD_resp_sender_sendfile == connection->resp_sender);
1211 if (max_off_t < offsetu64)
1213 connection->resp_sender = MHD_resp_sender_std;
1224 if (chunk_size < left)
1226 send_size = chunk_size;
1231 send_size = (size_t) left;
1236#ifdef MHD_LINUX_SOLARIS_SENDFILE
1237#ifndef HAVE_SENDFILE64
1238 offset = (off_t) offsetu64;
1244 offset = (off64_t) offsetu64;
1245 ret = sendfile64 (connection->
socket_fd,
1257 connection->epoll_state &=
1264#ifdef HAVE_LINUX_SENDFILE
1273 connection->resp_sender = MHD_resp_sender_std;
1276 if ( (EAFNOSUPPORT == err) ||
1278 (EOPNOTSUPP == err) )
1280 connection->resp_sender = MHD_resp_sender_std;
1283 if ( (ENOTCONN == err) ||
1292 else if (send_size > (
size_t) ret)
1293 connection->epoll_state &=
1296#elif defined(HAVE_FREEBSD_SENDFILE)
1298 flags = used_thr_p_c ?
1299 freebsd_sendfile_flags_thd_p_c_ : freebsd_sendfile_flags_;
1301 if (0 != sendfile (file_fd,
1315 if (0 != sent_bytes)
1316 return (ssize_t) sent_bytes;
1322 connection->resp_sender = MHD_resp_sender_std;
1327 ret = (ssize_t) sent_bytes;
1328#elif defined(HAVE_DARWIN_SENDFILE)
1329 len = (off_t) send_size;
1330 if (0 != sendfile (file_fd,
1345 return (ssize_t) len;
1349 if ((ENOTCONN == err) ||
1352 if ((ENOTSUP == err) ||
1353 (EOPNOTSUPP == err) )
1356 connection->resp_sender = MHD_resp_sender_std;
1364 ret = (ssize_t) len;
1372 (send_size == (size_t) ret) )
1381#if defined(MHD_VECT_SEND)
1404 size_t items_to_send;
1407#elif defined(MHD_WINSOCK_SOCKETS)
1420 items_to_send = r_iov->
cnt - r_iov->
sent;
1422 if (_MHD_IOV_MAX < items_to_send)
1425 if (0 == _MHD_IOV_MAX)
1427 items_to_send = _MHD_IOV_MAX;
1432 memset (&msg, 0,
sizeof(
struct msghdr));
1433 msg.msg_iov = r_iov->
iov + r_iov->
sent;
1434 msg.msg_iovlen = items_to_send;
1437#ifdef MHD_USE_MSG_MORE
1438 res = sendmsg (connection->
socket_fd, &msg,
1443#elif defined(HAVE_WRITEV)
1447#elif defined(MHD_WINSOCK_SOCKETS)
1455 cnt_w = (DWORD) items_to_send;
1457 cnt_w = (DWORD) items_to_send;
1460 if (0 == WSASend (connection->
socket_fd,
1461 (LPWSABUF) (r_iov->
iov + r_iov->
sent),
1464 res = (ssize_t) bytes_sent;
1468#error No vector-send function available
1479 connection->epoll_state &=
1508 while ((0 != res) && (r_iov->
iov[r_iov->
sent].
iov_len <= (size_t) res))
1515 if (r_iov->
cnt == r_iov->
sent)
1520 connection->epoll_state &=
1528 (
void *) ((uint8_t *) r_iov->
iov[r_iov->
sent].
iov_base + (size_t) res);
1539#if ! defined(MHD_VECT_SEND) || defined(HTTPS_SUPPORT) || \
1540 defined(_MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
1570 if ((
size_t)
SSIZE_MAX - total_sent < r_iov->iov[r_iov->
sent].iov_len)
1576 push_data && (r_iov->
cnt == r_iov->
sent + 1));
1580 if (0 == total_sent)
1589 total_sent += (size_t) res;
1596 (
void *) ((uint8_t *) r_iov->
iov[r_iov->
sent].
iov_base + (size_t) res);
1603 }
while ((r_iov->
cnt > r_iov->
sent) && (non_blk));
1605 return (ssize_t) total_sent;
1619#if defined(HTTPS_SUPPORT) || \
1620 defined(_MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
1621 bool use_iov_send =
true;
1629#if defined(HTTPS_SUPPORT) || \
1630 defined(_MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
1632 use_iov_send = use_iov_send &&
1635#ifdef _MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED
1641 return send_iov_nontls (connection, r_iov, push_data);
1644#if ! defined(MHD_VECT_SEND) || defined(HTTPS_SUPPORT) || \
1645 defined(_MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
#define MHD_ERR_OPNOTSUPP_
#define MHD_ERR_CONNRESET_
@ MHD_EPOLL_STATE_WRITE_READY
#define MHD_SCKT_ERR_IS_(err, code)
#define MHD_SCKT_ERR_IS_EAGAIN_(err)
#define MHD_SCKT_ERR_IS_LOW_RESOURCES_(err)
#define MHD_socket_strerr_(err)
#define MHD_socket_last_strerr_()
#define MHD_SCKT_EOPNOTSUPP_
#define MHD_socket_get_error_()
#define MHD_SCKT_ERR_IS_REMOTE_DISCNN_(err)
#define MHD_SCKT_ERR_IS_EINTR_(err)
#define MHD_SCKT_SEND_MAX_SIZE_
#define MHD_SCKT_ENOTCONN_
#define MHD_SCKT_ENOTSOCK_
#define MHD_send_(s, b, l)
#define MHD_SENFILE_CHUNK_THR_P_C_
ssize_t MHD_send_hdr_and_body_(struct MHD_Connection *connection, const char *header, size_t header_size, bool never_push_hdr, const char *body, size_t body_size, bool complete_response)
ssize_t MHD_send_iovec_(struct MHD_Connection *connection, struct MHD_iovec_track_ *const r_iov, bool push_data)
ssize_t MHD_send_data_(struct MHD_Connection *connection, const char *buffer, size_t buffer_size, bool push_data)
static bool zero_send_(struct MHD_Connection *connection)
bool MHD_connection_set_cork_state_(struct MHD_Connection *connection, bool cork_state)
#define _MHD_SEND_VEC_MAX
void MHD_send_init_static_vars_(void)
static void pre_send_setopt(struct MHD_Connection *connection, bool plain_send, bool push_data)
static void post_send_setopt(struct MHD_Connection *connection, bool plain_send_next, bool push_data)
static ssize_t send_iov_emu(struct MHD_Connection *connection, struct MHD_iovec_track_ *const r_iov, bool push_data)
bool MHD_connection_set_nodelay_state_(struct MHD_Connection *connection, bool nodelay_state)
#define MHD_SENFILE_CHUNK_
Declarations of send() wrappers.
limits values definitions
#define MHD_SCKT_ENOPROTOOPT_
#define MHD_send4_(s, b, l, f)
#define MSG_NOSIGNAL_OR_ZERO
#define MHD_INVALID_SOCKET
@ MHD_USE_THREAD_PER_CONNECTION
enum MHD_tristate sk_nodelay
enum MHD_tristate is_nonip
struct MHD_Response * response
uint64_t response_write_position
struct MHD_iovec_track_ resp_iov
enum MHD_CONNECTION_STATE state
struct MHD_Daemon * daemon
enum MHD_tristate sk_corked