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