libmicrohttpd2

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

upgraded_net.c (17634B)


      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_ALL_
    127 MHD_FN_PAR_OUT_SIZE_ (3, 2)
    128 MHD_FN_PAR_OUT_ (4) enum MHD_StatusCode
    129 MHD_upgraded_recv (struct MHD_UpgradedHandle *MHD_RESTRICT urh,
    130                    size_t recv_buf_size,
    131                    void *MHD_RESTRICT recv_buf,
    132                    size_t *MHD_RESTRICT received_size,
    133                    uint_fast64_t max_wait_millisec)
    134 {
    135   struct MHD_Connection *restrict c = urh->c;
    136 #if defined(MHD_SUPPORT_POLL) || defined(MHD_SUPPORT_SELECT)
    137   const MHD_Socket socket_fd = c->sk.fd;
    138 #endif /* MHD_SUPPORT_POLL || MHD_SUPPORT_SELECT */
    139   char *restrict buf_char = (char *)recv_buf;
    140   size_t last_block_size;
    141   enum mhd_SocketError res;
    142 
    143   *received_size = 0;
    144 
    145   if (&(c->upgr) != urh)
    146     return MHD_SC_UPGRADED_HANDLE_INVALID;
    147   if (mhd_HTTP_STAGE_UPGRADED != c->stage)
    148     return MHD_SC_UPGRADED_HANDLE_INVALID;
    149 
    150   if (0 == recv_buf_size)
    151     return MHD_SC_OK;
    152 
    153   if (NULL != c->read_buffer)
    154   {
    155     mhd_mutex_lock_chk (&(urh->lock));
    156     if (0 != c->read_buffer_offset) /* Re-check under the lock */
    157     {
    158       if (recv_buf_size < c->read_buffer_offset)
    159       {
    160         memcpy (buf_char, c->read_buffer, recv_buf_size);
    161         last_block_size = recv_buf_size;
    162         c->read_buffer += recv_buf_size;
    163         c->read_buffer_offset -= recv_buf_size;
    164         c->read_buffer_size -= recv_buf_size;
    165       }
    166       else
    167       {
    168         /* recv_buf_size >= c->read_buffer_offset */
    169         memcpy (buf_char, c->read_buffer, c->read_buffer_offset);
    170         last_block_size = c->read_buffer_offset;
    171         c->read_buffer_offset = 0;
    172         c->read_buffer_size = 0;
    173         /* Do not deallocate the read buffer to save the time under the lock.
    174            The connection memory pool will not be used anyway. */
    175         c->read_buffer = NULL;
    176       }
    177     }
    178     else
    179       last_block_size = 0;
    180     mhd_mutex_unlock_chk (&(urh->lock));
    181     *received_size = last_block_size;
    182     if (recv_buf_size == last_block_size)
    183       return MHD_SC_OK;
    184   }
    185 
    186   last_block_size = 0;
    187   res = mhd_recv (c,
    188                   recv_buf_size - *received_size,
    189                   buf_char + *received_size,
    190                   &last_block_size);
    191   if (mhd_SOCKET_ERR_NO_ERROR == res)
    192   {
    193     if (0 == last_block_size)
    194       c->sk.state.rmt_shut_wr = true;
    195     *received_size += last_block_size;
    196     return MHD_SC_OK;
    197   }
    198   else if (0 != *received_size)
    199     return MHD_SC_OK;
    200 
    201   if (!mhd_SOCKET_ERR_IS_HARD (res))
    202   {
    203     while (0 != max_wait_millisec)
    204     {
    205 #if defined(MHD_SUPPORT_POLL)
    206       if (1)
    207       {
    208         struct pollfd fds[1];
    209         int poll_wait;
    210         int poll_res;
    211         int wait_err;
    212 
    213         if (MHD_WAIT_INDEFINITELY <= max_wait_millisec)
    214           poll_wait = -1;
    215         else
    216         {
    217           poll_wait = (int)max_wait_millisec;
    218           if ((max_wait_millisec != (uint_fast64_t)poll_wait)
    219               || (0 > poll_wait))
    220             poll_wait = INT_MAX;
    221         }
    222         fds[0].fd = socket_fd;
    223         fds[0].events = POLLIN;
    224 
    225         poll_res = mhd_poll (fds,
    226                              1,
    227                              poll_wait);
    228         if ((0 >= poll_res)
    229             && (0 != *received_size))
    230           return MHD_SC_OK;
    231         else if (0 == poll_res)
    232           return MHD_SC_UPGRADED_NET_TIMEOUT;
    233         else if (0 > poll_res)
    234         {
    235           wait_err = mhd_SCKT_GET_LERR ();
    236           if (!mhd_SCKT_ERR_IS_EAGAIN (wait_err)
    237               && !mhd_SCKT_ERR_IS_EINTR (wait_err)
    238               && !mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
    239             return MHD_SC_UPGRADED_NET_HARD_ERROR;
    240         }
    241         max_wait_millisec = 0; /* Re-try only one time */
    242       }
    243 #else /* ! MHD_SUPPORT_POLL */
    244 #  if defined(MHD_SUPPORT_SELECT)
    245       bool use_select;
    246 #    ifdef MHD_SOCKETS_KIND_POSIX
    247       use_select = (socket_fd < FD_SETSIZE);
    248 #    else  /* MHD_SOCKETS_KIND_WINSOCK */
    249       use_select = true;
    250 #    endif /* MHD_SOCKETS_KIND_WINSOCK */
    251       if (use_select)
    252       {
    253         fd_set rfds;
    254         int sel_res;
    255         int wait_err;
    256         struct timeval tmvl;
    257 
    258 #    ifdef HAVE_TIME_T
    259         tmvl.tv_sec = (time_t)(max_wait_millisec / 1000);
    260 #    else  /* ! HAVE_TIME_T */
    261         tmvl.tv_sec = (long)(max_wait_millisec / 1000);
    262 #    endif /* ! HAVE_TIME_T */
    263         if ((max_wait_millisec / 1000 != (uint_fast64_t)tmvl.tv_sec)
    264             || ((0 >= tmvl.tv_sec) && (0 != tmvl.tv_sec))) /* Avoid signed/unsigned warnings */
    265         {
    266           /* Do not bother figuring out the real maximum 'time_t' value.
    267              '0x7FFFFFFF' is large enough to be already unrealistic and should
    268              fit most of signed or unsigned time_t types. */
    269           tmvl.tv_sec = 0x7FFFFFFF;
    270           tmvl.tv_usec = 0;
    271         }
    272         else
    273         {
    274 #    ifdef HAVE_SUSECONDS_T
    275           tmvl.tv_usec = (suseconds_t)((max_wait_millisec % 1000) * 1000);
    276 #    else  /* ! HAVE_SUSECONDS_T */
    277           tmvl.tv_usec = (long)((max_wait_millisec % 1000) * 1000);
    278 #    endif /* ! HAVE_SUSECONDS_T */
    279         }
    280         FD_ZERO (&rfds);
    281         FD_SET (socket_fd, &rfds);
    282 
    283         sel_res = select ((int)(c->sk.fd + 1),
    284                           &rfds,
    285                           NULL,
    286                           NULL,
    287                           (MHD_WAIT_INDEFINITELY <= max_wait_millisec) ?
    288                           NULL : &tmvl);
    289 
    290         if ((0 >= sel_res)
    291             && (0 != *received_size))
    292           return MHD_SC_OK;
    293         else if (0 == sel_res)
    294           return MHD_SC_UPGRADED_NET_TIMEOUT;
    295         else if (0 > sel_res)
    296         {
    297           wait_err = mhd_SCKT_GET_LERR ();
    298           if (!mhd_SCKT_ERR_IS_EAGAIN (wait_err)
    299               && !mhd_SCKT_ERR_IS_EINTR (wait_err)
    300               && !mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
    301             return MHD_SC_UPGRADED_NET_HARD_ERROR;
    302         }
    303         max_wait_millisec = 0; /* Re-try only one time */
    304       }
    305       else /* combined with the next 'if()' */
    306 #  endif /* MHD_SUPPORT_SELECT */
    307       if (1)
    308       {
    309 #  ifndef mhd_HAVE_MHD_SLEEP
    310         return MHD_SC_UPGRADED_WAITING_NOT_SUPPORTED;
    311 #  else  /* mhd_HAVE_MHD_SLEEP */
    312         uint_fast32_t wait_millisec = (uint_fast32_t)max_wait_millisec;
    313 
    314         if ((wait_millisec != max_wait_millisec)
    315             || (wait_millisec > 100))
    316           wait_millisec = 100;
    317         mhd_sleep (wait_millisec);
    318         if (MHD_WAIT_INDEFINITELY > max_wait_millisec)
    319           max_wait_millisec -= wait_millisec;
    320 #  endif /* mhd_HAVE_MHD_SLEEP */
    321       }
    322 #endif /* ! MHD_SUPPORT_POLL */
    323       last_block_size = 0;
    324       res = mhd_recv (c,
    325                       recv_buf_size - *received_size,
    326                       buf_char + *received_size,
    327                       &last_block_size);
    328       if (mhd_SOCKET_ERR_NO_ERROR == res)
    329       {
    330         if (0 == last_block_size)
    331           c->sk.state.rmt_shut_wr = true;
    332         *received_size += last_block_size;
    333         return MHD_SC_OK;
    334       }
    335     }
    336   }
    337   if (!mhd_SOCKET_ERR_IS_HARD (res))
    338     return MHD_SC_UPGRADED_NET_TIMEOUT;
    339   if (mhd_SOCKET_ERR_REMT_DISCONN == res)
    340     return MHD_SC_UPGRADED_NET_CONN_CLOSED;
    341 #ifdef MHD_SUPPORT_HTTPS
    342   if (mhd_SOCKET_ERR_TLS == res)
    343     return MHD_SC_UPGRADED_TLS_ERROR;
    344 #endif /* MHD_SUPPORT_HTTPS */
    345   if (!mhd_SOCKET_ERR_IS_BAD (res))
    346     return MHD_SC_UPGRADED_NET_CONN_BROKEN;
    347 
    348   return MHD_SC_UPGRADED_NET_HARD_ERROR;
    349 }
    350 
    351 
    352 MHD_EXTERN_
    353 MHD_FN_PAR_NONNULL_ALL_
    354 MHD_FN_PAR_IN_SIZE_ (3, 2)
    355 MHD_FN_PAR_OUT_ (4) enum MHD_StatusCode
    356 MHD_upgraded_send (struct MHD_UpgradedHandle *MHD_RESTRICT urh,
    357                    size_t send_buf_size,
    358                    const void *MHD_RESTRICT send_buf,
    359                    size_t *MHD_RESTRICT sent_size,
    360                    uint_fast64_t max_wait_millisec,
    361                    enum MHD_Bool more_data_to_come)
    362 {
    363   struct MHD_Connection *restrict c = urh->c;
    364 #if defined(MHD_SUPPORT_POLL) || defined(MHD_SUPPORT_SELECT)
    365   const MHD_Socket socket_fd = c->sk.fd;
    366 #endif /* MHD_SUPPORT_POLL || MHD_SUPPORT_SELECT */
    367   const char *restrict buf_char = (const char *)send_buf;
    368   const bool push_data = (MHD_NO == more_data_to_come);
    369   bool finish_time_set;
    370   bool wait_indefinitely;
    371   uint_fast64_t finish_time = 0;
    372 
    373   *sent_size = 0;
    374 
    375   if (&(c->upgr) != urh)
    376     return MHD_SC_UPGRADED_HANDLE_INVALID;
    377   if (mhd_HTTP_STAGE_UPGRADED != c->stage)
    378     return MHD_SC_UPGRADED_HANDLE_INVALID;
    379 
    380   finish_time_set = false;
    381   wait_indefinitely = (MHD_WAIT_INDEFINITELY <= max_wait_millisec);
    382 
    383   while (1)
    384   {
    385     enum mhd_SocketError res;
    386     size_t last_block_size;
    387     uint_fast64_t wait_left;
    388 #if !defined(MHD_SUPPORT_POLL) && defined(MHD_SUPPORT_SELECT)
    389     bool use_select;
    390 #endif /* ! MHD_SUPPORT_POLL */
    391 
    392     last_block_size = 0;
    393     res = mhd_send_data (c,
    394                          send_buf_size - *sent_size,
    395                          buf_char + *sent_size,
    396                          push_data,
    397                          &last_block_size);
    398     if (mhd_SOCKET_ERR_NO_ERROR == res)
    399     {
    400       *sent_size += last_block_size;
    401       if (send_buf_size == *sent_size)
    402         break;
    403     }
    404     else if (mhd_SOCKET_ERR_IS_HARD (res))
    405     {
    406       if (0 != *sent_size)
    407         break;
    408 
    409       if (mhd_SOCKET_ERR_REMT_DISCONN == res)
    410         return MHD_SC_UPGRADED_NET_CONN_CLOSED;
    411 #ifdef MHD_SUPPORT_HTTPS
    412       if (mhd_SOCKET_ERR_TLS == res)
    413         return MHD_SC_UPGRADED_TLS_ERROR;
    414 #endif /* MHD_SUPPORT_HTTPS */
    415       if (!mhd_SOCKET_ERR_IS_BAD (res))
    416         return MHD_SC_UPGRADED_NET_CONN_BROKEN;
    417 
    418       return MHD_SC_UPGRADED_NET_HARD_ERROR;
    419     }
    420 
    421     if (0 == max_wait_millisec)
    422     {
    423       mhd_assert (0 == *sent_size);
    424 
    425       return MHD_SC_UPGRADED_NET_TIMEOUT;
    426     }
    427 
    428     if (!wait_indefinitely)
    429     {
    430       uint_fast64_t cur_time;
    431       cur_time = mhd_monotonic_msec_counter ();
    432 
    433       if (!finish_time_set)
    434       {
    435         finish_time = cur_time + max_wait_millisec;
    436         wait_left = max_wait_millisec;
    437       }
    438       else
    439       {
    440         wait_left = finish_time - cur_time;
    441         if ((wait_left > cur_time - finish_time)
    442             || (0 == wait_left))
    443           return MHD_SC_UPGRADED_NET_TIMEOUT;
    444       }
    445     }
    446     else
    447       wait_left = MHD_WAIT_INDEFINITELY; /* Mute compiler warning */
    448 
    449 #if defined(MHD_SUPPORT_POLL)
    450     if (1)
    451     {
    452       struct pollfd fds[1];
    453       int poll_wait;
    454       int poll_res;
    455       int wait_err;
    456 
    457       if (wait_indefinitely)
    458         poll_wait = -1;
    459       else
    460       {
    461         poll_wait = (int)wait_left;
    462         if ((wait_left != (uint_fast64_t)poll_wait)
    463             || (0 > poll_wait))
    464           poll_wait = INT_MAX;
    465       }
    466       fds[0].fd = socket_fd;
    467       fds[0].events = POLLOUT;
    468 
    469       poll_res = mhd_poll (fds,
    470                            1,
    471                            poll_wait);
    472       if (0 < poll_res)
    473         continue;
    474       if (0 == poll_res)
    475       {
    476         if (wait_indefinitely
    477             || (INT_MAX == poll_wait))
    478           continue;
    479         if (0 != *sent_size)
    480           return MHD_SC_OK;
    481         return MHD_SC_UPGRADED_NET_TIMEOUT;
    482       }
    483 
    484       mhd_assert (0 > poll_res);
    485       wait_err = mhd_SCKT_GET_LERR ();
    486       if (!mhd_SCKT_ERR_IS_EAGAIN (wait_err)
    487           && !mhd_SCKT_ERR_IS_EINTR (wait_err)
    488           && !mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
    489         return MHD_SC_UPGRADED_NET_HARD_ERROR;
    490     }
    491 #else /* ! MHD_SUPPORT_POLL */
    492 #  if defined(MHD_SUPPORT_SELECT)
    493 #    ifdef MHD_SOCKETS_KIND_POSIX
    494     use_select = (socket_fd < FD_SETSIZE);
    495 #    else  /* MHD_SOCKETS_KIND_WINSOCK */
    496     use_select = true;
    497 #    endif /* MHD_SOCKETS_KIND_WINSOCK */
    498     if (use_select)
    499     {
    500       fd_set wfds;
    501       int sel_res;
    502       int wait_err;
    503       struct timeval tmvl;
    504       bool max_wait;
    505 
    506       max_wait = false;
    507       if (wait_indefinitely)
    508       {
    509         tmvl.tv_sec = 0;
    510         tmvl.tv_usec = 0;
    511       }
    512       else
    513       {
    514 #    ifdef HAVE_TIME_T
    515         tmvl.tv_sec = (time_t)(max_wait_millisec / 1000);
    516 #    else  /* ! HAVE_TIME_T */
    517         tmvl.tv_sec = (long)(max_wait_millisec / 1000);
    518 #    endif /* ! HAVE_TIME_T */
    519         if ((max_wait_millisec / 1000 != (uint_fast64_t)tmvl.tv_sec)
    520             || ((0 >= tmvl.tv_sec) && (0 != tmvl.tv_sec))) /* Avoid signed/unsigned warnings */
    521         {
    522           /* Do not bother figuring out the real maximum 'time_t' value.
    523              '0x7FFFFFFF' is large enough to be already unrealistic and should
    524              fit most of signed or unsigned time_t types. */
    525           tmvl.tv_sec = 0x7FFFFFFF;
    526           tmvl.tv_usec = 0;
    527           max_wait = true;
    528         }
    529         else
    530         {
    531 #    ifdef HAVE_SUSECONDS_T
    532           tmvl.tv_usec = (suseconds_t)((max_wait_millisec % 1000) * 1000);
    533 #    else  /* ! HAVE_SUSECONDS_T */
    534           tmvl.tv_usec = (long)((max_wait_millisec % 1000) * 1000);
    535 #    endif /* ! HAVE_SUSECONDS_T */
    536         }
    537       }
    538       FD_ZERO (&wfds);
    539       FD_SET (socket_fd, &wfds);
    540 
    541       sel_res = select ((int)(c->sk.fd + 1),
    542                         NULL,
    543                         &wfds,
    544                         NULL,
    545                         wait_indefinitely ? NULL : &tmvl);
    546 
    547       if (0 < sel_res)
    548         continue;
    549       if (0 == sel_res)
    550       {
    551         if (wait_indefinitely
    552             || max_wait)
    553           continue;
    554         if (0 != *sent_size)
    555           return MHD_SC_OK;
    556         return MHD_SC_UPGRADED_NET_TIMEOUT;
    557       }
    558 
    559       mhd_assert (0 > sel_res);
    560       wait_err = mhd_SCKT_GET_LERR ();
    561       if (!mhd_SCKT_ERR_IS_EAGAIN (wait_err)
    562           && !mhd_SCKT_ERR_IS_EINTR (wait_err)
    563           && !mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
    564         return MHD_SC_UPGRADED_NET_HARD_ERROR;
    565     }
    566     else /* combined with the next 'if()' */
    567 #  endif /* MHD_SUPPORT_SELECT */
    568     if (1)
    569     {
    570 #  ifndef mhd_HAVE_MHD_SLEEP
    571       return MHD_SC_UPGRADED_WAITING_NOT_SUPPORTED;
    572 #  else  /* mhd_HAVE_MHD_SLEEP */
    573       uint_fast32_t wait_millisec = (uint_fast32_t)wait_left;
    574 
    575       if ((wait_millisec != wait_left)
    576           || (wait_millisec > 100))
    577         wait_millisec = 100;
    578       mhd_sleep (wait_millisec);
    579 #  endif /* mhd_HAVE_MHD_SLEEP */
    580     }
    581 #endif /* ! MHD_SUPPORT_POLL */
    582   }
    583 
    584   return MHD_SC_OK;
    585 }