libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

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 }