mhd_send.c (58016B)
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_IN_SIZE_ (3,2) MHD_FN_PAR_IN_SIZE_ (6,5) enum mhd_SocketError 964 mhd_send_hdr_and_body (struct MHD_Connection *restrict connection, 965 size_t header_size, 966 const char *restrict header, 967 bool never_push_hdr, 968 size_t body_size, 969 const char *restrict body, 970 bool complete_response, 971 size_t *restrict sent) 972 { 973 mhd_iov_ret_type res; 974 bool send_error; 975 bool push_hdr; 976 bool push_body; 977 MHD_Socket s = connection->sk.fd; 978 #ifdef mhd_USE_VECT_SEND 979 #if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV) 980 struct iovec vector[2]; 981 #ifdef HAVE_SENDMSG 982 struct msghdr msg; 983 #endif /* HAVE_SENDMSG */ 984 #endif /* HAVE_SENDMSG || HAVE_WRITEV */ 985 #ifdef _WIN32 986 WSABUF vector[2]; 987 DWORD vec_sent; 988 #endif /* _WIN32 */ 989 bool no_vec; /* Is vector-send() disallowed? */ 990 991 no_vec = false; 992 no_vec = no_vec || (mhd_C_HAS_TLS (connection)); 993 #if (! defined(HAVE_SENDMSG) || ! defined(HAVE_DCLR_MSG_NOSIGNAL) ) && \ 994 defined(mhd_SEND_SPIPE_SUPPRESS_POSSIBLE) && \ 995 defined(mhd_SEND_SPIPE_SUPPRESS_NEEDED) 996 no_vec = no_vec || (! connection->daemon->sigpipe_blocked && 997 ! connection->sk.props.has_spipe_supp); 998 #endif /* (!HAVE_SENDMSG || ! HAVE_DCLR_MSG_NOSIGNAL) && 999 mhd_SEND_SPIPE_SUPPRESS_POSSIBLE && 1000 mhd_SEND_SPIPE_SUPPRESS_NEEDED */ 1001 #endif /* mhd_USE_VECT_SEND */ 1002 1003 mhd_assert ( (NULL != body) || (0 == body_size) ); 1004 1005 mhd_assert (MHD_INVALID_SOCKET != s); 1006 mhd_assert (mhd_HTTP_STAGE_CLOSED != connection->stage); 1007 1008 push_body = complete_response; 1009 1010 if (! never_push_hdr) 1011 { 1012 if (! complete_response) 1013 push_hdr = true; /* Push the header as the client may react 1014 * on header alone while the body data is 1015 * being prepared. */ 1016 else 1017 { 1018 if (1400 > (header_size + body_size)) 1019 push_hdr = false; /* Do not push the header as complete 1020 * reply is already ready and the whole 1021 * reply most probably will fit into 1022 * the single IP packet. */ 1023 else 1024 push_hdr = true; /* Push header alone so client may react 1025 * on it while reply body is being delivered. */ 1026 } 1027 } 1028 else 1029 push_hdr = false; 1030 1031 if (complete_response && (0 == body_size)) 1032 push_hdr = true; /* The header alone is equal to the whole response. */ 1033 1034 #ifndef mhd_USE_VECT_SEND 1035 no_vec = (no_vec || true); 1036 #else /* mhd_USE_VECT_SEND */ 1037 no_vec = (no_vec || (0 == body_size)); 1038 no_vec = (no_vec || ((sizeof(mhd_iov_elmn_size) <= sizeof(size_t)) && 1039 (((size_t) mhd_IOV_ELMN_MAX_SIZE) < header_size))); 1040 #endif /* mhd_USE_VECT_SEND */ 1041 1042 1043 if (no_vec) 1044 { 1045 enum mhd_SocketError ret; 1046 ret = mhd_send_data (connection, 1047 header_size, 1048 header, 1049 push_hdr, 1050 sent); 1051 1052 if ((mhd_SOCKET_ERR_NO_ERROR == ret) && 1053 (header_size == *sent) && 1054 (0 != body_size) && 1055 (header_size < header_size + body_size) && 1056 (connection->sk.props.is_nonblck)) 1057 { 1058 size_t sent_b; 1059 /* The header has been sent completely. 1060 * Try to send the reply body without waiting for 1061 * the next round. */ 1062 1063 ret = mhd_send_data (connection, 1064 body_size, 1065 body, 1066 push_body, 1067 &sent_b); 1068 1069 if (mhd_SOCKET_ERR_NO_ERROR == ret) 1070 *sent += sent_b; 1071 else if (mhd_SOCKET_ERR_IS_HARD (ret)) 1072 return ret; /* Unrecoverable error */ 1073 1074 return mhd_SOCKET_ERR_NO_ERROR; /* The header has been sent successfully */ 1075 } 1076 return ret; 1077 } 1078 #ifdef mhd_USE_VECT_SEND 1079 1080 mhd_assert (! mhd_C_HAS_TLS (connection)); 1081 1082 if (header_size > (header_size + body_size)) 1083 { 1084 /* Return value limit */ 1085 body_size = SIZE_MAX - header_size; 1086 complete_response = false; 1087 push_body = complete_response; 1088 } 1089 if (((mhd_iov_ret_type) (header_size + body_size)) < 0 || 1090 ((size_t) (mhd_iov_ret_type) (header_size + body_size)) != 1091 (header_size + body_size)) 1092 { 1093 /* Send sys-call total amount limit */ 1094 body_size = mhd_IOV_RET_MAX_SIZE - header_size; 1095 complete_response = false; 1096 push_body = complete_response; 1097 } 1098 1099 pre_send_setopt (&(connection->sk), 1100 #ifdef HAVE_SENDMSG 1101 true, 1102 #else /* ! HAVE_SENDMSG */ 1103 false, 1104 #endif /* ! HAVE_SENDMSG */ 1105 push_hdr || push_body); 1106 send_error = false; 1107 #if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV) 1108 vector[0].iov_base = mhd_DROP_CONST (header); 1109 vector[0].iov_len = header_size; 1110 vector[1].iov_base = mhd_DROP_CONST (body); 1111 vector[1].iov_len = body_size; 1112 1113 #if defined(HAVE_SENDMSG) 1114 memset (&msg, 0, sizeof(msg)); 1115 msg.msg_name = NULL; 1116 msg.msg_namelen = 0; 1117 msg.msg_iov = vector; 1118 msg.msg_iovlen = 2; 1119 msg.msg_control = NULL; 1120 msg.msg_controllen = 0; 1121 msg.msg_flags = 0; 1122 1123 res = sendmsg (s, &msg, mhd_MSG_NOSIGNAL 1124 # ifdef mhd_USE_MSG_MORE 1125 | ((push_hdr || push_body) ? 0 : mhd_MSG_MORE) 1126 # endif 1127 ); 1128 #elif defined(HAVE_WRITEV) 1129 res = writev (s, vector, 2); 1130 #endif /* HAVE_WRITEV */ 1131 if (0 < res) 1132 *sent = (size_t) res; 1133 else 1134 send_error = true; 1135 #endif /* HAVE_SENDMSG || HAVE_WRITEV */ 1136 #ifdef _WIN32 1137 if (((mhd_iov_elmn_size) body_size) != body_size) 1138 { 1139 /* Send item size limit */ 1140 body_size = mhd_IOV_ELMN_MAX_SIZE; 1141 complete_response = false; 1142 push_body = complete_response; 1143 } 1144 vector[0].buf = (char *) mhd_DROP_CONST (header); 1145 vector[0].len = (unsigned long) header_size; 1146 vector[1].buf = (char *) mhd_DROP_CONST (body); 1147 vector[1].len = (unsigned long) body_size; 1148 1149 res = WSASend (s, vector, 2, &vec_sent, 0, NULL, NULL); 1150 if (0 == res) 1151 *sent = (size_t) vec_sent; 1152 else 1153 send_error = true; 1154 #endif /* _WIN32 */ 1155 1156 if (send_error) 1157 { 1158 enum mhd_SocketError err; 1159 1160 err = mhd_socket_error_get_from_sys_err (mhd_SCKT_GET_LERR ()); 1161 1162 if (mhd_SOCKET_ERR_AGAIN == err) 1163 connection->sk.ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */ 1164 (((unsigned int) connection->sk.ready) 1165 & (~(enum mhd_SocketNetState) 1166 mhd_SOCKET_NET_STATE_SEND_READY)); 1167 1168 return err; 1169 } 1170 if (((header_size + body_size) > *sent) 1171 || ! connection->sk.props.is_nonblck) 1172 connection->sk.ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */ 1173 (((unsigned int) connection->sk.ready) 1174 & (~(enum mhd_SocketNetState) 1175 mhd_SOCKET_NET_STATE_SEND_READY)); 1176 1177 /* If there is a need to push the data from network buffers 1178 * call post_send_setopt(). */ 1179 if ( (push_body) && 1180 ((header_size + body_size) == *sent) ) 1181 { 1182 /* Complete reply has been sent. */ 1183 /* If TLS connection is used then next final send() will be 1184 * without MSG_MORE support. If non-TLS connection is used 1185 * it's unknown whether next 'send' will be plain send() / sendmsg() or 1186 * sendfile() will be used so assume that next final send() will be 1187 * the same, like for this response. */ 1188 post_send_setopt (&(connection->sk), 1189 #ifdef HAVE_SENDMSG 1190 true, /* Assume the same type of the send function */ 1191 #else /* ! HAVE_SENDMSG */ 1192 false, /* Assume the same type of the send function */ 1193 #endif /* ! HAVE_SENDMSG */ 1194 true); 1195 } 1196 else if ( (push_hdr) && 1197 (header_size <= *sent)) 1198 { 1199 /* The header has been sent completely and there is a 1200 * need to push the header data. */ 1201 /* Luckily the type of send function will be used next is known. */ 1202 post_send_setopt (&(connection->sk), 1203 true, 1204 true); 1205 } 1206 1207 return mhd_SOCKET_ERR_NO_ERROR; 1208 #else /* ! mhd_USE_VECT_SEND */ 1209 mhd_assert (0 && "Should be unreachable"); 1210 return mhd_SOCKET_ERR_INTERNAL; /* Unreachable. Mute warnings. */ 1211 #endif /* ! mhd_USE_VECT_SEND */ 1212 } 1213 1214 1215 #if defined(mhd_USE_SENDFILE) 1216 1217 #if defined(HAVE_LINUX_SENDFILE) && defined(HAVE_SENDFILE64) 1218 # define mhd_off_t off64_t 1219 #else 1220 # define mhd_off_t off_t 1221 #endif 1222 1223 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 1224 MHD_FN_PAR_OUT_ (2) enum mhd_SocketError 1225 mhd_send_sendfile (struct MHD_Connection *restrict c, 1226 size_t *restrict sent) 1227 { 1228 enum mhd_SocketError ret; 1229 const bool used_thr_p_c = 1230 mhd_D_HAS_THR_PER_CONN (c->daemon); 1231 const size_t chunk_size = 1232 used_thr_p_c ? 1233 mhd_SENFILE_CHUNK_SIZE_FOR_THR_P_C : mhd_SENFILE_CHUNK_SIZE; 1234 const int file_fd = c->rp.response->cntn.file.fd; 1235 mhd_off_t offset; 1236 size_t send_size = 0; /* Initialised to mute compiler warning */ 1237 size_t sent_bytes; 1238 bool push_data; 1239 bool fallback_to_filereader; 1240 mhd_assert (mhd_REPLY_CNTN_LOC_FILE == c->rp.cntn_loc); 1241 mhd_assert (MHD_SIZE_UNKNOWN != c->rp.response->cntn_size); 1242 mhd_assert (chunk_size <= (size_t) SSIZE_MAX); 1243 mhd_assert (! mhd_C_HAS_TLS (c)); 1244 1245 mhd_assert (0 == send_size); /* Mute analyser warning */ 1246 push_data = true; 1247 if (1) 1248 { 1249 bool too_large; 1250 uint_fast64_t left; 1251 1252 offset = (mhd_off_t) 1253 (c->rp.rsp_cntn_read_pos + c->rp.response->cntn.file.offset); 1254 too_large = (((uint_fast64_t) offset) < c->rp.rsp_cntn_read_pos); 1255 too_large = too_large || 1256 (((uint_fast64_t) offset) != 1257 (c->rp.rsp_cntn_read_pos + c->rp.response->cntn.file.offset)); 1258 too_large = too_large || (0 > offset); 1259 if (too_large) 1260 { /* Retry to send with file reader and standard 'send()'. */ 1261 c->rp.response->cntn.file.use_sf = false; 1262 return mhd_SOCKET_ERR_INTR; 1263 } 1264 1265 left = c->rp.response->cntn_size - c->rp.rsp_cntn_read_pos; 1266 1267 /* Do not allow system to stick sending on single fast connection: 1268 * use 128KiB chunks (2MiB for thread-per-connection). */ 1269 if (chunk_size < left) /* This also limit to SSIZE_MAX automatically */ 1270 { 1271 send_size = chunk_size; 1272 push_data = false; /* No need to push data, there is more to send. */ 1273 } 1274 else 1275 send_size = (size_t) left; 1276 } 1277 mhd_assert (0 != send_size); 1278 1279 pre_send_setopt (&(c->sk), false, push_data); 1280 1281 sent_bytes = 0; 1282 ret = mhd_SOCKET_ERR_NO_ERROR; 1283 fallback_to_filereader = false; 1284 #if defined(HAVE_LINUX_SENDFILE) 1285 if (1) 1286 { 1287 ssize_t res; 1288 #ifndef HAVE_SENDFILE64 1289 ret = sendfile (c->sk.fd, 1290 file_fd, 1291 &offset, 1292 send_size); 1293 #else /* HAVE_SENDFILE64 */ 1294 res = sendfile64 (c->sk.fd, 1295 file_fd, 1296 &offset, 1297 send_size); 1298 #endif /* HAVE_SENDFILE64 */ 1299 if (0 > res) 1300 { 1301 const int sk_err = mhd_SCKT_GET_LERR (); 1302 1303 if ((EINVAL == sk_err) || 1304 (EOVERFLOW == sk_err) || 1305 #ifdef EIO 1306 (EIO == sk_err) || 1307 #endif 1308 #ifdef EAFNOSUPPORT 1309 (EAFNOSUPPORT == sk_err) || 1310 #endif 1311 (EOPNOTSUPP == sk_err)) 1312 fallback_to_filereader = true; 1313 else 1314 ret = mhd_socket_error_get_from_sys_err (sk_err); 1315 } 1316 else 1317 sent_bytes = (size_t) res; 1318 } 1319 #elif defined(HAVE_FREEBSD_SENDFILE) 1320 if (1) 1321 { 1322 off_t sent_bytes_offt = 0; 1323 int flags = 0; 1324 bool sent_something = false; 1325 #ifdef SF_FLAGS 1326 flags = used_thr_p_c ? 1327 freebsd_sendfile_flags_thd_p_c_ : freebsd_sendfile_flags_; 1328 #endif /* SF_FLAGS */ 1329 if (0 != sendfile (file_fd, 1330 c->sk.fd, 1331 offset, 1332 send_size, 1333 NULL, 1334 &sent_bytes_offt, 1335 flags)) 1336 { 1337 const int sk_err = mhd_SCKT_GET_LERR (); 1338 1339 sent_something = 1340 (((EAGAIN == sk_err) || (EBUSY == sk_err) || (EINTR == sk_err)) && 1341 (0 != sent_bytes_offt)); 1342 1343 if (! sent_something) 1344 { 1345 enum mhd_SocketError err; 1346 if ((EINVAL == sk_err) || 1347 (EIO == sk_err) || 1348 (EOPNOTSUPP == sk_err)) 1349 fallback_to_filereader = true; 1350 else 1351 ret = mhd_socket_error_get_from_sys_err (sk_err); 1352 } 1353 } 1354 else 1355 sent_something = true; 1356 1357 if (sent_something) 1358 { 1359 mhd_assert (0 <= sent_bytes_offt); 1360 mhd_assert (SIZE_MAX >= sent_bytes_offt); 1361 sent_bytes = (size_t) sent_bytes_offt; 1362 } 1363 } 1364 #elif defined(HAVE_DARWIN_SENDFILE) 1365 if (1) 1366 { 1367 off_t len; 1368 bool sent_something; 1369 1370 sent_something = false; 1371 len = (off_t) send_size; /* chunk always fit */ 1372 1373 if (0 != sendfile (file_fd, 1374 c->sk.fd, 1375 offset, 1376 &len, 1377 NULL, 1378 0)) 1379 { 1380 const int sk_err = mhd_SCKT_GET_LERR (); 1381 1382 sent_something = 1383 ((EAGAIN == sk_err) || (EINTR == sk_err)) && 1384 (0 != len); 1385 1386 if (! sent_something) 1387 { 1388 if ((ENOTSUP == sk_err) || 1389 (EOPNOTSUPP == sk_err)) 1390 fallback_to_filereader = true; 1391 else 1392 ret = mhd_socket_error_get_from_sys_err (sk_err); 1393 } 1394 } 1395 else 1396 sent_something = true; 1397 1398 if (sent_something) 1399 { 1400 mhd_assert (0 <= len); 1401 mhd_assert (SIZE_MAX >= len); 1402 sent_bytes = (size_t) len; 1403 } 1404 } 1405 #else 1406 #error No sendfile() function 1407 #endif 1408 1409 mhd_assert (send_size >= sent_bytes); 1410 1411 /* Some platforms indicate "beyond of the end of the file" by returning 1412 * success with zero bytes. Let filereader to re-detect this kind of error. */ 1413 if ((fallback_to_filereader) || 1414 ((mhd_SOCKET_ERR_NO_ERROR == ret) && (0 == sent_bytes))) 1415 { /* Retry to send with file reader and standard 'send()'. */ 1416 c->rp.response->cntn.file.use_sf = false; 1417 return mhd_SOCKET_ERR_INTR; 1418 } 1419 1420 if ((mhd_SOCKET_ERR_AGAIN == ret) || ! c->sk.props.is_nonblck || 1421 ((mhd_SOCKET_ERR_NO_ERROR == ret) && (send_size > sent_bytes))) 1422 c->sk.ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */ 1423 (((unsigned int) c->sk.ready) 1424 & (~(enum mhd_SocketNetState) 1425 mhd_SOCKET_NET_STATE_SEND_READY)); 1426 1427 if (mhd_SOCKET_ERR_NO_ERROR != ret) 1428 return ret; 1429 1430 /* If there is a need to push the data from network buffers 1431 * call post_send_setopt(). */ 1432 /* It's unknown whether sendfile() will be used in the next 1433 * response so assume that next response will be the same. */ 1434 if ((push_data) && 1435 (send_size == sent_bytes)) 1436 post_send_setopt (&(c->sk), true, push_data); 1437 1438 *sent = sent_bytes; 1439 return ret; 1440 } 1441 1442 1443 #endif /* mhd_USE_SENDFILE */ 1444 1445 #if defined(mhd_USE_VECT_SEND) 1446 1447 1448 /** 1449 * Function sends iov data by system sendmsg or writev function. 1450 * 1451 * Connection must be in non-TLS (non-HTTPS) mode. 1452 * 1453 * @param connection the MHD connection structure 1454 * @param r_iov the pointer to iov data structure with tracking 1455 * @param push_data set to true to force push the data to the network from 1456 * system buffers (usually set for the last piece of data), 1457 * set to false to prefer holding incomplete network packets 1458 * (more data will be send for the same reply). 1459 * @param[out] sent the pointer to get amount of actually sent bytes 1460 * @return mhd_SOCKET_ERR_NO_ERROR if send succeed (the @a sent gets 1461 * the sent size) or socket error 1462 */ 1463 static MHD_FN_PAR_NONNULL_ALL_ 1464 MHD_FN_PAR_OUT_ (4) enum mhd_SocketError 1465 send_iov_nontls (struct MHD_Connection *restrict connection, 1466 struct mhd_iovec_track *const restrict r_iov, 1467 bool push_data, 1468 size_t *restrict sent) 1469 { 1470 bool send_error; 1471 size_t items_to_send; 1472 #ifndef MHD_SOCKETS_KIND_WINSOCK 1473 ssize_t res; 1474 #endif 1475 #ifdef HAVE_SENDMSG 1476 struct msghdr msg; 1477 #elif defined(MHD_SOCKETS_KIND_WINSOCK) 1478 DWORD bytes_sent; 1479 DWORD cnt_w; 1480 #endif /* MHD_SOCKETS_KIND_WINSOCK */ 1481 1482 mhd_assert (! mhd_C_HAS_TLS (connection)); 1483 mhd_assert (! mhd_D_HAS_TLS (connection->daemon)); 1484 1485 mhd_assert (MHD_INVALID_SOCKET != connection->sk.fd); 1486 mhd_assert (mhd_HTTP_STAGE_CLOSED != connection->stage); 1487 1488 send_error = false; 1489 items_to_send = r_iov->cnt - r_iov->sent; 1490 #ifdef mhd_IOV_MAX 1491 if (mhd_IOV_MAX < items_to_send) 1492 { 1493 mhd_assert (0 < mhd_IOV_MAX); 1494 if (0 == mhd_IOV_MAX) 1495 return mhd_SOCKET_ERR_INTERNAL; /* Should never happen */ 1496 items_to_send = mhd_IOV_MAX; 1497 push_data = false; /* Incomplete response */ 1498 } 1499 #endif /* mhd_IOV_MAX */ 1500 #ifdef HAVE_SENDMSG 1501 memset (&msg, 0, sizeof(struct msghdr)); 1502 msg.msg_name = NULL; 1503 msg.msg_namelen = 0; 1504 msg.msg_iov = r_iov->iov + r_iov->sent; 1505 msg.msg_iovlen = items_to_send; 1506 msg.msg_control = NULL; 1507 msg.msg_controllen = 0; 1508 msg.msg_flags = 0; 1509 1510 pre_send_setopt (&(connection->sk), true, push_data); 1511 res = sendmsg (connection->sk.fd, &msg, 1512 mhd_MSG_NOSIGNAL 1513 # ifdef mhd_USE_MSG_MORE 1514 | (push_data ? 0 : MSG_MORE) 1515 # endif 1516 ); 1517 if (0 < res) 1518 *sent = (size_t) res; 1519 else 1520 send_error = true; 1521 #elif defined(HAVE_WRITEV) 1522 pre_send_setopt (&(connection->sk), false, push_data); 1523 res = writev (connection->sk.fd, r_iov->iov + r_iov->sent, 1524 items_to_send); 1525 if (0 < res) 1526 *sent = (size_t) res; 1527 else 1528 send_error = true; 1529 #elif defined(MHD_SOCKETS_KIND_WINSOCK) 1530 #ifdef _WIN64 1531 if (items_to_send > ULONG_MAX) 1532 { 1533 cnt_w = ULONG_MAX; 1534 push_data = false; /* Incomplete response */ 1535 } 1536 else 1537 cnt_w = (DWORD) items_to_send; 1538 #else /* ! _WIN64 */ 1539 cnt_w = (DWORD) items_to_send; 1540 #endif /* ! _WIN64 */ 1541 pre_send_setopt (&(connection->sk), true, push_data); 1542 if (0 == WSASend (connection->sk.fd, 1543 (LPWSABUF) (r_iov->iov + r_iov->sent), 1544 cnt_w, 1545 &bytes_sent, 0, NULL, NULL)) 1546 *sent = (size_t) bytes_sent; 1547 else 1548 send_error = true; 1549 #else /* !HAVE_SENDMSG && !HAVE_WRITEV && !MHD_SOCKETS_KIND_WINSOCK */ 1550 #error No vector-send function available 1551 #endif 1552 1553 if (send_error) 1554 { 1555 enum mhd_SocketError err; 1556 1557 err = mhd_socket_error_get_from_sys_err (mhd_SCKT_GET_LERR ()); 1558 1559 if (mhd_SOCKET_ERR_AGAIN == err) 1560 connection->sk.ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */ 1561 (((unsigned int) connection->sk.ready) 1562 & (~(enum mhd_SocketNetState) 1563 mhd_SOCKET_NET_STATE_SEND_READY)); 1564 1565 return err; 1566 } 1567 1568 /* Some data has been sent */ 1569 if (1) 1570 { 1571 size_t track_sent = (size_t) *sent; 1572 1573 if (! connection->sk.props.is_nonblck) 1574 connection->sk.ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */ 1575 (((unsigned int) connection->sk.ready) 1576 & (~(enum mhd_SocketNetState) 1577 mhd_SOCKET_NET_STATE_SEND_READY)); 1578 1579 /* Adjust the internal tracking information for the iovec to 1580 * take this last send into account. */ 1581 while ((0 != track_sent) && (r_iov->iov[r_iov->sent].iov_len <= track_sent)) 1582 { 1583 track_sent -= r_iov->iov[r_iov->sent].iov_len; 1584 r_iov->sent++; /* The iov element has been completely sent */ 1585 mhd_assert ((r_iov->cnt > r_iov->sent) || (0 == track_sent)); 1586 } 1587 1588 if (r_iov->cnt == r_iov->sent) 1589 post_send_setopt (&(connection->sk), true, push_data); 1590 else 1591 { 1592 connection->sk.ready = (enum mhd_SocketNetState) /* Clear 'send-ready' */ 1593 (((unsigned int) connection->sk.ready) 1594 & (~(enum mhd_SocketNetState) 1595 mhd_SOCKET_NET_STATE_SEND_READY)); 1596 if (0 != track_sent) 1597 { 1598 mhd_assert (r_iov->cnt > r_iov->sent); 1599 /* The last iov element has been partially sent */ 1600 r_iov->iov[r_iov->sent].iov_base = 1601 (mhd_IOV_ELMN_PTR_TYPE) 1602 (((uint8_t *) r_iov->iov[r_iov->sent].iov_base) 1603 + track_sent); 1604 r_iov->iov[r_iov->sent].iov_len -= (mhd_iov_elmn_size) track_sent; 1605 } 1606 } 1607 } 1608 1609 return mhd_SOCKET_ERR_NO_ERROR; 1610 } 1611 1612 1613 #endif /* mhd_USE_VECT_SEND */ 1614 1615 #if ! defined(mhd_USE_VECT_SEND) || defined(MHD_SUPPORT_HTTPS) || \ 1616 defined(mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED) 1617 1618 1619 /** 1620 * Function sends iov data by sending buffers one-by-one by standard 1621 * data send function. 1622 * 1623 * Connection could be in HTTPS or non-HTTPS mode. 1624 * 1625 * @param connection the MHD connection structure 1626 * @param r_iov the pointer to iov data structure with tracking 1627 * @param push_data set to true to force push the data to the network from 1628 * system buffers (usually set for the last piece of data), 1629 * set to false to prefer holding incomplete network packets 1630 * (more data will be send for the same reply). 1631 * @param[out] sent the pointer to get amount of actually sent bytes 1632 * @return mhd_SOCKET_ERR_NO_ERROR if send succeed (the @a sent gets 1633 * the sent size) or socket error 1634 */ 1635 static MHD_FN_PAR_NONNULL_ALL_ 1636 MHD_FN_PAR_OUT_ (4) enum mhd_SocketError 1637 send_iov_emu (struct MHD_Connection *restrict connection, 1638 struct mhd_iovec_track *const restrict r_iov, 1639 bool push_data, 1640 size_t *restrict sent) 1641 { 1642 const bool non_blk = connection->sk.props.is_nonblck; 1643 size_t total_sent; 1644 size_t max_elelements_to_sent; 1645 1646 mhd_assert (NULL != r_iov->iov); 1647 total_sent = 0; 1648 max_elelements_to_sent = 8; /* Do not make too many sys-calls for just one connection */ 1649 do 1650 { 1651 enum mhd_SocketError res; 1652 size_t sent_el_size; 1653 1654 if (total_sent > (size_t) (r_iov->iov[r_iov->sent].iov_len + total_sent)) 1655 break; /* return value would overflow */ 1656 1657 res = mhd_send_data (connection, 1658 r_iov->iov[r_iov->sent].iov_len, 1659 (const char *) r_iov->iov[r_iov->sent].iov_base, 1660 push_data && (r_iov->cnt == r_iov->sent + 1), 1661 &sent_el_size); 1662 if (mhd_SOCKET_ERR_NO_ERROR == res) 1663 { 1664 /* Result is an error */ 1665 if (0 == total_sent) 1666 return res; /* Nothing was sent, return error as is */ 1667 1668 if (mhd_SOCKET_ERR_IS_HARD (res)) 1669 return res; /* Any kind of a hard error */ 1670 1671 break; /* Return the amount of the sent data */ 1672 } 1673 1674 total_sent += sent_el_size; 1675 1676 if (r_iov->iov[r_iov->sent].iov_len != sent_el_size) 1677 { 1678 /* Incomplete buffer has been sent. 1679 * Adjust buffer of the last element. */ 1680 r_iov->iov[r_iov->sent].iov_base = 1681 (mhd_IOV_ELMN_PTR_TYPE) 1682 (((uint8_t *) r_iov->iov[r_iov->sent].iov_base) + sent_el_size); 1683 r_iov->iov[r_iov->sent].iov_len -= (mhd_iov_elmn_size) sent_el_size; 1684 1685 break; /* Return the amount of the sent data */ 1686 } 1687 /* The iov element has been completely sent */ 1688 r_iov->sent++; 1689 } while ((r_iov->cnt > r_iov->sent) && 0 != (--max_elelements_to_sent) && 1690 (non_blk)); 1691 1692 mhd_assert (0 != total_sent); 1693 *sent = total_sent; 1694 return mhd_SOCKET_ERR_NO_ERROR; 1695 } 1696 1697 1698 #endif /* !mhd_USE_VECT_SEND || MHD_SUPPORT_HTTPS 1699 || mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */ 1700 1701 MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ 1702 MHD_FN_PAR_OUT_ (4) enum mhd_SocketError 1703 mhd_send_iovec (struct MHD_Connection *restrict connection, 1704 struct mhd_iovec_track *const restrict r_iov, 1705 bool push_data, 1706 size_t *restrict sent) 1707 { 1708 #ifdef mhd_USE_VECT_SEND 1709 #if defined(MHD_SUPPORT_HTTPS) || \ 1710 defined(mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED) 1711 bool use_iov_send = true; 1712 #endif /* MHD_SUPPORT_HTTPS || mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */ 1713 #endif /* mhd_USE_VECT_SEND */ 1714 1715 mhd_assert (NULL != connection->rp.resp_iov.iov); 1716 mhd_assert (mhd_RESPONSE_CONTENT_DATA_IOVEC == \ 1717 connection->rp.response->cntn_dtype); 1718 mhd_assert (connection->rp.resp_iov.cnt > connection->rp.resp_iov.sent); 1719 #ifdef mhd_USE_VECT_SEND 1720 #if defined(MHD_SUPPORT_HTTPS) || \ 1721 defined(mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED) 1722 use_iov_send = use_iov_send && 1723 (! mhd_C_HAS_TLS (connection)); 1724 #ifdef mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED 1725 use_iov_send = use_iov_send && (connection->daemon->sigpipe_blocked || 1726 connection->sk.props.has_spipe_supp); 1727 #endif /* mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */ 1728 if (use_iov_send) 1729 #endif /* MHD_SUPPORT_HTTPS || mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */ 1730 return send_iov_nontls (connection, r_iov, push_data, sent); 1731 #endif /* mhd_USE_VECT_SEND */ 1732 1733 #if ! defined(mhd_USE_VECT_SEND) || defined(MHD_SUPPORT_HTTPS) || \ 1734 defined(mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED) 1735 return send_iov_emu (connection, r_iov, push_data, sent); 1736 #endif /* !mhd_USE_VECT_SEND || MHD_SUPPORT_HTTPS 1737 || mhd_VECT_SEND_NEEDS_SPIPE_SUPPRESSED */ 1738 }