1 /* DO NOT CHANGE THIS LINE */ 2 /* 3 This file is part of libmicrohttpd 4 Copyright (C) 2007, 2009 Christian Grothoff 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., 59 Temple Place - Suite 330, 19 Boston, MA 02111-1307, USA. 20 */ 21 22 /** 23 * @file daemontest_get_response_cleanup.c 24 * @brief Testcase for libmicrohttpd response cleanup 25 * @author Christian Grothoff 26 */ 27 28 #include "MHD_config.h" 29 #include "platform.h" 30 #include <microhttpd.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <string.h> 34 #include <time.h> 35 #include <sys/types.h> 36 #include <sys/wait.h> 37 #include <fcntl.h> 38 39 #ifndef WINDOWS 40 #include <sys/socket.h> 41 #include <unistd.h> 42 #endif 43 44 #ifdef _WIN32 45 #ifndef WIN32_LEAN_AND_MEAN 46 #define WIN32_LEAN_AND_MEAN 1 47 #endif /* !WIN32_LEAN_AND_MEAN */ 48 #include <windows.h> 49 #endif 50 51 #if defined(CPU_COUNT) && (CPU_COUNT+0) < 2 52 #undef CPU_COUNT 53 #endif 54 #if !defined(CPU_COUNT) 55 #define CPU_COUNT 2 56 #endif 57 58 #define TESTSTR "/* DO NOT CHANGE THIS LINE */" 59 60 static int oneone; 61 62 static int ok; 63 64 65 static pid_t 66 fork_curl (const char *url) 67 { 68 pid_t ret; 69 70 ret = fork(); 71 if (ret != 0) 72 return ret; 73 execlp ("curl", "curl", "-s", "-N", "-o", "/dev/null", "-GET", url, NULL); 74 fprintf (stderr, 75 "Failed to exec curl: %s\n", 76 strerror (errno)); 77 _exit (-1); 78 } 79 80 static void 81 kill_curl (pid_t pid) 82 { 83 int status; 84 85 //fprintf (stderr, "Killing curl\n"); 86 kill (pid, SIGTERM); 87 waitpid (pid, &status, 0); 88 } 89 90 91 static ssize_t 92 push_callback (void *cls, uint64_t pos, char *buf, size_t max) 93 { 94 if (max == 0) 95 return 0; 96 buf[0] = 'd'; 97 return 1; 98 } 99 100 static void 101 push_free_callback (void *cls) 102 { 103 int *ok = cls; 104 105 //fprintf (stderr, "Cleanup callback called!\n"); 106 *ok = 0; 107 } 108 109 110 static int 111 ahc_echo (void *cls, 112 struct MHD_Connection *connection, 113 const char *url, 114 const char *method, 115 const char *version, 116 const char *upload_data, size_t *upload_data_size, 117 void **unused) 118 { 119 static int ptr; 120 const char *me = cls; 121 struct MHD_Response *response; 122 int ret; 123 124 //fprintf (stderr, "In CB: %s!\n", method); 125 if (0 != strcmp (me, method)) 126 return MHD_NO; /* unexpected method */ 127 if (&ptr != *unused) 128 { 129 *unused = &ptr; 130 return MHD_YES; 131 } 132 *unused = NULL; 133 response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 134 32 * 1024, 135 &push_callback, 136 &ok, 137 &push_free_callback); 138 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 139 MHD_destroy_response (response); 140 if (ret == MHD_NO) 141 abort (); 142 return ret; 143 } 144 145 146 static int 147 testInternalGet () 148 { 149 struct MHD_Daemon *d; 150 pid_t curl; 151 152 ok = 1; 153 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, 154 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); 155 if (d == NULL) 156 return 1; 157 curl = fork_curl ("http://127.0.0.1:11080/"); 158 sleep (1); 159 kill_curl (curl); 160 sleep (1); 161 // fprintf (stderr, "Stopping daemon!\n"); 162 MHD_stop_daemon (d); 163 if (ok != 0) 164 return 2; 165 return 0; 166 } 167 168 static int 169 testMultithreadedGet () 170 { 171 struct MHD_Daemon *d; 172 pid_t curl; 173 174 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, 175 1081, NULL, NULL, &ahc_echo, "GET", 176 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 2, 177 MHD_OPTION_END); 178 if (d == NULL) 179 return 16; 180 ok = 1; 181 //fprintf (stderr, "Forking cURL!\n"); 182 curl = fork_curl ("http://127.0.0.1:1081/"); 183 sleep (1); 184 kill_curl (curl); 185 sleep (1); 186 curl = fork_curl ("http://127.0.0.1:1081/"); 187 sleep (1); 188 if (ok != 0) 189 { 190 kill_curl (curl); 191 MHD_stop_daemon (d); 192 return 64; 193 } 194 kill_curl (curl); 195 sleep (1); 196 //fprintf (stderr, "Stopping daemon!\n"); 197 MHD_stop_daemon (d); 198 if (ok != 0) 199 return 32; 200 201 return 0; 202 } 203 204 static int 205 testMultithreadedPoolGet () 206 { 207 struct MHD_Daemon *d; 208 pid_t curl; 209 210 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, 211 1081, NULL, NULL, &ahc_echo, "GET", 212 MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT, MHD_OPTION_END); 213 if (d == NULL) 214 return 64; 215 ok = 1; 216 curl = fork_curl ("http://127.0.0.1:1081/"); 217 sleep (1); 218 kill_curl (curl); 219 sleep (1); 220 //fprintf (stderr, "Stopping daemon!\n"); 221 MHD_stop_daemon (d); 222 if (ok != 0) 223 return 128; 224 return 0; 225 } 226 227 static int 228 testExternalGet () 229 { 230 struct MHD_Daemon *d; 231 fd_set rs; 232 fd_set ws; 233 fd_set es; 234 MHD_socket max; 235 time_t start; 236 struct timeval tv; 237 pid_t curl; 238 239 d = MHD_start_daemon (MHD_USE_DEBUG, 240 1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); 241 if (d == NULL) 242 return 256; 243 curl = fork_curl ("http://127.0.0.1:1082/"); 244 245 start = time (NULL); 246 while ((time (NULL) - start < 2)) 247 { 248 max = 0; 249 FD_ZERO (&rs); 250 FD_ZERO (&ws); 251 FD_ZERO (&es); 252 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) 253 { 254 MHD_stop_daemon (d); 255 return 4096; 256 } 257 tv.tv_sec = 0; 258 tv.tv_usec = 1000; 259 select (max + 1, &rs, &ws, &es, &tv); 260 MHD_run (d); 261 } 262 kill_curl (curl); 263 start = time (NULL); 264 while ((time (NULL) - start < 2)) 265 { 266 max = 0; 267 FD_ZERO (&rs); 268 FD_ZERO (&ws); 269 FD_ZERO (&es); 270 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) 271 { 272 MHD_stop_daemon (d); 273 return 4096; 274 } 275 tv.tv_sec = 0; 276 tv.tv_usec = 1000; 277 select (max + 1, &rs, &ws, &es, &tv); 278 MHD_run (d); 279 } 280 // fprintf (stderr, "Stopping daemon!\n"); 281 MHD_stop_daemon (d); 282 if (ok != 0) 283 return 1024; 284 return 0; 285 } 286 287 288 int 289 main (int argc, char *const *argv) 290 { 291 unsigned int errorCount = 0; 292 293 oneone = (NULL != strrchr (argv[0], (int) '/')) ? 294 (NULL != strstr (strrchr (argv[0], (int) '/'), "11")) : 0; 295 errorCount += testInternalGet (); 296 errorCount += testMultithreadedGet (); 297 errorCount += testMultithreadedPoolGet (); 298 errorCount += testExternalGet (); 299 if (errorCount != 0) 300 fprintf (stderr, "Error (code: %u)\n", errorCount); 301 return errorCount != 0; /* 0 == pass */ 302 } 303