mhd_send.c (58285B)
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) 2017-2025 Karlson2k (Evgeny Grin), Full re-write of buffering 5 and pushing, many bugs fixes, optimisations, 6 sendfile() porting 7 Copyright (C) 2019 ng0 <ng0@n0.is>, Initial version of send() wrappers 8 9 GNU libmicrohttpd is free software; you can redistribute it and/or 10 modify it under the terms of the GNU Lesser General Public 11 License as published by the Free Software Foundation; either 12 version 2.1 of the License, or (at your option) any later version. 13 14 GNU libmicrohttpd is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 Lesser General Public License for more details. 18 19 Alternatively, you can redistribute GNU libmicrohttpd and/or 20 modify it under the terms of the GNU General Public License as 21 published by the Free Software Foundation; either version 2 of 22 the License, or (at your option) any later version, together 23 with the eCos exception, as follows: 24 25 As a special exception, if other files instantiate templates or 26 use macros or inline functions from this file, or you compile this 27 file and link it with other works to produce a work based on this 28 file, this file does not by itself cause the resulting work to be 29 covered by the GNU General Public License. However the source code 30 for this file must still be made available in accordance with 31 section (3) of the GNU General Public License v2. 32 33 This exception does not invalidate any other reasons why a work 34 based on this file might be covered by the GNU General Public 35 License. 36 37 You should have received copies of the GNU Lesser General Public 38 License and the GNU General Public License along with this library; 39 if not, see <https://www.gnu.org/licenses/>. 40 */ 41 42 /** 43 * @file src/mhd2/mhd_send.c 44 * @brief Implementation of send() wrappers and helper functions. 45 * @author Karlson2k (Evgeny Grin) 46 * @author ng0 (N. Gillmann) 47 * @author Christian Grothoff 48 */ 49 50 /* Worth considering for future improvements and additions: 51 * NetBSD has no sendfile or sendfile64. The way to work 52 * with this seems to be to mmap the file and write(2) as 53 * large a chunk as possible to the socket. Alternatively, 54 * use madvise(..., MADV_SEQUENTIAL). */ 55 56 #include "mhd_sys_options.h" 57 58 #include <string.h> 59 60 #include "sys_sockets_headers.h" 61 #include "sys_ip_headers.h" 62 #include "mhd_sockets_macros.h" 63 #include "daemon_logger.h" 64 #include "mhd_socket_error_funcs.h" 65 66 #include "mhd_daemon.h" 67 #include "mhd_connection.h" 68 #include "mhd_response.h" 69 70 #include "mhd_iovec.h" 71 #ifdef HAVE_LINUX_SENDFILE 72 # include <sys/sendfile.h> 73 #endif /* HAVE_LINUX_SENDFILE */ 74 75 #if defined(HAVE_FREEBSD_SENDFILE) || defined(HAVE_DARWIN_SENDFILE) 76 # include <sys/types.h> 77 # include <sys/socket.h> 78 # include <sys/uio.h> 79 #endif /* HAVE_FREEBSD_SENDFILE || HAVE_DARWIN_SENDFILE */ 80 #ifdef HAVE_SYS_PARAM_H 81 /* For FreeBSD version identification */ 82 # include <sys/param.h> 83 #endif /* HAVE_SYS_PARAM_H */ 84 #ifdef HAVE_SYSCONF 85 # include <unistd.h> 86 #endif /* HAVE_SYSCONF */ 87 #include "mhd_assert.h" 88 89 #include "mhd_limits.h" 90 91 #ifdef MHD_SUPPORT_HTTPS 92 # include "mhd_tls_funcs.h" 93 #endif 94 95 #include "sckt_send.h" 96 #include "mhd_send.h" 97 98 #if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV) || \ 99 defined(MHD_SOCKETS_KIND_WINSOCK) 100 # define mhd_USE_VECT_SEND 1 101 #endif /* HAVE_SENDMSG || HAVE_WRITEV || MHD_SOCKETS_KIND_WINSOCK */ 102 103 104 #ifdef mhd_USE_VECT_SEND 105 # if (!defined(HAVE_SENDMSG) || !defined(HAVE_DCLR_MSG_NOSIGNAL)) && \ 106 defined(mhd_SEND_SPIPE_SUPPRESS_POSSIBLE) && \ 107 defined(mhd_SEND_SPIPE_SUPPRESS_NEEDED) 108 # define mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED 1 109 # endif /* (!HAVE_SENDMSG || !HAVE_DCLR_MSG_NOSIGNAL) && 110 mhd_SEND_SPIPE_SUPPRESS_POSSIBLE && mhd_SEND_SPIPE_SUPPRESS_NEEDED */ 111 #endif /* mhd_USE_VECT_SEND */ 112 113 /** 114 * sendfile() chuck size 115 */ 116 #define mhd_SENFILE_CHUNK_SIZE (0x20000) 117 118 /** 119 * sendfile() chuck size for thread-per-connection 120 */ 121 #define mhd_SENFILE_CHUNK_SIZE_FOR_THR_P_C (0x200000) 122 123 #if defined(HAVE_FREEBSD_SENDFILE) && defined(SF_FLAGS) 124 /** 125 * FreeBSD sendfile() flags 126 */ 127 static int freebsd_sendfile_flags_; 128 129 /** 130 * FreeBSD sendfile() flags for thread-per-connection 131 */ 132 static int freebsd_sendfile_flags_thd_p_c_; 133 134 135 /** 136 * Initialises variables for FreeBSD's sendfile() 137 */ 138 static void 139 freebsd_sendfile_init_ (void) 140 { 141 long sys_page_size = sysconf (_SC_PAGESIZE); 142 if (0 >= sys_page_size) 143 { /* Failed to get page size. */ 144 freebsd_sendfile_flags_ = SF_NODISKIO; 145 freebsd_sendfile_flags_thd_p_c_ = SF_NODISKIO; 146 } 147 else 148 { 149 freebsd_sendfile_flags_ = 150 SF_FLAGS ((uint_least16_t) \ 151 ((mhd_SENFILE_CHUNK_SIZE + sys_page_size - 1) / sys_page_size) \ 152 & 0xFFFFU, SF_NODISKIO); 153 freebsd_sendfile_flags_thd_p_c_ = 154 SF_FLAGS ((uint_least16_t) \ 155 ((mhd_SENFILE_CHUNK_SIZE_FOR_THR_P_C + sys_page_size - 1) \ 156 / sys_page_size) & 0xFFFFU, SF_NODISKIO); 157 } 158 } 159 160 161 #else /* ! HAVE_FREEBSD_SENDFILE || ! SF_FLAGS */ 162 # define freebsd_sendfile_init_() (void) 0 163 #endif /* HAVE_FREEBSD_SENDFILE */ 164 165 166 #if defined(HAVE_SYSCONF) && defined(_SC_IOV_MAX) 167 /** 168 * Current IOV_MAX system value 169 */ 170 static unsigned long mhd_iov_max_ = 0; 171 172 static void 173 iov_max_init_ (void) 174 { 175 long res = sysconf (_SC_IOV_MAX); 176 if (res >= 0) 177 mhd_iov_max_ = (unsigned long)res; 178 else 179 { 180 # if defined(IOV_MAX) 181 mhd_iov_max_ = IOV_MAX; 182 # else /* ! IOV_MAX */ 183 mhd_iov_max_ = 8; /* Should be the safe limit */ 184 # endif /* ! IOV_MAX */ 185 } 186 } 187 188 189 /** 190 * IOV_MAX (run-time) value 191 */ 192 # define mhd_IOV_MAX mhd_iov_max_ 193 #else /* ! HAVE_SYSCONF || ! _SC_IOV_MAX */ 194 # define iov_max_init_() ((void) 0) 195 # if defined(IOV_MAX) 196 197 /** 198 * IOV_MAX (static) value 199 */ 200 # define mhd_IOV_MAX IOV_MAX 201 # endif /* IOV_MAX */ 202 #endif /* ! HAVE_SYSCONF || ! _SC_IOV_MAX */ 203 204 205 void 206 mhd_send_init_once (void) 207 { 208 /* FreeBSD 11 and later allow to specify read-ahead size 209 * and handles SF_NODISKIO differently. 210 * SF_FLAGS defined only on FreeBSD 11 and later. */ 211 freebsd_sendfile_init_ (); 212 213 iov_max_init_ (); 214 } 215 216 217 /** 218 * Set required TCP_NODELAY state for connection socket 219 * 220 * The function automatically updates sk.nodelay state. 221 * @param sk the socket data 222 * @param nodelay_state the requested new state of socket 223 * @return true if succeed, false if failed or not supported 224 * by the current platform / kernel. 225 */ 226 static MHD_FN_PAR_NONNULL_ALL_ bool 227 mhd_connection_set_nodelay_state (struct mhd_ConnSocket *restrict sk, 228 bool nodelay_state) 229 { 230 #ifdef HAVE_DCLR_TCP_NODELAY 231 static const mhd_SCKT_OPT_BOOL off_val = 0; 232 static const mhd_SCKT_OPT_BOOL on_val = 1; 233 int err_code; 234 235 if (mhd_T_IS_YES (sk->props.is_nonip)) 236 return false; 237 238 # ifndef mhd_NODELAY_SET_PUSH_DATA_ALWAYS 239 mhd_assert ((!nodelay_state) || (mhd_T_IS_NOT_YES (sk->state.nodelay))); 240 # endif /* mhd_NODELAY_SET_PUSH_DATA_ALWAYS */ 241 mhd_assert ((nodelay_state) || (mhd_T_IS_NOT_NO (sk->state.nodelay))); 242 243 if (0 == mhd_setsockopt (sk->fd, 244 IPPROTO_TCP, 245 TCP_NODELAY, 246 (const void *)(nodelay_state ? &on_val : &off_val), 247 sizeof (off_val))) 248 { 249 sk->state.nodelay = nodelay_state ? mhd_T_YES : mhd_T_NO; 250 return true; 251 } 252 253 err_code = mhd_SCKT_GET_LERR (); 254 if ((mhd_T_IS_NOT_YES (sk->props.is_nonip)) 255 && (mhd_SCKT_ERR_IS_EINVAL (err_code) 256 || mhd_SCKT_ERR_IS_NOPROTOOPT (err_code) 257 || mhd_SCKT_ERR_IS_NOTSOCK (err_code))) 258 { 259 sk->props.is_nonip = mhd_T_YES; 260 } 261 # if 0 /* No messages, avoid potential message flood in the log */ 262 else 263 { 264 mhd_LOG_MSG (connection->daemon, MHD_SC_SOCKET_TCP_NODELAY_FAILED, \ 265 "Failed to set required TCP_NODELAY option for the socket."); 266 } 267 # endif /* No messages */ 268 #else /* ! TCP_NODELAY */ 269 (void)nodelay_state; /* Mute compiler warnings */ 270 sk->state.nodelay = mhd_T_NO; 271 #endif /* ! TCP_NODELAY */ 272 return false; 273 } 274 275 276 /** 277 * Set required cork state for connection socket 278 * 279 * The function automatically updates sk.corked state. 280 * 281 * @param sk the socket data 282 * @param cork_state the requested new state of socket 283 * @return true if succeed, false if failed or not supported 284 * by the current platform / kernel. 285 */ 286 static MHD_FN_PAR_NONNULL_ALL_ bool 287 mhd_connection_set_cork_state (struct mhd_ConnSocket *restrict sk, 288 bool cork_state) 289 { 290 #if defined(mhd_TCP_CORK_NOPUSH) 291 static const mhd_SCKT_OPT_BOOL off_val = 0; 292 static const mhd_SCKT_OPT_BOOL on_val = 1; 293 int err_code; 294 295 if (mhd_T_IS_YES (sk->props.is_nonip)) 296 return false; 297 298 mhd_assert ((!cork_state) || (mhd_T_IS_NOT_YES (sk->state.corked))); 299 # ifndef mhd_CORK_RESET_PUSH_DATA_ALWAYS 300 mhd_assert ((cork_state) || (mhd_T_IS_NOT_NO (sk->state.corked))); 301 # endif /* mhd_CORK_RESET_PUSH_DATA_ALWAYS */ 302 303 if (0 == mhd_setsockopt (sk->fd, 304 IPPROTO_TCP, 305 mhd_TCP_CORK_NOPUSH, 306 (const void *)(cork_state ? &on_val : &off_val), 307 sizeof (off_val))) 308 { 309 sk->state.corked = cork_state ? mhd_T_YES : mhd_T_NO; 310 return true; 311 } 312 313 err_code = mhd_SCKT_GET_LERR (); 314 if ((mhd_T_IS_NOT_YES (sk->props.is_nonip)) 315 && (mhd_SCKT_ERR_IS_EINVAL (err_code) 316 || mhd_SCKT_ERR_IS_NOPROTOOPT (err_code) 317 || mhd_SCKT_ERR_IS_NOTSOCK (err_code))) 318 { 319 sk->props.is_nonip = mhd_T_YES; 320 } 321 # if 0 /* No messages, avoid potential message flood in the log */ 322 else 323 { 324 # ifdef TCP_CORK 325 mhd_LOG_MSG (connection->daemon, MHD_SC_SOCKET_TCP_CORK_NOPUSH_FAILED, \ 326 "Failed to set required TCP_CORK option for the socket."); 327 # else 328 mhd_LOG_MSG (connection->daemon, MHD_SC_SOCKET_TCP_CORK_NOPUSH_FAILED, \ 329 "Failed to set required TCP_NOPUSH option for the socket."); 330 # endif 331 } 332 # endif /* No messages */ 333 334 #else /* ! mhd_TCP_CORK_NOPUSH */ 335 (void)cork_state; /* Mute compiler warnings. */ 336 sk->state.corked = mhd_T_NO; 337 #endif /* ! mhd_TCP_CORK_NOPUSH */ 338 return false; 339 } 340 341 342 /** 343 * Handle pre-send setsockopt calls. 344 * 345 * @param sk the socket data 346 * @param plain_send set to true if plain send() or sendmsg() will be called, 347 * set to false if TLS socket send(), sendfile() or 348 * writev() will be called. 349 * @param push_data whether to push data to the network from buffers after 350 * the next call of send function. 351 */ 352 static void 353 pre_send_setopt (struct mhd_ConnSocket *restrict sk, 354 bool plain_send, 355 bool push_data) 356 { 357 /* Try to buffer data if not sending the final piece. 358 * Final piece is indicated by push_data == true. */ 359 const bool buffer_data = (!push_data); 360 361 if (mhd_T_IS_YES (sk->props.is_nonip)) 362 return; 363 364 // TODO: support inheriting of TCP_NODELAY and TCP_NOPUSH from accept() 365 366 /* The goal is to minimise the total number of additional sys-calls 367 * before and after send(). 368 * The following tricky (over-)complicated algorithm typically use zero, 369 * one or two additional sys-calls (depending on OS) for each response. */ 370 371 if (buffer_data) 372 { 373 /* Need to buffer data if possible. */ 374 #ifdef mhd_USE_MSG_MORE 375 if (plain_send) 376 return; /* Data is buffered by send() with MSG_MORE flag. 377 * No need to check or change anything. */ 378 #else /* ! mhd_USE_MSG_MORE */ 379 (void)plain_send; /* Mute compiler warning. */ 380 #endif /* ! mhd_USE_MSG_MORE */ 381 382 #ifdef mhd_TCP_CORK_NOPUSH 383 if (mhd_T_IS_YES (sk->state.corked)) 384 return; /* The connection was already corked. */ 385 386 /* Prefer 'cork' over 'no delay' as the 'cork' buffers better, regardless 387 * of the number of received ACKs. */ 388 if (mhd_connection_set_cork_state (sk, true)) 389 return; /* The connection has been corked. */ 390 391 /* Failed to cork the connection. 392 * Really unlikely to happen on TCP connections. */ 393 #endif /* mhd_TCP_CORK_NOPUSH */ 394 if (mhd_T_IS_NO (sk->state.nodelay)) 395 return; /* TCP_NODELAY was not set for the socket. 396 * Nagle's algorithm will buffer some data. */ 397 398 /* Try to reset TCP_NODELAY state for the socket. 399 * Ignore possible error as no other options exist to 400 * buffer data. */ 401 mhd_connection_set_nodelay_state (sk, false); 402 /* TCP_NODELAY has been (hopefully) reset for the socket. 403 * Nagle's algorithm will buffer some data. */ 404 return; 405 } 406 407 /* Need to push data after the next send() */ 408 /* If additional sys-call is required, prefer to make it only after the send() 409 * (if possible) as this send() may consume only part of the prepared data and 410 * more send() calls will be used. */ 411 #ifdef mhd_TCP_CORK_NOPUSH 412 # ifdef mhd_CORK_RESET_PUSH_DATA 413 # ifdef mhd_CORK_RESET_PUSH_DATA_ALWAYS 414 /* Data can be pushed immediately by uncorking socket regardless of 415 * cork state before. */ 416 /* This is typical for Linux, no other kernel with 417 * such behaviour are known so far. */ 418 419 /* No need to check the current state of TCP_CORK / TCP_NOPUSH 420 * as reset of cork will push the data anyway. */ 421 return; /* Data may be pushed by resetting of 422 * TCP_CORK / TCP_NOPUSH after send() */ 423 # else /* ! mhd_CORK_RESET_PUSH_DATA_ALWAYS */ 424 /* Reset of TCP_CORK / TCP_NOPUSH will push the data 425 * only if socket is corked. */ 426 427 # ifdef mhd_NODELAY_SET_PUSH_DATA_ALWAYS 428 /* Data can be pushed immediately by setting TCP_NODELAY regardless 429 * of TCP_NODDELAY or corking state before. */ 430 431 /* Dead code currently, no known kernels with such behaviour and without 432 * pushing by uncorking. */ 433 return; /* Data may be pushed by setting of TCP_NODELAY after send(). 434 No need to make extra sys-calls before send().*/ 435 # else /* ! mhd_NODELAY_SET_PUSH_DATA_ALWAYS */ 436 437 /* These next comment blocks are just generic description for the possible 438 * choices for the code below. */ 439 # ifdef mhd_NODELAY_SET_PUSH_DATA 440 /* Setting of TCP_NODELAY will push the data only if 441 * both TCP_NODELAY and TCP_CORK / TCP_NOPUSH were not set. */ 442 443 /* Data can be pushed immediately by uncorking socket if 444 * socket was corked before or by setting TCP_NODELAY if 445 * socket was not corked and TCP_NODELAY was not set before. */ 446 447 /* This combination not possible currently as Linux is the only kernel that 448 * pushes data by setting of TCP_NODELAY and Linux pushes data always 449 * by TCP_NODELAY, regardless previous TCP_NODELAY state. */ 450 # else /* ! mhd_NODELAY_SET_PUSH_DATA */ 451 /* Data can be pushed immediately by uncorking socket or 452 * can be pushed by send() on uncorked socket if 453 * TCP_NODELAY was set *before*. */ 454 455 /* This is typical modern FreeBSD and OpenBSD behaviour. */ 456 # endif /* ! mhd_NODELAY_SET_PUSH_DATA */ 457 458 if (mhd_T_IS_YES (sk->state.corked)) 459 return; /* Socket is corked. Data can be pushed by resetting of 460 * TCP_CORK / TCP_NOPUSH after send() */ 461 else if (mhd_T_IS_NO (sk->state.corked)) 462 { 463 /* The socket is not corked. */ 464 if (mhd_T_IS_YES (sk->state.nodelay)) 465 return; /* TCP_NODELAY was already set, 466 * data will be pushed automatically by the next send() */ 467 # ifdef mhd_NODELAY_SET_PUSH_DATA 468 else if (mhd_T_IS_MAYBE (sk->state.nodelay)) 469 { 470 /* Setting TCP_NODELAY may push data NOW. 471 * Cork socket here and uncork after send(). */ 472 if (mhd_connection_set_cork_state (sk, true)) 473 return; /* The connection has been corked. 474 * Data can be pushed by resetting of 475 * TCP_CORK / TCP_NOPUSH after send() */ 476 else 477 { 478 /* The socket cannot be corked. 479 * Really unlikely to happen on TCP connections */ 480 /* Have to set TCP_NODELAY. 481 * If TCP_NODELAY real system state was OFF then 482 * already buffered data may be pushed NOW, but it is unlikely 483 * to happen as this is only a backup solution when corking has failed. 484 * Ignore possible error here as no other options exist to 485 * push data. */ 486 mhd_connection_set_nodelay_state (sk, true); 487 /* TCP_NODELAY has been (hopefully) set for the socket. 488 * The data will be pushed by the next send(). */ 489 return; 490 } 491 } 492 # endif /* mhd_NODELAY_SET_PUSH_DATA */ 493 else 494 { 495 # ifdef mhd_NODELAY_SET_PUSH_DATA 496 /* The socket is not corked and TCP_NODELAY is switched off. */ 497 # else /* ! mhd_NODELAY_SET_PUSH_DATA */ 498 /* The socket is not corked and TCP_NODELAY is not set or unknown. */ 499 # endif /* ! mhd_NODELAY_SET_PUSH_DATA */ 500 501 /* At least one additional sys-call before send() is required. */ 502 /* Setting TCP_NODELAY is optimal here as data will be pushed 503 * automatically by the next send() and no additional 504 * sys-call are needed after the send(). */ 505 if (mhd_connection_set_nodelay_state (sk, true)) 506 return; 507 else 508 { 509 /* Failed to set TCP_NODELAY for the socket. 510 * Really unlikely to happen on TCP connections. */ 511 /* Cork the socket here and make additional sys-call 512 * to uncork the socket after send(). This will push the data. */ 513 /* Ignore possible error here as no other options exist to 514 * push data. */ 515 mhd_connection_set_cork_state (sk, true); 516 /* The connection has been (hopefully) corked. 517 * Data can be pushed by resetting of TCP_CORK / TCP_NOPUSH 518 * after send() */ 519 return; 520 } 521 } 522 } 523 /* Corked state is unknown. Need to make a sys-call here otherwise 524 * data may not be pushed. */ 525 if (mhd_connection_set_cork_state (sk, true)) 526 return; /* The connection has been corked. 527 * Data can be pushed by resetting of 528 * TCP_CORK / TCP_NOPUSH after send() */ 529 /* The socket cannot be corked. 530 * Really unlikely to happen on TCP connections */ 531 if (mhd_T_IS_YES (sk->state.nodelay)) 532 return; /* TCP_NODELAY was already set, 533 * data will be pushed by the next send() */ 534 535 /* Have to set TCP_NODELAY. */ 536 # ifdef mhd_NODELAY_SET_PUSH_DATA 537 /* If TCP_NODELAY state was unknown (external connection) then 538 * already buffered data may be pushed here, but this is unlikely 539 * to happen as it is only a backup solution when corking has failed. */ 540 # endif /* mhd_NODELAY_SET_PUSH_DATA */ 541 /* Ignore possible error here as no other options exist to 542 * push data. */ 543 mhd_connection_set_nodelay_state (sk, true); 544 /* TCP_NODELAY has been (hopefully) set for the socket. 545 * The data will be pushed by the next send(). */ 546 return; 547 # endif /* ! mhd_NODELAY_SET_PUSH_DATA_ALWAYS */ 548 # endif /* ! mhd_CORK_RESET_PUSH_DATA_ALWAYS */ 549 # else /* ! mhd_CORK_RESET_PUSH_DATA */ 550 551 # ifndef mhd_NODELAY_SET_PUSH_DATA 552 /* Neither uncorking the socket or setting TCP_NODELAY 553 * push the data immediately. */ 554 /* The only way to push the data is to use send() on uncorked 555 * socket with TCP_NODELAY switched on . */ 556 557 /* This is old FreeBSD and Darwin behaviour. */ 558 559 /* Uncork socket if socket wasn't uncorked. */ 560 if (mhd_T_IS_NOT_NO (sk->state.corked)) 561 mhd_connection_set_cork_state (sk, false); 562 563 /* Set TCP_NODELAY if it wasn't set. */ 564 if (mhd_T_IS_NOT_YES (sk->state.nodelay)) 565 mhd_connection_set_nodelay_state (sk, true); 566 567 return; 568 # else /* mhd_NODELAY_SET_PUSH_DATA */ 569 /* Setting TCP_NODELAY push the data immediately. */ 570 571 /* Dead code currently as Linux kernel is only kernel which push by 572 * setting TCP_NODELAY. The same kernel push data by resetting TCP_CORK. */ 573 # ifdef mhd_NODELAY_SET_PUSH_DATA_ALWAYS 574 return; /* Data may be pushed by setting of TCP_NODELAY after send(). 575 No need to make extra sys-calls before send().*/ 576 # else /* ! mhd_NODELAY_SET_PUSH_DATA_ALWAYS */ 577 /* Cannot set TCP_NODELAY here as it would push data NOW. 578 * Set TCP_NODELAY after the send(), together if uncorking if necessary. */ 579 # endif /* ! mhd_NODELAY_SET_PUSH_DATA_ALWAYS */ 580 # endif /* mhd_NODELAY_SET_PUSH_DATA */ 581 # endif /* ! mhd_CORK_RESET_PUSH_DATA */ 582 #else /* ! mhd_TCP_CORK_NOPUSH */ 583 /* Buffering of data is controlled only by 584 * Nagel's algorithm. */ 585 /* Set TCP_NODELAY if it wasn't set. */ 586 if (mhd_T_IS_NOT_YES (sk->state.nodelay)) 587 mhd_connection_set_nodelay_state (sk, true); 588 #endif /* ! mhd_TCP_CORK_NOPUSH */ 589 } 590 591 592 #ifndef mhd_CORK_RESET_PUSH_DATA_ALWAYS 593 /** 594 * Send zero-sized data 595 * 596 * This function use send of zero-sized data to kick data from the socket 597 * buffers to the network. The socket must not be corked and must have 598 * TCP_NODELAY switched on. 599 * Used only as last resort option, when other options are failed due to 600 * some errors. 601 * Should not be called on typical data processing. 602 * @return true if succeed, false if failed 603 */ 604 static bool 605 zero_send (struct mhd_ConnSocket *restrict sk) 606 { 607 static const int dummy = 0; 608 609 if (mhd_T_IS_YES (sk->props.is_nonip)) 610 return false; 611 mhd_assert (mhd_T_IS_NO (sk->state.corked)); 612 mhd_assert (mhd_T_IS_YES (sk->state.nodelay)); 613 if (0 == mhd_sys_send (sk->fd, &dummy, 0)) 614 return true; 615 # if 0 /* No messages, avoid potential message flood in the log */ 616 mhd_LOG_MSG (connection->daemon, MHD_SC_SOCKET_ZERO_SEND_FAILED, \ 617 "Failed to push the data by zero-sized send."); 618 # endif /* No messages */ 619 return false; 620 } 621 622 623 #endif /* ! mhd_CORK_RESET_PUSH_DATA_ALWAYS */ 624 625 /** 626 * Handle post-send setsockopt calls. 627 * 628 * @param sk the socket data 629 * @param plain_send_next set to true if plain send() or sendmsg() will be 630 * called next, 631 * set to false if TLS socket send(), sendfile() or 632 * writev() will be called next. 633 * @param push_data whether to push data to the network from buffers 634 */ 635 static void 636 post_send_setopt (struct mhd_ConnSocket *restrict sk, 637 bool plain_send_next, 638 bool push_data) 639 { 640 /* Try to buffer data if not sending the final piece. 641 * Final piece is indicated by push_data == true. */ 642 const bool buffer_data = (!push_data); 643 644 if (mhd_T_IS_YES (sk->props.is_nonip)) 645 return; 646 if (buffer_data) 647 return; /* Nothing to do after the send(). */ 648 649 #ifndef mhd_USE_MSG_MORE 650 (void)plain_send_next; /* Mute compiler warning */ 651 #endif /* ! mhd_USE_MSG_MORE */ 652 653 /* Need to push data. */ 654 #ifdef mhd_TCP_CORK_NOPUSH 655 if (mhd_T_IS_YES (sk->state.nodelay) \ 656 && mhd_T_IS_NO (sk->state.corked)) 657 return; /* Data has been already pushed by last send(). */ 658 659 # ifdef mhd_CORK_RESET_PUSH_DATA_ALWAYS 660 # ifdef mhd_NODELAY_SET_PUSH_DATA_ALWAYS 661 # ifdef mhd_USE_MSG_MORE 662 /* This is Linux kernel. 663 * The socket is corked (or unknown) or 'no delay' is not set (or unknown). 664 * There are options: 665 * * Push the data by setting of TCP_NODELAY (without change 666 * of the cork on the socket), 667 * * Push the data by resetting of TCP_CORK. 668 * The optimal choice depends on the next final send functions 669 * used on the same socket. 670 * 671 * In general on Linux kernel TCP_NODELAY always enabled is preferred, 672 * as buffering is controlled by MSG_MORE or cork/uncork. 673 * 674 * If next send function will not support MSG_MORE (like sendfile() 675 * or TLS-connection) than push data by setting TCP_NODELAY 676 * so the socket may remain corked (no additional sys-call before 677 * next send()). 678 * 679 * If send()/sendmsg() will be used next than push data by 680 * resetting of TCP_CORK so next final send without MSG_MORE will push 681 * data to the network (without additional sys-call to push data). */ 682 683 if (mhd_T_IS_NOT_YES (sk->state.nodelay) 684 || (!plain_send_next)) 685 { 686 if (mhd_connection_set_nodelay_state (sk, true)) 687 return; /* Data has been pushed by TCP_NODELAY. */ 688 /* Failed to set TCP_NODELAY for the socket. 689 * Really unlikely to happen on TCP connections. */ 690 if (mhd_connection_set_cork_state (sk, false)) 691 return; /* Data has been pushed by uncorking the socket. */ 692 /* Failed to uncork the socket. 693 * Really unlikely to happen on TCP connections. */ 694 695 /* The socket cannot be uncorked, no way to push data */ 696 } 697 else 698 { 699 if (mhd_connection_set_cork_state (sk, false)) 700 return; /* Data has been pushed by uncorking the socket. */ 701 /* Failed to uncork the socket. 702 * Really unlikely to happen on TCP connections. */ 703 if (mhd_connection_set_nodelay_state (sk, true)) 704 return; /* Data has been pushed by TCP_NODELAY. */ 705 /* Failed to set TCP_NODELAY for the socket. 706 * Really unlikely to happen on TCP connections. */ 707 708 /* The socket cannot be uncorked, no way to push data */ 709 } 710 # else /* ! mhd_USE_MSG_MORE */ 711 /* Push data by setting TCP_NODELAY here as uncorking here 712 * would require corking the socket before sending the next response. */ 713 if (mhd_connection_set_nodelay_state (sk, true)) 714 return; /* Data was pushed by TCP_NODELAY. */ 715 /* Failed to set TCP_NODELAY for the socket. 716 * Really unlikely to happen on TCP connections. */ 717 if (mhd_connection_set_cork_state (sk, false)) 718 return; /* Data was pushed by uncorking the socket. */ 719 /* Failed to uncork the socket. 720 * Really unlikely to happen on TCP connections. */ 721 722 /* The socket remains corked, no way to push data */ 723 # endif /* ! mhd_USE_MSG_MORE */ 724 # else /* ! mhd_NODELAY_SET_PUSH_DATA_ALWAYS */ 725 if (mhd_connection_set_cork_state (sk, false)) 726 return; /* Data was pushed by uncorking the socket. */ 727 /* Failed to uncork the socket. 728 * Really unlikely to happen on TCP connections. */ 729 730 /* Socket remains corked, no way to push data */ 731 # endif /* ! mhd_NODELAY_SET_PUSH_DATA_ALWAYS */ 732 # else /* ! mhd_CORK_RESET_PUSH_DATA_ALWAYS */ 733 /* This is old FreeBSD or Darwin kernel. */ 734 735 if (mhd_T_IS_NO (sk->state.corked)) 736 { 737 mhd_assert (mhd_T_IS_NOT_YES (sk->state.nodelay)); 738 739 /* Unlikely to reach this code. 740 * TCP_NODELAY should be turned on before send(). */ 741 if (mhd_connection_set_nodelay_state (sk, true)) 742 { 743 /* TCP_NODELAY has been set on uncorked socket. 744 * Use zero-send to push the data. */ 745 if (zero_send (sk)) 746 return; /* The data has been pushed by zero-send. */ 747 } 748 749 /* Failed to push the data by all means. */ 750 /* There is nothing left to try. */ 751 } 752 else 753 { 754 # ifdef mhd_CORK_RESET_PUSH_DATA 755 enum mhd_Tristate old_cork_state = sk->state.corked; 756 # endif /* mhd_CORK_RESET_PUSH_DATA */ 757 /* The socket is corked or cork state is unknown. */ 758 759 if (mhd_connection_set_cork_state (sk, false)) 760 { 761 # ifdef mhd_CORK_RESET_PUSH_DATA 762 /* Modern FreeBSD or OpenBSD kernel */ 763 if (mhd_T_IS_YES (old_cork_state)) 764 return; /* Data has been pushed by uncorking the socket. */ 765 # endif /* mhd_CORK_RESET_PUSH_DATA */ 766 767 /* Unlikely to reach this code. 768 * The data should be pushed by uncorking (FreeBSD) or 769 * the socket should be uncorked before send(). */ 770 if (mhd_T_IS_YES (sk->state.nodelay) 771 || (mhd_connection_set_nodelay_state (sk, true))) 772 { 773 /* TCP_NODELAY is turned ON on uncorked socket. 774 * Use zero-send to push the data. */ 775 if (zero_send (sk)) 776 return; /* The data has been pushed by zero-send. */ 777 } 778 } 779 /* Data cannot be pushed. */ 780 } 781 # endif /* ! mhd_CORK_RESET_PUSH_DATA_ALWAYS */ 782 #else /* ! mhd_TCP_CORK_NOPUSH */ 783 /* Corking is not supported. Buffering is controlled 784 * by TCP_NODELAY only. */ 785 mhd_assert (mhd_T_IS_NOT_YES (sk->state.corked)); 786 if (mhd_T_IS_YES (sk->state.nodelay)) 787 return; /* Data was already pushed by send(). */ 788 789 /* Unlikely to reach this code. 790 * TCP_NODELAY should be turned on before send(). */ 791 if (mhd_connection_set_nodelay_state (sk, true)) 792 { 793 /* TCP_NODELAY has been set. 794 * Use zero-send to try to push the data. */ 795 if (zero_send (sk)) 796 return; /* The data has been pushed by zero-send. */ 797 } 798 799 /* Failed to push the data. */ 800 #endif /* ! mhd_TCP_CORK_NOPUSH */ 801 802 #if 0 /* No messages, avoid potential message flood in the log */ 803 mhd_LOG_MSG (connection->daemon, MHD_SC_SOCKET_FLUSH_LAST_PART_FAILED, \ 804 "Failed to force flush the last part of the response header " \ 805 "or the response content that might have been buffered by " \ 806 "the kernel. The client may experience some delay (usually " \ 807 "in range 200ms - 5 sec)."); 808 #endif /* No messages */ 809 return; 810 } 811 812 813 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 814 MHD_FN_PAR_IN_SIZE_ (3, 2) 815 MHD_FN_PAR_OUT_ (5) enum mhd_SocketError 816 mhd_sckt_send (struct mhd_ConnSocket *restrict sk, 817 size_t buf_size, 818 const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)], 819 bool push_data, 820 size_t *restrict sent) 821 { 822 /* plaintext transmission */ 823 ssize_t res; 824 bool full_buf_sent; 825 826 if (buf_size > MHD_SCKT_SEND_MAX_SIZE_) 827 { 828 buf_size = MHD_SCKT_SEND_MAX_SIZE_; /* send() return value limit */ 829 push_data = false; /* Incomplete send */ 830 } 831 832 pre_send_setopt (sk, true, push_data); 833 #ifdef mhd_USE_MSG_MORE 834 res = mhd_sys_send4 (sk->fd, 835 buf, 836 buf_size, 837 push_data ? 0 : MSG_MORE); 838 #else 839 res = mhd_sys_send4 (sk->fd, 840 buf, 841 buf_size, 842 0); 843 #endif 844 845 if (0 >= res) 846 { 847 enum mhd_SocketError err; 848 849 err = mhd_socket_error_get_from_sys_err (mhd_SCKT_GET_LERR ()); 850 851 if (mhd_SOCKET_ERR_AGAIN == err) 852 mhd_SCKT_NET_ST_CLEAR_FLAG (&(sk->ready), 853 mhd_SOCKET_NET_STATE_SEND_READY); 854 855 return err; 856 } 857 *sent = (size_t)res; 858 859 full_buf_sent = (buf_size == (size_t)res); 860 861 if (!full_buf_sent || !sk->props.is_nonblck) 862 mhd_SCKT_NET_ST_CLEAR_FLAG (&(sk->ready), 863 mhd_SOCKET_NET_STATE_SEND_READY); 864 865 /* If there is a need to push the data from network buffers 866 * call post_send_setopt(). */ 867 /* It's unknown whether sendfile() (or other send function without 868 * MSG_MORE support) will be used for the next reply so assume 869 * that next sending will be the same, like this call. */ 870 if (push_data && full_buf_sent) 871 post_send_setopt (sk, true, push_data); 872 873 return mhd_SOCKET_ERR_NO_ERROR; 874 } 875 876 877 #ifdef MHD_SUPPORT_HTTPS 878 879 static MHD_FN_PAR_NONNULL_ALL_ 880 MHD_FN_PAR_IN_SIZE_ (3, 2) 881 MHD_FN_PAR_OUT_ (5) enum mhd_SocketError 882 mhd_send_tls (struct MHD_Connection *restrict c, 883 size_t buf_size, 884 const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)], 885 bool push_data, 886 size_t *restrict sent) 887 { 888 /* TLS connection */ 889 const bool custm_trnsp = mhd_tls_conn_has_cstm_tr (c->tls); 890 enum mhd_SocketError res; 891 892 mhd_assert (mhd_C_HAS_TLS (c)); 893 mhd_assert (mhd_D_HAS_TLS (c->daemon)); 894 mhd_assert (0 != buf_size); 895 896 if (!custm_trnsp) 897 pre_send_setopt (&(c->sk), false, push_data); 898 899 res = mhd_tls_conn_send (c->tls, 900 buf_size, 901 buf, 902 push_data, 903 sent); 904 905 if (mhd_SOCKET_ERR_NO_ERROR != res) 906 { 907 if (mhd_SOCKET_ERR_AGAIN == res) 908 c->sk.ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */ 909 (((unsigned int)c->sk.ready) 910 & (~(enum mhd_SocketNetState) 911 mhd_SOCKET_NET_STATE_SEND_READY)); 912 return res; 913 } 914 915 if (!c->sk.props.is_nonblck) 916 c->sk.ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */ 917 (((unsigned int)c->sk.ready) 918 & (~(enum mhd_SocketNetState) 919 mhd_SOCKET_NET_STATE_SEND_READY)); 920 921 /* If there is a need to push the data from network buffers 922 * call post_send_setopt(). */ 923 if ((!custm_trnsp) && push_data && (buf_size == *sent)) 924 post_send_setopt (&(c->sk), false, true); 925 926 return mhd_SOCKET_ERR_NO_ERROR; 927 } 928 929 930 #endif /* MHD_SUPPORT_HTTPS */ 931 932 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 933 MHD_FN_PAR_IN_SIZE_ (3, 2) 934 MHD_FN_PAR_OUT_ (5) enum mhd_SocketError 935 mhd_send_data (struct MHD_Connection *restrict connection, 936 size_t buf_size, 937 const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)], 938 bool push_data, 939 size_t *restrict sent) 940 { 941 mhd_assert (MHD_INVALID_SOCKET != connection->sk.fd); 942 mhd_assert (mhd_HTTP_STAGE_CLOSED != connection->stage); 943 944 #ifdef MHD_SUPPORT_HTTPS 945 if (mhd_C_HAS_TLS (connection)) 946 return mhd_send_tls (connection, 947 buf_size, 948 buf, 949 push_data, 950 sent); 951 #endif /* MHD_SUPPORT_HTTPS */ 952 953 return mhd_sckt_send (&(connection->sk), 954 buf_size, 955 buf, 956 push_data, 957 sent); 958 } 959 960 961 MHD_INTERNAL 962 MHD_FN_PAR_NONNULL_ (1) MHD_FN_PAR_NONNULL_ (3) 963 MHD_FN_PAR_NONNULL_IF_NONZERO_ (6, 5) 964 MHD_FN_PAR_NONNULL_ (8) MHD_FN_PAR_OUT_ (8) 965 MHD_FN_PAR_IN_SIZE_ (3, 2) MHD_FN_PAR_IN_SIZE_ (6, 5) enum mhd_SocketError 966 mhd_send_hdr_and_body (struct MHD_Connection *restrict connection, 967 size_t header_size, 968 const char *restrict header, 969 bool never_push_hdr, 970 size_t body_size, 971 const char *restrict body, 972 bool complete_response, 973 size_t *restrict sent) 974 { 975 mhd_iov_ret_type res; 976 bool send_error; 977 bool push_hdr; 978 bool push_body; 979 MHD_Socket s = connection->sk.fd; 980 #ifdef mhd_USE_VECT_SEND 981 # if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV) 982 struct iovec vector[2]; 983 # ifdef HAVE_SENDMSG 984 struct msghdr msg; 985 # endif /* HAVE_SENDMSG */ 986 # endif /* HAVE_SENDMSG || HAVE_WRITEV */ 987 # ifdef _WIN32 988 WSABUF vector[2]; 989 DWORD vec_sent; 990 # endif /* _WIN32 */ 991 bool no_vec; /* Is vector-send() disallowed? */ 992 993 no_vec = false; 994 no_vec = no_vec || (mhd_C_HAS_TLS (connection)); 995 # if (!defined(HAVE_SENDMSG) || !defined(HAVE_DCLR_MSG_NOSIGNAL)) && \ 996 defined(mhd_SEND_SPIPE_SUPPRESS_POSSIBLE) && \ 997 defined(mhd_SEND_SPIPE_SUPPRESS_NEEDED) 998 no_vec = no_vec || (!connection->daemon->sigpipe_blocked 999 && !connection->sk.props.has_spipe_supp); 1000 # endif /* (!HAVE_SENDMSG || ! HAVE_DCLR_MSG_NOSIGNAL) && 1001 mhd_SEND_SPIPE_SUPPRESS_POSSIBLE && 1002 mhd_SEND_SPIPE_SUPPRESS_NEEDED */ 1003 #endif /* mhd_USE_VECT_SEND */ 1004 1005 mhd_assert ((NULL != body) || (0 == body_size)); 1006 1007 mhd_assert (MHD_INVALID_SOCKET != s); 1008 mhd_assert (mhd_HTTP_STAGE_CLOSED != connection->stage); 1009 1010 push_body = complete_response; 1011 1012 if (!never_push_hdr) 1013 { 1014 if (!complete_response) 1015 push_hdr = true; /* Push the header as the client may react 1016 * on header alone while the body data is 1017 * being prepared. */ 1018 else 1019 { 1020 if (1400 > (header_size + body_size)) 1021 push_hdr = false; /* Do not push the header as complete 1022 * reply is already ready and the whole 1023 * reply most probably will fit into 1024 * the single IP packet. */ 1025 else 1026 push_hdr = true; /* Push header alone so client may react 1027 * on it while reply body is being delivered. */ 1028 } 1029 } 1030 else 1031 push_hdr = false; 1032 1033 if (complete_response && (0 == body_size)) 1034 push_hdr = true; /* The header alone is equal to the whole response. */ 1035 1036 #ifndef mhd_USE_VECT_SEND 1037 no_vec = (no_vec || true); 1038 #else /* mhd_USE_VECT_SEND */ 1039 no_vec = (no_vec || (0 == body_size)); 1040 no_vec = (no_vec || ((sizeof(mhd_iov_elmn_size) <= sizeof(size_t)) 1041 && (((size_t)mhd_IOV_ELMN_MAX_SIZE) < header_size))); 1042 #endif /* mhd_USE_VECT_SEND */ 1043 1044 1045 if (no_vec) 1046 { 1047 enum mhd_SocketError ret; 1048 ret = mhd_send_data (connection, 1049 header_size, 1050 header, 1051 push_hdr, 1052 sent); 1053 1054 if ((mhd_SOCKET_ERR_NO_ERROR == ret) 1055 && (header_size == *sent) 1056 && (0 != body_size) 1057 && (header_size < header_size + body_size) 1058 && (connection->sk.props.is_nonblck)) 1059 { 1060 size_t sent_b; 1061 /* The header has been sent completely. 1062 * Try to send the reply body without waiting for 1063 * the next round. */ 1064 1065 ret = mhd_send_data (connection, 1066 body_size, 1067 body, 1068 push_body, 1069 &sent_b); 1070 1071 if (mhd_SOCKET_ERR_NO_ERROR == ret) 1072 *sent += sent_b; 1073 else if (mhd_SOCKET_ERR_IS_HARD (ret)) 1074 return ret; /* Unrecoverable error */ 1075 1076 return mhd_SOCKET_ERR_NO_ERROR; /* The header has been sent successfully */ 1077 } 1078 return ret; 1079 } 1080 #ifdef mhd_USE_VECT_SEND 1081 1082 mhd_assert (!mhd_C_HAS_TLS (connection)); 1083 1084 if (header_size > (header_size + body_size)) 1085 { 1086 /* Return value limit */ 1087 body_size = SIZE_MAX - header_size; 1088 complete_response = false; 1089 push_body = complete_response; 1090 } 1091 if ((((mhd_iov_ret_type)(header_size + body_size)) < 0) 1092 || (((size_t)(mhd_iov_ret_type)(header_size + body_size)) != 1093 (header_size + body_size))) 1094 { 1095 /* Send sys-call total amount limit */ 1096 body_size = mhd_IOV_RET_MAX_SIZE - header_size; 1097 complete_response = false; 1098 push_body = complete_response; 1099 } 1100 1101 pre_send_setopt (&(connection->sk), 1102 # ifdef HAVE_SENDMSG 1103 true, 1104 # else /* ! HAVE_SENDMSG */ 1105 false, 1106 # endif /* ! HAVE_SENDMSG */ 1107 push_hdr || push_body); 1108 send_error = false; 1109 # if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV) 1110 vector[0].iov_base = mhd_DROP_CONST (header); 1111 vector[0].iov_len = header_size; 1112 vector[1].iov_base = mhd_DROP_CONST (body); 1113 vector[1].iov_len = body_size; 1114 1115 # if defined(HAVE_SENDMSG) 1116 memset (&msg, 0, sizeof(msg)); 1117 msg.msg_name = NULL; 1118 msg.msg_namelen = 0; 1119 msg.msg_iov = vector; 1120 msg.msg_iovlen = 2; 1121 msg.msg_control = NULL; 1122 msg.msg_controllen = 0; 1123 msg.msg_flags = 0; 1124 1125 res = sendmsg (s, &msg, mhd_MSG_NOSIGNAL 1126 # ifdef mhd_USE_MSG_MORE 1127 | ((push_hdr || push_body) ? 0 : mhd_MSG_MORE) 1128 # endif 1129 ); 1130 # elif defined(HAVE_WRITEV) 1131 res = writev (s, vector, 2); 1132 # endif /* HAVE_WRITEV */ 1133 if (0 < res) 1134 *sent = (size_t)res; 1135 else 1136 send_error = true; 1137 # endif /* HAVE_SENDMSG || HAVE_WRITEV */ 1138 # ifdef _WIN32 1139 if (((mhd_iov_elmn_size)body_size) != body_size) 1140 { 1141 /* Send item size limit */ 1142 body_size = mhd_IOV_ELMN_MAX_SIZE; 1143 complete_response = false; 1144 push_body = complete_response; 1145 } 1146 vector[0].buf = (char *)mhd_DROP_CONST (header); 1147 vector[0].len = (unsigned long)header_size; 1148 vector[1].buf = (char *)mhd_DROP_CONST (body); 1149 vector[1].len = (unsigned long)body_size; 1150 1151 res = WSASend (s, vector, 2, &vec_sent, 0, NULL, NULL); 1152 if (0 == res) 1153 *sent = (size_t)vec_sent; 1154 else 1155 send_error = true; 1156 # endif /* _WIN32 */ 1157 1158 if (send_error) 1159 { 1160 enum mhd_SocketError err; 1161 1162 err = mhd_socket_error_get_from_sys_err (mhd_SCKT_GET_LERR ()); 1163 1164 if (mhd_SOCKET_ERR_AGAIN == err) 1165 connection->sk.ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */ 1166 (((unsigned int)connection->sk.ready) 1167 & (~(enum mhd_SocketNetState) 1168 mhd_SOCKET_NET_STATE_SEND_READY)); 1169 1170 return err; 1171 } 1172 if (((header_size + body_size) > *sent) 1173 || !connection->sk.props.is_nonblck) 1174 connection->sk.ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */ 1175 (((unsigned int)connection->sk.ready) 1176 & (~(enum mhd_SocketNetState) 1177 mhd_SOCKET_NET_STATE_SEND_READY)); 1178 1179 /* If there is a need to push the data from network buffers 1180 * call post_send_setopt(). */ 1181 if ((push_body) 1182 && ((header_size + body_size) == *sent)) 1183 { 1184 /* Complete reply has been sent. */ 1185 /* If TLS connection is used then next final send() will be 1186 * without MSG_MORE support. If non-TLS connection is used 1187 * it's unknown whether next 'send' will be plain send() / sendmsg() or 1188 * sendfile() will be used so assume that next final send() will be 1189 * the same, like for this response. */ 1190 post_send_setopt (&(connection->sk), 1191 # ifdef HAVE_SENDMSG 1192 true, /* Assume the same type of the send function */ 1193 # else /* ! HAVE_SENDMSG */ 1194 false, /* Assume the same type of the send function */ 1195 # endif /* ! HAVE_SENDMSG */ 1196 true); 1197 } 1198 else if ((push_hdr) 1199 && (header_size <= *sent)) 1200 { 1201 /* The header has been sent completely and there is a 1202 * need to push the header data. */ 1203 /* Luckily the type of send function will be used next is known. */ 1204 post_send_setopt (&(connection->sk), 1205 true, 1206 true); 1207 } 1208 1209 return mhd_SOCKET_ERR_NO_ERROR; 1210 #else /* ! mhd_USE_VECT_SEND */ 1211 mhd_assert (0 && "Should be unreachable"); 1212 return mhd_SOCKET_ERR_INTERNAL; /* Unreachable. Mute warnings. */ 1213 #endif /* ! mhd_USE_VECT_SEND */ 1214 } 1215 1216 1217 #if defined(mhd_USE_SENDFILE) 1218 1219 # if defined(HAVE_LINUX_SENDFILE) && defined(HAVE_SENDFILE64) 1220 # define mhd_off_t off64_t 1221 # else 1222 # define mhd_off_t off_t 1223 # endif 1224 1225 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 1226 MHD_FN_PAR_OUT_ (2) enum mhd_SocketError 1227 mhd_send_sendfile (struct MHD_Connection *restrict c, 1228 size_t *restrict sent) 1229 { 1230 enum mhd_SocketError ret; 1231 const bool used_thr_p_c = 1232 mhd_D_HAS_THR_PER_CONN (c->daemon); 1233 const size_t chunk_size = 1234 used_thr_p_c ? 1235 mhd_SENFILE_CHUNK_SIZE_FOR_THR_P_C : mhd_SENFILE_CHUNK_SIZE; 1236 const int file_fd = c->rp.response->cntn.file.fd; 1237 mhd_off_t offset; 1238 size_t send_size = 0; /* Initialised to mute compiler warning */ 1239 size_t sent_bytes; 1240 bool push_data; 1241 bool fallback_to_filereader; 1242 mhd_assert (mhd_REPLY_CNTN_LOC_FILE == c->rp.cntn_loc); 1243 mhd_assert (MHD_SIZE_UNKNOWN != c->rp.response->cntn_size); 1244 mhd_assert (chunk_size <= (size_t)SSIZE_MAX); 1245 mhd_assert (!mhd_C_HAS_TLS (c)); 1246 1247 mhd_assert (0 == send_size); /* Mute analyser warning */ 1248 push_data = true; 1249 if (1) 1250 { 1251 bool too_large; 1252 uint_fast64_t left; 1253 1254 offset = (mhd_off_t) 1255 (c->rp.rsp_cntn_read_pos + c->rp.response->cntn.file.offset); 1256 too_large = (((uint_fast64_t)offset) < c->rp.rsp_cntn_read_pos); 1257 too_large = too_large 1258 || (((uint_fast64_t)offset) != 1259 (c->rp.rsp_cntn_read_pos 1260 + c->rp.response->cntn.file.offset)); 1261 too_large = too_large || (0 > offset); 1262 if (too_large) 1263 { /* Retry to send with file reader and standard 'send()'. */ 1264 c->rp.response->cntn.file.use_sf = false; 1265 return mhd_SOCKET_ERR_INTR; 1266 } 1267 1268 left = c->rp.response->cntn_size - c->rp.rsp_cntn_read_pos; 1269 1270 /* Do not allow system to stick sending on single fast connection: 1271 * use 128KiB chunks (2MiB for thread-per-connection). */ 1272 if (chunk_size < left) /* This also limit to SSIZE_MAX automatically */ 1273 { 1274 send_size = chunk_size; 1275 push_data = false; /* No need to push data, there is more to send. */ 1276 } 1277 else 1278 send_size = (size_t)left; 1279 } 1280 mhd_assert (0 != send_size); 1281 1282 pre_send_setopt (&(c->sk), false, push_data); 1283 1284 sent_bytes = 0; 1285 ret = mhd_SOCKET_ERR_NO_ERROR; 1286 fallback_to_filereader = false; 1287 # if defined(HAVE_LINUX_SENDFILE) 1288 if (1) 1289 { 1290 ssize_t res; 1291 # ifndef HAVE_SENDFILE64 1292 ret = sendfile (c->sk.fd, 1293 file_fd, 1294 &offset, 1295 send_size); 1296 # else /* HAVE_SENDFILE64 */ 1297 res = sendfile64 (c->sk.fd, 1298 file_fd, 1299 &offset, 1300 send_size); 1301 # endif /* HAVE_SENDFILE64 */ 1302 if (0 > res) 1303 { 1304 const int sk_err = mhd_SCKT_GET_LERR (); 1305 1306 if ((EINVAL == sk_err) 1307 || (EOVERFLOW == sk_err) || 1308 # ifdef EIO 1309 (EIO == sk_err) || 1310 # endif 1311 # ifdef EAFNOSUPPORT 1312 (EAFNOSUPPORT == sk_err) || 1313 # endif 1314 (EOPNOTSUPP == sk_err)) 1315 fallback_to_filereader = true; 1316 else 1317 ret = mhd_socket_error_get_from_sys_err (sk_err); 1318 } 1319 else 1320 sent_bytes = (size_t)res; 1321 } 1322 # elif defined(HAVE_FREEBSD_SENDFILE) 1323 if (1) 1324 { 1325 off_t sent_bytes_offt = 0; 1326 int flags = 0; 1327 bool sent_something = false; 1328 # ifdef SF_FLAGS 1329 flags = used_thr_p_c ? 1330 freebsd_sendfile_flags_thd_p_c_ : freebsd_sendfile_flags_; 1331 # endif /* SF_FLAGS */ 1332 if (0 != sendfile (file_fd, 1333 c->sk.fd, 1334 offset, 1335 send_size, 1336 NULL, 1337 &sent_bytes_offt, 1338 flags)) 1339 { 1340 const int sk_err = mhd_SCKT_GET_LERR (); 1341 1342 sent_something = 1343 (((EAGAIN == sk_err) || (EBUSY == sk_err) || (EINTR == sk_err)) 1344 && (0 != sent_bytes_offt)); 1345 1346 if (!sent_something) 1347 { 1348 enum mhd_SocketError err; 1349 if ((EINVAL == sk_err) 1350 || (EIO == sk_err) 1351 || (EOPNOTSUPP == sk_err)) 1352 fallback_to_filereader = true; 1353 else 1354 ret = mhd_socket_error_get_from_sys_err (sk_err); 1355 } 1356 } 1357 else 1358 sent_something = true; 1359 1360 if (sent_something) 1361 { 1362 mhd_assert (0 <= sent_bytes_offt); 1363 mhd_assert (SIZE_MAX >= sent_bytes_offt); 1364 sent_bytes = (size_t)sent_bytes_offt; 1365 } 1366 } 1367 # elif defined(HAVE_DARWIN_SENDFILE) 1368 if (1) 1369 { 1370 off_t len; 1371 bool sent_something; 1372 1373 sent_something = false; 1374 len = (off_t)send_size; /* chunk always fit */ 1375 1376 if (0 != sendfile (file_fd, 1377 c->sk.fd, 1378 offset, 1379 &len, 1380 NULL, 1381 0)) 1382 { 1383 const int sk_err = mhd_SCKT_GET_LERR (); 1384 1385 sent_something = 1386 ((EAGAIN == sk_err) || (EINTR == sk_err)) 1387 && (0 != len); 1388 1389 if (!sent_something) 1390 { 1391 if ((ENOTSUP == sk_err) 1392 || (EOPNOTSUPP == sk_err)) 1393 fallback_to_filereader = true; 1394 else 1395 ret = mhd_socket_error_get_from_sys_err (sk_err); 1396 } 1397 } 1398 else 1399 sent_something = true; 1400 1401 if (sent_something) 1402 { 1403 mhd_assert (0 <= len); 1404 mhd_assert (SIZE_MAX >= len); 1405 sent_bytes = (size_t)len; 1406 } 1407 } 1408 # else 1409 # error No sendfile() function 1410 # endif 1411 1412 mhd_assert (send_size >= sent_bytes); 1413 1414 /* Some platforms indicate "beyond of the end of the file" by returning 1415 * success with zero bytes. Let filereader to re-detect this kind of error. */ 1416 if ((fallback_to_filereader) 1417 || ((mhd_SOCKET_ERR_NO_ERROR == ret) && (0 == sent_bytes))) 1418 { /* Retry to send with file reader and standard 'send()'. */ 1419 c->rp.response->cntn.file.use_sf = false; 1420 return mhd_SOCKET_ERR_INTR; 1421 } 1422 1423 if ((mhd_SOCKET_ERR_AGAIN == ret) || !c->sk.props.is_nonblck 1424 || ((mhd_SOCKET_ERR_NO_ERROR == ret) && (send_size > sent_bytes))) 1425 c->sk.ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */ 1426 (((unsigned int)c->sk.ready) 1427 & (~(enum mhd_SocketNetState) 1428 mhd_SOCKET_NET_STATE_SEND_READY)); 1429 1430 if (mhd_SOCKET_ERR_NO_ERROR != ret) 1431 return ret; 1432 1433 /* If there is a need to push the data from network buffers 1434 * call post_send_setopt(). */ 1435 /* It's unknown whether sendfile() will be used in the next 1436 * response so assume that next response will be the same. */ 1437 if ((push_data) 1438 && (send_size == sent_bytes)) 1439 post_send_setopt (&(c->sk), true, push_data); 1440 1441 *sent = sent_bytes; 1442 return ret; 1443 } 1444 1445 1446 #endif /* mhd_USE_SENDFILE */ 1447 1448 #if defined(mhd_USE_VECT_SEND) 1449 1450 1451 /** 1452 * Function sends iov data by system sendmsg or writev function. 1453 * 1454 * Connection must be in non-TLS (non-HTTPS) mode. 1455 * 1456 * @param connection the MHD connection structure 1457 * @param r_iov the pointer to iov data structure with tracking 1458 * @param push_data set to true to force push the data to the network from 1459 * system buffers (usually set for the last piece of data), 1460 * set to false to prefer holding incomplete network packets 1461 * (more data will be send for the same reply). 1462 * @param[out] sent the pointer to get amount of actually sent bytes 1463 * @return mhd_SOCKET_ERR_NO_ERROR if send succeed (the @a sent gets 1464 * the sent size) or socket error 1465 */ 1466 static MHD_FN_PAR_NONNULL_ALL_ 1467 MHD_FN_PAR_OUT_ (4) enum mhd_SocketError 1468 send_iov_nontls (struct MHD_Connection *restrict connection, 1469 struct mhd_iovec_track *const restrict r_iov, 1470 bool push_data, 1471 size_t *restrict sent) 1472 { 1473 bool send_error; 1474 size_t items_to_send; 1475 # ifndef MHD_SOCKETS_KIND_WINSOCK 1476 ssize_t res; 1477 # endif 1478 # ifdef HAVE_SENDMSG 1479 struct msghdr msg; 1480 # elif defined(MHD_SOCKETS_KIND_WINSOCK) 1481 DWORD bytes_sent; 1482 DWORD cnt_w; 1483 # endif /* MHD_SOCKETS_KIND_WINSOCK */ 1484 1485 mhd_assert (!mhd_C_HAS_TLS (connection)); 1486 mhd_assert (!mhd_D_HAS_TLS (connection->daemon)); 1487 1488 mhd_assert (MHD_INVALID_SOCKET != connection->sk.fd); 1489 mhd_assert (mhd_HTTP_STAGE_CLOSED != connection->stage); 1490 1491 send_error = false; 1492 items_to_send = r_iov->cnt - r_iov->sent; 1493 # ifdef mhd_IOV_MAX 1494 if (mhd_IOV_MAX < items_to_send) 1495 { 1496 mhd_assert (0 < mhd_IOV_MAX); 1497 if (0 == mhd_IOV_MAX) 1498 return mhd_SOCKET_ERR_INTERNAL; /* Should never happen */ 1499 items_to_send = mhd_IOV_MAX; 1500 push_data = false; /* Incomplete response */ 1501 } 1502 # endif /* mhd_IOV_MAX */ 1503 # ifdef HAVE_SENDMSG 1504 memset (&msg, 0, sizeof(struct msghdr)); 1505 msg.msg_name = NULL; 1506 msg.msg_namelen = 0; 1507 msg.msg_iov = r_iov->iov + r_iov->sent; 1508 msg.msg_iovlen = items_to_send; 1509 msg.msg_control = NULL; 1510 msg.msg_controllen = 0; 1511 msg.msg_flags = 0; 1512 1513 pre_send_setopt (&(connection->sk), true, push_data); 1514 res = sendmsg (connection->sk.fd, &msg, 1515 mhd_MSG_NOSIGNAL 1516 # ifdef mhd_USE_MSG_MORE 1517 | (push_data ? 0 : MSG_MORE) 1518 # endif 1519 ); 1520 if (0 < res) 1521 *sent = (size_t)res; 1522 else 1523 send_error = true; 1524 # elif defined(HAVE_WRITEV) 1525 pre_send_setopt (&(connection->sk), false, push_data); 1526 res = writev (connection->sk.fd, r_iov->iov + r_iov->sent, 1527 items_to_send); 1528 if (0 < res) 1529 *sent = (size_t)res; 1530 else 1531 send_error = true; 1532 # elif defined(MHD_SOCKETS_KIND_WINSOCK) 1533 # ifdef _WIN64 1534 if (items_to_send > ULONG_MAX) 1535 { 1536 cnt_w = ULONG_MAX; 1537 push_data = false; /* Incomplete response */ 1538 } 1539 else 1540 cnt_w = (DWORD)items_to_send; 1541 # else /* ! _WIN64 */ 1542 cnt_w = (DWORD)items_to_send; 1543 # endif /* ! _WIN64 */ 1544 pre_send_setopt (&(connection->sk), true, push_data); 1545 if (0 == WSASend (connection->sk.fd, 1546 (LPWSABUF)(r_iov->iov + r_iov->sent), 1547 cnt_w, 1548 &bytes_sent, 0, NULL, NULL)) 1549 *sent = (size_t)bytes_sent; 1550 else 1551 send_error = true; 1552 # else /* !HAVE_SENDMSG && !HAVE_WRITEV && !MHD_SOCKETS_KIND_WINSOCK */ 1553 # error No vector-send function available 1554 # endif 1555 1556 if (send_error) 1557 { 1558 enum mhd_SocketError err; 1559 1560 err = mhd_socket_error_get_from_sys_err (mhd_SCKT_GET_LERR ()); 1561 1562 if (mhd_SOCKET_ERR_AGAIN == err) 1563 connection->sk.ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */ 1564 (((unsigned int)connection->sk.ready) 1565 & (~(enum mhd_SocketNetState) 1566 mhd_SOCKET_NET_STATE_SEND_READY)); 1567 1568 return err; 1569 } 1570 1571 /* Some data has been sent */ 1572 if (1) 1573 { 1574 size_t track_sent = (size_t)*sent; 1575 1576 if (!connection->sk.props.is_nonblck) 1577 connection->sk.ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */ 1578 (((unsigned int)connection->sk.ready) 1579 & (~(enum mhd_SocketNetState) 1580 mhd_SOCKET_NET_STATE_SEND_READY)); 1581 1582 /* Adjust the internal tracking information for the iovec to 1583 * take this last send into account. */ 1584 while ((0 != track_sent) && (r_iov->iov[r_iov->sent].iov_len <= track_sent)) 1585 { 1586 track_sent -= r_iov->iov[r_iov->sent].iov_len; 1587 r_iov->sent++; /* The iov element has been completely sent */ 1588 mhd_assert ((r_iov->cnt > r_iov->sent) || (0 == track_sent)); 1589 } 1590 1591 if (r_iov->cnt == r_iov->sent) 1592 post_send_setopt (&(connection->sk), true, push_data); 1593 else 1594 { 1595 connection->sk.ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */ 1596 (((unsigned int)connection->sk.ready) 1597 & (~(enum mhd_SocketNetState) 1598 mhd_SOCKET_NET_STATE_SEND_READY)); 1599 if (0 != track_sent) 1600 { 1601 mhd_assert (r_iov->cnt > r_iov->sent); 1602 /* The last iov element has been partially sent */ 1603 r_iov->iov[r_iov->sent].iov_base = 1604 (mhd_IOV_ELMN_PTR_TYPE) 1605 (((uint8_t *)r_iov->iov[r_iov->sent].iov_base) 1606 + track_sent); 1607 r_iov->iov[r_iov->sent].iov_len -= (mhd_iov_elmn_size)track_sent; 1608 } 1609 } 1610 } 1611 1612 return mhd_SOCKET_ERR_NO_ERROR; 1613 } 1614 1615 1616 #endif /* mhd_USE_VECT_SEND */ 1617 1618 #if !defined(mhd_USE_VECT_SEND) || defined(MHD_SUPPORT_HTTPS) || \ 1619 defined(mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED) 1620 1621 1622 /** 1623 * Function sends iov data by sending buffers one-by-one by standard 1624 * data send function. 1625 * 1626 * Connection could be in HTTPS or non-HTTPS mode. 1627 * 1628 * @param connection the MHD connection structure 1629 * @param r_iov the pointer to iov data structure with tracking 1630 * @param push_data set to true to force push the data to the network from 1631 * system buffers (usually set for the last piece of data), 1632 * set to false to prefer holding incomplete network packets 1633 * (more data will be send for the same reply). 1634 * @param[out] sent the pointer to get amount of actually sent bytes 1635 * @return mhd_SOCKET_ERR_NO_ERROR if send succeed (the @a sent gets 1636 * the sent size) or socket error 1637 */ 1638 static MHD_FN_PAR_NONNULL_ALL_ 1639 MHD_FN_PAR_OUT_ (4) enum mhd_SocketError 1640 send_iov_emu (struct MHD_Connection *restrict connection, 1641 struct mhd_iovec_track *const restrict r_iov, 1642 bool push_data, 1643 size_t *restrict sent) 1644 { 1645 const bool non_blk = connection->sk.props.is_nonblck; 1646 size_t total_sent; 1647 size_t max_elelements_to_sent; 1648 1649 mhd_assert (NULL != r_iov->iov); 1650 total_sent = 0; 1651 max_elelements_to_sent = 8; /* Do not make too many sys-calls for just one connection */ 1652 do 1653 { 1654 enum mhd_SocketError res; 1655 size_t sent_el_size; 1656 1657 if (total_sent > (size_t)(r_iov->iov[r_iov->sent].iov_len + total_sent)) 1658 break; /* return value would overflow */ 1659 1660 res = mhd_send_data (connection, 1661 r_iov->iov[r_iov->sent].iov_len, 1662 (const char *)r_iov->iov[r_iov->sent].iov_base, 1663 push_data && (r_iov->cnt == r_iov->sent + 1), 1664 &sent_el_size); 1665 if (mhd_SOCKET_ERR_NO_ERROR == res) 1666 { 1667 /* Result is an error */ 1668 if (0 == total_sent) 1669 return res; /* Nothing was sent, return error as is */ 1670 1671 if (mhd_SOCKET_ERR_IS_HARD (res)) 1672 return res; /* Any kind of a hard error */ 1673 1674 break; /* Return the amount of the sent data */ 1675 } 1676 1677 total_sent += sent_el_size; 1678 1679 if (r_iov->iov[r_iov->sent].iov_len != sent_el_size) 1680 { 1681 /* Incomplete buffer has been sent. 1682 * Adjust buffer of the last element. */ 1683 r_iov->iov[r_iov->sent].iov_base = 1684 (mhd_IOV_ELMN_PTR_TYPE) 1685 (((uint8_t *)r_iov->iov[r_iov->sent].iov_base) + sent_el_size); 1686 r_iov->iov[r_iov->sent].iov_len -= (mhd_iov_elmn_size)sent_el_size; 1687 1688 break; /* Return the amount of the sent data */ 1689 } 1690 /* The iov element has been completely sent */ 1691 r_iov->sent++; 1692 } while ((r_iov->cnt > r_iov->sent) && 0 != (--max_elelements_to_sent) 1693 && (non_blk)); 1694 1695 mhd_assert (0 != total_sent); 1696 *sent = total_sent; 1697 return mhd_SOCKET_ERR_NO_ERROR; 1698 } 1699 1700 1701 #endif /* !mhd_USE_VECT_SEND || MHD_SUPPORT_HTTPS 1702 || mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */ 1703 1704 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 1705 MHD_FN_PAR_OUT_ (4) enum mhd_SocketError 1706 mhd_send_iovec (struct MHD_Connection *restrict connection, 1707 struct mhd_iovec_track *const restrict r_iov, 1708 bool push_data, 1709 size_t *restrict sent) 1710 { 1711 #ifdef mhd_USE_VECT_SEND 1712 # if defined(MHD_SUPPORT_HTTPS) || \ 1713 defined(mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED) 1714 bool use_iov_send = true; 1715 # endif /* MHD_SUPPORT_HTTPS || mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */ 1716 #endif /* mhd_USE_VECT_SEND */ 1717 1718 mhd_assert (NULL != connection->rp.resp_iov.iov); 1719 mhd_assert (mhd_RESPONSE_CONTENT_DATA_IOVEC == \ 1720 connection->rp.response->cntn_dtype); 1721 mhd_assert (connection->rp.resp_iov.cnt > connection->rp.resp_iov.sent); 1722 #ifdef mhd_USE_VECT_SEND 1723 # if defined(MHD_SUPPORT_HTTPS) || \ 1724 defined(mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED) 1725 use_iov_send = use_iov_send 1726 && (!mhd_C_HAS_TLS (connection)); 1727 # ifdef mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED 1728 use_iov_send = use_iov_send && (connection->daemon->sigpipe_blocked 1729 || connection->sk.props.has_spipe_supp); 1730 # endif /* mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */ 1731 if (use_iov_send) 1732 # endif /* MHD_SUPPORT_HTTPS || mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */ 1733 return send_iov_nontls (connection, r_iov, push_data, sent); 1734 #endif /* mhd_USE_VECT_SEND */ 1735 1736 #if !defined(mhd_USE_VECT_SEND) || defined(MHD_SUPPORT_HTTPS) || \ 1737 defined(mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED) 1738 return send_iov_emu (connection, r_iov, push_data, sent); 1739 #endif /* !mhd_USE_VECT_SEND || MHD_SUPPORT_HTTPS 1740 || mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */ 1741 }