mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-09 19:06:15 +01:00
gsocketlistener: Fix multiple returns of GTask when accepting sockets
When calling g_socket_listener_accept_socket_async() on a GSocketListener with multiple sockets, the accept_ready() callback is called for the first incoming connection on each socket. It will return success/failure for the entire accept_socket_async() GTask, and then free the GSources for listening for incoming connections on the other sockets in the GSocketListener. The GSources are freed when the GTask is finalised. However, if incoming connections arrive for multiple sockets within the same GMainContext iteration, accept_ready() will be called multiple times, and will call g_task_return_*() multiple times, before the GTask is finalised. Calling g_task_return_*() multiple times is not allowed. Propagate the first success/failure, as before, but then ignore all subsequent incoming connections until the GTask is finalised. Signed-off-by: Philip Withnall <withnall@endlessm.com>
This commit is contained in:
parent
6d8c8f509e
commit
30ccfac9cf
@ -773,6 +773,19 @@ g_socket_listener_accept (GSocketListener *listener,
|
||||
return connection;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GList *sources; /* (element-type GSource) */
|
||||
gboolean returned_yet;
|
||||
} AcceptSocketAsyncData;
|
||||
|
||||
static void
|
||||
accept_socket_async_data_free (AcceptSocketAsyncData *data)
|
||||
{
|
||||
free_sources (data->sources);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
accept_ready (GSocket *accept_socket,
|
||||
GIOCondition condition,
|
||||
@ -782,6 +795,12 @@ accept_ready (GSocket *accept_socket,
|
||||
GError *error = NULL;
|
||||
GSocket *socket;
|
||||
GObject *source_object;
|
||||
AcceptSocketAsyncData *data = g_task_get_task_data (task);
|
||||
|
||||
/* Don’t call g_task_return_*() multiple times if we have multiple incoming
|
||||
* connections in the same #GMainContext iteration. */
|
||||
if (data->returned_yet)
|
||||
return G_SOURCE_REMOVE;
|
||||
|
||||
socket = g_socket_accept (accept_socket, g_task_get_cancellable (task), &error);
|
||||
if (socket)
|
||||
@ -798,8 +817,10 @@ accept_ready (GSocket *accept_socket,
|
||||
g_task_return_error (task, error);
|
||||
}
|
||||
|
||||
data->returned_yet = TRUE;
|
||||
g_object_unref (task);
|
||||
return FALSE;
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -824,8 +845,8 @@ g_socket_listener_accept_socket_async (GSocketListener *listener,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
GList *sources;
|
||||
GError *error = NULL;
|
||||
AcceptSocketAsyncData *data = NULL;
|
||||
|
||||
task = g_task_new (listener, cancellable, callback, user_data);
|
||||
g_task_set_source_tag (task, g_socket_listener_accept_socket_async);
|
||||
@ -837,12 +858,15 @@ g_socket_listener_accept_socket_async (GSocketListener *listener,
|
||||
return;
|
||||
}
|
||||
|
||||
sources = add_sources (listener,
|
||||
data = g_new0 (AcceptSocketAsyncData, 1);
|
||||
data->returned_yet = FALSE;
|
||||
data->sources = add_sources (listener,
|
||||
accept_ready,
|
||||
task,
|
||||
cancellable,
|
||||
g_main_context_get_thread_default ());
|
||||
g_task_set_task_data (task, sources, (GDestroyNotify) free_sources);
|
||||
g_task_set_task_data (task, g_steal_pointer (&data),
|
||||
(GDestroyNotify) accept_socket_async_data_free);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user