Annotation of embedaddon/curl/tests/libtest/lib537.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>