[gnio] Clean up and document GSocketControlMessage



commit 868d627f67653c5837e8ff8bf25df0c319575dd0
Author: Alexander Larsson <alexl redhat com>
Date:   Thu May 7 20:53:38 2009 +0200

    Clean up and document GSocketControlMessage
    
    Move all cmsg munging to GSocket, instead passing raw ints and gpointers
    to GSocketControlMessage.
    
    Made deserialization extensible by trying the deserialize method of all
    GSocketControlMessage subclasses when deserializing.
    
    Removed gsocketcontrol-private.h and all knowledge of specific
    control messages (other than type initialization) from the generic
    code.
---
 gio/gsocket.c                |   15 +++--
 gio/gsocketcontrol-private.h |   27 -------
 gio/gsocketcontrolmessage.c  |  158 +++++++++++++++++++++++++++++++-----------
 gio/gsocketcontrolmessage.h  |   44 ++++++++++--
 gio/gunixfdmessage.c         |   88 ++++++++++++++----------
 5 files changed, 213 insertions(+), 119 deletions(-)

diff --git a/gio/gsocket.c b/gio/gsocket.c
index 3da1218..4349e29 100644
--- a/gio/gsocket.c
+++ b/gio/gsocket.c
@@ -43,7 +43,6 @@
 #include <gio/gcancellable.h>
 #include <gio/gioenumtypes.h>
 #include <gio/ginitable.h>
-#include "gsocketcontrol-private.h"
 #include "gasynchelper.h"
 #include "gnioerror.h"
 #include "gnioenums.h"
