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