test_https_get_parallel_threads.c (5838B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007 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_https_get_parallel_threads.c 24 * @brief Testcase for libmicrohttpd HTTPS GET operations with multi-threaded 25 * MHD daemon and several clients working in parallel 26 * @author Sagie Amir 27 * @author Christian Grothoff 28 * @author Karlson2k (Evgeny Grin) 29 * 30 * TODO: add test for external select! 31 */ 32 33 #include "platform.h" 34 #include "microhttpd.h" 35 #include <sys/stat.h> 36 #include <limits.h> 37 #include <curl/curl.h> 38 #include <pthread.h> 39 #ifdef MHD_HTTPS_REQUIRE_GCRYPT 40 #include <gcrypt.h> 41 #endif /* MHD_HTTPS_REQUIRE_GCRYPT */ 42 #include "tls_test_common.h" 43 #include "tls_test_keys.h" 44 45 /* Turn any MHD_PANIC() or failing mhd_assert() reached from this 46 test into a marked, classifiable test error (TESTING.md, P5). */ 47 #include "mhd_panic_tripwire.h" 48 49 #if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 4 50 #undef MHD_CPU_COUNT 51 #endif 52 #if ! defined(MHD_CPU_COUNT) 53 #define MHD_CPU_COUNT 4 54 #endif 55 56 /** 57 * used when spawning multiple threads executing curl server requests 58 * 59 */ 60 static void * 61 https_transfer_thread_adapter (void *args) 62 { 63 static int nonnull; 64 struct https_test_data *cargs = args; 65 unsigned int ret; 66 67 ret = test_https_transfer (cargs->cls, cargs->port, 68 cargs->cipher_suite, cargs->proto_version); 69 if (ret == 0) 70 return NULL; 71 return &nonnull; 72 } 73 74 75 /** 76 * Test non-parallel requests. 77 * 78 * @return: 0 upon all client requests returning '0', 1 otherwise. 79 * 80 * TODO : make client_count a parameter - number of curl client threads to spawn 81 */ 82 static unsigned int 83 test_single_client (void *cls, uint16_t port, const char *cipher_suite, 84 int curl_proto_version) 85 { 86 void *client_thread_ret; 87 struct https_test_data client_args = 88 { NULL, port, cipher_suite, curl_proto_version }; 89 (void) cls; /* Unused. Silent compiler warning. */ 90 91 client_thread_ret = https_transfer_thread_adapter (&client_args); 92 if (client_thread_ret != NULL) 93 return 1; 94 return 0; 95 } 96 97 98 /** 99 * Test parallel request handling. 100 * 101 * @return: 0 upon all client requests returning '0', 1 otherwise. 102 * 103 * TODO : make client_count a parameter - number of curl client threads to spawn 104 */ 105 static unsigned int 106 test_parallel_clients (void *cls, uint16_t port, const char *cipher_suite, 107 int curl_proto_version) 108 { 109 int i; 110 int client_count = (MHD_CPU_COUNT - 1); 111 void *client_thread_ret; 112 pthread_t client_arr[client_count]; 113 struct https_test_data client_args = 114 { NULL, port, cipher_suite, curl_proto_version }; 115 (void) cls; /* Unused. Silent compiler warning. */ 116 117 for (i = 0; i < client_count; ++i) 118 { 119 if (pthread_create (&client_arr[i], NULL, 120 &https_transfer_thread_adapter, &client_args) != 0) 121 { 122 fprintf (stderr, "Error: failed to spawn test client threads.\n"); 123 124 return 1; 125 } 126 } 127 128 /* check all client requests fulfilled correctly */ 129 for (i = 0; i < client_count; ++i) 130 { 131 if ((pthread_join (client_arr[i], &client_thread_ret) != 0) || 132 (client_thread_ret != NULL)) 133 return 1; 134 } 135 136 return 0; 137 } 138 139 140 int 141 main (int argc, char *const *argv) 142 { 143 unsigned int errorCount = 0; 144 const char *ssl_version; 145 uint16_t port; 146 unsigned int iseed; 147 (void) argc; /* Unused. Silent compiler warning. */ 148 149 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 150 port = 0; 151 else 152 port = 3010; 153 154 /* initialize random seed used by curl clients */ 155 iseed = (unsigned int) time (NULL); 156 157 #ifdef MHD_HTTPS_REQUIRE_GCRYPT 158 #ifdef GCRYCTL_INITIALIZATION_FINISHED 159 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); 160 #endif 161 #endif /* MHD_HTTPS_REQUIRE_GCRYPT */ 162 srand (iseed); 163 if (! testsuite_curl_global_init ()) 164 return 99; 165 ssl_version = curl_version_info (CURLVERSION_NOW)->ssl_version; 166 if (NULL == ssl_version) 167 { 168 fprintf (stderr, "Curl does not support SSL. Cannot run the test.\n"); 169 curl_global_cleanup (); 170 return 77; 171 } 172 173 errorCount += 174 test_wrap ("multi threaded daemon, single client", &test_single_client, 175 NULL, port, 176 MHD_USE_TLS | MHD_USE_ERROR_LOG | MHD_USE_THREAD_PER_CONNECTION 177 | MHD_USE_INTERNAL_POLLING_THREAD, 178 NULL, CURL_SSLVERSION_DEFAULT, MHD_OPTION_HTTPS_MEM_KEY, 179 srv_self_signed_key_pem, MHD_OPTION_HTTPS_MEM_CERT, 180 srv_self_signed_cert_pem, MHD_OPTION_END); 181 182 errorCount += 183 test_wrap ("multi threaded daemon, parallel client", 184 &test_parallel_clients, NULL, port, 185 MHD_USE_TLS | MHD_USE_ERROR_LOG | MHD_USE_THREAD_PER_CONNECTION 186 | MHD_USE_INTERNAL_POLLING_THREAD, 187 NULL, CURL_SSLVERSION_DEFAULT, MHD_OPTION_HTTPS_MEM_KEY, 188 srv_self_signed_key_pem, MHD_OPTION_HTTPS_MEM_CERT, 189 srv_self_signed_cert_pem, MHD_OPTION_END); 190 191 if (errorCount != 0) 192 fprintf (stderr, "Failed test: %s, error: %u.\n", argv[0], errorCount); 193 194 curl_global_cleanup (); 195 return errorCount != 0 ? 1 : 0; 196 }