[glib] Add an event signal to GSocketListener



commit b64e2956f6b9ae74f1fdcecb129bff7738817509
Author: Paolo Borelli <pborelli gnome org>
Date:   Thu Oct 9 15:54:43 2014 +0200

    Add an event signal to GSocketListener
    
    This allows the caller to know when a socket has been bound so that
    it can for instance set the SO_SENDBUF and SO_RECVBUF socket options
    before listen is called
    
    https://bugzilla.gnome.org/show_bug.cgi?id=738207

 docs/reference/gio/gio-sections.txt |    1 +
 gio/gioenums.h                      |   23 ++++++
 gio/gsocketlistener.c               |  138 +++++++++++++++++++++++++++++++----
 gio/gsocketlistener.h               |    5 +-
 gio/tests/socket-listener.c         |   65 ++++++++++++++++
 5 files changed, 216 insertions(+), 16 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 39444f7..7936476 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
 <FILE>gsocketlistener</FILE>
 <TITLE>GSocketListener</TITLE>
 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 9fd563d..55a70b1 100644
--- a/gio/gioenums.h
+++ b/gio/gioenums.h
@@ -1751,6 +1751,29 @@ typedef enum {
 } 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 7185745..8b60ea3 100644
--- a/gio/gsocketlistener.c
+++ b/gio/gsocketlistener.c
@@ -26,6 +26,7 @@
 #include "config.h"
 #include "gsocketlistener.h"
 
+#include <gio/gioenumtypes.h>
 #include <gio/gtask.h>
 #include <gio/gcancellable.h>
 #include <gio/gsocketaddress.h>
@@ -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);
+
+          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);
 
-          if (!result)
+          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 82d309a..abf064a 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 98e3396..5a58206 100644
--- a/gio/tests/socket-listener.c
+++ b/gio/tests/socket-listener.c
@@ -19,6 +19,70 @@
 
 #include <gio/gio.h>
 
+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();


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]