1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 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#include "test.h" 25 26#ifdef HAVE_SYS_RESOURCE_H 27#include <sys/resource.h> 28#endif 29#ifdef HAVE_FCNTL_H 30#include <fcntl.h> 31#endif 32#include <limits.h> 33 34#include "warnless.h" 35#include "memdebug.h" 36 37#ifndef FD_SETSIZE 38#error "this test requires FD_SETSIZE" 39#endif 40 41#define SAFETY_MARGIN (16) 42#define NUM_OPEN (FD_SETSIZE + 10) 43#define NUM_NEEDED (NUM_OPEN + SAFETY_MARGIN) 44 45#if defined(_WIN32) || defined(MSDOS) 46#define DEV_NULL "NUL" 47#else 48#define DEV_NULL "/dev/null" 49#endif 50 51#if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) 52 53static int *fd = NULL; 54static struct rlimit num_open; 55static char msgbuff[256]; 56 57static void store_errmsg(const char *msg, int err) 58{ 59 if(!err) 60 msnprintf(msgbuff, sizeof(msgbuff), "%s", msg); 61 else 62 msnprintf(msgbuff, sizeof(msgbuff), "%s, errno %d, %s", msg, 63 err, strerror(err)); 64} 65 66static void close_file_descriptors(void) 67{ 68 for(num_open.rlim_cur = 0; 69 num_open.rlim_cur < num_open.rlim_max; 70 num_open.rlim_cur++) 71 if(fd[num_open.rlim_cur] > 0) 72 close(fd[num_open.rlim_cur]); 73 free(fd); 74 fd = NULL; 75} 76 77static int fopen_works(void) 78{ 79 FILE *fpa[3]; 80 int i; 81 int ret = 1; 82 83 for(i = 0; i < 3; i++) { 84 fpa[i] = NULL; 85 } 86 for(i = 0; i < 3; i++) { 87 fpa[i] = fopen(DEV_NULL, FOPEN_READTEXT); 88 if(!fpa[i]) { 89 store_errmsg("fopen failed", errno); 90 fprintf(stderr, "%s\n", msgbuff); 91 ret = 0; 92 break; 93 } 94 } 95 for(i = 0; i < 3; i++) { 96 if(fpa[i]) 97 fclose(fpa[i]); 98 } 99 return ret; 100} 101 102static void rlim2str(char *buf, size_t len, rlim_t val) 103{ 104#ifdef RLIM_INFINITY 105 if(val == RLIM_INFINITY) { 106 msnprintf(buf, len, "INFINITY"); 107 return; 108 } 109#endif 110#ifdef HAVE_LONGLONG 111 if(sizeof(rlim_t) > sizeof(long)) 112 msnprintf(buf, len, "%llu", (unsigned long long)val); 113 else 114#endif 115 { 116 if(sizeof(rlim_t) < sizeof(long)) 117 msnprintf(buf, len, "%u", (unsigned int)val); 118 else 119 msnprintf(buf, len, "%lu", (unsigned long)val); 120 } 121} 122 123static int rlimit(int keep_open) 124{ 125 rlim_t nitems, i; 126 int *memchunk = NULL; 127 struct rlimit rl; 128 char strbuff[256]; 129 char strbuff1[81]; 130 char strbuff2[81]; 131 132 /* get initial open file limits */ 133 134 if(getrlimit(RLIMIT_NOFILE, &rl) != 0) { 135 store_errmsg("getrlimit() failed", errno); 136 fprintf(stderr, "%s\n", msgbuff); 137 return -1; 138 } 139 140 /* show initial open file limits */ 141 142 rlim2str(strbuff, sizeof(strbuff), rl.rlim_cur); 143 fprintf(stderr, "initial soft limit: %s\n", strbuff); 144 145 rlim2str(strbuff, sizeof(strbuff), rl.rlim_max); 146 fprintf(stderr, "initial hard limit: %s\n", strbuff); 147 148 /* show our constants */ 149 150 fprintf(stderr, "test518 FD_SETSIZE: %d\n", FD_SETSIZE); 151 fprintf(stderr, "test518 NUM_OPEN : %d\n", NUM_OPEN); 152 fprintf(stderr, "test518 NUM_NEEDED: %d\n", NUM_NEEDED); 153 154 /* 155 * if soft limit and hard limit are different we ask the 156 * system to raise soft limit all the way up to the hard 157 * limit. Due to some other system limit the soft limit 158 * might not be raised up to the hard limit. So from this 159 * point the resulting soft limit is our limit. Trying to 160 * open more than soft limit file descriptors will fail. 161 */ 162 163 if(rl.rlim_cur != rl.rlim_max) { 164 165#ifdef OPEN_MAX 166 if((rl.rlim_cur > 0) && 167 (rl.rlim_cur < OPEN_MAX)) { 168 fprintf(stderr, "raising soft limit up to OPEN_MAX\n"); 169 rl.rlim_cur = OPEN_MAX; 170 if(setrlimit(RLIMIT_NOFILE, &rl) != 0) { 171 /* on failure don't abort just issue a warning */ 172 store_errmsg("setrlimit() failed", errno); 173 fprintf(stderr, "%s\n", msgbuff); 174 msgbuff[0] = '\0'; 175 } 176 } 177#endif 178 179 fprintf(stderr, "raising soft limit up to hard limit\n"); 180 rl.rlim_cur = rl.rlim_max; 181 if(setrlimit(RLIMIT_NOFILE, &rl) != 0) { 182 /* on failure don't abort just issue a warning */ 183 store_errmsg("setrlimit() failed", errno); 184 fprintf(stderr, "%s\n", msgbuff); 185 msgbuff[0] = '\0'; 186 } 187 188 /* get current open file limits */ 189 190 if(getrlimit(RLIMIT_NOFILE, &rl) != 0) { 191 store_errmsg("getrlimit() failed", errno); 192 fprintf(stderr, "%s\n", msgbuff); 193 return -3; 194 } 195 196 /* show current open file limits */ 197 198 rlim2str(strbuff, sizeof(strbuff), rl.rlim_cur); 199 fprintf(stderr, "current soft limit: %s\n", strbuff); 200 201 rlim2str(strbuff, sizeof(strbuff), rl.rlim_max); 202 fprintf(stderr, "current hard limit: %s\n", strbuff); 203 204 } /* (rl.rlim_cur != rl.rlim_max) */ 205 206 /* 207 * test 518 is all about testing libcurl functionality 208 * when more than FD_SETSIZE file descriptors are open. 209 * This means that if for any reason we are not able to 210 * open more than FD_SETSIZE file descriptors then test 211 * 518 should not be run. 212 */ 213 214 /* 215 * verify that soft limit is higher than NUM_NEEDED, 216 * which is the number of file descriptors we would 217 * try to open plus SAFETY_MARGIN to not exhaust the 218 * file descriptor pool 219 */ 220 221 num_open.rlim_cur = NUM_NEEDED; 222 223 if((rl.rlim_cur > 0) && 224#ifdef RLIM_INFINITY 225 (rl.rlim_cur != RLIM_INFINITY) && 226#endif 227 (rl.rlim_cur <= num_open.rlim_cur)) { 228 rlim2str(strbuff2, sizeof(strbuff2), rl.rlim_cur); 229 rlim2str(strbuff1, sizeof(strbuff1), num_open.rlim_cur); 230 msnprintf(strbuff, sizeof(strbuff), "fds needed %s > system limit %s", 231 strbuff1, strbuff2); 232 store_errmsg(strbuff, 0); 233 fprintf(stderr, "%s\n", msgbuff); 234 return -4; 235 } 236 237 /* 238 * reserve a chunk of memory before opening file descriptors to 239 * avoid a low memory condition once the file descriptors are 240 * open. System conditions that could make the test fail should 241 * be addressed in the precheck phase. This chunk of memory shall 242 * be always free()ed before exiting the rlimit() function so 243 * that it becomes available to the test. 244 */ 245 246 for(nitems = i = 1; nitems <= i; i *= 2) 247 nitems = i; 248 if(nitems > 0x7fff) 249 nitems = 0x40000; 250 do { 251 num_open.rlim_max = sizeof(*memchunk) * nitems; 252 rlim2str(strbuff, sizeof(strbuff), num_open.rlim_max); 253 fprintf(stderr, "allocating memchunk %s byte array\n", strbuff); 254 memchunk = malloc(sizeof(*memchunk) * (size_t)nitems); 255 if(!memchunk) { 256 fprintf(stderr, "memchunk, malloc() failed\n"); 257 nitems /= 2; 258 } 259 } while(nitems && !memchunk); 260 if(!memchunk) { 261 store_errmsg("memchunk, malloc() failed", errno); 262 fprintf(stderr, "%s\n", msgbuff); 263 return -5; 264 } 265 266 /* initialize it to fight lazy allocation */ 267 268 fprintf(stderr, "initializing memchunk array\n"); 269 270 for(i = 0; i < nitems; i++) 271 memchunk[i] = -1; 272 273 /* set the number of file descriptors we will try to open */ 274 275 num_open.rlim_max = NUM_OPEN; 276 277 /* verify that we won't overflow size_t in malloc() */ 278 279 if((size_t)(num_open.rlim_max) > ((size_t)-1) / sizeof(*fd)) { 280 rlim2str(strbuff1, sizeof(strbuff1), num_open.rlim_max); 281 msnprintf(strbuff, sizeof(strbuff), "unable to allocate an array for %s " 282 "file descriptors, would overflow size_t", strbuff1); 283 store_errmsg(strbuff, 0); 284 fprintf(stderr, "%s\n", msgbuff); 285 free(memchunk); 286 return -6; 287 } 288 289 /* allocate array for file descriptors */ 290 291 rlim2str(strbuff, sizeof(strbuff), num_open.rlim_max); 292 fprintf(stderr, "allocating array for %s file descriptors\n", strbuff); 293 294 fd = malloc(sizeof(*fd) * (size_t)(num_open.rlim_max)); 295 if(!fd) { 296 store_errmsg("fd, malloc() failed", errno); 297 fprintf(stderr, "%s\n", msgbuff); 298 free(memchunk); 299 return -7; 300 } 301 302 /* initialize it to fight lazy allocation */ 303 304 fprintf(stderr, "initializing fd array\n"); 305 306 for(num_open.rlim_cur = 0; 307 num_open.rlim_cur < num_open.rlim_max; 308 num_open.rlim_cur++) 309 fd[num_open.rlim_cur] = -1; 310 311 rlim2str(strbuff, sizeof(strbuff), num_open.rlim_max); 312 fprintf(stderr, "trying to open %s file descriptors\n", strbuff); 313 314 /* open a dummy descriptor */ 315 316 fd[0] = open(DEV_NULL, O_RDONLY); 317 if(fd[0] < 0) { 318 msnprintf(strbuff, sizeof(strbuff), "opening of %s failed", DEV_NULL); 319 store_errmsg(strbuff, errno); 320 fprintf(stderr, "%s\n", msgbuff); 321 free(fd); 322 fd = NULL; 323 free(memchunk); 324 return -8; 325 } 326 327 /* create a bunch of file descriptors */ 328 329 for(num_open.rlim_cur = 1; 330 num_open.rlim_cur < num_open.rlim_max; 331 num_open.rlim_cur++) { 332 333 fd[num_open.rlim_cur] = dup(fd[0]); 334 335 if(fd[num_open.rlim_cur] < 0) { 336 337 fd[num_open.rlim_cur] = -1; 338 339 rlim2str(strbuff1, sizeof(strbuff1), num_open.rlim_cur); 340 msnprintf(strbuff, sizeof(strbuff), "dup() attempt %s failed", strbuff1); 341 fprintf(stderr, "%s\n", strbuff); 342 343 rlim2str(strbuff1, sizeof(strbuff1), num_open.rlim_cur); 344 msnprintf(strbuff, sizeof(strbuff), "fds system limit seems close to %s", 345 strbuff1); 346 fprintf(stderr, "%s\n", strbuff); 347 348 num_open.rlim_max = NUM_NEEDED; 349 350 rlim2str(strbuff2, sizeof(strbuff2), num_open.rlim_max); 351 rlim2str(strbuff1, sizeof(strbuff1), num_open.rlim_cur); 352 msnprintf(strbuff, sizeof(strbuff), "fds needed %s > system limit %s", 353 strbuff2, strbuff1); 354 store_errmsg(strbuff, 0); 355 fprintf(stderr, "%s\n", msgbuff); 356 357 for(num_open.rlim_cur = 0; 358 fd[num_open.rlim_cur] >= 0; 359 num_open.rlim_cur++) 360 close(fd[num_open.rlim_cur]); 361 free(fd); 362 fd = NULL; 363 free(memchunk); 364 return -9; 365 } 366 } 367 368 rlim2str(strbuff, sizeof(strbuff), num_open.rlim_max); 369 fprintf(stderr, "%s file descriptors open\n", strbuff); 370 371#if !defined(HAVE_POLL_FINE) && !defined(USE_WINSOCK) 372 373 /* 374 * when using select() instead of poll() we cannot test 375 * libcurl functionality with a socket number equal or 376 * greater than FD_SETSIZE. In any case, macro VERIFY_SOCK 377 * in lib/select.c enforces this check and protects libcurl 378 * from a possible crash. The effect of this protection 379 * is that test 518 will always fail, since the actual 380 * call to select() never takes place. We skip test 518 381 * with an indication that select limit would be exceeded. 382 */ 383 384 num_open.rlim_cur = FD_SETSIZE - SAFETY_MARGIN; 385 if(num_open.rlim_max > num_open.rlim_cur) { 386 msnprintf(strbuff, sizeof(strbuff), "select limit is FD_SETSIZE %d", 387 FD_SETSIZE); 388 store_errmsg(strbuff, 0); 389 fprintf(stderr, "%s\n", msgbuff); 390 close_file_descriptors(); 391 free(memchunk); 392 return -10; 393 } 394 395 num_open.rlim_cur = FD_SETSIZE - SAFETY_MARGIN; 396 for(rl.rlim_cur = 0; 397 rl.rlim_cur < num_open.rlim_max; 398 rl.rlim_cur++) { 399 if((fd[rl.rlim_cur] > 0) && 400 ((unsigned int)fd[rl.rlim_cur] > num_open.rlim_cur)) { 401 msnprintf(strbuff, sizeof(strbuff), "select limit is FD_SETSIZE %d", 402 FD_SETSIZE); 403 store_errmsg(strbuff, 0); 404 fprintf(stderr, "%s\n", msgbuff); 405 close_file_descriptors(); 406 free(memchunk); 407 return -11; 408 } 409 } 410 411#endif /* using a FD_SETSIZE bound select() */ 412 413 /* 414 * Old or 'backwards compatible' implementations of stdio do not allow 415 * handling of streams with an underlying file descriptor number greater 416 * than 255, even when allowing high numbered file descriptors for sockets. 417 * At this point we have a big number of file descriptors which have been 418 * opened using dup(), so lets test the stdio implementation and discover 419 * if it is capable of fopen()ing some additional files. 420 */ 421 422 if(!fopen_works()) { 423 rlim2str(strbuff1, sizeof(strbuff1), num_open.rlim_max); 424 msnprintf(strbuff, sizeof(strbuff), "fopen fails with %s fds open", 425 strbuff1); 426 fprintf(stderr, "%s\n", msgbuff); 427 msnprintf(strbuff, sizeof(strbuff), "fopen fails with lots of fds open"); 428 store_errmsg(strbuff, 0); 429 close_file_descriptors(); 430 free(memchunk); 431 return -12; 432 } 433 434 /* free the chunk of memory we were reserving so that it 435 becomes becomes available to the test */ 436 437 free(memchunk); 438 439 /* close file descriptors unless instructed to keep them */ 440 441 if(!keep_open) { 442 close_file_descriptors(); 443 } 444 445 return 0; 446} 447 448int test(char *URL) 449{ 450 CURLcode res; 451 CURL *curl; 452 453 if(!strcmp(URL, "check")) { 454 /* used by the test script to ask if we can run this test or not */ 455 if(rlimit(FALSE)) { 456 fprintf(stdout, "rlimit problem: %s\n", msgbuff); 457 return 1; 458 } 459 return 0; /* sure, run this! */ 460 } 461 462 if(rlimit(TRUE)) { 463 /* failure */ 464 return TEST_ERR_MAJOR_BAD; 465 } 466 467 /* run the test with the bunch of open file descriptors 468 and close them all once the test is over */ 469 470 if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { 471 fprintf(stderr, "curl_global_init() failed\n"); 472 close_file_descriptors(); 473 return TEST_ERR_MAJOR_BAD; 474 } 475 476 curl = curl_easy_init(); 477 if(!curl) { 478 fprintf(stderr, "curl_easy_init() failed\n"); 479 close_file_descriptors(); 480 curl_global_cleanup(); 481 return TEST_ERR_MAJOR_BAD; 482 } 483 484 test_setopt(curl, CURLOPT_URL, URL); 485 test_setopt(curl, CURLOPT_HEADER, 1L); 486 487 res = curl_easy_perform(curl); 488 489test_cleanup: 490 491 close_file_descriptors(); 492 curl_easy_cleanup(curl); 493 curl_global_cleanup(); 494 495 return (int)res; 496} 497 498#else /* defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) */ 499 500int test(char *URL) 501{ 502 (void)URL; 503 printf("system lacks necessary system function(s)"); 504 return 1; /* skip test */ 505} 506 507#endif /* defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) */ 508