|
26 | 26 | #include "util-internal.h"
|
27 | 27 |
|
28 | 28 | #ifdef _WIN32
|
| 29 | +#ifdef EVENT__HAVE_AFUNIX_H |
| 30 | +#include <afunix.h> |
| 31 | +#endif |
| 32 | +#include <io.h> |
29 | 33 | #include <winsock2.h>
|
30 | 34 | #include <windows.h>
|
| 35 | +#include <winerror.h> |
31 | 36 | #endif
|
32 | 37 |
|
33 | 38 | #include <sys/types.h>
|
|
38 | 43 | # ifdef _XOPEN_SOURCE_EXTENDED
|
39 | 44 | # include <arpa/inet.h>
|
40 | 45 | # endif
|
| 46 | +#ifdef EVENT__HAVE_SYS_UN_H |
| 47 | +#include <sys/un.h> |
| 48 | +#endif |
41 | 49 | #include <unistd.h>
|
42 | 50 | #endif
|
43 | 51 | #ifdef EVENT__HAVE_SYS_RESOURCE_H
|
44 | 52 | #include <sys/resource.h>
|
45 | 53 | #endif
|
46 | 54 |
|
47 | 55 | #include <string.h>
|
| 56 | +#include <stdio.h> |
| 57 | +#include <stdlib.h> |
48 | 58 |
|
49 | 59 | #include "event2/listener.h"
|
50 | 60 | #include "event2/event.h"
|
|
54 | 64 | #include "regress_thread.h"
|
55 | 65 | #endif
|
56 | 66 |
|
57 |
| - |
| 67 | +#include "strlcpy-internal.h" |
58 | 68 | #include "regress.h"
|
59 | 69 | #include "tinytest.h"
|
60 | 70 | #include "tinytest_macros.h"
|
61 | 71 |
|
| 72 | +#ifdef _WIN32 |
| 73 | +#define unlink _unlink |
| 74 | +#define close _close |
| 75 | +#endif |
| 76 | + |
62 | 77 | static void
|
63 | 78 | acceptcb(struct evconnlistener *listener, evutil_socket_t fd,
|
64 | 79 | struct sockaddr *addr, int socklen, void *arg)
|
@@ -430,6 +445,118 @@ regress_listener_disable_in_thread_error(void *arg)
|
430 | 445 | }
|
431 | 446 | #endif
|
432 | 447 |
|
| 448 | +#ifdef EVENT__HAVE_STRUCT_SOCKADDR_UN |
| 449 | + |
| 450 | +#ifdef _WIN32 |
| 451 | +static int |
| 452 | +is_unicode_temp_path() |
| 453 | +{ |
| 454 | + DWORD n; |
| 455 | + WCHAR short_temp_path[MAX_PATH]; |
| 456 | + WCHAR long_temp_path[MAX_PATH]; |
| 457 | + n = GetTempPathW(MAX_PATH, short_temp_path); |
| 458 | + if (n == 0 || n > MAX_PATH) |
| 459 | + return 1; |
| 460 | + n = GetLongPathNameW(short_temp_path, long_temp_path, MAX_PATH); |
| 461 | + if (n == 0 || n > MAX_PATH) |
| 462 | + return 1; |
| 463 | + |
| 464 | + // If it contains valid wide characters, it is considered Unicode. |
| 465 | + for (const wchar_t* p = long_temp_path; *p != L'\0'; ++p) { |
| 466 | + if (*p > 127) { // Non-ASCII character |
| 467 | + return 1; // It's a Unicode path |
| 468 | + } |
| 469 | + } |
| 470 | + return 0; // No non-ASCII characters found, may not be Unicode |
| 471 | +} |
| 472 | +#endif |
| 473 | + |
| 474 | +static void |
| 475 | +empty_listener_cb(struct evconnlistener *listener, evutil_socket_t fd, |
| 476 | + struct sockaddr *sa, int socklen, void *user_data) |
| 477 | +{ |
| 478 | + printf("Empty listener, do nothing about it!\n"); |
| 479 | +} |
| 480 | + |
| 481 | +static void |
| 482 | +regress_listener_reuseport_on_unix_socket(void *arg) |
| 483 | +{ |
| 484 | + struct basic_test_data *data = arg; |
| 485 | + struct event_base *base = data->base; |
| 486 | + struct evconnlistener *listener = NULL; |
| 487 | + char *socket_path = NULL; |
| 488 | + int truncated_temp_file = 0; |
| 489 | + struct sockaddr_un addr; |
| 490 | + int tempfd; |
| 491 | + |
| 492 | + tempfd = regress_make_tmpfile("", 0, &socket_path); |
| 493 | + /* On Windows, if TMP environment variable is corrupted, we may not be |
| 494 | + * able create temporary file, just skip it */ |
| 495 | + if (tempfd < 0) |
| 496 | + tt_skip(); |
| 497 | + TT_BLATHER(("Temporary socket path: %s, fd: %i", socket_path, tempfd)); |
| 498 | + |
| 499 | +#if defined(_WIN32) && defined(EVENT__HAVE_AFUNIX_H) |
| 500 | + if (evutil_check_working_afunix_() == 0) |
| 501 | + /* AF_UNIX is not available on the current Windows platform, |
| 502 | + * just skip this test. */ |
| 503 | + tt_skip(); |
| 504 | +#endif |
| 505 | + |
| 506 | + /* close fd to avoid leaks, since we only need a temporary file path |
| 507 | + * for bind() to create a socket file. */ |
| 508 | + close(tempfd); |
| 509 | + /* For security reason, we must delete any existing sockets in the filesystem. |
| 510 | + * Besides, we will get EADDRINUSE error if the socket file already exists. */ |
| 511 | + unlink(socket_path); |
| 512 | + |
| 513 | + memset(&addr, 0, sizeof(addr)); |
| 514 | + addr.sun_family = AF_UNIX; |
| 515 | + if (strlcpy(addr.sun_path, socket_path, sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) |
| 516 | + /* The temporary path exceeds the system limit, we may need to adjust some subsequent |
| 517 | + * assertions accordingly to ensure the success of this test. */ |
| 518 | + truncated_temp_file = 1; |
| 519 | + |
| 520 | + listener = evconnlistener_new_bind(base, empty_listener_cb, (void *)base, |
| 521 | + LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1, |
| 522 | + (struct sockaddr*)&addr, sizeof(addr)); |
| 523 | + tt_assert_msg(listener == NULL, "AF_UNIX listener shouldn't use SO_REUSEADDR!"); |
| 524 | + |
| 525 | + listener = evconnlistener_new_bind(base, empty_listener_cb, (void *)base, |
| 526 | + LEV_OPT_REUSEABLE_PORT|LEV_OPT_CLOSE_ON_FREE, -1, |
| 527 | + (struct sockaddr*)&addr, sizeof(addr)); |
| 528 | + tt_assert_msg(listener == NULL, "AF_UNIX listener shouldn't use SO_REUSEPORT!"); |
| 529 | + |
| 530 | + /* Create a AF_UNIX listener without reusing address or port. */ |
| 531 | + listener = evconnlistener_new_bind(base, empty_listener_cb, (void *)base, |
| 532 | + LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_CLOSE_ON_FREE, -1, |
| 533 | + (struct sockaddr*)&addr, sizeof(addr)); |
| 534 | + if (truncated_temp_file) { |
| 535 | + tt_assert_msg(listener == NULL, "Should not create a AF_UNIX listener with truncated socket path!"); |
| 536 | + } else { |
| 537 | +#ifdef _WIN32 |
| 538 | + if (listener == NULL && WSAENETDOWN == EVUTIL_SOCKET_ERROR() && is_unicode_temp_path()) |
| 539 | + /* TODO(panjf2000): this error kept happening on the GitHub Runner of |
| 540 | + * (windows-latest, UNOCODE_TEMPORARY_DIRECTORY) disturbingly and the |
| 541 | + * root cause still remains unknown. |
| 542 | + * Thus, we skip this for now, but try to dive deep and figure out the |
| 543 | + * root cause later. */ |
| 544 | + tt_skip(); |
| 545 | +#endif |
| 546 | + tt_assert_msg(listener, "Could not create a AF_UNIX listener normally!"); |
| 547 | + } |
| 548 | + |
| 549 | +end: |
| 550 | + if (socket_path) { |
| 551 | + unlink(socket_path); |
| 552 | + free(socket_path); |
| 553 | + } |
| 554 | + if (listener) |
| 555 | + evconnlistener_free(listener); |
| 556 | +} |
| 557 | + |
| 558 | +#endif |
| 559 | + |
433 | 560 | struct testcase_t listener_testcases[] = {
|
434 | 561 |
|
435 | 562 | { "randport", regress_pick_a_port, TT_FORK|TT_NEED_BASE,
|
@@ -468,6 +595,12 @@ struct testcase_t listener_testcases[] = {
|
468 | 595 | &basic_setup, NULL, },
|
469 | 596 | #endif
|
470 | 597 |
|
| 598 | +#ifdef EVENT__HAVE_STRUCT_SOCKADDR_UN |
| 599 | + { "reuseport_on_unix_socket", regress_listener_reuseport_on_unix_socket, |
| 600 | + TT_FORK|TT_NEED_BASE, |
| 601 | + &basic_setup, NULL, }, |
| 602 | +#endif |
| 603 | + |
471 | 604 | END_OF_TESTCASES,
|
472 | 605 | };
|
473 | 606 |
|
|
0 commit comments