[telepathy-gabble/master] sync Gibber with Salut

Guillaume Desmottes guillaume.desmottes at collabora.co.uk
Fri May 15 03:45:03 PDT 2009


---
 lib/gibber/gibber-fd-transport.c   |    4 +-
 lib/gibber/gibber-fd-transport.h   |    5 +
 lib/gibber/gibber-listener.c       |    9 +-
 lib/gibber/gibber-unix-transport.c |  192 ++++++++++++++++++++++++++++++++++++
 lib/gibber/gibber-unix-transport.h |   33 ++++++
 5 files changed, 237 insertions(+), 6 deletions(-)

diff --git a/lib/gibber/gibber-fd-transport.c b/lib/gibber/gibber-fd-transport.c
index faf0c10..8babcfc 100644
--- a/lib/gibber/gibber-fd-transport.c
+++ b/lib/gibber/gibber-fd-transport.c
@@ -100,8 +100,6 @@ gibber_fd_transport_init (GibberFdTransport *self)
 
 static void gibber_fd_transport_dispose (GObject *object);
 static void gibber_fd_transport_finalize (GObject *object);
-static GibberFdIOResult gibber_fd_transport_read (GibberFdTransport *transport,
-    GIOChannel *channel, GError **error);
 static GibberFdIOResult gibber_fd_transport_write (
    GibberFdTransport *fd_transport, GIOChannel *channel, const guint8 *data,
    int len, gsize *written, GError **error);