@@ -2477,15 +2476,18 @@ g_socket_send_message (GSocket                *socket,
 
       msg.msg_controllen = 0;
       for (i = 0; i < num_messages; i++)
-	msg.msg_controllen += g_socket_control_message_space (messages[i]);
+	msg.msg_controllen += CMSG_SPACE (g_socket_control_message_get_size (messages[i]));
 
       msg.msg_control = g_alloca (msg.msg_controllen);
 
       cmsg = CMSG_FIRSTHDR (&msg);
       for (i = 0; i < num_messages; i++)
 	{
-	  g_assert (cmsg != NULL);
-	  g_socket_control_message_serialise (messages[i], cmsg);
+	  cmsg->cmsg_level = g_socket_control_message_get_level (messages[i]);
+	  cmsg->cmsg_type = g_socket_control_message_get_msg_type (messages[i]);
+	  cmsg->cmsg_len = CMSG_LEN (g_socket_control_message_get_size (messages[i]));
+	  g_socket_control_message_serialize (messages[i],
+					      CMSG_DATA (cmsg));
 	  cmsg = CMSG_NXTHDR (&msg, cmsg);
 	}
       g_assert (cmsg == NULL);
@@ -2783,7 +2785,10 @@ g_socket_receive_message (GSocket                 *socket,
 	{
 	  GSocketControlMessage *message;
 
-	  message = g_socket_control_message_deserialise (cmsg);
+	  message = g_socket_control_message_deserialize (cmsg->cmsg_level,
+							  cmsg->cmsg_type,
+							  cmsg->cmsg_len - ((char *)CMSG_DATA (cmsg) - (char *)cmsg),
+							  CMSG_DATA (cmsg));
 	  if (message == NULL)
 	    /* We've already spewed about the problem in the
 	       deserialization code, so just continue */
diff --git a/gio/gsocketcontrol-private.h b/gio/gsocketcontrol-private.h
deleted file mode 100644
index a9b0adf..0000000
--- a/gio/gsocketcontrol-private.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright © 2009 Codethink Limited
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation; either version 2 of the licence or (at
- * your option) any later version.
- *
- * See the included COPYING file for more information.
- *
- * Authors: Ryan Lortie <desrt desrt ca>
- */
-
-#ifndef _gsocketcontrol_private_h_
-#define _gsocketcontrol_private_h_
-
-#include "gsocketcontrolmessage.h"
-
-G_BEGIN_DECLS
-
-GSocketControlMessage * g_unix_fd_message_deserialise                   (gpointer scm_data,
-                                                                         gssize   scm_size);
-GSocketControlMessage * g_socket_control_message_deserialise            (gpointer scm_pointer);
-
-G_END_DECLS
-
-#endif /* _gsocketcontrolmessage_h_ */
diff --git a/gio/gsocketcontrolmessage.c b/gio/gsocketcontrolmessage.c
index c5c4854..3af0029 100644
--- a/gio/gsocketcontrolmessage.c
+++ b/gio/gsocketcontrolmessage.c
@@ -28,9 +28,21 @@
  *
  * These messages are sent with g_socket_send_message() and received
  * with g_socket_receive_message().
+ *
+ * To extend the set of control message that can be sent, subclass this
+ * class and override the get_size, get_level, get_type and serialize
+ * methods.
+ *
+ * To extend the set of control messages that can be recieved, subclass
+ * this class and implement the deserialize method. Also, make sure your
+ * class is registered with the GType typesystem before calling
+ * g_socket_recieve_message() to read such a message.
+ * 
+ * Since: 2.22
  **/
 
 #include "gsocketcontrolmessage.h"
+#include "gunixfdmessage.h"
 
 #ifndef G_OS_WIN32
 #include <sys/socket.h>
@@ -43,72 +55,134 @@ G_DEFINE_ABSTRACT_TYPE (GSocketControlMessage,
                         g_socket_control_message,
                         G_TYPE_OBJECT);
 
+/**
+ * g_socket_control_message_get_size:
+ * @message: a #GSocketControlMessage
+ *
+ * Returns the space required for the control message, not including
+ * headers or alignment.
+ *
+ * Returns: The number of bytes required.
+ *
+ * Since: 2.22
+ **/
 gsize
-g_socket_control_message_space (GSocketControlMessage *message)
+g_socket_control_message_get_size (GSocketControlMessage *message)
 {
   g_return_val_if_fail (G_IS_SOCKET_CONTROL_MESSAGE (message), 0);
-  gsize size;
 
-  size = G_SOCKET_CONTROL_MESSAGE_GET_CLASS (message)
-    -> size (message);
-
-#ifndef G_OS_WIN32
-  return CMSG_SPACE (size);
-#elif defined (WSA_CMSG_SPACE)
-  return WSA_CMSG_SPACE (size);
-#else
-  return size;
-#endif
+  return G_SOCKET_CONTROL_MESSAGE_GET_CLASS (message)->get_size (message);
 }
 
-static void
-g_socket_control_message_init (GSocketControlMessage *message)
+/**
+ * g_socket_control_message_get_level:
+ * @message: a #GSocketControlMessage
+ *
+ * Returns the "level" (i.e. the originating protocol) of the control message.
+ * This is often SOL_SOCKET.
+ *
+ * Returns: and int describing the level
+ *
+ * Since: 2.22
+ **/
+int
+g_socket_control_message_get_level (GSocketControlMessage *message)
 {
+  g_return_val_if_fail (G_IS_SOCKET_CONTROL_MESSAGE (message), 0);
+
+  return G_SOCKET_CONTROL_MESSAGE_GET_CLASS (message)->get_level (message);
 }
 
-static void
-g_socket_control_message_class_init (GSocketControlMessageClass *class)
+/**
+ * g_socket_control_message_get_msg_type:
+ * @message: a #GSocketControlMessage
+ *
+ * Returns the protocol specify type  of the control message.
+ * For instance, for unix fd passing this would be SCM_RIGHTS.
+ *
+ * Returns: and int describing the level
+ *
+ * Since: 2.22
+ **/
+int
+g_socket_control_message_get_msg_type (GSocketControlMessage *message)
 {
-}
+  g_return_val_if_fail (G_IS_SOCKET_CONTROL_MESSAGE (message), 0);
 
-#include "gsocketcontrol-private.h"
+  return G_SOCKET_CONTROL_MESSAGE_GET_CLASS (message)->get_type (message);
+}
 
+/**
+ * g_socket_control_message_serialize:
+ * @message: a #GSocketControlMessage
+ * @data: A buffer to write data to
+ *
+ * Converts the data in the message to bytes placed in the
+ * message.
+ *
+ * @data is guaranteed to have enough space to fit the size
+ * returned by g_socket_control_message_get_size() on this
+ * object.
+ *
+ * Since: 2.22
+ **/
 void
-g_socket_control_message_serialise (GSocketControlMessage *message,
-                                    gpointer               scm_pointer)
+g_socket_control_message_serialize (GSocketControlMessage *message,
+				    gpointer               data)
 {
   g_return_if_fail (G_IS_SOCKET_CONTROL_MESSAGE (message));
 
-  G_SOCKET_CONTROL_MESSAGE_GET_CLASS (message)
-    -> serialise (message, scm_pointer);
+  return G_SOCKET_CONTROL_MESSAGE_GET_CLASS (message)->serialize (message, data);
+}
+
+
+static void
+g_socket_control_message_init (GSocketControlMessage *message)
+{
 }
 
+static void
+g_socket_control_message_class_init (GSocketControlMessageClass *class)
+{
+}
 
 GSocketControlMessage *
-g_socket_control_message_deserialise (gpointer scm_pointer)
+g_socket_control_message_deserialize  (int                    level,
+				       int                    type,
+				       gsize                  size,
+				       gpointer               data)
 {
-#ifndef G_OS_WIN32
-  struct cmsghdr *cmsg = scm_pointer;
-  gpointer data;
-  gssize size;
+  GSocketControlMessageClass *klass;
+  GSocketControlMessage *message;
+  volatile GType a_type;
+  GType *message_types;
+  guint n_message_types;
+  int i;
+
+  /* Ensure we know about the built in types */
+  a_type = g_unix_fd_message_get_type ();
 
-  size = cmsg->cmsg_len - CMSG_LEN (0);
-  data = CMSG_DATA (cmsg);
+  message_types = g_type_children (G_TYPE_SOCKET_CONTROL_MESSAGE, &n_message_types);
 
-  switch (cmsg->cmsg_level)
+  message = NULL;
+  for (i = 0; i < n_message_types; i++)
     {
-     case SOL_SOCKET:
-      switch (cmsg->cmsg_type)
-        {
-         case SCM_RIGHTS:
-          return g_unix_fd_message_deserialise (data, size);
-        }
+      klass = (GSocketControlMessageClass *)g_type_class_ref (type);
+
+      if (klass && klass->deserialize)
+	{
+	  message = klass->deserialize (level, type, size, data);
+	  g_type_class_unref ((GTypeClass *) klass);
+	}
+
+      if (message != NULL)
+	break;
     }
 
-  g_warning ("unknown control message type %d:%d", 
-	     cmsg->cmsg_level, cmsg->cmsg_type);
-#else
-  g_warning ("socket control messages not supported on windows");
-#endif
-  return NULL;
+  g_free (message_types);
+
+  if (message == NULL)
+    g_warning ("unknown control message type %d:%d", level, type);
+
+  return message;
 }
diff --git a/gio/gsocketcontrolmessage.h b/gio/gsocketcontrolmessage.h
index 1e5cbb9..0a6af86 100644
--- a/gio/gsocketcontrolmessage.h
+++ b/gio/gsocketcontrolmessage.h
@@ -33,17 +33,38 @@ G_BEGIN_DECLS
                                                              G_TYPE_SOCKET_CONTROL_MESSAGE,                          \
                                                              GSocketControlMessageClass))
 
