libmicrohttpd

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

test_post_loop.c (19073B)


      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2007 Christian Grothoff
      4      Copyright (C) 2014-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 2, 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 daemontest_post_loop.c
     24  * @brief  Testcase for libmicrohttpd POST operations using URL-encoding
     25  * @author Christian Grothoff (inspired by bug report #1296)
     26  * @author Karlson2k (Evgeny Grin)
     27  */
     28 
     29 #include "MHD_config.h"
     30 #include "platform.h"
     31 #include <curl/curl.h>
     32 #include <microhttpd.h>
     33 #include <stdlib.h>
     34 #include <string.h>
     35 #include <time.h>
     36 #include <errno.h>
     37 #include "mhd_has_in_name.h"
     38 
     39 #ifndef WINDOWS
     40 #include <unistd.h>
     41 #endif
     42 
     43 #if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2
     44 #undef MHD_CPU_COUNT
     45 #endif
     46 #if ! defined(MHD_CPU_COUNT)
     47 #define MHD_CPU_COUNT 2
     48 #endif
     49 
     50 #define POST_DATA \
     51   "<?xml version='1.0' ?>\n<xml>\n<data-id>1</data-id>\n</xml>\n"
     52 
     53 #ifndef __APPLE__
     54 #define LOOPCOUNT 1000
     55 #else  /* __APPLE__ */
     56 /* FIXME: macOS may fail in this test with "unable to connect". Investigate deeper? */
     57 #define LOOPCOUNT 200
     58 #endif /* __APPLE__ */
     59 
     60 static int oneone;
     61 
     62 struct CBC
     63 {
     64   char *buf;
     65   size_t pos;
     66   size_t size;
     67 };
     68 
     69 static size_t
     70 copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
     71 {
     72   struct CBC *cbc = ctx;
     73 
     74   if (cbc->pos + size * nmemb > cbc->size)
     75     return 0;                   /* overflow */
     76   memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
     77   cbc->pos += size * nmemb;
     78   return size * nmemb;
     79 }
     80 
     81 
     82 static enum MHD_Result
     83 ahc_echo (void *cls,
     84           struct MHD_Connection *connection,
     85           const char *url,
     86           const char *method,
     87           const char *version,
     88           const char *upload_data, size_t *upload_data_size,
     89           void **req_cls)
     90 {
     91   static int marker;
     92   struct MHD_Response *response;
     93   enum MHD_Result ret;
     94   (void) cls; (void) url; (void) version;          /* Unused. Silent compiler warning. */
     95   (void) upload_data; (void) upload_data_size;     /* Unused. Silent compiler warning. */
     96 
     97   if (0 != strcmp ("POST", method))
     98   {
     99     printf ("METHOD: %s\n", method);
    100     return MHD_NO;              /* unexpected method */
    101   }
    102   if ((*req_cls != NULL) && (0 == *upload_data_size))
    103   {
    104     if (*req_cls != &marker)
    105       abort ();
    106     response = MHD_create_response_from_buffer_static (2,
    107                                                        "OK");
    108     ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
    109     MHD_destroy_response (response);
    110     *req_cls = NULL;
    111     return ret;
    112   }
    113   if (strlen (POST_DATA) != *upload_data_size)
    114     return MHD_YES;
    115   *upload_data_size = 0;
    116   *req_cls = &marker;
    117   return MHD_YES;
    118 }
    119 
    120 
    121 static unsigned int
    122 testInternalPost (void)
    123 {
    124   struct MHD_Daemon *d;
    125   CURL *c;
    126   char buf[2048];
    127   struct CBC cbc;
    128   CURLcode errornum;
    129   int i;
    130   char url[1024];
    131   uint16_t port;
    132 
    133   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    134     port = 0;
    135   else
    136   {
    137     port = 1350;
    138     if (oneone)
    139       port += 10;
    140   }
    141 
    142   cbc.buf = buf;
    143   cbc.size = 2048;
    144   d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
    145                         port, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END);
    146   if (d == NULL)
    147     return 1;
    148   if (0 == port)
    149   {
    150     const union MHD_DaemonInfo *dinfo;
    151     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    152     if ((NULL == dinfo) || (0 == dinfo->port) )
    153     {
    154       MHD_stop_daemon (d); return 32;
    155     }
    156     port = dinfo->port;
    157   }
    158   for (i = 0; i < LOOPCOUNT; i++)
    159   {
    160     if (99 == i % 100)
    161       fprintf (stderr, ".");
    162     c = curl_easy_init ();
    163     cbc.pos = 0;
    164     buf[0] = '\0';
    165     snprintf (url,
    166               sizeof (url),
    167               "http://127.0.0.1:%u/hw%d",
    168               (unsigned int) port,
    169               i);
    170     curl_easy_setopt (c, CURLOPT_URL, url);
    171     curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    172     curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    173     curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
    174     curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
    175     curl_easy_setopt (c, CURLOPT_POST, 1L);
    176     curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    177     curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    178     if (oneone)
    179       curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    180     else
    181       curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    182     curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    183     /* NOTE: use of CONNECTTIMEOUT without also
    184      *   setting NOSIGNAL results in really weird
    185      *   crashes on my system! */
    186     curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    187     if (CURLE_OK != (errornum = curl_easy_perform (c)))
    188     {
    189       fprintf (stderr,
    190                "curl_easy_perform failed: `%s'\n",
    191                curl_easy_strerror (errornum));
    192       curl_easy_cleanup (c);
    193       MHD_stop_daemon (d);
    194       return 2;
    195     }
    196     curl_easy_cleanup (c);
    197     if ((buf[0] != 'O') || (buf[1] != 'K'))
    198     {
    199       MHD_stop_daemon (d);
    200       return 4;
    201     }
    202   }
    203   MHD_stop_daemon (d);
    204   if (LOOPCOUNT >= 99)
    205     fprintf (stderr, "\n");
    206   return 0;
    207 }
    208 
    209 
    210 static unsigned int
    211 testMultithreadedPost (void)
    212 {
    213   struct MHD_Daemon *d;
    214   CURL *c;
    215   char buf[2048];
    216   struct CBC cbc;
    217   CURLcode errornum;
    218   int i;
    219   char url[1024];
    220   uint16_t port;
    221 
    222   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    223     port = 0;
    224   else
    225   {
    226     port = 1351;
    227     if (oneone)
    228       port += 10;
    229   }
    230 
    231   cbc.buf = buf;
    232   cbc.size = 2048;
    233   d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
    234                         | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
    235                         port, NULL, NULL,
    236                         &ahc_echo, NULL,
    237                         MHD_OPTION_END);
    238   if (d == NULL)
    239     return 16;
    240   if (0 == port)
    241   {
    242     const union MHD_DaemonInfo *dinfo;
    243     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    244     if ((NULL == dinfo) || (0 == dinfo->port) )
    245     {
    246       MHD_stop_daemon (d); return 32;
    247     }
    248     port = dinfo->port;
    249   }
    250   for (i = 0; i < LOOPCOUNT; i++)
    251   {
    252     if (99 == i % 100)
    253       fprintf (stderr, ".");
    254     c = curl_easy_init ();
    255     cbc.pos = 0;
    256     buf[0] = '\0';
    257     snprintf (url,
    258               sizeof (url),
    259               "http://127.0.0.1:%u/hw%d",
    260               (unsigned int) port,
    261               i);
    262     curl_easy_setopt (c, CURLOPT_URL, url);
    263     curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    264     curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    265     curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
    266     curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
    267     curl_easy_setopt (c, CURLOPT_POST, 1L);
    268     curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    269     curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    270     if (oneone)
    271       curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    272     else
    273       curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    274     curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    275     /* NOTE: use of CONNECTTIMEOUT without also
    276      *   setting NOSIGNAL results in really weird
    277      *   crashes on my system! */
    278     curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    279     if (CURLE_OK != (errornum = curl_easy_perform (c)))
    280     {
    281       fprintf (stderr,
    282                "curl_easy_perform failed: `%s'\n",
    283                curl_easy_strerror (errornum));
    284       curl_easy_cleanup (c);
    285       MHD_stop_daemon (d);
    286       return 32;
    287     }
    288     curl_easy_cleanup (c);
    289     if ((buf[0] != 'O') || (buf[1] != 'K'))
    290     {
    291       MHD_stop_daemon (d);
    292       return 64;
    293     }
    294   }
    295   MHD_stop_daemon (d);
    296   if (LOOPCOUNT >= 99)
    297     fprintf (stderr, "\n");
    298   return 0;
    299 }
    300 
    301 
    302 static unsigned int
    303 testMultithreadedPoolPost (void)
    304 {
    305   struct MHD_Daemon *d;
    306   CURL *c;
    307   char buf[2048];
    308   struct CBC cbc;
    309   CURLcode errornum;
    310   int i;
    311   char url[1024];
    312   uint16_t port;
    313 
    314   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    315     port = 0;
    316   else
    317   {
    318     port = 1352;
    319     if (oneone)
    320       port += 10;
    321   }
    322 
    323   cbc.buf = buf;
    324   cbc.size = 2048;
    325   d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG,
    326                         port, NULL, NULL, &ahc_echo, NULL,
    327                         MHD_OPTION_THREAD_POOL_SIZE, MHD_CPU_COUNT,
    328                         MHD_OPTION_END);
    329   if (d == NULL)
    330     return 16;
    331   if (0 == port)
    332   {
    333     const union MHD_DaemonInfo *dinfo;
    334     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    335     if ((NULL == dinfo) || (0 == dinfo->port) )
    336     {
    337       MHD_stop_daemon (d); return 32;
    338     }
    339     port = dinfo->port;
    340   }
    341   for (i = 0; i < LOOPCOUNT; i++)
    342   {
    343     if (99 == i % 100)
    344       fprintf (stderr, ".");
    345     c = curl_easy_init ();
    346     cbc.pos = 0;
    347     buf[0] = '\0';
    348     snprintf (url,
    349               sizeof (url),
    350               "http://127.0.0.1:%u/hw%d",
    351               (unsigned int) port,
    352               i);
    353     curl_easy_setopt (c, CURLOPT_URL, url);
    354     curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    355     curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    356     curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
    357     curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
    358     curl_easy_setopt (c, CURLOPT_POST, 1L);
    359     curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    360     curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    361     if (oneone)
    362       curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    363     else
    364       curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    365     curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    366     /* NOTE: use of CONNECTTIMEOUT without also
    367      *   setting NOSIGNAL results in really weird
    368      *   crashes on my system! */
    369     curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    370     if (CURLE_OK != (errornum = curl_easy_perform (c)))
    371     {
    372       fprintf (stderr,
    373                "curl_easy_perform failed: `%s'\n",
    374                curl_easy_strerror (errornum));
    375       curl_easy_cleanup (c);
    376       MHD_stop_daemon (d);
    377       return 32;
    378     }
    379     curl_easy_cleanup (c);
    380     if ((buf[0] != 'O') || (buf[1] != 'K'))
    381     {
    382       MHD_stop_daemon (d);
    383       return 64;
    384     }
    385   }
    386   MHD_stop_daemon (d);
    387   if (LOOPCOUNT >= 99)
    388     fprintf (stderr, "\n");
    389   return 0;
    390 }
    391 
    392 
    393 static unsigned int
    394 testExternalPost (void)
    395 {
    396   struct MHD_Daemon *d;
    397   CURL *c;
    398   char buf[2048];
    399   struct CBC cbc;
    400   CURLM *multi;
    401   CURLMcode mret;
    402   fd_set rs;
    403   fd_set ws;
    404   fd_set es;
    405   MHD_socket maxsock;
    406 #ifdef MHD_WINSOCK_SOCKETS
    407   int maxposixs; /* Max socket number unused on W32 */
    408 #else  /* MHD_POSIX_SOCKETS */
    409 #define maxposixs maxsock
    410 #endif /* MHD_POSIX_SOCKETS */
    411   int running;
    412   struct CURLMsg *msg;
    413   time_t start;
    414   struct timeval tv;
    415   int i;
    416   uint64_t timeout64;
    417   long ctimeout;
    418   char url[1024];
    419   uint16_t port;
    420 
    421   if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
    422     port = 0;
    423   else
    424   {
    425     port = 1353;
    426     if (oneone)
    427       port += 10;
    428   }
    429 
    430   multi = NULL;
    431   cbc.buf = buf;
    432   cbc.size = 2048;
    433   cbc.pos = 0;
    434   d = MHD_start_daemon (MHD_USE_ERROR_LOG | MHD_USE_NO_THREAD_SAFETY,
    435                         port, NULL, NULL, &ahc_echo, NULL,
    436                         MHD_OPTION_APP_FD_SETSIZE, (int) FD_SETSIZE,
    437                         MHD_OPTION_END);
    438   if (d == NULL)
    439     return 256;
    440   if (0 == port)
    441   {
    442     const union MHD_DaemonInfo *dinfo;
    443     dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
    444     if ((NULL == dinfo) || (0 == dinfo->port) )
    445     {
    446       MHD_stop_daemon (d); return 32;
    447     }
    448     port = dinfo->port;
    449   }
    450   multi = curl_multi_init ();
    451   if (multi == NULL)
    452   {
    453     MHD_stop_daemon (d);
    454     return 512;
    455   }
    456   for (i = 0; i < LOOPCOUNT; i++)
    457   {
    458     if (99 == i % 100)
    459       fprintf (stderr, ".");
    460     c = curl_easy_init ();
    461     cbc.pos = 0;
    462     buf[0] = '\0';
    463     snprintf (url,
    464               sizeof (url),
    465               "http://127.0.0.1:%u/hw%d",
    466               (unsigned int) port,
    467               i);
    468     curl_easy_setopt (c, CURLOPT_URL, url);
    469     curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    470     curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
    471     curl_easy_setopt (c, CURLOPT_POSTFIELDS, POST_DATA);
    472     curl_easy_setopt (c, CURLOPT_POSTFIELDSIZE, strlen (POST_DATA));
    473     curl_easy_setopt (c, CURLOPT_POST, 1L);
    474     curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
    475     curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    476     if (oneone)
    477       curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    478     else
    479       curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    480     curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    481     /* NOTE: use of CONNECTTIMEOUT without also
    482      *   setting NOSIGNAL results in really weird
    483      *   crashes on my system! */
    484     curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
    485     mret = curl_multi_add_handle (multi, c);
    486     if (mret != CURLM_OK)
    487     {
    488       curl_multi_cleanup (multi);
    489       curl_easy_cleanup (c);
    490       MHD_stop_daemon (d);
    491       return 1024;
    492     }
    493     start = time (NULL);
    494     while ((time (NULL) - start < 5) && (multi != NULL))
    495     {
    496       maxsock = MHD_INVALID_SOCKET;
    497       maxposixs = -1;
    498       FD_ZERO (&rs);
    499       FD_ZERO (&ws);
    500       FD_ZERO (&es);
    501       while (CURLM_CALL_MULTI_PERFORM ==
    502              curl_multi_perform (multi, &running))
    503         ;
    504       mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs);
    505       if (mret != CURLM_OK)
    506       {
    507         curl_multi_remove_handle (multi, c);
    508         curl_multi_cleanup (multi);
    509         curl_easy_cleanup (c);
    510         MHD_stop_daemon (d);
    511         return 2048;
    512       }
    513       if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock))
    514       {
    515         curl_multi_remove_handle (multi, c);
    516         curl_multi_cleanup (multi);
    517         curl_easy_cleanup (c);
    518         MHD_stop_daemon (d);
    519         return 4096;
    520       }
    521       if (MHD_NO == MHD_get_timeout64 (d, &timeout64))
    522         timeout64 = 100;          /* 100ms == INFTY -- CURL bug... */
    523       if ((CURLM_OK == curl_multi_timeout (multi, &ctimeout)) &&
    524           (ctimeout >= 0) && ((uint64_t) ctimeout < timeout64))
    525         timeout64 = (uint64_t) ctimeout;
    526       if (0 == running)
    527         timeout64 = 0; /* terminate quickly... */
    528 #if ! defined(_WIN32) || defined(__CYGWIN__)
    529       tv.tv_sec = (time_t) (timeout64 / 1000);
    530 #else  /* Native W32 */
    531       tv.tv_sec = (long) (timeout64 / 1000);
    532 #endif /* Native W32 */
    533       tv.tv_usec = (long) (1000 * (timeout64 % 1000));
    534       if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv))
    535       {
    536 #ifdef MHD_POSIX_SOCKETS
    537         if (EINTR != errno)
    538         {
    539           fprintf (stderr, "Unexpected select() error: %d. Line: %d\n",
    540                    (int) errno, __LINE__);
    541           fflush (stderr);
    542           exit (99);
    543         }
    544 #else
    545         if ((WSAEINVAL != WSAGetLastError ()) ||
    546             (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) )
    547         {
    548           fprintf (stderr, "Unexpected select() error: %d. Line: %d\n",
    549                    (int) WSAGetLastError (), __LINE__);
    550           fflush (stderr);
    551           exit (99);
    552         }
    553         Sleep (1);
    554 #endif
    555       }
    556       while (CURLM_CALL_MULTI_PERFORM ==
    557              curl_multi_perform (multi, &running))
    558         ;
    559       if (0 == running)
    560       {
    561         int pending;
    562         int curl_fine = 0;
    563         while (NULL != (msg = curl_multi_info_read (multi, &pending)))
    564         {
    565           if (msg->msg == CURLMSG_DONE)
    566           {
    567             if (msg->data.result == CURLE_OK)
    568               curl_fine = 1;
    569             else
    570             {
    571               fprintf (stderr,
    572                        "%s failed at %s:%d: `%s'\n",
    573                        "curl_multi_perform",
    574                        __FILE__,
    575                        __LINE__, curl_easy_strerror (msg->data.result));
    576               abort ();
    577             }
    578           }
    579         }
    580         if (! curl_fine)
    581         {
    582           fprintf (stderr, "libcurl haven't returned OK code\n");
    583           abort ();
    584         }
    585         break;
    586       }
    587       MHD_run (d);
    588     }
    589     if (NULL != c)
    590     {
    591       curl_multi_remove_handle (multi, c);
    592       curl_easy_cleanup (c);
    593     }
    594     if ((buf[0] != 'O') || (buf[1] != 'K'))
    595     {
    596       curl_multi_cleanup (multi);
    597       MHD_stop_daemon (d);
    598       return 8192;
    599     }
    600   }
    601   curl_multi_cleanup (multi);
    602   MHD_stop_daemon (d);
    603   if (LOOPCOUNT >= 99)
    604     fprintf (stderr, "\n");
    605   return 0;
    606 }
    607 
    608 
    609 /**
    610  * Time this round was started.
    611  */
    612 static unsigned long long start_time;
    613 
    614 
    615 /**
    616  * Get the current timestamp
    617  *
    618  * @return current time in ms
    619  */
    620 static unsigned long long
    621 now (void)
    622 {
    623   struct timeval tv;
    624 
    625   gettimeofday (&tv, NULL);
    626   return (((unsigned long long) tv.tv_sec * 1000LL)
    627           + ((unsigned long long) tv.tv_usec / 1000LL));
    628 }
    629 
    630 
    631 int
    632 main (int argc, char *const *argv)
    633 {
    634   unsigned int errorCount = 0;
    635   (void) argc;   /* Unused. Silent compiler warning. */
    636 
    637   if ((NULL == argv) || (0 == argv[0]))
    638     return 99;
    639   oneone = has_in_name (argv[0], "11");
    640   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
    641     return 2;
    642   if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
    643   {
    644     start_time = now ();
    645     errorCount += testInternalPost ();
    646     fprintf (stderr,
    647              oneone ? "%s: Sequential POSTs (http/1.1) %f/s\n" :
    648              "%s: Sequential POSTs (http/1.0) %f/s\n",
    649              "internal select",
    650              (double) 1000 * LOOPCOUNT
    651              / ((double) (now () - start_time) + 1.0));
    652     start_time = now ();
    653     errorCount += testMultithreadedPost ();
    654     fprintf (stderr,
    655              oneone ? "%s: Sequential POSTs (http/1.1) %f/s\n" :
    656              "%s: Sequential POSTs (http/1.0) %f/s\n",
    657              "multithreaded post",
    658              (double) 1000 * LOOPCOUNT
    659              / ((double) (now () - start_time) + 1.0));
    660     start_time = now ();
    661     errorCount += testMultithreadedPoolPost ();
    662     fprintf (stderr,
    663              oneone ? "%s: Sequential POSTs (http/1.1) %f/s\n" :
    664              "%s: Sequential POSTs (http/1.0) %f/s\n",
    665              "thread with pool",
    666              (double) 1000 * LOOPCOUNT
    667              / ((double) (now () - start_time) + 1.0));
    668   }
    669   start_time = now ();
    670   errorCount += testExternalPost ();
    671   fprintf (stderr,
    672            oneone ? "%s: Sequential POSTs (http/1.1) %f/s\n" :
    673            "%s: Sequential POSTs (http/1.0) %f/s\n",
    674            "external select",
    675            (double) 1000 * LOOPCOUNT
    676            / ((double) (now () - start_time) + 1.0));
    677   if (errorCount != 0)
    678     fprintf (stderr, "Error (code: %u)\n", errorCount);
    679   curl_global_cleanup ();
    680   return (0 == errorCount) ? 0 : 1;       /* 0 == pass */
    681 }