Return to lib518.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / tests / libtest |
1.1 ! misho 1: /*************************************************************************** ! 2: * _ _ ____ _ ! 3: * Project ___| | | | _ \| | ! 4: * / __| | | | |_) | | ! 5: * | (__| |_| | _ <| |___ ! 6: * \___|\___/|_| \_\_____| ! 7: * ! 8: * Copyright (C) 1998 - 2018, 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 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: #include <limits.h> ! 31: ! 32: #include "warnless.h" ! 33: #include "memdebug.h" ! 34: ! 35: #ifndef FD_SETSIZE ! 36: #error "this test requires FD_SETSIZE" ! 37: #endif ! 38: ! 39: #define SAFETY_MARGIN (16) ! 40: #define NUM_OPEN (FD_SETSIZE + 10) ! 41: #define NUM_NEEDED (NUM_OPEN + SAFETY_MARGIN) ! 42: ! 43: #if defined(WIN32) || defined(_WIN32) || defined(MSDOS) ! 44: #define DEV_NULL "NUL" ! 45: #else ! 46: #define DEV_NULL "/dev/null" ! 47: #endif ! 48: ! 49: #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) ! 50: ! 51: static int *fd = NULL; ! 52: static struct rlimit num_open; ! 53: static char msgbuff[256]; ! 54: ! 55: static void store_errmsg(const char *msg, int err) ! 56: { ! 57: if(!err) ! 58: msnprintf(msgbuff, sizeof(msgbuff), "%s", msg); ! 59: else ! 60: msnprintf(msgbuff, sizeof(msgbuff), "%s, errno %d, %s", msg, ! 61: err, strerror(err)); ! 62: } ! 63: ! 64: static void close_file_descriptors(void) ! 65: { ! 66: for(num_open.rlim_cur = 0; ! 67: num_open.rlim_cur < num_open.rlim_max; ! 68: num_open.rlim_cur++) ! 69: if(fd[num_open.rlim_cur] > 0) ! 70: close(fd[num_open.rlim_cur]); ! 71: free(fd); ! 72: fd = NULL; ! 73: } ! 74: ! 75: static int fopen_works(void) ! 76: { ! 77: FILE *fpa[3]; ! 78: int i; ! 79: int ret = 1; ! 80: ! 81: for(i = 0; i < 3; i++) { ! 82: fpa[i] = NULL; ! 83: } ! 84: for(i = 0; i < 3; i++) { ! 85: fpa[i] = fopen(DEV_NULL, FOPEN_READTEXT); ! 86: if(fpa[i] == NULL) { ! 87: store_errmsg("fopen failed", errno); ! 88: fprintf(stderr, "%s\n", msgbuff); ! 89: ret = 0; ! 90: break; ! 91: } ! 92: } ! 93: for(i = 0; i < 3; i++) { ! 94: if(fpa[i] != NULL) ! 95: fclose(fpa[i]); ! 96: } ! 97: return ret; ! 98: } ! 99: ! 100: static int rlimit(int keep_open) ! 101: { ! 102: int nitems, i; ! 103: int *memchunk = NULL; ! 104: char *fmt; ! 105: struct rlimit rl; ! 106: char strbuff[256]; ! 107: char strbuff1[81]; ! 108: char strbuff2[81]; ! 109: char fmt_u[] = "%u"; ! 110: char fmt_lu[] = "%lu"; ! 111: #ifdef HAVE_LONGLONG ! 112: char fmt_llu[] = "%llu"; ! 113: ! 114: if(sizeof(rl.rlim_max) > sizeof(long)) ! 115: fmt = fmt_llu; ! 116: else ! 117: #endif ! 118: fmt = (sizeof(rl.rlim_max) < sizeof(long))?fmt_u:fmt_lu; ! 119: ! 120: /* get initial open file limits */ ! 121: ! 122: if(getrlimit(RLIMIT_NOFILE, &rl) != 0) { ! 123: store_errmsg("getrlimit() failed", errno); ! 124: fprintf(stderr, "%s\n", msgbuff); ! 125: return -1; ! 126: } ! 127: ! 128: /* show initial open file limits */ ! 129: ! 130: #ifdef RLIM_INFINITY ! 131: if(rl.rlim_cur == RLIM_INFINITY) ! 132: strcpy(strbuff, "INFINITY"); ! 133: else ! 134: #endif ! 135: msnprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_cur); ! 136: fprintf(stderr, "initial soft limit: %s\n", strbuff); ! 137: ! 138: #ifdef RLIM_INFINITY ! 139: if(rl.rlim_max == RLIM_INFINITY) ! 140: strcpy(strbuff, "INFINITY"); ! 141: else ! 142: #endif ! 143: msnprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_max); ! 144: fprintf(stderr, "initial hard limit: %s\n", strbuff); ! 145: ! 146: /* show our constants */ ! 147: ! 148: fprintf(stderr, "test518 FD_SETSIZE: %d\n", FD_SETSIZE); ! 149: fprintf(stderr, "test518 NUM_OPEN : %d\n", NUM_OPEN); ! 150: fprintf(stderr, "test518 NUM_NEEDED: %d\n", NUM_NEEDED); ! 151: ! 152: /* ! 153: * if soft limit and hard limit are different we ask the ! 154: * system to raise soft limit all the way up to the hard ! 155: * limit. Due to some other system limit the soft limit ! 156: * might not be raised up to the hard limit. So from this ! 157: * point the resulting soft limit is our limit. Trying to ! 158: * open more than soft limit file descriptors will fail. ! 159: */ ! 160: ! 161: if(rl.rlim_cur != rl.rlim_max) { ! 162: ! 163: #ifdef OPEN_MAX ! 164: if((rl.rlim_cur > 0) && ! 165: (rl.rlim_cur < OPEN_MAX)) { ! 166: fprintf(stderr, "raising soft limit up to OPEN_MAX\n"); ! 167: rl.rlim_cur = OPEN_MAX; ! 168: if(setrlimit(RLIMIT_NOFILE, &rl) != 0) { ! 169: /* on failure don't abort just issue a warning */ ! 170: store_errmsg("setrlimit() failed", errno); ! 171: fprintf(stderr, "%s\n", msgbuff); ! 172: msgbuff[0] = '\0'; ! 173: } ! 174: } ! 175: #endif ! 176: ! 177: fprintf(stderr, "raising soft limit up to hard limit\n"); ! 178: rl.rlim_cur = rl.rlim_max; ! 179: if(setrlimit(RLIMIT_NOFILE, &rl) != 0) { ! 180: /* on failure don't abort just issue a warning */ ! 181: store_errmsg("setrlimit() failed", errno); ! 182: fprintf(stderr, "%s\n", msgbuff); ! 183: msgbuff[0] = '\0'; ! 184: } ! 185: ! 186: /* get current open file limits */ ! 187: ! 188: if(getrlimit(RLIMIT_NOFILE, &rl) != 0) { ! 189: store_errmsg("getrlimit() failed", errno); ! 190: fprintf(stderr, "%s\n", msgbuff); ! 191: return -3; ! 192: } ! 193: ! 194: /* show current open file limits */ ! 195: ! 196: #ifdef RLIM_INFINITY ! 197: if(rl.rlim_cur == RLIM_INFINITY) ! 198: strcpy(strbuff, "INFINITY"); ! 199: else ! 200: #endif ! 201: msnprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_cur); ! 202: fprintf(stderr, "current soft limit: %s\n", strbuff); ! 203: ! 204: #ifdef RLIM_INFINITY ! 205: if(rl.rlim_max == RLIM_INFINITY) ! 206: strcpy(strbuff, "INFINITY"); ! 207: else ! 208: #endif ! 209: msnprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_max); ! 210: fprintf(stderr, "current hard limit: %s\n", strbuff); ! 211: ! 212: } /* (rl.rlim_cur != rl.rlim_max) */ ! 213: ! 214: /* ! 215: * test 518 is all about testing libcurl functionality ! 216: * when more than FD_SETSIZE file descriptors are open. ! 217: * This means that if for any reason we are not able to ! 218: * open more than FD_SETSIZE file descriptors then test ! 219: * 518 should not be run. ! 220: */ ! 221: ! 222: /* ! 223: * verify that soft limit is higher than NUM_NEEDED, ! 224: * which is the number of file descriptors we would ! 225: * try to open plus SAFETY_MARGIN to not exhaust the ! 226: * file descriptor pool ! 227: */ ! 228: ! 229: num_open.rlim_cur = NUM_NEEDED; ! 230: ! 231: if((rl.rlim_cur > 0) && ! 232: #ifdef RLIM_INFINITY ! 233: (rl.rlim_cur != RLIM_INFINITY) && ! 234: #endif ! 235: (rl.rlim_cur <= num_open.rlim_cur)) { ! 236: msnprintf(strbuff2, sizeof(strbuff2), fmt, rl.rlim_cur); ! 237: msnprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur); ! 238: msnprintf(strbuff, sizeof(strbuff), "fds needed %s > system limit %s", ! 239: strbuff1, strbuff2); ! 240: store_errmsg(strbuff, 0); ! 241: fprintf(stderr, "%s\n", msgbuff); ! 242: return -4; ! 243: } ! 244: ! 245: /* ! 246: * reserve a chunk of memory before opening file descriptors to ! 247: * avoid a low memory condition once the file descriptors are ! 248: * open. System conditions that could make the test fail should ! 249: * be addressed in the precheck phase. This chunk of memory shall ! 250: * be always free()ed before exiting the rlimit() function so ! 251: * that it becomes available to the test. ! 252: */ ! 253: ! 254: for(nitems = i = 1; nitems <= i; i *= 2) ! 255: nitems = i; ! 256: if(nitems > 0x7fff) ! 257: nitems = 0x40000; ! 258: do { ! 259: num_open.rlim_max = sizeof(*memchunk) * (size_t)nitems; ! 260: msnprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max); ! 261: fprintf(stderr, "allocating memchunk %s byte array\n", strbuff); ! 262: memchunk = malloc(sizeof(*memchunk) * (size_t)nitems); ! 263: if(!memchunk) { ! 264: fprintf(stderr, "memchunk, malloc() failed\n"); ! 265: nitems /= 2; ! 266: } ! 267: } while(nitems && !memchunk); ! 268: if(!memchunk) { ! 269: store_errmsg("memchunk, malloc() failed", errno); ! 270: fprintf(stderr, "%s\n", msgbuff); ! 271: return -5; ! 272: } ! 273: ! 274: /* initialize it to fight lazy allocation */ ! 275: ! 276: fprintf(stderr, "initializing memchunk array\n"); ! 277: ! 278: for(i = 0; i < nitems; i++) ! 279: memchunk[i] = -1; ! 280: ! 281: /* set the number of file descriptors we will try to open */ ! 282: ! 283: num_open.rlim_max = NUM_OPEN; ! 284: ! 285: /* verify that we won't overflow size_t in malloc() */ ! 286: ! 287: if((size_t)(num_open.rlim_max) > ((size_t)-1) / sizeof(*fd)) { ! 288: msnprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_max); ! 289: msnprintf(strbuff, sizeof(strbuff), "unable to allocate an array for %s " ! 290: "file descriptors, would overflow size_t", strbuff1); ! 291: store_errmsg(strbuff, 0); ! 292: fprintf(stderr, "%s\n", msgbuff); ! 293: free(memchunk); ! 294: return -6; ! 295: } ! 296: ! 297: /* allocate array for file descriptors */ ! 298: ! 299: msnprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max); ! 300: fprintf(stderr, "allocating array for %s file descriptors\n", strbuff); ! 301: ! 302: fd = malloc(sizeof(*fd) * (size_t)(num_open.rlim_max)); ! 303: if(!fd) { ! 304: store_errmsg("fd, malloc() failed", errno); ! 305: fprintf(stderr, "%s\n", msgbuff); ! 306: free(memchunk); ! 307: return -7; ! 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: msnprintf(strbuff, sizeof(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: msnprintf(strbuff, sizeof(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 -8; ! 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: msnprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur); ! 348: msnprintf(strbuff, sizeof(strbuff), "dup() attempt %s failed", strbuff1); ! 349: fprintf(stderr, "%s\n", strbuff); ! 350: ! 351: msnprintf(strbuff1, sizeof(strbuff), fmt, num_open.rlim_cur); ! 352: msnprintf(strbuff, sizeof(strbuff), "fds system limit seems close to %s", ! 353: strbuff1); ! 354: fprintf(stderr, "%s\n", strbuff); ! 355: ! 356: num_open.rlim_max = NUM_NEEDED; ! 357: ! 358: msnprintf(strbuff2, sizeof(strbuff2), fmt, num_open.rlim_max); ! 359: msnprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur); ! 360: msnprintf(strbuff, sizeof(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: msnprintf(strbuff, sizeof(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: msnprintf(strbuff, sizeof(strbuff), "select limit is FD_SETSIZE %d", ! 399: FD_SETSIZE); ! 400: store_errmsg(strbuff, 0); ! 401: fprintf(stderr, "%s\n", msgbuff); ! 402: close_file_descriptors(); ! 403: free(memchunk); ! 404: return -10; ! 405: } ! 406: ! 407: num_open.rlim_cur = FD_SETSIZE - SAFETY_MARGIN; ! 408: for(rl.rlim_cur = 0; ! 409: rl.rlim_cur < num_open.rlim_max; ! 410: rl.rlim_cur++) { ! 411: if((fd[rl.rlim_cur] > 0) && ! 412: ((unsigned int)fd[rl.rlim_cur] > num_open.rlim_cur)) { ! 413: msnprintf(strbuff, sizeof(strbuff), "select limit is FD_SETSIZE %d", ! 414: FD_SETSIZE); ! 415: store_errmsg(strbuff, 0); ! 416: fprintf(stderr, "%s\n", msgbuff); ! 417: close_file_descriptors(); ! 418: free(memchunk); ! 419: return -11; ! 420: } ! 421: } ! 422: ! 423: #endif /* using a FD_SETSIZE bound select() */ ! 424: ! 425: /* ! 426: * Old or 'backwards compatible' implementations of stdio do not allow ! 427: * handling of streams with an underlying file descriptor number greater ! 428: * than 255, even when allowing high numbered file descriptors for sockets. ! 429: * At this point we have a big number of file descriptors which have been ! 430: * opened using dup(), so lets test the stdio implementation and discover ! 431: * if it is capable of fopen()ing some additional files. ! 432: */ ! 433: ! 434: if(!fopen_works()) { ! 435: msnprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_max); ! 436: msnprintf(strbuff, sizeof(strbuff), ! 437: "fopen fails with %s fds open()", ! 438: strbuff1); ! 439: fprintf(stderr, "%s\n", msgbuff); ! 440: msnprintf(strbuff, sizeof(strbuff), ! 441: "fopen fails with lots of fds open()"); ! 442: store_errmsg(strbuff, 0); ! 443: close_file_descriptors(); ! 444: free(memchunk); ! 445: return -12; ! 446: } ! 447: ! 448: /* free the chunk of memory we were reserving so that it ! 449: becomes becomes available to the test */ ! 450: ! 451: free(memchunk); ! 452: ! 453: /* close file descriptors unless instructed to keep them */ ! 454: ! 455: if(!keep_open) { ! 456: close_file_descriptors(); ! 457: } ! 458: ! 459: return 0; ! 460: } ! 461: ! 462: int test(char *URL) ! 463: { ! 464: CURLcode res; ! 465: CURL *curl; ! 466: ! 467: if(!strcmp(URL, "check")) { ! 468: /* used by the test script to ask if we can run this test or not */ ! 469: if(rlimit(FALSE)) { ! 470: fprintf(stdout, "rlimit problem: %s\n", msgbuff); ! 471: return 1; ! 472: } ! 473: return 0; /* sure, run this! */ ! 474: } ! 475: ! 476: if(rlimit(TRUE)) { ! 477: /* failure */ ! 478: return TEST_ERR_MAJOR_BAD; ! 479: } ! 480: ! 481: /* run the test with the bunch of open file descriptors ! 482: and close them all once the test is over */ ! 483: ! 484: if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { ! 485: fprintf(stderr, "curl_global_init() failed\n"); ! 486: close_file_descriptors(); ! 487: return TEST_ERR_MAJOR_BAD; ! 488: } ! 489: ! 490: curl = curl_easy_init(); ! 491: if(!curl) { ! 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: ! 503: test_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: ! 514: int 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) */