+/**
+ * GSocketControlMessage:
+ *
+ * Base class for socket-type specific control messages that can be sent and
+ * recieved over #GSocket.
+ **/
+typedef struct _GSocketControlMessage                       GSocketControlMessage;
 typedef struct _GSocketControlMessagePrivate                GSocketControlMessagePrivate;
 typedef struct _GSocketControlMessageClass                  GSocketControlMessageClass;
-typedef struct _GSocketControlMessage                       GSocketControlMessage;
+
+/**
+ * GSocketControlMessageClass:
+ * @get_size: gets the size of the message.
+ * @get_level: gets the protocol of the message.
+ * @get_type: gets the protocol specific type of the message.
+ * @serialize: Writes out the message data.
+ * @deserialize: Tries to deserialize a message.
+ **/
 
 struct _GSocketControlMessageClass
 {
   GObjectClass parent_class;
 
-  gsize (* size)      (GSocketControlMessage  *message);
-  void  (* serialise) (GSocketControlMessage  *message,
-                       gpointer                scm_pointer);
+  gsize                  (* get_size)  (GSocketControlMessage  *message);
+  int                    (* get_level) (GSocketControlMessage  *message);
+  int                    (* get_type)  (GSocketControlMessage  *message);
+  void                   (* serialize) (GSocketControlMessage  *message,
+					gpointer                data);
+  GSocketControlMessage *(* deserialize) (int                   level,
+					  int                   type,
+					  gsize                 size,
+					  gpointer              data);
 };
 
 struct _GSocketControlMessage
@@ -52,10 +73,17 @@ struct _GSocketControlMessage
   GSocketControlMessagePrivate *priv;
 };
 
-GType                   g_socket_control_message_get_type               (void);
-gsize                   g_socket_control_message_space                  (GSocketControlMessage  *message);
-void                    g_socket_control_message_serialise              (GSocketControlMessage  *message,
-                                                                         gpointer                scm_pointer);
+GType                  g_socket_control_message_get_type     (void);
+gsize                  g_socket_control_message_get_size     (GSocketControlMessage *message);
+int                    g_socket_control_message_get_level    (GSocketControlMessage *message);
+int                    g_socket_control_message_get_msg_type (GSocketControlMessage *message);
+void                   g_socket_control_message_serialize    (GSocketControlMessage *message,
+							      gpointer               data);
+GSocketControlMessage *g_socket_control_message_deserialize  (int                    level,
+							      int                    type,
+							      gsize                  size,
+							      gpointer               data);
+
 
 G_END_DECLS
 
