| xf.li | 6c8fc1e | 2023-08-12 00:11:09 -0700 | [diff] [blame] | 1 | /*************************************************************************** | 
|  | 2 | *                                  _   _ ____  _ | 
|  | 3 | *  Project                     ___| | | |  _ \| | | 
|  | 4 | *                             / __| | | | |_) | | | 
|  | 5 | *                            | (__| |_| |  _ <| |___ | 
|  | 6 | *                             \___|\___/|_| \_\_____| | 
|  | 7 | * | 
|  | 8 | * Copyright (C) 1998 - 2022, 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.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 | * SPDX-License-Identifier: curl | 
|  | 22 | * | 
|  | 23 | ***************************************************************************/ | 
|  | 24 | #include "test.h" | 
|  | 25 |  | 
|  | 26 | #ifdef HAVE_SYS_RESOURCE_H | 
|  | 27 | #include <sys/resource.h> | 
|  | 28 | #endif | 
|  | 29 | #ifdef HAVE_FCNTL_H | 
|  | 30 | #include <fcntl.h> | 
|  | 31 | #endif | 
|  | 32 | #include <limits.h> | 
|  | 33 |  | 
|  | 34 | #include "warnless.h" | 
|  | 35 | #include "memdebug.h" | 
|  | 36 |  | 
|  | 37 | #ifndef FD_SETSIZE | 
|  | 38 | #error "this test requires FD_SETSIZE" | 
|  | 39 | #endif | 
|  | 40 |  | 
|  | 41 | #define SAFETY_MARGIN (16) | 
|  | 42 | #define NUM_OPEN      (FD_SETSIZE + 10) | 
|  | 43 | #define NUM_NEEDED    (NUM_OPEN + SAFETY_MARGIN) | 
|  | 44 |  | 
|  | 45 | #if defined(WIN32) || defined(_WIN32) || defined(MSDOS) | 
|  | 46 | #define DEV_NULL "NUL" | 
|  | 47 | #else | 
|  | 48 | #define DEV_NULL "/dev/null" | 
|  | 49 | #endif | 
|  | 50 |  | 
|  | 51 | #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) | 
|  | 52 |  | 
|  | 53 | static int *fd = NULL; | 
|  | 54 | static struct rlimit num_open; | 
|  | 55 | static char msgbuff[256]; | 
|  | 56 |  | 
|  | 57 | static void store_errmsg(const char *msg, int err) | 
|  | 58 | { | 
|  | 59 | if(!err) | 
|  | 60 | msnprintf(msgbuff, sizeof(msgbuff), "%s", msg); | 
|  | 61 | else | 
|  | 62 | msnprintf(msgbuff, sizeof(msgbuff), "%s, errno %d, %s", msg, | 
|  | 63 | err, strerror(err)); | 
|  | 64 | } | 
|  | 65 |  | 
|  | 66 | static void close_file_descriptors(void) | 
|  | 67 | { | 
|  | 68 | for(num_open.rlim_cur = 0; | 
|  | 69 | num_open.rlim_cur < num_open.rlim_max; | 
|  | 70 | num_open.rlim_cur++) | 
|  | 71 | if(fd[num_open.rlim_cur] > 0) | 
|  | 72 | close(fd[num_open.rlim_cur]); | 
|  | 73 | free(fd); | 
|  | 74 | fd = NULL; | 
|  | 75 | } | 
|  | 76 |  | 
|  | 77 | static int fopen_works(void) | 
|  | 78 | { | 
|  | 79 | FILE *fpa[3]; | 
|  | 80 | int i; | 
|  | 81 | int ret = 1; | 
|  | 82 |  | 
|  | 83 | for(i = 0; i < 3; i++) { | 
|  | 84 | fpa[i] = NULL; | 
|  | 85 | } | 
|  | 86 | for(i = 0; i < 3; i++) { | 
|  | 87 | fpa[i] = fopen(DEV_NULL, FOPEN_READTEXT); | 
|  | 88 | if(!fpa[i]) { | 
|  | 89 | store_errmsg("fopen failed", errno); | 
|  | 90 | fprintf(stderr, "%s\n", msgbuff); | 
|  | 91 | ret = 0; | 
|  | 92 | break; | 
|  | 93 | } | 
|  | 94 | } | 
|  | 95 | for(i = 0; i < 3; i++) { | 
|  | 96 | if(fpa[i]) | 
|  | 97 | fclose(fpa[i]); | 
|  | 98 | } | 
|  | 99 | return ret; | 
|  | 100 | } | 
|  | 101 |  | 
|  | 102 | static int rlimit(int keep_open) | 
|  | 103 | { | 
|  | 104 | int nitems, i; | 
|  | 105 | int *memchunk = NULL; | 
|  | 106 | char *fmt; | 
|  | 107 | struct rlimit rl; | 
|  | 108 | char strbuff[256]; | 
|  | 109 | char strbuff1[81]; | 
|  | 110 | char strbuff2[81]; | 
|  | 111 | char fmt_u[] = "%u"; | 
|  | 112 | char fmt_lu[] = "%lu"; | 
|  | 113 | #ifdef HAVE_LONGLONG | 
|  | 114 | char fmt_llu[] = "%llu"; | 
|  | 115 |  | 
|  | 116 | if(sizeof(rl.rlim_max) > sizeof(long)) | 
|  | 117 | fmt = fmt_llu; | 
|  | 118 | else | 
|  | 119 | #endif | 
|  | 120 | fmt = (sizeof(rl.rlim_max) < sizeof(long))?fmt_u:fmt_lu; | 
|  | 121 |  | 
|  | 122 | /* get initial open file limits */ | 
|  | 123 |  | 
|  | 124 | if(getrlimit(RLIMIT_NOFILE, &rl) != 0) { | 
|  | 125 | store_errmsg("getrlimit() failed", errno); | 
|  | 126 | fprintf(stderr, "%s\n", msgbuff); | 
|  | 127 | return -1; | 
|  | 128 | } | 
|  | 129 |  | 
|  | 130 | /* show initial open file limits */ | 
|  | 131 |  | 
|  | 132 | #ifdef RLIM_INFINITY | 
|  | 133 | if(rl.rlim_cur == RLIM_INFINITY) | 
|  | 134 | strcpy(strbuff, "INFINITY"); | 
|  | 135 | else | 
|  | 136 | #endif | 
|  | 137 | msnprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_cur); | 
|  | 138 | fprintf(stderr, "initial soft limit: %s\n", strbuff); | 
|  | 139 |  | 
|  | 140 | #ifdef RLIM_INFINITY | 
|  | 141 | if(rl.rlim_max == RLIM_INFINITY) | 
|  | 142 | strcpy(strbuff, "INFINITY"); | 
|  | 143 | else | 
|  | 144 | #endif | 
|  | 145 | msnprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_max); | 
|  | 146 | fprintf(stderr, "initial hard limit: %s\n", strbuff); | 
|  | 147 |  | 
|  | 148 | /* show our constants */ | 
|  | 149 |  | 
|  | 150 | fprintf(stderr, "test518 FD_SETSIZE: %d\n", FD_SETSIZE); | 
|  | 151 | fprintf(stderr, "test518 NUM_OPEN  : %d\n", NUM_OPEN); | 
|  | 152 | fprintf(stderr, "test518 NUM_NEEDED: %d\n", NUM_NEEDED); | 
|  | 153 |  | 
|  | 154 | /* | 
|  | 155 | * if soft limit and hard limit are different we ask the | 
|  | 156 | * system to raise soft limit all the way up to the hard | 
|  | 157 | * limit. Due to some other system limit the soft limit | 
|  | 158 | * might not be raised up to the hard limit. So from this | 
|  | 159 | * point the resulting soft limit is our limit. Trying to | 
|  | 160 | * open more than soft limit file descriptors will fail. | 
|  | 161 | */ | 
|  | 162 |  | 
|  | 163 | if(rl.rlim_cur != rl.rlim_max) { | 
|  | 164 |  | 
|  | 165 | #ifdef OPEN_MAX | 
|  | 166 | if((rl.rlim_cur > 0) && | 
|  | 167 | (rl.rlim_cur < OPEN_MAX)) { | 
|  | 168 | fprintf(stderr, "raising soft limit up to OPEN_MAX\n"); | 
|  | 169 | rl.rlim_cur = OPEN_MAX; | 
|  | 170 | if(setrlimit(RLIMIT_NOFILE, &rl) != 0) { | 
|  | 171 | /* on failure don't abort just issue a warning */ | 
|  | 172 | store_errmsg("setrlimit() failed", errno); | 
|  | 173 | fprintf(stderr, "%s\n", msgbuff); | 
|  | 174 | msgbuff[0] = '\0'; | 
|  | 175 | } | 
|  | 176 | } | 
|  | 177 | #endif | 
|  | 178 |  | 
|  | 179 | fprintf(stderr, "raising soft limit up to hard limit\n"); | 
|  | 180 | rl.rlim_cur = rl.rlim_max; | 
|  | 181 | if(setrlimit(RLIMIT_NOFILE, &rl) != 0) { | 
|  | 182 | /* on failure don't abort just issue a warning */ | 
|  | 183 | store_errmsg("setrlimit() failed", errno); | 
|  | 184 | fprintf(stderr, "%s\n", msgbuff); | 
|  | 185 | msgbuff[0] = '\0'; | 
|  | 186 | } | 
|  | 187 |  | 
|  | 188 | /* get current open file limits */ | 
|  | 189 |  | 
|  | 190 | if(getrlimit(RLIMIT_NOFILE, &rl) != 0) { | 
|  | 191 | store_errmsg("getrlimit() failed", errno); | 
|  | 192 | fprintf(stderr, "%s\n", msgbuff); | 
|  | 193 | return -3; | 
|  | 194 | } | 
|  | 195 |  | 
|  | 196 | /* show current open file limits */ | 
|  | 197 |  | 
|  | 198 | #ifdef RLIM_INFINITY | 
|  | 199 | if(rl.rlim_cur == RLIM_INFINITY) | 
|  | 200 | strcpy(strbuff, "INFINITY"); | 
|  | 201 | else | 
|  | 202 | #endif | 
|  | 203 | msnprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_cur); | 
|  | 204 | fprintf(stderr, "current soft limit: %s\n", strbuff); | 
|  | 205 |  | 
|  | 206 | #ifdef RLIM_INFINITY | 
|  | 207 | if(rl.rlim_max == RLIM_INFINITY) | 
|  | 208 | strcpy(strbuff, "INFINITY"); | 
|  | 209 | else | 
|  | 210 | #endif | 
|  | 211 | msnprintf(strbuff, sizeof(strbuff), fmt, rl.rlim_max); | 
|  | 212 | fprintf(stderr, "current hard limit: %s\n", strbuff); | 
|  | 213 |  | 
|  | 214 | } /* (rl.rlim_cur != rl.rlim_max) */ | 
|  | 215 |  | 
|  | 216 | /* | 
|  | 217 | * test 518 is all about testing libcurl functionality | 
|  | 218 | * when more than FD_SETSIZE file descriptors are open. | 
|  | 219 | * This means that if for any reason we are not able to | 
|  | 220 | * open more than FD_SETSIZE file descriptors then test | 
|  | 221 | * 518 should not be run. | 
|  | 222 | */ | 
|  | 223 |  | 
|  | 224 | /* | 
|  | 225 | * verify that soft limit is higher than NUM_NEEDED, | 
|  | 226 | * which is the number of file descriptors we would | 
|  | 227 | * try to open plus SAFETY_MARGIN to not exhaust the | 
|  | 228 | * file descriptor pool | 
|  | 229 | */ | 
|  | 230 |  | 
|  | 231 | num_open.rlim_cur = NUM_NEEDED; | 
|  | 232 |  | 
|  | 233 | if((rl.rlim_cur > 0) && | 
|  | 234 | #ifdef RLIM_INFINITY | 
|  | 235 | (rl.rlim_cur != RLIM_INFINITY) && | 
|  | 236 | #endif | 
|  | 237 | (rl.rlim_cur <= num_open.rlim_cur)) { | 
|  | 238 | msnprintf(strbuff2, sizeof(strbuff2), fmt, rl.rlim_cur); | 
|  | 239 | msnprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur); | 
|  | 240 | msnprintf(strbuff, sizeof(strbuff), "fds needed %s > system limit %s", | 
|  | 241 | strbuff1, strbuff2); | 
|  | 242 | store_errmsg(strbuff, 0); | 
|  | 243 | fprintf(stderr, "%s\n", msgbuff); | 
|  | 244 | return -4; | 
|  | 245 | } | 
|  | 246 |  | 
|  | 247 | /* | 
|  | 248 | * reserve a chunk of memory before opening file descriptors to | 
|  | 249 | * avoid a low memory condition once the file descriptors are | 
|  | 250 | * open. System conditions that could make the test fail should | 
|  | 251 | * be addressed in the precheck phase. This chunk of memory shall | 
|  | 252 | * be always free()ed before exiting the rlimit() function so | 
|  | 253 | * that it becomes available to the test. | 
|  | 254 | */ | 
|  | 255 |  | 
|  | 256 | for(nitems = i = 1; nitems <= i; i *= 2) | 
|  | 257 | nitems = i; | 
|  | 258 | if(nitems > 0x7fff) | 
|  | 259 | nitems = 0x40000; | 
|  | 260 | do { | 
|  | 261 | num_open.rlim_max = sizeof(*memchunk) * (size_t)nitems; | 
|  | 262 | msnprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max); | 
|  | 263 | fprintf(stderr, "allocating memchunk %s byte array\n", strbuff); | 
|  | 264 | memchunk = malloc(sizeof(*memchunk) * (size_t)nitems); | 
|  | 265 | if(!memchunk) { | 
|  | 266 | fprintf(stderr, "memchunk, malloc() failed\n"); | 
|  | 267 | nitems /= 2; | 
|  | 268 | } | 
|  | 269 | } while(nitems && !memchunk); | 
|  | 270 | if(!memchunk) { | 
|  | 271 | store_errmsg("memchunk, malloc() failed", errno); | 
|  | 272 | fprintf(stderr, "%s\n", msgbuff); | 
|  | 273 | return -5; | 
|  | 274 | } | 
|  | 275 |  | 
|  | 276 | /* initialize it to fight lazy allocation */ | 
|  | 277 |  | 
|  | 278 | fprintf(stderr, "initializing memchunk array\n"); | 
|  | 279 |  | 
|  | 280 | for(i = 0; i < nitems; i++) | 
|  | 281 | memchunk[i] = -1; | 
|  | 282 |  | 
|  | 283 | /* set the number of file descriptors we will try to open */ | 
|  | 284 |  | 
|  | 285 | num_open.rlim_max = NUM_OPEN; | 
|  | 286 |  | 
|  | 287 | /* verify that we won't overflow size_t in malloc() */ | 
|  | 288 |  | 
|  | 289 | if((size_t)(num_open.rlim_max) > ((size_t)-1) / sizeof(*fd)) { | 
|  | 290 | msnprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_max); | 
|  | 291 | msnprintf(strbuff, sizeof(strbuff), "unable to allocate an array for %s " | 
|  | 292 | "file descriptors, would overflow size_t", strbuff1); | 
|  | 293 | store_errmsg(strbuff, 0); | 
|  | 294 | fprintf(stderr, "%s\n", msgbuff); | 
|  | 295 | free(memchunk); | 
|  | 296 | return -6; | 
|  | 297 | } | 
|  | 298 |  | 
|  | 299 | /* allocate array for file descriptors */ | 
|  | 300 |  | 
|  | 301 | msnprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max); | 
|  | 302 | fprintf(stderr, "allocating array for %s file descriptors\n", strbuff); | 
|  | 303 |  | 
|  | 304 | fd = malloc(sizeof(*fd) * (size_t)(num_open.rlim_max)); | 
|  | 305 | if(!fd) { | 
|  | 306 | store_errmsg("fd, malloc() failed", errno); | 
|  | 307 | fprintf(stderr, "%s\n", msgbuff); | 
|  | 308 | free(memchunk); | 
|  | 309 | return -7; | 
|  | 310 | } | 
|  | 311 |  | 
|  | 312 | /* initialize it to fight lazy allocation */ | 
|  | 313 |  | 
|  | 314 | fprintf(stderr, "initializing fd array\n"); | 
|  | 315 |  | 
|  | 316 | for(num_open.rlim_cur = 0; | 
|  | 317 | num_open.rlim_cur < num_open.rlim_max; | 
|  | 318 | num_open.rlim_cur++) | 
|  | 319 | fd[num_open.rlim_cur] = -1; | 
|  | 320 |  | 
|  | 321 | msnprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max); | 
|  | 322 | fprintf(stderr, "trying to open %s file descriptors\n", strbuff); | 
|  | 323 |  | 
|  | 324 | /* open a dummy descriptor */ | 
|  | 325 |  | 
|  | 326 | fd[0] = open(DEV_NULL, O_RDONLY); | 
|  | 327 | if(fd[0] < 0) { | 
|  | 328 | msnprintf(strbuff, sizeof(strbuff), "opening of %s failed", DEV_NULL); | 
|  | 329 | store_errmsg(strbuff, errno); | 
|  | 330 | fprintf(stderr, "%s\n", msgbuff); | 
|  | 331 | free(fd); | 
|  | 332 | fd = NULL; | 
|  | 333 | free(memchunk); | 
|  | 334 | return -8; | 
|  | 335 | } | 
|  | 336 |  | 
|  | 337 | /* create a bunch of file descriptors */ | 
|  | 338 |  | 
|  | 339 | for(num_open.rlim_cur = 1; | 
|  | 340 | num_open.rlim_cur < num_open.rlim_max; | 
|  | 341 | num_open.rlim_cur++) { | 
|  | 342 |  | 
|  | 343 | fd[num_open.rlim_cur] = dup(fd[0]); | 
|  | 344 |  | 
|  | 345 | if(fd[num_open.rlim_cur] < 0) { | 
|  | 346 |  | 
|  | 347 | fd[num_open.rlim_cur] = -1; | 
|  | 348 |  | 
|  | 349 | msnprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur); | 
|  | 350 | msnprintf(strbuff, sizeof(strbuff), "dup() attempt %s failed", strbuff1); | 
|  | 351 | fprintf(stderr, "%s\n", strbuff); | 
|  | 352 |  | 
|  | 353 | msnprintf(strbuff1, sizeof(strbuff), fmt, num_open.rlim_cur); | 
|  | 354 | msnprintf(strbuff, sizeof(strbuff), "fds system limit seems close to %s", | 
|  | 355 | strbuff1); | 
|  | 356 | fprintf(stderr, "%s\n", strbuff); | 
|  | 357 |  | 
|  | 358 | num_open.rlim_max = NUM_NEEDED; | 
|  | 359 |  | 
|  | 360 | msnprintf(strbuff2, sizeof(strbuff2), fmt, num_open.rlim_max); | 
|  | 361 | msnprintf(strbuff1, sizeof(strbuff1), fmt, num_open.rlim_cur); | 
|  | 362 | msnprintf(strbuff, sizeof(strbuff), "fds needed %s > system limit %s", | 
|  | 363 | strbuff2, strbuff1); | 
|  | 364 | store_errmsg(strbuff, 0); | 
|  | 365 | fprintf(stderr, "%s\n", msgbuff); | 
|  | 366 |  | 
|  | 367 | for(num_open.rlim_cur = 0; | 
|  | 368 | fd[num_open.rlim_cur] >= 0; | 
|  | 369 | num_open.rlim_cur++) | 
|  | 370 | close(fd[num_open.rlim_cur]); | 
|  | 371 | free(fd); | 
|  | 372 | fd = NULL; | 
|  | 373 | free(memchunk); | 
|  | 374 | return -9; | 
|  | 375 |  | 
|  | 376 | } | 
|  | 377 |  | 
|  | 378 | } | 
|  | 379 |  | 
|  | 380 | msnprintf(strbuff, sizeof(strbuff), fmt, num_open.rlim_max); | 
|  | 381 | fprintf(stderr, "%s file descriptors open\n", strbuff); | 
|  | 382 |  | 
|  | 383 | #if !defined(HAVE_POLL_FINE) && !defined(USE_WINSOCK) | 
|  | 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) */ |