[gnio] Add keepalive property to GSocket



commit f80d5b6ae57efaaa8435e3aa59514a3f8f2db293
Author: Alexander Larsson <alexl redhat com>
Date:   Tue Apr 28 11:59:59 2009 +0200

    Add keepalive property to GSocket
---
 gio/gsocket.c |  131 +++++++++++++++++++++++++++++++++++++++++++--------------
 gio/gsocket.h |    3 +
 2 files changed, 102 insertions(+), 32 deletions(-)

diff --git a/gio/gsocket.c b/gio/gsocket.c
index 8942ac7..ca40bb6 100644
--- a/gio/gsocket.c
+++ b/gio/gsocket.c
@@ -57,6 +57,7 @@ enum
   PROP_BLOCKING,
   PROP_LISTEN_BACKLOG,
   PROP_REUSE_ADDRESS,
+  PROP_KEEPALIVE,
   PROP_LOCAL_ADDRESS,
   PROP_REMOTE_ADDRESS
 };
@@ -69,6 +70,7 @@ struct _GSocketPrivate
   gboolean        blocking;
   gint            listen_backlog;
   gboolean        reuse_address;
+  gboolean        keepalive;
   GError         *construct_error;
   GSocketAddress *local_address;
   GSocketAddress *remote_address;
@@ -100,18 +102,17 @@ g_socket_details_from_fd (GSocket *socket)
 {
 #ifndef G_OS_WIN32
   struct sockaddr_storage address;
-  gint fd, result;
+  gint fd;
   guint addrlen;
   guint optlen;
-  gint value;
+  int value, result;
+  int errsv;
 
   fd = socket->priv->fd;
   optlen = sizeof value;
-  result = getsockopt (fd, SOL_SOCKET, SO_TYPE, &value, &optlen);
-
-  if G_UNLIKELY (result < 0)
+  if (getsockopt (fd, SOL_SOCKET, SO_TYPE, &value, &optlen) != 0)
     {
-      gint errsv = errno;
+      errsv = errno;
 
       switch (errsv)
         {
@@ -120,15 +121,11 @@ g_socket_details_from_fd (GSocket *socket)
           /* programmer error */
           g_error ("creating GSocket from fd %d: %s\n",
                    fd, g_strerror (errsv));
-
          default:
-          g_set_error (&socket->priv->construct_error, G_IO_ERROR,
-                       g_io_error_from_errno (errsv),
-                       "creating GSocket from fd: %s",
-                       g_strerror (errsv));
+	   break;
         }
 
-      return;
+      goto err;
     }
 
   g_assert (optlen == sizeof value);
@@ -152,18 +149,10 @@ g_socket_details_from_fd (GSocket *socket)
     }
 
   addrlen = sizeof address;
-  result = getsockname (fd, (struct sockaddr *) &address, &addrlen);
-
-  if G_UNLIKELY (result < 0)
+  if (getsockname (fd, (struct sockaddr *) &address, &addrlen) != 0)
     {
-      gint errsv = errno;
-
-      g_set_error (&socket->priv->construct_error, G_IO_ERROR,
-                   g_io_error_from_errno (errsv),
-                   "creating GSocket from fd: %s",
-                   g_strerror (errsv));
-
-      return;
+      errsv = errno;
+      goto err;
     }
 
   g_assert (G_STRUCT_OFFSET (struct sockaddr, sa_family) +
@@ -192,25 +181,55 @@ g_socket_details_from_fd (GSocket *socket)
           g_socket_address_new_from_native (&address, addrlen);
     }
 
-
   result = fcntl (fd, F_GETFL, NULL);
-
-  if G_UNLIKELY (result < 0)
+  if (result == -1)
     {
-      gint errsv = errno;
+      errsv = errno;
+      goto err;
+    }
+  socket->priv->blocking = !(result & O_NONBLOCK);
 
-      g_error ("fcntl failed while constructing a GSocket from fd (%s).  "
-               "This is really quite unexpected.  Please file a bug.",
-               g_strerror (errsv));
+  optlen = sizeof value;
+  if (getsockopt (fd, SOL_SOCKET, SO_KEEPALIVE,
+		  &value, &optlen) == 0)
+    {
+      g_assert (optlen == sizeof value);
+      socket->priv->keepalive = !!value;
+    }
+  else
+    {
+      /* Can't read, maybe not supported, assume FALSE */
+      socket->priv->keepalive = FALSE;
     }
 
