[glib] gsocket: Split out functions to convert to and from struct msghdr



commit 5d6894746635d19d719fbf15881dbd7fc375d77c
Author: Philip Withnall <philip withnall collabora co uk>
Date:   Fri Jun 12 08:30:20 2015 +0100

    gsocket: Split out functions to convert to and from struct msghdr
    
    As new methods are added to GSocket, we don’t want to duplicate this
    code, so factor it out.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=751924

 gio/gsocket.c |  522 ++++++++++++++++++++++++++++-----------------------------
 1 files changed, 257 insertions(+), 265 deletions(-)
---
diff --git a/gio/gsocket.c b/gio/gsocket.c
index 807a423..7a87690 100644
--- a/gio/gsocket.c
+++ b/gio/gsocket.c
@@ -135,6 +135,9 @@ static gboolean g_socket_initable_init       (GInitable       *initable,
                                              GCancellable    *cancellable,
                                              GError         **error);
 
+static GSocketAddress *
+cache_recv_address (GSocket *socket, struct sockaddr *native, int native_len);
+
 static gint
 g_socket_send_messages_with_blocking   (GSocket        *socket,
                                         GOutputMessage *messages,
@@ -3699,6 +3702,227 @@ g_socket_condition_timed_wait (GSocket       *socket,
   #endif
 }
 
+/* Unfortunately these have to be macros rather than inline functions due to
+ * using alloca(). */
+#define output_message_to_msghdr(message, prev_message, msg, prev_msg, error) \
+G_STMT_START { \
+  const GOutputMessage  *_message = (message); \
+  const GOutputMessage *_prev_message = (prev_message); \
+  struct msghdr *_msg = (msg); \
+  const struct msghdr *_prev_msg = (prev_msg); \
+  GError **_error = (error); \
+ \
+  _msg->msg_flags = 0; \
+ \
+  /* name */ \
+  if (_prev_message != NULL && _prev_message->address == _message->address) \
+    { \
+      _msg->msg_name = _prev_msg->msg_name; \
+      _msg->msg_namelen = _prev_msg->msg_namelen; \
+    } \
+  else if (_message->address != NULL) \
+    { \
+      _msg->msg_namelen = g_socket_address_get_native_size (_message->address); \
+      _msg->msg_name = g_alloca (_msg->msg_namelen); \
+      if (!g_socket_address_to_native (_message->address, _msg->msg_name, \
+                                       _msg->msg_namelen, _error)) \
+        break; \
+    } \
+  else \
+    { \
+      _msg->msg_name = NULL; \
+      _msg->msg_namelen = 0; \
+    } \
+ \
+  /* iov */ \
+  { \
+    /* this entire expression will be evaluated at compile time */ \
+    if (sizeof *_msg->msg_iov == sizeof *_message->vectors && \
+        sizeof _msg->msg_iov->iov_base == sizeof _message->vectors->buffer && \
+        G_STRUCT_OFFSET (struct iovec, iov_base) == \
+        G_STRUCT_OFFSET (GOutputVector, buffer) && \
+        sizeof _msg->msg_iov->iov_len == sizeof _message->vectors->size && \
+        G_STRUCT_OFFSET (struct iovec, iov_len) == \
+        G_STRUCT_OFFSET (GOutputVector, size)) \
+      /* ABI is compatible */ \
+      { \
+        _msg->msg_iov = (struct iovec *) _message->vectors; \
+        _msg->msg_iovlen = _message->num_vectors; \
+      } \
+    else \
+      /* ABI is incompatible */ \
+      { \
+        gint i; \
+ \
+        _msg->msg_iov = g_newa (struct iovec, _message->num_vectors); \
+        for (i = 0; i < _message->num_vectors; i++) \
+          { \
+            _msg->msg_iov[i].iov_base = (void *) _message->vectors[i].buffer; \
+            _msg->msg_iov[i].iov_len = _message->vectors[i].size; \
+          } \
+        _msg->msg_iovlen = _message->num_vectors; \
+      } \
+  } \
+ \
+  /* control */ \
+  { \
+    struct cmsghdr *cmsg; \
+    gint i; \
+ \
+    _msg->msg_controllen = 0; \
+    for (i = 0; i < _message->num_control_messages; i++) \
+      _msg->msg_controllen += CMSG_SPACE (g_socket_control_message_get_size 
(_message->control_messages[i])); \
+ \
+    if (_msg->msg_controllen == 0) \
+      _msg->msg_control = NULL; \
+    else \
+      { \
+        _msg->msg_control = g_alloca (_msg->msg_controllen); \
+        memset (_msg->msg_control, '\0', _msg->msg_controllen); \
+      } \
+ \
+    cmsg = CMSG_FIRSTHDR (_msg); \
+    for (i = 0; i < _message->num_control_messages; i++) \
+      { \
+        cmsg->cmsg_level = g_socket_control_message_get_level (_message->control_messages[i]); \
+        cmsg->cmsg_type = g_socket_control_message_get_msg_type (_message->control_messages[i]); \
+        cmsg->cmsg_len = CMSG_LEN (g_socket_control_message_get_size (_message->control_messages[i])); \
+        g_socket_control_message_serialize (_message->control_messages[i], \
+                                            CMSG_DATA (cmsg)); \
+        cmsg = CMSG_NXTHDR (_msg, cmsg); \
+      } \
+    g_assert (cmsg == NULL); \
+  } \
+} G_STMT_END
+
+#define input_message_to_msghdr(message, msg) \
+G_STMT_START { \
+  const GInputMessage  *_message = (message); \
+  struct msghdr *_msg = (msg); \
+ \
+  /* name */ \
+  if (_message->address) \
+    { \
+      _msg->msg_namelen = sizeof (struct sockaddr_storage); \
+      _msg->msg_name = g_alloca (_msg->msg_namelen); \
+    } \
+  else \
+    { \
+      _msg->msg_name = NULL; \
+      _msg->msg_namelen = 0; \
+    } \
+ \
+  /* iov */ \
+  /* this entire expression will be evaluated at compile time */ \
+  if (sizeof *_msg->msg_iov == sizeof *_message->vectors && \
+      sizeof _msg->msg_iov->iov_base == sizeof _message->vectors->buffer && \
+      G_STRUCT_OFFSET (struct iovec, iov_base) == \
+      G_STRUCT_OFFSET (GInputVector, buffer) && \
+      sizeof _msg->msg_iov->iov_len == sizeof _message->vectors->size && \
+      G_STRUCT_OFFSET (struct iovec, iov_len) == \
+      G_STRUCT_OFFSET (GInputVector, size)) \
+    /* ABI is compatible */ \
+    { \
+      _msg->msg_iov = (struct iovec *) _message->vectors; \
+      _msg->msg_iovlen = _message->num_vectors; \
+    } \
+  else \
+    /* ABI is incompatible */ \
+    { \
+      guint i; \
+ \
+      _msg->msg_iov = g_newa (struct iovec, _message->num_vectors); \
+      for (i = 0; i < _message->num_vectors; i++) \
+        { \
+          _msg->msg_iov[i].iov_base = _message->vectors[i].buffer; \
+          _msg->msg_iov[i].iov_len = _message->vectors[i].size; \
+        } \
+      _msg->msg_iovlen = _message->num_vectors; \
+    } \
+ \
+  /* control */ \
+  _msg->msg_controllen = 2048; \
+  _msg->msg_control = g_alloca (_msg->msg_controllen); \
+ \
+  /* flags */ \
+  _msg->msg_flags = _message->flags; \
+} G_STMT_END
+
+static void
+input_message_from_msghdr (const struct msghdr  *msg,
+                           GInputMessage        *message,
+                           GSocket              *socket)
+{
+  /* decode address */
+  if (message->address != NULL)
+    {
+      *message->address = cache_recv_address (socket, msg->msg_name,
+                                              msg->msg_namelen);
+    }
+
+  /* decode control messages */
+  {
+    GPtrArray *my_messages = NULL;
+    struct cmsghdr *cmsg;
+
+    if (msg->msg_controllen >= sizeof (struct cmsghdr))
+      {
+        for (cmsg = CMSG_FIRSTHDR (msg);
+             cmsg != NULL;
+             cmsg = CMSG_NXTHDR ((struct msghdr *) msg, cmsg))
+          {
+            GSocketControlMessage *control_message;
+
+            control_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 (control_message == NULL)
+              /* We've already spewed about the problem in the
+                 deserialization code, so just continue */
+              continue;
+
+            if (message->control_messages == NULL)
+              {
+                /* we have to do it this way if the user ignores the
+                 * messages so that we will close any received fds.
+                 */
+                g_object_unref (control_message);
+              }
+            else
+              {
+                if (my_messages == NULL)
+                  my_messages = g_ptr_array_new ();
+                g_ptr_array_add (my_messages, control_message);
+              }
+           }
+      }
+
+    if (message->num_control_messages)
+      *message->num_control_messages = my_messages != NULL ? my_messages->len : 0;
+
+    if (message->control_messages)
+      {
+        if (my_messages == NULL)
+          {
+            *message->control_messages = NULL;
+          }
+        else
+          {
+            g_ptr_array_add (my_messages, NULL);
+            *message->control_messages = (GSocketControlMessage **) g_ptr_array_free (my_messages, FALSE);
+          }
+      }
+    else
+      {
+        g_assert (my_messages == NULL);
+      }
+  }
+
+  /* capture the flags */
+  message->flags = msg->msg_flags;
+}
+
 /**
  * g_socket_send_message:
  * @socket: a #GSocket
@@ -3813,85 +4037,26 @@ g_socket_send_message (GSocket                *socket,
 
 #ifndef G_OS_WIN32
   {
+    GOutputMessage output_message;
     struct msghdr msg;
     gssize result;
+    GError *child_error = NULL;
 
-   msg.msg_flags = 0;
+    output_message.address = address;
+    output_message.vectors = vectors;
+    output_message.num_vectors = num_vectors;
+    output_message.bytes_sent = 0;
+    output_message.control_messages = messages;
+    output_message.num_control_messages = num_messages;
 
-    /* name */
-    if (address)
-      {
-       msg.msg_namelen = g_socket_address_get_native_size (address);
-       msg.msg_name = g_alloca (msg.msg_namelen);
-       if (!g_socket_address_to_native (address, msg.msg_name, msg.msg_namelen, error))
-         return -1;
-      }
-    else
+    output_message_to_msghdr (&output_message, NULL, &msg, NULL, &child_error);
+
+    if (child_error != NULL)
       {
-       msg.msg_name = NULL;
-       msg.msg_namelen = 0;
+        g_propagate_error (error, child_error);
+        return -1;
       }
 
-    /* iov */
-    {
-      /* this entire expression will be evaluated at compile time */
-      if (sizeof *msg.msg_iov == sizeof *vectors &&
-         sizeof msg.msg_iov->iov_base == sizeof vectors->buffer &&
-         G_STRUCT_OFFSET (struct iovec, iov_base) ==
-         G_STRUCT_OFFSET (GOutputVector, buffer) &&
-         sizeof msg.msg_iov->iov_len == sizeof vectors->size &&
-         G_STRUCT_OFFSET (struct iovec, iov_len) ==
-         G_STRUCT_OFFSET (GOutputVector, size))
-       /* ABI is compatible */
-       {
-         msg.msg_iov = (struct iovec *) vectors;
-         msg.msg_iovlen = num_vectors;
-       }
-      else
-       /* ABI is incompatible */
-       {
-         gint i;
-
-         msg.msg_iov = g_newa (struct iovec, num_vectors);
-         for (i = 0; i < num_vectors; i++)
-           {
-             msg.msg_iov[i].iov_base = (void *) vectors[i].buffer;
-             msg.msg_iov[i].iov_len = vectors[i].size;
-           }
-         msg.msg_iovlen = num_vectors;
-       }
-    }
-
-    /* control */
-    {
-      struct cmsghdr *cmsg;
-      gint i;
-
-      msg.msg_controllen = 0;
-      for (i = 0; i < num_messages; i++)
-       msg.msg_controllen += CMSG_SPACE (g_socket_control_message_get_size (messages[i]));
-
-      if (msg.msg_controllen == 0)
-        msg.msg_control = NULL;
-      else
-        {
-          msg.msg_control = g_alloca (msg.msg_controllen);
-          memset (msg.msg_control, '\0', msg.msg_controllen);
-        }
-
-      cmsg = CMSG_FIRSTHDR (&msg);
-      for (i = 0; i < num_messages; i++)
-       {
-         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);
-    }
-
     while (1)
       {
        result = sendmsg (socket->priv->fd, &msg, flags | G_SOCKET_DEFAULT_SEND_FLAGS);
@@ -4112,90 +4277,19 @@ g_socket_send_messages_with_blocking (GSocket        *socket,
       {
         GOutputMessage *msg = &messages[i];
         struct msghdr *msg_hdr = &msgvec[i].msg_hdr;
+        GError *child_error = NULL;
 
         msgvec[i].msg_len = 0;
 
-        msg_hdr->msg_flags = 0;
+        output_message_to_msghdr (msg, (i > 0) ? &messages[i - 1] : NULL,
+                                  msg_hdr, (i > 0) ? &msgvec[i - 1].msg_hdr : NULL,
+                                  &child_error);
 
-        /* name */
-        if (i > 0 && msg->address == messages[i-1].address)
+        if (child_error != NULL)
           {
-            msg_hdr->msg_name = msgvec[i-1].msg_hdr.msg_name;
-            msg_hdr->msg_namelen = msgvec[i-1].msg_hdr.msg_namelen;
+            g_propagate_error (error, child_error);
+            return -1;
           }
-        else if (msg->address)
-          {
-            msg_hdr->msg_namelen = g_socket_address_get_native_size (msg->address);
-            msg_hdr->msg_name = g_alloca (msg_hdr->msg_namelen);
-            if (!g_socket_address_to_native (msg->address, msg_hdr->msg_name, msg_hdr->msg_namelen, error))
-              return -1;
-          }
-        else
-          {
-            msg_hdr->msg_name = NULL;
-            msg_hdr->msg_namelen = 0;
-          }
-
-        /* iov */
-        {
-          /* this entire expression will be evaluated at compile time */
-          if (sizeof (struct iovec) == sizeof (GOutputVector) &&
-              sizeof msg_hdr->msg_iov->iov_base == sizeof msg->vectors->buffer &&
-              G_STRUCT_OFFSET (struct iovec, iov_base) ==
-              G_STRUCT_OFFSET (GOutputVector, buffer) &&
-              sizeof msg_hdr->msg_iov->iov_len == sizeof msg->vectors->size &&
-              G_STRUCT_OFFSET (struct iovec, iov_len) ==
-              G_STRUCT_OFFSET (GOutputVector, size))
-            /* ABI is compatible */
-            {
-              msg_hdr->msg_iov = (struct iovec *) msg->vectors;
-              msg_hdr->msg_iovlen = msg->num_vectors;
-            }
-          else
-            /* ABI is incompatible */
-            {
-              gint j;
-
-              msg_hdr->msg_iov = g_newa (struct iovec, msg->num_vectors);
-              for (j = 0; j < msg->num_vectors; j++)
-                {
-                  msg_hdr->msg_iov[j].iov_base = (void *) msg->vectors[j].buffer;
-                  msg_hdr->msg_iov[j].iov_len = msg->vectors[j].size;
-                }
-              msg_hdr->msg_iovlen = msg->num_vectors;
-            }
-        }
-
-        /* control */
-        {
-          struct cmsghdr *cmsg;
-          gint j;
-
-          msg_hdr->msg_controllen = 0;
-          for (j = 0; j < msg->num_control_messages; j++)
-            msg_hdr->msg_controllen += CMSG_SPACE (g_socket_control_message_get_size 
(msg->control_messages[j]));
-
-          if (msg_hdr->msg_controllen == 0)
-            msg_hdr->msg_control = NULL;
-          else
-            {
-              msg_hdr->msg_control = g_alloca (msg_hdr->msg_controllen);
-              memset (msg_hdr->msg_control, '\0', msg_hdr->msg_controllen);
-            }
-
-          cmsg = CMSG_FIRSTHDR (msg_hdr);
-          for (j = 0; j < msg->num_control_messages; j++)
-            {
-              GSocketControlMessage *cm = msg->control_messages[j];
-
-              cmsg->cmsg_level = g_socket_control_message_get_level (cm);
-              cmsg->cmsg_type = g_socket_control_message_get_msg_type (cm);
-              cmsg->cmsg_len = CMSG_LEN (g_socket_control_message_get_size (cm));
-              g_socket_control_message_serialize (cm, CMSG_DATA (cmsg));
-              cmsg = CMSG_NXTHDR (msg_hdr, cmsg);
-            }
-          g_assert (cmsg == NULL);
-        }
       }
 
     num_sent = result = 0;
@@ -4469,68 +4563,28 @@ g_socket_receive_message (GSocket                 *socket,
 
 #ifndef G_OS_WIN32
   {
+    GInputMessage input_message;
     struct msghdr msg;
     gssize result;
-    struct sockaddr_storage one_sockaddr;
-
-    /* name */
-    if (address)
-      {
-       msg.msg_name = &one_sockaddr;
-       msg.msg_namelen = sizeof (struct sockaddr_storage);
-      }
-    else
-      {
-       msg.msg_name = NULL;
-       msg.msg_namelen = 0;
-      }
-
-    /* iov */
-    /* this entire expression will be evaluated at compile time */
-    if (sizeof *msg.msg_iov == sizeof *vectors &&
-       sizeof msg.msg_iov->iov_base == sizeof vectors->buffer &&
-       G_STRUCT_OFFSET (struct iovec, iov_base) ==
-       G_STRUCT_OFFSET (GInputVector, buffer) &&
-       sizeof msg.msg_iov->iov_len == sizeof vectors->size &&
-       G_STRUCT_OFFSET (struct iovec, iov_len) ==
-       G_STRUCT_OFFSET (GInputVector, size))
-      /* ABI is compatible */
-      {
-       msg.msg_iov = (struct iovec *) vectors;
-       msg.msg_iovlen = num_vectors;
-      }
-    else
-      /* ABI is incompatible */
-      {
-       gint i;
-
-       msg.msg_iov = g_newa (struct iovec, num_vectors);
-       for (i = 0; i < num_vectors; i++)
-         {
-           msg.msg_iov[i].iov_base = vectors[i].buffer;
-           msg.msg_iov[i].iov_len = vectors[i].size;
-         }
-       msg.msg_iovlen = num_vectors;
-      }
 
-    /* control */
-    msg.msg_control = g_alloca (2048);
-    msg.msg_controllen = 2048;
-
-    /* flags */
-    if (flags != NULL)
-      msg.msg_flags = *flags;
-    else
-      msg.msg_flags = 0;
+    input_message.address = address;
+    input_message.vectors = vectors;
+    input_message.num_vectors = num_vectors;
+    input_message.bytes_received = 0;
+    input_message.flags = (flags != NULL) ? *flags : 0;
+    input_message.control_messages = messages;
+    input_message.num_control_messages = (guint *) num_messages;
 
     /* We always set the close-on-exec flag so we don't leak file
      * descriptors into child processes.  Note that gunixfdmessage.c
      * will later call fcntl (fd, FD_CLOEXEC), but that isn't atomic.
      */
 #ifdef MSG_CMSG_CLOEXEC
-    msg.msg_flags |= MSG_CMSG_CLOEXEC;
+    input_message.flags |= MSG_CMSG_CLOEXEC;
 #endif
 
+    input_message_to_msghdr (&input_message, &msg);
+
     /* do it */
     while (1)
       {
@@ -4568,72 +4622,10 @@ g_socket_receive_message (GSocket                 *socket,
        break;
       }
 
-    /* decode address */
-    if (address != NULL)
-      {
-        *address = cache_recv_address (socket, msg.msg_name, msg.msg_namelen);
-      }
-
-    /* decode control messages */
-    {
-      GPtrArray *my_messages = NULL;
-      struct cmsghdr *cmsg;
-
-      if (msg.msg_controllen >= sizeof (struct cmsghdr))
-        {
-          for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg))
-            {
-              GSocketControlMessage *message;
-
-              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 */
-                continue;
-
-              if (messages == NULL)
-                {
-                  /* we have to do it this way if the user ignores the
-                   * messages so that we will close any received fds.
-                   */
-                  g_object_unref (message);
-                }
-              else
-                {
-                  if (my_messages == NULL)
-                    my_messages = g_ptr_array_new ();
-                  g_ptr_array_add (my_messages, message);
-                }
-            }
-        }
-
-      if (num_messages)
-       *num_messages = my_messages != NULL ? my_messages->len : 0;
-
-      if (messages)
-       {
-         if (my_messages == NULL)
-           {
-             *messages = NULL;
-           }
-         else
-           {
-             g_ptr_array_add (my_messages, NULL);
-             *messages = (GSocketControlMessage **) g_ptr_array_free (my_messages, FALSE);
-           }
-       }
-      else
-       {
-         g_assert (my_messages == NULL);
-       }
-    }
+    input_message_from_msghdr (&msg, &input_message, socket);
 
-    /* capture the flags */
     if (flags != NULL)
-      *flags = msg.msg_flags;
+      *flags = input_message.flags;
 
     return result;
   }


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