libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

commit f9550a2c8dbf166c175e6c887feab065935d0a67
parent a9cd61a224e3696ae012a2f9b6f7faa90a07df93
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
Date:   Thu, 18 May 2023 16:15:43 +0300

test_client_put_stop: avoid stress-testing the OS

Diffstat:
Mconfigure.ac | 1+
Msrc/microhttpd/Makefile.am | 26++++++++++++++++++++++++++
Msrc/microhttpd/test_client_put_stop.c | 155++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
3 files changed, 118 insertions(+), 64 deletions(-)

diff --git a/configure.ac b/configure.ac @@ -1771,6 +1771,7 @@ AS_VAR_IF([use_heavy_tests], ["yes"], ] ) AM_CONDITIONAL([HEAVY_TESTS],[test "x$use_heavy_tests" = "xyes"]) +AM_CONDITIONAL([TESTS_STRESS_OS],[false]) AC_ARG_ENABLE([[poll]], [AS_HELP_STRING([[--enable-poll[=ARG]]], [enable poll support (yes, no, auto) [auto]])], diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am @@ -309,6 +309,17 @@ check_PROGRAMS += \ test_str_base64 endif + +if HEAVY_TESTS +if TESTS_STRESS_OS +check_PROGRAMS += \ + test_client_put_hard_close_stress_os \ + test_client_put_steps_hard_close_stress_os \ + test_client_put_chunked_steps_hard_close_stress_os +endif +endif + + TESTS = $(check_PROGRAMS) update-po-POTFILES.in: $(top_srcdir)/po/POTFILES.in @@ -564,6 +575,11 @@ test_client_put_hard_close_SOURCES = \ test_client_put_hard_close_LDADD = \ libmicrohttpd.la +test_client_put_hard_close_stress_os_SOURCES = \ + $(test_client_put_hard_close_SOURCES) +test_client_put_hard_close_stress_os_LDADD = \ + $(test_client_put_hard_close_LDADD) + test_client_put_steps_shutdown_SOURCES = \ test_client_put_stop.c test_client_put_steps_shutdown_LDADD = \ @@ -579,6 +595,11 @@ test_client_put_steps_hard_close_SOURCES = \ test_client_put_steps_hard_close_LDADD = \ libmicrohttpd.la +test_client_put_steps_hard_close_stress_os_SOURCES = \ + $(test_client_put_steps_hard_close_SOURCES) +test_client_put_steps_hard_close_stress_os_LDADD = \ + $(test_client_put_steps_hard_close_LDADD) + test_client_put_chunked_shutdown_SOURCES = \ test_client_put_stop.c test_client_put_chunked_shutdown_LDADD = \ @@ -609,6 +630,11 @@ test_client_put_chunked_steps_hard_close_SOURCES = \ test_client_put_chunked_steps_hard_close_LDADD = \ libmicrohttpd.la +test_client_put_chunked_steps_hard_close_stress_os_SOURCES = \ + $(test_client_put_chunked_steps_hard_close_SOURCES) +test_client_put_chunked_steps_hard_close_stress_os_LDADD = \ + $(test_client_put_chunked_steps_hard_close_LDADD) + test_set_panic_SOURCES = \ test_set_panic.c test_set_panic_LDADD = \ diff --git a/src/microhttpd/test_client_put_stop.c b/src/microhttpd/test_client_put_stop.c @@ -268,6 +268,7 @@ static uint16_t global_port; /**< MHD daemons listen port number */ static int use_shutdown; /**< Use shutdown at client side */ static int use_close; /**< Use socket close at client side */ static int use_hard_close; /**< Use socket close with RST at client side */ +static int use_stress_os; /**< Stress OS by RST before getting ACKs for sent packets */ static int by_step; /**< Send request byte-by-byte */ static int upl_chunked; /**< Use chunked encoding for request body */ @@ -277,83 +278,94 @@ static void test_global_init (void) { rate_limiter = 0; -#ifdef HAVE_SYSCTLBYNAME if (use_hard_close) { - int blck_hl; - size_t blck_hl_size = sizeof (blck_hl); - if (0 == sysctlbyname ("net.inet.tcp.blackhole", &blck_hl, &blck_hl_size, - NULL, 0)) +#ifdef HAVE_SYSCTLBYNAME + if (1) { - if (2 <= blck_hl) + int blck_hl; + size_t blck_hl_size = sizeof (blck_hl); + if (0 == sysctlbyname ("net.inet.tcp.blackhole", &blck_hl, &blck_hl_size, + NULL, 0)) { - fprintf (stderr, "'sysctl net.inet.tcp.blackhole = %d', test is " - "unreliable with this system setting, skipping.\n", blck_hl); - exit (77); + if (2 <= blck_hl) + { + fprintf (stderr, "'sysctl net.inet.tcp.blackhole = %d', test is " + "unreliable with this system setting, skipping.\n", blck_hl); + exit (77); + } + } + else + { + if (ENOENT != errno) + externalErrorExitDesc ("Cannot get 'net.inet.tcp.blackhole' value"); } } - else - { - if (ENOENT != errno) - externalErrorExitDesc ("Cannot get 'net.inet.tcp.blackhole' value"); - } - } #endif #if defined(HAVE_SYSCTL) && defined(CTL_NET) && defined(PF_INET) && \ - defined(IPPROTO_ICMP) && defined(ICMPCTL_ICMPLIM) - if (use_hard_close) - { - int mib[4]; - int limit; - size_t limit_size = sizeof(limit); - mib[0] = CTL_NET; - mib[1] = PF_INET; - mib[2] = IPPROTO_ICMP; - mib[3] = ICMPCTL_ICMPLIM; - if (0 != sysctl (mib, 4, &limit, &limit_size, NULL, 0)) - { - if (ENOENT == errno) - limit = 0; /* No such parameter (Darwin) */ - else - externalErrorExitDesc ("Cannot get RST rate limit value"); - } - else if (sizeof(limit) != limit_size) - externalErrorExitDesc ("Cannot get RST rate limit value"); - if (limit > 0) + defined(IPPROTO_ICMP) && defined(ICMPCTL_ICMPLIM) + if (1) { -#ifndef _MHD_HEAVY_TESTS - fprintf (stderr, "This system has limits on number of RST packet" - " per second (%d).\nThis test will be used only if configured " - "with '--enable-heavy-test'.\n", limit); - exit (77); -#else /* _MHD_HEAVY_TESTS */ - int test_limit; /**< Maximum number of checks per second */ - test_limit = limit - limit / 10; /* Add some space to not hit the limiter */ - test_limit /= 4; /* Assume that all four tests with 'hard_close' run in parallel */ - test_limit -= 5; /* Add some more space to not hit the limiter */ - test_limit /= 3; /* Use only one third of available limit */ - if (test_limit <= 0) + int mib[4]; + int limit; + size_t limit_size = sizeof(limit); + mib[0] = CTL_NET; + mib[1] = PF_INET; + mib[2] = IPPROTO_ICMP; + mib[3] = ICMPCTL_ICMPLIM; + if (0 != sysctl (mib, 4, &limit, &limit_size, NULL, 0)) { - fprintf (stderr, "System limit for 'net.inet.icmp.icmplim' is " - "too strict for this test (value: %d).\n", limit); - exit (77); + if (ENOENT == errno) + limit = 0; /* No such parameter (new Darwin versions) */ + else + externalErrorExitDesc ("Cannot get RST rate limit value"); } - if (verbose) + else if (sizeof(limit) != limit_size) + externalErrorExitDesc ("Cannot get RST rate limit value"); + if (limit > 0) { - printf ("Limiting number of checks to %d checks/second.\n", test_limit); - fflush (stdout); - } - rate_limiter = (unsigned int) test_limit; +#ifndef _MHD_HEAVY_TESTS + fprintf (stderr, "This system has limits on number of RST packet" + " per second (%d).\nThis test will be used only if configured " + "with '--enable-heavy-test'.\n", limit); + exit (77); +#else /* _MHD_HEAVY_TESTS */ + int test_limit; /**< Maximum number of checks per second */ + + if (use_stress_os) + { + fprintf (stderr, "This system has limits on number of RST packet" + " per second (%d).\n'_stress_os' is not possible.\n", limit); + exit (77); + } + test_limit = limit - limit / 10; /* Add some space to not hit the limiter */ + test_limit /= 4; /* Assume that all four tests with 'hard_close' run in parallel */ + test_limit -= 5; /* Add some more space to not hit the limiter */ + test_limit /= 3; /* Use only one third of available limit */ + if (test_limit <= 0) + { + fprintf (stderr, "System limit for 'net.inet.icmp.icmplim' is " + "too strict for this test (value: %d).\n", limit); + exit (77); + } + if (verbose) + { + printf ("Limiting number of checks to %d checks/second.\n", + test_limit); + fflush (stdout); + } + rate_limiter = (unsigned int) test_limit; #if ! defined(HAVE_USLEEP) && ! defined(HAVE_NANOSLEEP) && ! defined(_WIN32) - fprintf (stderr, "Sleep function is required for this test, " - "but not available on this system.\n"); - exit (77); + fprintf (stderr, "Sleep function is required for this test, " + "but not available on this system.\n"); + exit (77); #endif #endif /* _MHD_HEAVY_TESTS */ + } } - } #endif /* HAVE_SYSCTL && CTL_NET && PF_INET && IPPROTO_ICMP && ICMPCTL_ICMPLIM */ + } if (MHD_YES != MHD_is_feature_supported (MHD_FEATURE_AUTOSUPPRESS_SIGPIPE)) { #if defined(HAVE_SIGNAL_H) && defined(SIGPIPE) @@ -1523,12 +1535,24 @@ performQueryExternal (struct MHD_Daemon *d, struct _MHD_dumbClient *clnt) /* All request data has been sent. * Client will close the socket as the next step. */ if (full_req_recieved) - do_client = 1; /* All data has been received by the MHD */ - else if ((0 == rate_limiter) && some_data_recieved) { - /* No RST rate limiter, no need to avoid extra RST + /* All data has been received by the MHD */ + do_client = 1; /* Close the client socket */ + } + else if (some_data_recieved && + (! use_hard_close || ((0 == rate_limiter) && use_stress_os))) + { + /* No RST rate limiter or no "hard close", no need to avoid extra RST * and at least something was received by the MHD */ - do_client = 1; + /* In case of 'hard close' this can stress the OS, especially + * if 'by_step' is enabled as several ACKs (for delivered packets + * containing the request) from the server may arrive to the client + * when the client has closed port and may be reflected by several + * RSTs from the client side to the server side (when ACK received + * without active connection then RST packet should be sent). + * When listening socket receives RST packets, it may block + * the sender preventing the next connection. */ + do_client = 1; /* Proceed with the closure of the client socket */ } else { @@ -1536,7 +1560,7 @@ performQueryExternal (struct MHD_Daemon *d, struct _MHD_dumbClient *clnt) * before client closes connection to avoid RST for every ACK. * When rate limiter is not enabled, the MHD must receive at * least something before closing the connection. */ - do_client = 0; + do_client = 0; /* Do not close the client socket yet */ } } @@ -2074,6 +2098,7 @@ main (int argc, char *const *argv) use_shutdown = has_in_name (argv[0], "_shutdown") ? 1 : 0; use_close = has_in_name (argv[0], "_close") ? 1 : 0; use_hard_close = has_in_name (argv[0], "_hard_close") ? 1 : 0; + use_stress_os = has_in_name (argv[0], "_stress_os") ? 1 : 0; by_step = has_in_name (argv[0], "_steps") ? 1 : 0; upl_chunked = has_in_name (argv[0], "_chunked") ? 1 : 0; #ifndef SO_LINGER @@ -2089,6 +2114,8 @@ main (int argc, char *const *argv) has_param (argc, argv, "--quiet") || has_param (argc, argv, "-s") || has_param (argc, argv, "--silent")); + if (use_stress_os && ! use_hard_close) + return 99; test_global_init ();