upgraded_net.c (17634B)
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 #ifdef MHD_SUPPORT_HTTPS 342 if (mhd_SOCKET_ERR_TLS == res) 343 return MHD_SC_UPGRADED_TLS_ERROR; 344 #endif /* MHD_SUPPORT_HTTPS */ 345 if (!mhd_SOCKET_ERR_IS_BAD (res)) 346 return MHD_SC_UPGRADED_NET_CONN_BROKEN; 347 348 return MHD_SC_UPGRADED_NET_HARD_ERROR; 349 } 350 351 352 MHD_EXTERN_ 353 MHD_FN_PAR_NONNULL_ALL_ 354 MHD_FN_PAR_IN_SIZE_ (3, 2) 355 MHD_FN_PAR_OUT_ (4) enum MHD_StatusCode 356 MHD_upgraded_send (struct MHD_UpgradedHandle *MHD_RESTRICT urh, 357 size_t send_buf_size, 358 const void *MHD_RESTRICT send_buf, 359 size_t *MHD_RESTRICT sent_size, 360 uint_fast64_t max_wait_millisec, 361 enum MHD_Bool more_data_to_come) 362 { 363 struct MHD_Connection *restrict c = urh->c; 364 #if defined(MHD_SUPPORT_POLL) || defined(MHD_SUPPORT_SELECT) 365 const MHD_Socket socket_fd = c->sk.fd; 366 #endif /* MHD_SUPPORT_POLL || MHD_SUPPORT_SELECT */ 367 const char *restrict buf_char = (const char *)send_buf; 368 const bool push_data = (MHD_NO == more_data_to_come); 369 bool finish_time_set; 370 bool wait_indefinitely; 371 uint_fast64_t finish_time = 0; 372 373 *sent_size = 0; 374 375 if (&(c->upgr) != urh) 376 return MHD_SC_UPGRADED_HANDLE_INVALID; 377 if (mhd_HTTP_STAGE_UPGRADED != c->stage) 378 return MHD_SC_UPGRADED_HANDLE_INVALID; 379 380 finish_time_set = false; 381 wait_indefinitely = (MHD_WAIT_INDEFINITELY <= max_wait_millisec); 382 383 while (1) 384 { 385 enum mhd_SocketError res; 386 size_t last_block_size; 387 uint_fast64_t wait_left; 388 #if !defined(MHD_SUPPORT_POLL) && defined(MHD_SUPPORT_SELECT) 389 bool use_select; 390 #endif /* ! MHD_SUPPORT_POLL */ 391 392 last_block_size = 0; 393 res = mhd_send_data (c, 394 send_buf_size - *sent_size, 395 buf_char + *sent_size, 396 push_data, 397 &last_block_size); 398 if (mhd_SOCKET_ERR_NO_ERROR == res) 399 { 400 *sent_size += last_block_size; 401 if (send_buf_size == *sent_size) 402 break; 403 } 404 else if (mhd_SOCKET_ERR_IS_HARD (res)) 405 { 406 if (0 != *sent_size) 407 break; 408 409 if (mhd_SOCKET_ERR_REMT_DISCONN == res) 410 return MHD_SC_UPGRADED_NET_CONN_CLOSED; 411 #ifdef MHD_SUPPORT_HTTPS 412 if (mhd_SOCKET_ERR_TLS == res) 413 return MHD_SC_UPGRADED_TLS_ERROR; 414 #endif /* MHD_SUPPORT_HTTPS */ 415 if (!mhd_SOCKET_ERR_IS_BAD (res)) 416 return MHD_SC_UPGRADED_NET_CONN_BROKEN; 417 418 return MHD_SC_UPGRADED_NET_HARD_ERROR; 419 } 420 421 if (0 == max_wait_millisec) 422 { 423 mhd_assert (0 == *sent_size); 424 425 return MHD_SC_UPGRADED_NET_TIMEOUT; 426 } 427 428 if (!wait_indefinitely) 429 { 430 uint_fast64_t cur_time; 431 cur_time = mhd_monotonic_msec_counter (); 432 433 if (!finish_time_set) 434 { 435 finish_time = cur_time + max_wait_millisec; 436 wait_left = max_wait_millisec; 437 } 438 else 439 { 440 wait_left = finish_time - cur_time; 441 if ((wait_left > cur_time - finish_time) 442 || (0 == wait_left)) 443 return MHD_SC_UPGRADED_NET_TIMEOUT; 444 } 445 } 446 else 447 wait_left = MHD_WAIT_INDEFINITELY; /* Mute compiler warning */ 448 449 #if defined(MHD_SUPPORT_POLL) 450 if (1) 451 { 452 struct pollfd fds[1]; 453 int poll_wait; 454 int poll_res; 455 int wait_err; 456 457 if (wait_indefinitely) 458 poll_wait = -1; 459 else 460 { 461 poll_wait = (int)wait_left; 462 if ((wait_left != (uint_fast64_t)poll_wait) 463 || (0 > poll_wait)) 464 poll_wait = INT_MAX; 465 } 466 fds[0].fd = socket_fd; 467 fds[0].events = POLLOUT; 468 469 poll_res = mhd_poll (fds, 470 1, 471 poll_wait); 472 if (0 < poll_res) 473 continue; 474 if (0 == poll_res) 475 { 476 if (wait_indefinitely 477 || (INT_MAX == poll_wait)) 478 continue; 479 if (0 != *sent_size) 480 return MHD_SC_OK; 481 return MHD_SC_UPGRADED_NET_TIMEOUT; 482 } 483 484 mhd_assert (0 > poll_res); 485 wait_err = mhd_SCKT_GET_LERR (); 486 if (!mhd_SCKT_ERR_IS_EAGAIN (wait_err) 487 && !mhd_SCKT_ERR_IS_EINTR (wait_err) 488 && !mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err)) 489 return MHD_SC_UPGRADED_NET_HARD_ERROR; 490 } 491 #else /* ! MHD_SUPPORT_POLL */ 492 # if defined(MHD_SUPPORT_SELECT) 493 # ifdef MHD_SOCKETS_KIND_POSIX 494 use_select = (socket_fd < FD_SETSIZE); 495 # else /* MHD_SOCKETS_KIND_WINSOCK */ 496 use_select = true; 497 # endif /* MHD_SOCKETS_KIND_WINSOCK */ 498 if (use_select) 499 { 500 fd_set wfds; 501 int sel_res; 502 int wait_err; 503 struct timeval tmvl; 504 bool max_wait; 505 506 max_wait = false; 507 if (wait_indefinitely) 508 { 509 tmvl.tv_sec = 0; 510 tmvl.tv_usec = 0; 511 } 512 else 513 { 514 # ifdef HAVE_TIME_T 515 tmvl.tv_sec = (time_t)(max_wait_millisec / 1000); 516 # else /* ! HAVE_TIME_T */ 517 tmvl.tv_sec = (long)(max_wait_millisec / 1000); 518 # endif /* ! HAVE_TIME_T */ 519 if ((max_wait_millisec / 1000 != (uint_fast64_t)tmvl.tv_sec) 520 || ((0 >= tmvl.tv_sec) && (0 != tmvl.tv_sec))) /* Avoid signed/unsigned warnings */ 521 { 522 /* Do not bother figuring out the real maximum 'time_t' value. 523 '0x7FFFFFFF' is large enough to be already unrealistic and should 524 fit most of signed or unsigned time_t types. */ 525 tmvl.tv_sec = 0x7FFFFFFF; 526 tmvl.tv_usec = 0; 527 max_wait = true; 528 } 529 else 530 { 531 # ifdef HAVE_SUSECONDS_T 532 tmvl.tv_usec = (suseconds_t)((max_wait_millisec % 1000) * 1000); 533 # else /* ! HAVE_SUSECONDS_T */ 534 tmvl.tv_usec = (long)((max_wait_millisec % 1000) * 1000); 535 # endif /* ! HAVE_SUSECONDS_T */ 536 } 537 } 538 FD_ZERO (&wfds); 539 FD_SET (socket_fd, &wfds); 540 541 sel_res = select ((int)(c->sk.fd + 1), 542 NULL, 543 &wfds, 544 NULL, 545 wait_indefinitely ? NULL : &tmvl); 546 547 if (0 < sel_res) 548 continue; 549 if (0 == sel_res) 550 { 551 if (wait_indefinitely 552 || max_wait) 553 continue; 554 if (0 != *sent_size) 555 return MHD_SC_OK; 556 return MHD_SC_UPGRADED_NET_TIMEOUT; 557 } 558 559 mhd_assert (0 > sel_res); 560 wait_err = mhd_SCKT_GET_LERR (); 561 if (!mhd_SCKT_ERR_IS_EAGAIN (wait_err) 562 && !mhd_SCKT_ERR_IS_EINTR (wait_err) 563 && !mhd_SCKT_ERR_IS_LOW_RESOURCES (wait_err)) 564 return MHD_SC_UPGRADED_NET_HARD_ERROR; 565 } 566 else /* combined with the next 'if()' */ 567 # endif /* MHD_SUPPORT_SELECT */ 568 if (1) 569 { 570 # ifndef mhd_HAVE_MHD_SLEEP 571 return MHD_SC_UPGRADED_WAITING_NOT_SUPPORTED; 572 # else /* mhd_HAVE_MHD_SLEEP */ 573 uint_fast32_t wait_millisec = (uint_fast32_t)wait_left; 574 575 if ((wait_millisec != wait_left) 576 || (wait_millisec > 100)) 577 wait_millisec = 100; 578 mhd_sleep (wait_millisec); 579 # endif /* mhd_HAVE_MHD_SLEEP */ 580 } 581 #endif /* ! MHD_SUPPORT_POLL */ 582 } 583 584 return MHD_SC_OK; 585 }