diff --git a/gio/gunixfdmessage.c b/gio/gunixfdmessage.c
index 7a74372..04174f8 100644
--- a/gio/gunixfdmessage.c
+++ b/gio/gunixfdmessage.c
@@ -46,28 +46,61 @@ struct _GUnixFDMessagePrivate
   gint nfd;
 };
 
-static void
-g_unix_fd_message_serialise (GSocketControlMessage *message,
-                               gpointer               scm_pointer)
+static gsize
+g_unix_fd_message_get_size (GSocketControlMessage *message)
 {
   GUnixFDMessage *fd_message = G_UNIX_FD_MESSAGE (message);
-  struct cmsghdr *cmsg = scm_pointer;
 
-  cmsg->cmsg_level = SOL_SOCKET;
-  cmsg->cmsg_type = SCM_RIGHTS;
-  cmsg->cmsg_len = CMSG_LEN (sizeof (gint) * fd_message->priv->nfd);
-  memcpy (CMSG_DATA (cmsg), fd_message->priv->fds,
-          sizeof (gint) * fd_message->priv->nfd);
+  return fd_message->priv->nfd * sizeof (gint);
 }
 
-static gsize
-g_unix_fd_message_size (GSocketControlMessage *message)
+static int
+g_unix_fd_message_get_level (GSocketControlMessage *message)
 {
-  GUnixFDMessage *fd_message = G_UNIX_FD_MESSAGE (message);
+  return SOL_SOCKET;
+}
 
-  return fd_message->priv->nfd * sizeof (gint);
+static int
+g_unix_fd_message_get_msg_type (GSocketControlMessage *message)
+{
+  return SCM_RIGHTS;
 }
 
+static GSocketControlMessage *
+g_unix_fd_message_deserialize (int level,
+			       int type,
+			       gsize size,
+			       gpointer data)
+{
+  GUnixFDMessage *message;
+
+  if (level != SOL_SOCKET ||
+      level != SCM_RIGHTS)
+    return NULL;
+  
+  if (size % 4 > 0)
+    {
+      g_warning ("Kernel returned non-integral number of fds");
+      return NULL;
+    }
+
+  message = g_object_new (G_TYPE_UNIX_FD_MESSAGE, NULL);
+  message->priv->nfd = size / sizeof (gint);
+  message->priv->fds = g_new (gint, message->priv->nfd + 1);
+  memcpy (message->priv->fds, data, size);
+  message->priv->fds[message->priv->nfd] = -1;
+
+  return G_SOCKET_CONTROL_MESSAGE (message);
+}
+
+static void
+g_unix_fd_message_serialize (GSocketControlMessage *message,
+			     gpointer               data)
+{
+  GUnixFDMessage *fd_message = G_UNIX_FD_MESSAGE (message);
+  memcpy (data, fd_message->priv->fds,
+	  sizeof (gint) * fd_message->priv->nfd);
+}
 static void
 g_unix_fd_message_init (GUnixFDMessage *message)
 {
@@ -97,8 +130,11 @@ g_unix_fd_message_class_init (GUnixFDMessageClass *class)
   GObjectClass *object_class = G_OBJECT_CLASS (class);
 
   g_type_class_add_private (class, sizeof (GUnixFDMessagePrivate));
-  scm_class->size = g_unix_fd_message_size;
-  scm_class->serialise = g_unix_fd_message_serialise;
+  scm_class->get_size = g_unix_fd_message_get_size;
+  scm_class->get_level = g_unix_fd_message_get_level;
+  scm_class->get_type = g_unix_fd_message_get_msg_type;
+  scm_class->serialize = g_unix_fd_message_serialize;
+  scm_class->deserialize = g_unix_fd_message_deserialize;
   object_class->finalize = g_unix_fd_message_finalize;
 }
 
@@ -214,25 +250,3 @@ g_unix_fd_message_append_fd (GUnixFDMessage  *message,
   return TRUE;
 }
 
-#include "gsocketcontrol-private.h"
-
-GSocketControlMessage *
-g_unix_fd_message_deserialise (gpointer scm_data,
-                                 gssize   scm_size)
-{
-  GUnixFDMessage *message;
-
-  if (scm_size % 4 > 0)
-    {
-      g_warning ("Kernel returned non-integral number of fds");
-      return NULL;
-    }
-
-  message = g_object_new (G_TYPE_UNIX_FD_MESSAGE, NULL);
-  message->priv->nfd = scm_size / sizeof (gint);
-  message->priv->fds = g_new (gint, message->priv->nfd + 1);
-  memcpy (message->priv->fds, scm_data, scm_size);
-  message->priv->fds[message->priv->nfd] = -1;
-
-  return G_SOCKET_CONTROL_MESSAGE (message);
-}



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