-  socket->priv->blocking = !(result & O_NONBLOCK);
+  optlen = sizeof value;
+  if (getsockopt (fd, SOL_SOCKET, SO_REUSEADDR,
+		  &value, &optlen) == 0)
+    {
+      g_assert (optlen == sizeof value);
+      socket->priv->reuse_address = !!value;
+    }
+  else
+    {
+      /* Can't read, maybe not supported, assume FALSE */
+      socket->priv->reuse_address = FALSE;
+    }
 
 #else /* windows */
   socket->type = G_SOCKET_TYPE_INVALID;
   socket->family = G_SOCKET_DOMAIN_INVALID;
   socket->blocking = FALSE;
+  socket->keepalive = FALSE;
+  socket->reuse_address = FALSE;
 #endif
+
+  return;
+
+ err:
+  g_set_error (&socket->priv->construct_error, G_IO_ERROR,
+	       g_io_error_from_errno (errsv),
+	       "creating GSocket from fd: %s",
+	       g_strerror (errsv));
 }
 
 static gint
@@ -302,6 +321,10 @@ g_socket_get_property (GObject    *object,
         g_value_set_boolean (value, socket->priv->reuse_address);
         break;
 
+      case PROP_KEEPALIVE:
+        g_value_set_boolean (value, socket->priv->keepalive);
+        break;
+
       case PROP_LOCAL_ADDRESS:
         g_value_set_object (value, socket->priv->local_address);
         break;
@@ -349,6 +372,10 @@ g_socket_set_property (GObject      *object,
         g_socket_set_reuse_address (socket, g_value_get_boolean (value));
         break;
 
+      case PROP_KEEPALIVE:
+        g_socket_set_keepalive (socket, g_value_get_boolean (value));
+        break;
+
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -454,6 +481,13 @@ g_socket_class_init (GSocketClass *klass)
                                                          FALSE,
                                                          G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
 
+  g_object_class_install_property (gobject_class, PROP_KEEPALIVE,
+                                   g_param_spec_boolean ("keepalive",
+                                                         "keep connection alive",
+                                                         "keep connection alive by sending periodic pings",
+                                                         FALSE,
+                                                         G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
+
   g_object_class_install_property (gobject_class, PROP_LOCAL_ADDRESS,
                                    g_param_spec_object ("local-address",
                                                         "local address",
@@ -548,7 +582,7 @@ void
 g_socket_set_reuse_address (GSocket  *socket,
                             gboolean  reuse)
 {
-  gint value = (gint) reuse;
+  int value;
 
   g_return_if_fail (G_IS_SOCKET (socket));
 
@@ -556,6 +590,7 @@ g_socket_set_reuse_address (GSocket  *socket,
   if (socket->priv->reuse_address == reuse)
     return;
 
+  value = (int) reuse;
   if (setsockopt (socket->priv->fd, SOL_SOCKET, SO_REUSEADDR,
 		  (gpointer) &value, sizeof (value)) < 0)
     {
@@ -575,6 +610,38 @@ g_socket_get_reuse_address (GSocket *socket)
   return socket->priv->reuse_address;
 }
 
+void
+g_socket_set_keepalive (GSocket *socket,
+			gboolean keepalive)
+{
+  int value;
+
+  g_return_if_fail (G_IS_SOCKET (socket));
+
+  keepalive = !!keepalive;
+  if (socket->priv->keepalive == keepalive)
+    return;
+
+  value = (gint) keepalive;
+  if (setsockopt (socket->priv->fd, SOL_SOCKET, SO_KEEPALIVE,
+		  (gpointer) &value, sizeof (value)) < 0)
+    {
+      g_warning ("error setting keepalive: %s", g_strerror (errno));
+      return;
+    }
+
+  socket->priv->keepalive = keepalive;
+  g_object_notify (G_OBJECT (socket), "keepalive");
+}
+
+gboolean
+g_socket_get_keepalive (GSocket *socket)
+{
+  g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
+
+  return socket->priv->keepalive;
+}
+
 gint
 g_socket_get_listen_backlog  (GSocket                 *socket)
 {
diff --git a/gio/gsocket.h b/gio/gsocket.h
index 0a87590..cdb9697 100644
--- a/gio/gsocket.h
+++ b/gio/gsocket.h
@@ -88,6 +88,9 @@ gboolean               g_socket_get_blocking            (GSocket
 void                   g_socket_set_reuse_address       (GSocket                 *socket,
 							 gboolean                 reuse);
 gboolean               g_socket_get_reuse_address       (GSocket                 *socket);
+void                   g_socket_set_keepalive           (GSocket                 *socket,
+							 gboolean                 keepalive);
+gboolean               g_socket_get_keepalive           (GSocket                 *socket);
 gint                   g_socket_get_listen_backlog      (GSocket                 *socket);
 void                   g_socket_set_listen_backlog      (GSocket                 *socket,
 							 gint                     backlog);



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