libmicrohttpd2

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

upgraded_net.c (17521B)


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