libmicrohttpd

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

test_post_loop.c (19240B)


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