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