Re: [PATCH BlueZ] tools/iso-tester: add tests for socket shutdown with linger enabled
Luiz Augusto von Dentz <[email protected]>
| Newsgroups | org.kernel.vger.linux-bluetooth |
|---|---|
| Message-ID | <CABBYNZLyajk6bry4Wnr5DScz+KMVBQZ5wpOX51AnxYir6h5bYw@mail.gmail.com> |
Hi Pauli, On Tue, Jul 21, 2026 at 5:20 AM Pauli Virtanen <[email protected]> wrote: > > 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; I don't think this is a good idea, most of our userspace code isn't thread-safe, so I'd prefer we keep it that way and perhaps handle this with some async I/O or something else. > }; > > 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 > > -- Luiz Augusto von Dentz