aboutgitcodebugslistschat
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2024-07-17 14:52:22 +1000
committerStefano Brivio <sbrivio@redhat.com>2024-07-17 15:30:14 +0200
commit01e5611ec3912f02fb683305db8913f8eca15fee (patch)
treeee87ee8d29202434decff4f70ba07a2691a74e44
parent66a02c9f7cd5c7a643d9ac5dad5a7209a6e1c467 (diff)
downloadpasst-01e5611ec3912f02fb683305db8913f8eca15fee.tar
passt-01e5611ec3912f02fb683305db8913f8eca15fee.tar.gz
passt-01e5611ec3912f02fb683305db8913f8eca15fee.tar.bz2
passt-01e5611ec3912f02fb683305db8913f8eca15fee.tar.lz
passt-01e5611ec3912f02fb683305db8913f8eca15fee.tar.xz
passt-01e5611ec3912f02fb683305db8913f8eca15fee.tar.zst
passt-01e5611ec3912f02fb683305db8913f8eca15fee.zip
doc: Test behaviour of closing duplicate UDP sockets
To simplify lifetime management of "listening" UDP sockets, UDP flow support needs to duplicate existing bound sockets. Those duplicates will be close()d when their corresponding flow expires, but we expect the original to still receive datagrams as always. That is, we expect the close() on the duplicate to remove the duplicated fd, but not to close the underlying UDP socket. Add a test program to doc/platform-requirements to verify this requirement. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-rw-r--r--doc/platform-requirements/.gitignore1
-rw-r--r--doc/platform-requirements/Makefile4
-rw-r--r--doc/platform-requirements/udp-close-dup.c105
3 files changed, 108 insertions, 2 deletions
diff --git a/doc/platform-requirements/.gitignore b/doc/platform-requirements/.gitignore
index 555031d..3b5a10a 100644
--- a/doc/platform-requirements/.gitignore
+++ b/doc/platform-requirements/.gitignore
@@ -1,2 +1,3 @@
/reuseaddr-priority
/recv-zero
+/udp-close-dup
diff --git a/doc/platform-requirements/Makefile b/doc/platform-requirements/Makefile
index 82aaac2..6a7d374 100644
--- a/doc/platform-requirements/Makefile
+++ b/doc/platform-requirements/Makefile
@@ -3,8 +3,8 @@
# Copyright Red Hat
# Author: David Gibson <david@gibson.dropbear.id.au>
-TARGETS = reuseaddr-priority recv-zero
-SRCS = reuseaddr-priority.c recv-zero.c
+TARGETS = reuseaddr-priority recv-zero udp-close-dup
+SRCS = reuseaddr-priority.c recv-zero.c udp-close-dup.c
CFLAGS = -Wall
all: cppcheck clang-tidy $(TARGETS:%=check-%)
diff --git a/doc/platform-requirements/udp-close-dup.c b/doc/platform-requirements/udp-close-dup.c
new file mode 100644
index 0000000..99060fc
--- /dev/null
+++ b/doc/platform-requirements/udp-close-dup.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/* udp-close-dup.c
+ *
+ * Verify that closing one dup() of a UDP socket won't stop other dups from
+ * receiving packets.
+ *
+ * Copyright Red Hat
+ * Author: David Gibson <david@gibson.dropbear.id.au>
+ */
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "common.h"
+
+#define DSTPORT 13257U
+
+/* 127.0.0.1:DSTPORT */
+static const struct sockaddr_in lo_dst = SOCKADDR_INIT(INADDR_LOOPBACK, DSTPORT);
+
+enum dup_method {
+ DUP_DUP,
+ DUP_FCNTL,
+ NUM_METHODS,
+};
+
+static void test_close_dup(enum dup_method method)
+{
+ long token;
+ int s1, s2, send_s;
+ ssize_t rc;
+
+ s1 = sock_reuseaddr();
+ if (bind(s1, (struct sockaddr *)&lo_dst, sizeof(lo_dst)) < 0)
+ die("bind(): %s\n", strerror(errno));
+
+ send_s = sock_reuseaddr();
+ if (connect(send_s, (struct sockaddr *)&lo_dst, sizeof(lo_dst)) < 0)
+ die("connect(): %s\n", strerror(errno));
+
+ /* Receive before duplicating */
+ token = random();
+ send_token(send_s, token);
+ recv_token(s1, token);
+
+ switch (method) {
+ case DUP_DUP:
+ /* NOLINTNEXTLINE(android-cloexec-dup) */
+ s2 = dup(s1);
+ if (s2 < 0)
+ die("dup(): %s\n", strerror(errno));
+ break;
+ case DUP_FCNTL:
+ s2 = fcntl(s1, F_DUPFD_CLOEXEC, 0);
+ if (s2 < 0)
+ die("F_DUPFD_CLOEXEC: %s\n", strerror(errno));
+ break;
+ default:
+ die("Bad method\n");
+ }
+
+ /* Receive via original handle */
+ token = random();
+ send_token(send_s, token);
+ recv_token(s1, token);
+
+ /* Receive via duplicated handle */
+ token = random();
+ send_token(send_s, token);
+ recv_token(s2, token);
+
+ /* Close duplicate */
+ rc = close(s2);
+ if (rc < 0)
+ die("close() dup: %s\n", strerror(errno));
+
+ /* Receive after closing duplicate */
+ token = random();
+ send_token(send_s, token);
+ recv_token(s1, token);
+}
+
+int main(int argc, char *argv[])
+{
+ enum dup_method method;
+
+ (void)argc;
+ (void)argv;
+
+ for (method = 0; method < NUM_METHODS; method++)
+ test_close_dup(method);
+
+ printf("Closing dup()ed UDP sockets seems to work as expected\n");
+
+ exit(0);
+}