test_get_wait.c (6782B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007, 2009, 2011 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 test_get_wait.c 24 * @brief Test 'MHD_run_wait()' function. 25 * @author Christian Grothoff 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 <pthread.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 #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 /** 51 * How many rounds of operations do we do for each 52 * test. 53 * Check all three types of requests for HTTP/1.1: 54 * * first request, new connection; 55 * * "middle" request, existing connection with stay-alive; 56 * * final request, no data processed after. 57 */ 58 #define ROUNDS 3 59 60 /** 61 * Do we use HTTP 1.1? 62 */ 63 static int oneone; 64 65 /** 66 * Response to return (re-used). 67 */ 68 static struct MHD_Response *response; 69 70 /** 71 * Set to 1 if the worker threads are done. 72 */ 73 static volatile int signal_done; 74 75 76 static size_t 77 copyBuffer (void *ptr, 78 size_t size, size_t nmemb, 79 void *ctx) 80 { 81 (void) ptr; (void) ctx; /* Unused. Silent compiler warning. */ 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 ptr; 96 enum MHD_Result ret; 97 (void) cls; 98 (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 (MHD_HTTP_METHOD_GET, method)) 102 return MHD_NO; /* unexpected method */ 103 if (&ptr != *req_cls) 104 { 105 *req_cls = &ptr; 106 return MHD_YES; 107 } 108 *req_cls = NULL; 109 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 110 if (ret == MHD_NO) 111 abort (); 112 return ret; 113 } 114 115 116 static void * 117 thread_gets (void *param) 118 { 119 CURL *c; 120 CURLcode errornum; 121 unsigned int i; 122 char url[64]; 123 uint16_t port = (uint16_t) (intptr_t) param; 124 125 snprintf (url, 126 sizeof (url), 127 "http://127.0.0.1:%u/hello_world", 128 (unsigned int) port); 129 130 c = curl_easy_init (); 131 if (NULL == c) 132 _exit (99); 133 curl_easy_setopt (c, CURLOPT_URL, url); 134 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); 135 curl_easy_setopt (c, CURLOPT_WRITEDATA, NULL); 136 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L); 137 curl_easy_setopt (c, CURLOPT_TIMEOUT, 15L); 138 if (oneone) 139 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 140 else 141 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); 142 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); 143 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 144 for (i = 0; i < ROUNDS; i++) 145 { 146 if (CURLE_OK != (errornum = curl_easy_perform (c))) 147 { 148 signal_done = 1; 149 fprintf (stderr, 150 "curl_easy_perform failed: `%s'\n", 151 curl_easy_strerror (errornum)); 152 curl_easy_cleanup (c); 153 abort (); 154 } 155 } 156 curl_easy_cleanup (c); 157 signal_done = 1; 158 159 return NULL; 160 } 161 162 163 static unsigned int 164 testRunWaitGet (uint16_t port, uint32_t poll_flag) 165 { 166 pthread_t get_tid; 167 struct MHD_Daemon *d; 168 const char *const test_desc = ((poll_flag & MHD_USE_AUTO) ? 169 "MHD_USE_AUTO" : 170 (poll_flag & MHD_USE_POLL) ? 171 "MHD_USE_POLL" : 172 (poll_flag & MHD_USE_EPOLL) ? 173 "MHD_USE_EPOLL" : 174 "select()"); 175 176 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 177 port = 0; 178 179 printf ("Starting MHD_run_wait() test with MHD in %s polling mode.\n", 180 test_desc); 181 signal_done = 0; 182 d = MHD_start_daemon (MHD_USE_ERROR_LOG | (enum MHD_FLAG) poll_flag, 183 port, NULL, NULL, &ahc_echo, NULL, MHD_OPTION_END); 184 if (d == NULL) 185 abort (); 186 if (0 == port) 187 { 188 const union MHD_DaemonInfo *dinfo; 189 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 190 if ((NULL == dinfo) || (0 == dinfo->port) ) 191 abort (); 192 port = dinfo->port; 193 } 194 195 if (0 != pthread_create (&get_tid, NULL, 196 &thread_gets, (void *) (intptr_t) port)) 197 _exit (99); 198 199 /* As another thread sets "done" flag after ending of network 200 * activity, it's required to set positive timeout value for MHD_run_wait(). 201 * Alternatively, to use timeout value "-1" here, another thread should start 202 * additional connection to wake MHD after setting "done" flag. */ 203 do 204 { 205 if (MHD_NO == MHD_run_wait (d, 50)) 206 abort (); 207 } while (0 == signal_done); 208 209 if (0 != pthread_join (get_tid, NULL)) 210 _exit (99); 211 212 MHD_stop_daemon (d); 213 printf ("Test succeeded.\n"); 214 return 0; 215 } 216 217 218 int 219 main (int argc, char *const *argv) 220 { 221 uint16_t port = 1675; 222 (void) argc; /* Unused. Silent compiler warning. */ 223 224 if ((NULL == argv) || (0 == argv[0])) 225 return 99; 226 oneone = has_in_name (argv[0], "11"); 227 if (oneone) 228 port += 5; 229 if (0 != curl_global_init (CURL_GLOBAL_WIN32)) 230 return 2; 231 response = MHD_create_response_from_buffer_static (strlen ("/hello_world"), 232 "/hello_world"); 233 testRunWaitGet (port++, 0); 234 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_EPOLL)) 235 testRunWaitGet (port++, MHD_USE_EPOLL); 236 testRunWaitGet (port++, MHD_USE_AUTO); 237 238 MHD_destroy_response (response); 239 curl_global_cleanup (); 240 return 0; /* Errors produce abort() or _exit() */ 241 }