libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

test_upgrade.c (68941B)


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