GNU libmicrohttpd  0.9.70
mhd_send.c
Go to the documentation of this file.
1 /*
2  This file is part of libmicrohttpd
3  Copyright (C) 2019 ng0 <ng0@n0.is>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public
7  License as published by the Free Software Foundation; either
8  version 2.1 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 
19  */
20 
29 /* Worth considering for future improvements and additions:
30  * NetBSD has no sendfile or sendfile64. The way to work
31  * with this seems to be to mmap the file and write(2) as
32  * large a chunk as possible to the socket. Alternatively,
33  * use madvise(..., MADV_SEQUENTIAL). */
34 
35 /* Functions to be used in: send_param_adapter, MHD_send_
36  * and every place where sendfile(), sendfile64(), setsockopt()
37  * are used. */
38 
39 #include "mhd_send.h"
40 
47 static void
48 pre_cork_setsockopt (struct MHD_Connection *connection,
49  bool want_cork)
50 {
51 #if HAVE_MSG_MORE
52  /* We use the MSG_MORE option for corking, no need for extra syscalls! */
53 #elif defined(MHD_TCP_CORK_NOPUSH)
54  int ret;
55 
56  /* If sk_cork_on is already what we pass in, return. */
57  if (connection->sk_cork_on == want_cork)
58  {
59  /* nothing to do, success! */
60  return;
61  }
62  if (! want_cork)
63  return; /* nothing to do *pre* syscall! */
64  ret = MHD_socket_cork_ (connection->socket_fd,
65  true);
66  if (0 == ret)
67  {
68  connection->sk_cork_on = true;
69  return;
70  }
71  switch (errno)
72  {
73  case ENOTSOCK:
74  /* FIXME: Could be we are talking to a pipe, maybe remember this
75  and avoid all setsockopt() in the future? */
76  break;
77  case EBADF:
78  /* FIXME: should we die hard here? */
79  break;
80  case EINVAL:
81  /* FIXME: optlen invalid, should at least log this, maybe die */
82 #ifdef HAVE_MESSAGES
83  MHD_DLOG (daemon,
84  _ ("optlen invalid: %s\n"),
86 #endif
87  break;
88  case EFAULT:
89  /* wopsie, should at leats log this, FIXME: maybe die */
90 #ifdef HAVE_MESSAGES
91  MHD_DLOG (daemon,
92  _ (
93  "The addresss pointed to by optval is not a valid part of the process address space: %s\n"),
95 #endif
96  break;
97  case ENOPROTOOPT:
98  /* optlen unknown, should at least log this */
99 #ifdef HAVE_MESSAGES
100  MHD_DLOG (daemon,
101  _ ("The option is unknown: %s\n"),
103 #endif
104  break;
105  default:
106  /* any others? man page does not list more... */
107  break;
108  }
109 #else
110  /* CORK/NOPUSH/MSG_MORE do not exist on this platform,
111  so we must toggle Naggle's algorithm on/off instead
112  (otherwise we keep it always off) */
113  if (connection->sk_cork_on == want_cork)
114  {
115  /* nothing to do, success! */
116  return;
117  }
118  if ( (want_cork) &&
119  (0 == MHD_socket_set_nodelay_ (connection->socket_fd,
120  false)) )
121  connection->sk_cork_on = true;
122 #endif
123 }
124 
125 
132 static void
134  bool want_cork)
135 {
136 #if HAVE_MSG_MORE
137  /* We use the MSG_MORE option for corking, no need for extra syscalls! */
138 #elif defined(MHD_TCP_CORK_NOPUSH)
139  int ret;
140 
141  /* If sk_cork_on is already what we pass in, return. */
142  if (connection->sk_cork_on == want_cork)
143  {
144  /* nothing to do, success! */
145  return;
146  }
147  if (want_cork)
148  return; /* nothing to do *post* syscall (in fact, we should never
149  get here, as sk_cork_on should have succeeded in the
150  pre-syscall) */
151  ret = MHD_socket_cork_ (connection->socket_fd,
152  false);
153  if (0 == ret)
154  {
155  connection->sk_cork_on = false;
156  return;
157  }
158  switch (errno)
159  {
160  case ENOTSOCK:
161  /* FIXME: Could be we are talking to a pipe, maybe remember this
162  and avoid all setsockopt() in the future? */
163  break;
164  case EBADF:
165  /* FIXME: should we die hard here? */
166  break;
167  case EINVAL:
168  /* FIXME: optlen invalid, should at least log this, maybe die */
169 #ifdef HAVE_MESSAGES
170  MHD_DLOG (daemon,
171  _ ("optlen invalid: %s\n"),
173 #endif
174  break;
175  case EFAULT:
176  /* wopsie, should at leats log this, FIXME: maybe die */
177 #ifdef HAVE_MESSAGES
178  MHD_DLOG (daemon,
179  _ (
180  "The addresss pointed to by optval is not a valid part of the process address space: %s\n"),
182 #endif
183  break;
184  case ENOPROTOOPT:
185  /* optlen unknown, should at least log this */
186 #ifdef HAVE_MESSAGES
187  MHD_DLOG (daemon,
188  _ ("The option is unknown: %s\n"),
190 #endif
191  break;
192  default:
193  /* any others? man page does not list more... */
194  break;
195  }
196 #else
197  /* CORK/NOPUSH/MSG_MORE do not exist on this platform,
198  so we must toggle Naggle's algorithm on/off instead
199  (otherwise we keep it always off) */
200  if (connection->sk_cork_on == want_cork)
201  {
202  /* nothing to do, success! */
203  return;
204  }
205  if ( (! want_cork) &&
206  (0 == MHD_socket_set_nodelay_ (connection->socket_fd,
207  true)) )
208  connection->sk_cork_on = false;
209 #endif
210 }
211 
212 
232 ssize_t
234  const char *buffer,
235  size_t buffer_size,
236  enum MHD_SendSocketOptions options)
237 {
238  bool want_cork;
239  MHD_socket s = connection->socket_fd;
240  ssize_t ret;
241 
242  /* error handling from send_param_adapter() */
243  if ( (MHD_INVALID_SOCKET == s) ||
244  (MHD_CONNECTION_CLOSED == connection->state) )
245  {
246  return MHD_ERR_NOTCONN_;
247  }
248 
249  /* from send_param_adapter() */
250  if (buffer_size > MHD_SCKT_SEND_MAX_SIZE_)
251  buffer_size = MHD_SCKT_SEND_MAX_SIZE_; /* return value limit */
252 
253  /* Get socket options, change/set options if necessary. */
254  switch (options)
255  {
256  /* No corking */
257  case MHD_SSO_NO_CORK:
258  want_cork = false;
259  break;
260  /* Do corking, consider MSG_MORE instead if available. */
261  case MHD_SSO_MAY_CORK:
262  want_cork = true;
263  break;
264  /* Cork the header. */
265  case MHD_SSO_HDR_CORK:
266  want_cork = (buffer_size <= 1024);
267  break;
268  }
269 
270 #ifdef HTTPS_SUPPORT
271  if (0 != (connection->daemon->options & MHD_USE_TLS))
272  {
273  bool have_cork = connection->sk_cork_on;
274 
275  if (want_cork && ! have_cork)
276  {
277  gnutls_record_cork (connection->tls_session);
278  connection->sk_cork_on = true;
279  }
280  if (buffer_size > SSIZE_MAX)
281  buffer_size = SSIZE_MAX;
282  ret = gnutls_record_send (connection->tls_session,
283  buffer,
284  buffer_size);
285  if ( (GNUTLS_E_AGAIN == ret) ||
286  (GNUTLS_E_INTERRUPTED == ret) )
287  {
288 #ifdef EPOLL_SUPPORT
289  if (GNUTLS_E_AGAIN == ret)
290  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
291 #endif
292  return MHD_ERR_AGAIN_;
293  }
294  if (ret < 0)
295  {
296  /* Likely 'GNUTLS_E_INVALID_SESSION' (client communication
297  disrupted); interpret as a hard error */
298  return MHD_ERR_NOTCONN_;
299  }
300 #ifdef EPOLL_SUPPORT
301  /* Unlike non-TLS connections, do not reset "write-ready" if
302  * sent amount smaller than provided amount, as TLS
303  * connections may break data into smaller parts for sending. */
304 #endif /* EPOLL_SUPPORT */
305 
306  if (! want_cork && have_cork)
307  {
308  (void) gnutls_record_uncork (connection->tls_session, 0);
309  connection->sk_cork_on = false;
310  }
311  }
312  else
313 #endif /* HTTPS_SUPPORT */
314  {
315  /* plaintext transmission */
316  pre_cork_setsockopt (connection, want_cork);
317 #if HAVE_MSG_MORE
318  ret = send (s,
319  buffer,
320  buffer_size,
321  MAYBE_MSG_NOSIGNAL | (want_cork ? MSG_MORE : 0));
322 #else
323  ret = send (connection->socket_fd,
324  buffer,
325  buffer_size,
327 #endif
328 
329  if (0 > ret)
330  {
331  const int err = MHD_socket_get_error_ ();
332 
333  if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
334  {
335 #if EPOLL_SUPPORT
336  /* EAGAIN, no longer write-ready */
337  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
338 #endif /* EPOLL_SUPPORT */
339  return MHD_ERR_AGAIN_;
340  }
341  if (MHD_SCKT_ERR_IS_EINTR_ (err))
342  return MHD_ERR_AGAIN_;
344  return MHD_ERR_CONNRESET_;
345  /* Treat any other error as hard error. */
346  return MHD_ERR_NOTCONN_;
347  }
348 #if EPOLL_SUPPORT
349  else if (buffer_size > (size_t) ret)
350  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
351 #endif /* EPOLL_SUPPORT */
352  if (ret == buffer_size)
353  post_cork_setsockopt (connection, want_cork);
354  }
355 
356  return ret;
357 }
358 
359 
377 ssize_t
379  const char *header,
380  size_t header_size,
381  const char *buffer,
382  size_t buffer_size)
383 {
384 #ifdef HTTPS_SUPPORT
385  if (0 != (connection->daemon->options & MHD_USE_TLS))
386  {
387  ssize_t ret;
388 
389  ret = MHD_send_on_connection_ (connection,
390  header,
391  header_size,
393  if ( (ret == header_size) &&
394  (0 == buffer_size) &&
395  connection->sk_cork_on)
396  {
397  (void) gnutls_record_uncork (connection->tls_session, 0);
398  connection->sk_cork_on = false;
399  }
400  return ret;
401  }
402 #endif
403 #if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
404  MHD_socket s = connection->socket_fd;
405  ssize_t ret;
406  struct iovec vector[2];
407 
408  /* Since we generally give the fully answer, we do not want
409  corking to happen */
410  pre_cork_setsockopt (connection, false);
411 
412  vector[0].iov_base = (void *) header;
413  vector[0].iov_len = header_size;
414  vector[1].iov_base = (void *) buffer;
415  vector[1].iov_len = buffer_size;
416 
417 #if HAVE_SENDMSG
418  {
419  struct msghdr msg;
420 
421  memset (&msg, 0, sizeof(struct msghdr));
422  msg.msg_iov = vector;
423  msg.msg_iovlen = 2;
424 
425  ret = sendmsg (s, &msg, MAYBE_MSG_NOSIGNAL);
426  }
427 #elif HAVE_WRITEV
428  {
429  int iovcnt;
430 
431  iovcnt = sizeof (vector) / sizeof (struct iovec);
432  ret = writev (s, vector, iovcnt);
433  }
434 #endif
435 
436  /* Only if we succeeded sending the full buffer, we need to make sure that
437  the OS flushes at the end */
438  if (ret == header_size + buffer_size)
439  post_cork_setsockopt (connection, false);
440 
441  return ret;
442 
443 #else
444  return MHD_send_on_connection_ (connection,
445  header,
446  header_size,
448 #endif
449 }
450 
451 
455 #define MHD_SENFILE_CHUNK_ (0x20000)
456 
460 #define MHD_SENFILE_CHUNK_THR_P_C_ (0x200000)
461 
462 #ifdef HAVE_FREEBSD_SENDFILE
463 #ifdef SF_FLAGS
464 
467 static int freebsd_sendfile_flags_;
468 
472 static int freebsd_sendfile_flags_thd_p_c_;
473 #endif /* SF_FLAGS */
474 
475 #endif /* HAVE_FREEBSD_SENDFILE */
476 
477 #if defined(_MHD_HAVE_SENDFILE)
478 
484 ssize_t
485 MHD_send_sendfile_ (struct MHD_Connection *connection)
486 {
487  ssize_t ret;
488  const int file_fd = connection->response->fd;
489  uint64_t left;
490  uint64_t offsetu64;
491 #ifndef HAVE_SENDFILE64
492  const uint64_t max_off_t = (uint64_t) OFF_T_MAX;
493 #else /* HAVE_SENDFILE64 */
494  const uint64_t max_off_t = (uint64_t) OFF64_T_MAX;
495 #endif /* HAVE_SENDFILE64 */
496 #ifdef MHD_LINUX_SOLARIS_SENDFILE
497 #ifndef HAVE_SENDFILE64
498  off_t offset;
499 #else /* HAVE_SENDFILE64 */
500  off64_t offset;
501 #endif /* HAVE_SENDFILE64 */
502 #endif /* MHD_LINUX_SOLARIS_SENDFILE */
503 #ifdef HAVE_FREEBSD_SENDFILE
504  off_t sent_bytes;
505  int flags = 0;
506 #endif
507 #ifdef HAVE_DARWIN_SENDFILE
508  off_t len;
509 #endif /* HAVE_DARWIN_SENDFILE */
510  const bool used_thr_p_c = (0 != (connection->daemon->options
512  const size_t chunk_size = used_thr_p_c ? MHD_SENFILE_CHUNK_THR_P_C_ :
514  size_t send_size = 0;
515  mhd_assert (MHD_resp_sender_sendfile == connection->resp_sender);
516 
517  pre_cork_setsockopt (connection, false);
518 
519  offsetu64 = connection->response_write_position
520  + connection->response->fd_off;
521  left = connection->response->total_size - connection->response_write_position;
522  /* Do not allow system to stick sending on single fast connection:
523  * use 128KiB chunks (2MiB for thread-per-connection). */
524  send_size = (left > chunk_size) ? chunk_size : (size_t) left;
525  if (max_off_t < offsetu64)
526  { /* Retry to send with standard 'send()'. */
527  connection->resp_sender = MHD_resp_sender_std;
528  return MHD_ERR_AGAIN_;
529  }
530 #ifdef MHD_LINUX_SOLARIS_SENDFILE
531 #ifndef HAVE_SENDFILE64
532  offset = (off_t) offsetu64;
533  ret = sendfile (connection->socket_fd,
534  file_fd,
535  &offset,
536  send_size);
537 #else /* HAVE_SENDFILE64 */
538  offset = (off64_t) offsetu64;
539  ret = sendfile64 (connection->socket_fd,
540  file_fd,
541  &offset,
542  send_size);
543 #endif /* HAVE_SENDFILE64 */
544  if (0 > ret)
545  {
546  const int err = MHD_socket_get_error_ ();
547  if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
548  {
549 #ifdef EPOLL_SUPPORT
550  /* EAGAIN --- no longer write-ready */
551  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
552 #endif /* EPOLL_SUPPORT */
553  return MHD_ERR_AGAIN_;
554  }
555  if (MHD_SCKT_ERR_IS_EINTR_ (err))
556  return MHD_ERR_AGAIN_;
557 #ifdef HAVE_LINUX_SENDFILE
558  if (MHD_SCKT_ERR_IS_ (err,
560  return MHD_ERR_BADF_;
561  /* sendfile() failed with EINVAL if mmap()-like operations are not
562  supported for FD or other 'unusual' errors occurred, so we should try
563  to fall back to 'SEND'; see also this thread for info on
564  odd libc/Linux behavior with sendfile:
565  http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html */connection->resp_sender = MHD_resp_sender_std;
566  return MHD_ERR_AGAIN_;
567 #else /* HAVE_SOLARIS_SENDFILE */
568  if ( (EAFNOSUPPORT == err) ||
569  (EINVAL == err) ||
570  (EOPNOTSUPP == err) )
571  { /* Retry with standard file reader. */
572  connection->resp_sender = MHD_resp_sender_std;
573  return MHD_ERR_AGAIN_;
574  }
575  if ( (ENOTCONN == err) ||
576  (EPIPE == err) )
577  {
578  return MHD_ERR_CONNRESET_;
579  }
580  return MHD_ERR_BADF_; /* Fail hard */
581 #endif /* HAVE_SOLARIS_SENDFILE */
582  }
583 #ifdef EPOLL_SUPPORT
584  else if (send_size > (size_t) ret)
585  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
586 #endif /* EPOLL_SUPPORT */
587 #elif defined(HAVE_FREEBSD_SENDFILE)
588 #ifdef SF_FLAGS
589  flags = used_thr_p_c ?
590  freebsd_sendfile_flags_thd_p_c_ : freebsd_sendfile_flags_;
591 #endif /* SF_FLAGS */
592  if (0 != sendfile (file_fd,
593  connection->socket_fd,
594  (off_t) offsetu64,
595  send_size,
596  NULL,
597  &sent_bytes,
598  flags))
599  {
600  const int err = MHD_socket_get_error_ ();
601  if (MHD_SCKT_ERR_IS_EAGAIN_ (err) ||
602  MHD_SCKT_ERR_IS_EINTR_ (err) ||
603  (EBUSY == err) )
604  {
605  mhd_assert (SSIZE_MAX >= sent_bytes);
606  if (0 != sent_bytes)
607  return (ssize_t) sent_bytes;
608 
609  return MHD_ERR_AGAIN_;
610  }
611  /* Some unrecoverable error. Possibly file FD is not suitable
612  * for sendfile(). Retry with standard send(). */
613  connection->resp_sender = MHD_resp_sender_std;
614  return MHD_ERR_AGAIN_;
615  }
616  mhd_assert (0 < sent_bytes);
617  mhd_assert (SSIZE_MAX >= sent_bytes);
618  ret = (ssize_t) sent_bytes;
619 #elif defined(HAVE_DARWIN_SENDFILE)
620  len = (off_t) send_size; /* chunk always fit */
621  if (0 != sendfile (file_fd,
622  connection->socket_fd,
623  (off_t) offsetu64,
624  &len,
625  NULL,
626  0))
627  {
628  const int err = MHD_socket_get_error_ ();
629  if (MHD_SCKT_ERR_IS_EAGAIN_ (err) ||
631  {
632  mhd_assert (0 <= len);
633  mhd_assert (SSIZE_MAX >= len);
634  mhd_assert (send_size >= (size_t) len);
635  if (0 != len)
636  return (ssize_t) len;
637 
638  return MHD_ERR_AGAIN_;
639  }
640  if ((ENOTCONN == err) ||
641  (EPIPE == err) )
642  return MHD_ERR_CONNRESET_;
643  if ((ENOTSUP == err) ||
644  (EOPNOTSUPP == err) )
645  { /* This file FD is not suitable for sendfile().
646  * Retry with standard send(). */
647  connection->resp_sender = MHD_resp_sender_std;
648  return MHD_ERR_AGAIN_;
649  }
650  return MHD_ERR_BADF_; /* Return hard error. */
651  }
652  mhd_assert (0 <= len);
653  mhd_assert (SSIZE_MAX >= len);
654  mhd_assert (send_size >= (size_t) len);
655  ret = (ssize_t) len;
656 #endif /* HAVE_FREEBSD_SENDFILE */
657 
658  /* Make sure we send the data without delay ONLY if we
659  provided the complete response (not on partial write) */
660  if (ret == left)
661  post_cork_setsockopt (connection, false);
662 
663  return ret;
664 }
665 
666 
667 #endif /* _MHD_HAVE_SENDFILE */
MHD_socket
int MHD_socket
Definition: microhttpd.h:187
MHD_SENFILE_CHUNK_
#define MHD_SENFILE_CHUNK_
Definition: mhd_send.c:455
MHD_SSO_HDR_CORK
@ MHD_SSO_HDR_CORK
Definition: mhd_send.h:77
_
#define _(String)
Definition: mhd_options.h:42
MHD_Daemon::options
enum MHD_FLAG options
Definition: internal.h:1605
MHD_Connection::sk_cork_on
bool sk_cork_on
Definition: internal.h:885
MHD_EPOLL_STATE_WRITE_READY
@ MHD_EPOLL_STATE_WRITE_READY
Definition: internal.h:606
MHD_send_on_connection2_
ssize_t MHD_send_on_connection2_(struct MHD_Connection *connection, const char *header, size_t header_size, const char *buffer, size_t buffer_size)
Definition: mhd_send.c:378
MHD_Response::fd_off
uint64_t fd_off
Definition: internal.h:1653
MHD_socket_set_nodelay_
int MHD_socket_set_nodelay_(MHD_socket sock, bool on)
Definition: mhd_sockets.c:477
MHD_send_on_connection_
ssize_t MHD_send_on_connection_(struct MHD_Connection *connection, const char *buffer, size_t buffer_size, enum MHD_SendSocketOptions options)
Definition: mhd_send.c:233
MHD_ERR_AGAIN_
#define MHD_ERR_AGAIN_
Definition: internal.h:1863
post_cork_setsockopt
static void post_cork_setsockopt(struct MHD_Connection *connection, bool want_cork)
Definition: mhd_send.c:133
MHD_CONNECTION_CLOSED
@ MHD_CONNECTION_CLOSED
Definition: internal.h:526
OFF_T_MAX
#define OFF_T_MAX
Definition: mhd_limits.h:123
MHD_INVALID_SOCKET
#define MHD_INVALID_SOCKET
Definition: microhttpd.h:188
MHD_Response::total_size
uint64_t total_size
Definition: internal.h:1642
NULL
#define NULL
Definition: reason_phrase.c:30
MHD_socket_get_error_
#define MHD_socket_get_error_()
Definition: mhd_sockets.h:523
MHD_SCKT_ERR_IS_
#define MHD_SCKT_ERR_IS_(err, code)
Definition: mhd_sockets.h:611
MHD_Response::fd
int fd
Definition: internal.h:1680
MHD_SSO_MAY_CORK
@ MHD_SSO_MAY_CORK
Definition: mhd_send.h:68
pre_cork_setsockopt
static void pre_cork_setsockopt(struct MHD_Connection *connection, bool want_cork)
Definition: mhd_send.c:48
MHD_ERR_CONNRESET_
#define MHD_ERR_CONNRESET_
Definition: internal.h:1868
MHD_SendSocketOptions
MHD_SendSocketOptions
Definition: mhd_send.h:59
MHD_SENFILE_CHUNK_THR_P_C_
#define MHD_SENFILE_CHUNK_THR_P_C_
Definition: mhd_send.c:460
MHD_Connection::state
enum MHD_CONNECTION_STATE state
Definition: internal.h:924
MHD_USE_TLS
@ MHD_USE_TLS
Definition: microhttpd.h:1052
MHD_socket_last_strerr_
#define MHD_socket_last_strerr_()
Definition: mhd_sockets.h:549
MHD_Connection::response_write_position
uint64_t response_write_position
Definition: internal.h:824
mhd_assert
#define mhd_assert(CHK)
Definition: mhd_assert.h:39
SSIZE_MAX
#define SSIZE_MAX
Definition: mhd_limits.h:111
MHD_Connection::response
struct MHD_Response * response
Definition: internal.h:680
MHD_SCKT_ERR_IS_EAGAIN_
#define MHD_SCKT_ERR_IS_EAGAIN_(err)
Definition: mhd_sockets.h:645
MHD_Connection::daemon
struct MHD_Daemon * daemon
Definition: internal.h:675
MHD_ERR_BADF_
#define MHD_ERR_BADF_
Definition: internal.h:1884
MAYBE_MSG_NOSIGNAL
#define MAYBE_MSG_NOSIGNAL
Definition: mhd_sockets.h:169
MHD_socket_cork_
int MHD_socket_cork_(MHD_socket sock, bool on)
Definition: mhd_sockets.c:506
MHD_USE_THREAD_PER_CONNECTION
@ MHD_USE_THREAD_PER_CONNECTION
Definition: microhttpd.h:1067
MHD_Connection
Definition: internal.h:633
MHD_ERR_NOTCONN_
#define MHD_ERR_NOTCONN_
Definition: internal.h:1874
MHD_SCKT_ECONNRESET_
#define MHD_SCKT_ECONNRESET_
Definition: mhd_sockets.h:419
offset
int off_t offset
Definition: microhttpd.h:3158
mhd_send.h
Implementation of send() wrappers.
MHD_SCKT_EBADF_
#define MHD_SCKT_EBADF_
Definition: mhd_sockets.h:454
MHD_SCKT_ERR_IS_EINTR_
#define MHD_SCKT_ERR_IS_EINTR_(err)
Definition: mhd_sockets.h:634
MHD_SSO_NO_CORK
@ MHD_SSO_NO_CORK
Definition: mhd_send.h:64
MHD_SCKT_SEND_MAX_SIZE_
#define MHD_SCKT_SEND_MAX_SIZE_
Definition: mhd_sockets.h:222
MHD_Connection::socket_fd
MHD_socket socket_fd
Definition: internal.h:752