libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

mhd_send.c (54444B)


      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 
     23 /**
     24  * @file microhttpd/mhd_send.c
     25  * @brief Implementation of send() wrappers and helper functions.
     26  * @author Karlson2k (Evgeny Grin)
     27  * @author ng0 (N. Gillmann)
     28  * @author Christian Grothoff
     29  */
     30 
     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 
     66 /**
     67  * sendfile() chuck size
     68  */
     69 #define MHD_SENFILE_CHUNK_         (0x20000)
     70 
     71 /**
     72  * sendfile() chuck size for thread-per-connection
     73  */
     74 #define MHD_SENFILE_CHUNK_THR_P_C_ (0x200000)
     75 
     76 #ifdef HAVE_FREEBSD_SENDFILE
     77 #ifdef SF_FLAGS
     78 /**
     79  * FreeBSD sendfile() flags
     80  */
     81 static int freebsd_sendfile_flags_;
     82 
     83 /**
     84  * FreeBSD sendfile() flags for thread-per-connection
     85  */
     86 static int freebsd_sendfile_flags_thd_p_c_;
     87 
     88 
     89 /**
     90  * Initialises variables for FreeBSD's sendfile()
     91  */
     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)
    118 /**
    119  * Current IOV_MAX system value
    120  */
    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 
    140 /**
    141  * IOV_MAX (run-time) value
    142  */
    143 #define _MHD_IOV_MAX    mhd_iov_max_
    144 #elif defined(IOV_MAX)
    145 
    146 /**
    147  * IOV_MAX (static) value
    148  */
    149 #define _MHD_IOV_MAX    IOV_MAX
    150 #endif /* HAVE_SYSCONF && _SC_IOV_MAX */
    151 
    152 
    153 /**
    154  * Initialises static variables
    155  */
    156 void
    157 MHD_send_init_static_vars_ (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
    174 MHD_connection_set_nodelay_state_ (struct MHD_Connection *connection,
    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_) ||
    197       MHD_SCKT_ERR_IS_ (err_code, MHD_SCKT_ENOPROTOOPT_) ||
    198       MHD_SCKT_ERR_IS_ (err_code, MHD_SCKT_ENOTSOCK_))
    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 
    233 /**
    234  * Set required cork state for connection socket
    235  *
    236  * The function automatically updates sk_corked state.
    237  *
    238  * @param connection the connection to manipulate
    239  * @param cork_state the requested new state of socket
    240  * @return true if succeed, false if failed or not supported
    241  *         by the current platform / kernel.
    242  */
    243 bool
    244 MHD_connection_set_cork_state_ (struct MHD_Connection *connection,
    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_) ||
    266       MHD_SCKT_ERR_IS_ (err_code, MHD_SCKT_ENOPROTOOPT_) ||
    267       MHD_SCKT_ERR_IS_ (err_code, MHD_SCKT_ENOTSOCK_))
    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 
    310 /**
    311  * Handle pre-send setsockopt calls.
    312  *
    313  * @param connection the MHD_Connection structure
    314  * @param plain_send set to true if plain send() or sendmsg() will be called,
    315  *                   set to false if TLS socket send(), sendfile() or
    316  *                   writev() will be called.
    317  * @param push_data whether to push data to the network from buffers after
    318  *                  the next call of send function.
    319  */
    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
    537 /**
    538  * Send zero-sized data
    539  *
    540  * This function use send of zero-sized data to kick data from the socket
    541  * buffers to the network. The socket must not be corked and must have
    542  * TCP_NODELAY switched on.
    543  * Used only as last resort option, when other options are failed due to
    544  * some errors.
    545  * Should not be called on typical data processing.
    546  * @return true if succeed, false if failed
    547  */
    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"),
    563             MHD_socket_last_strerr_ () );
    564 #endif /* HAVE_MESSAGES */
    565   return false;
    566 }
    567 
    568 
    569 #endif /* ! _MHD_CORK_RESET_PUSH_DATA_ALWAYS */
    570 
    571 /**
    572  * Handle post-send setsockopt calls.
    573  *
    574  * @param connection the MHD_Connection structure
    575  * @param plain_send_next set to true if plain send() or sendmsg() will be
    576  *                        called next,
    577  *                        set to false if TLS socket send(), sendfile() or
    578  *                        writev() will be called next.
    579  * @param push_data whether to push data to the network from buffers
    580  */
    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 &=
    789         ~((enum MHD_EpollState) MHD_EPOLL_STATE_WRITE_READY);
    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 &=
    860           ~((enum MHD_EpollState) MHD_EPOLL_STATE_WRITE_READY);
    861 #endif /* EPOLL_SUPPORT */
    862         return MHD_ERR_AGAIN_;
    863       }
    864       if (MHD_SCKT_ERR_IS_EINTR_ (err))
    865         return MHD_ERR_AGAIN_;
    866       if (MHD_SCKT_ERR_IS_REMOTE_DISCNN_ (err))
    867         return MHD_ERR_CONNRESET_;
    868       if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EPIPE_))
    869         return MHD_ERR_PIPE_;
    870       if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EOPNOTSUPP_))
    871         return MHD_ERR_OPNOTSUPP_;
    872       if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ENOTCONN_))
    873         return MHD_ERR_NOTCONN_;
    874       if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EINVAL_))
    875         return MHD_ERR_INVAL_;
    876       if (MHD_SCKT_ERR_IS_LOW_RESOURCES_ (err))
    877         return MHD_ERR_NOMEM_;
    878       if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EBADF_))
    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 &=
    886         ~((enum MHD_EpollState) MHD_EPOLL_STATE_WRITE_READY);
    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
    905 MHD_send_hdr_and_body_ (struct MHD_Connection *connection,
    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 &=
   1106         ~((enum MHD_EpollState) MHD_EPOLL_STATE_WRITE_READY);
   1107 #endif /* EPOLL_SUPPORT */
   1108       return MHD_ERR_AGAIN_;
   1109     }
   1110     if (MHD_SCKT_ERR_IS_EINTR_ (err))
   1111       return MHD_ERR_AGAIN_;
   1112     if (MHD_SCKT_ERR_IS_REMOTE_DISCNN_ (err))
   1113       return MHD_ERR_CONNRESET_;
   1114     if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EPIPE_))
   1115       return MHD_ERR_PIPE_;
   1116     if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EOPNOTSUPP_))
   1117       return MHD_ERR_OPNOTSUPP_;
   1118     if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ENOTCONN_))
   1119       return MHD_ERR_NOTCONN_;
   1120     if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EINVAL_))
   1121       return MHD_ERR_INVAL_;
   1122     if (MHD_SCKT_ERR_IS_LOW_RESOURCES_ (err))
   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 &=
   1132       ~((enum MHD_EpollState) MHD_EPOLL_STATE_WRITE_READY);
   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 =
   1205     MHD_D_IS_USING_THREAD_PER_CONN_ (connection->daemon);
   1206   const size_t chunk_size = used_thr_p_c ? MHD_SENFILE_CHUNK_THR_P_C_ :
   1207                             MHD_SENFILE_CHUNK_;
   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 &=
   1263         ~((enum MHD_EpollState) MHD_EPOLL_STATE_WRITE_READY);
   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 &=
   1299       ~((enum MHD_EpollState) MHD_EPOLL_STATE_WRITE_READY);
   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 
   1389 /**
   1390  * Function sends iov data by system sendmsg or writev function.
   1391  *
   1392  * Connection must be in non-TLS (non-HTTPS) mode.
   1393  *
   1394  * @param connection the MHD connection structure
   1395  * @param r_iov the pointer to iov data structure with tracking
   1396  * @param push_data set to true to force push the data to the network from
   1397  *                  system buffers (usually set for the last piece of data),
   1398  *                  set to false to prefer holding incomplete network packets
   1399  *                  (more data will be send for the same reply).
   1400  * @return actual number of bytes sent
   1401  */
   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 &=
   1484         ~((enum MHD_EpollState) MHD_EPOLL_STATE_WRITE_READY);
   1485 #endif /* EPOLL_SUPPORT */
   1486       return MHD_ERR_AGAIN_;
   1487     }
   1488     if (MHD_SCKT_ERR_IS_EINTR_ (err))
   1489       return MHD_ERR_AGAIN_;
   1490     if (MHD_SCKT_ERR_IS_REMOTE_DISCNN_ (err))
   1491       return MHD_ERR_CONNRESET_;
   1492     if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EPIPE_))
   1493       return MHD_ERR_PIPE_;
   1494     if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EOPNOTSUPP_))
   1495       return MHD_ERR_OPNOTSUPP_;
   1496     if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_ENOTCONN_))
   1497       return MHD_ERR_NOTCONN_;
   1498     if (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EINVAL_))
   1499       return MHD_ERR_INVAL_;
   1500     if (MHD_SCKT_ERR_IS_LOW_RESOURCES_ (err))
   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 &=
   1527         ~((enum MHD_EpollState) MHD_EPOLL_STATE_WRITE_READY);
   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 
   1550 /**
   1551  * Function sends iov data by sending buffers one-by-one by standard
   1552  * data send function.
   1553  *
   1554  * Connection could be in HTTPS or non-HTTPS mode.
   1555  *
   1556  * @param connection the MHD connection structure
   1557  * @param r_iov the pointer to iov data structure with tracking
   1558  * @param push_data set to true to force push the data to the network from
   1559  *                  system buffers (usually set for the last piece of data),
   1560  *                  set to false to prefer holding incomplete network packets
   1561  *                  (more data will be send for the same reply).
   1562  * @return actual number of bytes sent
   1563  */
   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 }