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>