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