libmicrohttpd2

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

upgraded_net.c (16585B)


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