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