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 }