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