diff options
author | Yang Tse <yangsita@gmail.com> | 2006-11-02 20:50:18 +0000 |
---|---|---|
committer | Yang Tse <yangsita@gmail.com> | 2006-11-02 20:50:18 +0000 |
commit | 2149a095f7ec9bb977c6deac948d9ac32d650389 (patch) | |
tree | 627d69059231dbc2f1889d90db311d343bfb32d8 /tests/libtest/lib537.c | |
parent | e8d21adbaaf829d2980ec9160c7d170227759daa (diff) | |
download | curl-2149a095f7ec9bb977c6deac948d9ac32d650389.tar.gz |
update and split test cases 518 and 537 into its own source code file
Diffstat (limited to 'tests/libtest/lib537.c')
-rw-r--r-- | tests/libtest/lib537.c | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/tests/libtest/lib537.c b/tests/libtest/lib537.c new file mode 100644 index 000000000..7f1d7b3e2 --- /dev/null +++ b/tests/libtest/lib537.c @@ -0,0 +1,399 @@ +/***************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * $Id$ + */ + +/* + * This source code is used for lib518 and lib537. + */ + +#include "test.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +#define SAFETY_MARGIN (10) + +#if defined(WIN32) || defined(_WIN32) || defined(MSDOS) +#define DEV_NULL "NUL" +#else +#define DEV_NULL "/dev/null" +#endif + +#if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) + +static int *fd = NULL; +static struct rlimit num_open; +static char msgbuff[256]; + +/* + * our_errno() returns the NOT *socket-related* errno (or equivalent) + * on this platform to hide platform specific for the calling function. + */ + +static int our_errno(void) +{ +#ifdef WIN32 + return (int)GetLastError(); +#else + return errno; +#endif +} + +static void store_errmsg(const char *msg, int err) +{ + if (!err) + sprintf(msgbuff, "%s", msg); + else + sprintf(msgbuff, "%s, errno %d, %s", msg, err, strerror(err)); +} + +static void close_file_descriptors(void) +{ + for (num_open.rlim_cur = 0; + num_open.rlim_cur < num_open.rlim_max; + num_open.rlim_cur++) + if (fd[num_open.rlim_cur] > 0) + close(fd[num_open.rlim_cur]); + free(fd); + fd = NULL; +} + +static int rlimit(int keep_open) +{ + int *tmpfd; + int nitems, i; + int *memchunk = NULL; + char *fmt; + struct rlimit rl; + char strbuff[256]; + char strbuff1[81]; + char fmt_u[] = "%u"; + char fmt_lu[] = "%lu"; +#ifdef HAVE_LONGLONG + char fmt_llu[] = "%llu"; + + if (sizeof(rl.rlim_max) > sizeof(long)) + fmt = fmt_llu; + else +#endif + fmt = (sizeof(rl.rlim_max) < sizeof(long))?fmt_u:fmt_lu; + + /* get initial open file limits */ + + if (getrlimit(RLIMIT_NOFILE, &rl) != 0) { + store_errmsg("getrlimit() failed", our_errno()); + fprintf(stderr, "%s\n", msgbuff); + return -1; + } + + /* show initial open file limits */ + +#ifdef RLIM_INFINITY + if (rl.rlim_cur == RLIM_INFINITY) + strcpy(strbuff, "INFINITY"); + else +#endif + sprintf(strbuff, fmt, rl.rlim_cur); + fprintf(stderr, "initial soft limit: %s\n", strbuff); + +#ifdef RLIM_INFINITY + if (rl.rlim_max == RLIM_INFINITY) + strcpy(strbuff, "INFINITY"); + else +#endif + sprintf(strbuff, fmt, rl.rlim_max); + fprintf(stderr, "initial hard limit: %s\n", strbuff); + + /* + * if soft limit and hard limit are different we ask the + * system to raise soft limit all the way up to the hard + * limit. Due to some other system limit the soft limit + * might not be raised up to the hard limit. So from this + * point the resulting soft limit is our limit. Trying to + * open more than soft limit file descriptors will fail. + */ + + if (rl.rlim_cur != rl.rlim_max) { + + fprintf(stderr, "raising soft limit up to hard limit\n"); + rl.rlim_cur = rl.rlim_max; + if (setrlimit(RLIMIT_NOFILE, &rl) != 0) { + store_errmsg("setrlimit() failed", our_errno()); + fprintf(stderr, "%s\n", msgbuff); + return -2; + } + + /* get current open file limits */ + + if (getrlimit(RLIMIT_NOFILE, &rl) != 0) { + store_errmsg("getrlimit() failed", our_errno()); + fprintf(stderr, "%s\n", msgbuff); + return -3; + } + + /* show current open file limits */ + +#ifdef RLIM_INFINITY + if (rl.rlim_cur == RLIM_INFINITY) + strcpy(strbuff, "INFINITY"); + else +#endif + sprintf(strbuff, fmt, rl.rlim_cur); + fprintf(stderr, "current soft limit: %s\n", strbuff); + +#ifdef RLIM_INFINITY + if (rl.rlim_max == RLIM_INFINITY) + strcpy(strbuff, "INFINITY"); + else +#endif + sprintf(strbuff, fmt, rl.rlim_max); + fprintf(stderr, "current hard limit: %s\n", strbuff); + + } /* (rl.rlim_cur != rl.rlim_max) */ + + /* + * test 537 is all about testing libcurl functionality + * when the system has nearly exhausted the number of + * free file descriptors. Test 537 will try to run with + * very few free file descriptors. + */ + + /* + * reserve a chunk of memory before opening file descriptors to + * avoid a low memory condition once the file descriptors are + * open. System conditions that could make the test fail should + * be addressed in the precheck phase. This chunk of memory shall + * be always free()ed before exiting the rlimit() function so + * that it becomes available to the test. + */ + + nitems = INT_MAX / sizeof(*memchunk); + do { + memchunk = malloc(sizeof(*memchunk) * (size_t)nitems); + if (!memchunk) + nitems /= 2; + } while (nitems && !memchunk); + if (!memchunk) { + store_errmsg("memchunk, malloc() failed", our_errno()); + fprintf(stderr, "%s\n", msgbuff); + return -7; + } + + /* initialize it to fight lazy allocation */ + + for (i = 0; i < nitems; i++) + memchunk[i] = -1; + + /* set the number of file descriptors we will try to open */ + +#ifdef RLIM_INFINITY + if ((rl.rlim_cur > 0) && (rl.rlim_cur != RLIM_INFINITY)) { +#else + if (rl.rlim_cur > 0) { +#endif + /* soft limit minus SAFETY_MARGIN */ + num_open.rlim_max = rl.rlim_cur - SAFETY_MARGIN; + } + else { + /* biggest file descriptor array size */ + num_open.rlim_max = INT_MAX / sizeof(*fd); + } + + /* verify that we won't overflow size_t in malloc() */ + + if (num_open.rlim_max > ((size_t)-1) / sizeof(*fd)) { + sprintf(strbuff1, fmt, num_open.rlim_max); + sprintf(strbuff, "unable to allocate an array for %s " + "file descriptors, would overflow size_t", strbuff1); + store_errmsg(strbuff, 0); + fprintf(stderr, "%s\n", msgbuff); + free(memchunk); + return -8; + } + + /* allocate array for file descriptors */ + + do { + sprintf(strbuff, fmt, num_open.rlim_max); + fprintf(stderr, "allocating array for %s file descriptors\n", strbuff); + fd = malloc(sizeof(*fd) * (size_t)(num_open.rlim_max)); + if (!fd) { + fprintf(stderr, "fd, malloc() failed\n"); + num_open.rlim_max /= 2; + } + } while (num_open.rlim_max && !fd); + if (!fd) { + store_errmsg("fd, malloc() failed", our_errno()); + fprintf(stderr, "%s\n", msgbuff); + free(memchunk); + return -9; + } + + /* initialize it to fight lazy allocation */ + + for (num_open.rlim_cur = 0; + num_open.rlim_cur < num_open.rlim_max; + num_open.rlim_cur++) + fd[num_open.rlim_cur] = -1; + + sprintf(strbuff, fmt, num_open.rlim_max); + fprintf(stderr, "trying to open %s file descriptors\n", strbuff); + + /* open a dummy descriptor */ + + fd[0] = open(DEV_NULL, O_RDONLY); + if (fd[0] < 0) { + sprintf(strbuff, "opening of %s failed", DEV_NULL); + store_errmsg(strbuff, our_errno()); + fprintf(stderr, "%s\n", msgbuff); + free(fd); + fd = NULL; + free(memchunk); + return -10; + } + + /* create a bunch of file descriptors */ + + for (num_open.rlim_cur = 1; + num_open.rlim_cur < num_open.rlim_max; + num_open.rlim_cur++) { + + fd[num_open.rlim_cur] = dup(fd[0]); + + if (fd[num_open.rlim_cur] < 0) { + + fd[num_open.rlim_cur] = -1; + + sprintf(strbuff1, fmt, num_open.rlim_cur); + sprintf(strbuff, "dup() attempt %s failed", strbuff1); + fprintf(stderr, "%s\n", strbuff); + + sprintf(strbuff1, fmt, num_open.rlim_cur + 2); + sprintf(strbuff, "system does not support opening " + "more than %s files" , strbuff1); + fprintf(stderr, "%s\n", strbuff); + + num_open.rlim_max = num_open.rlim_cur + 2 - SAFETY_MARGIN; + + num_open.rlim_cur -= num_open.rlim_max; + sprintf(strbuff1, fmt, num_open.rlim_cur); + sprintf(strbuff, "closing %s files", strbuff1); + fprintf(stderr, "%s\n", strbuff); + + for (num_open.rlim_cur = num_open.rlim_max; + fd[num_open.rlim_cur] >= 0; + num_open.rlim_cur++) { + close(fd[num_open.rlim_cur]); + fd[num_open.rlim_cur] = -1; + } + + sprintf(strbuff, fmt, num_open.rlim_max); + fprintf(stderr, "shrinking array for %s file descriptors\n", strbuff); + + tmpfd = realloc(fd, sizeof(*fd) * (size_t)(num_open.rlim_max)); + if (!tmpfd) { + sprintf(strbuff, "fd, realloc() failed, " + "errno %d, %s", our_errno(), strerror(our_errno())); + fprintf(stderr, "%s\n", strbuff); + } + else { + fd = tmpfd; + tmpfd = NULL; + } + + } + + } + + sprintf(strbuff, fmt, num_open.rlim_max); + fprintf(stderr, "%s file descriptors open\n", strbuff); + + /* free the chunk of memory we were reserving so that it + becomes becomes available to the test */ + + free(memchunk); + + /* close file descriptors unless instructed to keep them */ + if (!keep_open) { + close_file_descriptors(); + } + + return 0; +} + +int test(char *URL) +{ + CURLcode res; + CURL *curl; + + if(!strcmp(URL, "check")) { + /* used by the test script to ask if we can run this test or not */ + if(rlimit(FALSE)) { + fprintf(stdout, "rlimit problem: %s\n", msgbuff); + return 1; + } + return 0; /* sure, run this! */ + } + + if (rlimit(TRUE)) { + /* failure */ + return TEST_ERR_MAJOR_BAD; + } + + /* run the test with the bunch of open file descriptors + and close them all once the test is over */ + + if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { + fprintf(stderr, "curl_global_init() failed\n"); + close_file_descriptors(); + return TEST_ERR_MAJOR_BAD; + } + + if ((curl = curl_easy_init()) == NULL) { + fprintf(stderr, "curl_easy_init() failed\n"); + close_file_descriptors(); + curl_global_cleanup(); + return TEST_ERR_MAJOR_BAD; + } + + curl_easy_setopt(curl, CURLOPT_URL, URL); + curl_easy_setopt(curl, CURLOPT_HEADER, TRUE); + + res = curl_easy_perform(curl); + + close_file_descriptors(); + curl_easy_cleanup(curl); + curl_global_cleanup(); + + return (int)res; +} + +#else /* defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) */ + +int test(char *URL) +{ + (void)URL; + printf("system lacks necessary system function(s)"); + return 1; /* skip test */ +} + +#endif /* defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) */ |