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