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