lib2405.c (11020B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Dmitry Karpov <dkarpov1970@gmail.com> 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 25 /* 26 * The purpose of this test is to test behavior of curl_multi_waitfds 27 * function in different scenarios: 28 * empty multi handle (expected zero descriptors), 29 * HTTP1 amd HTTP2 (no multiplexing) two transfers (expected two descriptors), 30 * HTTP2 with multiplexing (expected one descriptors) 31 * Improper inputs to the API result in CURLM_BAD_FUNCTION_ARGUMENT. 32 * Sending an empty ufds, and size = 0 will return the number of fds needed. 33 * Sending a non-empty ufds, but smaller than the fds needed will result in a 34 * CURLM_OUT_OF_MEMORY, and a number of fds that is >= to the number needed. 35 * 36 * It is also expected that all transfers run by multi-handle should complete 37 * successfully. 38 */ 39 40 #include "first.h" 41 42 #include "memdebug.h" 43 44 /* ---------------------------------------------------------------- */ 45 46 #define test_check(expected_fds) \ 47 if(res != CURLE_OK) { \ 48 curl_mfprintf(stderr, "test failed with code: %d\n", res); \ 49 goto test_cleanup; \ 50 } \ 51 else if(fd_count != expected_fds) { \ 52 curl_mfprintf(stderr, "Max number of waitfds: %d not as expected: %d\n", \ 53 fd_count, expected_fds); \ 54 res = TEST_ERR_FAILURE; \ 55 goto test_cleanup; \ 56 } 57 58 #define test_run_check(option, expected_fds) do { \ 59 res = test_run(URL, option, &fd_count); \ 60 test_check(expected_fds); \ 61 } while(0) 62 63 /* ---------------------------------------------------------------- */ 64 65 enum { 66 TEST_USE_HTTP1 = 0, 67 TEST_USE_HTTP2, 68 TEST_USE_HTTP2_MPLEX 69 }; 70 71 static size_t emptyWriteFunc(void *ptr, size_t size, size_t nmemb, 72 void *data) { 73 (void)ptr; (void)data; 74 return size * nmemb; 75 } 76 77 static CURLcode set_easy(char *URL, CURL *easy, long option) 78 { 79 CURLcode res = CURLE_OK; 80 81 /* First set the URL that is about to receive our POST. */ 82 easy_setopt(easy, CURLOPT_URL, URL); 83 84 /* get verbose debug output please */ 85 easy_setopt(easy, CURLOPT_VERBOSE, 1L); 86 87 switch(option) { 88 case TEST_USE_HTTP1: 89 /* go http1 */ 90 easy_setopt(easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 91 break; 92 93 case TEST_USE_HTTP2: 94 /* go http2 */ 95 easy_setopt(easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); 96 break; 97 98 case TEST_USE_HTTP2_MPLEX: 99 /* go http2 with multiplexing */ 100 easy_setopt(easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); 101 easy_setopt(easy, CURLOPT_PIPEWAIT, 1L); 102 break; 103 } 104 105 /* no peer verify */ 106 easy_setopt(easy, CURLOPT_SSL_VERIFYPEER, 0L); 107 easy_setopt(easy, CURLOPT_SSL_VERIFYHOST, 0L); 108 109 /* include headers */ 110 easy_setopt(easy, CURLOPT_HEADER, 1L); 111 112 /* empty write function */ 113 easy_setopt(easy, CURLOPT_WRITEFUNCTION, emptyWriteFunc); 114 115 test_cleanup: 116 return res; 117 } 118 119 static CURLcode test_run(char *URL, long option, unsigned int *max_fd_count) 120 { 121 CURLMcode mc = CURLM_OK; 122 CURLM *multi = NULL; 123 CURLM *multi1 = NULL; 124 125 CURL *easy1 = NULL; 126 CURL *easy2 = NULL; 127 128 unsigned int max_count = 0; 129 130 int still_running; /* keep number of running handles */ 131 CURLMsg *msg; /* for picking up messages with the transfer status */ 132 int msgs_left; /* how many messages are left */ 133 134 CURLcode result; 135 CURLcode res = CURLE_OK; 136 137 struct curl_waitfd ufds[10]; 138 struct curl_waitfd ufds1[10]; 139 int numfds; 140 141 easy_init(easy1); 142 easy_init(easy2); 143 144 if(set_easy(URL, easy1, option) != CURLE_OK) 145 goto test_cleanup; 146 147 if(set_easy(URL, easy2, option) != CURLE_OK) 148 goto test_cleanup; 149 150 multi_init(multi); 151 multi_init(multi1); 152 153 if(option == TEST_USE_HTTP2_MPLEX) 154 multi_setopt(multi, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); 155 156 multi_add_handle(multi, easy1); 157 multi_add_handle(multi, easy2); 158 159 while(!mc) { 160 /* get the count of file descriptors from the transfers */ 161 unsigned int fd_count = 0; 162 unsigned int fd_count_chk = 0; 163 164 mc = curl_multi_perform(multi, &still_running); 165 if(!still_running || mc != CURLM_OK) 166 break; 167 168 /* verify improper inputs are treated correctly. */ 169 mc = curl_multi_waitfds(multi, NULL, 0, NULL); 170 171 if(mc != CURLM_BAD_FUNCTION_ARGUMENT) { 172 curl_mfprintf(stderr, "curl_multi_waitfds() return code %d instead of " 173 "CURLM_BAD_FUNCTION_ARGUMENT.\n", mc); 174 res = TEST_ERR_FAILURE; 175 break; 176 } 177 178 mc = curl_multi_waitfds(multi, NULL, 1, NULL); 179 180 if(mc != CURLM_BAD_FUNCTION_ARGUMENT) { 181 curl_mfprintf(stderr, "curl_multi_waitfds() return code %d instead of " 182 "CURLM_BAD_FUNCTION_ARGUMENT.\n", mc); 183 res = TEST_ERR_FAILURE; 184 break; 185 } 186 187 mc = curl_multi_waitfds(multi, NULL, 1, &fd_count); 188 189 if(mc != CURLM_BAD_FUNCTION_ARGUMENT) { 190 curl_mfprintf(stderr, "curl_multi_waitfds() return code %d instead of " 191 "CURLM_BAD_FUNCTION_ARGUMENT.\n", mc); 192 res = TEST_ERR_FAILURE; 193 break; 194 } 195 196 mc = curl_multi_waitfds(multi, ufds, 10, &fd_count); 197 198 if(mc != CURLM_OK) { 199 curl_mfprintf(stderr, "curl_multi_waitfds() failed, code %d.\n", mc); 200 res = TEST_ERR_FAILURE; 201 break; 202 } 203 204 if(!fd_count) 205 continue; /* no descriptors yet */ 206 207 /* verify that sending nothing but the fd_count results in at least the 208 * same number of fds */ 209 mc = curl_multi_waitfds(multi, NULL, 0, &fd_count_chk); 210 211 if(mc != CURLM_OK) { 212 curl_mfprintf(stderr, "curl_multi_waitfds() failed, code %d.\n", mc); 213 res = TEST_ERR_FAILURE; 214 break; 215 } 216 217 if(fd_count_chk < fd_count) { 218 curl_mfprintf(stderr, 219 "curl_multi_waitfds() should return at least the number " 220 "of fds needed\n"); 221 res = TEST_ERR_FAILURE; 222 break; 223 } 224 225 /* checking case when we don't have enough space for waitfds */ 226 mc = curl_multi_waitfds(multi, ufds1, fd_count - 1, &fd_count_chk); 227 228 if(mc != CURLM_OUT_OF_MEMORY) { 229 curl_mfprintf(stderr, "curl_multi_waitfds() return code %d instead of " 230 "CURLM_OUT_OF_MEMORY.\n", mc); 231 res = TEST_ERR_FAILURE; 232 break; 233 } 234 235 if(fd_count_chk < fd_count) { 236 curl_mfprintf(stderr, 237 "curl_multi_waitfds() should return the amount of fds " 238 "needed if enough isn't passed in.\n"); 239 res = TEST_ERR_FAILURE; 240 break; 241 } 242 243 /* sending ufds with zero size, is valid */ 244 mc = curl_multi_waitfds(multi, ufds, 0, NULL); 245 246 if(mc != CURLM_OUT_OF_MEMORY) { 247 curl_mfprintf(stderr, "curl_multi_waitfds() return code %d instead of " 248 "CURLM_OUT_OF_MEMORY.\n", mc); 249 res = TEST_ERR_FAILURE; 250 break; 251 } 252 253 mc = curl_multi_waitfds(multi, ufds, 0, &fd_count_chk); 254 255 if(mc != CURLM_OUT_OF_MEMORY) { 256 curl_mfprintf(stderr, "curl_multi_waitfds() return code %d instead of " 257 "CURLM_OUT_OF_MEMORY.\n", mc); 258 res = TEST_ERR_FAILURE; 259 break; 260 } 261 262 if(fd_count_chk < fd_count) { 263 curl_mfprintf(stderr, 264 "curl_multi_waitfds() should return the amount of fds " 265 "needed if enough isn't passed in.\n"); 266 res = TEST_ERR_FAILURE; 267 break; 268 } 269 270 if(fd_count > max_count) 271 max_count = fd_count; 272 273 /* Do polling on descriptors in ufds in Multi 1 */ 274 mc = curl_multi_poll(multi1, ufds, fd_count, 500, &numfds); 275 276 if(mc != CURLM_OK) { 277 curl_mfprintf(stderr, "curl_multi_poll() failed, code %d.\\n", mc); 278 res = TEST_ERR_FAILURE; 279 break; 280 } 281 } 282 283 for(;;) { 284 msg = curl_multi_info_read(multi, &msgs_left); 285 if(!msg) 286 break; 287 if(msg->msg == CURLMSG_DONE) { 288 result = msg->data.result; 289 290 if(!res) 291 res = result; 292 } 293 } 294 295 curl_multi_remove_handle(multi, easy1); 296 curl_multi_remove_handle(multi, easy2); 297 298 test_cleanup: 299 curl_easy_cleanup(easy1); 300 curl_easy_cleanup(easy2); 301 302 curl_multi_cleanup(multi); 303 curl_multi_cleanup(multi1); 304 305 if(max_fd_count) 306 *max_fd_count = max_count; 307 308 return res; 309 } 310 311 static CURLcode empty_multi_test(void) 312 { 313 CURLMcode mc = CURLM_OK; 314 CURLM *multi = NULL; 315 CURL *easy = NULL; 316 317 struct curl_waitfd ufds[10]; 318 319 CURLcode res = CURLE_OK; 320 unsigned int fd_count = 0; 321 322 multi_init(multi); 323 324 /* calling curl_multi_waitfds() on an empty multi handle. */ 325 mc = curl_multi_waitfds(multi, ufds, 10, &fd_count); 326 327 if(mc != CURLM_OK) { 328 curl_mfprintf(stderr, "curl_multi_waitfds() failed, code %d.\n", mc); 329 res = TEST_ERR_FAILURE; 330 goto test_cleanup; 331 } 332 else if(fd_count > 0) { 333 curl_mfprintf(stderr, "curl_multi_waitfds() returned non-zero count of " 334 "waitfds: %d.\n", fd_count); 335 res = TEST_ERR_FAILURE; 336 goto test_cleanup; 337 } 338 339 /* calling curl_multi_waitfds() on multi handle with added easy handle. */ 340 easy_init(easy); 341 342 if(set_easy((char *)CURL_UNCONST("http://example.com"), easy, 343 TEST_USE_HTTP1) != CURLE_OK) 344 goto test_cleanup; 345 346 multi_add_handle(multi, easy); 347 348 mc = curl_multi_waitfds(multi, ufds, 10, &fd_count); 349 350 if(mc != CURLM_OK) { 351 curl_mfprintf(stderr, "curl_multi_waitfds() failed, code %d.\n", mc); 352 res = TEST_ERR_FAILURE; 353 goto test_cleanup; 354 } 355 else if(fd_count > 0) { 356 curl_mfprintf(stderr, "curl_multi_waitfds() returned non-zero count of " 357 "waitfds: %d.\n", fd_count); 358 res = TEST_ERR_FAILURE; 359 goto test_cleanup; 360 } 361 362 curl_multi_remove_handle(multi, easy); 363 364 test_cleanup: 365 curl_easy_cleanup(easy); 366 curl_multi_cleanup(multi); 367 return res; 368 } 369 370 static CURLcode test_lib2405(char *URL) 371 { 372 CURLcode res = CURLE_OK; 373 unsigned int fd_count = 0; 374 375 global_init(CURL_GLOBAL_ALL); 376 377 /* Testing curl_multi_waitfds on empty and not started handles */ 378 res = empty_multi_test(); 379 if(res != CURLE_OK) 380 goto test_cleanup; 381 382 /* HTTP1, expected 2 waitfds - one for each transfer */ 383 test_run_check(TEST_USE_HTTP1, 2); 384 385 /* HTTP2, expected 2 waitfds - one for each transfer */ 386 test_run_check(TEST_USE_HTTP2, 2); 387 388 /* HTTP2 with multiplexing, expected 1 waitfds - one for all transfers */ 389 test_run_check(TEST_USE_HTTP2_MPLEX, 1); 390 391 test_cleanup: 392 curl_global_cleanup(); 393 return res; 394 }