test_upgrade.c (56297B)
1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */ 2 /* 3 This file is part of GNU libmicrohttpd. 4 Copyright (C) 2016-2020 Christian Grothoff 5 Copyright (C) 2016-2024 Evgeny Grin (Karlson2k) 6 7 GNU libmicrohttpd is free software; you can redistribute it and/or 8 modify it under the terms of the GNU Lesser General Public 9 License as published by the Free Software Foundation; either 10 version 2.1 of the License, or (at your option) any later version. 11 12 GNU libmicrohttpd is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 Lesser General Public License for more details. 16 17 Alternatively, you can redistribute GNU libmicrohttpd and/or 18 modify it under the terms of the GNU General Public License as 19 published by the Free Software Foundation; either version 2 of 20 the License, or (at your option) any later version, together 21 with the eCos exception, as follows: 22 23 As a special exception, if other files instantiate templates or 24 use macros or inline functions from this file, or you compile this 25 file and link it with other works to produce a work based on this 26 file, this file does not by itself cause the resulting work to be 27 covered by the GNU General Public License. However the source code 28 for this file must still be made available in accordance with 29 section (3) of the GNU General Public License v2. 30 31 This exception does not invalidate any other reasons why a work 32 based on this file might be covered by the GNU General Public 33 License. 34 35 You should have received copies of the GNU Lesser General Public 36 License and the GNU General Public License along with this library; 37 if not, see <https://www.gnu.org/licenses/>. 38 */ 39 40 /** 41 * @file src/tests/upgrade/test_upgrade.c 42 * @brief Testcase for libmicrohttpd upgrading a connection 43 * @author Christian Grothoff 44 * @author Karlson2k (Evgeny Grin) 45 */ 46 47 #include "mhd_sys_options.h" 48 #include <stddef.h> 49 #include <stdint.h> 50 #include <string.h> 51 #include <stdlib.h> 52 #include <stdio.h> 53 #include <pthread.h> 54 #include <errno.h> 55 #ifdef HAVE_UNISTD_H 56 # include <unistd.h> 57 #endif 58 #ifdef HAVE_STDBOOL_H 59 # include <stdbool.h> 60 #endif /* HAVE_STDBOOL_H */ 61 62 #include "sys_sockets_headers.h" 63 #include "sys_sockets_types.h" 64 #include "sys_ip_headers.h" 65 #include "mhd_sockets_macros.h" 66 #include <fcntl.h> 67 68 #include "microhttpd2.h" 69 70 #include "mhdt_has_in_name.h" 71 #include "mhdt_has_param.h" 72 73 #ifdef HTTPS_SUPPORT 74 # include <gnutls/gnutls.h> 75 # include "tls_test_keys.h" 76 77 # if defined(HAVE_FORK) && defined(HAVE_WAITPID) 78 # include <sys/types.h> 79 # include <sys/wait.h> 80 # endif /* HAVE_FORK && HAVE_WAITPID */ 81 #endif /* HTTPS_SUPPORT */ 82 83 #if defined(MHD_SOCKETS_KIND_POSIX) 84 # ifdef MHD_SOCKETS_KIND_WINSOCK 85 # error Both MHD_SOCKETS_KIND_POSIX and MHD_SOCKETS_KIND_WINSOCK are defined 86 # endif /* MHD_SOCKETS_KIND_WINSOCK */ 87 #elif ! defined(MHD_SOCKETS_KIND_WINSOCK) 88 # error Neither MHD_SOCKETS_KIND_POSIX nor MHD_SOCKETS_KIND_WINSOCK are defined 89 #endif /* MHD_SOCKETS_KIND_WINSOCK */ 90 91 92 #ifndef mhd_SSTR_LEN 93 /** 94 * Determine length of static string / macro strings at compile time. 95 */ 96 #define mhd_SSTR_LEN(macro) (sizeof(macro) / sizeof(char) - 1) 97 #endif /* ! mhd_SSTR_LEN */ 98 99 #if ! defined(SHUT_WR) && defined(SD_SEND) 100 # define SHUT_WR SD_SEND 101 #endif 102 103 #if ! defined(SHUT_RD) && defined(SD_RECEIVE) 104 # define SHUT_RD SD_RECEIVE 105 #endif 106 107 #if ! defined(SHUT_RDWR) && defined(SD_BOTH) 108 # define SHUT_RDWR SD_BOTH 109 #endif 110 111 #if defined(MHD_SOCKETS_KIND_POSIX) 112 # if defined(ENETUNREACH) 113 # define mhdt_SCKT_HARD_ERR ENETUNREACH 114 # elif defined(ENOTCONN) 115 # define mhdt_SCKT_HARD_ERR ENOTCONN 116 # elif defined(ECONNRESET) 117 # define mhdt_SCKT_HARD_ERR ECONNRESET 118 # elif defined(EPIPE) 119 # define mhdt_SCKT_HARD_ERR EPIPE 120 # elif defined(EBADF) 121 # define mhdt_SCKT_HARD_ERR EBADF 122 # else 123 # define mhdt_SCKT_HARD_ERR 99 /* Fallback, never used in practice */ 124 # endif 125 #else /* MHD_SOCKETS_KIND_WINSOCK */ 126 # define mhdt_SCKT_HARD_ERR WSAENETRESET 127 #endif 128 129 130 MHD_NORETURN_ static void 131 _externalErrorExit_func (const char *errDesc, const char *funcName, 132 int lineNum, int test_failed) 133 { 134 int last_errno = errno; 135 fflush (stdout); 136 if ((NULL != errDesc) && (0 != errDesc[0])) 137 fprintf (stderr, "!!! %s", errDesc); 138 else 139 fprintf (stderr, "!!! System or external library call failed"); 140 if ((NULL != funcName) && (0 != funcName[0])) 141 fprintf (stderr, " in %s", funcName); 142 if (0 < lineNum) 143 fprintf (stderr, " at line %d", lineNum); 144 145 fprintf (stderr, ".\nLast errno value: %d (%s)\n", last_errno, 146 strerror (last_errno)); 147 #ifdef MHD_SOCKETS_KIND_WINSOCK 148 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); 149 #endif /* MHD_SOCKETS_KIND_WINSOCK */ 150 fflush (stderr); 151 exit (test_failed ? 9 : 99); 152 } 153 154 155 MHD_NORETURN_ static void 156 _mhdErrorExit_func (const char *errDesc, const char *funcName, int lineNum) 157 { 158 int last_errno = errno; 159 fflush (stdout); 160 if ((NULL != errDesc) && (0 != errDesc[0])) 161 fprintf (stderr, "!!! %s", errDesc); 162 else 163 fprintf (stderr, "!!! MHD unexpected error"); 164 if ((NULL != funcName) && (0 != funcName[0])) 165 fprintf (stderr, " in %s", funcName); 166 if (0 < lineNum) 167 fprintf (stderr, " at line %d", lineNum); 168 169 fprintf (stderr, ".\nLast errno value: %d (%s)\n", last_errno, 170 strerror (last_errno)); 171 172 fflush (stderr); 173 exit (8); 174 } 175 176 177 static void 178 _testErrorLog_func (const char *errDesc, const char *funcName, int lineNum) 179 { 180 int last_errno = errno; 181 fflush (stdout); 182 if ((NULL != errDesc) && (0 != errDesc[0])) 183 fprintf (stderr, "!!! %s", errDesc); 184 else 185 fprintf (stderr, "!!! System or external library call resulted in error"); 186 if ((NULL != funcName) && (0 != funcName[0])) 187 fprintf (stderr, " in %s", funcName); 188 if (0 < lineNum) 189 fprintf (stderr, " at line %d", lineNum); 190 191 fprintf (stderr, ".\nLast errno value: %d (%s)\n", last_errno, 192 strerror (last_errno)); 193 #ifdef MHD_SOCKETS_KIND_WINSOCK 194 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); 195 #endif /* MHD_SOCKETS_KIND_WINSOCK */ 196 fflush (stderr); 197 } 198 199 200 #ifdef MHD_HAVE_MHD_FUNC_ 201 #define externalErrorExit() \ 202 _externalErrorExit_func (NULL, MHD_FUNC_, __LINE__, 0) 203 #define externalErrorExitDesc(errDesc) \ 204 _externalErrorExit_func (errDesc, MHD_FUNC_, __LINE__, 0) 205 #define testFailedExitDesc(errDesc) \ 206 _externalErrorExit_func (errDesc, MHD_FUNC_, __LINE__, ! 0) 207 #define mhdErrorExit(ignore) \ 208 _mhdErrorExit_func (NULL, MHD_FUNC_, __LINE__) 209 #define mhdErrorExitDesc(errDesc) \ 210 _mhdErrorExit_func (errDesc, MHD_FUNC_, __LINE__) 211 #define testErrorLog(ignore) \ 212 _testErrorLog_func (NULL, MHD_FUNC_, __LINE__) 213 #define testErrorLogDesc(errDesc) \ 214 _testErrorLog_func (errDesc, MHD_FUNC_, __LINE__) 215 #else /* ! MHD_HAVE_MHD_FUNC_ */ 216 #define externalErrorExit() _externalErrorExit_func (NULL, NULL, __LINE__, 0) 217 #define externalErrorExitDesc(errDesc) \ 218 _externalErrorExit_func (errDesc, NULL, __LINE__, 0) 219 #define testFailedExitDesc(errDesc) \ 220 _externalErrorExit_func (errDesc, NULL, __LINE__, ! 0) 221 #define mhdErrorExit(ignore) _mhdErrorExit_func (NULL, NULL, __LINE__) 222 #define mhdErrorExitDesc(errDesc) _mhdErrorExit_func (errDesc, NULL, __LINE__) 223 #define testErrorLog(ignore) _testErrorLog_func (NULL, NULL, __LINE__) 224 #define testErrorLogDesc(errDesc) _testErrorLog_func (errDesc, NULL, __LINE__) 225 #endif /* ! MHD_HAVE_MHD_FUNC_ */ 226 227 /* ** External parameters ** */ 228 static bool use_large; 229 230 static bool use_vlarge; 231 232 static bool test_tls; 233 234 static int verbose = 0; 235 236 enum tls_tool 237 { 238 TLS_CLI_NO_TOOL = 0, 239 TLS_CLI_GNUTLS, 240 TLS_CLI_OPENSSL, 241 TLS_LIB_GNUTLS 242 }; 243 244 static enum tls_tool use_tls_tool; 245 246 247 /* ** Internal values ** */ 248 249 /* Could be increased to facilitate debugging */ 250 static int test_timeout = 5; 251 252 static uint_least16_t global_port; 253 254 static const void *rclient_msg; 255 256 static size_t rclient_msg_size; 257 258 static const void *app_msg; 259 260 static size_t app_msg_size; 261 262 static void *alloc_ptr[2] = {NULL, NULL}; 263 264 265 static void 266 fflush_allstd (void) 267 { 268 fflush (stderr); 269 fflush (stdout); 270 } 271 272 273 #if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID) 274 /** 275 * Fork child that connects via GnuTLS-CLI to our @a port. Allows us to 276 * talk to our port over a socket in @a sp without having to worry 277 * about TLS. 278 * 279 * @param location where the socket is returned 280 * @return -1 on error, otherwise PID of TLS child process 281 */ 282 static pid_t 283 gnutlscli_connect (int *sock, 284 uint16_t port) 285 { 286 pid_t chld; 287 int sp[2]; 288 char destination[30]; 289 290 if (0 != socketpair (AF_UNIX, 291 SOCK_STREAM, 292 0, 293 sp)) 294 { 295 testErrorLogDesc ("socketpair() failed"); 296 return (pid_t) -1; 297 } 298 chld = fork (); 299 if (0 != chld) 300 { 301 *sock = sp[1]; 302 mhd_socket_close (sp[0]); 303 return chld; 304 } 305 mhd_socket_close (sp[1]); 306 (void) close (0); 307 (void) close (1); 308 if (-1 == dup2 (sp[0], 0)) 309 externalErrorExitDesc ("dup2() failed"); 310 if (-1 == dup2 (sp[0], 1)) 311 externalErrorExitDesc ("dup2() failed"); 312 mhd_socket_close (sp[0]); 313 if (TLS_CLI_GNUTLS == use_tls_tool) 314 { 315 snprintf (destination, 316 sizeof(destination), 317 "%u", 318 (unsigned int) port); 319 execlp ("gnutls-cli", 320 "gnutls-cli", 321 "--insecure", 322 "-p", 323 destination, 324 "127.0.0.1", 325 (char *) NULL); 326 } 327 else if (TLS_CLI_OPENSSL == use_tls_tool) 328 { 329 snprintf (destination, 330 sizeof(destination), 331 "127.0.0.1:%u", 332 (unsigned int) port); 333 execlp ("openssl", 334 "openssl", 335 "s_client", 336 "-connect", 337 destination, 338 "-verify", 339 "1", 340 (char *) NULL); 341 } 342 _exit (1); 343 } 344 345 346 #endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */ 347 348 349 #if 0 /* Unused code */ 350 /** 351 * Change socket to blocking. 352 * 353 * @param fd the socket to manipulate 354 */ 355 static void 356 make_blocking (MHD_Socket fd) 357 { 358 #if defined(MHD_SOCKETS_KIND_POSIX) 359 int flags; 360 361 flags = fcntl (fd, F_GETFL); 362 if (-1 == flags) 363 externalErrorExitDesc ("fcntl() failed"); 364 if ((flags & ~O_NONBLOCK) != flags) 365 if (-1 == fcntl (fd, F_SETFL, flags & ~O_NONBLOCK)) 366 externalErrorExitDesc ("fcntl() failed"); 367 #elif defined(MHD_SOCKETS_KIND_WINSOCK) 368 unsigned long flags = 0; 369 370 if (0 != ioctlsocket (fd, (int) FIONBIO, &flags)) 371 externalErrorExitDesc ("ioctlsocket() failed"); 372 #endif /* MHD_SOCKETS_KIND_WINSOCK */ 373 } 374 375 376 #endif /* Unused code */ 377 378 379 /** 380 * Change socket to non-blocking. 381 * 382 * @param fd the socket to manipulate 383 */ 384 static void 385 make_nonblocking (MHD_Socket fd) 386 { 387 #if defined(MHD_SOCKETS_KIND_POSIX) 388 int flags; 389 390 flags = fcntl (fd, F_GETFL); 391 if (-1 == flags) 392 externalErrorExitDesc ("fcntl() failed"); 393 if (O_NONBLOCK != (flags & O_NONBLOCK)) 394 if (-1 == fcntl (fd, F_SETFL, flags | O_NONBLOCK)) 395 externalErrorExitDesc ("fcntl() failed"); 396 #elif defined(MHD_SOCKETS_KIND_WINSOCK) 397 unsigned long flags = 1; 398 399 if (0 != ioctlsocket (fd, (int) FIONBIO, &flags)) 400 externalErrorExitDesc ("ioctlsocket() failed"); 401 #endif /* MHD_SOCKETS_KIND_WINSOCK */ 402 } 403 404 405 /** 406 * Enable TCP_NODELAY on TCP/IP socket. 407 * 408 * @param fd the socket to manipulate 409 */ 410 static void 411 make_nodelay (MHD_Socket fd) 412 { 413 #ifdef TCP_NODELAY 414 const mhd_SCKT_OPT_BOOL on_val = 1; 415 416 if (0 == setsockopt (fd, 417 IPPROTO_TCP, 418 TCP_NODELAY, 419 (const void *) &on_val, 420 sizeof (on_val))) 421 return; /* Success exit point */ 422 423 #ifndef MHD_SOCKETS_KIND_WINSOCK 424 fprintf (stderr, "Failed to enable TCP_NODELAY on socket (ignored). " 425 "errno: %d (%s)\n", (int) errno, strerror (errno)); 426 #else /* MHD_SOCKETS_KIND_WINSOCK */ 427 fprintf (stderr, "Failed to enable TCP_NODELAY on socket (ignored). " 428 "WSAGetLastError() value: %d\n", (int) WSAGetLastError ()); 429 #endif /* MHD_SOCKETS_KIND_WINSOCK */ 430 fflush (stderr); 431 #endif /* TCP_NODELAY */ 432 } 433 434 435 /** 436 * Type of the socket in struct wr_socket 437 */ 438 enum wr_type 439 { 440 wr_invalid = 0, 441 wr_plain = 1, 442 wr_tls = 2 443 }; 444 445 /** 446 * Wrapper structure for plain&TLS sockets 447 */ 448 struct wr_socket 449 { 450 /** 451 * Real network socket 452 */ 453 MHD_Socket fd; 454 455 /** 456 * Type of this socket 457 */ 458 enum wr_type t; 459 460 bool is_nonblocking; 461 462 bool eof_recieved; 463 #ifdef HTTPS_SUPPORT 464 /** 465 * TLS credentials 466 */ 467 gnutls_certificate_credentials_t tls_crd; 468 469 /** 470 * TLS session. 471 */ 472 gnutls_session_t tls_s; 473 474 /** 475 * TLS handshake already succeed? 476 */ 477 bool tls_connected; 478 #endif 479 }; 480 481 482 /** 483 * Get underlying real socket. 484 * @return FD of real socket 485 */ 486 #define wr_fd(s) ((s)->fd) 487 488 489 #if 0 /* Unused code */ 490 static void 491 wr_make_blocking (struct wr_socket *s) 492 { 493 if (s->is_nonblocking) 494 make_blocking (s->fd); 495 s->is_nonblocking = false; 496 } 497 498 499 #endif /* Unused code */ 500 501 502 static void 503 wr_make_nonblocking (struct wr_socket *s) 504 { 505 if (! s->is_nonblocking) 506 make_nonblocking (s->fd); 507 s->is_nonblocking = true; 508 } 509 510 511 /** 512 * Create wr_socket with plain TCP underlying socket 513 * @return created socket on success, NULL otherwise 514 */ 515 static struct wr_socket * 516 wr_create_plain_sckt (void) 517 { 518 struct wr_socket *s = 519 (struct wr_socket *) malloc (sizeof(struct wr_socket)); 520 if (NULL == s) 521 { 522 testErrorLogDesc ("malloc() failed"); 523 return NULL; 524 } 525 s->t = wr_plain; 526 s->eof_recieved = false; 527 s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); 528 s->is_nonblocking = false; 529 if (MHD_INVALID_SOCKET != s->fd) 530 { 531 make_nodelay (s->fd); 532 return s; /* Success */ 533 } 534 testErrorLogDesc ("socket() failed"); 535 free (s); 536 return NULL; 537 } 538 539 540 /** 541 * Create wr_socket with TLS TCP underlying socket 542 * @return created socket on success, NULL otherwise 543 */ 544 static struct wr_socket * 545 wr_create_tls_sckt (void) 546 { 547 #ifdef HTTPS_SUPPORT 548 struct wr_socket *s = malloc (sizeof(struct wr_socket)); 549 if (NULL == s) 550 { 551 testErrorLogDesc ("malloc() failed"); 552 return NULL; 553 } 554 s->t = wr_tls; 555 s->eof_recieved = false; 556 s->tls_connected = 0; 557 s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); 558 s->is_nonblocking = false; 559 if (MHD_INVALID_SOCKET != s->fd) 560 { 561 make_nodelay (s->fd); 562 if (GNUTLS_E_SUCCESS == gnutls_init (&(s->tls_s), GNUTLS_CLIENT)) 563 { 564 if (GNUTLS_E_SUCCESS == gnutls_set_default_priority (s->tls_s)) 565 { 566 if (GNUTLS_E_SUCCESS == 567 gnutls_certificate_allocate_credentials (&(s->tls_crd))) 568 { 569 if (GNUTLS_E_SUCCESS == gnutls_credentials_set (s->tls_s, 570 GNUTLS_CRD_CERTIFICATE, 571 s->tls_crd)) 572 { 573 #if (GNUTLS_VERSION_NUMBER + 0 >= 0x030109) && ! defined(_WIN64) 574 gnutls_transport_set_int (s->tls_s, (int) (s->fd)); 575 #else /* GnuTLS before 3.1.9 or Win x64 */ 576 gnutls_transport_set_ptr (s->tls_s, 577 (gnutls_transport_ptr_t) \ 578 (intptr_t) (s->fd)); 579 #endif /* GnuTLS before 3.1.9 or Win x64 */ 580 return s; 581 } 582 else 583 testErrorLogDesc ("gnutls_credentials_set() failed"); 584 gnutls_certificate_free_credentials (s->tls_crd); 585 } 586 else 587 testErrorLogDesc ("gnutls_certificate_allocate_credentials() failed"); 588 } 589 else 590 testErrorLogDesc ("gnutls_set_default_priority() failed"); 591 gnutls_deinit (s->tls_s); 592 } 593 else 594 testErrorLogDesc ("gnutls_init() failed"); 595 (void) mhd_socket_close (s->fd); 596 } 597 else 598 testErrorLogDesc ("socket() failed"); 599 free (s); 600 #endif /* HTTPS_SUPPORT */ 601 return NULL; 602 } 603 604 605 #if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID) 606 607 /** 608 * Create wr_socket with plain TCP underlying socket 609 * from already created TCP socket. 610 * @param plain_sk real TCP socket 611 * @return created socket on success, NULL otherwise 612 */ 613 static struct wr_socket * 614 wr_create_from_plain_sckt (MHD_Socket plain_sk) 615 { 616 struct wr_socket *s = malloc (sizeof(struct wr_socket)); 617 618 if (NULL == s) 619 { 620 testErrorLogDesc ("malloc() failed"); 621 return NULL; 622 } 623 s->t = wr_plain; 624 s->eof_recieved = false; 625 s->fd = plain_sk; 626 s->is_nonblocking = false; /* The actual mode is unknown */ 627 wr_make_nonblocking (s); /* Force set mode to have correct status */ 628 make_nodelay (s->fd); 629 return s; 630 } 631 632 633 #endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */ 634 635 #if 0 /* Disabled code */ 636 /** 637 * Check whether shutdown of connection was received from remote 638 * @param s socket to check 639 * @return zero if shutdown signal has not been received, 640 * 1 if shutdown signal was already received 641 */ 642 static int 643 wr_is_eof_received (struct wr_socket *s) 644 { 645 return s->eof_recieved ? 1 : 0; 646 } 647 648 649 #endif /* Disabled code */ 650 651 652 enum wr_wait_for_type 653 { 654 WR_WAIT_FOR_RECV = 0, 655 WR_WAIT_FOR_SEND = 1 656 }; 657 658 static bool 659 wr_wait_socket_ready_noabort_ (struct wr_socket *s, 660 int timeout_ms, 661 enum wr_wait_for_type wait_for) 662 { 663 fd_set fds; 664 int sel_res; 665 struct timeval tmo; 666 struct timeval *tmo_ptr; 667 668 #ifndef MHD_SOCKETS_KIND_WINSOCK 669 if (FD_SETSIZE <= s->fd) 670 externalErrorExitDesc ("Too large FD value"); 671 #endif /* ! MHD_SOCKETS_KIND_WINSOCK */ 672 FD_ZERO (&fds); 673 FD_SET (s->fd, &fds); 674 if (0 <= timeout_ms) 675 { 676 #if ! defined(_WIN32) || defined(__CYGWIN__) 677 tmo.tv_sec = (time_t) (timeout_ms / 1000); 678 #else /* Native W32 */ 679 tmo.tv_sec = (long) (timeout_ms / 1000); 680 #endif /* Native W32 */ 681 tmo.tv_usec = ((long) (timeout_ms % 1000)) * 1000; 682 tmo_ptr = &tmo; 683 } 684 else 685 tmo_ptr = NULL; /* No timeout */ 686 687 do 688 { 689 if (WR_WAIT_FOR_RECV == wait_for) 690 sel_res = select (1 + (int) s->fd, &fds, NULL, NULL, tmo_ptr); 691 else 692 sel_res = select (1 + (int) s->fd, NULL, &fds, NULL, tmo_ptr); 693 } while (0 > sel_res && mhd_SCKT_ERR_IS_EINTR (mhd_SCKT_GET_LERR ())); 694 695 if (1 == sel_res) 696 return true; 697 698 if (0 == sel_res) 699 fprintf (stderr, "Timeout"); 700 else 701 { 702 #ifndef MHD_SOCKETS_KIND_WINSOCK 703 fprintf (stderr, "Error %d (%s)", (int) errno, strerror (errno)); 704 #else /* MHD_SOCKETS_KIND_WINSOCK */ 705 fprintf (stderr, "Error (WSAGetLastError code: %d)", 706 (int) WSAGetLastError ()); 707 #endif /* MHD_SOCKETS_KIND_WINSOCK */ 708 } 709 fprintf (stderr, " waiting for socket to be available for %s.\n", 710 (WR_WAIT_FOR_RECV == wait_for) ? "receiving" : "sending"); 711 return false; 712 } 713 714 715 static void 716 wr_wait_socket_ready_ (struct wr_socket *s, 717 int timeout_ms, 718 enum wr_wait_for_type wait_for) 719 { 720 if (wr_wait_socket_ready_noabort_ (s, timeout_ms, wait_for)) 721 return; 722 723 if (WR_WAIT_FOR_RECV == wait_for) 724 mhdErrorExitDesc ("Client failed to receive the data"); 725 else 726 mhdErrorExitDesc ("Client failed to send the data"); 727 } 728 729 730 /** 731 * Connect socket to specified address. 732 * @param s socket to use 733 * @param addr address to connect 734 * @param length of structure pointed by @a addr 735 * @param timeout_ms the maximum wait time in milliseconds to send the data, 736 * no limit if negative value is used 737 * @return zero on success, -1 otherwise. 738 */ 739 static int 740 wr_connect_tmo (struct wr_socket *s, 741 const struct sockaddr *addr, 742 unsigned int length, 743 int timeout_ms) 744 { 745 if (0 != connect (s->fd, addr, (socklen_t) length)) 746 { 747 int err; 748 bool connect_completed = false; 749 750 err = mhd_SCKT_GET_LERR (); 751 #if defined(MHD_SOCKETS_KIND_POSIX) 752 while (! connect_completed && (EINTR == err)) 753 { 754 connect_completed = (0 == connect (s->fd, addr, (socklen_t) length)); 755 if (! connect_completed) 756 { 757 err = errno; 758 if (EALREADY == err) 759 err = EINPROGRESS; 760 else if (EISCONN == err) 761 connect_completed = true; 762 } 763 } 764 #endif /* MHD_SOCKETS_KIND_POSIX */ 765 if (! connect_completed && 766 (mhd_SCKT_ERR_IS_INPROGRESS (err) 767 || mhd_SCKT_ERR_IS_EAGAIN (err))) /* No modern system uses EAGAIN, except W32 */ 768 connect_completed = 769 wr_wait_socket_ready_noabort_ (s, timeout_ms, WR_WAIT_FOR_SEND); 770 if (! connect_completed) 771 { 772 testErrorLogDesc ("connect() failed"); 773 return -1; 774 } 775 } 776 if (wr_plain == s->t) 777 return 0; 778 #ifdef HTTPS_SUPPORT 779 if (wr_tls == s->t) 780 { 781 /* Do not try handshake here as 782 * it requires processing on MHD side and 783 * when testing with "external" polling, 784 * test will call MHD processing only 785 * after return from wr_connect(). */ 786 s->tls_connected = 0; 787 return 0; 788 } 789 #endif /* HTTPS_SUPPORT */ 790 testErrorLogDesc ("HTTPS socket connect called, but code does not support" \ 791 " HTTPS sockets"); 792 return -1; 793 } 794 795 796 /** 797 * Connect socket to specified address. 798 * @param s socket to use 799 * @param addr address to connect 800 * @param length of structure pointed by @a addr 801 * @return zero on success, -1 otherwise. 802 */ 803 static int 804 wr_connect (struct wr_socket *s, 805 const struct sockaddr *addr, 806 unsigned int length) 807 { 808 return wr_connect_tmo (s, addr, length, test_timeout * 1000); 809 } 810 811 812 #ifdef HTTPS_SUPPORT 813 /* Only to be called from wr_send() and wr_recv() ! */ 814 static bool 815 wr_handshake_tmo_ (struct wr_socket *s, 816 int timeout_ms) 817 { 818 int res = gnutls_handshake (s->tls_s); 819 820 while ((GNUTLS_E_AGAIN == res) || (GNUTLS_E_INTERRUPTED == res)) 821 { 822 wr_wait_socket_ready_ (s, timeout_ms, 823 gnutls_record_get_direction (s->tls_s) ? 824 WR_WAIT_FOR_SEND : WR_WAIT_FOR_RECV); 825 res = gnutls_handshake (s->tls_s); 826 } 827 if (GNUTLS_E_SUCCESS == res) 828 s->tls_connected = true; 829 else 830 { 831 fprintf (stderr, "The error returned by gnutls_handshake() is " 832 "'%s' ", gnutls_strerror ((int) res)); 833 #if GNUTLS_VERSION_NUMBER >= 0x020600 834 fprintf (stderr, "(%s)\n", gnutls_strerror_name ((int) res)); 835 #else /* GNUTLS_VERSION_NUMBER < 0x020600 */ 836 fprintf (stderr, "(%d)\n", (int) res); 837 #endif /* GNUTLS_VERSION_NUMBER < 0x020600 */ 838 testErrorLogDesc ("gnutls_handshake() failed with hard error"); 839 mhd_SCKT_SET_LERR (mhdt_SCKT_HARD_ERR); /* hard error */ 840 } 841 return s->tls_connected; 842 } 843 844 845 #if 0 /* Unused function */ 846 /* Only to be called from wr_send() and wr_recv() ! */ 847 static bool 848 wr_handshake_ (struct wr_socket *s) 849 { 850 return wr_handshake_tmo_ (s, test_timeout * 1000); 851 } 852 853 854 #endif /* Unused function */ 855 856 #endif /* HTTPS_SUPPORT */ 857 858 859 /** 860 * Send data to remote by socket. 861 * @param s the socket to use 862 * @param buf the buffer with data to send 863 * @param len the length of data in @a buf 864 * @param timeout_ms the maximum wait time in milliseconds to send the data, 865 * no limit if negative value is used 866 * @return number of bytes were sent if succeed, 867 * -1 if failed. Use #mhd_SCKT_GET_LERR() 868 * to get socket error. 869 */ 870 static ssize_t 871 wr_send_tmo (struct wr_socket *s, 872 const void *buf, 873 size_t len, 874 int timeout_ms) 875 { 876 if (wr_plain == s->t) 877 { 878 ssize_t res; 879 while (! 0) 880 { 881 int err; 882 res = mhd_sys_send (s->fd, buf, len); 883 if (0 <= res) 884 break; /* Success */ 885 err = mhd_SCKT_GET_LERR (); 886 if (! mhd_SCKT_ERR_IS_EAGAIN (err) && ! mhd_SCKT_ERR_IS_EINTR (err)) 887 break; /* Failure */ 888 wr_wait_socket_ready_ (s, timeout_ms, WR_WAIT_FOR_SEND); 889 } 890 return res; 891 } 892 #ifdef HTTPS_SUPPORT 893 else if (wr_tls == s->t) 894 { 895 ssize_t ret; 896 if (! s->tls_connected && ! wr_handshake_tmo_ (s, timeout_ms)) 897 return -1; 898 899 while (1) 900 { 901 ret = gnutls_record_send (s->tls_s, buf, len); 902 if (ret >= 0) 903 return ret; 904 if ((GNUTLS_E_AGAIN != ret) && (GNUTLS_E_INTERRUPTED != ret)) 905 break; 906 wr_wait_socket_ready_ (s, timeout_ms, 907 gnutls_record_get_direction (s->tls_s) ? 908 WR_WAIT_FOR_SEND : WR_WAIT_FOR_RECV); 909 } 910 fprintf (stderr, "The error returned by gnutls_record_send() is " 911 "'%s' ", gnutls_strerror ((int) ret)); 912 #if GNUTLS_VERSION_NUMBER >= 0x020600 913 fprintf (stderr, "(%s)\n", gnutls_strerror_name ((int) ret)); 914 #else /* GNUTLS_VERSION_NUMBER < 0x020600 */ 915 fprintf (stderr, "(%d)\n", (int) ret); 916 #endif /* GNUTLS_VERSION_NUMBER < 0x020600 */ 917 testErrorLogDesc ("gnutls_record_send() failed with hard error"); 918 mhd_SCKT_SET_LERR (mhdt_SCKT_HARD_ERR); /* hard error */ 919 return -1; 920 } 921 #endif /* HTTPS_SUPPORT */ 922 testErrorLogDesc ("HTTPS socket send called, but code does not support" \ 923 " HTTPS sockets"); 924 mhd_SCKT_SET_LERR (mhdt_SCKT_HARD_ERR); /* hard error */ 925 return -1; 926 } 927 928 929 /** 930 * Send data to remote by socket. 931 * @param s the socket to use 932 * @param buf the buffer with data to send 933 * @param len the length of data in @a buf 934 * @return number of bytes were sent if succeed, 935 * -1 if failed. Use #mhd_SCKT_GET_LERR() 936 * to get socket error. 937 */ 938 static ssize_t 939 wr_send (struct wr_socket *s, 940 const void *buf, 941 size_t len) 942 { 943 return wr_send_tmo (s, buf, len, test_timeout * 1000); 944 } 945 946 947 /** 948 * Receive data from remote by socket. 949 * @param s the socket to use 950 * @param buf the buffer to store received data 951 * @param len the length of @a buf 952 * @param timeout_ms the maximum wait time in milliseconds to receive the data, 953 * no limit if negative value is used 954 * @return number of bytes were received if succeed, 955 * -1 if failed. Use #mhd_SCKT_GET_LERR() 956 * to get socket error. 957 */ 958 static ssize_t 959 wr_recv_tmo (struct wr_socket *s, 960 void *buf, 961 size_t len, 962 int timeout_ms) 963 { 964 if (wr_plain == s->t) 965 { 966 ssize_t res; 967 while (! 0) 968 { 969 int err; 970 res = mhd_sys_recv (s->fd, buf, len); 971 if (0 == res) 972 s->eof_recieved = true; 973 if (0 <= res) 974 break; /* Success */ 975 err = mhd_SCKT_GET_LERR (); 976 if (! mhd_SCKT_ERR_IS_EAGAIN (err) && ! mhd_SCKT_ERR_IS_EINTR (err)) 977 break; /* Failure */ 978 wr_wait_socket_ready_ (s, timeout_ms, WR_WAIT_FOR_RECV); 979 } 980 return res; 981 } 982 #ifdef HTTPS_SUPPORT 983 if (wr_tls == s->t) 984 { 985 ssize_t ret; 986 if (! s->tls_connected && ! wr_handshake_tmo_ (s, timeout_ms)) 987 return -1; 988 989 while (1) 990 { 991 ret = gnutls_record_recv (s->tls_s, buf, len); 992 if (0 == ret) 993 s->eof_recieved = true; 994 if (ret >= 0) 995 return ret; 996 if ((GNUTLS_E_AGAIN != ret) && (GNUTLS_E_INTERRUPTED != ret)) 997 break; 998 wr_wait_socket_ready_ (s, timeout_ms, 999 gnutls_record_get_direction (s->tls_s) ? 1000 WR_WAIT_FOR_SEND : WR_WAIT_FOR_RECV); 1001 } 1002 1003 fprintf (stderr, "The error returned by gnutls_record_recv() is " 1004 "'%s' ", gnutls_strerror ((int) ret)); 1005 #if GNUTLS_VERSION_NUMBER >= 0x020600 1006 fprintf (stderr, "(%s)\n", gnutls_strerror_name ((int) ret)); 1007 #else /* GNUTLS_VERSION_NUMBER < 0x020600 */ 1008 fprintf (stderr, "(%d)\n", (int) ret); 1009 #endif /* GNUTLS_VERSION_NUMBER < 0x020600 */ 1010 testErrorLogDesc ("gnutls_record_recv() failed with hard error"); 1011 mhd_SCKT_SET_LERR (mhdt_SCKT_HARD_ERR); /* hard error */ 1012 return -1; 1013 } 1014 #endif /* HTTPS_SUPPORT */ 1015 mhd_SCKT_SET_LERR (mhdt_SCKT_HARD_ERR); /* hard error */ 1016 return -1; 1017 } 1018 1019 1020 /** 1021 * Receive data from remote by socket. 1022 * @param s the socket to use 1023 * @param buf the buffer to store received data 1024 * @param len the length of @a buf 1025 * @return number of bytes were received if succeed, 1026 * -1 if failed. Use #mhd_SCKT_GET_LERR() 1027 * to get socket error. 1028 */ 1029 static ssize_t 1030 wr_recv (struct wr_socket *s, 1031 void *buf, 1032 size_t len) 1033 { 1034 return wr_recv_tmo (s, buf, len, test_timeout * 1000); 1035 } 1036 1037 1038 /** 1039 * Shutdown send/write on the socket. 1040 * @param s the socket to shutdown 1041 * @param how the type of shutdown: SHUT_WR or SHUT_RDWR 1042 * @param timeout_ms the maximum wait time in milliseconds to receive the data, 1043 * no limit if negative value is used 1044 * @return zero on succeed, -1 otherwise 1045 */ 1046 static int 1047 wr_shutdown_tmo (struct wr_socket *s, int how, int timeout_ms) 1048 { 1049 switch (how) 1050 { 1051 case SHUT_WR: /* Valid value */ 1052 break; 1053 case SHUT_RDWR: /* Valid value */ 1054 break; 1055 case SHUT_RD: 1056 externalErrorExitDesc ("Unsupported 'how' value"); 1057 break; 1058 default: 1059 externalErrorExitDesc ("Invalid 'how' value"); 1060 break; 1061 } 1062 if (wr_plain == s->t) 1063 { 1064 (void) timeout_ms; /* Unused parameter for plain sockets */ 1065 return shutdown (s->fd, how); 1066 } 1067 #ifdef HTTPS_SUPPORT 1068 if (wr_tls == s->t) 1069 { 1070 ssize_t ret; 1071 if (! s->tls_connected && ! wr_handshake_tmo_ (s, timeout_ms)) 1072 return -1; 1073 1074 while (1) 1075 { 1076 ret = 1077 gnutls_bye (s->tls_s, 1078 (SHUT_WR == how) ? GNUTLS_SHUT_WR : GNUTLS_SHUT_RDWR); 1079 if (GNUTLS_E_SUCCESS == ret) 1080 { 1081 #if 0 /* Disabled to test pure behaviour */ 1082 if (SHUT_RDWR == how) 1083 (void) shutdown (s->fd, how); /* Also shutdown the underlying transport layer */ 1084 #endif 1085 return 0; 1086 } 1087 if ((GNUTLS_E_AGAIN != ret) && (GNUTLS_E_INTERRUPTED != ret)) 1088 break; 1089 wr_wait_socket_ready_ (s, timeout_ms, 1090 gnutls_record_get_direction (s->tls_s) ? 1091 WR_WAIT_FOR_SEND : WR_WAIT_FOR_RECV); 1092 } 1093 1094 fprintf (stderr, "The error returned by gnutls_bye() is " 1095 "'%s' ", gnutls_strerror ((int) ret)); 1096 #if GNUTLS_VERSION_NUMBER >= 0x020600 1097 fprintf (stderr, "(%s)\n", gnutls_strerror_name ((int) ret)); 1098 #else /* GNUTLS_VERSION_NUMBER < 0x020600 */ 1099 fprintf (stderr, "(%d)\n", (int) ret); 1100 #endif /* GNUTLS_VERSION_NUMBER < 0x020600 */ 1101 testErrorLogDesc ("gnutls_bye() failed with hard error"); 1102 mhd_SCKT_SET_LERR (mhdt_SCKT_HARD_ERR); /* hard error */ 1103 return -1; 1104 } 1105 #endif /* HTTPS_SUPPORT */ 1106 mhd_SCKT_SET_LERR (mhdt_SCKT_HARD_ERR); /* hard error */ 1107 return -1; 1108 } 1109 1110 1111 /** 1112 * Shutdown the socket. 1113 * @param s the socket to shutdown 1114 * @return zero on succeed, -1 otherwise 1115 */ 1116 static int 1117 wr_shutdown (struct wr_socket *s, int how) 1118 { 1119 return wr_shutdown_tmo (s, how, test_timeout * 1000); 1120 } 1121 1122 1123 /** 1124 * Close socket and release allocated resourced 1125 * @param s the socket to close 1126 * @return zero on succeed, -1 otherwise 1127 */ 1128 static int 1129 wr_close (struct wr_socket *s) 1130 { 1131 int ret = (mhd_socket_close (s->fd)) ? 0 : -1; 1132 #ifdef HTTPS_SUPPORT 1133 if (wr_tls == s->t) 1134 { 1135 gnutls_deinit (s->tls_s); 1136 gnutls_certificate_free_credentials (s->tls_crd); 1137 } 1138 #endif /* HTTPS_SUPPORT */ 1139 free (s); 1140 return ret; 1141 } 1142 1143 1144 /** 1145 * String used to identify the test pseudo-protocol 1146 */ 1147 #define mhdt_UPGRADE_PROTOCOL_STR "MHDT_upgrade_test/2.0" 1148 1149 /** 1150 * Thread we use to run the interaction with the upgraded socket. 1151 */ 1152 static pthread_t pt_server; 1153 1154 /** 1155 * Thread we use to run the interaction with the upgraded socket. 1156 */ 1157 static pthread_t pt_client; 1158 1159 /** 1160 * Flag set to true once the client is finished. 1161 */ 1162 static volatile bool client_done; 1163 1164 /** 1165 * Flag set to true once the app is finished. 1166 */ 1167 static volatile bool app_done; 1168 1169 1170 static void 1171 send_all (struct wr_socket *sock, 1172 const void *data, 1173 size_t data_size) 1174 { 1175 ssize_t ret; 1176 size_t sent; 1177 const uint8_t *const buf = (const uint8_t *) data; 1178 1179 wr_make_nonblocking (sock); 1180 for (sent = 0; sent < data_size; sent += (size_t) ret) 1181 { 1182 ret = wr_send (sock, 1183 buf + sent, 1184 data_size - sent); 1185 if (0 > ret) 1186 { 1187 if (mhd_SCKT_ERR_IS_EAGAIN (mhd_SCKT_GET_LERR ()) || 1188 mhd_SCKT_ERR_IS_EINTR (mhd_SCKT_GET_LERR ())) 1189 { 1190 ret = 0; 1191 continue; 1192 } 1193 testFailedExitDesc ("send() failed"); 1194 } 1195 } 1196 } 1197 1198 1199 #define send_all_stext(sk,st) send_all (sk,st,mhd_SSTR_LEN (st)) 1200 1201 1202 /** 1203 * Read character-by-character until we 1204 * get 'CRLNCRLN'. 1205 */ 1206 static void 1207 recv_hdr (struct wr_socket *sock) 1208 { 1209 unsigned int i; 1210 char next; 1211 char c; 1212 ssize_t ret; 1213 1214 wr_make_nonblocking (sock); 1215 next = '\r'; 1216 i = 0; 1217 while (i < 4) 1218 { 1219 ret = wr_recv (sock, 1220 &c, 1221 1); 1222 if (0 > ret) 1223 { 1224 if (mhd_SCKT_ERR_IS_EAGAIN (mhd_SCKT_GET_LERR ())) 1225 continue; 1226 if (mhd_SCKT_ERR_IS_EINTR (mhd_SCKT_GET_LERR ())) 1227 continue; 1228 testFailedExitDesc ("recv() failed"); 1229 } 1230 if (0 == ret) 1231 testFailedExitDesc ("The server unexpectedly closed connection"); 1232 if (c == next) 1233 { 1234 i++; 1235 if (next == '\r') 1236 next = '\n'; 1237 else 1238 next = '\r'; 1239 continue; 1240 } 1241 if (c == '\r') 1242 { 1243 i = 1; 1244 next = '\n'; 1245 continue; 1246 } 1247 i = 0; 1248 next = '\r'; 1249 } 1250 } 1251 1252 1253 static void 1254 recv_all (struct wr_socket *sock, 1255 const void *data, 1256 size_t data_size) 1257 { 1258 uint8_t *buf; 1259 ssize_t ret; 1260 size_t rcvd; 1261 1262 buf = (uint8_t *) malloc (data_size); 1263 if (NULL == buf) 1264 externalErrorExitDesc ("malloc() failed"); 1265 1266 wr_make_nonblocking (sock); 1267 for (rcvd = 0; rcvd < data_size; rcvd += (size_t) ret) 1268 { 1269 ret = wr_recv (sock, 1270 buf + rcvd, 1271 data_size - rcvd); 1272 if (0 > ret) 1273 { 1274 if (mhd_SCKT_ERR_IS_EAGAIN (mhd_SCKT_GET_LERR ()) || 1275 mhd_SCKT_ERR_IS_EINTR (mhd_SCKT_GET_LERR ())) 1276 { 1277 ret = 0; 1278 continue; 1279 } 1280 testFailedExitDesc ("recv() failed"); 1281 } 1282 else if (0 == ret) 1283 { 1284 fprintf (stderr, "Partial only received text. Expected: '%.*s' " 1285 "(length: %ud). Got: '%.*s' (length: %ud). ", 1286 (int) data_size, (const char *) data, (unsigned int) data_size, 1287 (int) rcvd, (const char *) buf, (unsigned int) rcvd); 1288 mhdErrorExitDesc ("The server unexpectedly closed connection"); 1289 } 1290 if ((data_size - rcvd) < (size_t) ret) 1291 testFailedExitDesc ("recv() returned excessive amount of data"); 1292 if (0 != memcmp (data, buf, rcvd + (size_t) ret)) 1293 { 1294 fprintf (stderr, "Wrong received text. Expected: '%.*s'. " 1295 "Got: '%.*s'. ", 1296 (int) (rcvd + (size_t) ret), (const char *) data, 1297 (int) (rcvd + (size_t) ret), (const char *) buf); 1298 mhdErrorExit (); 1299 } 1300 } 1301 if (0 != memcmp (data, buf, data_size)) 1302 { 1303 fprintf (stderr, "Wrong received text. Expected: '%.*s'. " 1304 "Got: '%.*s'. ", 1305 (int) data_size, (const char *) data, 1306 (int) data_size, (const char *) buf); 1307 mhdErrorExit (); 1308 } 1309 free (buf); 1310 } 1311 1312 1313 #define recv_all_stext(sk,st) recv_all (sk,st,mhd_SSTR_LEN (st)) 1314 1315 1316 /** 1317 * Shutdown write of the connection to signal end of transmission 1318 * for the remote side 1319 * @param sock the socket to shutdown 1320 */ 1321 static void 1322 send_eof (struct wr_socket *sock) 1323 { 1324 if (0 != wr_shutdown (sock, /* 1325 ** On Darwin local shutdown of RD cause error 1326 ** if remote side shut down WR before. 1327 wr_is_eof_received (sock) ? SHUT_RDWR : */ 1328 SHUT_WR)) 1329 externalErrorExitDesc ("Failed to shutdown connection"); 1330 } 1331 1332 1333 #if 0 /* Unused code */ 1334 1335 /** 1336 * Receive end of the transmission indication from the remote side 1337 * @param sock the socket to use 1338 */ 1339 static void 1340 receive_eof (struct wr_socket *sock) 1341 { 1342 uint8_t buf[127]; 1343 ssize_t ret; 1344 size_t rcvd; 1345 bool got_eof = false; 1346 1347 wr_make_nonblocking (sock); 1348 for (rcvd = 0; rcvd < sizeof(buf); rcvd += (size_t) ret) 1349 { 1350 ret = wr_recv (sock, 1351 buf + rcvd, 1352 sizeof(buf) - rcvd); 1353 if (0 > ret) 1354 { 1355 if (mhd_SCKT_ERR_IS_EAGAIN (mhd_SCKT_GET_LERR ()) || 1356 mhd_SCKT_ERR_IS_EINTR (mhd_SCKT_GET_LERR ())) 1357 { 1358 ret = 0; 1359 continue; 1360 } 1361 testFailedExitDesc ("recv() failed"); 1362 } 1363 else if (0 == ret) 1364 { 1365 got_eof = true; 1366 break; 1367 } 1368 } 1369 if (got_eof && (0 == rcvd)) 1370 return; /* Success */ 1371 1372 if (0 != rcvd) 1373 { 1374 if (sizeof(buf) == rcvd) 1375 { 1376 fprintf (stderr, "Received at least %lu extra bytes while " 1377 "end-of-file is expected.\n", (unsigned long) sizeof(buf)); 1378 mhdErrorExit (); 1379 } 1380 fprintf (stderr, "Received at %lu extra bytes and then %s" 1381 "end-of-file marker.\n", (unsigned long) rcvd, 1382 got_eof ? "" : "NO "); 1383 mhdErrorExit (); 1384 } 1385 if (! got_eof) 1386 mhdErrorExitDesc ("Failed to receive end-of-file marker."); 1387 } 1388 1389 1390 #endif /* Unused code */ 1391 1392 static void 1393 recv_upg_all (struct MHD_UpgradedHandle *urh, 1394 const void *data, 1395 size_t data_size) 1396 { 1397 uint8_t *buf; 1398 size_t last_rcvd; 1399 size_t rcvd; 1400 1401 buf = (uint8_t *) malloc (data_size); 1402 if (NULL == buf) 1403 externalErrorExitDesc ("malloc() failed"); 1404 1405 for (rcvd = 0; rcvd < data_size; rcvd += last_rcvd) 1406 { 1407 if (MHD_SC_OK != 1408 MHD_upgraded_recv (urh, 1409 data_size - rcvd, 1410 buf + rcvd, 1411 &last_rcvd, 1412 1000 * (unsigned long) test_timeout)) 1413 mhdErrorExitDesc ("MHD_upgraded_recv() failed"); 1414 1415 if (0 == last_rcvd) 1416 { 1417 fprintf (stderr, "Partial only received text. Expected: '%.*s' " 1418 "(length: %ud). Got: '%.*s' (length: %ud). ", 1419 (int) data_size, (const char *) data, (unsigned int) data_size, 1420 (int) rcvd, (const char *) buf, (unsigned int) rcvd); 1421 mhdErrorExitDesc ("The server unexpectedly closed connection"); 1422 } 1423 if ((data_size - rcvd) < last_rcvd) 1424 mhdErrorExitDesc ("MHD_upgraded_recv() returned excessive " \ 1425 "amount of data"); 1426 if (0 != memcmp (data, buf, rcvd + (size_t) last_rcvd)) 1427 { 1428 fprintf (stderr, "Wrong received text. Expected: '%.*s'. " 1429 "Got: '%.*s'. ", 1430 (int) (rcvd + last_rcvd), (const char *) data, 1431 (int) (rcvd + last_rcvd), (const char *) buf); 1432 mhdErrorExit (); 1433 } 1434 } 1435 if (0 != memcmp (data, buf, data_size)) 1436 { 1437 fprintf (stderr, "Wrong received text. Expected: '%.*s'. " 1438 "Got: '%.*s'. ", 1439 (int) data_size, (const char *) data, 1440 (int) data_size, (const char *) buf); 1441 mhdErrorExit (); 1442 } 1443 free (buf); 1444 } 1445 1446 1447 #define recv_upg_all_stext(uh,st) recv_upg_all (uh,st,mhd_SSTR_LEN (st)) 1448 1449 1450 static void 1451 send_upg_all (struct MHD_UpgradedHandle *urh, 1452 const void *data, 1453 size_t data_size) 1454 { 1455 size_t sent_size; 1456 1457 if (MHD_SC_OK != 1458 MHD_upgraded_send (urh, 1459 data_size, 1460 data, 1461 &sent_size, 1462 1000 * (unsigned long) test_timeout, 1463 MHD_NO)) 1464 mhdErrorExitDesc ("MHD_upgraded_send() failed"); 1465 1466 if (sent_size != data_size) 1467 mhdErrorExitDesc ("'sent_size' value is wrong"); 1468 } 1469 1470 1471 /** 1472 * Receive end of the transmission indication from the remote side 1473 * @param urh the "upgraded" handle to use 1474 */ 1475 static void 1476 receive_upg_eof (struct MHD_UpgradedHandle *urh) 1477 { 1478 size_t rcvd_sise; 1479 uint8_t buf[1]; 1480 1481 if (MHD_SC_OK != 1482 MHD_upgraded_recv (urh, 1483 sizeof(buf), 1484 buf, 1485 &rcvd_sise, 1486 1000 * (unsigned long) test_timeout)) 1487 mhdErrorExitDesc ("MHD_upgraded_recv() failed"); 1488 1489 if (0 != rcvd_sise) 1490 mhdErrorExitDesc ("EOF marker is not received"); 1491 1492 } 1493 1494 1495 /** 1496 * Main function for the thread that runs the interaction with 1497 * the upgraded socket. 1498 * 1499 * @param cls the handle for the upgrade 1500 */ 1501 static void * 1502 run_usock_server (void *cls) 1503 { 1504 struct MHD_UpgradedHandle *urh = (struct MHD_UpgradedHandle *) cls; 1505 1506 recv_upg_all (urh, 1507 rclient_msg, 1508 rclient_msg_size); 1509 send_upg_all (urh, 1510 app_msg, 1511 app_msg_size); 1512 recv_upg_all_stext (urh, \ 1513 "Finished"); 1514 if (! test_tls) 1515 { 1516 receive_upg_eof (urh); 1517 } 1518 if (MHD_SC_OK != 1519 MHD_upgraded_close (urh)) 1520 mhdErrorExitDesc ("MHD_upgraded_close() failed"); 1521 1522 app_done = true; 1523 return NULL; 1524 } 1525 1526 1527 /** 1528 * Main function for the thread that runs the client-side of the 1529 * interaction with the upgraded socket. 1530 * 1531 * @param cls the client socket 1532 */ 1533 static void * 1534 run_usock_client (void *cls) 1535 { 1536 struct wr_socket *sock = (struct wr_socket *) cls; 1537 1538 send_all_stext (sock, 1539 "GET / HTTP/1.1\r\n" \ 1540 "Host: localhost\r\n" \ 1541 "Connection: Upgrade\r\n" \ 1542 "Upgrade: " mhdt_UPGRADE_PROTOCOL_STR "\r\n" \ 1543 "\r\n"); 1544 recv_hdr (sock); 1545 send_all (sock, 1546 rclient_msg, 1547 rclient_msg_size); 1548 recv_all (sock, 1549 app_msg, 1550 app_msg_size); 1551 send_all_stext (sock, 1552 "Finished"); 1553 if (! test_tls) 1554 { 1555 send_eof (sock); 1556 } 1557 wr_close (sock); 1558 client_done = true; 1559 return NULL; 1560 } 1561 1562 1563 /** 1564 * Function called after a protocol "upgrade" response was sent successfully 1565 * and the connection is being switched to other protocol. 1566 * 1567 * The newly provided handle @a urh can be used to send and receive the data 1568 * by #MHD_upgraded_send() and #MHD_upgraded_recv(). The handle must be closed 1569 * by #MHD_upgraded_close() before destroying the daemon. 1570 * 1571 * "Upgraded" connection will not time out, but still counted for daemon 1572 * global connections limit and for per-IP limit (if set). 1573 * 1574 * Except when in 'thread-per-connection' mode, implementations 1575 * of this function should never block (as it will still be called 1576 * from within the main event loop). 1577 * 1578 * @param cls closure, whatever was given to #MHD_action_upgrade(). 1579 * @param request original HTTP request handle, 1580 * giving the function a last chance 1581 * to inspect the original HTTP request 1582 * @param urh argument for #MHD_upgrade_operation() on this @a response. 1583 * Applications must eventually use this callback to (indirectly) 1584 * perform the close() action on the @a sock. 1585 */ 1586 static void 1587 upgrade_cb (void *cls, 1588 struct MHD_Request *MHD_RESTRICT request, 1589 struct MHD_UpgradedHandle *MHD_RESTRICT urh) 1590 { 1591 if (NULL != cls) 1592 mhdErrorExitDesc ("'cls' is not NULL"); 1593 if (NULL == request) 1594 mhdErrorExitDesc ("'request' is NULL"); 1595 1596 if (0 != pthread_create (&pt_server, 1597 NULL, 1598 &run_usock_server, 1599 urh)) 1600 externalErrorExitDesc ("pthread_create() failed"); 1601 } 1602 1603 1604 /** 1605 * A client has requested the given url using the given method 1606 * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT, 1607 * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc). 1608 * If @a upload_size is not zero and response action is provided by this 1609 * callback, then upload will be discarded and the stream (the connection for 1610 * HTTP/1.1) will be closed after sending the response. 1611 * 1612 * @param cls argument given together with the function 1613 * pointer when the handler was registered with MHD 1614 * @param request the request object 1615 * @param path the requested uri (without arguments after "?") 1616 * @param method the HTTP method used (#MHD_HTTP_METHOD_GET, 1617 * #MHD_HTTP_METHOD_PUT, etc.) 1618 * @param upload_size the size of the message upload content payload, 1619 * #MHD_SIZE_UNKNOWN for chunked uploads (if the 1620 * final chunk has not been processed yet) 1621 * @return action how to proceed, NULL 1622 * if the request must be aborted due to a serious 1623 * error while handling the request (implies closure 1624 * of underling data stream, for HTTP/1.1 it means 1625 * socket closure). 1626 */ 1627 static const struct MHD_Action * 1628 req_handle_upgrade (void *cls, 1629 struct MHD_Request *MHD_RESTRICT request, 1630 const struct MHD_String *MHD_RESTRICT path, 1631 enum MHD_HTTP_Method method, 1632 uint_fast64_t upload_size) 1633 { 1634 const struct MHD_Action *act; 1635 if (NULL != cls) 1636 mhdErrorExitDesc ("'cls' is not NULL"); 1637 if (NULL == request) 1638 mhdErrorExitDesc ("'request' is NULL"); 1639 if (NULL == path) 1640 mhdErrorExitDesc ("'path' is NULL"); 1641 if (1 != path->len) 1642 mhdErrorExitDesc ("'path->len' is not 1"); 1643 if (0 != memcmp ("/", path->cstr, 1)) 1644 mhdErrorExitDesc ("'path->cstr' is not \"/\""); 1645 if (0 != path->cstr[path->len]) 1646 mhdErrorExitDesc ("'path->cstr' is not zero-terminated"); 1647 if (MHD_HTTP_METHOD_GET != method) 1648 mhdErrorExitDesc ("'method' is not MHD_HTTP_METHOD_GET"); 1649 if (0 != upload_size) 1650 mhdErrorExitDesc ("'upload_size' is not zero"); 1651 1652 act = MHD_action_upgrade (request, 1653 mhdt_UPGRADE_PROTOCOL_STR, 1654 &upgrade_cb, 1655 NULL, 1656 0, 1657 NULL); 1658 if (NULL == act) 1659 mhdErrorExitDesc ("MHD_action_upgrade() failed"); 1660 1661 return act; 1662 } 1663 1664 1665 /** 1666 * Test upgrading a connection. 1667 * @return zero if succeed 1668 */ 1669 static unsigned int 1670 test_upgrade (void) 1671 { 1672 struct MHD_Daemon *d = NULL; 1673 struct wr_socket *sock; 1674 struct sockaddr_in sa; 1675 union MHD_DaemonInfoFixedData dinfo; 1676 1677 #if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID) 1678 pid_t pid = -1; 1679 #endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */ 1680 1681 client_done = false; 1682 app_done = false; 1683 1684 d = MHD_daemon_create (&req_handle_upgrade, 1685 NULL); 1686 if (NULL == d) 1687 mhdErrorExitDesc ("MHD_daemon_create() failed"); 1688 1689 if (MHD_SC_OK != 1690 MHD_DAEMON_SET_OPTIONS ( \ 1691 d, \ 1692 MHD_D_OPTION_BIND_PORT (MHD_AF_DUAL_v6_OPTIONAL, global_port), \ 1693 MHD_D_OPTION_WORK_MODE (MHD_WM_OPTION_WORKER_THREADS (1)))) 1694 mhdErrorExitDesc ("MHD_DAEMON_SET_OPTIONS() failed"); 1695 1696 if (MHD_SC_OK != 1697 MHD_daemon_start (d)) 1698 mhdErrorExitDesc ("MHD_daemon_start() failed"); 1699 1700 if (MHD_SC_OK != 1701 MHD_daemon_get_info_fixed (d, \ 1702 MHD_DAEMON_INFO_FIXED_BIND_PORT, \ 1703 &dinfo)) 1704 mhdErrorExitDesc ("MHD_daemon_get_info_fixed() failed"); 1705 1706 if (0 == dinfo.v_bind_port_uint16) 1707 mhdErrorExitDesc ("MHD_daemon_get_info_fixed() returned wrong data"); 1708 global_port = dinfo.v_bind_port_uint16; /* Re-use the same port for the next checks */ 1709 if (! test_tls || (TLS_LIB_GNUTLS == use_tls_tool)) 1710 { 1711 sock = test_tls ? wr_create_tls_sckt () : wr_create_plain_sckt (); 1712 if (NULL == sock) 1713 externalErrorExitDesc ("Create socket failed"); 1714 wr_make_nonblocking (sock); 1715 sa.sin_family = AF_INET; 1716 sa.sin_port = htons (global_port); 1717 #ifdef INADDR_LOOPBACK 1718 sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); 1719 #else /* ! INADDR_LOOPBACK */ 1720 memcpy (&(sa.sin_addr.s_addr), "\x7f\0\0\1", 4); 1721 #endif /* ! INADDR_LOOPBACK */ 1722 if (0 != wr_connect (sock, 1723 (struct sockaddr *) &sa, 1724 sizeof (sa))) 1725 externalErrorExitDesc ("Connect socket failed"); 1726 } 1727 else 1728 { 1729 #if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID) 1730 MHD_Socket tls_fork_sock; 1731 uint16_t port; 1732 1733 port = global_port; 1734 if (-1 == (pid = gnutlscli_connect (&tls_fork_sock, 1735 port))) 1736 externalErrorExitDesc ("gnutlscli_connect() failed"); 1737 1738 sock = wr_create_from_plain_sckt (tls_fork_sock); 1739 if (NULL == sock) 1740 externalErrorExitDesc ("wr_create_from_plain_sckt() failed"); 1741 1742 wr_make_nonblocking (sock); 1743 #else /* !HTTPS_SUPPORT || !HAVE_FORK || !HAVE_WAITPID */ 1744 externalErrorExitDesc ("Unsupported 'use_tls_tool' value"); 1745 #endif /* !HTTPS_SUPPORT || !HAVE_FORK || !HAVE_WAITPID */ 1746 } 1747 1748 if (0 != pthread_create (&pt_client, 1749 NULL, 1750 &run_usock_client, 1751 sock)) 1752 externalErrorExitDesc ("pthread_create() failed"); 1753 // TODO: support external events 1754 if (0 != pthread_join (pt_client, 1755 NULL)) 1756 externalErrorExitDesc ("pthread_join() failed"); 1757 if (0 != pthread_join (pt_server, 1758 NULL)) 1759 externalErrorExitDesc ("pthread_join() failed"); 1760 #if defined(HTTPS_SUPPORT) && defined(HAVE_FORK) && defined(HAVE_WAITPID) 1761 if (test_tls && (TLS_LIB_GNUTLS != use_tls_tool)) 1762 { 1763 if ((pid_t) -1 == waitpid (pid, NULL, 0)) 1764 externalErrorExitDesc ("waitpid() failed"); 1765 } 1766 #endif /* HTTPS_SUPPORT && HAVE_FORK && HAVE_WAITPID */ 1767 if (! client_done) 1768 testFailedExitDesc ("The client thread has not signalled " \ 1769 "successful finish"); 1770 if (! app_done) 1771 testFailedExitDesc ("The application thread has not signalled " \ 1772 "successful finish"); 1773 MHD_daemon_destroy (d); 1774 return 0; 1775 } 1776 1777 1778 enum test_msg_type 1779 { 1780 test_msg_large_app_data, 1781 test_msg_large_rclient_data, 1782 test_msg_vlarge_app_data, 1783 test_msg_vlarge_rclient_data 1784 }; 1785 1786 /** 1787 * Initialise test message data 1788 * @param buf the pointer to the buffer to fill with the test data 1789 * @param buf_size the size of the @a buf 1790 * @param msg_type the type of the data to fill the @a buf 1791 * @return the @a buf pointer 1792 */ 1793 static void * 1794 init_test_msg (void *buf, size_t buf_size, enum test_msg_type msg_type) 1795 { 1796 size_t i; 1797 char *const text_buf = (char *) buf; 1798 uint8_t *const bin_buf = (uint8_t *) buf; 1799 if (0 == buf_size) 1800 return buf; 1801 switch (msg_type) 1802 { 1803 case test_msg_large_app_data: 1804 case test_msg_large_rclient_data: 1805 /* Simulate text data */ 1806 for (i = 0; i < buf_size; ++i) 1807 { 1808 size_t pos; 1809 if (test_msg_large_app_data == msg_type) 1810 pos = i + 43; 1811 else 1812 pos = i + 26; 1813 if ((0 == i) || (2 == pos % 100) ) 1814 text_buf[i] = 1815 (char) (unsigned char) ((test_msg_large_app_data == msg_type) ? 1816 ('Z' - pos % ('Z' - 'A' + 1)) : 1817 ('A' + pos % ('Z' - 'A' + 1))); 1818 else if (0 == pos % 100) 1819 text_buf[i] = '.'; 1820 else if (1 == pos % 100) 1821 text_buf[i] = ' '; 1822 else if ((99 != pos % 100) && (2 != pos % 100) && (0 == pos % 5)) 1823 text_buf[i] = ' '; 1824 else if (test_msg_large_app_data == msg_type) 1825 text_buf[i] = (char) (unsigned char) ('z' - pos % ('z' - 'a' + 1)); 1826 else 1827 text_buf[i] = (char) (unsigned char) ('a' + pos % ('z' - 'a' + 1)); 1828 } 1829 break; 1830 case test_msg_vlarge_app_data: 1831 /* Simulate binary data */ 1832 for (i = 0; i < buf_size; ++i) 1833 { 1834 bin_buf[i] = (uint8_t) ((i + 182) & 0xFF); 1835 } 1836 break; 1837 case test_msg_vlarge_rclient_data: 1838 /* Simulate binary data */ 1839 for (i = 0; i < buf_size; ++i) 1840 { 1841 bin_buf[i] = (uint8_t) ((111 - i) & 0xFF); 1842 } 1843 break; 1844 default: 1845 exit (99); 1846 break; 1847 } 1848 return buf; 1849 } 1850 1851 1852 /** 1853 * Perform initialisation of variables used in all check in this test 1854 * @return true if succeed, 1855 * false if failed. 1856 */ 1857 static bool 1858 global_test_init (void) 1859 { 1860 global_port = 0; 1861 1862 if (use_large || use_vlarge) 1863 { 1864 unsigned int i; 1865 size_t alloc_size; 1866 alloc_size = use_vlarge ? (256U * 1024U) : (17U * 1024U); 1867 for (i = 0; i < (sizeof(alloc_ptr) / sizeof(alloc_ptr[0])); ++i) 1868 { 1869 alloc_ptr[i] = malloc (alloc_size); 1870 if (NULL == alloc_ptr[i]) 1871 { 1872 for (--i; i < (sizeof(alloc_ptr) / sizeof(alloc_ptr[0])); --i) 1873 { 1874 free (alloc_ptr[i]); 1875 } 1876 return false; 1877 } 1878 } 1879 1880 rclient_msg_size = alloc_size; 1881 rclient_msg = init_test_msg (alloc_ptr[0], rclient_msg_size, 1882 use_vlarge ? 1883 test_msg_vlarge_rclient_data : 1884 test_msg_large_rclient_data); 1885 app_msg_size = alloc_size; 1886 app_msg = init_test_msg (alloc_ptr[1], app_msg_size, 1887 use_vlarge ? 1888 test_msg_vlarge_app_data : 1889 test_msg_large_app_data); 1890 } 1891 else 1892 { 1893 unsigned int i; 1894 for (i = 0; i < (sizeof(alloc_ptr) / sizeof(alloc_ptr[0])); ++i) 1895 alloc_ptr[i] = NULL; 1896 1897 rclient_msg_size = mhd_SSTR_LEN ("Hello"); 1898 rclient_msg = "Hello"; 1899 app_msg_size = mhd_SSTR_LEN ("World"); 1900 app_msg = "World"; 1901 } 1902 return true; 1903 } 1904 1905 1906 /** 1907 * Perform de-initialisation of variables with memory de-allocation if required. 1908 */ 1909 static void 1910 global_test_deinit (void) 1911 { 1912 unsigned int i; 1913 for (i = ((sizeof(alloc_ptr) / sizeof(alloc_ptr[0])) - 1); 1914 i < (sizeof(alloc_ptr) / sizeof(alloc_ptr[0])); 1915 --i) 1916 { 1917 if (NULL != alloc_ptr[i]) 1918 free (alloc_ptr[i]); 1919 } 1920 } 1921 1922 1923 int 1924 main (int argc, 1925 char *const *argv) 1926 { 1927 unsigned int error_count = 0; 1928 unsigned int res; 1929 1930 use_vlarge = (0 != mhdt_has_in_name (argv[0], "_vlarge")); 1931 use_large = (! use_vlarge) && (0 != mhdt_has_in_name (argv[0], "_large")); 1932 1933 use_tls_tool = TLS_CLI_NO_TOOL; 1934 test_tls = mhdt_has_in_name (argv[0], "_tls"); 1935 1936 verbose = ! (mhdt_has_param (argc, argv, "-q") || 1937 mhdt_has_param (argc, argv, "--quiet") || 1938 mhdt_has_param (argc, argv, "-s") || 1939 mhdt_has_param (argc, argv, "--silent")); 1940 1941 if ((((int) ((~((unsigned int) 0U)) >> 1)) / 1000) < test_timeout) 1942 { 1943 fprintf (stderr, "The test timeout value (%d) is too large.\n" 1944 "The test cannot run.\n", test_timeout); 1945 fprintf (stderr, "The maximum allowed timeout value is %d.\n", 1946 (((int) ((~((unsigned int) 0U)) >> 1)) / 1000)); 1947 return 3; 1948 } 1949 1950 if (test_tls) 1951 { 1952 use_tls_tool = TLS_LIB_GNUTLS; /* Should be always available as MHD uses it when TLS is supported. */ 1953 #ifdef HTTPS_SUPPORT 1954 if (mhdt_has_param (argc, argv, "--use-gnutls-cli")) 1955 use_tls_tool = TLS_CLI_GNUTLS; 1956 else if (mhdt_has_param (argc, argv, "--use-openssl")) 1957 use_tls_tool = TLS_CLI_OPENSSL; 1958 else if (mhdt_has_param (argc, argv, "--use-gnutls-lib")) 1959 use_tls_tool = TLS_LIB_GNUTLS; 1960 #if defined(HAVE_FORK) && defined(HAVE_WAITPID) 1961 else if (0 == system ("gnutls-cli --version 1> /dev/null 2> /dev/null")) 1962 use_tls_tool = TLS_CLI_GNUTLS; 1963 else if (0 == system ("openssl version 1> /dev/null 2> /dev/null")) 1964 use_tls_tool = TLS_CLI_OPENSSL; 1965 #endif /* HAVE_FORK && HAVE_WAITPID */ 1966 if (verbose) 1967 { 1968 switch (use_tls_tool) 1969 { 1970 case TLS_CLI_GNUTLS: 1971 printf ("GnuTLS-CLI will be used for testing.\n"); 1972 break; 1973 case TLS_CLI_OPENSSL: 1974 printf ("Command line version of OpenSSL will be used for testing.\n"); 1975 break; 1976 case TLS_LIB_GNUTLS: 1977 printf ("GnuTLS library will be used for testing.\n"); 1978 break; 1979 case TLS_CLI_NO_TOOL: 1980 default: 1981 externalErrorExitDesc ("Wrong 'use_tls_tool' value"); 1982 } 1983 } 1984 if ( (TLS_LIB_GNUTLS == use_tls_tool) && 1985 (GNUTLS_E_SUCCESS != gnutls_global_init ()) ) 1986 externalErrorExitDesc ("gnutls_global_init() failed"); 1987 1988 #else /* ! HTTPS_SUPPORT */ 1989 fprintf (stderr, "HTTPS support was disabled by configure.\n"); 1990 return 77; 1991 #endif /* ! HTTPS_SUPPORT */ 1992 } 1993 1994 if (! global_test_init ()) 1995 { 1996 #ifdef HTTPS_SUPPORT 1997 if (test_tls && (TLS_LIB_GNUTLS == use_tls_tool)) 1998 gnutls_global_deinit (); 1999 #endif /* HTTPS_SUPPORT */ 2000 fprintf (stderr, "Failed to initialise the test.\n"); 2001 return 99; 2002 } 2003 2004 /* run tests */ 2005 if (verbose) 2006 printf ("Starting HTTP \"Upgrade\" tests with %s connections and " 2007 "%s size messages.\n", 2008 test_tls ? "TLS" : "plain", 2009 use_large ? "large" : (use_vlarge ? "very large" : "basic")); 2010 res = test_upgrade (); 2011 fflush_allstd (); 2012 error_count += res; 2013 if (res) 2014 fprintf (stderr, 2015 "FAILED: HTTP Upgrade, return code %u.\n", 2016 res); 2017 else if (verbose) 2018 printf ("PASSED: HTTP Upgrade.\n"); 2019 2020 // TODO: add thread-per-connection testing 2021 // TODO: add external events testing 2022 2023 /* report result */ 2024 if (0 != error_count) 2025 fprintf (stderr, 2026 "Error (code: %u)\n", 2027 error_count); 2028 2029 global_test_deinit (); 2030 #ifdef HTTPS_SUPPORT 2031 if (test_tls && (TLS_LIB_GNUTLS == use_tls_tool)) 2032 gnutls_global_deinit (); 2033 #endif /* HTTPS_SUPPORT */ 2034 2035 return error_count != 0; /* 0 == pass */ 2036 }