libmicrohttpd2

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

upgraded_net.c (17546B)


      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   if (mhd_SOCKET_ERR_TLS == res)
    342     return MHD_SC_UPGRADED_TLS_ERROR;
    343   if (! mhd_SOCKET_ERR_IS_BAD (res))
    344     return MHD_SC_UPGRADED_NET_CONN_BROKEN;
    345 
    346   return MHD_SC_UPGRADED_NET_HARD_ERROR;
    347 }
    348 
    349 
    350 MHD_EXTERN_
    351 MHD_FN_PAR_NONNULL_ALL_
    352 MHD_FN_PAR_IN_SIZE_ (3,2)
    353 MHD_FN_PAR_OUT_ (4) enum MHD_StatusCode
    354 MHD_upgraded_send (struct MHD_UpgradedHandle *MHD_RESTRICT urh,
    355                    size_t send_buf_size,
    356                    const void *MHD_RESTRICT send_buf,
    357                    size_t *MHD_RESTRICT sent_size,
    358                    uint_fast64_t max_wait_millisec,
    359                    enum MHD_Bool more_data_to_come)
    360 {
    361   struct MHD_Connection *restrict c = urh->c;
    362 #if defined(MHD_SUPPORT_POLL) || defined(MHD_SUPPORT_SELECT)
    363   const MHD_Socket socket_fd = c->sk.fd;
    364 #endif /* MHD_SUPPORT_POLL || MHD_SUPPORT_SELECT */
    365   const char *restrict buf_char = (const char *) send_buf;
    366   const bool push_data = (MHD_NO == more_data_to_come);
    367   bool finish_time_set;
    368   bool wait_indefinitely;
    369   uint_fast64_t finish_time = 0;
    370 
    371   *sent_size = 0;
    372 
    373   if (&(c->upgr) != urh)
    374     return MHD_SC_UPGRADED_HANDLE_INVALID;
    375   if (mhd_HTTP_STAGE_UPGRADED != c->stage)
    376     return MHD_SC_UPGRADED_HANDLE_INVALID;
    377 
    378   finish_time_set = false;
    379   wait_indefinitely = (MHD_WAIT_INDEFINITELY <= max_wait_millisec);
    380 
    381   while (1)
    382   {
    383     enum mhd_SocketError res;
    384     size_t last_block_size;
    385     uint_fast64_t wait_left;
    386 #if ! defined(MHD_SUPPORT_POLL) && defined(MHD_SUPPORT_SELECT)
    387     bool use_select;
    388 #endif /* ! MHD_SUPPORT_POLL */
    389 
    390     last_block_size = 0;
    391     res = mhd_send_data (c,
    392                          send_buf_size - *sent_size,
    393                          buf_char + *sent_size,
    394                          push_data,
    395                          &last_block_size);
    396     if (mhd_SOCKET_ERR_NO_ERROR == res)
    397     {
    398       *sent_size += last_block_size;
    399       if (send_buf_size == *sent_size)
    400         break;
    401     }
    402     else if (mhd_SOCKET_ERR_IS_HARD (res))
    403     {
    404       if (0 != *sent_size)
    405         break;
    406 
    407       if (mhd_SOCKET_ERR_REMT_DISCONN == res)
    408         return MHD_SC_UPGRADED_NET_CONN_CLOSED;
    409       if (mhd_SOCKET_ERR_TLS == res)
    410         return MHD_SC_UPGRADED_TLS_ERROR;
    411       if (! mhd_SOCKET_ERR_IS_BAD (res))
    412         return MHD_SC_UPGRADED_NET_CONN_BROKEN;
    413 
    414       return MHD_SC_UPGRADED_NET_HARD_ERROR;
    415     }
    416 
    417     if (0 == max_wait_millisec)
    418     {
    419       mhd_assert (0 == *sent_size);
    420 
    421       return MHD_SC_UPGRADED_NET_TIMEOUT;
    422     }
    423 
    424     if (! wait_indefinitely)
    425     {
    426       uint_fast64_t cur_time;
    427       cur_time = mhd_monotonic_msec_counter ();
    428 
    429       if (! finish_time_set)
    430       {
    431         finish_time = cur_time + max_wait_millisec;
    432         wait_left = max_wait_millisec;
    433       }
    434       else
    435       {
    436         wait_left = finish_time - cur_time;
    437         if ((wait_left > cur_time - finish_time) ||
    438             (0 == wait_left))
    439           return MHD_SC_UPGRADED_NET_TIMEOUT;
    440       }
    441     }
    442     else
    443       wait_left = MHD_WAIT_INDEFINITELY; /* Mute compiler warning */
    444 
    445 #if defined(MHD_SUPPORT_POLL)
    446     if (1)
    447     {
    448       struct pollfd fds[1];
    449       int poll_wait;
    450       int poll_res;
    451       int wait_err;
    452 
    453       if (wait_indefinitely)
    454         poll_wait = -1;
    455       else
    456       {
    457         poll_wait = (int) wait_left;
    458         if ((wait_left != (uint_fast64_t) poll_wait) ||
    459             (0 > poll_wait))
    460           poll_wait = INT_MAX;
    461       }
    462       fds[0].fd = socket_fd;
    463       fds[0].events = POLLOUT;
    464 
    465       poll_res = mhd_poll (fds,
    466                            1,
    467                            poll_wait);
    468       if (0 < poll_res)
    469         continue;
    470       if (0 == poll_res)
    471       {
    472         if (wait_indefinitely ||
    473             (INT_MAX == poll_wait))
    474           continue;
    475         if (0 != *sent_size)
    476           return MHD_SC_OK;
    477         return MHD_SC_UPGRADED_NET_TIMEOUT;
    478       }
    479 
    480       mhd_assert (0 > poll_res);
    481       wait_err = mhd_SCKT_GET_LERR ();
    482       if (! mhd_SCKT_ERR_IS_EAGAIN (wait_err) &&
    483           ! mhd_SCKT_ERR_IS_EINTR (wait_err) &&
    484           ! mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
    485         return MHD_SC_UPGRADED_NET_HARD_ERROR;
    486     }
    487 #else /* ! MHD_SUPPORT_POLL */
    488 #  if defined(MHD_SUPPORT_SELECT)
    489 #    ifdef MHD_SOCKETS_KIND_POSIX
    490     use_select = (socket_fd < FD_SETSIZE);
    491 #    else  /* MHD_SOCKETS_KIND_WINSOCK */
    492     use_select = true;
    493 #    endif /* MHD_SOCKETS_KIND_WINSOCK */
    494     if (use_select)
    495     {
    496       fd_set wfds;
    497       int sel_res;
    498       int wait_err;
    499       struct timeval tmvl;
    500       bool max_wait;
    501 
    502       max_wait = false;
    503       if (wait_indefinitely)
    504       {
    505         tmvl.tv_sec = 0;
    506         tmvl.tv_usec = 0;
    507       }
    508       else
    509       {
    510 #    ifdef HAVE_TIME_T
    511         tmvl.tv_sec = (time_t) (max_wait_millisec / 1000);
    512 #    else  /* ! HAVE_TIME_T */
    513         tmvl.tv_sec = (long) (max_wait_millisec / 1000);
    514 #    endif /* ! HAVE_TIME_T */
    515         if ((max_wait_millisec / 1000 != (uint_fast64_t) tmvl.tv_sec) ||
    516             ((0 >= tmvl.tv_sec) && (0 != tmvl.tv_sec))) /* Avoid signed/unsigned warnings */
    517         {
    518           /* Do not bother figuring out the real maximum 'time_t' value.
    519              '0x7FFFFFFF' is large enough to be already unrealistic and should
    520              fit most of signed or unsigned time_t types. */
    521           tmvl.tv_sec = 0x7FFFFFFF;
    522           tmvl.tv_usec = 0;
    523           max_wait = true;
    524         }
    525         else
    526         {
    527 #    ifdef HAVE_SUSECONDS_T
    528           tmvl.tv_usec = (suseconds_t) ((max_wait_millisec % 1000) * 1000);
    529 #    else  /* ! HAVE_SUSECONDS_T */
    530           tmvl.tv_usec = (long) ((max_wait_millisec % 1000) * 1000);
    531 #    endif /* ! HAVE_SUSECONDS_T */
    532         }
    533       }
    534       FD_ZERO (&wfds);
    535       FD_SET (socket_fd, &wfds);
    536 
    537       sel_res = select ((int) (c->sk.fd + 1),
    538                         NULL,
    539                         &wfds,
    540                         NULL,
    541                         wait_indefinitely ? NULL : &tmvl);
    542 
    543       if (0 < sel_res)
    544         continue;
    545       if (0 == sel_res)
    546       {
    547         if (wait_indefinitely ||
    548             max_wait)
    549           continue;
    550         if (0 != *sent_size)
    551           return MHD_SC_OK;
    552         return MHD_SC_UPGRADED_NET_TIMEOUT;
    553       }
    554 
    555       mhd_assert (0 > sel_res);
    556       wait_err = mhd_SCKT_GET_LERR ();
    557       if (! mhd_SCKT_ERR_IS_EAGAIN (wait_err) &&
    558           ! mhd_SCKT_ERR_IS_EINTR (wait_err) &&
    559           ! mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err))
    560         return MHD_SC_UPGRADED_NET_HARD_ERROR;
    561     }
    562     else /* combined with the next 'if()' */
    563 #  endif /* MHD_SUPPORT_SELECT */
    564     if (1)
    565     {
    566 #  ifndef mhd_HAVE_MHD_SLEEP
    567       return MHD_SC_UPGRADED_WAITING_NOT_SUPPORTED;
    568 #  else  /* mhd_HAVE_MHD_SLEEP */
    569       uint_fast32_t wait_millisec = (uint_fast32_t) wait_left;
    570 
    571       if ((wait_millisec != wait_left) ||
    572           (wait_millisec > 100))
    573         wait_millisec = 100;
    574       mhd_sleep (wait_millisec);
    575 #  endif /* mhd_HAVE_MHD_SLEEP */
    576     }
    577 #endif /* ! MHD_SUPPORT_POLL */
    578   }
    579 
    580   return MHD_SC_OK;
    581 }