lib518.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 #include "test.h"
00023 
00024 #ifdef HAVE_SYS_RESOURCE_H
00025 #include <sys/resource.h>
00026 #endif
00027 #ifdef HAVE_FCNTL_H
00028 #include <fcntl.h>
00029 #endif
00030 #ifdef HAVE_LIMITS_H
00031 #include <limits.h>
00032 #endif
00033 
00034 #include "warnless.h"
00035 #include "memdebug.h"
00036 
00037 #ifndef FD_SETSIZE
00038 #error "this test requires FD_SETSIZE"
00039 #endif
00040 
00041 #define SAFETY_MARGIN (16)
00042 #define NUM_OPEN      (FD_SETSIZE + 10)
00043 #define NUM_NEEDED    (NUM_OPEN + SAFETY_MARGIN)
00044 
00045 #if defined(WIN32) || defined(_WIN32) || defined(MSDOS)
00046 #define DEV_NULL "NUL"
00047 #else
00048 #define DEV_NULL "/dev/null"
00049 #endif
00050 
00051 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
00052 
00053 static int *fd = NULL;
00054 static struct rlimit num_open;
00055 static char msgbuff[256];
00056 
00057 static void store_errmsg(const char *msg, int err)
00058 {
00059   if(!err)
00060     snprintf(msgbuff, sizeof(msgbuff), "%s", msg);
00061   else
00062     snprintf(msgbuff, sizeof(msgbuff), "%s, errno %d, %s", msg,
00063              err, strerror(err));
00064 }
00065 
00066 static void close_file_descriptors(void)
00067 {
00068   for(num_open.rlim_cur = 0;
00069       num_open.rlim_cur < num_open.rlim_max;
00070       num_open.rlim_cur++)
00071     if(fd[num_open.rlim_cur] > 0)
00072       close(fd[num_open.rlim_cur]);
00073   free(fd);
00074   fd = NULL;
00075 }
00076 
00077 static int fopen_works(void)
00078 {
00079   FILE *fpa[3];
00080   int i;
00081   int ret = 1;
00082 
00083   for(i = 0; i < 3; i++) {
00084     fpa[i] = NULL;
00085   }
00086   for(i = 0; i < 3; i++) {
00087     fpa[i] = fopen(DEV_NULL, FOPEN_READTEXT);
00088     if(fpa[i] == NULL) {
00089       store_errmsg("fopen failed", ERRNO);
00090       fprintf(stderr, "%s\n", msgbuff);
00091       ret = 0;
00092       break;
00093     }
00094   }
00095   for(i = 0; i < 3; i++) {
00096     if(fpa[i] != NULL)
00097       fclose(fpa[i]);
00098   }
00099   return ret;
00100 }
00101 
00102 static int rlimit(int keep_open)
00103 {
00104   int nitems, i;
00105   int *memchunk = NULL;
00106   char *fmt;
00107   struct rlimit rl;
00108   char strbuff[256];
00109   char strbuff1[81];
00110   char strbuff2[81];
00111   char fmt_u[] = "%u";
00112   char fmt_lu[] = "%lu";
00113 #ifdef HAVE_LONGLONG
00114   char fmt_llu[] = "%llu";
00115 
00116   if(sizeof(rl.rlim_max) > sizeof(long))
00117     fmt = fmt_llu;
00118   else
00119 #endif
00120     fmt = (sizeof(rl.rlim_max) < sizeof(long))?fmt_u:fmt_lu;
00121 
00122   /* get initial open file limits */
00123 
00124   if(getrlimit(RLIMIT_NOFILE, &rl) != 0) {
00125     store_errmsg("getrlimit() failed", ERRNO);
00126     fprintf(stderr, "%s\n", msgbuff);
00127     return -1;
00128   }
00129 
00130   /* show initial open file limits */
00131 
00132 #ifdef RLIM_INFINITY
00133   if(rl.rlim_cur == RLIM_INFINITY)
00134     strcpy(strbuff, "INFINITY");
00135   else
00136 #endif
00137     snprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_cur);
00138   fprintf(stderr, "initial soft limit: %s\n", strbuff);
00139 
00140 #ifdef RLIM_INFINITY
00141   if(rl.rlim_max == RLIM_INFINITY)
00142     strcpy(strbuff, "INFINITY");
00143   else
00144 #endif
00145     snprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_max);
00146   fprintf(stderr, "initial hard limit: %s\n", strbuff);
00147 
00148   /* show our constants */
00149 
00150   fprintf(stderr, "test518 FD_SETSIZE: %d\n", FD_SETSIZE);
00151   fprintf(stderr, "test518 NUM_OPEN  : %d\n", NUM_OPEN);
00152   fprintf(stderr, "test518 NUM_NEEDED: %d\n", NUM_NEEDED);
00153 
00154   /*
00155    * if soft limit and hard limit are different we ask the
00156    * system to raise soft limit all the way up to the hard
00157    * limit. Due to some other system limit the soft limit
00158    * might not be raised up to the hard limit. So from this
00159    * point the resulting soft limit is our limit. Trying to
00160    * open more than soft limit file descriptors will fail.
00161    */
00162 
00163   if(rl.rlim_cur != rl.rlim_max) {
00164 
00165 #ifdef OPEN_MAX
00166     if((rl.rlim_cur > 0) &&
00167        (rl.rlim_cur < OPEN_MAX)) {
00168       fprintf(stderr, "raising soft limit up to OPEN_MAX\n");
00169       rl.rlim_cur = OPEN_MAX;
00170       if(setrlimit(RLIMIT_NOFILE, &rl) != 0) {
00171         /* on failure don't abort just issue a warning */
00172         store_errmsg("setrlimit() failed", ERRNO);
00173         fprintf(stderr, "%s\n", msgbuff);
00174         msgbuff[0] = '\0';
00175       }
00176     }
00177 #endif
00178 
00179     fprintf(stderr, "raising soft limit up to hard limit\n");
00180     rl.rlim_cur = rl.rlim_max;
00181     if(setrlimit(RLIMIT_NOFILE, &rl) != 0) {
00182       /* on failure don't abort just issue a warning */
00183       store_errmsg("setrlimit() failed", ERRNO);
00184       fprintf(stderr, "%s\n", msgbuff);
00185       msgbuff[0] = '\0';
00186     }
00187 
00188     /* get current open file limits */
00189 
00190     if(getrlimit(RLIMIT_NOFILE, &rl) != 0) {
00191       store_errmsg("getrlimit() failed", ERRNO);
00192       fprintf(stderr, "%s\n", msgbuff);
00193       return -3;
00194     }
00195 
00196     /* show current open file limits */
00197 
00198 #ifdef RLIM_INFINITY
00199     if(rl.rlim_cur == RLIM_INFINITY)
00200       strcpy(strbuff, "INFINITY");
00201     else
00202 #endif
00203       snprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_cur);
00204     fprintf(stderr, "current soft limit: %s\n", strbuff);
00205 
00206 #ifdef RLIM_INFINITY
00207     if(rl.rlim_max == RLIM_INFINITY)
00208       strcpy(strbuff, "INFINITY");
00209     else
00210 #endif
00211       snprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_max);
00212     fprintf(stderr, "current hard limit: %s\n", strbuff);
00213 
00214   } /* (rl.rlim_cur != rl.rlim_max) */
00215 
00216   /*
00217    * test 518 is all about testing libcurl functionality
00218    * when more than FD_SETSIZE file descriptors are open.
00219    * This means that if for any reason we are not able to
00220    * open more than FD_SETSIZE file descriptors then test
00221    * 518 should not be run.
00222    */
00223 
00224   /*
00225    * verify that soft limit is higher than NUM_NEEDED,
00226    * which is the number of file descriptors we would
00227    * try to open plus SAFETY_MARGIN to not exhaust the
00228    * file descriptor pool
00229    */
00230 
00231   num_open.rlim_cur = NUM_NEEDED;
00232 
00233   if((rl.rlim_cur > 0) &&
00234 #ifdef RLIM_INFINITY
00235      (rl.rlim_cur != RLIM_INFINITY) &&
00236 #endif
00237      (rl.rlim_cur <= num_open.rlim_cur)) {
00238     snprintf(strbuff2, sizeof(strbuff2), fmt, rl.rlim_cur);
00239     snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur);
00240     snprintf(strbuff, sizeof(strbuff), "fds needed %s > system limit %s",
00241              strbuff1, strbuff2);
00242     store_errmsg(strbuff, 0);
00243     fprintf(stderr, "%s\n", msgbuff);
00244     return -4;
00245   }
00246 
00247   /*
00248    * reserve a chunk of memory before opening file descriptors to
00249    * avoid a low memory condition once the file descriptors are
00250    * open. System conditions that could make the test fail should
00251    * be addressed in the precheck phase. This chunk of memory shall
00252    * be always free()ed before exiting the rlimit() function so
00253    * that it becomes available to the test.
00254    */
00255 
00256   for(nitems = i = 1; nitems <= i; i *= 2)
00257     nitems = i;
00258   if(nitems > 0x7fff)
00259     nitems = 0x40000;
00260   do {
00261     num_open.rlim_max = sizeof(*memchunk) * (size_t)nitems;
00262     snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
00263     fprintf(stderr, "allocating memchunk %s byte array\n", strbuff);
00264     memchunk = malloc(sizeof(*memchunk) * (size_t)nitems);
00265     if(!memchunk) {
00266       fprintf(stderr, "memchunk, malloc() failed\n");
00267       nitems /= 2;
00268     }
00269   } while(nitems && !memchunk);
00270   if(!memchunk) {
00271     store_errmsg("memchunk, malloc() failed", ERRNO);
00272     fprintf(stderr, "%s\n", msgbuff);
00273     return -5;
00274   }
00275 
00276   /* initialize it to fight lazy allocation */
00277 
00278   fprintf(stderr, "initializing memchunk array\n");
00279 
00280   for(i = 0; i < nitems; i++)
00281     memchunk[i] = -1;
00282 
00283   /* set the number of file descriptors we will try to open */
00284 
00285   num_open.rlim_max = NUM_OPEN;
00286 
00287   /* verify that we won't overflow size_t in malloc() */
00288 
00289   if((size_t)(num_open.rlim_max) > ((size_t)-1) / sizeof(*fd)) {
00290     snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_max);
00291     snprintf(strbuff, sizeof(strbuff), "unable to allocate an array for %s "
00292              "file descriptors, would overflow size_t", strbuff1);
00293     store_errmsg(strbuff, 0);
00294     fprintf(stderr, "%s\n", msgbuff);
00295     free(memchunk);
00296     return -6;
00297   }
00298 
00299   /* allocate array for file descriptors */
00300 
00301   snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
00302   fprintf(stderr, "allocating array for %s file descriptors\n", strbuff);
00303 
00304   fd = malloc(sizeof(*fd) * (size_t)(num_open.rlim_max));
00305   if(!fd) {
00306     store_errmsg("fd, malloc() failed", ERRNO);
00307     fprintf(stderr, "%s\n", msgbuff);
00308     free(memchunk);
00309     return -7;
00310   }
00311 
00312   /* initialize it to fight lazy allocation */
00313 
00314   fprintf(stderr, "initializing fd array\n");
00315 
00316   for(num_open.rlim_cur = 0;
00317       num_open.rlim_cur < num_open.rlim_max;
00318       num_open.rlim_cur++)
00319     fd[num_open.rlim_cur] = -1;
00320 
00321   snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
00322   fprintf(stderr, "trying to open %s file descriptors\n", strbuff);
00323 
00324   /* open a dummy descriptor */
00325 
00326   fd[0] = open(DEV_NULL, O_RDONLY);
00327   if(fd[0] < 0) {
00328     snprintf(strbuff, sizeof(strbuff), "opening of %s failed", DEV_NULL);
00329     store_errmsg(strbuff, ERRNO);
00330     fprintf(stderr, "%s\n", msgbuff);
00331     free(fd);
00332     fd = NULL;
00333     free(memchunk);
00334     return -8;
00335   }
00336 
00337   /* create a bunch of file descriptors */
00338 
00339   for(num_open.rlim_cur = 1;
00340       num_open.rlim_cur < num_open.rlim_max;
00341       num_open.rlim_cur++) {
00342 
00343     fd[num_open.rlim_cur] = dup(fd[0]);
00344 
00345     if(fd[num_open.rlim_cur] < 0) {
00346 
00347       fd[num_open.rlim_cur] = -1;
00348 
00349       snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur);
00350       snprintf(strbuff, sizeof(strbuff), "dup() attempt %s failed", strbuff1);
00351       fprintf(stderr, "%s\n", strbuff);
00352 
00353       snprintf(strbuff1, sizeof(strbuff), fmt, num_open.rlim_cur);
00354       snprintf(strbuff, sizeof(strbuff), "fds system limit seems close to %s",
00355                strbuff1);
00356       fprintf(stderr, "%s\n", strbuff);
00357 
00358       num_open.rlim_max = NUM_NEEDED;
00359 
00360       snprintf(strbuff2, sizeof(strbuff2), fmt, num_open.rlim_max);
00361       snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur);
00362       snprintf(strbuff, sizeof(strbuff), "fds needed %s > system limit %s",
00363                strbuff2, strbuff1);
00364       store_errmsg(strbuff, 0);
00365       fprintf(stderr, "%s\n", msgbuff);
00366 
00367       for(num_open.rlim_cur = 0;
00368           fd[num_open.rlim_cur] >= 0;
00369           num_open.rlim_cur++)
00370         close(fd[num_open.rlim_cur]);
00371       free(fd);
00372       fd = NULL;
00373       free(memchunk);
00374       return -9;
00375 
00376     }
00377 
00378   }
00379 
00380   snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
00381   fprintf(stderr, "%s file descriptors open\n", strbuff);
00382 
00383 #if !defined(HAVE_POLL_FINE)    && \
00384     !defined(USE_WINSOCK)       && \
00385     !defined(TPF)
00386 
00387   /*
00388    * when using select() instead of poll() we cannot test
00389    * libcurl functionality with a socket number equal or
00390    * greater than FD_SETSIZE. In any case, macro VERIFY_SOCK
00391    * in lib/select.c enforces this check and protects libcurl
00392    * from a possible crash. The effect of this protection
00393    * is that test 518 will always fail, since the actual
00394    * call to select() never takes place. We skip test 518
00395    * with an indication that select limit would be exceeded.
00396    */
00397 
00398   num_open.rlim_cur = FD_SETSIZE - SAFETY_MARGIN;
00399   if(num_open.rlim_max > num_open.rlim_cur) {
00400     snprintf(strbuff, sizeof(strbuff), "select limit is FD_SETSIZE %d",
00401              FD_SETSIZE);
00402     store_errmsg(strbuff, 0);
00403     fprintf(stderr, "%s\n", msgbuff);
00404     close_file_descriptors();
00405     free(memchunk);
00406     return -10;
00407   }
00408 
00409   num_open.rlim_cur = FD_SETSIZE - SAFETY_MARGIN;
00410   for(rl.rlim_cur = 0;
00411       rl.rlim_cur < num_open.rlim_max;
00412       rl.rlim_cur++) {
00413     if((fd[rl.rlim_cur] > 0) &&
00414        ((unsigned int)fd[rl.rlim_cur] > num_open.rlim_cur)) {
00415       snprintf(strbuff, sizeof(strbuff), "select limit is FD_SETSIZE %d",
00416                FD_SETSIZE);
00417       store_errmsg(strbuff, 0);
00418       fprintf(stderr, "%s\n", msgbuff);
00419       close_file_descriptors();
00420       free(memchunk);
00421       return -11;
00422     }
00423   }
00424 
00425 #endif /* using a FD_SETSIZE bound select() */
00426 
00427   /*
00428    * Old or 'backwards compatible' implementations of stdio do not allow
00429    * handling of streams with an underlying file descriptor number greater
00430    * than 255, even when allowing high numbered file descriptors for sockets.
00431    * At this point we have a big number of file descriptors which have been
00432    * opened using dup(), so lets test the stdio implementation and discover
00433    * if it is capable of fopen()ing some additional files.
00434    */
00435 
00436   if(!fopen_works()) {
00437     snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_max);
00438     snprintf(strbuff, sizeof(strbuff),
00439              "fopen fails with %s fds open()",
00440              strbuff1);
00441     fprintf(stderr, "%s\n", msgbuff);
00442     snprintf(strbuff, sizeof(strbuff),
00443              "fopen fails with lots of fds open()");
00444     store_errmsg(strbuff, 0);
00445     close_file_descriptors();
00446     free(memchunk);
00447     return -12;
00448   }
00449 
00450   /* free the chunk of memory we were reserving so that it
00451      becomes becomes available to the test */
00452 
00453   free(memchunk);
00454 
00455   /* close file descriptors unless instructed to keep them */
00456 
00457   if(!keep_open) {
00458     close_file_descriptors();
00459   }
00460 
00461   return 0;
00462 }
00463 
00464 int test(char *URL)
00465 {
00466   CURLcode res;
00467   CURL *curl;
00468 
00469   if(!strcmp(URL, "check")) {
00470     /* used by the test script to ask if we can run this test or not */
00471     if(rlimit(FALSE)) {
00472       fprintf(stdout, "rlimit problem: %s\n", msgbuff);
00473       return 1;
00474     }
00475     return 0; /* sure, run this! */
00476   }
00477 
00478   if(rlimit(TRUE)) {
00479     /* failure */
00480     return TEST_ERR_MAJOR_BAD;
00481   }
00482 
00483   /* run the test with the bunch of open file descriptors
00484      and close them all once the test is over */
00485 
00486   if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
00487     fprintf(stderr, "curl_global_init() failed\n");
00488     close_file_descriptors();
00489     return TEST_ERR_MAJOR_BAD;
00490   }
00491 
00492   curl = curl_easy_init();
00493   if(!curl) {
00494     fprintf(stderr, "curl_easy_init() failed\n");
00495     close_file_descriptors();
00496     curl_global_cleanup();
00497     return TEST_ERR_MAJOR_BAD;
00498   }
00499 
00500   test_setopt(curl, CURLOPT_URL, URL);
00501   test_setopt(curl, CURLOPT_HEADER, 1L);
00502 
00503   res = curl_easy_perform(curl);
00504 
00505 test_cleanup:
00506 
00507   close_file_descriptors();
00508   curl_easy_cleanup(curl);
00509   curl_global_cleanup();
00510 
00511   return (int)res;
00512 }
00513 
00514 #else /* defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) */
00515 
00516 int test(char *URL)
00517 {
00518   (void)URL;
00519   printf("system lacks necessary system function(s)");
00520   return 1; /* skip test */
00521 }
00522 
00523 #endif /* defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) */


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:05