@@ -386,7 +384,7 @@ gibber_fd_transport_write (GibberFdTransport *fd_transport,
 
 #define BUFSIZE 1024
 
-static GibberFdIOResult
+GibberFdIOResult
 gibber_fd_transport_read (GibberFdTransport *transport,
     GIOChannel *channel, GError **error)
 {
diff --git a/lib/gibber/gibber-fd-transport.h b/lib/gibber/gibber-fd-transport.h
index 813947f..0b852d5 100644
--- a/lib/gibber/gibber-fd-transport.h
+++ b/lib/gibber/gibber-fd-transport.h
@@ -87,6 +87,11 @@ GType gibber_fd_transport_get_type (void);
 
 void
 gibber_fd_transport_set_fd (GibberFdTransport *fd_transport, int fd);
+
+GibberFdIOResult gibber_fd_transport_read (GibberFdTransport *transport,
+    GIOChannel *channel,
+    GError **error);
+
 G_END_DECLS
 
 #endif /* #ifndef __GIBBER_FD_TRANSPORT_H__*/
diff --git a/lib/gibber/gibber-listener.c b/lib/gibber/gibber-listener.c
index dedc2b6..6b15446 100644
--- a/lib/gibber/gibber-listener.c
+++ b/lib/gibber/gibber-listener.c
@@ -33,6 +33,7 @@
 
 #include "gibber-listener.h"
 #include "gibber-fd-transport.h"
+#include "gibber-unix-transport.h"
 #include "gibber-util.h"
 
 #define DEBUG_FLAG DEBUG_NET
@@ -186,11 +187,10 @@ listener_io_in_cb (GIOChannel *source,
   nfd = accept (fd, (struct sockaddr *) &addr, &addrlen);
   gibber_normalize_address (&addr);
 
-  transport = g_object_new (GIBBER_TYPE_FD_TRANSPORT, NULL);
-  gibber_fd_transport_set_fd (transport, nfd);
-
   if (addr.ss_family == AF_UNIX)
     {
+      transport = GIBBER_FD_TRANSPORT (gibber_unix_transport_new_from_fd (nfd));
+
       /* UNIX sockets doesn't have port */
       ret = getnameinfo ((struct sockaddr *) &addr, addrlen,
           host, NI_MAXHOST, NULL, 0,
@@ -200,6 +200,9 @@ listener_io_in_cb (GIOChannel *source,
     }
   else
     {
+      transport = g_object_new (GIBBER_TYPE_FD_TRANSPORT, NULL);
+      gibber_fd_transport_set_fd (transport, nfd);
+
       ret = getnameinfo ((struct sockaddr *) &addr, addrlen,
           host, NI_MAXHOST, port, NI_MAXSERV,
           NI_NUMERICHOST | NI_NUMERICSERV);
diff --git a/lib/gibber/gibber-unix-transport.c b/lib/gibber/gibber-unix-transport.c
index b1a6641..244f468 100644
--- a/lib/gibber/gibber-unix-transport.c
+++ b/lib/gibber/gibber-unix-transport.c
@@ -19,6 +19,9 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+/* needed for struct ucred */
+#define _GNU_SOURCE
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -55,6 +58,10 @@ typedef struct _GibberUnixTransportPrivate GibberUnixTransportPrivate;
 struct _GibberUnixTransportPrivate
 {
   gboolean incoming;
+
+  GibberUnixTransportRecvCredentialsCb recv_creds_cb;
+  gpointer recv_creds_data;
+
   gboolean dispose_has_run;
 };
 
@@ -72,17 +79,27 @@ gibber_unix_transport_init (GibberUnixTransport *self)
 }
 
 static void gibber_unix_transport_dispose (GObject *object);
+static GibberFdIOResult gibber_unix_transport_read (
+    GibberFdTransport *transport,
+    GIOChannel *channel,
+    GError **error);
+
 static void
 gibber_unix_transport_class_init (
     GibberUnixTransportClass *gibber_unix_transport_class)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (gibber_unix_transport_class);
+  GibberFdTransportClass *fd_class = GIBBER_FD_TRANSPORT_CLASS (
+      gibber_unix_transport_class);
 
   g_type_class_add_private (gibber_unix_transport_class,
                             sizeof (GibberUnixTransportPrivate));
 
   object_class->dispose = gibber_unix_transport_dispose;
   object_class->finalize = gibber_unix_transport_finalize;
+
+  /* override GibberFdTransport's read */
+  fd_class->read = gibber_unix_transport_read;
 }
 
 void
@@ -96,6 +113,9 @@ gibber_unix_transport_dispose (GObject *object)
 
   priv->dispose_has_run = TRUE;
 
+  priv->recv_creds_cb = NULL;
+  priv->recv_creds_data = NULL;
+
   if (G_OBJECT_CLASS (gibber_unix_transport_parent_class)->dispose)
     G_OBJECT_CLASS (gibber_unix_transport_parent_class)->dispose (object);
 }
@@ -164,3 +184,175 @@ failed:
   return FALSE;
 }
 
+GibberUnixTransport *
+gibber_unix_transport_new_from_fd (int fd)
+{
+  GibberUnixTransport *transport;
+
+  transport = gibber_unix_transport_new ();
+  gibber_fd_transport_set_fd (GIBBER_FD_TRANSPORT (transport), fd);
+  return transport;
+}
+
+gboolean
+gibber_unix_transport_send_credentials (GibberUnixTransport *transport,
+    const guint8 *data,
+    gsize size)
+{
+  int fd, ret;
+  struct ucred *cred;
+  struct msghdr msg;
+  struct cmsghdr *ch;
+  struct iovec iov;
+  char buffer[CMSG_SPACE (sizeof (struct ucred))];
+
+  DEBUG ("send credentials");
+  fd = GIBBER_FD_TRANSPORT (transport)->fd;
+
+  /* Set the message payload */
+  memset (&iov, 0, sizeof (iov));
+  iov.iov_base = (void *) data;
+  iov.iov_len = size;
+
+  memset (&msg, 0, sizeof msg);
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = buffer;
+  msg.msg_controllen = sizeof (buffer);
+
+  /* Set the credentials */
+  ch = CMSG_FIRSTHDR (&msg);
+  ch->cmsg_len = CMSG_LEN (sizeof (struct ucred));
+  ch->cmsg_level = SOL_SOCKET;
+  ch->cmsg_type = SCM_CREDENTIALS;
+
+  cred = (struct ucred *) CMSG_DATA (ch);
+  cred->pid = getpid ();
+  cred->uid = getuid ();
+  cred->gid = getgid ();
+
+  ret = sendmsg (fd, &msg, 0);
+  if (ret == -1)
+    {
+      DEBUG ("sendmsg failed: %s", g_strerror (errno));
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+#define BUFSIZE 1024
+
+static GibberFdIOResult
+gibber_unix_transport_read (GibberFdTransport *transport,
+    GIOChannel *channel,
+    GError **error)
+{
+  GibberUnixTransport *self = GIBBER_UNIX_TRANSPORT (transport);
+  GibberUnixTransportPrivate *priv = GIBBER_UNIX_TRANSPORT_GET_PRIVATE (self);
+  int fd;
+  guint8 buffer[BUFSIZE];
+  ssize_t bytes_read;
+  GibberBuffer buf;
+  struct iovec iov;
+  struct msghdr msg;
+  char control[CMSG_SPACE (sizeof (struct ucred))];
+  struct cmsghdr *ch;
+  struct ucred *cred;
+  int opt;
+
+  if (priv->recv_creds_cb == NULL)
+    return gibber_fd_transport_read (transport, channel, error);
+
+  /* We are waiting for credentials */
+  fd = transport->fd;
+
+  /* set SO_PASSCRED flag */
+  opt = 1;
+  setsockopt (fd, SOL_SOCKET, SO_PASSCRED, &opt, sizeof (opt));
+
+  memset (buffer, 0, sizeof (buffer));
+  memset (&iov, 0, sizeof (iov));
+  iov.iov_base = buffer;
+  iov.iov_len = sizeof (buffer);
+
+  memset (&msg, 0, sizeof (msg));
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = control;
+  msg.msg_controllen = sizeof (control);
+
+  bytes_read = recvmsg (fd, &msg, 0);
+
+  if (bytes_read == -1)
+    {
+      GError *err = NULL;
+
+      g_set_error_literal (&err, G_IO_CHANNEL_ERROR,
+          g_io_channel_error_from_errno (errno), "recvmsg failed");
+
+      priv->recv_creds_cb (self, NULL, NULL, err, priv->recv_creds_data);
+      g_propagate_error (error, err);
+
+      priv->recv_creds_cb = NULL;
+      priv->recv_creds_data = NULL;
+      return GIBBER_FD_IO_RESULT_ERROR;
+    }
+
+  /* unset SO_PASSCRED flag */
+  opt = 0;
+  setsockopt (fd, SOL_SOCKET, SO_PASSCRED, &opt, sizeof (opt));
+
+  buf.data = buffer;
+  buf.length = bytes_read;
+
+  /* extract the credentials */
+  ch = CMSG_FIRSTHDR (&msg);
+  if (ch == NULL)
+    {
+      GError *err = NULL;
+
+      DEBUG ("Message doesn't contain credentials");
+
+      g_set_error_literal (&err, GIBBER_UNIX_TRANSPORT_ERROR,
+          GIBBER_UNIX_TRANSPORT_ERROR_NO_CREDENTIALS,
+          "no credentials received");
+
+      priv->recv_creds_cb (self, &buf, NULL, err, priv->recv_creds_data);
+      g_error_free (err);
+    }
+  else
+    {
+      GibberCredentials credentials;
+
+      cred = (struct ucred *) CMSG_DATA (ch);
+      credentials.pid = cred->pid;
+      credentials.uid = cred->uid;
+      credentials.gid = cred->gid;
+
+      priv->recv_creds_cb (self, &buf, &credentials, NULL,
+          priv->recv_creds_data);
+    }
+
+  priv->recv_creds_cb = NULL;
+  priv->recv_creds_data = NULL;
+  return GIBBER_FD_IO_RESULT_SUCCESS;
+}
+
+gboolean
+gibber_unix_transport_recv_credentials (GibberUnixTransport *self,
+    GibberUnixTransportRecvCredentialsCb callback,
+    gpointer user_data)
+{
+  GibberUnixTransportPrivate *priv = GIBBER_UNIX_TRANSPORT_GET_PRIVATE (self);
+
+  if (priv->recv_creds_cb != NULL)
+    {
+      DEBUG ("already waiting for credentials");
+      return FALSE;
+    }
+
+  priv->recv_creds_cb = callback;
+  priv->recv_creds_data = user_data;
+  return TRUE;
+}
diff --git a/lib/gibber/gibber-unix-transport.h b/lib/gibber/gibber-unix-transport.h
index e7ca190..b89a0dd 100644
--- a/lib/gibber/gibber-unix-transport.h
+++ b/lib/gibber/gibber-unix-transport.h
@@ -24,6 +24,16 @@
 
 #include <glib-object.h>
 
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <sys/un.h>
+
 #include "gibber-fd-transport.h"
 
 G_BEGIN_DECLS
@@ -35,6 +45,7 @@ typedef enum
 {
   GIBBER_UNIX_TRANSPORT_ERROR_CONNECT_FAILED,
   GIBBER_UNIX_TRANSPORT_ERROR_FAILED,
+  GIBBER_UNIX_TRANSPORT_ERROR_NO_CREDENTIALS,
 } GibberUnixTransportError;
 
 typedef struct _GibberUnixTransport GibberUnixTransport;
@@ -70,9 +81,31 @@ GType gibber_unix_transport_get_type (void);
 
 GibberUnixTransport * gibber_unix_transport_new (void);
 
+GibberUnixTransport * gibber_unix_transport_new_from_fd (int fd);
+
 gboolean gibber_unix_transport_connect (GibberUnixTransport *transport,
     const gchar *path, GError **error);
 
+gboolean gibber_unix_transport_send_credentials (GibberUnixTransport *transport,
+    const guint8 *data, gsize size);
+
+typedef struct {
+    pid_t pid;
+    uid_t uid;
+    gid_t gid;
+} GibberCredentials;
+
+typedef void (*GibberUnixTransportRecvCredentialsCb) (
+    GibberUnixTransport *transport,
+    GibberBuffer *buffer,
+    GibberCredentials *credentials,
+    GError *error,
+    gpointer user_data);
+
+gboolean gibber_unix_transport_recv_credentials (GibberUnixTransport *transport,
+    GibberUnixTransportRecvCredentialsCb callback,
+    gpointer user_data);
+
 G_END_DECLS
 
 #endif /* #ifndef __GIBBER_UNIX_TRANSPORT_H__*/
-- 
1.5.6.5



More information about the telepathy-commits mailing list