test_upgrade.c (68941B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2016-2020 Christian Grothoff 4 Copyright (C) 2016-2022 Evgeny Grin (Karlson2k) 5 6 libmicrohttpd is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published 8 by the Free Software Foundation; either version 3, or (at your 9 option) any later version. 10 11 libmicrohttpd is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with libmicrohttpd; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 Boston, MA 02110-1301, USA. 20 */ 21 22 /** 23 * @file test_upgrade.c 24 * @brief Testcase for libmicrohttpd upgrading a connection 25 * @author Christian Grothoff 26 * @author Karlson2k (Evgeny Grin) 27 */ 28 29 #include "mhd_options.h" 30 #include <stddef.h> 31 #include <stdint.h> 32 #include <string.h> 33 #include <stdlib.h> 34 #include <stdio.h> 35 #include <pthread.h> 36 #include <errno.h> 37 #ifndef WINDOWS 38 #include <unistd.h> 39 #endif 40 #ifdef HAVE_STDBOOL_H 41 #include <stdbool.h> 42 #endif /* HAVE_STDBOOL_H */ 43 44 #include "mhd_sockets.h" 45 #ifdef HAVE_NETINET_IP_H 46 #include <netinet/ip.h> 47 #endif /* HAVE_NETINET_IP_H */ 48 49 #include "platform.h" 50 #include "microhttpd.h" 51 52 #include "test_helpers.h" 53 54 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this 55 test into a marked, classifiable test error (TESTING.md, P5). */ 56 #include "mhd_panic_tripwire.h" 57 58 #ifdef HTTPS_SUPPORT 59 #include <gnutls/gnutls.h> 60 #include "../testcurl/https/tls_test_keys.h" 61 62 #if defined(HAVE_FORK) && defined(HAVE_WAITPID) 63 #include <sys/types.h> 64 #include <sys/wait.h> 65 #endif /* HAVE_FORK && HAVE_WAITPID */ 66 #endif /* HTTPS_SUPPORT */ 67 68 #if defined(MHD_POSIX_SOCKETS) 69 # ifdef MHD_WINSOCK_SOCKETS 70 # error Both MHD_POSIX_SOCKETS and MHD_WINSOCK_SOCKETS are defined 71 # endif /* MHD_WINSOCK_SOCKETS */ 72 #elif ! defined(MHD_WINSOCK_SOCKETS) 73 # error Neither MHD_POSIX_SOCKETS nor MHD_WINSOCK_SOCKETS are defined 74 #endif /* MHD_WINSOCK_SOCKETS */ 75 76 77 #ifndef MHD_STATICSTR_LEN_ 78 /** 79 * Determine length of static string / macro strings at compile time. 80 */ 81 #define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1) 82 #endif /* ! MHD_STATICSTR_LEN_ */ 83 84 85 _MHD_NORETURN static void 86 _externalErrorExit_func (const char *errDesc, const char *funcName, int lineNum) 87 { 88 fflush (stdout); 89 if ((NULL != errDesc) && (0 != errDesc[0])) 90 fprintf (stderr, "%s", errDesc); 91 else 92 fprintf (stderr, "System or external library call failed"); 93 if ((NULL != funcName) && (0 != funcName[0])) 94 fprintf (stderr, " in %s", funcName); 95 if (0 < lineNum) 96 fprintf (stderr, " at line %d", lineNum); 97 98 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 99 strerror (errno)); 100 #ifdef MHD_WINSOCK_SOCKETS 101 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); 102 #endif /* MHD_WINSOCK_SOCKETS */ 103 fflush (stderr); 104 exit (99); 105 } 106 107 108 _MHD_NORETURN static void 109 _mhdErrorExit_func (const char *errDesc, const char *funcName, int lineNum) 110 { 111 fflush (stdout); 112 if ((NULL != errDesc) && (0 != errDesc[0])) 113 fprintf (stderr, "%s", errDesc); 114 else 115 fprintf (stderr, "MHD unexpected error"); 116 if ((NULL != funcName) && (0 != funcName[0])) 117 fprintf (stderr, " in %s", funcName); 118 if (0 < lineNum) 119 fprintf (stderr, " at line %d", lineNum); 120 121 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 122 strerror (errno)); 123 124 fflush (stderr); 125 exit (8); 126 } 127 128 129 static void 130 _testErrorLog_func (const char *errDesc, const char *funcName, int lineNum) 131 { 132 fflush (stdout); 133 if ((NULL != errDesc) && (0 != errDesc[0])) 134 fprintf (stderr, "%s", errDesc); 135 else 136 fprintf (stderr, "System or external library call resulted in error"); 137 if ((NULL != funcName) && (0 != funcName[0])) 138 fprintf (stderr, " in %s", funcName); 139 if (0 < lineNum) 140 fprintf (stderr, " at line %d", lineNum); 141 142 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno, 143 strerror (errno)); 144 #ifdef MHD_WINSOCK_SOCKETS 145 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); 146 #endif /* MHD_WINSOCK_SOCKETS */ 147 fflush (stderr); 148 } 149 150 151 #ifdef MHD_HAVE_MHD_FUNC_ 152 #define externalErrorExit(ignore) \ 153 _externalErrorExit_func(NULL, MHD_FUNC_, __LINE__) 154 #define externalErrorExitDesc(errDesc) \ 155 _externalErrorExit_func(errDesc, MHD_FUNC_, __LINE__) 156 #define mhdErrorExit(ignore) \ 157 _mhdErrorExit_func(NULL, MHD_FUNC_, __LINE__) 158 #define mhdErrorExitDesc(errDesc) \ 159 _mhdErrorExit_func(errDesc, MHD_FUNC_, __LINE__) 160 #define testErrorLog(ignore) \ 161 _testErrorLog_func(NULL, MHD_FUNC_, __LINE__) 162 #define testErrorLogDesc(errDesc) \ 163 _testErrorLog_func(errDesc, MHD_FUNC_, __LINE__) 164 #else /* ! MHD_HAVE_MHD_FUNC_ */ 165 #define externalErrorExit(ignore) _externalErrorExit_func(NULL, NULL, __LINE__) 166 #define externalErrorExitDesc(errDesc) \ 167 _externalErrorExit_func(errDesc, NULL, __LINE__) 168 #define mhdErrorExit(ignore) _mhdErrorExit_func(NULL, NULL, __LINE__) 169 #define mhdErrorExitDesc(errDesc) _mhdErrorExit_func(errDesc, NULL, __LINE__) 170 #define testErrorLog(ignore) _testErrorLog_func(NULL, NULL, __LINE__) 171 #define testErrorLogDesc(errDesc) _testErrorLog_func(errDesc, NULL, __LINE__) 172 #endif /* ! MHD_HAVE_MHD_FUNC_ */ 173 174 /* ** External parameters ** */ 175 static bool use_large; 176 177 static bool use_vlarge; 178 179 static bool test_tls; 180 181 static int verbose = 0; 182 183 enum tls_tool 184 { 185 TLS_CLI_NO_TOOL = 0, 186 TLS_CLI_GNUTLS, 187 TLS_CLI_OPENSSL, 188 TLS_LIB_GNUTLS 189 }; 190 191 static enum tls_tool use_tls_tool; 192 193 194 /* ** Internal values ** */ 195 196 /* Could be increased to facilitate debugging */ 197 static int test_timeout = 5; 198 199 static uint16_t global_port; 200 201 static const void *rclient_msg; 202 203 static size_t rclient_msg_size; 204 205 static const void *app_msg; 206 207 static size_t app_msg_size; 208 209 static void *alloc_ptr[2] = {NULL, NULL}; 210 211 212 static void 213 fflush_allstd (void) 214 { 215 fflush (stderr); 216 fflush (stdout); 217 } 218 219 220 #if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID) 221 /** 222 * Fork child that connects via GnuTLS-CLI to our @a port. Allows us to 223 * talk to our port over a socket in @a sp without having to worry 224 * about TLS. 225 * 226 * @param location where the socket is returned 227 * @return -1 on error, otherwise PID of TLS child process 228 */ 229 static pid_t 230 gnutlscli_connect (int *sock, 231 uint16_t port) 232 { 233 pid_t chld; 234 int sp[2]; 235 char destination[30]; 236 237 if (0 != socketpair (AF_UNIX, 238 SOCK_STREAM, 239 0, 240 sp)) 241 { 242 testErrorLogDesc ("socketpair() failed"); 243 return (pid_t) -1; 244 } 245 chld = fork (); 246 if (0 != chld) 247 { 248 *sock = sp[1]; 249 MHD_socket_close_chk_ (sp[0]); 250 return chld; 251 } 252 MHD_socket_close_chk_ (sp[1]); 253 (void) close (0); 254 (void) close (1); 255 if (-1 == dup2 (sp[0], 0)) 256 externalErrorExitDesc ("dup2() failed"); 257 if (-1 == dup2 (sp[0], 1)) 258 externalErrorExitDesc ("dup2() failed"); 259 MHD_socket_close_chk_ (sp[0]); 260 if (TLS_CLI_GNUTLS == use_tls_tool) 261 { 262 snprintf (destination, 263 sizeof(destination), 264 "%u", 265 (unsigned int) port); 266 execlp ("gnutls-cli", 267 "gnutls-cli", 268 "--insecure", 269 "-p", 270 destination, 271 "127.0.0.1", 272 (char *) NULL); 273 } 274 else if (TLS_CLI_OPENSSL == use_tls_tool) 275 { 276 snprintf (destination, 277 sizeof(destination), 278 "127.0.0.1:%u", 279 (unsigned int) port); 280 execlp ("openssl", 281 "openssl", 282 "s_client", 283 "-connect", 284 destination, 285 "-verify", 286 "1", 287 (char *) NULL); 288 } 289 _exit (1); 290 } 291 292 293 #endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */ 294 295 296 #if 0 /* Unused code */ 297 /** 298 * Change socket to blocking. 299 * 300 * @param fd the socket to manipulate 301 */ 302 static void 303 make_blocking (MHD_socket fd) 304 { 305 #if defined(MHD_POSIX_SOCKETS) 306 int flags; 307 308 flags = fcntl (fd, F_GETFL); 309 if (-1 == flags) 310 externalErrorExitDesc ("fcntl() failed"); 311 if ((flags & ~O_NONBLOCK) != flags) 312 if (-1 == fcntl (fd, F_SETFL, flags & ~O_NONBLOCK)) 313 externalErrorExitDesc ("fcntl() failed"); 314 #elif defined(MHD_WINSOCK_SOCKETS) 315 unsigned long flags = 0; 316 317 if (0 != ioctlsocket (fd, (int) FIONBIO, &flags)) 318 externalErrorExitDesc ("ioctlsocket() failed"); 319 #endif /* MHD_WINSOCK_SOCKETS */ 320 } 321 322 323 #endif /* Unused code */ 324 325 326 /** 327 * Change socket to non-blocking. 328 * 329 * @param fd the socket to manipulate 330 */ 331 static void 332 make_nonblocking (MHD_socket fd) 333 { 334 #if defined(MHD_POSIX_SOCKETS) 335 int flags; 336 337 flags = fcntl (fd, F_GETFL); 338 if (-1 == flags) 339 externalErrorExitDesc ("fcntl() failed"); 340 if (O_NONBLOCK != (flags & O_NONBLOCK)) 341 if (-1 == fcntl (fd, F_SETFL, flags | O_NONBLOCK)) 342 externalErrorExitDesc ("fcntl() failed"); 343 #elif defined(MHD_WINSOCK_SOCKETS) 344 unsigned long flags = 1; 345 346 if (0 != ioctlsocket (fd, (int) FIONBIO, &flags)) 347 externalErrorExitDesc ("ioctlsocket() failed"); 348 #endif /* MHD_WINSOCK_SOCKETS */ 349 } 350 351 352 /** 353 * Enable TCP_NODELAY on TCP/IP socket. 354 * 355 * @param fd the socket to manipulate 356 */ 357 static void 358 make_nodelay (MHD_socket fd) 359 { 360 #ifdef TCP_NODELAY 361 const MHD_SCKT_OPT_BOOL_ on_val = 1; 362 363 if (0 == setsockopt (fd, 364 IPPROTO_TCP, 365 TCP_NODELAY, 366 (const void *) &on_val, 367 sizeof (on_val))) 368 return; /* Success exit point */ 369 370 #ifndef MHD_WINSOCK_SOCKETS 371 fprintf (stderr, "Failed to enable TCP_NODELAY on socket (ignored). " 372 "errno: %d (%s)\n", (int) errno, strerror (errno)); 373 #else /* MHD_WINSOCK_SOCKETS */ 374 fprintf (stderr, "Failed to enable TCP_NODELAY on socket (ignored). " 375 "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); 376 #endif /* MHD_WINSOCK_SOCKETS */ 377 fflush (stderr); 378 #endif /* TCP_NODELAY */ 379 } 380 381 382 /** 383 * Wrapper structure for plain&TLS sockets 384 */ 385 struct wr_socket 386 { 387 /** 388 * Real network socket 389 */ 390 MHD_socket fd; 391 392 /** 393 * Type of this socket 394 */ 395 enum wr_type 396 { 397 wr_invalid = 0, 398 wr_plain = 1, 399 wr_tls = 2 400 } t; 401 402 bool is_nonblocking; 403 404 bool eof_recieved; 405 #ifdef HTTPS_SUPPORT 406 /** 407 * TLS credentials 408 */ 409 gnutls_certificate_credentials_t tls_crd; 410 411 /** 412 * TLS session. 413 */ 414 gnutls_session_t tls_s; 415 416 /** 417 * TLS handshake already succeed? 418 */ 419 bool tls_connected; 420 #endif 421 }; 422 423 424 /** 425 * Get underlying real socket. 426 * @return FD of real socket 427 */ 428 #define wr_fd(s) ((s)->fd) 429 430 431 #if 0 /* Unused code */ 432 static void 433 wr_make_blocking (struct wr_socket *s) 434 { 435 if (s->is_nonblocking) 436 make_blocking (s->fd); 437 s->is_nonblocking = false; 438 } 439 440 441 #endif /* Unused code */ 442 443 444 static void 445 wr_make_nonblocking (struct wr_socket *s) 446 { 447 if (! s->is_nonblocking) 448 make_nonblocking (s->fd); 449 s->is_nonblocking = true; 450 } 451 452 453 /** 454 * Create wr_socket with plain TCP underlying socket 455 * @return created socket on success, NULL otherwise 456 */ 457 static struct wr_socket * 458 wr_create_plain_sckt (void) 459 { 460 struct wr_socket *s = malloc (sizeof(struct wr_socket)); 461 if (NULL == s) 462 { 463 testErrorLogDesc ("malloc() failed"); 464 return NULL; 465 } 466 s->t = wr_plain; 467 s->eof_recieved = false; 468 s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); 469 s->is_nonblocking = false; 470 if (MHD_INVALID_SOCKET != s->fd) 471 { 472 make_nodelay (s->fd); 473 return s; /* Success */ 474 } 475 testErrorLogDesc ("socket() failed"); 476 free (s); 477 return NULL; 478 } 479 480 481 /** 482 * Create wr_socket with TLS TCP underlying socket 483 * @return created socket on success, NULL otherwise 484 */ 485 static struct wr_socket * 486 wr_create_tls_sckt (void) 487 { 488 #ifdef HTTPS_SUPPORT 489 struct wr_socket *s = malloc (sizeof(struct wr_socket)); 490 if (NULL == s) 491 { 492 testErrorLogDesc ("malloc() failed"); 493 return NULL; 494 } 495 s->t = wr_tls; 496 s->eof_recieved = false; 497 s->tls_connected = 0; 498 s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); 499 s->is_nonblocking = false; 500 if (MHD_INVALID_SOCKET != s->fd) 501 { 502 make_nodelay (s->fd); 503 if (GNUTLS_E_SUCCESS == gnutls_init (&(s->tls_s), GNUTLS_CLIENT)) 504 { 505 if (GNUTLS_E_SUCCESS == gnutls_set_default_priority (s->tls_s)) 506 { 507 if (GNUTLS_E_SUCCESS == 508 gnutls_certificate_allocate_credentials (&(s->tls_crd))) 509 { 510 if (GNUTLS_E_SUCCESS == gnutls_credentials_set (s->tls_s, 511 GNUTLS_CRD_CERTIFICATE, 512 s->tls_crd)) 513 { 514 #if (GNUTLS_VERSION_NUMBER + 0 >= 0x030109) && ! defined(_WIN64) 515 gnutls_transport_set_int (s->tls_s, (int) (s->fd)); 516 #else /* GnuTLS before 3.1.9 or Win x64 */ 517 gnutls_transport_set_ptr (s->tls_s, 518 (gnutls_transport_ptr_t) \ 519 (intptr_t) (s->fd)); 520 #endif /* GnuTLS before 3.1.9 or Win x64 */ 521 return s; 522 } 523 else 524 testErrorLogDesc ("gnutls_credentials_set() failed"); 525 gnutls_certificate_free_credentials (s->tls_crd); 526 } 527 else 528 testErrorLogDesc ("gnutls_certificate_allocate_credentials() failed"); 529 } 530 else 531 testErrorLogDesc ("gnutls_set_default_priority() failed"); 532 gnutls_deinit (s->tls_s); 533 } 534 else 535 testErrorLogDesc ("gnutls_init() failed"); 536 (void) MHD_socket_close_ (s->fd); 537 } 538 else 539 testErrorLogDesc ("socket() failed"); 540 free (s); 541 #endif /* HTTPS_SUPPORT */ 542 return NULL; 543 } 544 545 546 /** 547 * Create wr_socket with plain TCP underlying socket 548 * from already created TCP socket. 549 * @param plain_sk real TCP socket 550 * @return created socket on success, NULL otherwise 551 */ 552 static struct wr_socket * 553 wr_create_from_plain_sckt (MHD_socket plain_sk) 554 { 555 struct wr_socket *s = malloc (sizeof(struct wr_socket)); 556 557 if (NULL == s) 558 { 559 testErrorLogDesc ("malloc() failed"); 560 return NULL; 561 } 562 s->t = wr_plain; 563 s->eof_recieved = false; 564 s->fd = plain_sk; 565 s->is_nonblocking = false; /* The actual mode is unknown */ 566 wr_make_nonblocking (s); /* Force set mode to have correct status */ 567 make_nodelay (s->fd); 568 return s; 569 } 570 571 572 #if 0 /* Disabled code */ 573 /** 574 * Check whether shutdown of connection was received from remote 575 * @param s socket to check 576 * @return zero if shutdown signal has not been received, 577 * 1 if shutdown signal was already received 578 */ 579 static int 580 wr_is_eof_received (struct wr_socket *s) 581 { 582 return s->eof_recieved ? 1 : 0; 583 } 584 585 586 #endif /* Disabled code */ 587 588 589 enum wr_wait_for_type 590 { 591 WR_WAIT_FOR_RECV = 0, 592 WR_WAIT_FOR_SEND = 1 593 }; 594 595 static bool 596 wr_wait_socket_ready_noabort_ (struct wr_socket *s, 597 int timeout_ms, 598 enum wr_wait_for_type wait_for) 599 { 600 fd_set fds; 601 int sel_res; 602 struct timeval tmo; 603 struct timeval *tmo_ptr; 604 605 #ifndef MHD_WINSOCK_SOCKETS 606 if (FD_SETSIZE <= s->fd) 607 externalErrorExitDesc ("Too large FD value"); 608 #endif /* ! MHD_WINSOCK_SOCKETS */ 609 FD_ZERO (&fds); 610 FD_SET (s->fd, &fds); 611 if (0 <= timeout_ms) 612 { 613 #if ! defined(_WIN32) || defined(__CYGWIN__) 614 tmo.tv_sec = (time_t) (timeout_ms / 1000); 615 #else /* Native W32 */ 616 tmo.tv_sec = (long) (timeout_ms / 1000); 617 #endif /* Native W32 */ 618 tmo.tv_usec = ((long) (timeout_ms % 1000)) * 1000; 619 tmo_ptr = &tmo; 620 } 621 else 622 tmo_ptr = NULL; /* No timeout */ 623 624 do 625 { 626 if (WR_WAIT_FOR_RECV == wait_for) 627 sel_res = select (1 + (int) s->fd, &fds, NULL, NULL, tmo_ptr); 628 else 629 sel_res = select (1 + (int) s->fd, NULL, &fds, NULL, tmo_ptr); 630 } while (0 > sel_res && MHD_SCKT_ERR_IS_EINTR_ (MHD_socket_get_error_ ())); 631 632 if (1 == sel_res) 633 return true; 634 635 if (0 == sel_res) 636 fprintf (stderr, "Timeout"); 637 else 638 { 639 #ifndef MHD_WINSOCK_SOCKETS 640 fprintf (stderr, "Error %d (%s)", (int) errno, strerror (errno)); 641 #else /* MHD_WINSOCK_SOCKETS */ 642 fprintf (stderr, "Error (WSAGetLastError code: %d)", 643 (int) WSAGetLastError ()); 644 #endif /* MHD_WINSOCK_SOCKETS */ 645 } 646 fprintf (stderr, " waiting for socket to be available for %s.\n", 647 (WR_WAIT_FOR_RECV == wait_for) ? "receiving" : "sending"); 648 return false; 649 } 650 651 652 static void 653 wr_wait_socket_ready_ (struct wr_socket *s, 654 int timeout_ms, 655 enum wr_wait_for_type wait_for) 656 { 657 if (wr_wait_socket_ready_noabort_ (s, timeout_ms, wait_for)) 658 return; 659 660 if (WR_WAIT_FOR_RECV == wait_for) 661 mhdErrorExitDesc ("Client or application failed to receive the data"); 662 else 663 mhdErrorExitDesc ("Client or application failed to send the data"); 664 } 665 666 667 /** 668 * Connect socket to specified address. 669 * @param s socket to use 670 * @param addr address to connect 671 * @param length of structure pointed by @a addr 672 * @param timeout_ms the maximum wait time in milliseconds to send the data, 673 * no limit if negative value is used 674 * @return zero on success, -1 otherwise. 675 */ 676 static int 677 wr_connect_tmo (struct wr_socket *s, 678 const struct sockaddr *addr, 679 unsigned int length, 680 int timeout_ms) 681 { 682 if (0 != connect (s->fd, addr, (socklen_t) length)) 683 { 684 int err; 685 bool connect_completed = false; 686 687 err = MHD_socket_get_error_ (); 688 #if defined(MHD_POSIX_SOCKETS) 689 while (! connect_completed && (EINTR == err)) 690 { 691 connect_completed = (0 == connect (s->fd, addr, (socklen_t) length)); 692 if (! connect_completed) 693 { 694 err = errno; 695 if (EALREADY == err) 696 err = EINPROGRESS; 697 else if (EISCONN == err) 698 connect_completed = true; 699 } 700 } 701 #endif /* MHD_POSIX_SOCKETS */ 702 if (! connect_completed && 703 (MHD_SCKT_ERR_IS_ (err, MHD_SCKT_EINPROGRESS_) 704 || MHD_SCKT_ERR_IS_EAGAIN_ (err))) /* No modern system uses EAGAIN, except W32 */ 705 connect_completed = 706 wr_wait_socket_ready_noabort_ (s, timeout_ms, WR_WAIT_FOR_SEND); 707 if (! connect_completed) 708 { 709 testErrorLogDesc ("connect() failed"); 710 return -1; 711 } 712 } 713 if (wr_plain == s->t) 714 return 0; 715 #ifdef HTTPS_SUPPORT 716 if (wr_tls == s->t) 717 { 718 /* Do not try handshake here as 719 * it requires processing on MHD side and 720 * when testing with "external" polling, 721 * test will call MHD processing only 722 * after return from wr_connect(). */ 723 s->tls_connected = 0; 724 return 0; 725 } 726 #endif /* HTTPS_SUPPORT */ 727 testErrorLogDesc ("HTTPS socket connect called, but code does not support" \ 728 " HTTPS sockets"); 729 return -1; 730 } 731 732 733 /** 734 * Connect socket to specified address. 735 * @param s socket to use 736 * @param addr address to connect 737 * @param length of structure pointed by @a addr 738 * @return zero on success, -1 otherwise. 739 */ 740 static int 741 wr_connect (struct wr_socket *s, 742 const struct sockaddr *addr, 743 unsigned int length) 744 { 745 return wr_connect_tmo (s, addr, length, test_timeout * 1000); 746 } 747 748 749 #ifdef HTTPS_SUPPORT 750 /* Only to be called from wr_send() and wr_recv() ! */ 751 static bool 752 wr_handshake_tmo_ (struct wr_socket *s, 753 int timeout_ms) 754 { 755 int res = gnutls_handshake (s->tls_s); 756 757 while ((GNUTLS_E_AGAIN == res) || (GNUTLS_E_INTERRUPTED == res)) 758 { 759 wr_wait_socket_ready_ (s, timeout_ms, 760 gnutls_record_get_direction (s->tls_s) ? 761 WR_WAIT_FOR_SEND : WR_WAIT_FOR_RECV); 762 res = gnutls_handshake (s->tls_s); 763 } 764 if (GNUTLS_E_SUCCESS == res) 765 s->tls_connected = true; 766 else 767 { 768 fprintf (stderr, "The error returned by gnutls_handshake() is " 769 "'%s' ", gnutls_strerror ((int) res)); 770 #if GNUTLS_VERSION_NUMBER >= 0x020600 771 fprintf (stderr, "(%s)\n", gnutls_strerror_name ((int) res)); 772 #else /* GNUTLS_VERSION_NUMBER < 0x020600 */ 773 fprintf (stderr, "(%d)\n", (int) res); 774 #endif /* GNUTLS_VERSION_NUMBER < 0x020600 */ 775 testErrorLogDesc ("gnutls_handshake() failed with hard error"); 776 MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */ 777 } 778 return s->tls_connected; 779 } 780 781 782 #if 0 /* Unused function */ 783 /* Only to be called from wr_send() and wr_recv() ! */ 784 static bool 785 wr_handshake_ (struct wr_socket *s) 786 { 787 return wr_handshake_tmo_ (s, test_timeout * 1000); 788 } 789 790 791 #endif /* Unused function */ 792 793 #endif /* HTTPS_SUPPORT */ 794 795 796 /** 797 * Send data to remote by socket. 798 * @param s the socket to use 799 * @param buf the buffer with data to send 800 * @param len the length of data in @a buf 801 * @param timeout_ms the maximum wait time in milliseconds to send the data, 802 * no limit if negative value is used 803 * @return number of bytes were sent if succeed, 804 * -1 if failed. Use #MHD_socket_get_error_() 805 * to get socket error. 806 */ 807 static ssize_t 808 wr_send_tmo (struct wr_socket *s, 809 const void *buf, 810 size_t len, 811 int timeout_ms) 812 { 813 if (wr_plain == s->t) 814 { 815 ssize_t res; 816 while (! 0) 817 { 818 int err; 819 res = MHD_send_ (s->fd, buf, len); 820 if (0 <= res) 821 break; /* Success */ 822 err = MHD_socket_get_error_ (); 823 if (! MHD_SCKT_ERR_IS_EAGAIN_ (err) && ! MHD_SCKT_ERR_IS_EINTR_ (err)) 824 break; /* Failure */ 825 wr_wait_socket_ready_ (s, timeout_ms, WR_WAIT_FOR_SEND); 826 } 827 return res; 828 } 829 #ifdef HTTPS_SUPPORT 830 else if (wr_tls == s->t) 831 { 832 ssize_t ret; 833 if (! s->tls_connected && ! wr_handshake_tmo_ (s, timeout_ms)) 834 return -1; 835 836 while (1) 837 { 838 ret = gnutls_record_send (s->tls_s, buf, len); 839 if (ret >= 0) 840 return ret; 841 if ((GNUTLS_E_AGAIN != ret) && (GNUTLS_E_INTERRUPTED != ret)) 842 break; 843 wr_wait_socket_ready_ (s, timeout_ms, 844 gnutls_record_get_direction (s->tls_s) ? 845 WR_WAIT_FOR_SEND : WR_WAIT_FOR_RECV); 846 } 847 fprintf (stderr, "The error returned by gnutls_record_send() is " 848 "'%s' ", gnutls_strerror ((int) ret)); 849 #if GNUTLS_VERSION_NUMBER >= 0x020600 850 fprintf (stderr, "(%s)\n", gnutls_strerror_name ((int) ret)); 851 #else /* GNUTLS_VERSION_NUMBER < 0x020600 */ 852 fprintf (stderr, "(%d)\n", (int) ret); 853 #endif /* GNUTLS_VERSION_NUMBER < 0x020600 */ 854 testErrorLogDesc ("gnutls_record_send() failed with hard error"); 855 MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */ 856 return -1; 857 } 858 #endif /* HTTPS_SUPPORT */ 859 testErrorLogDesc ("HTTPS socket send called, but code does not support" \ 860 " HTTPS sockets"); 861 return -1; 862 } 863 864 865 /** 866 * Send data to remote by socket. 867 * @param s the socket to use 868 * @param buf the buffer with data to send 869 * @param len the length of data in @a buf 870 * @return number of bytes were sent if succeed, 871 * -1 if failed. Use #MHD_socket_get_error_() 872 * to get socket error. 873 */ 874 static ssize_t 875 wr_send (struct wr_socket *s, 876 const void *buf, 877 size_t len) 878 { 879 return wr_send_tmo (s, buf, len, test_timeout * 1000); 880 } 881 882 883 /** 884 * Receive data from remote by socket. 885 * @param s the socket to use 886 * @param buf the buffer to store received data 887 * @param len the length of @a buf 888 * @param timeout_ms the maximum wait time in milliseconds to receive the data, 889 * no limit if negative value is used 890 * @return number of bytes were received if succeed, 891 * -1 if failed. Use #MHD_socket_get_error_() 892 * to get socket error. 893 */ 894 static ssize_t 895 wr_recv_tmo (struct wr_socket *s, 896 void *buf, 897 size_t len, 898 int timeout_ms) 899 { 900 if (wr_plain == s->t) 901 { 902 ssize_t res; 903 while (! 0) 904 { 905 int err; 906 res = MHD_recv_ (s->fd, buf, len); 907 if (0 == res) 908 s->eof_recieved = true; 909 if (0 <= res) 910 break; /* Success */ 911 err = MHD_socket_get_error_ (); 912 if (! MHD_SCKT_ERR_IS_EAGAIN_ (err) && ! MHD_SCKT_ERR_IS_EINTR_ (err)) 913 break; /* Failure */ 914 wr_wait_socket_ready_ (s, timeout_ms, WR_WAIT_FOR_RECV); 915 } 916 return res; 917 } 918 #ifdef HTTPS_SUPPORT 919 if (wr_tls == s->t) 920 { 921 ssize_t ret; 922 if (! s->tls_connected && ! wr_handshake_tmo_ (s, timeout_ms)) 923 return -1; 924 925 while (1) 926 { 927 ret = gnutls_record_recv (s->tls_s, buf, len); 928 if (0 == ret) 929 s->eof_recieved = true; 930 if (ret >= 0) 931 return ret; 932 if ((GNUTLS_E_AGAIN != ret) && (GNUTLS_E_INTERRUPTED != ret)) 933 break; 934 wr_wait_socket_ready_ (s, timeout_ms, 935 gnutls_record_get_direction (s->tls_s) ? 936 WR_WAIT_FOR_SEND : WR_WAIT_FOR_RECV); 937 } 938 939 fprintf (stderr, "The error returned by gnutls_record_recv() is " 940 "'%s' ", gnutls_strerror ((int) ret)); 941 #if GNUTLS_VERSION_NUMBER >= 0x020600 942 fprintf (stderr, "(%s)\n", gnutls_strerror_name ((int) ret)); 943 #else /* GNUTLS_VERSION_NUMBER < 0x020600 */ 944 fprintf (stderr, "(%d)\n", (int) ret); 945 #endif /* GNUTLS_VERSION_NUMBER < 0x020600 */ 946 testErrorLogDesc ("gnutls_record_recv() failed with hard error"); 947 MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */ 948 return -1; 949 } 950 #endif /* HTTPS_SUPPORT */ 951 return -1; 952 } 953 954 955 /** 956 * Receive data from remote by socket. 957 * @param s the socket to use 958 * @param buf the buffer to store received data 959 * @param len the length of @a buf 960 * @return number of bytes were received if succeed, 961 * -1 if failed. Use #MHD_socket_get_error_() 962 * to get socket error. 963 */ 964 static ssize_t 965 wr_recv (struct wr_socket *s, 966 void *buf, 967 size_t len) 968 { 969 return wr_recv_tmo (s, buf, len, test_timeout * 1000); 970 } 971 972 973 /** 974 * Shutdown send/write on the socket. 975 * @param s the socket to shutdown 976 * @param how the type of shutdown: SHUT_WR or SHUT_RDWR 977 * @param timeout_ms the maximum wait time in milliseconds to receive the data, 978 * no limit if negative value is used 979 * @return zero on succeed, -1 otherwise 980 */ 981 static int 982 wr_shutdown_tmo (struct wr_socket *s, int how, int timeout_ms) 983 { 984 switch (how) 985 { 986 case SHUT_WR: /* Valid value */ 987 break; 988 case SHUT_RDWR: /* Valid value */ 989 break; 990 case SHUT_RD: 991 externalErrorExitDesc ("Unsupported 'how' value"); 992 break; 993 default: 994 externalErrorExitDesc ("Invalid 'how' value"); 995 break; 996 } 997 if (wr_plain == s->t) 998 { 999 (void) timeout_ms; /* Unused parameter for plain sockets */ 1000 return shutdown (s->fd, how); 1001 } 1002 #ifdef HTTPS_SUPPORT 1003 if (wr_tls == s->t) 1004 { 1005 ssize_t ret; 1006 if (! s->tls_connected && ! wr_handshake_tmo_ (s, timeout_ms)) 1007 return -1; 1008 1009 while (1) 1010 { 1011 ret = 1012 gnutls_bye (s->tls_s, 1013 (SHUT_WR == how) ? GNUTLS_SHUT_WR : GNUTLS_SHUT_RDWR); 1014 if (GNUTLS_E_SUCCESS == ret) 1015 { 1016 #if 0 /* Disabled to test pure behaviour */ 1017 if (SHUT_RDWR == how) 1018 (void) shutdown (s->fd, how); /* Also shutdown the underlying transport layer */ 1019 #endif 1020 return 0; 1021 } 1022 if ((GNUTLS_E_AGAIN != ret) && (GNUTLS_E_INTERRUPTED != ret)) 1023 break; 1024 wr_wait_socket_ready_ (s, timeout_ms, 1025 gnutls_record_get_direction (s->tls_s) ? 1026 WR_WAIT_FOR_SEND : WR_WAIT_FOR_RECV); 1027 } 1028 1029 fprintf (stderr, "The error returned by gnutls_bye() is " 1030 "'%s' ", gnutls_strerror ((int) ret)); 1031 #if GNUTLS_VERSION_NUMBER >= 0x020600 1032 fprintf (stderr, "(%s)\n", gnutls_strerror_name ((int) ret)); 1033 #else /* GNUTLS_VERSION_NUMBER < 0x020600 */ 1034 fprintf (stderr, "(%d)\n", (int) ret); 1035 #endif /* GNUTLS_VERSION_NUMBER < 0x020600 */ 1036 testErrorLogDesc ("gnutls_bye() failed with hard error"); 1037 MHD_socket_set_error_ (MHD_SCKT_ECONNABORTED_); /* hard error */ 1038 return -1; 1039 } 1040 #endif /* HTTPS_SUPPORT */ 1041 return -1; 1042 } 1043 1044 1045 /** 1046 * Shutdown the socket. 1047 * @param s the socket to shutdown 1048 * @return zero on succeed, -1 otherwise 1049 */ 1050 static int 1051 wr_shutdown (struct wr_socket *s, int how) 1052 { 1053 return wr_shutdown_tmo (s, how, test_timeout * 1000); 1054 } 1055 1056 1057 /** 1058 * Close socket and release allocated resourced 1059 * @param s the socket to close 1060 * @return zero on succeed, -1 otherwise 1061 */ 1062 static int 1063 wr_close (struct wr_socket *s) 1064 { 1065 int ret = (MHD_socket_close_ (s->fd)) ? 0 : -1; 1066 #ifdef HTTPS_SUPPORT 1067 if (wr_tls == s->t) 1068 { 1069 gnutls_deinit (s->tls_s); 1070 gnutls_certificate_free_credentials (s->tls_crd); 1071 } 1072 #endif /* HTTPS_SUPPORT */ 1073 free (s); 1074 return ret; 1075 } 1076 1077 1078 /** 1079 * Thread we use to run the interaction with the upgraded socket. 1080 */ 1081 static pthread_t pt; 1082 1083 /** 1084 * Will be set to the upgraded socket. 1085 */ 1086 static struct wr_socket *volatile usock; 1087 1088 /** 1089 * Thread we use to run the interaction with the upgraded socket. 1090 */ 1091 static pthread_t pt_client; 1092 1093 /** 1094 * Flag set to true once the client is finished. 1095 */ 1096 static volatile bool client_done; 1097 1098 /** 1099 * Flag set to true once the app is finished. 1100 */ 1101 static volatile bool app_done; 1102 1103 1104 static const char * 1105 term_reason_str (enum MHD_RequestTerminationCode term_code) 1106 { 1107 switch ((int) term_code) 1108 { 1109 case MHD_REQUEST_TERMINATED_COMPLETED_OK: 1110 return "COMPLETED_OK"; 1111 case MHD_REQUEST_TERMINATED_WITH_ERROR: 1112 return "TERMINATED_WITH_ERROR"; 1113 case MHD_REQUEST_TERMINATED_TIMEOUT_REACHED: 1114 return "TIMEOUT_REACHED"; 1115 case MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN: 1116 return "DAEMON_SHUTDOWN"; 1117 case MHD_REQUEST_TERMINATED_READ_ERROR: 1118 return "READ_ERROR"; 1119 case MHD_REQUEST_TERMINATED_CLIENT_ABORT: 1120 return "CLIENT_ABORT"; 1121 case -1: 1122 return "(not called)"; 1123 default: 1124 return "(unknown code)"; 1125 } 1126 return "(problem)"; /* unreachable */ 1127 } 1128 1129 1130 /** 1131 * Callback used by MHD to notify the application about completed 1132 * requests. Frees memory. 1133 * 1134 * @param cls client-defined closure 1135 * @param connection connection handle 1136 * @param req_cls value as set by the last call to 1137 * the #MHD_AccessHandlerCallback 1138 * @param toe reason for request termination 1139 */ 1140 static void 1141 notify_completed_cb (void *cls, 1142 struct MHD_Connection *connection, 1143 void **req_cls, 1144 enum MHD_RequestTerminationCode toe) 1145 { 1146 (void) cls; 1147 (void) connection; /* Unused. Silent compiler warning. */ 1148 if (verbose) 1149 printf ("notify_completed_cb() has been called with '%s' code.\n", 1150 term_reason_str (toe)); 1151 if ( (toe != MHD_REQUEST_TERMINATED_COMPLETED_OK) && 1152 (toe != MHD_REQUEST_TERMINATED_CLIENT_ABORT) && 1153 (toe != MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN) ) 1154 mhdErrorExitDesc ("notify_completed_cb() called with wrong code"); 1155 if (NULL == req_cls) 1156 mhdErrorExitDesc ("'req_cls' parameter is NULL"); 1157 if (NULL == *req_cls) 1158 mhdErrorExitDesc ("'*req_cls' pointer is NULL"); 1159 if (! pthread_equal (**((pthread_t **) req_cls), 1160 pthread_self ())) 1161 mhdErrorExitDesc ("notify_completed_cb() is called in wrong thread"); 1162 free (*req_cls); 1163 *req_cls = NULL; 1164 } 1165 1166 1167 /** 1168 * Logging callback. 1169 * 1170 * @param cls logging closure (NULL) 1171 * @param uri access URI 1172 * @param connection connection handle 1173 * @return #TEST_PTR 1174 */ 1175 static void * 1176 log_cb (void *cls, 1177 const char *uri, 1178 struct MHD_Connection *connection) 1179 { 1180 pthread_t *ppth; 1181 1182 (void) cls; 1183 (void) connection; /* Unused. Silent compiler warning. */ 1184 if (NULL == uri) 1185 mhdErrorExitDesc ("The 'uri' parameter is NULL"); 1186 if (0 != strcmp (uri, "/")) 1187 { 1188 fprintf (stderr, "Wrong 'uri' value: '%s'. ", uri); 1189 mhdErrorExit (); 1190 } 1191 ppth = malloc (sizeof (pthread_t)); 1192 if (NULL == ppth) 1193 externalErrorExitDesc ("malloc() failed"); 1194 *ppth = pthread_self (); 1195 return (void *) ppth; 1196 } 1197 1198 1199 /** 1200 * Function to check that MHD properly notifies about starting 1201 * and stopping. 1202 * 1203 * @param cls client-defined closure 1204 * @param connection connection handle 1205 * @param socket_context socket-specific pointer where the 1206 * client can associate some state specific 1207 * to the TCP connection; note that this is 1208 * different from the "req_cls" which is per 1209 * HTTP request. The client can initialize 1210 * during #MHD_CONNECTION_NOTIFY_STARTED and 1211 * cleanup during #MHD_CONNECTION_NOTIFY_CLOSED 1212 * and access in the meantime using 1213 * #MHD_CONNECTION_INFO_SOCKET_CONTEXT. 1214 * @param toe reason for connection notification 1215 * @see #MHD_OPTION_NOTIFY_CONNECTION 1216 * @ingroup request 1217 */ 1218 static void 1219 notify_connection_cb (void *cls, 1220 struct MHD_Connection *connection, 1221 void **socket_context, 1222 enum MHD_ConnectionNotificationCode toe) 1223 { 1224 static int started = MHD_NO; 1225 1226 (void) cls; 1227 (void) connection; /* Unused. Silent compiler warning. */ 1228 switch (toe) 1229 { 1230 case MHD_CONNECTION_NOTIFY_STARTED: 1231 if (MHD_NO != started) 1232 mhdErrorExitDesc ("The connection has been already started"); 1233 started = MHD_YES; 1234 *socket_context = &started; 1235 break; 1236 case MHD_CONNECTION_NOTIFY_CLOSED: 1237 if (MHD_YES != started) 1238 mhdErrorExitDesc ("The connection has not been started before"); 1239 if (&started != *socket_context) 1240 mhdErrorExitDesc ("Wrong '*socket_context' value"); 1241 *socket_context = NULL; 1242 started = MHD_NO; 1243 break; 1244 } 1245 } 1246 1247 1248 static void 1249 send_all (struct wr_socket *sock, 1250 const void *data, 1251 size_t data_size) 1252 { 1253 ssize_t ret; 1254 size_t sent; 1255 const uint8_t *const buf = (const uint8_t *) data; 1256 1257 wr_make_nonblocking (sock); 1258 for (sent = 0; sent < data_size; sent += (size_t) ret) 1259 { 1260 ret = wr_send (sock, 1261 buf + sent, 1262 data_size - sent); 1263 if (0 > ret) 1264 { 1265 if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()) || 1266 MHD_SCKT_ERR_IS_EINTR_ (MHD_socket_get_error_ ())) 1267 { 1268 ret = 0; 1269 continue; 1270 } 1271 externalErrorExitDesc ("send() failed"); 1272 } 1273 } 1274 } 1275 1276 1277 #define send_all_stext(sk,st) send_all(sk,st,MHD_STATICSTR_LEN_(st)) 1278 1279 1280 /** 1281 * Read character-by-character until we 1282 * get 'CRLNCRLN'. 1283 */ 1284 static void 1285 recv_hdr (struct wr_socket *sock) 1286 { 1287 unsigned int i; 1288 char next; 1289 char c; 1290 ssize_t ret; 1291 1292 wr_make_nonblocking (sock); 1293 next = '\r'; 1294 i = 0; 1295 while (i < 4) 1296 { 1297 ret = wr_recv (sock, 1298 &c, 1299 1); 1300 if (0 > ret) 1301 { 1302 if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ())) 1303 continue; 1304 if (MHD_SCKT_ERR_IS_EINTR_ (MHD_socket_get_error_ ())) 1305 continue; 1306 externalErrorExitDesc ("recv() failed"); 1307 } 1308 if (0 == ret) 1309 mhdErrorExitDesc ("The server unexpectedly closed connection"); 1310 if (c == next) 1311 { 1312 i++; 1313 if (next == '\r') 1314 next = '\n'; 1315 else 1316 next = '\r'; 1317 continue; 1318 } 1319 if (c == '\r') 1320 { 1321 i = 1; 1322 next = '\n'; 1323 continue; 1324 } 1325 i = 0; 1326 next = '\r'; 1327 } 1328 } 1329 1330 1331 static void 1332 recv_all (struct wr_socket *sock, 1333 const void *data, 1334 size_t data_size) 1335 { 1336 uint8_t *buf; 1337 ssize_t ret; 1338 size_t rcvd; 1339 1340 buf = (uint8_t *) malloc (data_size); 1341 if (NULL == buf) 1342 externalErrorExitDesc ("malloc() failed"); 1343 1344 wr_make_nonblocking (sock); 1345 for (rcvd = 0; rcvd < data_size; rcvd += (size_t) ret) 1346 { 1347 ret = wr_recv (sock, 1348 buf + rcvd, 1349 data_size - rcvd); 1350 if (0 > ret) 1351 { 1352 if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()) || 1353 MHD_SCKT_ERR_IS_EINTR_ (MHD_socket_get_error_ ())) 1354 { 1355 ret = 0; 1356 continue; 1357 } 1358 externalErrorExitDesc ("recv() failed"); 1359 } 1360 else if (0 == ret) 1361 { 1362 fprintf (stderr, "Partial only received text. Expected: '%.*s' " 1363 "(length: %ud). Got: '%.*s' (length: %ud). ", 1364 (int) data_size, (const char *) data, (unsigned int) data_size, 1365 (int) rcvd, (const char *) buf, (unsigned int) rcvd); 1366 mhdErrorExitDesc ("The server unexpectedly closed connection"); 1367 } 1368 if ((data_size - rcvd) < (size_t) ret) 1369 externalErrorExitDesc ("recv() returned excessive amount of data"); 1370 if (0 != memcmp (data, buf, rcvd + (size_t) ret)) 1371 { 1372 fprintf (stderr, "Wrong received text. Expected: '%.*s'. " 1373 "Got: '%.*s'. ", 1374 (int) (rcvd + (size_t) ret), (const char *) data, 1375 (int) (rcvd + (size_t) ret), (const char *) buf); 1376 mhdErrorExit (); 1377 } 1378 } 1379 if (0 != memcmp (data, buf, data_size)) 1380 { 1381 fprintf (stderr, "Wrong received text. Expected: '%.*s'. " 1382 "Got: '%.*s'. ", 1383 (int) data_size, (const char *) data, 1384 (int) data_size, (const char *) buf); 1385 mhdErrorExit (); 1386 } 1387 free (buf); 1388 } 1389 1390 1391 #define recv_all_stext(sk,st) recv_all(sk,st,MHD_STATICSTR_LEN_(st)) 1392 1393 1394 /** 1395 * Shutdown write of the connection to signal end of transmission 1396 * for the remote side 1397 * @param sock the socket to shutdown 1398 */ 1399 static void 1400 send_eof (struct wr_socket *sock) 1401 { 1402 if (0 != wr_shutdown (sock, /* 1403 ** On Darwin local shutdown of RD cause error 1404 ** if remote side shut down WR before. 1405 wr_is_eof_received (sock) ? SHUT_RDWR : */ 1406 SHUT_WR)) 1407 externalErrorExitDesc ("Failed to shutdown connection"); 1408 } 1409 1410 1411 /** 1412 * Receive end of the transmission indication from the remote side 1413 * @param sock the socket to use 1414 */ 1415 static void 1416 receive_eof (struct wr_socket *sock) 1417 { 1418 uint8_t buf[127]; 1419 ssize_t ret; 1420 size_t rcvd; 1421 bool got_eof = false; 1422 1423 wr_make_nonblocking (sock); 1424 for (rcvd = 0; rcvd < sizeof(buf); rcvd += (size_t) ret) 1425 { 1426 ret = wr_recv (sock, 1427 buf + rcvd, 1428 sizeof(buf) - rcvd); 1429 if (0 > ret) 1430 { 1431 if (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ()) || 1432 MHD_SCKT_ERR_IS_EINTR_ (MHD_socket_get_error_ ())) 1433 { 1434 ret = 0; 1435 continue; 1436 } 1437 externalErrorExitDesc ("recv() failed"); 1438 } 1439 else if (0 == ret) 1440 { 1441 got_eof = true; 1442 break; 1443 } 1444 } 1445 if (got_eof && (0 == rcvd)) 1446 return; /* Success */ 1447 1448 if (0 != rcvd) 1449 { 1450 if (sizeof(buf) == rcvd) 1451 { 1452 fprintf (stderr, "Received at least %lu extra bytes while " 1453 "end-of-file is expected.\n", (unsigned long) sizeof(buf)); 1454 mhdErrorExit (); 1455 } 1456 fprintf (stderr, "Received at %lu extra bytes and then %s" 1457 "end-of-file marker.\n", (unsigned long) rcvd, 1458 got_eof ? "" : "NO "); 1459 mhdErrorExit (); 1460 } 1461 if (! got_eof) 1462 mhdErrorExitDesc ("Failed to receive end-of-file marker."); 1463 } 1464 1465 1466 /** 1467 * Main function for the thread that runs the interaction with 1468 * the upgraded socket. 1469 * 1470 * @param cls the handle for the upgrade 1471 */ 1472 static void * 1473 run_usock (void *cls) 1474 { 1475 struct MHD_UpgradeResponseHandle *urh = cls; 1476 1477 recv_all (usock, rclient_msg, rclient_msg_size); 1478 send_all (usock, app_msg, app_msg_size); 1479 recv_all_stext (usock, 1480 "Finished"); 1481 if (! test_tls) 1482 { 1483 receive_eof (usock); 1484 send_eof (usock); 1485 } 1486 MHD_upgrade_action (urh, 1487 MHD_UPGRADE_ACTION_CLOSE); 1488 free (usock); 1489 usock = NULL; 1490 app_done = true; 1491 return NULL; 1492 } 1493 1494 1495 /** 1496 * Main function for the thread that runs the client-side of the 1497 * interaction with the upgraded socket. 1498 * 1499 * @param cls the client socket 1500 */ 1501 static void * 1502 run_usock_client (void *cls) 1503 { 1504 struct wr_socket *sock = cls; 1505 1506 send_all_stext (sock, 1507 "GET / HTTP/1.1\r\nHost: localhost\r\nConnection: Upgrade\r\n\r\n"); 1508 recv_hdr (sock); 1509 send_all (sock, rclient_msg, rclient_msg_size); 1510 recv_all (sock, app_msg, app_msg_size); 1511 send_all_stext (sock, 1512 "Finished"); 1513 if (! test_tls) 1514 { 1515 send_eof (sock); 1516 receive_eof (sock); 1517 } 1518 wr_close (sock); 1519 client_done = true; 1520 return NULL; 1521 } 1522 1523 1524 /** 1525 * Function called after a protocol "upgrade" response was sent 1526 * successfully and the socket should now be controlled by some 1527 * protocol other than HTTP. 1528 * 1529 * Any data already received on the socket will be made available in 1530 * @e extra_in. This can happen if the application sent extra data 1531 * before MHD send the upgrade response. The application should 1532 * treat data from @a extra_in as if it had read it from the socket. 1533 * 1534 * Note that the application must not close() @a sock directly, 1535 * but instead use #MHD_upgrade_action() for special operations 1536 * on @a sock. 1537 * 1538 * Except when in 'thread-per-connection' mode, implementations 1539 * of this function should never block (as it will still be called 1540 * from within the main event loop). 1541 * 1542 * @param cls closure, whatever was given to #MHD_create_response_for_upgrade(). 1543 * @param connection original HTTP connection handle, 1544 * giving the function a last chance 1545 * to inspect the original HTTP request 1546 * @param req_cls last value left in `req_cls` of the `MHD_AccessHandlerCallback` 1547 * @param extra_in if we happened to have read bytes after the 1548 * HTTP header already (because the client sent 1549 * more than the HTTP header of the request before 1550 * we sent the upgrade response), 1551 * these are the extra bytes already read from @a sock 1552 * by MHD. The application should treat these as if 1553 * it had read them from @a sock. 1554 * @param extra_in_size number of bytes in @a extra_in 1555 * @param sock socket to use for bi-directional communication 1556 * with the client. For HTTPS, this may not be a socket 1557 * that is directly connected to the client and thus certain 1558 * operations (TCP-specific setsockopt(), getsockopt(), etc.) 1559 * may not work as expected (as the socket could be from a 1560 * socketpair() or a TCP-loopback). The application is expected 1561 * to perform read()/recv() and write()/send() calls on the socket. 1562 * The application may also call shutdown(), but must not call 1563 * close() directly. 1564 * @param urh argument for #MHD_upgrade_action()s on this @a connection. 1565 * Applications must eventually use this callback to (indirectly) 1566 * perform the close() action on the @a sock. 1567 */ 1568 static void 1569 upgrade_cb (void *cls, 1570 struct MHD_Connection *connection, 1571 void *req_cls, 1572 const char *extra_in, 1573 size_t extra_in_size, 1574 MHD_socket sock, 1575 struct MHD_UpgradeResponseHandle *urh) 1576 { 1577 (void) cls; 1578 (void) connection; 1579 (void) req_cls; 1580 (void) extra_in; /* Unused. Silent compiler warning. */ 1581 1582 usock = wr_create_from_plain_sckt (sock); 1583 wr_make_nonblocking (usock); 1584 if (0 != extra_in_size) 1585 mhdErrorExitDesc ("'extra_in_size' is not zero"); 1586 if (0 != pthread_create (&pt, 1587 NULL, 1588 &run_usock, 1589 urh)) 1590 externalErrorExitDesc ("pthread_create() failed"); 1591 } 1592 1593 1594 /** 1595 * A client has requested the given url using the given method 1596 * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT, 1597 * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc). The callback 1598 * must call MHD callbacks to provide content to give back to the 1599 * client and return an HTTP status code (i.e. #MHD_HTTP_OK, 1600 * #MHD_HTTP_NOT_FOUND, etc.). 1601 * 1602 * @param cls argument given together with the function 1603 * pointer when the handler was registered with MHD 1604 * @param url the requested url 1605 * @param method the HTTP method used (#MHD_HTTP_METHOD_GET, 1606 * #MHD_HTTP_METHOD_PUT, etc.) 1607 * @param version the HTTP version string (i.e. 1608 * #MHD_HTTP_VERSION_1_1) 1609 * @param upload_data the data being uploaded (excluding HEADERS, 1610 * for a POST that fits into memory and that is encoded 1611 * with a supported encoding, the POST data will NOT be 1612 * given in upload_data and is instead available as 1613 * part of #MHD_get_connection_values; very large POST 1614 * data *will* be made available incrementally in 1615 * @a upload_data) 1616 * @param upload_data_size set initially to the size of the 1617 * @a upload_data provided; the method must update this 1618 * value to the number of bytes NOT processed; 1619 * @param req_cls pointer that the callback can set to some 1620 * address and that will be preserved by MHD for future 1621 * calls for this request; since the access handler may 1622 * be called many times (i.e., for a PUT/POST operation 1623 * with plenty of upload data) this allows the application 1624 * to easily associate some request-specific state. 1625 * If necessary, this state can be cleaned up in the 1626 * global #MHD_RequestCompletedCallback (which 1627 * can be set with the #MHD_OPTION_NOTIFY_COMPLETED). 1628 * Initially, `*req_cls` will be NULL. 1629 * @return #MHD_YES if the connection was handled successfully, 1630 * #MHD_NO if the socket must be closed due to a serious 1631 * error while handling the request 1632 */ 1633 static enum MHD_Result 1634 ahc_upgrade (void *cls, 1635 struct MHD_Connection *connection, 1636 const char *url, 1637 const char *method, 1638 const char *version, 1639 const char *upload_data, 1640 size_t *upload_data_size, 1641 void **req_cls) 1642 { 1643 struct MHD_Response *resp; 1644 (void) cls; 1645 (void) url; 1646 (void) method; /* Unused. Silent compiler warning. */ 1647 (void) version; 1648 (void) upload_data; 1649 (void) upload_data_size; /* Unused. Silent compiler warning. */ 1650 1651 if (NULL == req_cls) 1652 mhdErrorExitDesc ("'req_cls' is NULL"); 1653 if (NULL == *req_cls) 1654 mhdErrorExitDesc ("'*req_cls' value is NULL"); 1655 if (! pthread_equal (**((pthread_t **) req_cls), pthread_self ())) 1656 mhdErrorExitDesc ("ahc_upgrade() is called in wrong thread"); 1657 resp = MHD_create_response_for_upgrade (&upgrade_cb, 1658 NULL); 1659 if (NULL == resp) 1660 mhdErrorExitDesc ("MHD_create_response_for_upgrade() failed"); 1661 if (MHD_YES != MHD_add_response_header (resp, 1662 MHD_HTTP_HEADER_UPGRADE, 1663 "Hello World Protocol")) 1664 mhdErrorExitDesc ("MHD_add_response_header() failed"); 1665 if (MHD_YES != MHD_queue_response (connection, 1666 MHD_HTTP_SWITCHING_PROTOCOLS, 1667 resp)) 1668 mhdErrorExitDesc ("MHD_queue_response() failed"); 1669 MHD_destroy_response (resp); 1670 return MHD_YES; 1671 } 1672 1673 1674 /** 1675 * Run the MHD external event loop using select or epoll. 1676 * 1677 * select/epoll modes are used automatically based on daemon's flags. 1678 * 1679 * @param daemon daemon to run it for 1680 */ 1681 static void 1682 run_mhd_select_loop (struct MHD_Daemon *daemon) 1683 { 1684 const time_t start_time = time (NULL); 1685 const union MHD_DaemonInfo *pdinfo; 1686 bool connection_was_accepted; 1687 bool connection_has_finished; 1688 #ifdef EPOLL_SUPPORT 1689 bool use_epoll = false; 1690 int ep = -1; 1691 1692 pdinfo = MHD_get_daemon_info (daemon, 1693 MHD_DAEMON_INFO_FLAGS); 1694 if (NULL == pdinfo) 1695 mhdErrorExitDesc ("MHD_get_daemon_info() failed"); 1696 else 1697 use_epoll = (0 != (pdinfo->flags & MHD_USE_EPOLL)); 1698 if (use_epoll) 1699 { 1700 pdinfo = MHD_get_daemon_info (daemon, 1701 MHD_DAEMON_INFO_EPOLL_FD); 1702 if (NULL == pdinfo) 1703 mhdErrorExitDesc ("MHD_get_daemon_info() failed"); 1704 ep = pdinfo->listen_fd; 1705 if (0 > ep) 1706 mhdErrorExitDesc ("Invalid epoll FD value"); 1707 } 1708 #endif /* EPOLL_SUPPORT */ 1709 1710 connection_was_accepted = false; 1711 connection_has_finished = false; 1712 while (1) 1713 { 1714 fd_set rs; 1715 fd_set ws; 1716 fd_set es; 1717 MHD_socket max_fd; 1718 struct timeval tv; 1719 uint64_t to64; 1720 bool has_mhd_timeout; 1721 1722 FD_ZERO (&rs); 1723 FD_ZERO (&ws); 1724 FD_ZERO (&es); 1725 max_fd = MHD_INVALID_SOCKET; 1726 1727 if (time (NULL) - start_time > ((time_t) test_timeout)) 1728 mhdErrorExitDesc ("Test timeout"); 1729 1730 pdinfo = MHD_get_daemon_info (daemon, MHD_DAEMON_INFO_CURRENT_CONNECTIONS); 1731 1732 if (NULL == pdinfo) 1733 mhdErrorExitDesc ("MHD_get_daemon_info() failed"); 1734 1735 if (0 != pdinfo->num_connections) 1736 connection_was_accepted = true; 1737 else 1738 { 1739 if (connection_was_accepted) 1740 connection_has_finished = true; 1741 } 1742 if (connection_has_finished) 1743 return; 1744 1745 if (MHD_YES != 1746 MHD_get_fdset (daemon, 1747 &rs, 1748 &ws, 1749 &es, 1750 &max_fd)) 1751 mhdErrorExitDesc ("MHD_get_fdset() failed"); 1752 1753 #ifdef EPOLL_SUPPORT 1754 if (use_epoll) 1755 { 1756 if (ep != max_fd) 1757 mhdErrorExitDesc ("Wrong 'max_fd' value"); 1758 if (! FD_ISSET (ep, &rs)) 1759 mhdErrorExitDesc ("Epoll FD is NOT set in read fd_set"); 1760 } 1761 #endif /* EPOLL_SUPPORT */ 1762 1763 has_mhd_timeout = (MHD_NO != MHD_get_timeout64 (daemon, 1764 &to64)); 1765 if (has_mhd_timeout) 1766 { 1767 #if ! defined(_WIN32) || defined(__CYGWIN__) 1768 tv.tv_sec = (time_t) (to64 / 1000); 1769 #else /* Native W32 */ 1770 tv.tv_sec = (long) (to64 / 1000); 1771 #endif /* Native W32 */ 1772 tv.tv_usec = (long) (1000 * (to64 % 1000)); 1773 } 1774 else 1775 { 1776 #if ! defined(_WIN32) || defined(__CYGWIN__) 1777 tv.tv_sec = (time_t) test_timeout; 1778 #else /* Native W32 */ 1779 tv.tv_sec = (long) test_timeout; 1780 #endif /* Native W32 */ 1781 tv.tv_usec = 0; 1782 } 1783 1784 #ifdef MHD_WINSOCK_SOCKETS 1785 if ((0 == rs.fd_count) && (0 == ws.fd_count) && (0 != es.fd_count)) 1786 Sleep ((DWORD) (tv.tv_sec * 1000 + tv.tv_usec / 1000)); 1787 else /* Combined with the next 'if' */ 1788 #endif 1789 if (1) 1790 { 1791 int sel_res; 1792 sel_res = MHD_SYS_select_ (max_fd + 1, 1793 &rs, 1794 &ws, 1795 &es, 1796 &tv); 1797 if (0 == sel_res) 1798 { 1799 if (! has_mhd_timeout) 1800 mhdErrorExitDesc ("Timeout waiting for data on sockets"); 1801 } 1802 else if (0 > sel_res) 1803 { 1804 #ifdef MHD_POSIX_SOCKETS 1805 if (EINTR != errno) 1806 #endif /* MHD_POSIX_SOCKETS */ 1807 mhdErrorExitDesc ("Unexpected select() error"); 1808 } 1809 } 1810 MHD_run_from_select (daemon, 1811 &rs, 1812 &ws, 1813 &es); 1814 } 1815 } 1816 1817 1818 #ifdef HAVE_POLL 1819 1820 /** 1821 * Run the MHD external event loop using select. 1822 * 1823 * @param daemon daemon to run it for 1824 */ 1825 _MHD_NORETURN static void 1826 run_mhd_poll_loop (struct MHD_Daemon *daemon) 1827 { 1828 (void) daemon; /* Unused. Silent compiler warning. */ 1829 externalErrorExitDesc ("Not implementable with MHD API"); 1830 } 1831 1832 1833 #endif /* HAVE_POLL */ 1834 1835 1836 /** 1837 * Run the MHD external event loop using select. 1838 * 1839 * @param daemon daemon to run it for 1840 */ 1841 static void 1842 run_mhd_loop (struct MHD_Daemon *daemon, 1843 unsigned int flags) 1844 { 1845 if (0 == (flags & (MHD_USE_POLL | MHD_USE_EPOLL))) 1846 run_mhd_select_loop (daemon); 1847 #ifdef HAVE_POLL 1848 else if (0 != (flags & MHD_USE_POLL)) 1849 run_mhd_poll_loop (daemon); 1850 #endif /* HAVE_POLL */ 1851 #ifdef EPOLL_SUPPORT 1852 else if (0 != (flags & MHD_USE_EPOLL)) 1853 run_mhd_select_loop (daemon); 1854 #endif 1855 else 1856 externalErrorExitDesc ("Wrong 'flags' value"); 1857 } 1858 1859 1860 /** 1861 * Test upgrading a connection. 1862 * 1863 * @param flags which event loop style should be tested 1864 * @param pool size of the thread pool, 0 to disable 1865 */ 1866 static unsigned int 1867 test_upgrade (unsigned int flags, 1868 unsigned int pool) 1869 { 1870 struct MHD_Daemon *d = NULL; 1871 struct wr_socket *sock; 1872 struct sockaddr_in sa; 1873 enum MHD_FLAG used_flags; 1874 const union MHD_DaemonInfo *dinfo; 1875 #if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID) 1876 pid_t pid = -1; 1877 #endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */ 1878 size_t mem_limit; 1879 1880 /* Handle memory limits. Actually makes sense only for TLS */ 1881 if (use_vlarge) 1882 mem_limit = 64U * 1024U; /* Half of the buffer should be large enough to take more than max TLS packet */ 1883 else if (use_large) 1884 mem_limit = 4U * 1024; /* Make sure that several iteration required to deliver a single message */ 1885 else 1886 mem_limit = 0; /* Use default value */ 1887 1888 client_done = false; 1889 app_done = false; 1890 1891 if (! test_tls) 1892 d = MHD_start_daemon (flags | MHD_USE_ERROR_LOG | MHD_ALLOW_UPGRADE 1893 | MHD_USE_ITC, 1894 global_port, 1895 NULL, NULL, 1896 &ahc_upgrade, NULL, 1897 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL, 1898 MHD_OPTION_NOTIFY_COMPLETED, ¬ify_completed_cb, 1899 NULL, 1900 MHD_OPTION_NOTIFY_CONNECTION, ¬ify_connection_cb, 1901 NULL, 1902 MHD_OPTION_THREAD_POOL_SIZE, pool, 1903 MHD_OPTION_CONNECTION_TIMEOUT, test_timeout, 1904 MHD_OPTION_CONNECTION_MEMORY_LIMIT, mem_limit, 1905 MHD_OPTION_END); 1906 #ifdef HTTPS_SUPPORT 1907 else 1908 d = MHD_start_daemon (flags | MHD_USE_ERROR_LOG | MHD_ALLOW_UPGRADE 1909 | MHD_USE_TLS | MHD_USE_ITC, 1910 global_port, 1911 NULL, NULL, 1912 &ahc_upgrade, NULL, 1913 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL, 1914 MHD_OPTION_NOTIFY_COMPLETED, ¬ify_completed_cb, 1915 NULL, 1916 MHD_OPTION_NOTIFY_CONNECTION, ¬ify_connection_cb, 1917 NULL, 1918 MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem, 1919 MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem, 1920 MHD_OPTION_THREAD_POOL_SIZE, pool, 1921 MHD_OPTION_CONNECTION_TIMEOUT, test_timeout, 1922 MHD_OPTION_CONNECTION_MEMORY_LIMIT, mem_limit, 1923 MHD_OPTION_END); 1924 #endif /* HTTPS_SUPPORT */ 1925 if (NULL == d) 1926 mhdErrorExitDesc ("MHD_start_daemon() failed"); 1927 dinfo = MHD_get_daemon_info (d, 1928 MHD_DAEMON_INFO_FLAGS); 1929 if (NULL == dinfo) 1930 mhdErrorExitDesc ("MHD_get_daemon_info() failed"); 1931 used_flags = dinfo->flags; 1932 dinfo = MHD_get_daemon_info (d, 1933 MHD_DAEMON_INFO_BIND_PORT); 1934 if ( (NULL == dinfo) || 1935 (0 == dinfo->port) ) 1936 mhdErrorExitDesc ("MHD_get_daemon_info() failed"); 1937 global_port = dinfo->port; /* Re-use the same port for the next checks */ 1938 if (! test_tls || (TLS_LIB_GNUTLS == use_tls_tool)) 1939 { 1940 sock = test_tls ? wr_create_tls_sckt () : wr_create_plain_sckt (); 1941 if (NULL == sock) 1942 externalErrorExitDesc ("Create socket failed"); 1943 wr_make_nonblocking (sock); 1944 sa.sin_family = AF_INET; 1945 sa.sin_port = htons (dinfo->port); 1946 sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); 1947 if (0 != wr_connect (sock, 1948 (struct sockaddr *) &sa, 1949 sizeof (sa))) 1950 externalErrorExitDesc ("Connect socket failed"); 1951 } 1952 else 1953 { 1954 #if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID) 1955 MHD_socket tls_fork_sock; 1956 uint16_t port; 1957 1958 port = dinfo->port; 1959 if (-1 == (pid = gnutlscli_connect (&tls_fork_sock, 1960 port))) 1961 externalErrorExitDesc ("gnutlscli_connect() failed"); 1962 1963 sock = wr_create_from_plain_sckt (tls_fork_sock); 1964 if (NULL == sock) 1965 externalErrorExitDesc ("wr_create_from_plain_sckt() failed"); 1966 1967 wr_make_nonblocking (sock); 1968 #else /* !HTTPS_SUPPORT || !HAVE_FORK || !HAVE_WAITPID */ 1969 externalErrorExitDesc ("Unsupported 'use_tls_tool' value"); 1970 #endif /* !HTTPS_SUPPORT || !HAVE_FORK || !HAVE_WAITPID */ 1971 } 1972 1973 if (0 != pthread_create (&pt_client, 1974 NULL, 1975 &run_usock_client, 1976 sock)) 1977 externalErrorExitDesc ("pthread_create() failed"); 1978 if (0 == (flags & MHD_USE_INTERNAL_POLLING_THREAD) ) 1979 run_mhd_loop (d, used_flags); 1980 if (0 != pthread_join (pt_client, 1981 NULL)) 1982 externalErrorExitDesc ("pthread_join() failed"); 1983 if (0 != pthread_join (pt, 1984 NULL)) 1985 externalErrorExitDesc ("pthread_join() failed"); 1986 #if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID) 1987 if (test_tls && (TLS_LIB_GNUTLS != use_tls_tool)) 1988 { 1989 if ((pid_t) -1 == waitpid (pid, NULL, 0)) 1990 externalErrorExitDesc ("waitpid() failed"); 1991 } 1992 #endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */ 1993 if (! client_done) 1994 externalErrorExitDesc ("The client thread has not signalled " \ 1995 "successful finish"); 1996 if (! app_done) 1997 externalErrorExitDesc ("The application thread has not signalled " \ 1998 "successful finish"); 1999 MHD_stop_daemon (d); 2000 return 0; 2001 } 2002 2003 2004 enum test_msg_type 2005 { 2006 test_msg_large_app_data, 2007 test_msg_large_rclient_data, 2008 test_msg_vlarge_app_data, 2009 test_msg_vlarge_rclient_data 2010 }; 2011 2012 /** 2013 * Initialise test message data 2014 * @param buf the pointer to the buffer to fill with the test data 2015 * @param buf_size the size of the @a buf 2016 * @param msg_type the type of the data to fill the @a buf 2017 * @return the @a buf pointer 2018 */ 2019 static void * 2020 init_test_msg (void *buf, size_t buf_size, enum test_msg_type msg_type) 2021 { 2022 size_t i; 2023 char *const text_buf = (char *) buf; 2024 uint8_t *const bin_buf = (uint8_t *) buf; 2025 if (0 == buf_size) 2026 return buf; 2027 switch (msg_type) 2028 { 2029 case test_msg_large_app_data: 2030 case test_msg_large_rclient_data: 2031 /* Simulate text data */ 2032 for (i = 0; i < buf_size; ++i) 2033 { 2034 size_t pos; 2035 if (test_msg_large_app_data == msg_type) 2036 pos = i + 43; 2037 else 2038 pos = i + 26; 2039 if ((0 == i) || (2 == pos % 100) ) 2040 text_buf[i] = 2041 (char) (unsigned char) ((test_msg_large_app_data == msg_type) ? 2042 ('Z' - pos % ('Z' - 'A' + 1)) : 2043 ('A' + pos % ('Z' - 'A' + 1))); 2044 else if (0 == pos % 100) 2045 text_buf[i] = '.'; 2046 else if (1 == pos % 100) 2047 text_buf[i] = ' '; 2048 else if ((99 != pos % 100) && (2 != pos % 100) && (0 == pos % 5)) 2049 text_buf[i] = ' '; 2050 else if (test_msg_large_app_data == msg_type) 2051 text_buf[i] = (char) (unsigned char) ('z' - pos % ('z' - 'a' + 1)); 2052 else 2053 text_buf[i] = (char) (unsigned char) ('a' + pos % ('z' - 'a' + 1)); 2054 } 2055 break; 2056 case test_msg_vlarge_app_data: 2057 /* Simulate binary data */ 2058 for (i = 0; i < buf_size; ++i) 2059 { 2060 bin_buf[i] = (uint8_t) ((i + 182) & 0xFF); 2061 } 2062 break; 2063 case test_msg_vlarge_rclient_data: 2064 /* Simulate binary data */ 2065 for (i = 0; i < buf_size; ++i) 2066 { 2067 bin_buf[i] = (uint8_t) ((111 - i) & 0xFF); 2068 } 2069 break; 2070 default: 2071 exit (99); 2072 break; 2073 } 2074 return buf; 2075 } 2076 2077 2078 /** 2079 * Perform initialisation of variables used in all check in this test 2080 * @return true if succeed, 2081 * false if failed. 2082 */ 2083 static bool 2084 global_test_init (void) 2085 { 2086 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 2087 global_port = 0; 2088 else 2089 { 2090 global_port = 1090; 2091 if (test_tls) 2092 global_port += 1U << 0; 2093 if (use_large) 2094 global_port += 1U << 1; 2095 else if (use_vlarge) 2096 global_port += 1U << 2; 2097 } 2098 if (use_large || use_vlarge) 2099 { 2100 unsigned int i; 2101 size_t alloc_size; 2102 alloc_size = use_vlarge ? (64U * 1024U) : (17U * 1024U); 2103 for (i = 0; i < (sizeof(alloc_ptr) / sizeof(alloc_ptr[0])); ++i) 2104 { 2105 alloc_ptr[i] = malloc (alloc_size); 2106 if (NULL == alloc_ptr[i]) 2107 { 2108 for (--i; i < (sizeof(alloc_ptr) / sizeof(alloc_ptr[0])); --i) 2109 { 2110 free (alloc_ptr[i]); 2111 } 2112 return false; 2113 } 2114 } 2115 2116 rclient_msg_size = alloc_size; 2117 rclient_msg = init_test_msg (alloc_ptr[0], rclient_msg_size, 2118 use_vlarge ? 2119 test_msg_vlarge_rclient_data : 2120 test_msg_large_rclient_data); 2121 app_msg_size = alloc_size; 2122 app_msg = init_test_msg (alloc_ptr[1], app_msg_size, 2123 use_vlarge ? 2124 test_msg_vlarge_app_data : 2125 test_msg_large_app_data); 2126 } 2127 else 2128 { 2129 unsigned int i; 2130 for (i = 0; i < (sizeof(alloc_ptr) / sizeof(alloc_ptr[0])); ++i) 2131 alloc_ptr[i] = NULL; 2132 2133 rclient_msg_size = MHD_STATICSTR_LEN_ ("Hello"); 2134 rclient_msg = "Hello"; 2135 app_msg_size = MHD_STATICSTR_LEN_ ("World"); 2136 app_msg = "World"; 2137 } 2138 return true; 2139 } 2140 2141 2142 /** 2143 * Perform de-initialisation of variables with memory de-allocation if required. 2144 */ 2145 static void 2146 global_test_deinit (void) 2147 { 2148 unsigned int i; 2149 for (i = ((sizeof(alloc_ptr) / sizeof(alloc_ptr[0])) - 1); 2150 i < (sizeof(alloc_ptr) / sizeof(alloc_ptr[0])); 2151 --i) 2152 { 2153 if (NULL != alloc_ptr[i]) 2154 free (alloc_ptr[i]); 2155 } 2156 } 2157 2158 2159 int 2160 main (int argc, 2161 char *const *argv) 2162 { 2163 unsigned int error_count = 0; 2164 unsigned int res; 2165 2166 use_vlarge = (0 != has_in_name (argv[0], "_vlarge")); 2167 use_large = (! use_vlarge) && (0 != has_in_name (argv[0], "_large")); 2168 2169 use_tls_tool = TLS_CLI_NO_TOOL; 2170 test_tls = has_in_name (argv[0], "_tls"); 2171 2172 verbose = ! (has_param (argc, argv, "-q") || 2173 has_param (argc, argv, "--quiet") || 2174 has_param (argc, argv, "-s") || 2175 has_param (argc, argv, "--silent")); 2176 2177 if ((((int) ((~((unsigned int) 0U)) >> 1)) / 1000) < test_timeout) 2178 { 2179 fprintf (stderr, "The test timeout value (%d) is too large.\n" 2180 "The test cannot run.\n", test_timeout); 2181 fprintf (stderr, "The maximum allowed timeout value is %d.\n", 2182 (((int) ((~((unsigned int) 0U)) >> 1)) / 1000)); 2183 return 3; 2184 } 2185 2186 if (test_tls) 2187 { 2188 use_tls_tool = TLS_LIB_GNUTLS; /* Should be always available as MHD uses it. */ 2189 #ifdef HTTPS_SUPPORT 2190 if (has_param (argc, argv, "--use-gnutls-cli")) 2191 use_tls_tool = TLS_CLI_GNUTLS; 2192 else if (has_param (argc, argv, "--use-openssl")) 2193 use_tls_tool = TLS_CLI_OPENSSL; 2194 else if (has_param (argc, argv, "--use-gnutls-lib")) 2195 use_tls_tool = TLS_LIB_GNUTLS; 2196 #if defined(HAVE_FORK) && defined(HAVE_WAITPID) 2197 else if (0 == system ("gnutls-cli --version 1> /dev/null 2> /dev/null")) 2198 use_tls_tool = TLS_CLI_GNUTLS; 2199 else if (0 == system ("openssl version 1> /dev/null 2> /dev/null")) 2200 use_tls_tool = TLS_CLI_OPENSSL; 2201 #endif /* HAVE_FORK && HAVE_WAITPID */ 2202 if (verbose) 2203 { 2204 switch (use_tls_tool) 2205 { 2206 case TLS_CLI_GNUTLS: 2207 printf ("GnuTLS-CLI will be used for testing.\n"); 2208 break; 2209 case TLS_CLI_OPENSSL: 2210 printf ("Command line version of OpenSSL will be used for testing.\n"); 2211 break; 2212 case TLS_LIB_GNUTLS: 2213 printf ("GnuTLS library will be used for testing.\n"); 2214 break; 2215 case TLS_CLI_NO_TOOL: 2216 default: 2217 externalErrorExitDesc ("Wrong 'use_tls_tool' value"); 2218 } 2219 } 2220 if ( (TLS_LIB_GNUTLS == use_tls_tool) && 2221 (GNUTLS_E_SUCCESS != gnutls_global_init ()) ) 2222 externalErrorExitDesc ("gnutls_global_init() failed"); 2223 2224 #else /* ! HTTPS_SUPPORT */ 2225 fprintf (stderr, "HTTPS support was disabled by configure.\n"); 2226 return 77; 2227 #endif /* ! HTTPS_SUPPORT */ 2228 } 2229 2230 if (! global_test_init ()) 2231 { 2232 #ifdef HTTPS_SUPPORT 2233 if (test_tls && (TLS_LIB_GNUTLS == use_tls_tool)) 2234 gnutls_global_deinit (); 2235 #endif /* HTTPS_SUPPORT */ 2236 fprintf (stderr, "Failed to initialise the test.\n"); 2237 return 99; 2238 } 2239 2240 /* run tests */ 2241 if (verbose) 2242 printf ("Starting HTTP \"Upgrade\" tests with %s connections.\n", 2243 test_tls ? "TLS" : "plain"); 2244 /* try external select */ 2245 res = test_upgrade (0, 2246 0); 2247 fflush_allstd (); 2248 error_count += res; 2249 if (res) 2250 fprintf (stderr, 2251 "FAILED: Upgrade with external select, return code %u.\n", 2252 res); 2253 else if (verbose) 2254 printf ("PASSED: Upgrade with external select.\n"); 2255 2256 /* Try external auto */ 2257 res = test_upgrade (MHD_USE_AUTO, 2258 0); 2259 fflush_allstd (); 2260 error_count += res; 2261 if (res) 2262 fprintf (stderr, 2263 "FAILED: Upgrade with external 'auto', return code %u.\n", 2264 res); 2265 else if (verbose) 2266 printf ("PASSED: Upgrade with external 'auto'.\n"); 2267 2268 #ifdef EPOLL_SUPPORT 2269 res = test_upgrade (MHD_USE_EPOLL, 2270 0); 2271 fflush_allstd (); 2272 error_count += res; 2273 if (res) 2274 fprintf (stderr, 2275 "FAILED: Upgrade with external select with EPOLL, return code %u.\n", 2276 res); 2277 else if (verbose) 2278 printf ("PASSED: Upgrade with external select with EPOLL.\n"); 2279 #endif 2280 2281 /* Test thread-per-connection */ 2282 res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD 2283 | MHD_USE_THREAD_PER_CONNECTION, 2284 0); 2285 fflush_allstd (); 2286 error_count += res; 2287 if (res) 2288 fprintf (stderr, 2289 "FAILED: Upgrade with thread per connection, return code %u.\n", 2290 res); 2291 else if (verbose) 2292 printf ("PASSED: Upgrade with thread per connection.\n"); 2293 2294 res = test_upgrade (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD 2295 | MHD_USE_THREAD_PER_CONNECTION, 2296 0); 2297 fflush_allstd (); 2298 error_count += res; 2299 if (res) 2300 fprintf (stderr, 2301 "FAILED: Upgrade with thread per connection and 'auto', return code %u.\n", 2302 res); 2303 else if (verbose) 2304 printf ("PASSED: Upgrade with thread per connection and 'auto'.\n"); 2305 #ifdef HAVE_POLL 2306 res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD 2307 | MHD_USE_THREAD_PER_CONNECTION | MHD_USE_POLL, 2308 0); 2309 fflush_allstd (); 2310 error_count += res; 2311 if (res) 2312 fprintf (stderr, 2313 "FAILED: Upgrade with thread per connection and poll, return code %u.\n", 2314 res); 2315 else if (verbose) 2316 printf ("PASSED: Upgrade with thread per connection and poll.\n"); 2317 #endif /* HAVE_POLL */ 2318 2319 /* Test different event loops, with and without thread pool */ 2320 res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD, 2321 0); 2322 fflush_allstd (); 2323 error_count += res; 2324 if (res) 2325 fprintf (stderr, 2326 "FAILED: Upgrade with internal select, return code %u.\n", 2327 res); 2328 else if (verbose) 2329 printf ("PASSED: Upgrade with internal select.\n"); 2330 res = test_upgrade (MHD_USE_INTERNAL_POLLING_THREAD, 2331 2); 2332 fflush_allstd (); 2333 error_count += res; 2334 if (res) 2335 fprintf (stderr, 2336 "FAILED: Upgrade with internal select with thread pool, return code %u.\n", 2337 res); 2338 else if (verbose) 2339 printf ("PASSED: Upgrade with internal select with thread pool.\n"); 2340 res = test_upgrade (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD, 2341 0); 2342 fflush_allstd (); 2343 error_count += res; 2344 if (res) 2345 fprintf (stderr, 2346 "FAILED: Upgrade with internal 'auto' return code %u.\n", 2347 res); 2348 else if (verbose) 2349 printf ("PASSED: Upgrade with internal 'auto'.\n"); 2350 res = test_upgrade (MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD, 2351 2); 2352 fflush_allstd (); 2353 error_count += res; 2354 if (res) 2355 fprintf (stderr, 2356 "FAILED: Upgrade with internal 'auto' with thread pool, return code %u.\n", 2357 res); 2358 else if (verbose) 2359 printf ("PASSED: Upgrade with internal 'auto' with thread pool.\n"); 2360 #ifdef HAVE_POLL 2361 res = test_upgrade (MHD_USE_POLL_INTERNAL_THREAD, 2362 0); 2363 fflush_allstd (); 2364 error_count += res; 2365 if (res) 2366 fprintf (stderr, 2367 "FAILED: Upgrade with internal poll, return code %u.\n", 2368 res); 2369 else if (verbose) 2370 printf ("PASSED: Upgrade with internal poll.\n"); 2371 res = test_upgrade (MHD_USE_POLL_INTERNAL_THREAD, 2372 2); 2373 fflush_allstd (); 2374 if (res) 2375 fprintf (stderr, 2376 "FAILED: Upgrade with internal poll with thread pool, return code %u.\n", 2377 res); 2378 else if (verbose) 2379 printf ("PASSED: Upgrade with internal poll with thread pool.\n"); 2380 #endif 2381 #ifdef EPOLL_SUPPORT 2382 res = test_upgrade (MHD_USE_EPOLL_INTERNAL_THREAD, 2383 0); 2384 fflush_allstd (); 2385 if (res) 2386 fprintf (stderr, 2387 "FAILED: Upgrade with internal epoll, return code %u.\n", 2388 res); 2389 else if (verbose) 2390 printf ("PASSED: Upgrade with internal epoll.\n"); 2391 res = test_upgrade (MHD_USE_EPOLL_INTERNAL_THREAD, 2392 2); 2393 fflush_allstd (); 2394 if (res) 2395 fprintf (stderr, 2396 "FAILED: Upgrade with internal epoll, return code %u.\n", 2397 res); 2398 else if (verbose) 2399 printf ("PASSED: Upgrade with internal epoll.\n"); 2400 #endif 2401 /* report result */ 2402 if (0 != error_count) 2403 fprintf (stderr, 2404 "Error (code: %u)\n", 2405 error_count); 2406 2407 global_test_deinit (); 2408 #ifdef HTTPS_SUPPORT 2409 if (test_tls && (TLS_LIB_GNUTLS == use_tls_tool)) 2410 gnutls_global_deinit (); 2411 #endif /* HTTPS_SUPPORT */ 2412 2413 return error_count != 0; /* 0 == pass */ 2414 }