libmicrohttpd

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

test_upgrade.c (68774B)


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