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