diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 39444f79d..7936476ce 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -2225,6 +2225,7 @@ g_socket_control_message_get_type
gsocketlistener
GSocketListener
GSocketListener
+GSocketListenerEvent
g_socket_listener_new
g_socket_listener_add_socket
g_socket_listener_add_address
diff --git a/gio/gioenums.h b/gio/gioenums.h
index 9fd563dcc..55a70b174 100644
--- a/gio/gioenums.h
+++ b/gio/gioenums.h
@@ -1750,6 +1750,29 @@ typedef enum {
G_SOCKET_CLIENT_COMPLETE
} GSocketClientEvent;
+/**
+ * GSocketListenerEvent:
+ * @G_SOCKET_LISTENER_BINDING: The listener is about to bind a socket.
+ * @G_SOCKET_LISTENER_BOUND: The listener has bound a socket.
+ * @G_SOCKET_LISTENER_LISTENING: The listener is about to start
+ * listening on this socket.
+ * @G_SOCKET_LISTENER_LISTENED: The listener is now listening on
+ * this socket.
+ *
+ * Describes an event occurring on a #GSocketListener. See the
+ * #GSocketListener::event signal for more details.
+ *
+ * Additional values may be added to this type in the future.
+ *
+ * Since: 2.46
+ */
+typedef enum {
+ G_SOCKET_LISTENER_BINDING,
+ G_SOCKET_LISTENER_BOUND,
+ G_SOCKET_LISTENER_LISTENING,
+ G_SOCKET_LISTENER_LISTENED
+} GSocketListenerEvent;
+
/**
* GTestDBusFlags:
* @G_TEST_DBUS_NONE: No flags.
diff --git a/gio/gsocketlistener.c b/gio/gsocketlistener.c
index 7185745ff..8b60ea316 100644
--- a/gio/gsocketlistener.c
+++ b/gio/gsocketlistener.c
@@ -26,6 +26,7 @@
#include "config.h"
#include "gsocketlistener.h"
+#include
#include
#include
#include
@@ -61,6 +62,13 @@ enum
PROP_LISTEN_BACKLOG
};
+enum
+{
+ EVENT,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
static GQuark source_quark = 0;
@@ -131,7 +139,6 @@ g_socket_listener_set_property (GObject *object,
}
}
-
static void
g_socket_listener_class_init (GSocketListenerClass *klass)
{
@@ -149,6 +156,29 @@ g_socket_listener_class_init (GSocketListenerClass *klass)
10,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GSocketListener::event:
+ * @listener: the #GSocketListener
+ * @event: the event that is occurring
+ * @socket: the #GSocket the event is occurring on
+ *
+ * Emitted when @listener's activity on @socket changes state.
+ * Note that when @listener is used to listen on both IPv4 and
+ * IPv6, a separate set of signals will be emitted for each, and
+ * the order they happen in is undefined.
+ *
+ * Since: 2.46
+ */
+ signals[EVENT] =
+ g_signal_new (I_("event"),
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GSocketListenerClass, event),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 2,
+ G_TYPE_SOCKET_LISTENER_EVENT,
+ G_TYPE_SOCKET);
+
source_quark = g_quark_from_static_string ("g-socket-listener-source");
}
@@ -306,13 +336,29 @@ g_socket_listener_add_address (GSocketListener *listener,
g_socket_set_listen_backlog (socket, listener->priv->listen_backlog);
- if (!g_socket_bind (socket, address, TRUE, error) ||
- !g_socket_listen (socket, error))
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_BINDING, socket);
+
+ if (!g_socket_bind (socket, address, TRUE, error))
{
g_object_unref (socket);
return FALSE;
}
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_BOUND, socket);
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_LISTENING, socket);
+
+ if (!g_socket_listen (socket, error))
+ {
+ g_object_unref (socket);
+ return FALSE;
+ }
+
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_LISTENED, socket);
+
local_address = NULL;
if (effective_address)
{
@@ -392,7 +438,6 @@ g_socket_listener_add_inet_port (GSocketListener *listener,
{
GInetAddress *inet_address;
GSocketAddress *address;
- gboolean result;
inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6);
address = g_inet_socket_address_new (inet_address, port);
@@ -400,18 +445,32 @@ g_socket_listener_add_inet_port (GSocketListener *listener,
g_socket_set_listen_backlog (socket6, listener->priv->listen_backlog);
- result = g_socket_bind (socket6, address, TRUE, error) &&
- g_socket_listen (socket6, error);
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_BINDING, socket6);
+
+ if (!g_socket_bind (socket6, address, TRUE, error))
+ {
+ g_object_unref (address);
+ g_object_unref (socket6);
+ return FALSE;
+ }
g_object_unref (address);
- if (!result)
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_BOUND, socket6);
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_LISTENING, socket6);
+
+ if (!g_socket_listen (socket6, error))
{
g_object_unref (socket6);
-
return FALSE;
}
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_LISTENED, socket6);
+
if (source_object)
g_object_set_qdata_full (G_OBJECT (socket6), source_quark,
g_object_ref (source_object),
@@ -445,7 +504,6 @@ g_socket_listener_add_inet_port (GSocketListener *listener,
{
GInetAddress *inet_address;
GSocketAddress *address;
- gboolean result;
inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4);
address = g_inet_socket_address_new (inet_address, port);
@@ -454,21 +512,40 @@ g_socket_listener_add_inet_port (GSocketListener *listener,
g_socket_set_listen_backlog (socket4,
listener->priv->listen_backlog);
- result = g_socket_bind (socket4, address, TRUE, error) &&
- g_socket_listen (socket4, error);
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_BINDING, socket4);
- g_object_unref (address);
-
- if (!result)
+ if (!g_socket_bind (socket4, address, TRUE, error))
{
+ g_object_unref (address);
g_object_unref (socket4);
-
if (socket6 != NULL)
g_object_unref (socket6);
return FALSE;
}
+ g_object_unref (address);
+
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_BOUND, socket4);
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_LISTENING, socket4);
+
+ if (!g_socket_listen (socket4, error))
+ {
+ g_object_unref (socket4);
+ if (socket6 != NULL)
+ g_object_unref (socket6);
+
+ return FALSE;
+ }
+
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_LISTENED, socket4);
+
+ g_object_unref (address);
+
if (source_object)
g_object_set_qdata_full (G_OBJECT (socket4), source_quark,
g_object_ref (source_object),
@@ -965,6 +1042,10 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6);
address = g_inet_socket_address_new (inet_address, 0);
g_object_unref (inet_address);
+
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_BINDING, socket6);
+
result = g_socket_bind (socket6, address, TRUE, error);
g_object_unref (address);
@@ -976,6 +1057,9 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
break;
}
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_BOUND, socket6);
+
g_assert (G_IS_INET_SOCKET_ADDRESS (address));
candidate_port =
g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (address));
@@ -1004,6 +1088,10 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4);
address = g_inet_socket_address_new (inet_address, candidate_port);
g_object_unref (inet_address);
+
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_BINDING, socket4);
+
/* a note on the 'error' clause below:
*
* if candidate_port is 0 then we report the error right away
@@ -1029,8 +1117,11 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
if (result)
/* got our candidate port successfully */
- break;
-
+ {
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_BOUND, socket4);
+ break;
+ }
else
/* we failed to bind to the specified port. try again. */
{
@@ -1060,6 +1151,9 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
break;
}
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_BOUND, socket4);
+
g_assert (G_IS_INET_SOCKET_ADDRESS (address));
candidate_port =
g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (address));
@@ -1083,6 +1177,10 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
if (socket6 != NULL)
{
g_socket_set_listen_backlog (socket6, listener->priv->listen_backlog);
+
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_LISTENING, socket6);
+
if (!g_socket_listen (socket6, error))
{
g_object_unref (socket6);
@@ -1092,6 +1190,9 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
return 0;
}
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_LISTENED, socket6);
+
if (source_object)
g_object_set_qdata_full (G_OBJECT (socket6), source_quark,
g_object_ref (source_object),
@@ -1103,6 +1204,10 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
if (socket4 != NULL)
{
g_socket_set_listen_backlog (socket4, listener->priv->listen_backlog);
+
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_LISTENING, socket4);
+
if (!g_socket_listen (socket4, error))
{
g_object_unref (socket4);
@@ -1112,6 +1217,9 @@ g_socket_listener_add_any_inet_port (GSocketListener *listener,
return 0;
}
+ g_signal_emit (listener, signals[EVENT], 0,
+ G_SOCKET_LISTENER_LISTENED, socket4);
+
if (source_object)
g_object_set_qdata_full (G_OBJECT (socket4), source_quark,
g_object_ref (source_object),
diff --git a/gio/gsocketlistener.h b/gio/gsocketlistener.h
index 82d309acb..abf064a06 100644
--- a/gio/gsocketlistener.h
+++ b/gio/gsocketlistener.h
@@ -61,8 +61,11 @@ struct _GSocketListenerClass
void (* changed) (GSocketListener *listener);
+ void (* event) (GSocketListener *listener,
+ GSocketListenerEvent *event,
+ GSocket *socket);
+
/* Padding for future expansion */
- void (*_g_reserved1) (void);
void (*_g_reserved2) (void);
void (*_g_reserved3) (void);
void (*_g_reserved4) (void);
diff --git a/gio/tests/socket-listener.c b/gio/tests/socket-listener.c
index 98e33960d..5a58206bc 100644
--- a/gio/tests/socket-listener.c
+++ b/gio/tests/socket-listener.c
@@ -19,6 +19,70 @@
#include
+static void
+event_cb (GSocketListener *listener,
+ GSocketListenerEvent event,
+ GSocket *socket,
+ gpointer data)
+{
+ static GSocketListenerEvent expected_event = G_SOCKET_LISTENER_BINDING;
+ gboolean *success = (gboolean *)data;
+
+ g_assert (G_IS_SOCKET_LISTENER (listener));
+ g_assert (G_IS_SOCKET (socket));
+ g_assert (event == expected_event);
+
+ switch (event)
+ {
+ case G_SOCKET_LISTENER_BINDING:
+ expected_event = G_SOCKET_LISTENER_BOUND;
+ break;
+ case G_SOCKET_LISTENER_BOUND:
+ expected_event = G_SOCKET_LISTENER_LISTENING;
+ break;
+ case G_SOCKET_LISTENER_LISTENING:
+ expected_event = G_SOCKET_LISTENER_LISTENED;
+ break;
+ case G_SOCKET_LISTENER_LISTENED:
+ *success = TRUE;
+ break;
+ }
+}
+
+static void
+test_event_signal (void)
+{
+ gboolean success = FALSE;
+ GInetAddress *iaddr;
+ GSocketAddress *saddr;
+ GSocketListener *listener;
+ GError *error = NULL;
+
+ iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
+ saddr = g_inet_socket_address_new (iaddr, 0);
+ g_object_unref (iaddr);
+
+ listener = g_socket_listener_new ();
+
+ g_signal_connect (listener, "event", G_CALLBACK (event_cb), &success);
+
+ g_socket_listener_add_address (listener,
+ saddr,
+ G_SOCKET_TYPE_STREAM,
+ G_SOCKET_PROTOCOL_TCP,
+ NULL,
+ NULL,
+ &error);
+ g_assert_no_error (error);
+ g_object_unref (saddr);
+
+ do
+ g_main_context_iteration (NULL, TRUE);
+ while (!success);
+
+ g_object_unref (listener);
+}
+
GMutex mutex_712570;
GCond cond_712570;
volatile gboolean finalized;
@@ -160,6 +224,7 @@ main (int argc,
g_test_bug_base ("http://bugzilla.gnome.org/");
+ g_test_add_func ("/socket-listener/event-signal", test_event_signal);
g_test_add_func ("/socket-listener/threaded/712570", test_threaded_712570);
return g_test_run();