libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

upgraded_net.c (17807B)


      1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
      2 /*
      3   This file is part of GNU libmicrohttpd.
      4   Copyright (C) 2024 Evgeny Grin (Karlson2k) & Christian Grothoff
      5 
      6   GNU libmicrohttpd is free software; you can redistribute it and/or
      7   modify it under the terms of the GNU Lesser General Public
      8   License as published by the Free Software Foundation; either
      9   version 2.1 of the License, or (at your option) any later version.
     10 
     11   GNU libmicrohttpd is distributed in the hope that it will be useful,
     12   but WITHOUT ANY WARRANTY; without even the implied warranty of
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14   Lesser General Public License for more details.
     15 
     16   Alternatively, you can redistribute GNU libmicrohttpd and/or
     17   modify it under the terms of the GNU General Public License as
     18   published by the Free Software Foundation; either version 2 of
     19   the License, or (at your option) any later version, together
     20   with the eCos exception, as follows:
     21 
     22     As a special exception, if other files instantiate templates or
     23     use macros or inline functions from this file, or you compile this
     24     file and link it with other works to produce a work based on this
     25     file, this file does not by itself cause the resulting work to be
     26     covered by the GNU General Public License. However the source code
     27     for this file must still be made available in accordance with
     28     section (3) of the GNU General Public License v2.
     29 
     30     This exception does not invalidate any other reasons why a work
     31     based on this file might be covered by the GNU General Public
     32     License.
     33 
     34   You should have received copies of the GNU Lesser General Public
     35   License and the GNU General Public License along with this library;
     36   if not, see <https://www.gnu.org/licenses/>.
     37 */
     38 
     39 /**
     40  * @file src/mhd2/upgraded_net.c
     41  * @brief  The implementation of functions for network data exchange
     42  *         for HTTP Upgraded connections
     43  * @author Karlson2k (Evgeny Grin)
     44  * @author Christian Grothoff
     45  */
     46 
     47 #include "mhd_sys_options.h"
     48 
     49 #include "sys_bool_type.h"
     50 #include "sys_base_types.h"
     51 
     52 #include "mhd_assert.h"
     53 
     54 #include "sys_poll.h"
     55 #ifndef MHD_SUPPORT_POLL
     56 #  include "sys_select.h"
     57 #endif
     58 #include "mhd_limits.h"
     59 
     60 #include "mhd_sockets_macros.h"
     61 
     62 #include "mhd_upgrade.h"
     63 #include "mhd_connection.h"
     64 #include "mhd_locks.h"
     65 
     66 #include "mhd_recv.h"
     67 #include "mhd_send.h"
     68 #include "mhd_mono_clock.h"
     69 
     70 #include <string.h>
     71 
     72 #include "mhd_public_api.h"
     73 
     74 
     75 #if !defined(MHD_SUPPORT_POLL) && \
     76   (defined(MHD_SOCKETS_KIND_POSIX) || !defined(MHD_SUPPORT_SELECT))
     77 #  if defined(_WIN32) || defined(HAVE_NANOSLEEP) || defined(HAVE_USLEEP)
     78 #    define mhd_HAVE_MHD_SLEEP 1
     79 
     80 /**
     81  * Pause execution for specified number of milliseconds.
     82  *
     83  * @param millisec the number of milliseconds to sleep
     84  */
     85 static void
     86 mhd_sleep (uint_fast32_t millisec)
     87 {
     88 #    if defined(_WIN32)
     89   Sleep (millisec);
     90 #    elif defined(HAVE_NANOSLEEP)
     91   struct timespec slp = { (time_t)(millisec / 1000),
     92                           (long)((millisec % 1000) * 1000000l)};
     93   struct timespec rmn;
     94   int num_retries = 0;
     95   while (0 != nanosleep (&slp, &rmn))
     96   {
     97     if (EINTR != errno)
     98       break;
     99     if (num_retries++ > 8)
    100       break;
    101     slp = rmn;
    102   }
    103 #    elif defined(HAVE_USLEEP)
    104   uint64_t us = millisec * 1000;
    105   do
    106   {
    107     uint64_t this_sleep;
    108     if (999999 < us)
    109       this_sleep = 999999;
    110     else
    111       this_sleep = us;
    112     /* Ignore return value as it could be void */
    113     usleep (this_sleep);
    114     us -= this_sleep;
    115   } while (us > 0);
    116 #    endif
    117 }
    118 
    119 
    120 #  endif /* _WIN32 || HAVE_NANOSLEEP || HAVE_USLEEP */
    121 #endif /* ! MHD_SUPPORT_POLL &&
    122           (MHD_SOCKETS_KIND_POSIX || ! MHD_SUPPORT_SELECT) */
    123 
    124 
    125 MHD_EXTERN_
    126 MHD_FN_PAR_NONNULL_ (1)
    127 MHD_FN_PAR_NONNULL_IF_NONZERO_ (3, 2)
    128 MHD_FN_PAR_OUT_SIZE_ (3, 2)
    129 MHD_FN_PAR_NONNULL_ (4)
    130 MHD_FN_PAR_OUT_ (4) enum MHD_StatusCode
    131 MHD_upgraded_recv (struct MHD_UpgradedHandle *MHD_RESTRICT urh,
    132                    size_t recv_buf_size,
    133                    void *MHD_RESTRICT recv_buf,
    134                    size_t *MHD_RESTRICT received_size,
    135                    uint_fast64_t max_wait_millisec)
    136 {
    137   struct MHD_Connection *restrict c = urh->c;
    138 #if defined(MHD_SUPPORT_POLL) || defined(MHD_SUPPORT_SELECT)
    139   const MHD_Socket socket_fd = c->sk.fd;
    140 #endif /* MHD_SUPPORT_POLL || MHD_SUPPORT_SELECT */
    141   char *restrict buf_char = (char *)recv_buf;
    142   size_t last_block_size;
    143   enum mhd_SocketError res;
    144 
    145   *received_size = 0;
    146 
    147   if (&(c->upgr) != urh)
    148     return MHD_SC_UPGRADED_HANDLE_INVALID;
    149   if (mhd_HTTP_STAGE_UPGRADED != c->stage)
    150     return MHD_SC_UPGRADED_HANDLE_INVALID;
    151 
    152   if (0 == recv_buf_size)
    153     return MHD_SC_OK;
    154 
    155   if (NULL != c->read_buffer)
    156   {
    157     mhd_mutex_lock_chk (&(urh->lock));
    158     if (0 != c->read_buffer_offset) /* Re-check under the lock */
    159     {
    160       if (recv_buf_size < c->read_buffer_offset)
    161       {
    162         memcpy (buf_char, c->read_buffer, recv_buf_size);
    163         last_block_size = recv_buf_size;
    164         c->read_buffer += recv_buf_size;
    165         c->read_buffer_offset -= recv_buf_size;
    166         c->read_buffer_size -= recv_buf_size;
    167       }
    168       else
    169       {
    170         /* recv_buf_size >= c->read_buffer_offset */
    171         memcpy (buf_char, c->read_buffer, c->read_buffer_offset);
    172         last_block_size = c->read_buffer_offset;
    173         c->read_buffer_offset = 0;
    174         c->read_buffer_size = 0;
    175         /* Do not deallocate the read buffer to save the time under the lock.
    176            The connection memory pool will not be used anyway. */
    177         c->read_buffer = NULL;
    178       }
    179     }
    180     else
    181       last_block_size = 0;
    182     mhd_mutex_unlock_chk (&(urh->lock));
    183     *received_size = last_block_size;
    184     if (recv_buf_size == last_block_size)
    185       return MHD_SC_OK;
    186   }
    187 
    188   last_block_size = 0;
    189   res = mhd_recv (c,
    190                   recv_buf_size - *received_size,
    191                   buf_char + *received_size,
    192                   &last_block_size);
    193   if (mhd_SOCKET_ERR_NO_ERROR == res)
    194   {
    195     if (0 == last_block_size)
    196       c->sk.state.rmt_shut_wr = true;
    197     *received_size += last_block_size;
    198     return MHD_SC_OK;
    199   }
    200   else if (0 != *received_size)
    201     return MHD_SC_OK;
    202 
    203   if (!mhd_SOCKET_ERR_IS_HARD (res))
    204   {
    205     while (0 != max_wait_millisec)
    206     {
    207 #if defined(MHD_SUPPORT_POLL)
    208       if (1)
    209       {
    210         struct pollfd fds[1];
    211         int poll_wait;
    212         int poll_res;
    213         int wait_err;
    214 
    215         if (MHD_WAIT_INDEFINITELY <= max_wait_millisec)
    216           poll_wait = -1;
    217         else
    218         {
    219           poll_wait = (int)max_wait_millisec;
    220           if ((max_wait_millisec != (uint_fast64_t)poll_wait)
    221               || (0 > poll_wait))
    222             poll_wait = INT_MAX;
    223         }
    224         fds[0].fd = socket_fd;
    225         fds[0].events = POLLIN;
    226 
    227         poll_res = mhd_poll (fds,
    228                              1,
    229                              poll_wait);
    230         if ((0 >= poll_res)
    231             && (0 != *received_size))
    232           return MHD_SC_OK;
    233         else if (0 == poll_res)
    234           return MHD_SC_UPGRADED_NET_TIMEOUT;
    235         else if (0 > poll_res)
    236         {
    237           wait_err = mhd_SCKT_GET_LERR ();
    238           if (!mhd_SCKT_ERR_IS_EAGAIN (wait_err)
    239               && !mhd_SCKT_ERR_IS_EINTR (wait_err)
    240               && !mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
    241             return MHD_SC_UPGRADED_NET_HARD_ERROR;
    242         }
    243         max_wait_millisec = 0; /* Re-try only one time */
    244       }
    245 #else /* ! MHD_SUPPORT_POLL */
    246 #  if defined(MHD_SUPPORT_SELECT)
    247       bool use_select;
    248 #    ifdef MHD_SOCKETS_KIND_POSIX
    249       use_select = (socket_fd < FD_SETSIZE);
    250 #    else  /* MHD_SOCKETS_KIND_WINSOCK */
    251       use_select = true;
    252 #    endif /* MHD_SOCKETS_KIND_WINSOCK */
    253       if (use_select)
    254       {
    255         fd_set rfds;
    256         int sel_res;
    257         int wait_err;
    258         struct timeval tmvl;
    259 
    260 #    ifdef HAVE_TIME_T
    261         tmvl.tv_sec = (time_t)(max_wait_millisec / 1000);
    262 #    else  /* ! HAVE_TIME_T */
    263         tmvl.tv_sec = (long)(max_wait_millisec / 1000);
    264 #    endif /* ! HAVE_TIME_T */
    265         if ((max_wait_millisec / 1000 != (uint_fast64_t)tmvl.tv_sec)
    266             || ((0 >= tmvl.tv_sec) && (0 != tmvl.tv_sec))) /* Avoid signed/unsigned warnings */
    267         {
    268           /* Do not bother figuring out the real maximum 'time_t' value.
    269              '0x7FFFFFFF' is large enough to be already unrealistic and should
    270              fit most of signed or unsigned time_t types. */
    271           tmvl.tv_sec = 0x7FFFFFFF;
    272           tmvl.tv_usec = 0;
    273         }
    274         else
    275         {
    276 #    ifdef HAVE_SUSECONDS_T
    277           tmvl.tv_usec = (suseconds_t)((max_wait_millisec % 1000) * 1000);
    278 #    else  /* ! HAVE_SUSECONDS_T */
    279           tmvl.tv_usec = (long)((max_wait_millisec % 1000) * 1000);
    280 #    endif /* ! HAVE_SUSECONDS_T */
    281         }
    282         FD_ZERO (&rfds);
    283         FD_SET (socket_fd, &rfds);
    284 
    285         sel_res = select ((int)(c->sk.fd + 1),
    286                           &rfds,
    287                           NULL,
    288                           NULL,
    289                           (MHD_WAIT_INDEFINITELY <= max_wait_millisec) ?
    290                           NULL : &tmvl);
    291 
    292         if ((0 >= sel_res)
    293             && (0 != *received_size))
    294           return MHD_SC_OK;
    295         else if (0 == sel_res)
    296           return MHD_SC_UPGRADED_NET_TIMEOUT;
    297         else if (0 > sel_res)
    298         {
    299           wait_err = mhd_SCKT_GET_LERR ();
    300           if (!mhd_SCKT_ERR_IS_EAGAIN (wait_err)
    301               && !mhd_SCKT_ERR_IS_EINTR (wait_err)
    302               && !mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
    303             return MHD_SC_UPGRADED_NET_HARD_ERROR;
    304         }
    305         max_wait_millisec = 0; /* Re-try only one time */
    306       }
    307       else /* combined with the next 'if()' */
    308 #  endif /* MHD_SUPPORT_SELECT */
    309       if (1)
    310       {
    311 #  ifndef mhd_HAVE_MHD_SLEEP
    312         return MHD_SC_UPGRADED_WAITING_NOT_SUPPORTED;
    313 #  else  /* mhd_HAVE_MHD_SLEEP */
    314         uint_fast32_t wait_millisec = (uint_fast32_t)max_wait_millisec;
    315 
    316         if ((wait_millisec != max_wait_millisec)
    317             || (wait_millisec > 100))
    318           wait_millisec = 100;
    319         mhd_sleep (wait_millisec);
    320         if (MHD_WAIT_INDEFINITELY > max_wait_millisec)
    321           max_wait_millisec -= wait_millisec;
    322 #  endif /* mhd_HAVE_MHD_SLEEP */
    323       }
    324 #endif /* ! MHD_SUPPORT_POLL */
    325       last_block_size = 0;
    326       res = mhd_recv (c,
    327                       recv_buf_size - *received_size,
    328                       buf_char + *received_size,
    329                       &last_block_size);
    330       if (mhd_SOCKET_ERR_NO_ERROR == res)
    331       {
    332         if (0 == last_block_size)
    333           c->sk.state.rmt_shut_wr = true;
    334         *received_size += last_block_size;
    335         return MHD_SC_OK;
    336       }
    337     }
    338   }
    339   if (!mhd_SOCKET_ERR_IS_HARD (res))
    340     return MHD_SC_UPGRADED_NET_TIMEOUT;
    341   if (mhd_SOCKET_ERR_REMT_DISCONN == res)
    342     return MHD_SC_UPGRADED_NET_CONN_CLOSED;
    343 #ifdef MHD_SUPPORT_HTTPS
    344   if (mhd_SOCKET_ERR_TLS == res)
    345     return MHD_SC_UPGRADED_TLS_ERROR;
    346 #endif /* MHD_SUPPORT_HTTPS */
    347   if (!mhd_SOCKET_ERR_IS_BAD (res))
    348     return MHD_SC_UPGRADED_NET_CONN_BROKEN;
    349 
    350   return MHD_SC_UPGRADED_NET_HARD_ERROR;
    351 }
    352 
    353 
    354 MHD_EXTERN_
    355 MHD_FN_PAR_NONNULL_ (1)
    356 MHD_FN_PAR_NONNULL_IF_NONZERO_ (3, 2)
    357 MHD_FN_PAR_IN_SIZE_ (3, 2)
    358 MHD_FN_PAR_NONNULL_ (4)
    359 MHD_FN_PAR_OUT_ (4) enum MHD_StatusCode
    360 MHD_upgraded_send (struct MHD_UpgradedHandle *MHD_RESTRICT urh,
    361                    size_t send_buf_size,
    362                    const void *MHD_RESTRICT send_buf,
    363                    size_t *MHD_RESTRICT sent_size,
    364                    uint_fast64_t max_wait_millisec,
    365                    enum MHD_Bool more_data_to_come)
    366 {
    367   struct MHD_Connection *restrict c = urh->c;
    368 #if defined(MHD_SUPPORT_POLL) || defined(MHD_SUPPORT_SELECT)
    369   const MHD_Socket socket_fd = c->sk.fd;
    370 #endif /* MHD_SUPPORT_POLL || MHD_SUPPORT_SELECT */
    371   const char *restrict buf_char = (const char *)send_buf;
    372   const bool push_data = (MHD_NO == more_data_to_come);
    373   bool finish_time_set;
    374   bool wait_indefinitely;
    375   uint_fast64_t finish_time = 0;
    376 
    377   *sent_size = 0;
    378 
    379   if (&(c->upgr) != urh)
    380     return MHD_SC_UPGRADED_HANDLE_INVALID;
    381   if (mhd_HTTP_STAGE_UPGRADED != c->stage)
    382     return MHD_SC_UPGRADED_HANDLE_INVALID;
    383 
    384   if (0 == send_buf_size)
    385     return MHD_SC_OK;
    386 
    387   finish_time_set = false;
    388   wait_indefinitely = (MHD_WAIT_INDEFINITELY <= max_wait_millisec);
    389 
    390   while (1)
    391   {
    392     enum mhd_SocketError res;
    393     size_t last_block_size;
    394     uint_fast64_t wait_left;
    395 #if !defined(MHD_SUPPORT_POLL) && defined(MHD_SUPPORT_SELECT)
    396     bool use_select;
    397 #endif /* ! MHD_SUPPORT_POLL */
    398 
    399     last_block_size = 0;
    400     res = mhd_send_data (c,
    401                          send_buf_size - *sent_size,
    402                          buf_char + *sent_size,
    403                          push_data,
    404                          &last_block_size);
    405     if (mhd_SOCKET_ERR_NO_ERROR == res)
    406     {
    407       *sent_size += last_block_size;
    408       if (send_buf_size == *sent_size)
    409         break;
    410     }
    411     else if (mhd_SOCKET_ERR_IS_HARD (res))
    412     {
    413       if (0 != *sent_size)
    414         break;
    415 
    416       if (mhd_SOCKET_ERR_REMT_DISCONN == res)
    417         return MHD_SC_UPGRADED_NET_CONN_CLOSED;
    418 #ifdef MHD_SUPPORT_HTTPS
    419       if (mhd_SOCKET_ERR_TLS == res)
    420         return MHD_SC_UPGRADED_TLS_ERROR;
    421 #endif /* MHD_SUPPORT_HTTPS */
    422       if (!mhd_SOCKET_ERR_IS_BAD (res))
    423         return MHD_SC_UPGRADED_NET_CONN_BROKEN;
    424 
    425       return MHD_SC_UPGRADED_NET_HARD_ERROR;
    426     }
    427 
    428     if (0 == max_wait_millisec)
    429     {
    430       mhd_assert (0 == *sent_size);
    431 
    432       return MHD_SC_UPGRADED_NET_TIMEOUT;
    433     }
    434 
    435     if (!wait_indefinitely)
    436     {
    437       uint_fast64_t cur_time;
    438       cur_time = mhd_monotonic_msec_counter ();
    439 
    440       if (!finish_time_set)
    441       {
    442         finish_time = cur_time + max_wait_millisec;
    443         wait_left = max_wait_millisec;
    444       }
    445       else
    446       {
    447         wait_left = finish_time - cur_time;
    448         if ((wait_left > cur_time - finish_time)
    449             || (0 == wait_left))
    450           return MHD_SC_UPGRADED_NET_TIMEOUT;
    451       }
    452     }
    453     else
    454       wait_left = MHD_WAIT_INDEFINITELY; /* Mute compiler warning */
    455 
    456 #if defined(MHD_SUPPORT_POLL)
    457     if (1)
    458     {
    459       struct pollfd fds[1];
    460       int poll_wait;
    461       int poll_res;
    462       int wait_err;
    463 
    464       if (wait_indefinitely)
    465         poll_wait = -1;
    466       else
    467       {
    468         poll_wait = (int)wait_left;
    469         if ((wait_left != (uint_fast64_t)poll_wait)
    470             || (0 > poll_wait))
    471           poll_wait = INT_MAX;
    472       }
    473       fds[0].fd = socket_fd;
    474       fds[0].events = POLLOUT;
    475 
    476       poll_res = mhd_poll (fds,
    477                            1,
    478                            poll_wait);
    479       if (0 < poll_res)
    480         continue;
    481       if (0 == poll_res)
    482       {
    483         if (wait_indefinitely
    484             || (INT_MAX == poll_wait))
    485           continue;
    486         if (0 != *sent_size)
    487           return MHD_SC_OK;
    488         return MHD_SC_UPGRADED_NET_TIMEOUT;
    489       }
    490 
    491       mhd_assert (0 > poll_res);
    492       wait_err = mhd_SCKT_GET_LERR ();
    493       if (!mhd_SCKT_ERR_IS_EAGAIN (wait_err)
    494           && !mhd_SCKT_ERR_IS_EINTR (wait_err)
    495           && !mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
    496         return MHD_SC_UPGRADED_NET_HARD_ERROR;
    497     }
    498 #else /* ! MHD_SUPPORT_POLL */
    499 #  if defined(MHD_SUPPORT_SELECT)
    500 #    ifdef MHD_SOCKETS_KIND_POSIX
    501     use_select = (socket_fd < FD_SETSIZE);
    502 #    else  /* MHD_SOCKETS_KIND_WINSOCK */
    503     use_select = true;
    504 #    endif /* MHD_SOCKETS_KIND_WINSOCK */
    505     if (use_select)
    506     {
    507       fd_set wfds;
    508       int sel_res;
    509       int wait_err;
    510       struct timeval tmvl;
    511       bool max_wait;
    512 
    513       max_wait = false;
    514       if (wait_indefinitely)
    515       {
    516         tmvl.tv_sec = 0;
    517         tmvl.tv_usec = 0;
    518       }
    519       else
    520       {
    521 #    ifdef HAVE_TIME_T
    522         tmvl.tv_sec = (time_t)(max_wait_millisec / 1000);
    523 #    else  /* ! HAVE_TIME_T */
    524         tmvl.tv_sec = (long)(max_wait_millisec / 1000);
    525 #    endif /* ! HAVE_TIME_T */
    526         if ((max_wait_millisec / 1000 != (uint_fast64_t)tmvl.tv_sec)
    527             || ((0 >= tmvl.tv_sec) && (0 != tmvl.tv_sec))) /* Avoid signed/unsigned warnings */
    528         {
    529           /* Do not bother figuring out the real maximum 'time_t' value.
    530              '0x7FFFFFFF' is large enough to be already unrealistic and should
    531              fit most of signed or unsigned time_t types. */
    532           tmvl.tv_sec = 0x7FFFFFFF;
    533           tmvl.tv_usec = 0;
    534           max_wait = true;
    535         }
    536         else
    537         {
    538 #    ifdef HAVE_SUSECONDS_T
    539           tmvl.tv_usec = (suseconds_t)((max_wait_millisec % 1000) * 1000);
    540 #    else  /* ! HAVE_SUSECONDS_T */
    541           tmvl.tv_usec = (long)((max_wait_millisec % 1000) * 1000);
    542 #    endif /* ! HAVE_SUSECONDS_T */
    543         }
    544       }
    545       FD_ZERO (&wfds);
    546       FD_SET (socket_fd, &wfds);
    547 
    548       sel_res = select ((int)(c->sk.fd + 1),
    549                         NULL,
    550                         &wfds,
    551                         NULL,
    552                         wait_indefinitely ? NULL : &tmvl);
    553 
    554       if (0 < sel_res)
    555         continue;
    556       if (0 == sel_res)
    557       {
    558         if (wait_indefinitely
    559             || max_wait)
    560           continue;
    561         if (0 != *sent_size)
    562           return MHD_SC_OK;
    563         return MHD_SC_UPGRADED_NET_TIMEOUT;
    564       }
    565 
    566       mhd_assert (0 > sel_res);
    567       wait_err = mhd_SCKT_GET_LERR ();
    568       if (!mhd_SCKT_ERR_IS_EAGAIN (wait_err)
    569           && !mhd_SCKT_ERR_IS_EINTR (wait_err)
    570           && !mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
    571         return MHD_SC_UPGRADED_NET_HARD_ERROR;
    572     }
    573     else /* combined with the next 'if()' */
    574 #  endif /* MHD_SUPPORT_SELECT */
    575     if (1)
    576     {
    577 #  ifndef mhd_HAVE_MHD_SLEEP
    578       return MHD_SC_UPGRADED_WAITING_NOT_SUPPORTED;
    579 #  else  /* mhd_HAVE_MHD_SLEEP */
    580       uint_fast32_t wait_millisec = (uint_fast32_t)wait_left;
    581 
    582       if ((wait_millisec != wait_left)
    583           || (wait_millisec > 100))
    584         wait_millisec = 100;
    585       mhd_sleep (wait_millisec);
    586 #  endif /* mhd_HAVE_MHD_SLEEP */
    587     }
    588 #endif /* ! MHD_SUPPORT_POLL */
    589   }
    590 
    591   return MHD_SC_OK;
    592 }