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