test_https_get_parallel_threads.c (5671B)
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 #if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 4 46 #undef MHD_CPU_COUNT 47 #endif 48 #if ! defined(MHD_CPU_COUNT) 49 #define MHD_CPU_COUNT 4 50 #endif 51 52 /** 53 * used when spawning multiple threads executing curl server requests 54 * 55 */ 56 static void * 57 https_transfer_thread_adapter (void *args) 58 { 59 static int nonnull; 60 struct https_test_data *cargs = args; 61 unsigned int ret; 62 63 ret = test_https_transfer (cargs->cls, cargs->port, 64 cargs->cipher_suite, cargs->proto_version); 65 if (ret == 0) 66 return NULL; 67 return &nonnull; 68 } 69 70 71 /** 72 * Test non-parallel requests. 73 * 74 * @return: 0 upon all client requests returning '0', 1 otherwise. 75 * 76 * TODO : make client_count a parameter - number of curl client threads to spawn 77 */ 78 static unsigned int 79 test_single_client (void *cls, uint16_t port, const char *cipher_suite, 80 int curl_proto_version) 81 { 82 void *client_thread_ret; 83 struct https_test_data client_args = 84 { NULL, port, cipher_suite, curl_proto_version }; 85 (void) cls; /* Unused. Silent compiler warning. */ 86 87 client_thread_ret = https_transfer_thread_adapter (&client_args); 88 if (client_thread_ret != NULL) 89 return 1; 90 return 0; 91 } 92 93 94 /** 95 * Test parallel request handling. 96 * 97 * @return: 0 upon all client requests returning '0', 1 otherwise. 98 * 99 * TODO : make client_count a parameter - number of curl client threads to spawn 100 */ 101 static unsigned int 102 test_parallel_clients (void *cls, uint16_t port, const char *cipher_suite, 103 int curl_proto_version) 104 { 105 int i; 106 int client_count = (MHD_CPU_COUNT - 1); 107 void *client_thread_ret; 108 pthread_t client_arr[client_count]; 109 struct https_test_data client_args = 110 { NULL, port, cipher_suite, curl_proto_version }; 111 (void) cls; /* Unused. Silent compiler warning. */ 112 113 for (i = 0; i < client_count; ++i) 114 { 115 if (pthread_create (&client_arr[i], NULL, 116 &https_transfer_thread_adapter, &client_args) != 0) 117 { 118 fprintf (stderr, "Error: failed to spawn test client threads.\n"); 119 120 return 1; 121 } 122 } 123 124 /* check all client requests fulfilled correctly */ 125 for (i = 0; i < client_count; ++i) 126 { 127 if ((pthread_join (client_arr[i], &client_thread_ret) != 0) || 128 (client_thread_ret != NULL)) 129 return 1; 130 } 131 132 return 0; 133 } 134 135 136 int 137 main (int argc, char *const *argv) 138 { 139 unsigned int errorCount = 0; 140 const char *ssl_version; 141 uint16_t port; 142 unsigned int iseed; 143 (void) argc; /* Unused. Silent compiler warning. */ 144 145 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 146 port = 0; 147 else 148 port = 3010; 149 150 /* initialize random seed used by curl clients */ 151 iseed = (unsigned int) time (NULL); 152 153 #ifdef MHD_HTTPS_REQUIRE_GCRYPT 154 #ifdef GCRYCTL_INITIALIZATION_FINISHED 155 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); 156 #endif 157 #endif /* MHD_HTTPS_REQUIRE_GCRYPT */ 158 srand (iseed); 159 if (! testsuite_curl_global_init ()) 160 return 99; 161 ssl_version = curl_version_info (CURLVERSION_NOW)->ssl_version; 162 if (NULL == ssl_version) 163 { 164 fprintf (stderr, "Curl does not support SSL. Cannot run the test.\n"); 165 curl_global_cleanup (); 166 return 77; 167 } 168 169 errorCount += 170 test_wrap ("multi threaded daemon, single client", &test_single_client, 171 NULL, port, 172 MHD_USE_TLS | MHD_USE_ERROR_LOG | MHD_USE_THREAD_PER_CONNECTION 173 | MHD_USE_INTERNAL_POLLING_THREAD, 174 NULL, CURL_SSLVERSION_DEFAULT, MHD_OPTION_HTTPS_MEM_KEY, 175 srv_self_signed_key_pem, MHD_OPTION_HTTPS_MEM_CERT, 176 srv_self_signed_cert_pem, MHD_OPTION_END); 177 178 errorCount += 179 test_wrap ("multi threaded daemon, parallel client", 180 &test_parallel_clients, NULL, port, 181 MHD_USE_TLS | MHD_USE_ERROR_LOG | MHD_USE_THREAD_PER_CONNECTION 182 | MHD_USE_INTERNAL_POLLING_THREAD, 183 NULL, CURL_SSLVERSION_DEFAULT, MHD_OPTION_HTTPS_MEM_KEY, 184 srv_self_signed_key_pem, MHD_OPTION_HTTPS_MEM_CERT, 185 srv_self_signed_cert_pem, MHD_OPTION_END); 186 187 if (errorCount != 0) 188 fprintf (stderr, "Failed test: %s, error: %u.\n", argv[0], errorCount); 189 190 curl_global_cleanup (); 191 return errorCount != 0 ? 1 : 0; 192 }