GNU libmicrohttpd  0.9.72
mhd_send.c
Go to the documentation of this file.
1 /*
2  This file is part of libmicrohttpd
3  Copyright (C) 2017,2020 Karlson2k (Evgeny Grin), Full re-write of buffering and
4  pushing, many bugs fixes, optimisations, sendfile() porting
5  Copyright (C) 2019 ng0 <ng0@n0.is>, Initial version of send() wrappers
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public
9  License as published by the Free Software Foundation; either
10  version 2.1 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License along with this library; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 
21  */
22 
31 /* Worth considering for future improvements and additions:
32  * NetBSD has no sendfile or sendfile64. The way to work
33  * with this seems to be to mmap the file and write(2) as
34  * large a chunk as possible to the socket. Alternatively,
35  * use madvise(..., MADV_SEQUENTIAL). */
36 
37 #include "mhd_send.h"
38 #ifdef MHD_LINUX_SOLARIS_SENDFILE
39 #include <sys/sendfile.h>
40 #endif /* MHD_LINUX_SOLARIS_SENDFILE */
41 #if defined(HAVE_FREEBSD_SENDFILE) || defined(HAVE_DARWIN_SENDFILE)
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <sys/uio.h>
45 #endif /* HAVE_FREEBSD_SENDFILE || HAVE_DARWIN_SENDFILE */
46 #ifdef HAVE_SYS_PARAM_H
47 /* For FreeBSD version identification */
48 #include <sys/param.h>
49 #endif /* HAVE_SYS_PARAM_H */
50 #include "mhd_assert.h"
51 
52 #include "mhd_limits.h"
53 
57 #define MHD_SENFILE_CHUNK_ (0x20000)
58 
62 #define MHD_SENFILE_CHUNK_THR_P_C_ (0x200000)
63 
64 #ifdef HAVE_FREEBSD_SENDFILE
65 #ifdef SF_FLAGS
69 static int freebsd_sendfile_flags_;
70 
74 static int freebsd_sendfile_flags_thd_p_c_;
75 #endif /* SF_FLAGS */
79 void
80 MHD_send_init_static_vars_ (void)
81 {
82 /* FreeBSD 11 and later allow to specify read-ahead size
83  * and handles SF_NODISKIO differently.
84  * SF_FLAGS defined only on FreeBSD 11 and later. */
85 #ifdef SF_FLAGS
86  long sys_page_size = sysconf (_SC_PAGESIZE);
87  if (0 >= sys_page_size)
88  { /* Failed to get page size. */
89  freebsd_sendfile_flags_ = SF_NODISKIO;
90  freebsd_sendfile_flags_thd_p_c_ = SF_NODISKIO;
91  }
92  else
93  {
94  freebsd_sendfile_flags_ =
95  SF_FLAGS ((uint16_t) ((MHD_SENFILE_CHUNK_ + sys_page_size - 1)
96  / sys_page_size), SF_NODISKIO);
97  freebsd_sendfile_flags_thd_p_c_ =
98  SF_FLAGS ((uint16_t) ((MHD_SENFILE_CHUNK_THR_P_C_ + sys_page_size - 1)
99  / sys_page_size), SF_NODISKIO);
100  }
101 #endif /* SF_FLAGS */
102 }
103 
104 
105 #endif /* HAVE_FREEBSD_SENDFILE */
106 
107 
116 static bool
118  bool nodelay_state)
119 {
120  const MHD_SCKT_OPT_BOOL_ off_val = 0;
121  const MHD_SCKT_OPT_BOOL_ on_val = 1;
122  int err_code;
123 
124  if (0 == setsockopt (connection->socket_fd,
125  IPPROTO_TCP,
126  TCP_NODELAY,
127  (const void *) (nodelay_state ? &on_val : &off_val),
128  sizeof (off_val)))
129  {
130  connection->sk_nodelay = nodelay_state;
131  return true;
132  }
133  err_code = MHD_socket_get_error_ ();
134  switch (err_code)
135  {
136  case ENOTSOCK:
137  /* FIXME: Could be we are talking to a pipe, maybe remember this
138  and avoid all setsockopt() in the future? */
139  break;
140  case EBADF:
141  /* FIXME: should we die hard here? */
142  case EINVAL:
143  /* FIXME: optlen invalid, should at least log this, maybe die */
144  case EFAULT:
145  /* wopsie, should at least log this, FIXME: maybe die */
146  case ENOPROTOOPT:
147  /* optlen unknown, should at least log this */
148  default:
149 #ifdef HAVE_MESSAGES
150  MHD_DLOG (connection->daemon,
151  _ ("Setting %s option to %s state failed: %s\n"),
152  "TCP_NODELAY",
153  nodelay_state ? _ ("ON") : _ ("OFF"),
154  MHD_socket_strerr_ (err_code));
155 #endif /* HAVE_MESSAGES */
156  break;
157  }
158  return false;
159 }
160 
161 
162 #if defined(MHD_TCP_CORK_NOPUSH)
171 static bool
172 connection_set_cork_state_ (struct MHD_Connection *connection,
173  bool cork_state)
174 {
175  const MHD_SCKT_OPT_BOOL_ off_val = 0;
176  const MHD_SCKT_OPT_BOOL_ on_val = 1;
177  int err_code;
178 
179  if (0 == setsockopt (connection->socket_fd,
180  IPPROTO_TCP,
181  MHD_TCP_CORK_NOPUSH,
182  (const void *) (cork_state ? &on_val : &off_val),
183  sizeof (off_val)))
184  {
185  connection->sk_corked = cork_state;
186  return true;
187  }
188  err_code = MHD_socket_get_error_ ();
189  switch (err_code)
190  {
191  case ENOTSOCK:
192  /* FIXME: Could be we are talking to a pipe, maybe remember this
193  and avoid all setsockopt() in the future? */
194  break;
195  case EBADF:
196  /* FIXME: should we die hard here? */
197  case EINVAL:
198  /* FIXME: optlen invalid, should at least log this, maybe die */
199  case EFAULT:
200  /* wopsie, should at least log this, FIXME: maybe die */
201  case ENOPROTOOPT:
202  /* optlen unknown, should at least log this */
203  default:
204 #ifdef HAVE_MESSAGES
205  MHD_DLOG (connection->daemon,
206  _ ("Setting %s option to %s state failed: %s\n"),
207 #ifdef TCP_CORK
208  "TCP_CORK",
209 #else /* ! TCP_CORK */
210  "TCP_NOPUSH",
211 #endif /* ! TCP_CORK */
212  cork_state ? _ ("ON") : _ ("OFF"),
213  MHD_socket_strerr_ (err_code));
214 #endif /* HAVE_MESSAGES */
215  break;
216  }
217  return false;
218 }
219 
220 
221 #endif /* MHD_TCP_CORK_NOPUSH */
222 
233 static void
234 pre_send_setopt (struct MHD_Connection *connection,
235  bool plain_send,
236  bool push_data)
237 {
238  /* Try to buffer data if not sending the final piece.
239  * Final piece is indicated by push_data == true. */
240  const bool buffer_data = (! push_data);
241 
242  /* The goal is to minimise the total number of additional sys-calls
243  * before and after send().
244  * The following tricky (over-)complicated algorithm typically use zero,
245  * one or two additional sys-calls (depending on OS) for each response. */
246 
247  if (buffer_data)
248  {
249  /* Need to buffer data if possible. */
250 #ifdef MHD_USE_MSG_MORE
251  if (plain_send)
252  return; /* Data is buffered by send() with MSG_MORE flag.
253  * No need to check or change anything. */
254 #else /* ! MHD_USE_MSG_MORE */
255  (void) plain_send; /* Mute compiler warning. */
256 #endif /* ! MHD_USE_MSG_MORE */
257 
258 #ifdef MHD_TCP_CORK_NOPUSH
259  if (_MHD_ON == connection->sk_corked)
260  return; /* The connection was already corked. */
261 
262  if (connection_set_cork_state_ (connection, true))
263  return; /* The connection has been corked. */
264 
265  /* Failed to cork the connection.
266  * Really unlikely to happen on TCP connections. */
267 #endif /* MHD_TCP_CORK_NOPUSH */
268  if (_MHD_OFF == connection->sk_nodelay)
269  return; /* TCP_NODELAY was not set for the socket.
270  * Nagle's algorithm will buffer some data. */
271 
272  /* Try to reset TCP_NODELAY state for the socket.
273  * Ignore possible error as no other options exist to
274  * buffer data. */
275  connection_set_nodelay_state_ (connection, false);
276  /* TCP_NODELAY has been (hopefully) reset for the socket.
277  * Nagle's algorithm will buffer some data. */
278  return;
279  }
280 
281  /* Need to push data after send() */
282  /* If additional sys-call is required prefer to make it after the send()
283  * as the next send() may consume only part of the prepared data and
284  * more send() calls will be used. */
285 #ifdef MHD_TCP_CORK_NOPUSH
286 #ifdef _MHD_CORK_RESET_PUSH_DATA
287 #ifdef _MHD_CORK_RESET_PUSH_DATA_ALWAYS
288  /* Data can be pushed immediately by uncorking socket regardless of
289  * cork state before. */
290  /* This is typical for Linux, no other kernel with
291  * such behavior are known so far. */
292 
293  /* No need to check the current state of TCP_CORK / TCP_NOPUSH
294  * as reset of cork will push the data anyway. */
295  return; /* Data may be pushed by resetting of
296  * TCP_CORK / TCP_NOPUSH after send() */
297 #else /* ! _MHD_CORK_RESET_PUSH_DATA_ALWAYS */
298  /* Reset of TCP_CORK / TCP_NOPUSH will push the data
299  * only if socket is corked. */
300 
301 #ifdef _MHD_NODELAY_SET_PUSH_DATA_ALWAYS
302  /* Data can be pushed immediately by setting TCP_NODELAY regardless
303  * of TCP_NODDELAY or corking state before. */
304 
305  /* Dead code currently, no known kernels with such behavior. */
306  return; /* Data may be pushed by setting of TCP_NODELAY after send().
307  No need to make extra sys-calls before send().*/
308 #else /* ! _MHD_NODELAY_SET_PUSH_DATA_ALWAYS */
309 
310 #ifdef _MHD_NODELAY_SET_PUSH_DATA
311  /* Setting of TCP_NODELAY will push the data only if
312  * both TCP_NODELAY and TCP_CORK / TCP_NOPUSH were not set. */
313 
314  /* Data can be pushed immediately by uncorking socket if
315  * socket was corked before or by setting TCP_NODELAY if
316  * socket was not corked and TCP_NODELAY was not set before. */
317 
318  /* Dead code currently as Linux is the only kernel that push
319  * data by setting of TCP_NODELAY and Linux push data always. */
320 #else /* ! _MHD_NODELAY_SET_PUSH_DATA */
321  /* Data can be pushed immediately by uncorking socket or
322  * can be pushed by send() on uncorked socket if
323  * TCP_NODELAY was set *before*. */
324 
325  /* This is typical FreeBSD behavior. */
326 #endif /* ! _MHD_NODELAY_SET_PUSH_DATA */
327 
328  if (_MHD_ON == connection->sk_corked)
329  return; /* Socket is corked. Data can be pushed by resetting of
330  * TCP_CORK / TCP_NOPUSH after send() */
331  else if (_MHD_OFF == connection->sk_corked)
332  {
333  /* The socket is not corked. */
334  if (_MHD_ON == connection->sk_nodelay)
335  return; /* TCP_NODELAY was already set,
336  * data will be pushed automatically by the next send() */
337 #ifdef _MHD_NODELAY_SET_PUSH_DATA
338  else if (_MHD_UNKNOWN == connection->sk_nodelay)
339  {
340  /* Setting TCP_NODELAY may push data.
341  * Cork socket here and uncork after send(). */
342  if (connection_set_cork_state_ (connection, true))
343  return; /* The connection has been corked.
344  * Data can be pushed by resetting of
345  * TCP_CORK / TCP_NOPUSH after send() */
346  else
347  {
348  /* The socket cannot be corked.
349  * Really unlikely to happen on TCP connections */
350  /* Have to set TCP_NODELAY.
351  * If TCP_NODELAY real system state was OFF then
352  * already buffered data may be pushed here, but this is unlikely
353  * to happen as it is only a backup solution when corking has failed.
354  * Ignore possible error here as no other options exist to
355  * push data. */
356  connection_set_nodelay_state_ (connection, true);
357  /* TCP_NODELAY has been (hopefully) set for the socket.
358  * The data will be pushed by the next send(). */
359  return;
360  }
361  }
362 #endif /* _MHD_NODELAY_SET_PUSH_DATA */
363  else
364  {
365 #ifdef _MHD_NODELAY_SET_PUSH_DATA
366  /* TCP_NODELAY was switched off and
367  * the socket is not corked. */
368 #else /* ! _MHD_NODELAY_SET_PUSH_DATA */
369  /* Socket is not corked and TCP_NODELAY was not set or unknown. */
370 #endif /* ! _MHD_NODELAY_SET_PUSH_DATA */
371 
372  /* At least one additional sys-call is required. */
373  /* Setting TCP_NODELAY is optimal here as data will be pushed
374  * automatically by the next send() and no additional
375  * sys-call are needed after the send(). */
376  if (connection_set_nodelay_state_ (connection, true))
377  return;
378  else
379  {
380  /* Failed to set TCP_NODELAY for the socket.
381  * Really unlikely to happen on TCP connections. */
382  /* Cork the socket here and make additional sys-call
383  * to uncork the socket after send(). */
384  /* Ignore possible error here as no other options exist to
385  * push data. */
386  connection_set_cork_state_ (connection, true);
387  /* The connection has been (hopefully) corked.
388  * Data can be pushed by resetting of TCP_CORK / TCP_NOPUSH
389  * after send() */
390  return;
391  }
392  }
393  }
394  /* Corked state is unknown. Need to make sys-call here otherwise
395  * data may not be pushed. */
396  if (connection_set_cork_state_ (connection, true))
397  return; /* The connection has been corked.
398  * Data can be pushed by resetting of
399  * TCP_CORK / TCP_NOPUSH after send() */
400  /* The socket cannot be corked.
401  * Really unlikely to happen on TCP connections */
402  if (_MHD_ON == connection->sk_nodelay)
403  return; /* TCP_NODELAY was already set,
404  * data will be pushed by the next send() */
405  /* Have to set TCP_NODELAY. */
406 #ifdef _MHD_NODELAY_SET_PUSH_DATA
407  /* If TCP_NODELAY state was unknown (external connection) then
408  * already buffered data may be pushed here, but this is unlikely
409  * to happen as it is only a backup solution when corking has failed. */
410 #endif /* _MHD_NODELAY_SET_PUSH_DATA */
411  /* Ignore possible error here as no other options exist to
412  * push data. */
413  connection_set_nodelay_state_ (connection, true);
414  /* TCP_NODELAY has been (hopefully) set for the socket.
415  * The data will be pushed by the next send(). */
416  return;
417 #endif /* ! _MHD_NODELAY_SET_PUSH_DATA_ALWAYS */
418 #endif /* ! _MHD_CORK_RESET_PUSH_DATA_ALWAYS */
419 #else /* ! _MHD_CORK_RESET_PUSH_DATA */
420  /* Neither uncorking the socket or setting TCP_NODELAY
421  * push the data immediately. */
422  /* The only way to push the data is to use send() on uncorked
423  * socket with TCP_NODELAY switched on . */
424 
425  /* This is a typical *BSD (except FreeBSD) and Darwin behavior. */
426 
427  /* Uncork socket if socket wasn't uncorked. */
428  if (_MHD_OFF != connection->sk_corked)
429  connection_set_cork_state_ (connection, false);
430 
431  /* Set TCP_NODELAY if it wasn't set. */
432  if (_MHD_ON != connection->sk_nodelay)
433  connection_set_nodelay_state_ (connection, true);
434 
435  return;
436 #endif /* ! _MHD_CORK_RESET_PUSH_DATA */
437 #else /* ! MHD_TCP_CORK_NOPUSH */
438  /* Buffering of data is controlled only by
439  * Nagel's algorithm. */
440  /* Set TCP_NODELAY if it wasn't set. */
441  if (_MHD_ON != connection->sk_nodelay)
442  connection_set_nodelay_state_ (connection, true);
443 #endif /* ! MHD_TCP_CORK_NOPUSH */
444 }
445 
446 
447 #ifndef _MHD_CORK_RESET_PUSH_DATA_ALWAYS
459 static bool
460 zero_send_ (struct MHD_Connection *connection)
461 {
462  int dummy;
463  mhd_assert (_MHD_OFF == connection->sk_corked);
464  mhd_assert (_MHD_ON == connection->sk_nodelay);
465 
466  dummy = 0; /* Mute compiler and analyzer warnings */
467 
468  if (0 == MHD_send_ (connection->socket_fd, &dummy, 0))
469  return true;
470 
471 #ifdef HAVE_MESSAGES
472  MHD_DLOG (connection->daemon,
473  _ ("Zero-send failed: %s\n"),
475 #endif /* HAVE_MESSAGES */
476  return false;
477 }
478 
479 
480 #endif /* ! _MHD_CORK_RESET_PUSH_DATA_ALWAYS */
481 
492 static void
493 post_send_setopt (struct MHD_Connection *connection,
494  bool plain_send_next,
495  bool push_data)
496 {
497  /* Try to buffer data if not sending the final piece.
498  * Final piece is indicated by push_data == true. */
499  const bool buffer_data = (! push_data);
500 
501  if (buffer_data)
502  return; /* Nothing to do after send(). */
503 
504 #ifndef MHD_USE_MSG_MORE
505  (void) plain_send_next; /* Mute compiler warning */
506 #endif /* ! MHD_USE_MSG_MORE */
507 
508  /* Need to push data. */
509 #ifdef MHD_TCP_CORK_NOPUSH
510 #ifdef _MHD_CORK_RESET_PUSH_DATA_ALWAYS
511 #ifdef _MHD_NODELAY_SET_PUSH_DATA_ALWAYS
512 #ifdef MHD_USE_MSG_MORE
513  if (_MHD_OFF == connection->sk_corked)
514  {
515  if (_MHD_ON == connection->sk_nodelay)
516  return; /* Data was already pushed by send(). */
517  }
518  /* This is Linux kernel. There are options:
519  * * Push the data by setting of TCP_NODELAY (without change
520  * of the cork on the socket),
521  * * Push the data by resetting of TCP_CORK.
522  * The optimal choice depends on the next final send functions
523  * used on the same socket. If TCP_NODELAY wasn't set then push
524  * data by setting TCP_NODELAY (TCP_NODELAY will not be removed
525  * and is needed to push the data by send() without MSG_MORE).
526  * If send()/sendmsg() will be used next than push data by
527  * reseting of TCP_CORK so next send without MSG_MORE will push
528  * data to the network (without additional sys-call to push data).
529  * If next final send function will not support MSG_MORE (like
530  * sendfile() or TLS-connection) than push data by setting
531  * TCP_NODELAY so socket will remain corked (no additional
532  * sys-call before next send()). */
533  if ((_MHD_ON != connection->sk_nodelay) ||
534  (! plain_send_next))
535  {
536  if (connection_set_nodelay_state_ (connection, true))
537  return; /* Data has been pushed by TCP_NODELAY. */
538  /* Failed to set TCP_NODELAY for the socket.
539  * Really unlikely to happen on TCP connections. */
540  if (connection_set_cork_state_ (connection, false))
541  return; /* Data has been pushed by uncorking the socket. */
542  /* Failed to uncork the socket.
543  * Really unlikely to happen on TCP connections. */
544 
545  /* The socket cannot be uncorked, no way to push data */
546  }
547  else
548  {
549  if (connection_set_cork_state_ (connection, false))
550  return; /* Data has been pushed by uncorking the socket. */
551  /* Failed to uncork the socket.
552  * Really unlikely to happen on TCP connections. */
553  if (connection_set_nodelay_state_ (connection, true))
554  return; /* Data has been pushed by TCP_NODELAY. */
555  /* Failed to set TCP_NODELAY for the socket.
556  * Really unlikely to happen on TCP connections. */
557 
558  /* The socket cannot be uncorked, no way to push data */
559  }
560 #else /* ! MHD_USE_MSG_MORE */
561  /* Use setting of TCP_NODELAY here to avoid sys-call
562  * for corking the socket during sending of the next response. */
563  if (connection_set_nodelay_state_ (connection, true))
564  return; /* Data was pushed by TCP_NODELAY. */
565  /* Failed to set TCP_NODELAY for the socket.
566  * Really unlikely to happen on TCP connections. */
567  if (connection_set_cork_state_ (connection, false))
568  return; /* Data was pushed by uncorking the socket. */
569  /* Failed to uncork the socket.
570  * Really unlikely to happen on TCP connections. */
571 
572  /* The socket remains corked, no way to push data */
573 #endif /* ! MHD_USE_MSG_MORE */
574 #else /* ! _MHD_NODELAY_SET_PUSH_DATA_ALWAYS */
575  if (connection_set_cork_state_ (connection, false))
576  return; /* Data was pushed by uncorking the socket. */
577  /* Failed to uncork the socket.
578  * Really unlikely to happen on TCP connections. */
579  return; /* Socket remains corked, no way to push data */
580 #endif /* ! _MHD_NODELAY_SET_PUSH_DATA_ALWAYS */
581 #else /* ! _MHD_CORK_RESET_PUSH_DATA_ALWAYS */
582  /* This is a typical *BSD or Darwin kernel. */
583 
584  if (_MHD_OFF == connection->sk_corked)
585  {
586  if (_MHD_ON == connection->sk_nodelay)
587  return; /* Data was already pushed by send(). */
588 
589  /* Unlikely to reach this code.
590  * TCP_NODELAY should be turned on before send(). */
591  if (connection_set_nodelay_state_ (connection, true))
592  {
593  /* TCP_NODELAY has been set on uncorked socket.
594  * Use zero-send to push the data. */
595  if (zero_send_ (connection))
596  return; /* The data has been pushed by zero-send. */
597  }
598 
599  /* Failed to push the data by all means. */
600  /* There is nothing left to try. */
601  }
602  else
603  {
604 #ifdef _MHD_CORK_RESET_PUSH_DATA
605  enum MHD_tristate old_cork_state = connection->sk_corked;
606 #endif /* _MHD_CORK_RESET_PUSH_DATA */
607  /* The socket is corked or cork state is unknown. */
608 
609  if (connection_set_cork_state_ (connection, false))
610  {
611 #ifdef _MHD_CORK_RESET_PUSH_DATA
612  /* FreeBSD kernel */
613  if (_MHD_OFF == old_cork_state)
614  return; /* Data has been pushed by uncorking the socket. */
615 #endif /* _MHD_CORK_RESET_PUSH_DATA */
616 
617  /* Unlikely to reach this code.
618  * The data should be pushed by uncorking (FreeBSD) or
619  * the socket should be uncorked before send(). */
620  if ((_MHD_ON == connection->sk_nodelay) ||
621  (connection_set_nodelay_state_ (connection, true)))
622  {
623  /* TCP_NODELAY is turned ON on uncorked socket.
624  * Use zero-send to push the data. */
625  if (zero_send_ (connection))
626  return; /* The data has been pushed by zero-send. */
627  }
628  }
629  /* The socket remains corked. Data cannot be pushed. */
630  }
631 #endif /* ! _MHD_CORK_RESET_PUSH_DATA_ALWAYS */
632 #else /* ! MHD_TCP_CORK_NOPUSH */
633  /* Corking is not supported. Buffering is controlled
634  * by TCP_NODELAY only. */
635  mhd_assert (_MHD_ON != connection->sk_corked);
636  if (_MHD_ON == connection->sk_nodelay)
637  return; /* Data was already pushed by send(). */
638 
639  /* Unlikely to reach this code.
640  * TCP_NODELAY should be turned on before send(). */
641  if (connection_set_nodelay_state_ (connection, true))
642  {
643  /* TCP_NODELAY has been set.
644  * Use zero-send to push the data. */
645  if (zero_send_ (connection))
646  return; /* The data has been pushed by zero-send. */
647  }
648 
649  /* Failed to push the data. */
650 #endif /* ! MHD_TCP_CORK_NOPUSH */
651 #ifdef HAVE_MESSAGES
652  MHD_DLOG (connection->daemon,
653  _ ("Failed to push the data from buffers to the network. "
654  "Client may experience some delay "
655  "(usually in range 200ms - 5 sec).\n"));
656 #endif /* HAVE_MESSAGES */
657  return;
658 }
659 
660 
661 ssize_t
662 MHD_send_data_ (struct MHD_Connection *connection,
663  const char *buffer,
664  size_t buffer_size,
665  bool push_data)
666 {
667  MHD_socket s = connection->socket_fd;
668  ssize_t ret;
669 #ifdef HTTPS_SUPPORT
670  const bool tls_conn = (connection->daemon->options & MHD_USE_TLS);
671 #else /* ! HTTPS_SUPPORT */
672  const bool tls_conn = false;
673 #endif /* ! HTTPS_SUPPORT */
674 
675  if ( (MHD_INVALID_SOCKET == s) ||
676  (MHD_CONNECTION_CLOSED == connection->state) )
677  {
678  return MHD_ERR_NOTCONN_;
679  }
680 
681  if (buffer_size > SSIZE_MAX)
682  {
683  buffer_size = SSIZE_MAX; /* Max return value */
684  push_data = false; /* Incomplete send */
685  }
686 
687  if (tls_conn)
688  {
689 #ifdef HTTPS_SUPPORT
690  pre_send_setopt (connection, (! tls_conn), push_data);
691  ret = gnutls_record_send (connection->tls_session,
692  buffer,
693  buffer_size);
694  if (GNUTLS_E_AGAIN == ret)
695  {
696 #ifdef EPOLL_SUPPORT
697  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
698 #endif
699  return MHD_ERR_AGAIN_;
700  }
701  if (GNUTLS_E_INTERRUPTED == ret)
702  return MHD_ERR_AGAIN_;
703  if ( (GNUTLS_E_ENCRYPTION_FAILED == ret) ||
704  (GNUTLS_E_INVALID_SESSION == ret) )
705  return MHD_ERR_CONNRESET_;
706  if (GNUTLS_E_MEMORY_ERROR == ret)
707  return MHD_ERR_NOMEM_;
708  if (ret < 0)
709  {
710  /* Treat any other error as hard error. */
711  return MHD_ERR_NOTCONN_;
712  }
713 #ifdef EPOLL_SUPPORT
714  /* Unlike non-TLS connections, do not reset "write-ready" if
715  * sent amount smaller than provided amount, as TLS
716  * connections may break data into smaller parts for sending. */
717 #endif /* EPOLL_SUPPORT */
718 #endif /* HTTPS_SUPPORT */
719  (void) 0; /* Mute compiler warning for non-TLS builds. */
720  }
721  else
722  {
723  /* plaintext transmission */
724  if (buffer_size > MHD_SCKT_SEND_MAX_SIZE_)
725  {
726  buffer_size = MHD_SCKT_SEND_MAX_SIZE_; /* send() return value limit */
727  push_data = false; /* Incomplete send */
728  }
729 
730  pre_send_setopt (connection, (! tls_conn), push_data);
731 #ifdef MHD_USE_MSG_MORE
732  ret = MHD_send4_ (s,
733  buffer,
734  buffer_size,
735  push_data ? 0 : MSG_MORE);
736 #else
737  ret = MHD_send4_ (s,
738  buffer,
739  buffer_size,
740  0);
741 #endif
742 
743  if (0 > ret)
744  {
745  const int err = MHD_socket_get_error_ ();
746 
747  if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
748  {
749 #if EPOLL_SUPPORT
750  /* EAGAIN, no longer write-ready */
751  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
752 #endif /* EPOLL_SUPPORT */
753  return MHD_ERR_AGAIN_;
754  }
755  if (MHD_SCKT_ERR_IS_EINTR_ (err))
756  return MHD_ERR_AGAIN_;
758  return MHD_ERR_CONNRESET_;
760  return MHD_ERR_NOMEM_;
761  /* Treat any other error as hard error. */
762  return MHD_ERR_NOTCONN_;
763  }
764 #if EPOLL_SUPPORT
765  else if (buffer_size > (size_t) ret)
766  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
767 #endif /* EPOLL_SUPPORT */
768  }
769 
770  /* If there is a need to push the data from network buffers
771  * call post_send_setopt(). */
772  /* If TLS connection is used then next final send() will be
773  * without MSG_MORE support. If non-TLS connection is used
774  * it's unknown whether sendfile() will be used or not so
775  * assume that next call will be the same, like this call. */
776  if ( (push_data) &&
777  (buffer_size == (size_t) ret) )
778  post_send_setopt (connection, (! tls_conn), push_data);
779 
780  return ret;
781 }
782 
783 
784 #if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV) || defined(_WIN32)
785 #define _MHD_USE_SEND_VEC 1
786 #endif /* HAVE_SENDMSG || HAVE_WRITEV || _WIN32*/
787 
788 ssize_t
790  const char *header,
791  size_t header_size,
792  bool never_push_hdr,
793  const char *body,
794  size_t body_size,
795  bool complete_response)
796 {
797  ssize_t ret;
798  bool push_hdr;
799  bool push_body;
800  MHD_socket s = connection->socket_fd;
801 #ifndef _WIN32
802 #define _MHD_SEND_VEC_MAX MHD_SCKT_SEND_MAX_SIZE_
803 #else /* ! _WIN32 */
804 #define _MHD_SEND_VEC_MAX UINT32_MAX
805 #endif /* ! _WIN32 */
806 #ifdef _MHD_USE_SEND_VEC
807 #if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
808  struct iovec vector[2];
809 #ifdef HAVE_SENDMSG
810  struct msghdr msg;
811 #endif /* HAVE_SENDMSG */
812 #endif /* HAVE_SENDMSG || HAVE_WRITEV */
813 #ifdef _WIN32
814  WSABUF vector[2];
815  DWORD vec_sent;
816 #endif /* _WIN32 */
817  bool no_vec; /* Is vector-send() disallowed? */
818 
819  no_vec = false;
820 #ifdef HTTPS_SUPPORT
821  no_vec = no_vec || (connection->daemon->options & MHD_USE_TLS);
822 #endif /* HTTPS_SUPPORT */
823 #if ! defined(MHD_WINSOCK_SOCKETS) && \
824  (! defined(HAVE_SENDMSG) || ! defined(MSG_NOSIGNAL)) && \
825  defined(HAVE_SEND_SIGPIPE_SUPPRESS)
826  no_vec = no_vec || (! connection->daemon->sigpipe_blocked &&
827  ! connection->sk_spipe_suppress);
828 #endif /* !MHD_WINSOCK_SOCKETS && (!HAVE_SENDMSG || ! MSG_NOSIGNAL)
829  && !HAVE_SEND_SIGPIPE_SUPPRESS */
830 #endif /* _MHD_USE_SEND_VEC */
831 
832  mhd_assert ( (NULL != body) || (0 == body_size) );
833 
834  if ( (MHD_INVALID_SOCKET == s) ||
835  (MHD_CONNECTION_CLOSED == connection->state) )
836  {
837  return MHD_ERR_NOTCONN_;
838  }
839 
840  push_body = complete_response;
841 
842  if (! never_push_hdr)
843  {
844  if (! complete_response)
845  push_hdr = true; /* Push the header as the client may react
846  * on header alone while the body data is
847  * being prepared. */
848  else
849  {
850  if (1400 > (header_size + body_size))
851  push_hdr = false; /* Do not push the header as complete
852  * reply is already ready and the whole
853  * reply most probably will fit into
854  * the single IP packet. */
855  else
856  push_hdr = true; /* Push header alone so client may react
857  * on it while reply body is being delivered. */
858  }
859  }
860  else
861  push_hdr = false;
862 
863  if (complete_response && (0 == body_size))
864  push_hdr = true; /* The header alone is equal to the whole response. */
865 
866  if (
867 #ifdef _MHD_USE_SEND_VEC
868  (no_vec) ||
869  (0 == body_size) ||
870  ((size_t) SSIZE_MAX <= header_size) ||
871  ((size_t) _MHD_SEND_VEC_MAX < header_size)
872 #ifdef _WIN32
873  || ((size_t) UINT_MAX < header_size)
874 #endif /* _WIN32 */
875 #else /* ! _MHD_USE_SEND_VEC */
876  true
877 #endif /* ! _MHD_USE_SEND_VEC */
878  )
879  {
880  ret = MHD_send_data_ (connection,
881  header,
882  header_size,
883  push_hdr);
884 
885  if ( (header_size == (size_t) ret) &&
886  ((size_t) SSIZE_MAX > header_size) &&
887  (0 != body_size) &&
888  (connection->sk_nonblck) )
889  {
890  ssize_t ret2;
891  /* The header has been sent completely.
892  * Try to send the reply body without waiting for
893  * the next round. */
894  /* Make sure that sum of ret + ret2 will not exceed SSIZE_MAX as
895  * function needs to return positive value if succeed. */
896  if ( (((size_t) SSIZE_MAX) - ((size_t) ret)) < body_size)
897  {
898  body_size = (((size_t) SSIZE_MAX) - ((size_t) ret));
899  complete_response = false;
900  push_body = complete_response;
901  }
902 
903  ret2 = MHD_send_data_ (connection,
904  body,
905  body_size,
906  push_body);
907  if (0 < ret2)
908  return ret + ret2; /* Total data sent */
909  if (MHD_ERR_AGAIN_ == ret2)
910  return ret;
911 
912  return ret2; /* Error code */
913  }
914  return ret;
915  }
916 #ifdef _MHD_USE_SEND_VEC
917 
918  if ( ((size_t) SSIZE_MAX <= body_size) ||
919  ((size_t) SSIZE_MAX < (header_size + body_size)) )
920  {
921  /* Return value limit */
922  body_size = SSIZE_MAX - header_size;
923  complete_response = false;
924  push_body = complete_response;
925  }
926 #if (SSIZE_MAX != _MHD_SEND_VEC_MAX) || (_MHD_SEND_VEC_MAX + 0 == 0)
927  if (((size_t) _MHD_SEND_VEC_MAX <= body_size) ||
928  ((size_t) _MHD_SEND_VEC_MAX < (header_size + body_size)))
929  {
930  /* Send total amount limit */
931  body_size = _MHD_SEND_VEC_MAX - header_size;
932  complete_response = false;
933  push_body = complete_response;
934  }
935 #endif /* SSIZE_MAX != _MHD_SEND_VEC_MAX */
936 
937  pre_send_setopt (connection,
938 #ifdef HAVE_SENDMSG
939  true,
940 #else /* ! HAVE_SENDMSG */
941  false,
942 #endif /* ! HAVE_SENDMSG */
943  push_hdr || push_body);
944 #if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
945  vector[0].iov_base = (void *) header;
946  vector[0].iov_len = header_size;
947  vector[1].iov_base = (void *) body;
948  vector[1].iov_len = body_size;
949 
950 #if defined(HAVE_SENDMSG)
951  memset (&msg, 0, sizeof(msg));
952  msg.msg_iov = vector;
953  msg.msg_iovlen = 2;
954 
955  ret = sendmsg (s, &msg, MSG_NOSIGNAL_OR_ZERO);
956 #elif defined (HAVE_WRITEV)
957  ret = writev (s, vector, 2);
958 #endif /* HAVE_WRITEV */
959 #endif /* HAVE_SENDMSG || HAVE_WRITEV */
960 #ifdef _WIN32
961  if ((size_t) UINT_MAX < body_size)
962  {
963  /* Send item size limit */
964  body_size = UINT_MAX;
965  complete_response = false;
966  push_body = complete_response;
967  }
968  vector[0].buf = (char *) header;
969  vector[0].len = (unsigned long) header_size;
970  vector[1].buf = (char *) body;
971  vector[1].len = (unsigned long) body_size;
972 
973  ret = WSASend (s, vector, 2, &vec_sent, 0, NULL, NULL);
974  if (0 == ret)
975  ret = (ssize_t) vec_sent;
976  else
977  ret = -1;
978 #endif /* _WIN32 */
979 
980  if (0 > ret)
981  {
982  const int err = MHD_socket_get_error_ ();
983 
984  if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
985  {
986 #if EPOLL_SUPPORT
987  /* EAGAIN, no longer write-ready */
988  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
989 #endif /* EPOLL_SUPPORT */
990  return MHD_ERR_AGAIN_;
991  }
992  if (MHD_SCKT_ERR_IS_EINTR_ (err))
993  return MHD_ERR_AGAIN_;
995  return MHD_ERR_CONNRESET_;
997  return MHD_ERR_NOMEM_;
998  /* Treat any other error as hard error. */
999  return MHD_ERR_NOTCONN_;
1000  }
1001 #if EPOLL_SUPPORT
1002  else if ((header_size + body_size) > (size_t) ret)
1003  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
1004 #endif /* EPOLL_SUPPORT */
1005 
1006  /* If there is a need to push the data from network buffers
1007  * call post_send_setopt(). */
1008  if ( (push_body) &&
1009  ((header_size + body_size) == (size_t) ret) )
1010  {
1011  /* Complete reply has been sent. */
1012  /* If TLS connection is used then next final send() will be
1013  * without MSG_MORE support. If non-TLS connection is used
1014  * it's unknown whether next 'send' will be plain send() / sendmsg() or
1015  * sendfile() will be used so assume that next final send() will be
1016  * the same, like for this response. */
1017  post_send_setopt (connection,
1018 #ifdef HAVE_SENDMSG
1019  true,
1020 #else /* ! HAVE_SENDMSG */
1021  false,
1022 #endif /* ! HAVE_SENDMSG */
1023  true);
1024  }
1025  else if ( (push_hdr) &&
1026  (header_size <= (size_t) ret))
1027  {
1028  /* The header has been sent completely and there is a
1029  * need to push the header data. */
1030  /* Luckily the type of send function will be used next is known. */
1031  post_send_setopt (connection,
1032 #if defined(_MHD_HAVE_SENDFILE)
1033  MHD_resp_sender_std == connection->resp_sender,
1034 #else /* ! _MHD_HAVE_SENDFILE */
1035  true,
1036 #endif /* ! _MHD_HAVE_SENDFILE */
1037  true);
1038  }
1039 
1040  return ret;
1041 #else /* ! _MHD_USE_SEND_VEC */
1042  mhd_assert (false);
1043  return MHD_ERR_CONNRESET_; /* Unreachable. Mute warnings. */
1044 #endif /* ! _MHD_USE_SEND_VEC */
1045 }
1046 
1047 
1048 #if defined(_MHD_HAVE_SENDFILE)
1049 ssize_t
1050 MHD_send_sendfile_ (struct MHD_Connection *connection)
1051 {
1052  ssize_t ret;
1053  const int file_fd = connection->response->fd;
1054  uint64_t left;
1055  uint64_t offsetu64;
1056 #ifndef HAVE_SENDFILE64
1057  const uint64_t max_off_t = (uint64_t) OFF_T_MAX;
1058 #else /* HAVE_SENDFILE64 */
1059  const uint64_t max_off_t = (uint64_t) OFF64_T_MAX;
1060 #endif /* HAVE_SENDFILE64 */
1061 #ifdef MHD_LINUX_SOLARIS_SENDFILE
1062 #ifndef HAVE_SENDFILE64
1063  off_t offset;
1064 #else /* HAVE_SENDFILE64 */
1065  off64_t offset;
1066 #endif /* HAVE_SENDFILE64 */
1067 #endif /* MHD_LINUX_SOLARIS_SENDFILE */
1068 #ifdef HAVE_FREEBSD_SENDFILE
1069  off_t sent_bytes;
1070  int flags = 0;
1071 #endif
1072 #ifdef HAVE_DARWIN_SENDFILE
1073  off_t len;
1074 #endif /* HAVE_DARWIN_SENDFILE */
1075  const bool used_thr_p_c = (0 != (connection->daemon->options
1077  const size_t chunk_size = used_thr_p_c ? MHD_SENFILE_CHUNK_THR_P_C_ :
1079  size_t send_size = 0;
1080  bool push_data;
1081  mhd_assert (MHD_resp_sender_sendfile == connection->resp_sender);
1082  mhd_assert (0 == (connection->daemon->options & MHD_USE_TLS));
1083 
1084  offsetu64 = connection->response_write_position
1085  + connection->response->fd_off;
1086  if (max_off_t < offsetu64)
1087  { /* Retry to send with standard 'send()'. */
1088  connection->resp_sender = MHD_resp_sender_std;
1089  return MHD_ERR_AGAIN_;
1090  }
1091 
1092  left = connection->response->total_size - connection->response_write_position;
1093 
1094  if ( (uint64_t) SSIZE_MAX < left)
1095  left = SSIZE_MAX;
1096 
1097  /* Do not allow system to stick sending on single fast connection:
1098  * use 128KiB chunks (2MiB for thread-per-connection). */
1099  if (chunk_size < left)
1100  {
1101  send_size = chunk_size;
1102  push_data = false; /* No need to push data, there is more to send. */
1103  }
1104  else
1105  {
1106  send_size = (size_t) left;
1107  push_data = true; /* Final piece of data, need to push to the network. */
1108  }
1109  pre_send_setopt (connection, false, push_data);
1110 
1111 #ifdef MHD_LINUX_SOLARIS_SENDFILE
1112 #ifndef HAVE_SENDFILE64
1113  offset = (off_t) offsetu64;
1114  ret = sendfile (connection->socket_fd,
1115  file_fd,
1116  &offset,
1117  send_size);
1118 #else /* HAVE_SENDFILE64 */
1119  offset = (off64_t) offsetu64;
1120  ret = sendfile64 (connection->socket_fd,
1121  file_fd,
1122  &offset,
1123  send_size);
1124 #endif /* HAVE_SENDFILE64 */
1125  if (0 > ret)
1126  {
1127  const int err = MHD_socket_get_error_ ();
1128  if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
1129  {
1130 #ifdef EPOLL_SUPPORT
1131  /* EAGAIN --- no longer write-ready */
1132  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
1133 #endif /* EPOLL_SUPPORT */
1134  return MHD_ERR_AGAIN_;
1135  }
1136  if (MHD_SCKT_ERR_IS_EINTR_ (err))
1137  return MHD_ERR_AGAIN_;
1138 #ifdef HAVE_LINUX_SENDFILE
1139  if (MHD_SCKT_ERR_IS_ (err,
1140  MHD_SCKT_EBADF_))
1141  return MHD_ERR_BADF_;
1142  /* sendfile() failed with EINVAL if mmap()-like operations are not
1143  supported for FD or other 'unusual' errors occurred, so we should try
1144  to fall back to 'SEND'; see also this thread for info on
1145  odd libc/Linux behavior with sendfile:
1146  http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html */
1147  connection->resp_sender = MHD_resp_sender_std;
1148  return MHD_ERR_AGAIN_;
1149 #else /* HAVE_SOLARIS_SENDFILE */
1150  if ( (EAFNOSUPPORT == err) ||
1151  (EINVAL == err) ||
1152  (EOPNOTSUPP == err) )
1153  { /* Retry with standard file reader. */
1154  connection->resp_sender = MHD_resp_sender_std;
1155  return MHD_ERR_AGAIN_;
1156  }
1157  if ( (ENOTCONN == err) ||
1158  (EPIPE == err) )
1159  {
1160  return MHD_ERR_CONNRESET_;
1161  }
1162  return MHD_ERR_BADF_; /* Fail hard */
1163 #endif /* HAVE_SOLARIS_SENDFILE */
1164  }
1165 #ifdef EPOLL_SUPPORT
1166  else if (send_size > (size_t) ret)
1167  connection->epoll_state &= ~MHD_EPOLL_STATE_WRITE_READY;
1168 #endif /* EPOLL_SUPPORT */
1169 #elif defined(HAVE_FREEBSD_SENDFILE)
1170 #ifdef SF_FLAGS
1171  flags = used_thr_p_c ?
1172  freebsd_sendfile_flags_thd_p_c_ : freebsd_sendfile_flags_;
1173 #endif /* SF_FLAGS */
1174  if (0 != sendfile (file_fd,
1175  connection->socket_fd,
1176  (off_t) offsetu64,
1177  send_size,
1178  NULL,
1179  &sent_bytes,
1180  flags))
1181  {
1182  const int err = MHD_socket_get_error_ ();
1183  if (MHD_SCKT_ERR_IS_EAGAIN_ (err) ||
1184  MHD_SCKT_ERR_IS_EINTR_ (err) ||
1185  (EBUSY == err) )
1186  {
1187  mhd_assert (SSIZE_MAX >= sent_bytes);
1188  if (0 != sent_bytes)
1189  return (ssize_t) sent_bytes;
1190 
1191  return MHD_ERR_AGAIN_;
1192  }
1193  /* Some unrecoverable error. Possibly file FD is not suitable
1194  * for sendfile(). Retry with standard send(). */
1195  connection->resp_sender = MHD_resp_sender_std;
1196  return MHD_ERR_AGAIN_;
1197  }
1198  mhd_assert (0 < sent_bytes);
1199  mhd_assert (SSIZE_MAX >= sent_bytes);
1200  ret = (ssize_t) sent_bytes;
1201 #elif defined(HAVE_DARWIN_SENDFILE)
1202  len = (off_t) send_size; /* chunk always fit */
1203  if (0 != sendfile (file_fd,
1204  connection->socket_fd,
1205  (off_t) offsetu64,
1206  &len,
1207  NULL,
1208  0))
1209  {
1210  const int err = MHD_socket_get_error_ ();
1211  if (MHD_SCKT_ERR_IS_EAGAIN_ (err) ||
1212  MHD_SCKT_ERR_IS_EINTR_ (err))
1213  {
1214  mhd_assert (0 <= len);
1215  mhd_assert (SSIZE_MAX >= len);
1216  mhd_assert (send_size >= (size_t) len);
1217  if (0 != len)
1218  return (ssize_t) len;
1219 
1220  return MHD_ERR_AGAIN_;
1221  }
1222  if ((ENOTCONN == err) ||
1223  (EPIPE == err) )
1224  return MHD_ERR_CONNRESET_;
1225  if ((ENOTSUP == err) ||
1226  (EOPNOTSUPP == err) )
1227  { /* This file FD is not suitable for sendfile().
1228  * Retry with standard send(). */
1229  connection->resp_sender = MHD_resp_sender_std;
1230  return MHD_ERR_AGAIN_;
1231  }
1232  return MHD_ERR_BADF_; /* Return hard error. */
1233  }
1234  mhd_assert (0 <= len);
1235  mhd_assert (SSIZE_MAX >= len);
1236  mhd_assert (send_size >= (size_t) len);
1237  ret = (ssize_t) len;
1238 #endif /* HAVE_FREEBSD_SENDFILE */
1239 
1240  /* If there is a need to push the data from network buffers
1241  * call post_send_setopt(). */
1242  /* It's unknown whether sendfile() will be used in the next
1243  * response so assume that next response will be the same. */
1244  if ( (push_data) &&
1245  (send_size == (size_t) ret) )
1246  post_send_setopt (connection, false, push_data);
1247 
1248  return ret;
1249 }
1250 
1251 
1252 #endif /* _MHD_HAVE_SENDFILE */
#define MHD_ERR_CONNRESET_
Definition: internal.h:1868
#define MHD_ERR_NOMEM_
Definition: internal.h:1879
@ MHD_EPOLL_STATE_WRITE_READY
Definition: internal.h:606
#define MHD_ERR_AGAIN_
Definition: internal.h:1863
#define MHD_ERR_BADF_
Definition: internal.h:1884
#define MHD_ERR_NOTCONN_
Definition: internal.h:1874
#define mhd_assert(CHK)
Definition: mhd_assert.h:39
#define OFF_T_MAX
Definition: mhd_limits.h:123
#define UINT_MAX
Definition: mhd_limits.h:45
#define MHD_SCKT_ERR_IS_(err, code)
Definition: mhd_sockets.h:611
int MHD_SCKT_OPT_BOOL_
Definition: mhd_sockets.h:203
#define MHD_SCKT_ERR_IS_EAGAIN_(err)
Definition: mhd_sockets.h:643
#define MHD_SCKT_ERR_IS_LOW_RESOURCES_(err)
Definition: mhd_sockets.h:656
#define MHD_socket_strerr_(err)
Definition: mhd_sockets.h:542
#define MHD_socket_last_strerr_()
Definition: mhd_sockets.h:549
#define MHD_SCKT_EBADF_
Definition: mhd_sockets.h:454
#define MHD_socket_get_error_()
Definition: mhd_sockets.h:523
#define MHD_SCKT_ERR_IS_EINTR_(err)
Definition: mhd_sockets.h:634
#define MHD_SCKT_SEND_MAX_SIZE_
Definition: mhd_sockets.h:222
#define MHD_send_(s, b, l)
Definition: mhd_sockets.h:261
#define MHD_SCKT_ECONNRESET_
Definition: mhd_sockets.h:419
#define NULL
Definition: reason_phrase.c:30
#define _(String)
Definition: mhd_options.h:42
#define MHD_SENFILE_CHUNK_THR_P_C_
Definition: mhd_send.c:62
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)
Definition: mhd_send.c:789
ssize_t MHD_send_data_(struct MHD_Connection *connection, const char *buffer, size_t buffer_size, bool push_data)
Definition: mhd_send.c:662
static bool zero_send_(struct MHD_Connection *connection)
Definition: mhd_send.c:460
#define _MHD_SEND_VEC_MAX
static bool connection_set_nodelay_state_(struct MHD_Connection *connection, bool nodelay_state)
Definition: mhd_send.c:117
static void pre_send_setopt(struct MHD_Connection *connection, bool plain_send, bool push_data)
Definition: mhd_send.c:234
static void post_send_setopt(struct MHD_Connection *connection, bool plain_send_next, bool push_data)
Definition: mhd_send.c:493
#define MHD_SENFILE_CHUNK_
Definition: mhd_send.c:57
Declarations of send() wrappers.
@ MHD_CONNECTION_CLOSED
Definition: internal.h:576
MHD_tristate
Definition: internal.h:173
@ _MHD_ON
Definition: internal.h:176
@ _MHD_UNKNOWN
Definition: internal.h:174
@ _MHD_OFF
Definition: internal.h:175
macros for mhd_assert()
limits values definitions
#define SSIZE_MAX
Definition: mhd_limits.h:111
#define MHD_send4_(s, b, l, f)
Definition: mhd_sockets.h:345
#define MSG_NOSIGNAL_OR_ZERO
Definition: mhd_sockets.h:184
int MHD_socket
Definition: microhttpd.h:196
int off_t offset
Definition: microhttpd.h:3196
#define MHD_INVALID_SOCKET
Definition: microhttpd.h:197
@ MHD_USE_THREAD_PER_CONNECTION
Definition: microhttpd.h:1090
@ MHD_USE_TLS
Definition: microhttpd.h:1075
MHD_socket socket_fd
Definition: internal.h:752
enum MHD_tristate sk_nodelay
Definition: internal.h:944
struct MHD_Response * response
Definition: internal.h:730
bool sk_nonblck
Definition: internal.h:784
uint64_t response_write_position
Definition: internal.h:874
enum MHD_CONNECTION_STATE state
Definition: internal.h:983
struct MHD_Daemon * daemon
Definition: internal.h:675
bool sk_spipe_suppress
Definition: internal.h:934
enum MHD_tristate sk_corked
Definition: internal.h:939
enum MHD_FLAG options
Definition: internal.h:1330
bool sigpipe_blocked
Definition: internal.h:1708
uint64_t total_size
Definition: internal.h:1642
uint64_t fd_off
Definition: internal.h:1653