[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