[PATCH BlueZ] tools/iso-tester: add tests for socket shutdown with linger enabled

Pauli Virtanen <[email protected]>
Newsgroups org.kernel.vger.linux-bluetooth
Message-ID <f81384d367ad95cbe74338eba688daa46b379feb.1784624911.git.pav@iki.fi>
Add tests with SO_LINGER enabled, to test kernel sock transitions
properly to BT_CLOSED on shutdown.

Unlike L2CAP, ISO sockets don't have a feature to send POLLHUP only
after HCI Disconnect is received, so only SO_LINGER can be used to test
the sequence is shutdown -> Disconnect, HUP -> release, and not
shutdown -> HUP -> release -> Disconnect.

Add tests:

ISO Defer Linger - Success
ISO Connect Linger - Success
---
 tools/iso-tester.c | 68 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 67 insertions(+), 1 deletion(-)

diff --git a/tools/iso-tester.c b/tools/iso-tester.c
index fe27eaaf3..a792a804b 100644
--- a/tools/iso-tester.c
+++ b/tools/iso-tester.c
@@ -478,6 +478,7 @@ struct test_data {
 	bool suspending;
 	struct tx_tstamp_data tx_ts;
 	int seqnum;
+	GThread *thread;
 };
 
 struct iso_client_data {
@@ -522,6 +523,9 @@ struct iso_client_data {
 	 * Used for testing TX timestamping OPT_ID.
 	 */
 	unsigned int repeat_send;
+
+	/* Whether to enable SO_LINGER (for test_connect_wait_close) */
+	bool so_linger;
 };
 
 typedef bool (*iso_defer_accept_t)(struct test_data *data, GIOChannel *io,
@@ -717,6 +721,11 @@ static void test_post_teardown(const void *test_data)
 
 	hciemu_unref(data->hciemu);
 	data->hciemu = NULL;
+
+	if (data->thread) {
+		g_thread_unref(data->thread);
+		data->thread = NULL;
+	}
 }
 
 static void test_data_free(void *test_data)
@@ -1352,6 +1361,19 @@ static const struct iso_client_data connect_ac_1_2_cig_1_2 = {
 	.mconn = true,
 };
 
+static const struct iso_client_data linger_16_2_1 = {
+	.qos = QOS_16_2_1,
+	.expect_err = 0,
+	.so_linger = true,
+};
+
+static const struct iso_client_data linger_defer_16_2_1 = {
+	.qos = QOS_16_2_1,
+	.expect_err = 0,
+	.defer = true,
+	.so_linger = true,
+};
+
 static const struct iso_client_data bcast_48_1_g = {
 	.qos = QOS_OUT_48_1_g,
 	.expect_err = 0,
@@ -3679,6 +3701,19 @@ static void test_connect2_busy(const void *test_data)
 	setup_connect(data, 0, iso_connect_cb_busy);
 }
 
+static gpointer shutdown_sk_thread_cb(gpointer data)
+{
+	int sk = PTR_TO_UINT(data);
+	struct timespec start, end;
+
+	clock_gettime(CLOCK_MONOTONIC, &start);
+	shutdown(sk, SHUT_RDWR);
+	clock_gettime(CLOCK_MONOTONIC, &end);
+
+	/* Completed before linger timeout? */
+	return UINT_TO_PTR(TS_NSEC(&end) - TS_NSEC(&start) < SEC_NSEC(2));
+}
+
 static gboolean iso_connect_close_cb(GIOChannel *io, GIOCondition cond,
 							gpointer user_data)
 {
@@ -3688,6 +3723,13 @@ static gboolean iso_connect_close_cb(GIOChannel *io, GIOCondition cond,
 
 	tester_print("Disconnected");
 
+	if (data->thread) {
+		/* Wait for shutdown() to complete, for linger enabled */
+		if (!g_thread_join(data->thread))
+			tester_test_failed();
+		data->thread = NULL;
+	}
+
 	--data->step;
 	if (!data->step)
 		tester_test_passed();
@@ -3737,16 +3779,34 @@ static gboolean iso_connect_wait_close_cb(GIOChannel *io, GIOCondition cond,
 							gpointer user_data)
 {
 	struct test_data *data = tester_get_data();
+	const struct iso_client_data *isodata = data->test_data;
 	int sk;
 
 	tester_print("Connected");
 
 	sk = g_io_channel_unix_get_fd(io);
 
+	if (isodata->so_linger) {
+		struct linger val = { .l_onoff = 1, .l_linger = 2 };
+
+		if (setsockopt(sk, SOL_SOCKET, SO_LINGER, &val, sizeof(val))) {
+			tester_warn("Can't set socket option : %s (%d)",
+							strerror(errno), errno);
+			tester_test_failed();
+			return FALSE;
+		}
+	}
+
 	data->io_id[0] = g_io_add_watch(io, G_IO_HUP, iso_connect_close_cb,
 									data);
 
-	shutdown(sk, SHUT_RDWR);
+	if (!isodata->so_linger)
+		shutdown(sk, SHUT_RDWR);
+	else {
+		/* With linger shutdown() blocks, so run in separate thread */
+		data->thread = g_thread_new("close_sk", shutdown_sk_thread_cb,
+							UINT_TO_PTR(sk));
+	}
 
 	return FALSE;
 }
@@ -4160,6 +4220,12 @@ int main(int argc, char *argv[])
 	test_iso("ISO Connect Wait Close - Success", &connect_16_2_1,
 					setup_powered, test_connect_wait_close);
 
+	test_iso("ISO Defer Linger - Success", &linger_16_2_1,
+					setup_powered, test_connect_wait_close);
+
+	test_iso("ISO Connect Linger - Success", &linger_defer_16_2_1,
+					setup_powered, test_connect_wait_close);
+
 	test_iso("ISO Connect Suspend - Success", &connect_suspend,
 							setup_powered,
 							test_connect_suspend);
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.