00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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 #if !defined(HAVE_POLL_FINE) && \
00038 !defined(USE_WINSOCK) && \
00039 !defined(TPF) && \
00040 !defined(FD_SETSIZE)
00041 #error "this test requires FD_SETSIZE"
00042 #endif
00043
00044 #define SAFETY_MARGIN (11)
00045
00046 #if defined(WIN32) || defined(_WIN32) || defined(MSDOS)
00047 #define DEV_NULL "NUL"
00048 #else
00049 #define DEV_NULL "/dev/null"
00050 #endif
00051
00052 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
00053
00054 static int *fd = NULL;
00055 static struct rlimit num_open;
00056 static char msgbuff[256];
00057
00058 static void store_errmsg(const char *msg, int err)
00059 {
00060 if(!err)
00061 snprintf(msgbuff, sizeof(msgbuff), "%s", msg);
00062 else
00063 snprintf(msgbuff, sizeof(msgbuff), "%s, errno %d, %s", msg, err,
00064 strerror(err));
00065 }
00066
00067 static void close_file_descriptors(void)
00068 {
00069 for(num_open.rlim_cur = 0;
00070 num_open.rlim_cur < num_open.rlim_max;
00071 num_open.rlim_cur++)
00072 if(fd[num_open.rlim_cur] > 0)
00073 close(fd[num_open.rlim_cur]);
00074 free(fd);
00075 fd = NULL;
00076 }
00077
00078 static int fopen_works(void)
00079 {
00080 FILE *fpa[3];
00081 int i;
00082 int ret = 1;
00083
00084 for(i = 0; i < 3; i++) {
00085 fpa[i] = NULL;
00086 }
00087 for(i = 0; i < 3; i++) {
00088 fpa[i] = fopen(DEV_NULL, FOPEN_READTEXT);
00089 if(fpa[i] == NULL) {
00090 store_errmsg("fopen failed", ERRNO);
00091 fprintf(stderr, "%s\n", msgbuff);
00092 ret = 0;
00093 break;
00094 }
00095 }
00096 for(i = 0; i < 3; i++) {
00097 if(fpa[i] != NULL)
00098 fclose(fpa[i]);
00099 }
00100 return ret;
00101 }
00102
00103 static int rlimit(int keep_open)
00104 {
00105 int *tmpfd;
00106 int nitems, i;
00107 int *memchunk = NULL;
00108 char *fmt;
00109 struct rlimit rl;
00110 char strbuff[256];
00111 char strbuff1[81];
00112 char fmt_u[] = "%u";
00113 char fmt_lu[] = "%lu";
00114 #ifdef HAVE_LONGLONG
00115 char fmt_llu[] = "%llu";
00116
00117 if(sizeof(rl.rlim_max) > sizeof(long))
00118 fmt = fmt_llu;
00119 else
00120 #endif
00121 fmt = (sizeof(rl.rlim_max) < sizeof(long))?fmt_u:fmt_lu;
00122
00123
00124
00125 if(getrlimit(RLIMIT_NOFILE, &rl) != 0) {
00126 store_errmsg("getrlimit() failed", ERRNO);
00127 fprintf(stderr, "%s\n", msgbuff);
00128 return -1;
00129 }
00130
00131
00132
00133 #ifdef RLIM_INFINITY
00134 if(rl.rlim_cur == RLIM_INFINITY)
00135 strcpy(strbuff, "INFINITY");
00136 else
00137 #endif
00138 snprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_cur);
00139 fprintf(stderr, "initial soft limit: %s\n", strbuff);
00140
00141 #ifdef RLIM_INFINITY
00142 if(rl.rlim_max == RLIM_INFINITY)
00143 strcpy(strbuff, "INFINITY");
00144 else
00145 #endif
00146 snprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_max);
00147 fprintf(stderr, "initial hard limit: %s\n", strbuff);
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158 if(rl.rlim_cur != rl.rlim_max) {
00159
00160 #ifdef OPEN_MAX
00161 if((rl.rlim_cur > 0) &&
00162 (rl.rlim_cur < OPEN_MAX)) {
00163 fprintf(stderr, "raising soft limit up to OPEN_MAX\n");
00164 rl.rlim_cur = OPEN_MAX;
00165 if(setrlimit(RLIMIT_NOFILE, &rl) != 0) {
00166
00167 store_errmsg("setrlimit() failed", ERRNO);
00168 fprintf(stderr, "%s\n", msgbuff);
00169 msgbuff[0] = '\0';
00170 }
00171 }
00172 #endif
00173
00174 fprintf(stderr, "raising soft limit up to hard limit\n");
00175 rl.rlim_cur = rl.rlim_max;
00176 if(setrlimit(RLIMIT_NOFILE, &rl) != 0) {
00177
00178 store_errmsg("setrlimit() failed", ERRNO);
00179 fprintf(stderr, "%s\n", msgbuff);
00180 msgbuff[0] = '\0';
00181 }
00182
00183
00184
00185 if(getrlimit(RLIMIT_NOFILE, &rl) != 0) {
00186 store_errmsg("getrlimit() failed", ERRNO);
00187 fprintf(stderr, "%s\n", msgbuff);
00188 return -3;
00189 }
00190
00191
00192
00193 #ifdef RLIM_INFINITY
00194 if(rl.rlim_cur == RLIM_INFINITY)
00195 strcpy(strbuff, "INFINITY");
00196 else
00197 #endif
00198 snprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_cur);
00199 fprintf(stderr, "current soft limit: %s\n", strbuff);
00200
00201 #ifdef RLIM_INFINITY
00202 if(rl.rlim_max == RLIM_INFINITY)
00203 strcpy(strbuff, "INFINITY");
00204 else
00205 #endif
00206 snprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_max);
00207 fprintf(stderr, "current hard limit: %s\n", strbuff);
00208
00209 }
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 for(nitems = i = 1; nitems <= i; i *= 2)
00231 nitems = i;
00232 if(nitems > 0x7fff)
00233 nitems = 0x40000;
00234 do {
00235 num_open.rlim_max = sizeof(*memchunk) * (size_t)nitems;
00236 snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
00237 fprintf(stderr, "allocating memchunk %s byte array\n", strbuff);
00238 memchunk = malloc(sizeof(*memchunk) * (size_t)nitems);
00239 if(!memchunk) {
00240 fprintf(stderr, "memchunk, malloc() failed\n");
00241 nitems /= 2;
00242 }
00243 } while(nitems && !memchunk);
00244 if(!memchunk) {
00245 store_errmsg("memchunk, malloc() failed", ERRNO);
00246 fprintf(stderr, "%s\n", msgbuff);
00247 return -4;
00248 }
00249
00250
00251
00252 fprintf(stderr, "initializing memchunk array\n");
00253
00254 for(i = 0; i < nitems; i++)
00255 memchunk[i] = -1;
00256
00257
00258
00259 #ifdef RLIM_INFINITY
00260 if((rl.rlim_cur > 0) && (rl.rlim_cur != RLIM_INFINITY)) {
00261 #else
00262 if(rl.rlim_cur > 0) {
00263 #endif
00264
00265 num_open.rlim_max = rl.rlim_cur - SAFETY_MARGIN;
00266 }
00267 else {
00268
00269 for(nitems = i = 1; nitems <= i; i *= 2)
00270 nitems = i;
00271 if(nitems > 0x7fff)
00272 nitems = 0x40000;
00273 num_open.rlim_max = nitems;
00274 }
00275
00276
00277
00278 if((size_t)(num_open.rlim_max) > ((size_t)-1) / sizeof(*fd)) {
00279 snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_max);
00280 snprintf(strbuff, sizeof(strbuff), "unable to allocate an array for %s "
00281 "file descriptors, would overflow size_t", strbuff1);
00282 store_errmsg(strbuff, 0);
00283 fprintf(stderr, "%s\n", msgbuff);
00284 free(memchunk);
00285 return -5;
00286 }
00287
00288
00289
00290 do {
00291 snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
00292 fprintf(stderr, "allocating array for %s file descriptors\n", strbuff);
00293 fd = malloc(sizeof(*fd) * (size_t)(num_open.rlim_max));
00294 if(!fd) {
00295 fprintf(stderr, "fd, malloc() failed\n");
00296 num_open.rlim_max /= 2;
00297 }
00298 } while(num_open.rlim_max && !fd);
00299 if(!fd) {
00300 store_errmsg("fd, malloc() failed", ERRNO);
00301 fprintf(stderr, "%s\n", msgbuff);
00302 free(memchunk);
00303 return -6;
00304 }
00305
00306
00307
00308 fprintf(stderr, "initializing fd array\n");
00309
00310 for(num_open.rlim_cur = 0;
00311 num_open.rlim_cur < num_open.rlim_max;
00312 num_open.rlim_cur++)
00313 fd[num_open.rlim_cur] = -1;
00314
00315 snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
00316 fprintf(stderr, "trying to open %s file descriptors\n", strbuff);
00317
00318
00319
00320 fd[0] = open(DEV_NULL, O_RDONLY);
00321 if(fd[0] < 0) {
00322 snprintf(strbuff, sizeof(strbuff), "opening of %s failed", DEV_NULL);
00323 store_errmsg(strbuff, ERRNO);
00324 fprintf(stderr, "%s\n", msgbuff);
00325 free(fd);
00326 fd = NULL;
00327 free(memchunk);
00328 return -7;
00329 }
00330
00331
00332
00333 for(num_open.rlim_cur = 1;
00334 num_open.rlim_cur < num_open.rlim_max;
00335 num_open.rlim_cur++) {
00336
00337 fd[num_open.rlim_cur] = dup(fd[0]);
00338
00339 if(fd[num_open.rlim_cur] < 0) {
00340
00341 fd[num_open.rlim_cur] = -1;
00342
00343 snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur);
00344 snprintf(strbuff, sizeof(strbuff), "dup() attempt %s failed", strbuff1);
00345 fprintf(stderr, "%s\n", strbuff);
00346
00347 snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur);
00348 snprintf(strbuff, sizeof(strbuff), "fds system limit seems close to %s",
00349 strbuff1);
00350 fprintf(stderr, "%s\n", strbuff);
00351
00352 num_open.rlim_max = num_open.rlim_cur - SAFETY_MARGIN;
00353
00354 num_open.rlim_cur -= num_open.rlim_max;
00355 snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur);
00356 snprintf(strbuff, sizeof(strbuff), "closing %s file descriptors",
00357 strbuff1);
00358 fprintf(stderr, "%s\n", strbuff);
00359
00360 for(num_open.rlim_cur = num_open.rlim_max;
00361 fd[num_open.rlim_cur] >= 0;
00362 num_open.rlim_cur++) {
00363 close(fd[num_open.rlim_cur]);
00364 fd[num_open.rlim_cur] = -1;
00365 }
00366
00367 snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
00368 fprintf(stderr, "shrinking array for %s file descriptors\n", strbuff);
00369
00370
00371
00372 tmpfd = realloc(fd, sizeof(*fd) * (size_t)(num_open.rlim_max));
00373 if(tmpfd) {
00374 fd = tmpfd;
00375 tmpfd = NULL;
00376 }
00377
00378 break;
00379
00380 }
00381
00382 }
00383
00384 snprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max);
00385 fprintf(stderr, "%s file descriptors open\n", strbuff);
00386
00387 #if !defined(HAVE_POLL_FINE) && \
00388 !defined(USE_WINSOCK) && \
00389 !defined(TPF)
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402 num_open.rlim_cur = FD_SETSIZE - SAFETY_MARGIN;
00403 if(num_open.rlim_max > num_open.rlim_cur) {
00404 snprintf(strbuff, sizeof(strbuff), "select limit is FD_SETSIZE %d",
00405 FD_SETSIZE);
00406 store_errmsg(strbuff, 0);
00407 fprintf(stderr, "%s\n", msgbuff);
00408 close_file_descriptors();
00409 free(memchunk);
00410 return -8;
00411 }
00412
00413 num_open.rlim_cur = FD_SETSIZE - SAFETY_MARGIN;
00414 for(rl.rlim_cur = 0;
00415 rl.rlim_cur < num_open.rlim_max;
00416 rl.rlim_cur++) {
00417 if((fd[rl.rlim_cur] > 0) &&
00418 ((unsigned int)fd[rl.rlim_cur] > num_open.rlim_cur)) {
00419 snprintf(strbuff, sizeof(strbuff), "select limit is FD_SETSIZE %d",
00420 FD_SETSIZE);
00421 store_errmsg(strbuff, 0);
00422 fprintf(stderr, "%s\n", msgbuff);
00423 close_file_descriptors();
00424 free(memchunk);
00425 return -9;
00426 }
00427 }
00428
00429 #endif
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440 if(!fopen_works()) {
00441 snprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_max);
00442 snprintf(strbuff, sizeof(strbuff), "fopen fails with %s fds open",
00443 strbuff1);
00444 fprintf(stderr, "%s\n", msgbuff);
00445 snprintf(strbuff, sizeof(strbuff), "fopen fails with lots of fds open");
00446 store_errmsg(strbuff, 0);
00447 close_file_descriptors();
00448 free(memchunk);
00449 return -10;
00450 }
00451
00452
00453
00454
00455 free(memchunk);
00456
00457
00458
00459 if(!keep_open) {
00460 close_file_descriptors();
00461 }
00462
00463 return 0;
00464 }
00465
00466 int test(char *URL)
00467 {
00468 CURLcode res;
00469 CURL *curl;
00470
00471 if(!strcmp(URL, "check")) {
00472
00473 if(rlimit(FALSE)) {
00474 fprintf(stdout, "rlimit problem: %s\n", msgbuff);
00475 return 1;
00476 }
00477 return 0;
00478 }
00479
00480 if(rlimit(TRUE)) {
00481
00482 return TEST_ERR_MAJOR_BAD;
00483 }
00484
00485
00486
00487
00488 if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
00489 fprintf(stderr, "curl_global_init() failed\n");
00490 close_file_descriptors();
00491 return TEST_ERR_MAJOR_BAD;
00492 }
00493
00494 curl = curl_easy_init();
00495 if(!curl) {
00496 fprintf(stderr, "curl_easy_init() failed\n");
00497 close_file_descriptors();
00498 curl_global_cleanup();
00499 return TEST_ERR_MAJOR_BAD;
00500 }
00501
00502 test_setopt(curl, CURLOPT_URL, URL);
00503 test_setopt(curl, CURLOPT_HEADER, 1L);
00504
00505 res = curl_easy_perform(curl);
00506
00507 test_cleanup:
00508
00509 close_file_descriptors();
00510 curl_easy_cleanup(curl);
00511 curl_global_cleanup();
00512
00513 return (int)res;
00514 }
00515
00516 #else
00517
00518 int test(char *URL)
00519 {
00520 (void)URL;
00521 printf("system lacks necessary system function(s)");
00522 return 1;
00523 }
00524
00525 #endif