diff options
Diffstat (limited to 'src/microhttpd/test_client_put_stop.c')
-rw-r--r-- | src/microhttpd/test_client_put_stop.c | 155 |
1 files changed, 91 insertions, 64 deletions
diff --git a/src/microhttpd/test_client_put_stop.c b/src/microhttpd/test_client_put_stop.c index eb481567..16a09d65 100644 --- 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 */ | |||
268 | static int use_shutdown; /**< Use shutdown at client side */ | 268 | static int use_shutdown; /**< Use shutdown at client side */ |
269 | static int use_close; /**< Use socket close at client side */ | 269 | static int use_close; /**< Use socket close at client side */ |
270 | static int use_hard_close; /**< Use socket close with RST at client side */ | 270 | static int use_hard_close; /**< Use socket close with RST at client side */ |
271 | static int use_stress_os; /**< Stress OS by RST before getting ACKs for sent packets */ | ||
271 | static int by_step; /**< Send request byte-by-byte */ | 272 | static int by_step; /**< Send request byte-by-byte */ |
272 | static int upl_chunked; /**< Use chunked encoding for request body */ | 273 | static int upl_chunked; /**< Use chunked encoding for request body */ |
273 | 274 | ||
@@ -277,83 +278,94 @@ static void | |||
277 | test_global_init (void) | 278 | test_global_init (void) |
278 | { | 279 | { |
279 | rate_limiter = 0; | 280 | rate_limiter = 0; |
280 | #ifdef HAVE_SYSCTLBYNAME | ||
281 | if (use_hard_close) | 281 | if (use_hard_close) |
282 | { | 282 | { |
283 | int blck_hl; | 283 | #ifdef HAVE_SYSCTLBYNAME |
284 | size_t blck_hl_size = sizeof (blck_hl); | 284 | if (1) |
285 | if (0 == sysctlbyname ("net.inet.tcp.blackhole", &blck_hl, &blck_hl_size, | ||
286 | NULL, 0)) | ||
287 | { | 285 | { |
288 | if (2 <= blck_hl) | 286 | int blck_hl; |
287 | size_t blck_hl_size = sizeof (blck_hl); | ||
288 | if (0 == sysctlbyname ("net.inet.tcp.blackhole", &blck_hl, &blck_hl_size, | ||
289 | NULL, 0)) | ||
289 | { | 290 | { |
290 | fprintf (stderr, "'sysctl net.inet.tcp.blackhole = %d', test is " | 291 | if (2 <= blck_hl) |
291 | "unreliable with this system setting, skipping.\n", blck_hl); | 292 | { |
292 | exit (77); | 293 | fprintf (stderr, "'sysctl net.inet.tcp.blackhole = %d', test is " |
294 | "unreliable with this system setting, skipping.\n", blck_hl); | ||
295 | exit (77); | ||
296 | } | ||
297 | } | ||
298 | else | ||
299 | { | ||
300 | if (ENOENT != errno) | ||
301 | externalErrorExitDesc ("Cannot get 'net.inet.tcp.blackhole' value"); | ||
293 | } | 302 | } |
294 | } | 303 | } |
295 | else | ||
296 | { | ||
297 | if (ENOENT != errno) | ||
298 | externalErrorExitDesc ("Cannot get 'net.inet.tcp.blackhole' value"); | ||
299 | } | ||
300 | } | ||
301 | #endif | 304 | #endif |
302 | #if defined(HAVE_SYSCTL) && defined(CTL_NET) && defined(PF_INET) && \ | 305 | #if defined(HAVE_SYSCTL) && defined(CTL_NET) && defined(PF_INET) && \ |
303 | defined(IPPROTO_ICMP) && defined(ICMPCTL_ICMPLIM) | 306 | defined(IPPROTO_ICMP) && defined(ICMPCTL_ICMPLIM) |
304 | if (use_hard_close) | 307 | if (1) |
305 | { | ||
306 | int mib[4]; | ||
307 | int limit; | ||
308 | size_t limit_size = sizeof(limit); | ||
309 | mib[0] = CTL_NET; | ||
310 | mib[1] = PF_INET; | ||
311 | mib[2] = IPPROTO_ICMP; | ||
312 | mib[3] = ICMPCTL_ICMPLIM; | ||
313 | if (0 != sysctl (mib, 4, &limit, &limit_size, NULL, 0)) | ||
314 | { | ||
315 | if (ENOENT == errno) | ||
316 | limit = 0; /* No such parameter (Darwin) */ | ||
317 | else | ||
318 | externalErrorExitDesc ("Cannot get RST rate limit value"); | ||
319 | } | ||
320 | else if (sizeof(limit) != limit_size) | ||
321 | externalErrorExitDesc ("Cannot get RST rate limit value"); | ||
322 | if (limit > 0) | ||
323 | { | 308 | { |
324 | #ifndef _MHD_HEAVY_TESTS | 309 | int mib[4]; |
325 | fprintf (stderr, "This system has limits on number of RST packet" | 310 | int limit; |
326 | " per second (%d).\nThis test will be used only if configured " | 311 | size_t limit_size = sizeof(limit); |
327 | "with '--enable-heavy-test'.\n", limit); | 312 | mib[0] = CTL_NET; |
328 | exit (77); | 313 | mib[1] = PF_INET; |
329 | #else /* _MHD_HEAVY_TESTS */ | 314 | mib[2] = IPPROTO_ICMP; |
330 | int test_limit; /**< Maximum number of checks per second */ | 315 | mib[3] = ICMPCTL_ICMPLIM; |
331 | test_limit = limit - limit / 10; /* Add some space to not hit the limiter */ | 316 | if (0 != sysctl (mib, 4, &limit, &limit_size, NULL, 0)) |
332 | test_limit /= 4; /* Assume that all four tests with 'hard_close' run in parallel */ | ||
333 | test_limit -= 5; /* Add some more space to not hit the limiter */ | ||
334 | test_limit /= 3; /* Use only one third of available limit */ | ||
335 | if (test_limit <= 0) | ||
336 | { | 317 | { |
337 | fprintf (stderr, "System limit for 'net.inet.icmp.icmplim' is " | 318 | if (ENOENT == errno) |
338 | "too strict for this test (value: %d).\n", limit); | 319 | limit = 0; /* No such parameter (new Darwin versions) */ |
339 | exit (77); | 320 | else |
321 | externalErrorExitDesc ("Cannot get RST rate limit value"); | ||
340 | } | 322 | } |
341 | if (verbose) | 323 | else if (sizeof(limit) != limit_size) |
324 | externalErrorExitDesc ("Cannot get RST rate limit value"); | ||
325 | if (limit > 0) | ||
342 | { | 326 | { |
343 | printf ("Limiting number of checks to %d checks/second.\n", test_limit); | 327 | #ifndef _MHD_HEAVY_TESTS |
344 | fflush (stdout); | 328 | fprintf (stderr, "This system has limits on number of RST packet" |
345 | } | 329 | " per second (%d).\nThis test will be used only if configured " |
346 | rate_limiter = (unsigned int) test_limit; | 330 | "with '--enable-heavy-test'.\n", limit); |
331 | exit (77); | ||
332 | #else /* _MHD_HEAVY_TESTS */ | ||
333 | int test_limit; /**< Maximum number of checks per second */ | ||
334 | |||
335 | if (use_stress_os) | ||
336 | { | ||
337 | fprintf (stderr, "This system has limits on number of RST packet" | ||
338 | " per second (%d).\n'_stress_os' is not possible.\n", limit); | ||
339 | exit (77); | ||
340 | } | ||
341 | test_limit = limit - limit / 10; /* Add some space to not hit the limiter */ | ||
342 | test_limit /= 4; /* Assume that all four tests with 'hard_close' run in parallel */ | ||
343 | test_limit -= 5; /* Add some more space to not hit the limiter */ | ||
344 | test_limit /= 3; /* Use only one third of available limit */ | ||
345 | if (test_limit <= 0) | ||
346 | { | ||
347 | fprintf (stderr, "System limit for 'net.inet.icmp.icmplim' is " | ||
348 | "too strict for this test (value: %d).\n", limit); | ||
349 | exit (77); | ||
350 | } | ||
351 | if (verbose) | ||
352 | { | ||
353 | printf ("Limiting number of checks to %d checks/second.\n", | ||
354 | test_limit); | ||
355 | fflush (stdout); | ||
356 | } | ||
357 | rate_limiter = (unsigned int) test_limit; | ||
347 | #if ! defined(HAVE_USLEEP) && ! defined(HAVE_NANOSLEEP) && ! defined(_WIN32) | 358 | #if ! defined(HAVE_USLEEP) && ! defined(HAVE_NANOSLEEP) && ! defined(_WIN32) |
348 | fprintf (stderr, "Sleep function is required for this test, " | 359 | fprintf (stderr, "Sleep function is required for this test, " |
349 | "but not available on this system.\n"); | 360 | "but not available on this system.\n"); |
350 | exit (77); | 361 | exit (77); |
351 | #endif | 362 | #endif |
352 | #endif /* _MHD_HEAVY_TESTS */ | 363 | #endif /* _MHD_HEAVY_TESTS */ |
364 | } | ||
353 | } | 365 | } |
354 | } | ||
355 | #endif /* HAVE_SYSCTL && CTL_NET && PF_INET && | 366 | #endif /* HAVE_SYSCTL && CTL_NET && PF_INET && |
356 | IPPROTO_ICMP && ICMPCTL_ICMPLIM */ | 367 | IPPROTO_ICMP && ICMPCTL_ICMPLIM */ |
368 | } | ||
357 | if (MHD_YES != MHD_is_feature_supported (MHD_FEATURE_AUTOSUPPRESS_SIGPIPE)) | 369 | if (MHD_YES != MHD_is_feature_supported (MHD_FEATURE_AUTOSUPPRESS_SIGPIPE)) |
358 | { | 370 | { |
359 | #if defined(HAVE_SIGNAL_H) && defined(SIGPIPE) | 371 | #if defined(HAVE_SIGNAL_H) && defined(SIGPIPE) |
@@ -1523,12 +1535,24 @@ performQueryExternal (struct MHD_Daemon *d, struct _MHD_dumbClient *clnt) | |||
1523 | /* All request data has been sent. | 1535 | /* All request data has been sent. |
1524 | * Client will close the socket as the next step. */ | 1536 | * Client will close the socket as the next step. */ |
1525 | if (full_req_recieved) | 1537 | if (full_req_recieved) |
1526 | do_client = 1; /* All data has been received by the MHD */ | ||
1527 | else if ((0 == rate_limiter) && some_data_recieved) | ||
1528 | { | 1538 | { |
1529 | /* No RST rate limiter, no need to avoid extra RST | 1539 | /* All data has been received by the MHD */ |
1540 | do_client = 1; /* Close the client socket */ | ||
1541 | } | ||
1542 | else if (some_data_recieved && | ||
1543 | (! use_hard_close || ((0 == rate_limiter) && use_stress_os))) | ||
1544 | { | ||
1545 | /* No RST rate limiter or no "hard close", no need to avoid extra RST | ||
1530 | * and at least something was received by the MHD */ | 1546 | * and at least something was received by the MHD */ |
1531 | do_client = 1; | 1547 | /* In case of 'hard close' this can stress the OS, especially |
1548 | * if 'by_step' is enabled as several ACKs (for delivered packets | ||
1549 | * containing the request) from the server may arrive to the client | ||
1550 | * when the client has closed port and may be reflected by several | ||
1551 | * RSTs from the client side to the server side (when ACK received | ||
1552 | * without active connection then RST packet should be sent). | ||
1553 | * When listening socket receives RST packets, it may block | ||
1554 | * the sender preventing the next connection. */ | ||
1555 | do_client = 1; /* Proceed with the closure of the client socket */ | ||
1532 | } | 1556 | } |
1533 | else | 1557 | else |
1534 | { | 1558 | { |
@@ -1536,7 +1560,7 @@ performQueryExternal (struct MHD_Daemon *d, struct _MHD_dumbClient *clnt) | |||
1536 | * before client closes connection to avoid RST for every ACK. | 1560 | * before client closes connection to avoid RST for every ACK. |
1537 | * When rate limiter is not enabled, the MHD must receive at | 1561 | * When rate limiter is not enabled, the MHD must receive at |
1538 | * least something before closing the connection. */ | 1562 | * least something before closing the connection. */ |
1539 | do_client = 0; | 1563 | do_client = 0; /* Do not close the client socket yet */ |
1540 | } | 1564 | } |
1541 | } | 1565 | } |
1542 | 1566 | ||
@@ -2074,6 +2098,7 @@ main (int argc, char *const *argv) | |||
2074 | use_shutdown = has_in_name (argv[0], "_shutdown") ? 1 : 0; | 2098 | use_shutdown = has_in_name (argv[0], "_shutdown") ? 1 : 0; |
2075 | use_close = has_in_name (argv[0], "_close") ? 1 : 0; | 2099 | use_close = has_in_name (argv[0], "_close") ? 1 : 0; |
2076 | use_hard_close = has_in_name (argv[0], "_hard_close") ? 1 : 0; | 2100 | use_hard_close = has_in_name (argv[0], "_hard_close") ? 1 : 0; |
2101 | use_stress_os = has_in_name (argv[0], "_stress_os") ? 1 : 0; | ||
2077 | by_step = has_in_name (argv[0], "_steps") ? 1 : 0; | 2102 | by_step = has_in_name (argv[0], "_steps") ? 1 : 0; |
2078 | upl_chunked = has_in_name (argv[0], "_chunked") ? 1 : 0; | 2103 | upl_chunked = has_in_name (argv[0], "_chunked") ? 1 : 0; |
2079 | #ifndef SO_LINGER | 2104 | #ifndef SO_LINGER |
@@ -2089,6 +2114,8 @@ main (int argc, char *const *argv) | |||
2089 | has_param (argc, argv, "--quiet") || | 2114 | has_param (argc, argv, "--quiet") || |
2090 | has_param (argc, argv, "-s") || | 2115 | has_param (argc, argv, "-s") || |
2091 | has_param (argc, argv, "--silent")); | 2116 | has_param (argc, argv, "--silent")); |
2117 | if (use_stress_os && ! use_hard_close) | ||
2118 | return 99; | ||
2092 | 2119 | ||
2093 | test_global_init (); | 2120 | test_global_init (); |
2094 | 2121 | ||