gsocket: Handle cancellation of accept() in non-blocking mode

Currently, if `g_socket_accept()` is called with a cancelled cancellable
and the socket is in non-blocking mode, `G_IO_ERROR_CANCELLED` is not
returned, because the cancellable is only checked in the call to
`g_socket_condition_wait()`, which only happens in blocking mode.

Fix that and add a unit test.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Helps: #3739
This commit is contained in:
Philip Withnall
2025-07-25 15:20:13 +01:00
parent 6a399d740a
commit e6a1eacfe1
2 changed files with 40 additions and 0 deletions

View File

@@ -2543,6 +2543,41 @@ test_receive_bytes_from (void)
ip_test_data_free (data);
}
static void
test_accept_cancelled (void)
{
GSocket *socket = NULL;
GError *local_error = NULL;
GCancellable *cancellable = NULL;
GSocket *socket2 = NULL;
g_test_summary ("Calling g_socket_accept() with a cancelled cancellable "
"should return immediately regardless of whether the socket "
"is blocking");
socket = g_socket_new (G_SOCKET_FAMILY_IPV4,
G_SOCKET_TYPE_STREAM,
G_SOCKET_PROTOCOL_DEFAULT,
&local_error);
g_assert_no_error (local_error);
cancellable = g_cancellable_new ();
g_cancellable_cancel (cancellable);
for (unsigned int i = 0; i < 2; i++)
{
g_socket_set_blocking (socket, i);
socket2 = g_socket_accept (socket, cancellable, &local_error);
g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
g_assert_null (socket2);
g_clear_error (&local_error);
}
g_clear_object (&cancellable);
g_clear_object (&socket);
}
int
main (int argc,
char *argv[])
@@ -2612,5 +2647,7 @@ main (int argc,
g_test_add_func ("/socket/receive_bytes", test_receive_bytes);
g_test_add_func ("/socket/receive_bytes_from", test_receive_bytes_from);
g_test_add_func ("/socket/accept/cancelled", test_accept_cancelled);
return g_test_run();
}