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, ©Buffer); 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