Home | History | Annotate | Download | only in testcurl
      1 /*
      2      This file is part of libmicrohttpd
      3      Copyright (C) 2007, 2009, 2011, 2015 Christian Grothoff
      4 
      5      libmicrohttpd is free software; you can redistribute it and/or modify
      6      it under the terms of the GNU General Public License as published
      7      by the Free Software Foundation; either version 3, or (at your
      8      option) any later version.
      9 
     10      libmicrohttpd is distributed in the hope that it will be useful, but
     11      WITHOUT ANY WARRANTY; without even the implied warranty of
     12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13      General Public License for more details.
     14 
     15      You should have received a copy of the GNU General Public License
     16      along with libmicrohttpd; see the file COPYING.  If not, write to the
     17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
     18      Boston, MA 02111-1307, USA.
     19 */
     20 
     21 /**
     22  * @file test_concurrent_stop.c
     23  * @brief test stopping server while concurrent GETs are ongoing
     24  * @author Christian Grothoff
     25  */
     26 #include "MHD_config.h"
     27 #include "platform.h"
     28 #include <curl/curl.h>
     29 #include <microhttpd.h>
     30 #include <stdlib.h>
     31 #include <string.h>
     32 #include <time.h>
     33 #include "gauger.h"
     34 
     35 #ifdef CPU_COUNT
     36 #undef CPU_COUNT
     37 #endif
     38 #define CPU_COUNT 40
     39 
     40 
     41 /**
     42  * How many rounds of operations do we do for each
     43  * test (total number of requests will be ROUNDS * PAR).
     44  */
     45 #define ROUNDS 50000
     46 
     47 /**
     48  * How many requests do we do in parallel?
     49  */
     50 #define PAR CPU_COUNT
     51 
     52 /**
     53  * Do we use HTTP 1.1?
     54  */
     55 static int oneone;
     56 
     57 /**
     58  * Response to return (re-used).
     59  */
     60 static struct MHD_Response *response;
     61 
     62 
     63 static size_t
     64 copyBuffer (void *ptr,
     65 	    size_t size, size_t nmemb,
     66 	    void *ctx)
     67 {
     68   return size * nmemb;
     69 }
     70 
     71 static int
     72 ahc_echo (void *cls,
     73           struct MHD_Connection *connection,
     74           const char *url,
     75           const char *method,
     76           const char *version,
     77           const char *upload_data, size_t *upload_data_size,
     78           void **unused)
     79 {
     80   static int ptr;
     81   const char *me = cls;
     82   int ret;
     83 
     84   if (0 != strcmp (me, method))
     85     return MHD_NO;              /* unexpected method */
     86   if (&ptr != *unused)
     87     {
     88       *unused = &ptr;
     89       return MHD_YES;
     90     }
     91   *unused = NULL;
     92   ret = MHD_queue_response (connection,
     93                             MHD_HTTP_OK,
     94                             response);
     95   if (ret == MHD_NO)
     96     abort ();
     97   return ret;
     98 }
     99 
    100 
    101 static pid_t
    102 do_gets (int port)
    103 {
    104   pid_t ret;
    105   CURL *c;
    106   CURLcode errornum;
    107   unsigned int i;
    108   unsigned int j;
    109   pid_t par[PAR];
    110   char url[64];
    111 
    112   sprintf(url, "http://127.0.0.1:%d/hello_world", port);
    113 
    114   ret = fork ();
    115   if (ret == -1) abort ();
    116   if (ret != 0)
    117     return ret;
    118   for (j=0;j<PAR;j++)
    119     {
    120       par[j] = fork ();
    121       if (par[j] == 0)
    122 	{
    123 	  for (i=0;i<ROUNDS;i++)
    124 	    {
    125 	      c = curl_easy_init ();
    126 	      curl_easy_setopt (c, CURLOPT_URL, url);
    127 	      curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
    128 	      curl_easy_setopt (c, CURLOPT_WRITEDATA, NULL);
    129 	      curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
    130 	      curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
    131 	      if (oneone)
    132 		curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
    133 	      else
    134 		curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    135 	      curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
    136 	      /* NOTE: use of CONNECTTIMEOUT without also
    137 		 setting NOSIGNAL results in really weird
    138 		 crashes on my system! */
    139 	      curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
    140 	      if (CURLE_OK != (errornum = curl_easy_perform (c)))
    141 		{
    142 		  curl_easy_cleanup (c);
    143 		  _exit (1);
    144 		}
    145 	      curl_easy_cleanup (c);
    146 	    }
    147 	  _exit (0);
    148 	}
    149     }
    150   for (j=0;j<PAR;j++)
    151     waitpid (par[j], NULL, 0);
    152   _exit (0);
    153 }
    154 
    155 
    156 static void
    157 join_gets (pid_t pid)
    158 {
    159   int status;
    160 
    161   status = 1;
    162   waitpid (pid, &status, 0);
    163   if (0 != status)
    164     abort ();
    165 }
    166 
    167 
    168 static int
    169 testMultithreadedGet (int port, int poll_flag)
    170 {
    171   struct MHD_Daemon *d;
    172   pid_t p;
    173 
    174   d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG  | poll_flag,
    175                         port, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
    176   if (d == NULL)
    177     return 16;
    178   p = do_gets (port);
    179   sleep (1);
    180   MHD_stop_daemon (d);
    181   join_gets (p);
    182   return 0;
    183 }
    184 
    185 
    186 static int
    187 testMultithreadedPoolGet (int port, int poll_flag)
    188 {
    189   struct MHD_Daemon *d;
    190   pid_t p;
    191 
    192   d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
    193                         port,
    194                         NULL, NULL,
    195                         &ahc_echo, "GET",
    196                         MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT,
    197                         MHD_OPTION_END);
    198   if (d == NULL)
    199     return 16;
    200   p = do_gets (port);
    201   sleep (1);
    202   MHD_stop_daemon (d);
    203   join_gets (p);
    204   return 0;
    205 }
    206 
    207 
    208 int
    209 main (int argc, char *const *argv)
    210 {
    211   unsigned int errorCount = 0;
    212   int port = 1081;
    213 
    214   oneone = (NULL != strrchr (argv[0], (int) '/')) ?
    215     (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0;
    216   if (0 != curl_global_init (CURL_GLOBAL_WIN32))
    217     return 2;
    218   response = MHD_create_response_from_buffer (strlen ("/hello_world"),
    219 					      "/hello_world",
    220 					      MHD_RESPMEM_MUST_COPY);
    221   errorCount += testMultithreadedGet (port++, 0);
    222   errorCount += testMultithreadedPoolGet (port++, 0);
    223   MHD_destroy_response (response);
    224   if (errorCount != 0)
    225     fprintf (stderr, "Error (code: %u)\n", errorCount);
    226   curl_global_cleanup ();
    227   return errorCount != 0;       /* 0 == pass */
    228 }
    229