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