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 }