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 }