• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/curl-7.21.7/tests/libtest/
1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2011, 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 http://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_TYPES_H
25#include <sys/types.h>
26#endif
27#ifdef HAVE_SYS_RESOURCE_H
28#include <sys/resource.h>
29#endif
30#ifdef HAVE_FCNTL_H
31#include <fcntl.h>
32#endif
33#ifdef HAVE_LIMITS_H
34#include <limits.h>
35#endif
36#ifdef HAVE_STRING_H
37#include <string.h>
38#endif
39
40#include "memdebug.h"
41
42#ifndef FD_SETSIZE
43#error "this test requires FD_SETSIZE"
44#endif
45
46#define SAFETY_MARGIN (16)
47#define NUM_OPEN      (FD_SETSIZE + 10)
48#define NUM_NEEDED    (NUM_OPEN + SAFETY_MARGIN)
49
50#if defined(WIN32) || defined(_WIN32) || defined(MSDOS)
51#define DEV_NULL "NUL"
52#else
53#define DEV_NULL "/dev/null"
54#endif
55
56#if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
57
58static int *fd = NULL;
59static struct rlimit num_open;
60static char msgbuff[256];
61
62static void store_errmsg(const char *msg, int err)
63{
64  if (!err)
65    sprintf(msgbuff, "%s", msg);
66  else
67    sprintf(msgbuff, "%s, errno %d, %s", msg, err, strerror(err));
68}
69
70static void close_file_descriptors(void)
71{
72  for (num_open.rlim_cur = 0;
73       num_open.rlim_cur < num_open.rlim_max;
74       num_open.rlim_cur++)
75    if (fd[num_open.rlim_cur] > 0)
76      close(fd[num_open.rlim_cur]);
77  free(fd);
78  fd = NULL;
79}
80
81static int fopen_works(void)
82{
83  FILE *fpa[3];
84  int i;
85  int ret = 1;
86
87  for (i = 0; i < 3; i++) {
88    fpa[i] = NULL;
89  }
90  for (i = 0; i < 3; i++) {
91    fpa[i] = fopen(DEV_NULL, "r");
92    if (fpa[i] == NULL) {
93      store_errmsg("fopen() failed", ERRNO);
94      fprintf(stderr, "%s\n", msgbuff);
95      ret = 0;
96      break;
97    }
98  }
99  for (i = 0; i < 3; i++) {
100    if (fpa[i] != NULL)
101      fclose(fpa[i]);
102  }
103  return ret;
104}
105
106static int rlimit(int keep_open)
107{
108  int nitems, i;
109  int *memchunk = NULL;
110  char *fmt;
111  struct rlimit rl;
112  char strbuff[256];
113  char strbuff1[81];
114  char strbuff2[81];
115  char fmt_u[] = "%u";
116  char fmt_lu[] = "%lu";
117#ifdef HAVE_LONGLONG
118  char fmt_llu[] = "%llu";
119
120  if (sizeof(rl.rlim_max) > sizeof(long))
121    fmt = fmt_llu;
122  else
123#endif
124    fmt = (sizeof(rl.rlim_max) < sizeof(long))?fmt_u:fmt_lu;
125
126  /* get initial open file limits */
127
128  if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
129    store_errmsg("getrlimit() failed", ERRNO);
130    fprintf(stderr, "%s\n", msgbuff);
131    return -1;
132  }
133
134  /* show initial open file limits */
135
136#ifdef RLIM_INFINITY
137  if (rl.rlim_cur == RLIM_INFINITY)
138    strcpy(strbuff, "INFINITY");
139  else
140#endif
141    sprintf(strbuff, fmt, rl.rlim_cur);
142  fprintf(stderr, "initial soft limit: %s\n", strbuff);
143
144#ifdef RLIM_INFINITY
145  if (rl.rlim_max == RLIM_INFINITY)
146    strcpy(strbuff, "INFINITY");
147  else
148#endif
149    sprintf(strbuff, fmt, rl.rlim_max);
150  fprintf(stderr, "initial hard limit: %s\n", strbuff);
151
152  /* show our constants */
153
154  fprintf(stderr, "test518 FD_SETSIZE: %d\n", FD_SETSIZE);
155  fprintf(stderr, "test518 NUM_OPEN  : %d\n", NUM_OPEN);
156  fprintf(stderr, "test518 NUM_NEEDED: %d\n", NUM_NEEDED);
157
158  /*
159   * if soft limit and hard limit are different we ask the
160   * system to raise soft limit all the way up to the hard
161   * limit. Due to some other system limit the soft limit
162   * might not be raised up to the hard limit. So from this
163   * point the resulting soft limit is our limit. Trying to
164   * open more than soft limit file descriptors will fail.
165   */
166
167  if (rl.rlim_cur != rl.rlim_max) {
168
169#ifdef OPEN_MAX
170    if ((rl.rlim_cur > 0) &&
171        (rl.rlim_cur < OPEN_MAX)) {
172      fprintf(stderr, "raising soft limit up to OPEN_MAX\n");
173      rl.rlim_cur = OPEN_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#endif
182
183    fprintf(stderr, "raising soft limit up to hard limit\n");
184    rl.rlim_cur = rl.rlim_max;
185    if (setrlimit(RLIMIT_NOFILE, &rl) != 0) {
186      /* on failure don't abort just issue a warning */
187      store_errmsg("setrlimit() failed", ERRNO);
188      fprintf(stderr, "%s\n", msgbuff);
189      msgbuff[0] = '\0';
190    }
191
192    /* get current open file limits */
193
194    if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
195      store_errmsg("getrlimit() failed", ERRNO);
196      fprintf(stderr, "%s\n", msgbuff);
197      return -3;
198    }
199
200    /* show current open file limits */
201
202#ifdef RLIM_INFINITY
203    if (rl.rlim_cur == RLIM_INFINITY)
204      strcpy(strbuff, "INFINITY");
205    else
206#endif
207      sprintf(strbuff, fmt, rl.rlim_cur);
208    fprintf(stderr, "current soft limit: %s\n", strbuff);
209
210#ifdef RLIM_INFINITY
211    if (rl.rlim_max == RLIM_INFINITY)
212      strcpy(strbuff, "INFINITY");
213    else
214#endif
215      sprintf(strbuff, fmt, rl.rlim_max);
216    fprintf(stderr, "current hard limit: %s\n", strbuff);
217
218  } /* (rl.rlim_cur != rl.rlim_max) */
219
220  /*
221   * test 518 is all about testing libcurl functionality
222   * when more than FD_SETSIZE file descriptors are open.
223   * This means that if for any reason we are not able to
224   * open more than FD_SETSIZE file descriptors then test
225   * 518 should not be run.
226   */
227
228  /*
229   * verify that soft limit is higher than NUM_NEEDED,
230   * which is the number of file descriptors we would
231   * try to open plus SAFETY_MARGIN to not exhaust the
232   * file descriptor pool
233   */
234
235  num_open.rlim_cur = NUM_NEEDED;
236
237  if ((rl.rlim_cur > 0) &&
238#ifdef RLIM_INFINITY
239     (rl.rlim_cur != RLIM_INFINITY) &&
240#endif
241     (rl.rlim_cur <= num_open.rlim_cur)) {
242    sprintf(strbuff2, fmt, rl.rlim_cur);
243    sprintf(strbuff1, fmt, num_open.rlim_cur);
244    sprintf(strbuff, "fds needed %s > system limit %s",
245            strbuff1, strbuff2);
246    store_errmsg(strbuff, 0);
247    fprintf(stderr, "%s\n", msgbuff);
248    return -4;
249  }
250
251  /*
252   * reserve a chunk of memory before opening file descriptors to
253   * avoid a low memory condition once the file descriptors are
254   * open. System conditions that could make the test fail should
255   * be addressed in the precheck phase. This chunk of memory shall
256   * be always free()ed before exiting the rlimit() function so
257   * that it becomes available to the test.
258   */
259
260  for (nitems = i = 1; nitems <= i; i *= 2)
261    nitems = i;
262  if (nitems > 0x7fff)
263    nitems = 0x40000;
264  do {
265    num_open.rlim_max = sizeof(*memchunk) * (size_t)nitems;
266    sprintf(strbuff, fmt, num_open.rlim_max);
267    fprintf(stderr, "allocating memchunk %s byte array\n", strbuff);
268    memchunk = malloc(sizeof(*memchunk) * (size_t)nitems);
269    if (!memchunk) {
270      fprintf(stderr, "memchunk, malloc() failed\n");
271      nitems /= 2;
272    }
273  } while (nitems && !memchunk);
274  if (!memchunk) {
275    store_errmsg("memchunk, malloc() failed", ERRNO);
276    fprintf(stderr, "%s\n", msgbuff);
277    return -5;
278  }
279
280  /* initialize it to fight lazy allocation */
281
282  fprintf(stderr, "initializing memchunk array\n");
283
284  for (i = 0; i < nitems; i++)
285    memchunk[i] = -1;
286
287  /* set the number of file descriptors we will try to open */
288
289  num_open.rlim_max = NUM_OPEN;
290
291  /* verify that we won't overflow size_t in malloc() */
292
293  if ((size_t)(num_open.rlim_max) > ((size_t)-1) / sizeof(*fd)) {
294    sprintf(strbuff1, fmt, num_open.rlim_max);
295    sprintf(strbuff, "unable to allocate an array for %s "
296            "file descriptors, would overflow size_t", strbuff1);
297    store_errmsg(strbuff, 0);
298    fprintf(stderr, "%s\n", msgbuff);
299    free(memchunk);
300    return -6;
301  }
302
303  /* allocate array for file descriptors */
304
305  sprintf(strbuff, fmt, num_open.rlim_max);
306  fprintf(stderr, "allocating array for %s file descriptors\n", strbuff);
307
308  fd = malloc(sizeof(*fd) * (size_t)(num_open.rlim_max));
309  if (!fd) {
310    store_errmsg("fd, malloc() failed", ERRNO);
311    fprintf(stderr, "%s\n", msgbuff);
312    free(memchunk);
313    return -7;
314  }
315
316  /* initialize it to fight lazy allocation */
317
318  fprintf(stderr, "initializing fd array\n");
319
320  for (num_open.rlim_cur = 0;
321       num_open.rlim_cur < num_open.rlim_max;
322       num_open.rlim_cur++)
323    fd[num_open.rlim_cur] = -1;
324
325  sprintf(strbuff, fmt, num_open.rlim_max);
326  fprintf(stderr, "trying to open %s file descriptors\n", strbuff);
327
328  /* open a dummy descriptor */
329
330  fd[0] = open(DEV_NULL, O_RDONLY);
331  if (fd[0] < 0) {
332    sprintf(strbuff, "opening of %s failed", DEV_NULL);
333    store_errmsg(strbuff, ERRNO);
334    fprintf(stderr, "%s\n", msgbuff);
335    free(fd);
336    fd = NULL;
337    free(memchunk);
338    return -8;
339  }
340
341  /* create a bunch of file descriptors */
342
343  for (num_open.rlim_cur = 1;
344       num_open.rlim_cur < num_open.rlim_max;
345       num_open.rlim_cur++) {
346
347    fd[num_open.rlim_cur] = dup(fd[0]);
348
349    if (fd[num_open.rlim_cur] < 0) {
350
351      fd[num_open.rlim_cur] = -1;
352
353      sprintf(strbuff1, fmt, num_open.rlim_cur);
354      sprintf(strbuff, "dup() attempt %s failed", strbuff1);
355      fprintf(stderr, "%s\n", strbuff);
356
357      sprintf(strbuff1, fmt, num_open.rlim_cur);
358      sprintf(strbuff, "fds system limit seems close to %s", strbuff1);
359      fprintf(stderr, "%s\n", strbuff);
360
361      num_open.rlim_max = NUM_NEEDED;
362
363      sprintf(strbuff2, fmt, num_open.rlim_max);
364      sprintf(strbuff1, fmt, num_open.rlim_cur);
365      sprintf(strbuff, "fds needed %s > system limit %s",
366              strbuff2, strbuff1);
367      store_errmsg(strbuff, 0);
368      fprintf(stderr, "%s\n", msgbuff);
369
370      for (num_open.rlim_cur = 0;
371           fd[num_open.rlim_cur] >= 0;
372           num_open.rlim_cur++)
373        close(fd[num_open.rlim_cur]);
374      free(fd);
375      fd = NULL;
376      free(memchunk);
377      return -9;
378
379    }
380
381  }
382
383  sprintf(strbuff, fmt, num_open.rlim_max);
384  fprintf(stderr, "%s file descriptors open\n", strbuff);
385
386#if !defined(HAVE_POLL_FINE)    && \
387    !defined(USE_WINSOCK)       && \
388    !defined(TPF)
389
390  /*
391   * when using select() instead of poll() we cannot test
392   * libcurl functionality with a socket number equal or
393   * greater than FD_SETSIZE. In any case, macro VERIFY_SOCK
394   * in lib/select.c enforces this check and protects libcurl
395   * from a possible crash. The effect of this protection
396   * is that test 518 will always fail, since the actual
397   * call to select() never takes place. We skip test 518
398   * with an indication that select limit would be exceeded.
399   */
400
401  num_open.rlim_cur = FD_SETSIZE - SAFETY_MARGIN;
402  if (num_open.rlim_max > num_open.rlim_cur) {
403    sprintf(strbuff, "select limit is FD_SETSIZE %d", FD_SETSIZE);
404    store_errmsg(strbuff, 0);
405    fprintf(stderr, "%s\n", msgbuff);
406    close_file_descriptors();
407    free(memchunk);
408    return -10;
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      sprintf(strbuff, "select limit is FD_SETSIZE %d", FD_SETSIZE);
418      store_errmsg(strbuff, 0);
419      fprintf(stderr, "%s\n", msgbuff);
420      close_file_descriptors();
421      free(memchunk);
422      return -11;
423    }
424  }
425
426#endif /* using a FD_SETSIZE bound select() */
427
428  /*
429   * Old or 'backwards compatible' implementations of stdio do not allow
430   * handling of streams with an underlying file descriptor number greater
431   * than 255, even when allowing high numbered file descriptors for sockets.
432   * At this point we have a big number of file descriptors which have been
433   * opened using dup(), so lets test the stdio implementation and discover
434   * if it is capable of fopen()ing some additional files.
435   */
436
437  if (!fopen_works()) {
438    sprintf(strbuff1, fmt, num_open.rlim_max);
439    sprintf(strbuff, "stdio fopen() fails with %s fds open()",
440            strbuff1);
441    fprintf(stderr, "%s\n", msgbuff);
442    sprintf(strbuff, "stdio fopen() fails with lots of fds open()");
443    store_errmsg(strbuff, 0);
444    close_file_descriptors();
445    free(memchunk);
446    return -12;
447  }
448
449  /* free the chunk of memory we were reserving so that it
450     becomes becomes available to the test */
451
452  free(memchunk);
453
454  /* close file descriptors unless instructed to keep them */
455
456  if (!keep_open) {
457    close_file_descriptors();
458  }
459
460  return 0;
461}
462
463int test(char *URL)
464{
465  CURLcode res;
466  CURL *curl;
467
468  if(!strcmp(URL, "check")) {
469    /* used by the test script to ask if we can run this test or not */
470    if(rlimit(FALSE)) {
471      fprintf(stdout, "rlimit problem: %s\n", msgbuff);
472      return 1;
473    }
474    return 0; /* sure, run this! */
475  }
476
477  if (rlimit(TRUE)) {
478    /* failure */
479    return TEST_ERR_MAJOR_BAD;
480  }
481
482  /* run the test with the bunch of open file descriptors
483     and close them all once the test is over */
484
485  if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
486    fprintf(stderr, "curl_global_init() failed\n");
487    close_file_descriptors();
488    return TEST_ERR_MAJOR_BAD;
489  }
490
491  if ((curl = curl_easy_init()) == NULL) {
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
503test_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
514int 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) */
522