GNU libmicrohttpd  0.9.76
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 #ifdef HAVE_SYSCONF
51 #include <unistd.h>
52 #endif /* HAVE_SYSCONF */
53 #include "mhd_assert.h"
54 
55 #include "mhd_limits.h"
56 
57 #ifdef MHD_VECT_SEND
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
62 #endif /* (!HAVE_SENDMSG || !MSG_NOSIGNAL) &&
63  MHD_SEND_SPIPE_SUPPRESS_POSSIBLE && MHD_SEND_SPIPE_SUPPRESS_NEEDED */
64 #endif /* MHD_VECT_SEND */
65 
69 #define MHD_SENFILE_CHUNK_ (0x20000)
70 
74 #define MHD_SENFILE_CHUNK_THR_P_C_ (0x200000)
75 
76 #ifdef HAVE_FREEBSD_SENDFILE
77 #ifdef SF_FLAGS
81 static int freebsd_sendfile_flags_;
82 
86 static int freebsd_sendfile_flags_thd_p_c_;
87 
88 
92 static void
93 freebsd_sendfile_init_ (void)
94 {
95  long sys_page_size = sysconf (_SC_PAGESIZE);
96  if (0 >= sys_page_size)
97  { /* Failed to get page size. */
98  freebsd_sendfile_flags_ = SF_NODISKIO;
99  freebsd_sendfile_flags_thd_p_c_ = SF_NODISKIO;
100  }
101  else
102  {
103  freebsd_sendfile_flags_ =
104  SF_FLAGS ((uint16_t) ((MHD_SENFILE_CHUNK_ + sys_page_size - 1)
105  / sys_page_size), SF_NODISKIO);
106  freebsd_sendfile_flags_thd_p_c_ =
107  SF_FLAGS ((uint16_t) ((MHD_SENFILE_CHUNK_THR_P_C_ + sys_page_size - 1)
108  / sys_page_size), SF_NODISKIO);
109  }
110 }
111 
112 
113 #endif /* SF_FLAGS */
114 #endif /* HAVE_FREEBSD_SENDFILE */
115 
116 
117 #if defined(HAVE_SYSCONF) && defined(_SC_IOV_MAX)
121 static unsigned long mhd_iov_max_ = 0;
122 
123 static void
124 iov_max_init_ (void)
125 {
126  long res = sysconf (_SC_IOV_MAX);
127  if (res >= 0)
128  mhd_iov_max_ = res;
129 #if defined(IOV_MAX)
130  else
131  mhd_iov_max_ = IOV_MAX;
132 #endif /* IOV_MAX */
133 }
134 
135 
139 #define _MHD_IOV_MAX mhd_iov_max_
140 #elif defined(IOV_MAX)
141 
145 #define _MHD_IOV_MAX IOV_MAX
146 #endif /* HAVE_SYSCONF && _SC_IOV_MAX */
147 
148 
152 void
154 {
155 #ifdef HAVE_FREEBSD_SENDFILE
156  /* FreeBSD 11 and later allow to specify read-ahead size
157  * and handles SF_NODISKIO differently.
158  * SF_FLAGS defined only on FreeBSD 11 and later. */
159 #ifdef SF_FLAGS
160  freebsd_sendfile_init_ ();
161 #endif /* SF_FLAGS */
162 #endif /* HAVE_FREEBSD_SENDFILE */
163 #if defined(HAVE_SYSCONF) && defined(_SC_IOV_MAX)
164  iov_max_init_ ();
165 #endif /* HAVE_SYSCONF && _SC_IOV_MAX */
166 }
167 
168 
169 bool
171  bool nodelay_state)
172 {
173 #ifdef TCP_NODELAY
174  const MHD_SCKT_OPT_BOOL_ off_val = 0;
175  const MHD_SCKT_OPT_BOOL_ on_val = 1;
176  int err_code;
177 
178  if (_MHD_YES == connection->is_nonip)
179  return false;
180 
181  if (0 == setsockopt (connection->socket_fd,
182  IPPROTO_TCP,
183  TCP_NODELAY,
184  (const void *) (nodelay_state ? &on_val : &off_val),
185  sizeof (off_val)))
186  {
187  connection->sk_nodelay = nodelay_state;
188  return true;
189  }
190 
191  err_code = MHD_socket_get_error_ ();
192  if (MHD_SCKT_ERR_IS_ (err_code, MHD_SCKT_EINVAL_) ||
195  {
196  if (_MHD_UNKNOWN == connection->is_nonip)
197  connection->is_nonip = _MHD_YES;
198 #ifdef HAVE_MESSAGES
199  else
200  {
201  MHD_DLOG (connection->daemon,
202  _ ("Setting %s option to %s state failed "
203  "for TCP/IP socket %d: %s\n"),
204  "TCP_NODELAY",
205  nodelay_state ? _ ("ON") : _ ("OFF"),
206  (int) connection->socket_fd,
207  MHD_socket_strerr_ (err_code));
208  }
209 #endif /* HAVE_MESSAGES */
210  }
211 #ifdef HAVE_MESSAGES
212  else
213  {
214  MHD_DLOG (connection->daemon,
215  _ ("Setting %s option to %s state failed: %s\n"),
216  "TCP_NODELAY",
217  nodelay_state ? _ ("ON") : _ ("OFF"),
218  MHD_socket_strerr_ (err_code));
219  }
220 #endif /* HAVE_MESSAGES */
221 
222 #else /* ! TCP_NODELAY */
223  (void) connection; (void) nodelay_state; /* Mute compiler warnings */
224 #endif /* ! TCP_NODELAY */
225  return false;
226 }
227 
228 
239 bool
241  bool cork_state)
242 {
243 #if defined(MHD_TCP_CORK_NOPUSH)
244  const MHD_SCKT_OPT_BOOL_ off_val = 0;
245  const MHD_SCKT_OPT_BOOL_ on_val = 1;
246  int err_code;
247 
248  if (_MHD_YES == connection->is_nonip)
249  return false;
250  if (0 == setsockopt (connection->socket_fd,
251  IPPROTO_TCP,
252  MHD_TCP_CORK_NOPUSH,
253  (const void *) (cork_state ? &on_val : &off_val),
254  sizeof (off_val)))
255  {
256  connection->sk_corked = cork_state;
257  return true;
258  }
259 
260  err_code = MHD_socket_get_error_ ();
261  if (MHD_SCKT_ERR_IS_ (err_code, MHD_SCKT_EINVAL_) ||
264  {
265  if (_MHD_UNKNOWN == connection->is_nonip)
266  connection->is_nonip = _MHD_YES;
267 #ifdef HAVE_MESSAGES
268  else
269  {
270  MHD_DLOG (connection->daemon,
271  _ ("Setting %s option to %s state failed "
272  "for TCP/IP socket %d: %s\n"),
273 #ifdef TCP_CORK
274  "TCP_CORK",
275 #else /* ! TCP_CORK */
276  "TCP_NOPUSH",
277 #endif /* ! TCP_CORK */
278  cork_state ? _ ("ON") : _ ("OFF"),
279  (int) connection->socket_fd,
280  MHD_socket_strerr_ (err_code));
281  }
282 #endif /* HAVE_MESSAGES */
283  }
284 #ifdef HAVE_MESSAGES
285  else
286  {
287  MHD_DLOG (connection->daemon,
288  _ ("Setting %s option to %s state failed: %s\n"),
289 #ifdef TCP_CORK
290  "TCP_CORK",
291 #else /* ! TCP_CORK */
292  "TCP_NOPUSH",
293 #endif /* ! TCP_CORK */
294  cork_state ? _ ("ON") : _ ("OFF"),
295  MHD_socket_strerr_ (err_code));
296  }
297 #endif /* HAVE_MESSAGES */
298 
299 #else /* ! MHD_TCP_CORK_NOPUSH */
300  (void) connection; (void) cork_state; /* Mute compiler warnings. */
301 #endif /* ! MHD_TCP_CORK_NOPUSH */
302  return false;
303 }
304 
305 
316 static void
317 pre_send_setopt (struct MHD_Connection *connection,
318  bool plain_send,
319  bool push_data)
320 {
321  /* Try to buffer data if not sending the final piece.
322  * Final piece is indicated by push_data == true. */
323  const bool buffer_data = (! push_data);
324 
325  if (_MHD_YES == connection->is_nonip)
326  return;
327  /* The goal is to minimise the total number of additional sys-calls
328  * before and after send().
329  * The following tricky (over-)complicated algorithm typically use zero,
330  * one or two additional sys-calls (depending on OS) for each response. */
331 
332  if (buffer_data)
333  {
334  /* Need to buffer data if possible. */
335 #ifdef MHD_USE_MSG_MORE
336  if (plain_send)
337  return; /* Data is buffered by send() with MSG_MORE flag.
338  * No need to check or change anything. */
339 #else /* ! MHD_USE_MSG_MORE */
340  (void) plain_send; /* Mute compiler warning. */
341 #endif /* ! MHD_USE_MSG_MORE */
342 
343 #ifdef MHD_TCP_CORK_NOPUSH
344  if (_MHD_ON == connection->sk_corked)
345  return; /* The connection was already corked. */
346 
347  if (MHD_connection_set_cork_state_ (connection, true))
348  return; /* The connection has been corked. */
349 
350  /* Failed to cork the connection.
351  * Really unlikely to happen on TCP connections. */
352 #endif /* MHD_TCP_CORK_NOPUSH */
353  if (_MHD_OFF == connection->sk_nodelay)
354  return; /* TCP_NODELAY was not set for the socket.
355  * Nagle's algorithm will buffer some data. */
356 
357  /* Try to reset TCP_NODELAY state for the socket.
358  * Ignore possible error as no other options exist to
359  * buffer data. */
360  MHD_connection_set_nodelay_state_ (connection, false);
361  /* TCP_NODELAY has been (hopefully) reset for the socket.
362  * Nagle's algorithm will buffer some data. */
363  return;
364  }
365 
366  /* Need to push data after send() */
367  /* If additional sys-call is required prefer to make it after the send()
368  * as the next send() may consume only part of the prepared data and
369  * more send() calls will be used. */
370 #ifdef MHD_TCP_CORK_NOPUSH
371 #ifdef _MHD_CORK_RESET_PUSH_DATA
372 #ifdef _MHD_CORK_RESET_PUSH_DATA_ALWAYS
373  /* Data can be pushed immediately by uncorking socket regardless of
374  * cork state before. */
375  /* This is typical for Linux, no other kernel with
376  * such behavior are known so far. */
377 
378  /* No need to check the current state of TCP_CORK / TCP_NOPUSH
379  * as reset of cork will push the data anyway. */
380  return; /* Data may be pushed by resetting of
381  * TCP_CORK / TCP_NOPUSH after send() */
382 #else /* ! _MHD_CORK_RESET_PUSH_DATA_ALWAYS */
383  /* Reset of TCP_CORK / TCP_NOPUSH will push the data
384  * only if socket is corked. */
385 
386 #ifdef _MHD_NODELAY_SET_PUSH_DATA_ALWAYS
387  /* Data can be pushed immediately by setting TCP_NODELAY regardless
388  * of TCP_NODDELAY or corking state before. */
389 
390  /* Dead code currently, no known kernels with such behavior. */
391  return; /* Data may be pushed by setting of TCP_NODELAY after send().
392  No need to make extra sys-calls before send().*/
393 #else /* ! _MHD_NODELAY_SET_PUSH_DATA_ALWAYS */
394 
395 #ifdef _MHD_NODELAY_SET_PUSH_DATA
396  /* Setting of TCP_NODELAY will push the data only if
397  * both TCP_NODELAY and TCP_CORK / TCP_NOPUSH were not set. */
398 
399  /* Data can be pushed immediately by uncorking socket if
400  * socket was corked before or by setting TCP_NODELAY if
401  * socket was not corked and TCP_NODELAY was not set before. */
402 
403  /* Dead code currently as Linux is the only kernel that push
404  * data by setting of TCP_NODELAY and Linux push data always. */
405 #else /* ! _MHD_NODELAY_SET_PUSH_DATA */
406  /* Data can be pushed immediately by uncorking socket or
407  * can be pushed by send() on uncorked socket if
408  * TCP_NODELAY was set *before*. */
409 
410  /* This is typical FreeBSD behavior. */
411 #endif /* ! _MHD_NODELAY_SET_PUSH_DATA */
412 
413  if (_MHD_ON == connection->sk_corked)
414  return; /* Socket is corked. Data can be pushed by resetting of
415  * TCP_CORK / TCP_NOPUSH after send() */
416  else if (_MHD_OFF == connection->sk_corked)
417  {
418  /* The socket is not corked. */
419  if (_MHD_ON == connection->sk_nodelay)
420  return; /* TCP_NODELAY was already set,
421  * data will be pushed automatically by the next send() */
422 #ifdef _MHD_NODELAY_SET_PUSH_DATA
423  else if (_MHD_UNKNOWN == connection->sk_nodelay)
424  {
425  /* Setting TCP_NODELAY may push data.
426  * Cork socket here and uncork after send(). */
427  if (MHD_connection_set_cork_state_ (connection, true))
428  return; /* The connection has been corked.
429  * Data can be pushed by resetting of
430  * TCP_CORK / TCP_NOPUSH after send() */
431  else
432  {
433  /* The socket cannot be corked.
434  * Really unlikely to happen on TCP connections */
435  /* Have to set TCP_NODELAY.
436  * If TCP_NODELAY real system state was OFF then
437  * already buffered data may be pushed here, but this is unlikely
438  * to happen as it is only a backup solution when corking has failed.
439  * Ignore possible error here as no other options exist to
440  * push data. */
441  MHD_connection_set_nodelay_state_ (connection, true);
442  /* TCP_NODELAY has been (hopefully) set for the socket.
443  * The data will be pushed by the next send(). */
444  return;
445  }
446  }
447 #endif /* _MHD_NODELAY_SET_PUSH_DATA */
448  else
449  {
450 #ifdef _MHD_NODELAY_SET_PUSH_DATA
451  /* TCP_NODELAY was switched off and
452  * the socket is not corked. */
453 #else /* ! _MHD_NODELAY_SET_PUSH_DATA */
454  /* Socket is not corked and TCP_NODELAY was not set or unknown. */
455 #endif /* ! _MHD_NODELAY_SET_PUSH_DATA */
456 
457  /* At least one additional sys-call is required. */
458  /* Setting TCP_NODELAY is optimal here as data will be pushed
459  * automatically by the next send() and no additional
460  * sys-call are needed after the send(). */
461  if (MHD_connection_set_nodelay_state_ (connection, true))
462  return;
463  else
464  {
465  /* Failed to set TCP_NODELAY for the socket.
466  * Really unlikely to happen on TCP connections. */
467  /* Cork the socket here and make additional sys-call
468  * to uncork the socket after send(). */
469  /* Ignore possible error here as no other options exist to
470  * push data. */
471  MHD_connection_set_cork_state_ (connection, true);
472  /* The connection has been (hopefully) corked.
473  * Data can be pushed by resetting of TCP_CORK / TCP_NOPUSH
474  * after send() */
475  return;
476  }
477  }
478  }
479  /* Corked state is unknown. Need to make sys-call here otherwise
480  * data may not be pushed. */
481  if (MHD_connection_set_cork_state_ (connection, true))
482  return; /* The connection has been corked.
483  * Data can be pushed by resetting of
484  * TCP_CORK / TCP_NOPUSH after send() */
485  /* The socket cannot be corked.
486  * Really unlikely to happen on TCP connections */
487  if (_MHD_ON == connection->sk_nodelay)
488  return; /* TCP_NODELAY was already set,
489  * data will be pushed by the next send() */
490  /* Have to set TCP_NODELAY. */
491 #ifdef _MHD_NODELAY_SET_PUSH_DATA
492  /* If TCP_NODELAY state was unknown (external connection) then
493  * already buffered data may be pushed here, but this is unlikely
494  * to happen as it is only a backup solution when corking has failed. */
495 #endif /* _MHD_NODELAY_SET_PUSH_DATA */
496  /* Ignore possible error here as no other options exist to
497  * push data. */
498  MHD_connection_set_nodelay_state_ (connection, true);
499  /* TCP_NODELAY has been (hopefully) set for the socket.
500  * The data will be pushed by the next send(). */
501  return;
502 #endif /* ! _MHD_NODELAY_SET_PUSH_DATA_ALWAYS */
503 #endif /* ! _MHD_CORK_RESET_PUSH_DATA_ALWAYS */
504 #else /* ! _MHD_CORK_RESET_PUSH_DATA */
505  /* Neither uncorking the socket or setting TCP_NODELAY
506  * push the data immediately. */
507  /* The only way to push the data is to use send() on uncorked
508  * socket with TCP_NODELAY switched on . */
509 
510  /* This is a typical *BSD (except FreeBSD) and Darwin behavior. */
511 
512  /* Uncork socket if socket wasn't uncorked. */
513  if (_MHD_OFF != connection->sk_corked)
514  MHD_connection_set_cork_state_ (connection, false);
515 
516  /* Set TCP_NODELAY if it wasn't set. */
517  if (_MHD_ON != connection->sk_nodelay)
518  MHD_connection_set_nodelay_state_ (connection, true);
519 
520  return;
521 #endif /* ! _MHD_CORK_RESET_PUSH_DATA */
522 #else /* ! MHD_TCP_CORK_NOPUSH */
523  /* Buffering of data is controlled only by
524  * Nagel's algorithm. */
525  /* Set TCP_NODELAY if it wasn't set. */
526  if (_MHD_ON != connection->sk_nodelay)
527  MHD_connection_set_nodelay_state_ (connection, true);
528 #endif /* ! MHD_TCP_CORK_NOPUSH */
529 }
530 
531 
532 #ifndef _MHD_CORK_RESET_PUSH_DATA_ALWAYS
544 static bool
545 zero_send_ (struct MHD_Connection *connection)
546 {
547  int dummy;
548 
549  if (_MHD_YES == connection->is_nonip)
550  return false;
551  mhd_assert (_MHD_OFF == connection->sk_corked);
552  mhd_assert (_MHD_ON == connection->sk_nodelay);
553  dummy = 0; /* Mute compiler and analyzer warnings */
554  if (0 == MHD_send_ (connection->socket_fd, &dummy, 0))
555  return true;
556 #ifdef HAVE_MESSAGES
557  MHD_DLOG (connection->daemon,
558  _ ("Zero-send failed: %s\n"),
560 #endif /* HAVE_MESSAGES */
561  return false;
562 }
563 
564 
565 #endif /* ! _MHD_CORK_RESET_PUSH_DATA_ALWAYS */
566 
577 static void
578 post_send_setopt (struct MHD_Connection *connection,
579  bool plain_send_next,
580  bool push_data)
581 {
582  /* Try to buffer data if not sending the final piece.
583  * Final piece is indicated by push_data == true. */
584  const bool buffer_data = (! push_data);
585 
586  if (_MHD_YES == connection->is_nonip)
587  return;
588  if (buffer_data)
589  return; /* Nothing to do after send(). */
590 
591 #ifndef MHD_USE_MSG_MORE
592  (void) plain_send_next; /* Mute compiler warning */
593 #endif /* ! MHD_USE_MSG_MORE */
594 
595  /* Need to push data. */
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
600  if (_MHD_OFF == connection->sk_corked)
601  {
602  if (_MHD_ON == connection->sk_nodelay)
603  return; /* Data was already pushed by send(). */
604  }
605  /* This is Linux kernel. There are options:
606  * * Push the data by setting of TCP_NODELAY (without change
607  * of the cork on the socket),
608  * * Push the data by resetting of TCP_CORK.
609  * The optimal choice depends on the next final send functions
610  * used on the same socket. If TCP_NODELAY wasn't set then push
611  * data by setting TCP_NODELAY (TCP_NODELAY will not be removed
612  * and is needed to push the data by send() without MSG_MORE).
613  * If send()/sendmsg() will be used next than push data by
614  * resetting of TCP_CORK so next send without MSG_MORE will push
615  * data to the network (without additional sys-call to push data).
616  * If next final send function will not support MSG_MORE (like
617  * sendfile() or TLS-connection) than push data by setting
618  * TCP_NODELAY so socket will remain corked (no additional
619  * sys-call before next send()). */
620  if ((_MHD_ON != connection->sk_nodelay) ||
621  (! plain_send_next))
622  {
623  if (MHD_connection_set_nodelay_state_ (connection, true))
624  return; /* Data has been pushed by TCP_NODELAY. */
625  /* Failed to set TCP_NODELAY for the socket.
626  * Really unlikely to happen on TCP connections. */
627  if (MHD_connection_set_cork_state_ (connection, false))
628  return; /* Data has been pushed by uncorking the socket. */
629  /* Failed to uncork the socket.
630  * Really unlikely to happen on TCP connections. */
631 
632  /* The socket cannot be uncorked, no way to push data */
633  }
634  else
635  {
636  if (MHD_connection_set_cork_state_ (connection, false))
637  return; /* Data has been pushed by uncorking the socket. */
638  /* Failed to uncork the socket.
639  * Really unlikely to happen on TCP connections. */
640  if (MHD_connection_set_nodelay_state_ (connection, true))
641  return; /* Data has been pushed by TCP_NODELAY. */
642  /* Failed to set TCP_NODELAY for the socket.
643  * Really unlikely to happen on TCP connections. */
644 
645  /* The socket cannot be uncorked, no way to push data */
646  }
647 #else /* ! MHD_USE_MSG_MORE */
648  /* Use setting of TCP_NODELAY here to avoid sys-call
649  * for corking the socket during sending of the next response. */
650  if (MHD_connection_set_nodelay_state_ (connection, true))
651  return; /* Data was pushed by TCP_NODELAY. */
652  /* Failed to set TCP_NODELAY for the socket.
653  * Really unlikely to happen on TCP connections. */
654  if (MHD_connection_set_cork_state_ (connection, false))
655  return; /* Data was pushed by uncorking the socket. */
656  /* Failed to uncork the socket.
657  * Really unlikely to happen on TCP connections. */
658 
659  /* The socket remains corked, no way to push data */
660 #endif /* ! MHD_USE_MSG_MORE */
661 #else /* ! _MHD_NODELAY_SET_PUSH_DATA_ALWAYS */
662  if (MHD_connection_set_cork_state_ (connection, false))
663  return; /* Data was pushed by uncorking the socket. */
664  /* Failed to uncork the socket.
665  * Really unlikely to happen on TCP connections. */
666  return; /* Socket remains corked, no way to push data */
667 #endif /* ! _MHD_NODELAY_SET_PUSH_DATA_ALWAYS */
668 #else /* ! _MHD_CORK_RESET_PUSH_DATA_ALWAYS */
669  /* This is a typical *BSD or Darwin kernel. */
670 
671  if (_MHD_OFF == connection->sk_corked)
672  {
673  if (_MHD_ON == connection->sk_nodelay)
674  return; /* Data was already pushed by send(). */
675 
676  /* Unlikely to reach this code.
677  * TCP_NODELAY should be turned on before send(). */
678  if (MHD_connection_set_nodelay_state_ (connection, true))
679  {
680  /* TCP_NODELAY has been set on uncorked socket.
681  * Use zero-send to push the data. */
682  if (zero_send_ (connection))
683  return; /* The data has been pushed by zero-send. */
684  }
685 
686  /* Failed to push the data by all means. */
687  /* There is nothing left to try. */
688  }
689  else
690  {
691 #ifdef _MHD_CORK_RESET_PUSH_DATA
692  enum MHD_tristate old_cork_state = connection->sk_corked;
693 #endif /* _MHD_CORK_RESET_PUSH_DATA */
694  /* The socket is corked or cork state is unknown. */
695 
696  if (MHD_connection_set_cork_state_ (connection, false))
697  {
698 #ifdef _MHD_CORK_RESET_PUSH_DATA
699  /* FreeBSD kernel */
700  if (_MHD_OFF == old_cork_state)
701  return; /* Data has been pushed by uncorking the socket. */
702 #endif /* _MHD_CORK_RESET_PUSH_DATA */
703 
704  /* Unlikely to reach this code.
705  * The data should be pushed by uncorking (FreeBSD) or
706  * the socket should be uncorked before send(). */
707  if ((_MHD_ON == connection->sk_nodelay) ||
708  (MHD_connection_set_nodelay_state_ (connection, true)))
709  {
710  /* TCP_NODELAY is turned ON on uncorked socket.
711  * Use zero-send to push the data. */
712  if (zero_send_ (connection))
713  return; /* The data has been pushed by zero-send. */
714  }
715  }
716  /* The socket remains corked. Data cannot be pushed. */
717  }
718 #endif /* ! _MHD_CORK_RESET_PUSH_DATA_ALWAYS */
719 #else /* ! MHD_TCP_CORK_NOPUSH */
720  /* Corking is not supported. Buffering is controlled
721  * by TCP_NODELAY only. */
722  mhd_assert (_MHD_ON != connection->sk_corked);
723  if (_MHD_ON == connection->sk_nodelay)
724  return; /* Data was already pushed by send(). */
725 
726  /* Unlikely to reach this code.
727  * TCP_NODELAY should be turned on before send(). */
728  if (MHD_connection_set_nodelay_state_ (connection, true))
729  {
730  /* TCP_NODELAY has been set.
731  * Use zero-send to push the data. */
732  if (zero_send_ (connection))
733  return; /* The data has been pushed by zero-send. */
734  }
735 
736  /* Failed to push the data. */
737 #endif /* ! MHD_TCP_CORK_NOPUSH */
738 #ifdef HAVE_MESSAGES
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"));
743 #endif /* HAVE_MESSAGES */
744  return;
745 }
746 
747 
748 ssize_t
749 MHD_send_data_ (struct MHD_Connection *connection,
750  const char *buffer,
751  size_t buffer_size,
752  bool push_data)
753 {
754  MHD_socket s = connection->socket_fd;
755  ssize_t ret;
756 #ifdef HTTPS_SUPPORT
757  const bool tls_conn = (connection->daemon->options & MHD_USE_TLS);
758 #else /* ! HTTPS_SUPPORT */
759  const bool tls_conn = false;
760 #endif /* ! HTTPS_SUPPORT */
761 
762  if ( (MHD_INVALID_SOCKET == s) ||
763  (MHD_CONNECTION_CLOSED == connection->state) )
764  {
765  return MHD_ERR_NOTCONN_;
766  }
767 
768  if (buffer_size > SSIZE_MAX)
769  {
770  buffer_size = SSIZE_MAX; /* Max return value */
771  push_data = false; /* Incomplete send */
772  }
773 
774  if (tls_conn)
775  {
776 #ifdef HTTPS_SUPPORT
777  pre_send_setopt (connection, (! tls_conn), push_data);
778  ret = gnutls_record_send (connection->tls_session,
779  buffer,
780  buffer_size);
781  if (GNUTLS_E_AGAIN == ret)
782  {
783 #ifdef EPOLL_SUPPORT
784  connection->epoll_state &=
786 #endif
787  return MHD_ERR_AGAIN_;
788  }
789  if (GNUTLS_E_INTERRUPTED == ret)
790  return MHD_ERR_AGAIN_;
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) )
796  return MHD_ERR_TLS_;
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) )
801  return MHD_ERR_PIPE_;
802 #if defined(GNUTLS_E_PREMATURE_TERMINATION)
803  if (GNUTLS_E_PREMATURE_TERMINATION == ret)
804  return MHD_ERR_CONNRESET_;
805 #elif defined(GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
806  if (GNUTLS_E_UNEXPECTED_PACKET_LENGTH == ret)
807  return MHD_ERR_CONNRESET_;
808 #endif /* GNUTLS_E_UNEXPECTED_PACKET_LENGTH */
809  if (GNUTLS_E_MEMORY_ERROR == ret)
810  return MHD_ERR_NOMEM_;
811  if (ret < 0)
812  {
813  /* Treat any other error as hard error. */
814  return MHD_ERR_NOTCONN_;
815  }
816 #ifdef EPOLL_SUPPORT
817  /* Unlike non-TLS connections, do not reset "write-ready" if
818  * sent amount smaller than provided amount, as TLS
819  * connections may break data into smaller parts for sending. */
820 #endif /* EPOLL_SUPPORT */
821 #endif /* HTTPS_SUPPORT */
822  (void) 0; /* Mute compiler warning for non-TLS builds. */
823  }
824  else
825  {
826  /* plaintext transmission */
827  if (buffer_size > MHD_SCKT_SEND_MAX_SIZE_)
828  {
829  buffer_size = MHD_SCKT_SEND_MAX_SIZE_; /* send() return value limit */
830  push_data = false; /* Incomplete send */
831  }
832 
833  pre_send_setopt (connection, (! tls_conn), push_data);
834 #ifdef MHD_USE_MSG_MORE
835  ret = MHD_send4_ (s,
836  buffer,
837  buffer_size,
838  push_data ? 0 : MSG_MORE);
839 #else
840  ret = MHD_send4_ (s,
841  buffer,
842  buffer_size,
843  0);
844 #endif
845 
846  if (0 > ret)
847  {
848  const int err = MHD_socket_get_error_ ();
849 
850  if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
851  {
852 #if EPOLL_SUPPORT
853  /* EAGAIN, no longer write-ready */
854  connection->epoll_state &=
856 #endif /* EPOLL_SUPPORT */
857  return MHD_ERR_AGAIN_;
858  }
859  if (MHD_SCKT_ERR_IS_EINTR_ (err))
860  return MHD_ERR_AGAIN_;
862  return MHD_ERR_CONNRESET_;
864  return MHD_ERR_PIPE_;
866  return MHD_ERR_OPNOTSUPP_;
868  return MHD_ERR_NOTCONN_;
870  return MHD_ERR_INVAL_;
872  return MHD_ERR_NOMEM_;
874  return MHD_ERR_BADF_;
875  /* Treat any other error as a hard error. */
876  return MHD_ERR_NOTCONN_;
877  }
878 #if EPOLL_SUPPORT
879  else if (buffer_size > (size_t) ret)
880  connection->epoll_state &=
882 #endif /* EPOLL_SUPPORT */
883  }
884 
885  /* If there is a need to push the data from network buffers
886  * call post_send_setopt(). */
887  /* If TLS connection is used then next final send() will be
888  * without MSG_MORE support. If non-TLS connection is used
889  * it's unknown whether sendfile() will be used or not so
890  * assume that next call will be the same, like this call. */
891  if ( (push_data) &&
892  (buffer_size == (size_t) ret) )
893  post_send_setopt (connection, (! tls_conn), push_data);
894 
895  return ret;
896 }
897 
898 
899 ssize_t
901  const char *header,
902  size_t header_size,
903  bool never_push_hdr,
904  const char *body,
905  size_t body_size,
906  bool complete_response)
907 {
908  ssize_t ret;
909  bool push_hdr;
910  bool push_body;
911  MHD_socket s = connection->socket_fd;
912 #ifndef _WIN32
913 #define _MHD_SEND_VEC_MAX MHD_SCKT_SEND_MAX_SIZE_
914 #else /* ! _WIN32 */
915 #define _MHD_SEND_VEC_MAX UINT32_MAX
916 #endif /* ! _WIN32 */
917 #ifdef MHD_VECT_SEND
918 #if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
919  struct iovec vector[2];
920 #ifdef HAVE_SENDMSG
921  struct msghdr msg;
922 #endif /* HAVE_SENDMSG */
923 #endif /* HAVE_SENDMSG || HAVE_WRITEV */
924 #ifdef _WIN32
925  WSABUF vector[2];
926  DWORD vec_sent;
927 #endif /* _WIN32 */
928  bool no_vec; /* Is vector-send() disallowed? */
929 
930  no_vec = false;
931 #ifdef HTTPS_SUPPORT
932  no_vec = no_vec || (connection->daemon->options & MHD_USE_TLS);
933 #endif /* HTTPS_SUPPORT */
934 #if (! defined(HAVE_SENDMSG) || ! defined(MSG_NOSIGNAL) ) && \
935  defined(MHD_SEND_SPIPE_SEND_SUPPRESS_POSSIBLE) && \
936  defined(MHD_SEND_SPIPE_SUPPRESS_NEEDED)
937  no_vec = no_vec || (! connection->daemon->sigpipe_blocked &&
938  ! connection->sk_spipe_suppress);
939 #endif /* (!HAVE_SENDMSG || ! MSG_NOSIGNAL) &&
940  MHD_SEND_SPIPE_SEND_SUPPRESS_POSSIBLE &&
941  MHD_SEND_SPIPE_SUPPRESS_NEEDED */
942 #endif /* MHD_VECT_SEND */
943 
944  mhd_assert ( (NULL != body) || (0 == body_size) );
945 
946  if ( (MHD_INVALID_SOCKET == s) ||
947  (MHD_CONNECTION_CLOSED == connection->state) )
948  {
949  return MHD_ERR_NOTCONN_;
950  }
951 
952  push_body = complete_response;
953 
954  if (! never_push_hdr)
955  {
956  if (! complete_response)
957  push_hdr = true; /* Push the header as the client may react
958  * on header alone while the body data is
959  * being prepared. */
960  else
961  {
962  if (1400 > (header_size + body_size))
963  push_hdr = false; /* Do not push the header as complete
964  * reply is already ready and the whole
965  * reply most probably will fit into
966  * the single IP packet. */
967  else
968  push_hdr = true; /* Push header alone so client may react
969  * on it while reply body is being delivered. */
970  }
971  }
972  else
973  push_hdr = false;
974 
975  if (complete_response && (0 == body_size))
976  push_hdr = true; /* The header alone is equal to the whole response. */
977 
978  if (
979 #ifdef MHD_VECT_SEND
980  (no_vec) ||
981  (0 == body_size) ||
982  ((size_t) SSIZE_MAX <= header_size) ||
983  ((size_t) _MHD_SEND_VEC_MAX < header_size)
984 #ifdef _WIN32
985  || ((size_t) UINT_MAX < header_size)
986 #endif /* _WIN32 */
987 #else /* ! MHD_VECT_SEND */
988  true
989 #endif /* ! MHD_VECT_SEND */
990  )
991  {
992  ret = MHD_send_data_ (connection,
993  header,
994  header_size,
995  push_hdr);
996 
997  if ( (header_size == (size_t) ret) &&
998  ((size_t) SSIZE_MAX > header_size) &&
999  (0 != body_size) &&
1000  (connection->sk_nonblck) )
1001  {
1002  ssize_t ret2;
1003  /* The header has been sent completely.
1004  * Try to send the reply body without waiting for
1005  * the next round. */
1006  /* Make sure that sum of ret + ret2 will not exceed SSIZE_MAX as
1007  * function needs to return positive value if succeed. */
1008  if ( (((size_t) SSIZE_MAX) - ((size_t) ret)) < body_size)
1009  {
1010  body_size = (((size_t) SSIZE_MAX) - ((size_t) ret));
1011  complete_response = false;
1012  push_body = complete_response;
1013  }
1014 
1015  ret2 = MHD_send_data_ (connection,
1016  body,
1017  body_size,
1018  push_body);
1019  if (0 < ret2)
1020  return ret + ret2; /* Total data sent */
1021  if (MHD_ERR_AGAIN_ == ret2)
1022  return ret;
1023 
1024  return ret2; /* Error code */
1025  }
1026  return ret;
1027  }
1028 #ifdef MHD_VECT_SEND
1029 
1030  if ( ((size_t) SSIZE_MAX <= body_size) ||
1031  ((size_t) SSIZE_MAX < (header_size + body_size)) )
1032  {
1033  /* Return value limit */
1034  body_size = SSIZE_MAX - header_size;
1035  complete_response = false;
1036  push_body = complete_response;
1037  }
1038 #if (SSIZE_MAX != _MHD_SEND_VEC_MAX) || (_MHD_SEND_VEC_MAX + 0 == 0)
1039  if (((size_t) _MHD_SEND_VEC_MAX <= body_size) ||
1040  ((size_t) _MHD_SEND_VEC_MAX < (header_size + body_size)))
1041  {
1042  /* Send total amount limit */
1043  body_size = _MHD_SEND_VEC_MAX - header_size;
1044  complete_response = false;
1045  push_body = complete_response;
1046  }
1047 #endif /* SSIZE_MAX != _MHD_SEND_VEC_MAX */
1048 
1049  pre_send_setopt (connection,
1050 #ifdef HAVE_SENDMSG
1051  true,
1052 #else /* ! HAVE_SENDMSG */
1053  false,
1054 #endif /* ! HAVE_SENDMSG */
1055  push_hdr || push_body);
1056 #if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
1057  vector[0].iov_base = (void *) header;
1058  vector[0].iov_len = header_size;
1059  vector[1].iov_base = (void *) body;
1060  vector[1].iov_len = body_size;
1061 
1062 #if defined(HAVE_SENDMSG)
1063  memset (&msg, 0, sizeof(msg));
1064  msg.msg_iov = vector;
1065  msg.msg_iovlen = 2;
1066 
1067  ret = sendmsg (s, &msg, MSG_NOSIGNAL_OR_ZERO);
1068 #elif defined (HAVE_WRITEV)
1069  ret = writev (s, vector, 2);
1070 #endif /* HAVE_WRITEV */
1071 #endif /* HAVE_SENDMSG || HAVE_WRITEV */
1072 #ifdef _WIN32
1073  if ((size_t) UINT_MAX < body_size)
1074  {
1075  /* Send item size limit */
1076  body_size = UINT_MAX;
1077  complete_response = false;
1078  push_body = complete_response;
1079  }
1080  vector[0].buf = (char *) header;
1081  vector[0].len = (unsigned long) header_size;
1082  vector[1].buf = (char *) body;
1083  vector[1].len = (unsigned long) body_size;
1084 
1085  ret = WSASend (s, vector, 2, &vec_sent, 0, NULL, NULL);
1086  if (0 == ret)
1087  ret = (ssize_t) vec_sent;
1088  else
1089  ret = -1;
1090 #endif /* _WIN32 */
1091 
1092  if (0 > ret)
1093  {
1094  const int err = MHD_socket_get_error_ ();
1095 
1096  if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
1097  {
1098 #if EPOLL_SUPPORT
1099  /* EAGAIN, no longer write-ready */
1100  connection->epoll_state &=
1102 #endif /* EPOLL_SUPPORT */
1103  return MHD_ERR_AGAIN_;
1104  }
1105  if (MHD_SCKT_ERR_IS_EINTR_ (err))
1106  return MHD_ERR_AGAIN_;
1108  return MHD_ERR_CONNRESET_;
1109  if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EPIPE_))
1110  return MHD_ERR_PIPE_;
1112  return MHD_ERR_OPNOTSUPP_;
1114  return MHD_ERR_NOTCONN_;
1116  return MHD_ERR_INVAL_;
1118  return MHD_ERR_NOMEM_;
1119  if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EBADF_))
1120  return MHD_ERR_BADF_;
1121  /* Treat any other error as a hard error. */
1122  return MHD_ERR_NOTCONN_;
1123  }
1124 #if EPOLL_SUPPORT
1125  else if ((header_size + body_size) > (size_t) ret)
1126  connection->epoll_state &=
1128 #endif /* EPOLL_SUPPORT */
1129 
1130  /* If there is a need to push the data from network buffers
1131  * call post_send_setopt(). */
1132  if ( (push_body) &&
1133  ((header_size + body_size) == (size_t) ret) )
1134  {
1135  /* Complete reply has been sent. */
1136  /* If TLS connection is used then next final send() will be
1137  * without MSG_MORE support. If non-TLS connection is used
1138  * it's unknown whether next 'send' will be plain send() / sendmsg() or
1139  * sendfile() will be used so assume that next final send() will be
1140  * the same, like for this response. */
1141  post_send_setopt (connection,
1142 #ifdef HAVE_SENDMSG
1143  true,
1144 #else /* ! HAVE_SENDMSG */
1145  false,
1146 #endif /* ! HAVE_SENDMSG */
1147  true);
1148  }
1149  else if ( (push_hdr) &&
1150  (header_size <= (size_t) ret))
1151  {
1152  /* The header has been sent completely and there is a
1153  * need to push the header data. */
1154  /* Luckily the type of send function will be used next is known. */
1155  post_send_setopt (connection,
1156 #if defined(_MHD_HAVE_SENDFILE)
1157  MHD_resp_sender_std == connection->resp_sender,
1158 #else /* ! _MHD_HAVE_SENDFILE */
1159  true,
1160 #endif /* ! _MHD_HAVE_SENDFILE */
1161  true);
1162  }
1163 
1164  return ret;
1165 #else /* ! MHD_VECT_SEND */
1166  mhd_assert (false);
1167  return MHD_ERR_CONNRESET_; /* Unreachable. Mute warnings. */
1168 #endif /* ! MHD_VECT_SEND */
1169 }
1170 
1171 
1172 #if defined(_MHD_HAVE_SENDFILE)
1173 ssize_t
1174 MHD_send_sendfile_ (struct MHD_Connection *connection)
1175 {
1176  ssize_t ret;
1177  const int file_fd = connection->response->fd;
1178  uint64_t left;
1179  uint64_t offsetu64;
1180 #ifndef HAVE_SENDFILE64
1181  const uint64_t max_off_t = (uint64_t) OFF_T_MAX;
1182 #else /* HAVE_SENDFILE64 */
1183  const uint64_t max_off_t = (uint64_t) OFF64_T_MAX;
1184 #endif /* HAVE_SENDFILE64 */
1185 #ifdef MHD_LINUX_SOLARIS_SENDFILE
1186 #ifndef HAVE_SENDFILE64
1187  off_t offset;
1188 #else /* HAVE_SENDFILE64 */
1189  off64_t offset;
1190 #endif /* HAVE_SENDFILE64 */
1191 #endif /* MHD_LINUX_SOLARIS_SENDFILE */
1192 #ifdef HAVE_FREEBSD_SENDFILE
1193  off_t sent_bytes;
1194  int flags = 0;
1195 #endif
1196 #ifdef HAVE_DARWIN_SENDFILE
1197  off_t len;
1198 #endif /* HAVE_DARWIN_SENDFILE */
1199  const bool used_thr_p_c = (0 != (connection->daemon->options
1201  const size_t chunk_size = used_thr_p_c ? MHD_SENFILE_CHUNK_THR_P_C_ :
1203  size_t send_size = 0;
1204  bool push_data;
1205  mhd_assert (MHD_resp_sender_sendfile == connection->resp_sender);
1206  mhd_assert (0 == (connection->daemon->options & MHD_USE_TLS));
1207 
1208  offsetu64 = connection->response_write_position
1209  + connection->response->fd_off;
1210  if (max_off_t < offsetu64)
1211  { /* Retry to send with standard 'send()'. */
1212  connection->resp_sender = MHD_resp_sender_std;
1213  return MHD_ERR_AGAIN_;
1214  }
1215 
1216  left = connection->response->total_size - connection->response_write_position;
1217 
1218  if ( (uint64_t) SSIZE_MAX < left)
1219  left = SSIZE_MAX;
1220 
1221  /* Do not allow system to stick sending on single fast connection:
1222  * use 128KiB chunks (2MiB for thread-per-connection). */
1223  if (chunk_size < left)
1224  {
1225  send_size = chunk_size;
1226  push_data = false; /* No need to push data, there is more to send. */
1227  }
1228  else
1229  {
1230  send_size = (size_t) left;
1231  push_data = true; /* Final piece of data, need to push to the network. */
1232  }
1233  pre_send_setopt (connection, false, push_data);
1234 
1235 #ifdef MHD_LINUX_SOLARIS_SENDFILE
1236 #ifndef HAVE_SENDFILE64
1237  offset = (off_t) offsetu64;
1238  ret = sendfile (connection->socket_fd,
1239  file_fd,
1240  &offset,
1241  send_size);
1242 #else /* HAVE_SENDFILE64 */
1243  offset = (off64_t) offsetu64;
1244  ret = sendfile64 (connection->socket_fd,
1245  file_fd,
1246  &offset,
1247  send_size);
1248 #endif /* HAVE_SENDFILE64 */
1249  if (0 > ret)
1250  {
1251  const int err = MHD_socket_get_error_ ();
1252  if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
1253  {
1254 #ifdef EPOLL_SUPPORT
1255  /* EAGAIN --- no longer write-ready */
1256  connection->epoll_state &=
1258 #endif /* EPOLL_SUPPORT */
1259  return MHD_ERR_AGAIN_;
1260  }
1261  if (MHD_SCKT_ERR_IS_EINTR_ (err))
1262  return MHD_ERR_AGAIN_;
1263 #ifdef HAVE_LINUX_SENDFILE
1264  if (MHD_SCKT_ERR_IS_ (err,
1265  MHD_SCKT_EBADF_))
1266  return MHD_ERR_BADF_;
1267  /* sendfile() failed with EINVAL if mmap()-like operations are not
1268  supported for FD or other 'unusual' errors occurred, so we should try
1269  to fall back to 'SEND'; see also this thread for info on
1270  odd libc/Linux behavior with sendfile:
1271  http://lists.gnu.org/archive/html/libmicrohttpd/2011-02/msg00015.html */
1272  connection->resp_sender = MHD_resp_sender_std;
1273  return MHD_ERR_AGAIN_;
1274 #else /* HAVE_SOLARIS_SENDFILE */
1275  if ( (EAFNOSUPPORT == err) ||
1276  (EINVAL == err) ||
1277  (EOPNOTSUPP == err) )
1278  { /* Retry with standard file reader. */
1279  connection->resp_sender = MHD_resp_sender_std;
1280  return MHD_ERR_AGAIN_;
1281  }
1282  if ( (ENOTCONN == err) ||
1283  (EPIPE == err) )
1284  {
1285  return MHD_ERR_CONNRESET_;
1286  }
1287  return MHD_ERR_BADF_; /* Fail hard */
1288 #endif /* HAVE_SOLARIS_SENDFILE */
1289  }
1290 #ifdef EPOLL_SUPPORT
1291  else if (send_size > (size_t) ret)
1292  connection->epoll_state &=
1294 #endif /* EPOLL_SUPPORT */
1295 #elif defined(HAVE_FREEBSD_SENDFILE)
1296 #ifdef SF_FLAGS
1297  flags = used_thr_p_c ?
1298  freebsd_sendfile_flags_thd_p_c_ : freebsd_sendfile_flags_;
1299 #endif /* SF_FLAGS */
1300  if (0 != sendfile (file_fd,
1301  connection->socket_fd,
1302  (off_t) offsetu64,
1303  send_size,
1304  NULL,
1305  &sent_bytes,
1306  flags))
1307  {
1308  const int err = MHD_socket_get_error_ ();
1309  if (MHD_SCKT_ERR_IS_EAGAIN_ (err) ||
1310  MHD_SCKT_ERR_IS_EINTR_ (err) ||
1311  (EBUSY == err) )
1312  {
1313  mhd_assert (SSIZE_MAX >= sent_bytes);
1314  if (0 != sent_bytes)
1315  return (ssize_t) sent_bytes;
1316 
1317  return MHD_ERR_AGAIN_;
1318  }
1319  /* Some unrecoverable error. Possibly file FD is not suitable
1320  * for sendfile(). Retry with standard send(). */
1321  connection->resp_sender = MHD_resp_sender_std;
1322  return MHD_ERR_AGAIN_;
1323  }
1324  mhd_assert (0 < sent_bytes);
1325  mhd_assert (SSIZE_MAX >= sent_bytes);
1326  ret = (ssize_t) sent_bytes;
1327 #elif defined(HAVE_DARWIN_SENDFILE)
1328  len = (off_t) send_size; /* chunk always fit */
1329  if (0 != sendfile (file_fd,
1330  connection->socket_fd,
1331  (off_t) offsetu64,
1332  &len,
1333  NULL,
1334  0))
1335  {
1336  const int err = MHD_socket_get_error_ ();
1337  if (MHD_SCKT_ERR_IS_EAGAIN_ (err) ||
1338  MHD_SCKT_ERR_IS_EINTR_ (err))
1339  {
1340  mhd_assert (0 <= len);
1341  mhd_assert (SSIZE_MAX >= len);
1342  mhd_assert (send_size >= (size_t) len);
1343  if (0 != len)
1344  return (ssize_t) len;
1345 
1346  return MHD_ERR_AGAIN_;
1347  }
1348  if ((ENOTCONN == err) ||
1349  (EPIPE == err) )
1350  return MHD_ERR_CONNRESET_;
1351  if ((ENOTSUP == err) ||
1352  (EOPNOTSUPP == err) )
1353  { /* This file FD is not suitable for sendfile().
1354  * Retry with standard send(). */
1355  connection->resp_sender = MHD_resp_sender_std;
1356  return MHD_ERR_AGAIN_;
1357  }
1358  return MHD_ERR_BADF_; /* Return hard error. */
1359  }
1360  mhd_assert (0 <= len);
1361  mhd_assert (SSIZE_MAX >= len);
1362  mhd_assert (send_size >= (size_t) len);
1363  ret = (ssize_t) len;
1364 #endif /* HAVE_FREEBSD_SENDFILE */
1365 
1366  /* If there is a need to push the data from network buffers
1367  * call post_send_setopt(). */
1368  /* It's unknown whether sendfile() will be used in the next
1369  * response so assume that next response will be the same. */
1370  if ( (push_data) &&
1371  (send_size == (size_t) ret) )
1372  post_send_setopt (connection, false, push_data);
1373 
1374  return ret;
1375 }
1376 
1377 
1378 #endif /* _MHD_HAVE_SENDFILE */
1379 
1380 #if defined(MHD_VECT_SEND)
1381 
1382 
1396 static ssize_t
1397 send_iov_nontls (struct MHD_Connection *connection,
1398  struct MHD_iovec_track_ *const r_iov,
1399  bool push_data)
1400 {
1401  ssize_t res;
1402  ssize_t total_sent;
1403  size_t items_to_send;
1404 #ifdef HAVE_SENDMSG
1405  struct msghdr msg;
1406 #elif defined(MHD_WINSOCK_SOCKETS)
1407  DWORD bytes_sent;
1408  DWORD cnt_w;
1409 #endif /* MHD_WINSOCK_SOCKETS */
1410 
1411  mhd_assert (0 == (connection->daemon->options & MHD_USE_TLS));
1412 
1413  if ( (MHD_INVALID_SOCKET == connection->socket_fd) ||
1414  (MHD_CONNECTION_CLOSED == connection->state) )
1415  {
1416  return MHD_ERR_NOTCONN_;
1417  }
1418 
1419  items_to_send = r_iov->cnt - r_iov->sent;
1420 #ifdef _MHD_IOV_MAX
1421  if (_MHD_IOV_MAX < items_to_send)
1422  {
1423  mhd_assert (0 < _MHD_IOV_MAX);
1424  if (0 == _MHD_IOV_MAX)
1425  return MHD_ERR_NOTCONN_; /* Should never happen */
1426  items_to_send = _MHD_IOV_MAX;
1427  push_data = false; /* Incomplete response */
1428  }
1429 #endif /* _MHD_IOV_MAX */
1430 #ifdef HAVE_SENDMSG
1431  memset (&msg, 0, sizeof(struct msghdr));
1432  msg.msg_iov = r_iov->iov + r_iov->sent;
1433  msg.msg_iovlen = items_to_send;
1434 
1435  pre_send_setopt (connection, true, push_data);
1436 #ifdef MHD_USE_MSG_MORE
1437  res = sendmsg (connection->socket_fd, &msg,
1438  MSG_NOSIGNAL_OR_ZERO | (push_data ? 0 : MSG_MORE));
1439 #else /* ! MHD_USE_MSG_MORE */
1440  res = sendmsg (connection->socket_fd, &msg, MSG_NOSIGNAL_OR_ZERO);
1441 #endif /* ! MHD_USE_MSG_MORE */
1442 #elif defined(HAVE_WRITEV)
1443  pre_send_setopt (connection, true, push_data);
1444  res = writev (connection->socket_fd, r_iov->iov + r_iov->sent,
1445  items_to_send);
1446 #elif defined(MHD_WINSOCK_SOCKETS)
1447 #ifdef _WIN64
1448  if (items_to_send > UINT32_MAX)
1449  {
1450  cnt_w = UINT32_MAX;
1451  push_data = false; /* Incomplete response */
1452  }
1453  else
1454  cnt_w = (DWORD) items_to_send;
1455 #else /* ! _WIN64 */
1456  cnt_w = (DWORD) items_to_send;
1457 #endif /* ! _WIN64 */
1458  pre_send_setopt (connection, true, push_data);
1459  if (0 == WSASend (connection->socket_fd,
1460  (LPWSABUF) (r_iov->iov + r_iov->sent),
1461  cnt_w,
1462  &bytes_sent, 0, NULL, NULL))
1463  res = (ssize_t) bytes_sent;
1464  else
1465  res = -1;
1466 #else /* !HAVE_SENDMSG && !HAVE_WRITEV && !MHD_WINSOCK_SOCKETS */
1467 #error No vector-send function available
1468 #endif
1469 
1470  if (0 > res)
1471  {
1472  const int err = MHD_socket_get_error_ ();
1473 
1474  if (MHD_SCKT_ERR_IS_EAGAIN_ (err))
1475  {
1476 #ifdef EPOLL_SUPPORT
1477  /* EAGAIN --- no longer write-ready */
1478  connection->epoll_state &=
1480 #endif /* EPOLL_SUPPORT */
1481  return MHD_ERR_AGAIN_;
1482  }
1483  if (MHD_SCKT_ERR_IS_EINTR_ (err))
1484  return MHD_ERR_AGAIN_;
1486  return MHD_ERR_CONNRESET_;
1487  if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EPIPE_))
1488  return MHD_ERR_PIPE_;
1490  return MHD_ERR_OPNOTSUPP_;
1492  return MHD_ERR_NOTCONN_;
1494  return MHD_ERR_INVAL_;
1496  return MHD_ERR_NOMEM_;
1497  if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EBADF_))
1498  return MHD_ERR_BADF_;
1499  /* Treat any other error as a hard error. */
1500  return MHD_ERR_NOTCONN_;
1501  }
1502 
1503  /* Some data has been sent */
1504  total_sent = res;
1505  /* Adjust the internal tracking information for the iovec to
1506  * take this last send into account. */
1507  while ((0 != res) && (r_iov->iov[r_iov->sent].iov_len <= (size_t) res))
1508  {
1509  res -= r_iov->iov[r_iov->sent].iov_len;
1510  r_iov->sent++; /* The iov element has been completely sent */
1511  mhd_assert ((r_iov->cnt > r_iov->sent) || (0 == res));
1512  }
1513 
1514  if (r_iov->cnt == r_iov->sent)
1515  post_send_setopt (connection, true, push_data);
1516  else
1517  {
1518 #ifdef EPOLL_SUPPORT
1519  connection->epoll_state &=
1521 #endif /* EPOLL_SUPPORT */
1522  if (0 != res)
1523  {
1524  mhd_assert (r_iov->cnt > r_iov->sent);
1525  /* The last iov element has been partially sent */
1526  r_iov->iov[r_iov->sent].iov_base =
1527  (void *) ((uint8_t *) r_iov->iov[r_iov->sent].iov_base + (size_t) res);
1528  r_iov->iov[r_iov->sent].iov_len -= (MHD_iov_size_) res;
1529  }
1530  }
1531 
1532  return total_sent;
1533 }
1534 
1535 
1536 #endif /* MHD_VECT_SEND */
1537 
1538 #if ! defined(MHD_VECT_SEND) || defined(HTTPS_SUPPORT) || \
1539  defined(_MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
1540 
1541 
1556 static ssize_t
1557 send_iov_emu (struct MHD_Connection *connection,
1558  struct MHD_iovec_track_ *const r_iov,
1559  bool push_data)
1560 {
1561  const bool non_blk = connection->sk_nonblck;
1562  size_t total_sent;
1563  ssize_t res;
1564 
1565  mhd_assert (NULL != r_iov->iov);
1566  total_sent = 0;
1567  do
1568  {
1569  if ((size_t) SSIZE_MAX - total_sent < r_iov->iov[r_iov->sent].iov_len)
1570  return total_sent; /* return value would overflow */
1571 
1572  res = MHD_send_data_ (connection,
1573  r_iov->iov[r_iov->sent].iov_base,
1574  r_iov->iov[r_iov->sent].iov_len,
1575  push_data && (r_iov->cnt == r_iov->sent + 1));
1576  if (0 > res)
1577  {
1578  /* Result is an error */
1579  if (0 == total_sent)
1580  return res; /* Nothing was sent, return result as is */
1581 
1582  if (MHD_ERR_AGAIN_ == res)
1583  return total_sent; /* Some data has been sent, return the amount */
1584 
1585  return res; /* Any kind of a hard error */
1586  }
1587 
1588  total_sent += (size_t) res;
1589 
1590  if (r_iov->iov[r_iov->sent].iov_len != (size_t) res)
1591  {
1592  /* Incomplete buffer has been sent.
1593  * Adjust buffer of the last element. */
1594  r_iov->iov[r_iov->sent].iov_base =
1595  (void *) ((uint8_t *) r_iov->iov[r_iov->sent].iov_base + (size_t) res);
1596  r_iov->iov[r_iov->sent].iov_len -= res;
1597 
1598  return total_sent;
1599  }
1600  /* The iov element has been completely sent */
1601  r_iov->sent++;
1602  } while ((r_iov->cnt > r_iov->sent) && (non_blk));
1603 
1604  return (ssize_t) total_sent;
1605 }
1606 
1607 
1608 #endif /* !MHD_VECT_SEND || HTTPS_SUPPORT
1609  || _MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
1610 
1611 
1612 ssize_t
1613 MHD_send_iovec_ (struct MHD_Connection *connection,
1614  struct MHD_iovec_track_ *const r_iov,
1615  bool push_data)
1616 {
1617 #ifdef MHD_VECT_SEND
1618 #if defined(HTTPS_SUPPORT) || \
1619  defined(_MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
1620  bool use_iov_send = true;
1621 #endif /* HTTPS_SUPPORT || _MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
1622 #endif /* MHD_VECT_SEND */
1623 
1624  mhd_assert (NULL != connection->resp_iov.iov);
1625  mhd_assert (NULL != connection->response->data_iov);
1626  mhd_assert (connection->resp_iov.cnt > connection->resp_iov.sent);
1627 #ifdef MHD_VECT_SEND
1628 #if defined(HTTPS_SUPPORT) || \
1629  defined(_MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
1630 #ifdef HTTPS_SUPPORT
1631  use_iov_send = use_iov_send &&
1632  (0 == (connection->daemon->options & MHD_USE_TLS));
1633 #endif /* HTTPS_SUPPORT */
1634 #ifdef _MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED
1635  use_iov_send = use_iov_send && (connection->daemon->sigpipe_blocked ||
1636  connection->sk_spipe_suppress);
1637 #endif /* _MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
1638  if (use_iov_send)
1639 #endif /* HTTPS_SUPPORT || _MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
1640  return send_iov_nontls (connection, r_iov, push_data);
1641 #endif /* MHD_VECT_SEND */
1642 
1643 #if ! defined(MHD_VECT_SEND) || defined(HTTPS_SUPPORT) || \
1644  defined(_MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED)
1645  return send_iov_emu (connection, r_iov, push_data);
1646 #endif /* !MHD_VECT_SEND || HTTPS_SUPPORT
1647  || _MHD_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */
1648 }
#define MHD_ERR_TLS_
Definition: connection.h:77
#define MHD_ERR_OPNOTSUPP_
Definition: connection.h:67
#define MHD_ERR_PIPE_
Definition: connection.h:72
#define MHD_ERR_INVAL_
Definition: internal.h:1889
#define MHD_ERR_CONNRESET_
Definition: internal.h:1868
#define MHD_ERR_NOMEM_
Definition: internal.h:1879
MHD_EpollState
Definition: internal.h:588
@ 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 UINT32_MAX
Definition: mhd_limits.h:73
#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_EOPNOTSUPP_
Definition: mhd_sockets.h:484
#define MHD_SCKT_EBADF_
Definition: mhd_sockets.h:454
#define MHD_socket_get_error_()
Definition: mhd_sockets.h:523
#define MHD_SCKT_ERR_IS_REMOTE_DISCNN_(err)
Definition: mhd_sockets.h:688
#define MHD_SCKT_EINVAL_
Definition: mhd_sockets.h:464
#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_SCKT_ENOTCONN_
Definition: mhd_sockets.h:429
#define MHD_SCKT_ENOTSOCK_
Definition: mhd_sockets.h:459
#define MHD_send_(s, b, l)
Definition: mhd_sockets.h:261
#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:74
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:900
ssize_t MHD_send_iovec_(struct MHD_Connection *connection, struct MHD_iovec_track_ *const r_iov, bool push_data)
Definition: mhd_send.c:1613
ssize_t MHD_send_data_(struct MHD_Connection *connection, const char *buffer, size_t buffer_size, bool push_data)
Definition: mhd_send.c:749
static bool zero_send_(struct MHD_Connection *connection)
Definition: mhd_send.c:545
bool MHD_connection_set_cork_state_(struct MHD_Connection *connection, bool cork_state)
Definition: mhd_send.c:240
#define _MHD_SEND_VEC_MAX
void MHD_send_init_static_vars_(void)
Definition: mhd_send.c:153
static void pre_send_setopt(struct MHD_Connection *connection, bool plain_send, bool push_data)
Definition: mhd_send.c:317
static void post_send_setopt(struct MHD_Connection *connection, bool plain_send_next, bool push_data)
Definition: mhd_send.c:578
static ssize_t send_iov_emu(struct MHD_Connection *connection, struct MHD_iovec_track_ *const r_iov, bool push_data)
Definition: mhd_send.c:1557
bool MHD_connection_set_nodelay_state_(struct MHD_Connection *connection, bool nodelay_state)
Definition: mhd_send.c:170
#define MHD_SENFILE_CHUNK_
Definition: mhd_send.c:69
Declarations of send() wrappers.
@ MHD_CONNECTION_CLOSED
Definition: internal.h:696
size_t MHD_iov_size_
Definition: internal.h:403
MHD_tristate
Definition: internal.h:183
@ _MHD_ON
Definition: internal.h:187
@ _MHD_UNKNOWN
Definition: internal.h:184
@ _MHD_YES
Definition: internal.h:188
@ _MHD_OFF
Definition: internal.h:185
macros for mhd_assert()
limits values definitions
#define SSIZE_MAX
Definition: mhd_limits.h:113
#define MHD_SCKT_ENOPROTOOPT_
Definition: mhd_sockets.h:584
#define MHD_send4_(s, b, l, f)
Definition: mhd_sockets.h:357
#define MSG_NOSIGNAL_OR_ZERO
Definition: mhd_sockets.h:189
#define MHD_SCKT_EPIPE_
Definition: mhd_sockets.h:569
int MHD_socket
Definition: microhttpd.h:207
int off_t offset
Definition: microhttpd.h:3643
#define MHD_INVALID_SOCKET
Definition: microhttpd.h:208
@ MHD_USE_THREAD_PER_CONNECTION
Definition: microhttpd.h:1261
@ MHD_USE_TLS
Definition: microhttpd.h:1246
MHD_socket socket_fd
Definition: internal.h:752
enum MHD_tristate sk_nodelay
Definition: internal.h:1207
enum MHD_tristate is_nonip
Definition: internal.h:1187
struct MHD_Response * response
Definition: internal.h:968
bool sk_nonblck
Definition: internal.h:784
uint64_t response_write_position
Definition: internal.h:1121
struct MHD_iovec_track_ resp_iov
Definition: internal.h:1129
enum MHD_CONNECTION_STATE state
Definition: internal.h:1263
struct MHD_Daemon * daemon
Definition: internal.h:675
bool sk_spipe_suppress
Definition: internal.h:1197
enum MHD_tristate sk_corked
Definition: internal.h:1202
enum MHD_FLAG options
Definition: internal.h:1619
bool sigpipe_blocked
Definition: internal.h:2008
const void * iov_base
Definition: microhttpd.h:2185
size_t iov_len
Definition: microhttpd.h:2190
MHD_iovec_ * data_iov
Definition: internal.h:549
uint64_t total_size
Definition: internal.h:1642
uint64_t fd_off
Definition: internal.h:1653
MHD_iovec_ * iov
Definition: internal.h:414