[Telepathy-commits] [telepathy-gabble/master] Import gibber transports and listerner

Guillaume Desmottes guillaume.desmottes at collabora.co.uk
Mon Dec 15 03:28:11 PST 2008


---
 lib/Makefile.am                         |    1 +
 lib/gibber/Makefile.am                  |   80 +++++
 lib/gibber/gibber-debug.c               |   95 ++++++
 lib/gibber/gibber-debug.h               |   99 ++++++
 lib/gibber/gibber-fd-transport.c        |  461 +++++++++++++++++++++++++++
 lib/gibber/gibber-fd-transport.h        |   83 +++++
 lib/gibber/gibber-linklocal-transport.c |  194 ++++++++++++
 lib/gibber/gibber-linklocal-transport.h |   84 +++++
 lib/gibber/gibber-listener.c            |  524 +++++++++++++++++++++++++++++++
 lib/gibber/gibber-listener.h            |   99 ++++++
 lib/gibber/gibber-tcp-transport.c       |  181 +++++++++++
 lib/gibber/gibber-tcp-transport.h       |   67 ++++
 lib/gibber/gibber-transport.c           |  284 +++++++++++++++++
 lib/gibber/gibber-transport.h           |  125 ++++++++
 lib/gibber/gibber-unix-transport.c      |  166 ++++++++++
 lib/gibber/gibber-unix-transport.h      |   78 +++++
 lib/gibber/gibber-util.c                |   72 +++++
 lib/gibber/gibber-util.h                |   34 ++
 18 files changed, 2727 insertions(+), 0 deletions(-)
 create mode 100644 lib/Makefile.am
 create mode 100644 lib/gibber/Makefile.am
 create mode 100644 lib/gibber/gibber-debug.c
 create mode 100644 lib/gibber/gibber-debug.h
 create mode 100644 lib/gibber/gibber-fd-transport.c
 create mode 100644 lib/gibber/gibber-fd-transport.h
 create mode 100644 lib/gibber/gibber-linklocal-transport.c
 create mode 100644 lib/gibber/gibber-linklocal-transport.h
 create mode 100644 lib/gibber/gibber-listener.c
 create mode 100644 lib/gibber/gibber-listener.h
 create mode 100644 lib/gibber/gibber-tcp-transport.c
 create mode 100644 lib/gibber/gibber-tcp-transport.h
 create mode 100644 lib/gibber/gibber-transport.c
 create mode 100644 lib/gibber/gibber-transport.h
 create mode 100644 lib/gibber/gibber-unix-transport.c
 create mode 100644 lib/gibber/gibber-unix-transport.h
 create mode 100644 lib/gibber/gibber-util.c
 create mode 100644 lib/gibber/gibber-util.h

diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..aad4b38
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS=gibber
diff --git a/lib/gibber/Makefile.am b/lib/gibber/Makefile.am
new file mode 100644
index 0000000..4854dbf
--- /dev/null
+++ b/lib/gibber/Makefile.am
@@ -0,0 +1,80 @@
+noinst_LTLIBRARIES = libgibber.la
+
+BUILT_SOURCES = \
+  gibber-signals-marshal.list \
+  gibber-signals-marshal.h \
+  gibber-signals-marshal.c
+
+HANDWRITTEN_SOURCES =             \
+  gibber-debug.c                  \
+  gibber-debug.h                  \
+  gibber-transport.c              \
+  gibber-transport.h              \
+  gibber-fd-transport.c           \
+  gibber-fd-transport.h           \
+  gibber-tcp-transport.c          \
+  gibber-tcp-transport.h          \
+  gibber-unix-transport.c         \
+  gibber-unix-transport.h         \
+  gibber-linklocal-transport.c    \
+  gibber-linklocal-transport.h    \
+  gibber-listener.c               \
+  gibber-listener.h               \
+  gibber-util.h                   \
+  gibber-util.c
+
+libgibber_la_SOURCES = $(HANDWRITTEN_SOURCES) $(BUILT_SOURCES)
+
+# Coding style checks
+check_c_sources = \
+    $(HANDWRITTEN_SOURCES)
+
+include $(top_srcdir)/tools/check-coding-style.mk
+check-local: check-coding-style
+
+CLEANFILES=$(BUILT_SOURCES)
+dist-hook:
+	$(shell for x in $(BUILT_SOURCES); do rm -f $(distdir)/$$x ; done)
+
+gibber-signals-marshal.list: $(HANDWRITTEN_SOURCES) Makefile.am
+	( cd $(srcdir) && \
+	sed -n -e 's/.*_gibber_signals_marshal_\([[:upper:][:digit:]]*__[[:upper:][:digit:]_]*\).*/\1/p' \
+	$(HANDWRITTEN_SOURCES) ) \
+	| sed -e 's/__/:/' -e 'y/_/,/' | sort -u > $@.tmp
+	if cmp -s $@.tmp $@; then \
+		rm $@.tmp; \
+		touch $@; \
+	else \
+		mv $@.tmp $@; \
+	fi
+
+%-signals-marshal.h: %-signals-marshal.list Makefile.am
+	glib-genmarshal --header --prefix=_$(subst -,_,$*)_signals_marshal $< > $@
+
+%-signals-marshal.c: %-signals-marshal.list Makefile.am
+	{ echo '#include "$*-signals-marshal.h"' && \
+	glib-genmarshal --body --prefix=_$(subst -,_,$*)_signals_marshal $< ; \
+	} > $@
+
+
+AM_CFLAGS = $(ERROR_CFLAGS) $(GCOV_CFLAGS) @GLIB_CFLAGS@
+
+AM_LDFLAGS = $(GCOV_LIBS) @GLIB_LIBS@ @RESOLV_LIBS@
+
+# rules for making the glib enum objects
+%-enumtypes.h: %.h Makefile.in
+	glib-mkenums \
+	--fhead "#ifndef __$(shell echo $* | tr [:lower:]- [:upper:]_)_ENUM_TYPES_H__\n#define __$(shell echo $* | tr [:lower:]- [:upper:]_)_ENUM_TYPES_H__\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \
+	--fprod "/* enumerations from \"@filename@\" */\n" \
+	--vhead "GType @enum_name at _get_type (void);\n#define $(shell echo $* | tr [:lower:]- [:upper:]_ | sed 's/_.*//')_TYPE_ at ENUMSHORT@ (@enum_name at _get_type())\n"         \
+	--ftail "G_END_DECLS\n\n#endif /* __$(shell echo $* | tr [:lower:]- [:upper:]_)_ENUM_TYPES_H__ */" \
+	$< > $@
+
+%-enumtypes.c: %.h Makefile.in
+	glib-mkenums \
+	--fhead "#include <$*.h>\n#include <$*-enumtypes.h>" \
+	--fprod "\n/* enumerations from \"@filename@\" */" \
+	--vhead "GType\n at enum_name@_get_type (void)\n{\n  static GType etype = 0;\n  if (etype == 0) {\n    static const G at Type@Value values[] = {"     \
+	--vprod "      { @VALUENAME@, \"@VALUENAME@\", \"@VALUENAME@\" }," \
+	--vtail "      { 0, NULL, NULL }\n    };\n    etype = g_ at type@_register_static (\"@EnumName@\", values);\n  }\n  return etype;\n}\n" \
+	$< > $@
diff --git a/lib/gibber/gibber-debug.c b/lib/gibber/gibber-debug.c
new file mode 100644
index 0000000..942d82a
--- /dev/null
+++ b/lib/gibber/gibber-debug.c
@@ -0,0 +1,95 @@
+
+#include <stdarg.h>
+
+#include <glib.h>
+
+#include "gibber-debug.h"
+
+static DebugFlags flags = 0;
+static gboolean initialized = FALSE;
+
+static GDebugKey keys[] = {
+  { "transport",         DEBUG_TRANSPORT         },
+  { "net",               DEBUG_NET               },
+  { "xmpp",              DEBUG_XMPP              },
+  { "xmpp-reader",       DEBUG_XMPP_READER       },
+  { "xmpp-writer",       DEBUG_XMPP_WRITER       },
+  { "sasl",              DEBUG_SASL              },
+  { "ssl",               DEBUG_SSL               },
+  { "rmulticast",        DEBUG_RMULTICAST        },
+  { "rmulticast-sender", DEBUG_RMULTICAST_SENDER },
+  { "muc-connection",    DEBUG_MUC_CONNECTION    },
+  { "bytestream",        DEBUG_BYTESTREAM        },
+  { "ft",                DEBUG_FILE_TRANSFER     },
+  { "all",               ~0                      },
+  { 0, },
+};
+
+void gibber_debug_set_flags_from_env ()
+{
+  guint nkeys;
+  const gchar *flags_string;
+
+  for (nkeys = 0; keys[nkeys].value; nkeys++);
+
+  flags_string = g_getenv ("GIBBER_DEBUG");
+
+  if (flags_string)
+    gibber_debug_set_flags (g_parse_debug_string (flags_string, keys, nkeys));
+
+  initialized = TRUE;
+}
+
+void gibber_debug_set_flags (DebugFlags new_flags)
+{
+  flags |= new_flags;
+  initialized = TRUE;
+}
+
+gboolean gibber_debug_flag_is_set (DebugFlags flag)
+{
+  return flag & flags;
+}
+
+void gibber_debug (DebugFlags flag,
+                   const gchar *format,
+                   ...)
+{
+  if (G_UNLIKELY(!initialized))
+    gibber_debug_set_flags_from_env ();
+  if (flag & flags)
+    {
+      va_list args;
+      va_start (args, format);
+      g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format, args);
+      va_end (args);
+    }
+}
+
+#if 0
+void
+gibber_debug_stanza (DebugFlags flag,
+                     GibberXmppStanza *stanza,
+                     const gchar *format,
+                     ...)
+{
+  if (G_UNLIKELY(!initialized))
+    gibber_debug_set_flags_from_env ();
+  if (flag & flags)
+    {
+      va_list args;
+      gchar *msg, *node_str;
+
+      va_start (args, format);
+      msg = g_strdup_vprintf (format, args);
+      va_end (args);
+
+      node_str = gibber_xmpp_node_to_string (stanza->node);
+
+      g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s\n%s", msg, node_str);
+
+      g_free (msg);
+      g_free (node_str);
+    }
+}
+#endif
diff --git a/lib/gibber/gibber-debug.h b/lib/gibber/gibber-debug.h
new file mode 100644
index 0000000..d77b508
--- /dev/null
+++ b/lib/gibber/gibber-debug.h
@@ -0,0 +1,99 @@
+
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+
+#include "config.h"
+
+#include <glib.h>
+
+#if 0
+#include "gibber-xmpp-stanza.h"
+#endif
+
+#ifdef ENABLE_DEBUG
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+  DEBUG_TRANSPORT         = 1 << 0,
+  DEBUG_NET               = 1 << 1,
+  DEBUG_XMPP_READER       = 1 << 2,
+  DEBUG_XMPP_WRITER       = 1 << 3,
+  DEBUG_SASL              = 1 << 4,
+  DEBUG_SSL               = 1 << 5,
+  DEBUG_RMULTICAST        = 1 << 6,
+  DEBUG_RMULTICAST_SENDER = 1 << 7,
+  DEBUG_MUC_CONNECTION    = 1 << 8,
+  DEBUG_BYTESTREAM        = 1 << 9,
+  DEBUG_FILE_TRANSFER     = 1 << 10,
+} DebugFlags;
+
+#define DEBUG_XMPP (DEBUG_XMPP_READER | DEBUG_XMPP_WRITER)
+
+void gibber_debug_set_flags_from_env (void);
+void gibber_debug_set_flags (DebugFlags flags);
+gboolean gibber_debug_flag_is_set (DebugFlags flag);
+void gibber_debug (DebugFlags flag, const gchar *format, ...)
+    G_GNUC_PRINTF (2, 3);
+#if 0
+void gibber_debug_stanza (DebugFlags flag, GibberXmppStanza *stanza,
+    const gchar *format, ...)
+    G_GNUC_PRINTF (3, 4);
+#endif
+
+#define gibber_goto_if_reached(label) G_STMT_START{ \
+    g_log (G_LOG_DOMAIN, \
+        G_LOG_LEVEL_CRITICAL, \
+        "file %s: line %d: should not be reached", \
+        __FILE__, \
+        __LINE__); \
+    goto label; }G_STMT_END;
+
+#define gibber_goto_if_fail(expr, label)  G_STMT_START{ \
+    if (expr) {} \
+    else \
+      { \
+        g_log (G_LOG_DOMAIN, \
+            G_LOG_LEVEL_CRITICAL, \
+            "file %s: line %d: assertion `%s' failed", \
+            __FILE__, \
+            __LINE__, \
+            #expr); \
+        goto label; \
+      }; }G_STMT_END
+
+
+#ifdef DEBUG_FLAG
+
+#define DEBUG(format, ...) \
+  gibber_debug (DEBUG_FLAG, "%s: " format, G_STRFUNC, ##__VA_ARGS__)
+
+#define DEBUG_STANZA(stanza, format, ...) \
+  gibber_debug_stanza (DEBUG_FLAG, stanza, "%s: " format, G_STRFUNC,\
+      ##__VA_ARGS__)
+
+#define DEBUGGING debug_flag_is_set(DEBUG_FLAG)
+
+#endif /* DEBUG_FLAG */
+
+#else /* ENABLE_DEBUG */
+
+#ifdef DEBUG_FLAG
+
+#define DEBUG(format, ...)
+
+#define DEBUG_STANZA(stanza, format, ...)
+
+#define DEBUGGING 0
+
+#define NODE_DEBUG(n, s)
+
+#endif /* DEBUG_FLAG */
+
+#endif /* ENABLE_DEBUG */
+
+G_END_DECLS
+
+#endif
+
diff --git a/lib/gibber/gibber-fd-transport.c b/lib/gibber/gibber-fd-transport.c
new file mode 100644
index 0000000..3e678b1
--- /dev/null
+++ b/lib/gibber/gibber-fd-transport.c
@@ -0,0 +1,461 @@
+/*
+ * gibber-fd-transport.c - Source for GibberFdTransport
+ * Copyright (C) 2006-2007 Collabora Ltd.
+ *   @author: Sjoerd Simons <sjoerd.simons at collabora.co.uk>
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+#include "gibber-fd-transport.h"
+
+#define DEBUG_FLAG DEBUG_NET
+#include "gibber-debug.h"
+
+static gboolean _channel_io_out (GIOChannel *source,
+    GIOCondition condition, gpointer data);
+
+
+static gboolean gibber_fd_transport_send (GibberTransport *transport,
+    const guint8 *data, gsize size, GError **error);
+
+static void gibber_fd_transport_disconnect (GibberTransport *transport);
+
+static gboolean gibber_fd_transport_get_sockaddr (GibberTransport *transport,
+    struct sockaddr_storage *addr, socklen_t *len);
+
+static void _do_disconnect (GibberFdTransport *self);
+
+static gboolean gibber_fd_transport_buffer_is_empty (
+    GibberTransport *transport);
+
+static void gibber_fd_transport_block_receiving (GibberTransport *transport,
+    gboolean block);
+
+G_DEFINE_TYPE(GibberFdTransport, gibber_fd_transport, GIBBER_TYPE_TRANSPORT)
+
+/* private structure */
+typedef struct _GibberFdTransportPrivate GibberFdTransportPrivate;
+
+struct _GibberFdTransportPrivate
+{
+  GIOChannel *channel;
+  gboolean dispose_has_run;
+  guint watch_in;
+  guint watch_out;
+  guint watch_err;
+  GString *output_buffer;
+};
+
+#define GIBBER_FD_TRANSPORT_GET_PRIVATE(o)  \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), GIBBER_TYPE_FD_TRANSPORT, \
+   GibberFdTransportPrivate))
+
+
+static void
+gibber_fd_transport_init (GibberFdTransport *self)
+{
+  GibberFdTransportPrivate *priv = GIBBER_FD_TRANSPORT_GET_PRIVATE (self);
+  self->fd = -1;
+  priv->channel = NULL;
+  priv->output_buffer = NULL;
+  priv->watch_in = 0;
+  priv->watch_out = 0;
+  priv->watch_err = 0;
+}
+
+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);
+
+static void
+gibber_fd_transport_class_init (
+    GibberFdTransportClass *gibber_fd_transport_class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (gibber_fd_transport_class);
+  GibberTransportClass *transport_class =
+    GIBBER_TRANSPORT_CLASS (gibber_fd_transport_class);
+
+  g_type_class_add_private (gibber_fd_transport_class,
+                            sizeof (GibberFdTransportPrivate));
+
+  object_class->dispose = gibber_fd_transport_dispose;
+  object_class->finalize = gibber_fd_transport_finalize;
+
+  transport_class->send = gibber_fd_transport_send;
+  transport_class->disconnect = gibber_fd_transport_disconnect;
+  transport_class->get_sockaddr = gibber_fd_transport_get_sockaddr;
+  transport_class->buffer_is_empty = gibber_fd_transport_buffer_is_empty;
+  transport_class->block_receiving = gibber_fd_transport_block_receiving;
+
+  gibber_fd_transport_class->read = gibber_fd_transport_read;
+  gibber_fd_transport_class->write = gibber_fd_transport_write;
+}
+
+void
+gibber_fd_transport_dispose (GObject *object)
+{
+  GibberFdTransport *self = GIBBER_FD_TRANSPORT (object);
+  GibberFdTransportPrivate *priv = GIBBER_FD_TRANSPORT_GET_PRIVATE (self);
+
+  if (priv->dispose_has_run)
+    return;
+
+  priv->dispose_has_run = TRUE;
+
+  _do_disconnect (self);
+
+  if (G_OBJECT_CLASS (gibber_fd_transport_parent_class)->dispose)
+    G_OBJECT_CLASS (gibber_fd_transport_parent_class)->dispose (object);
+}
+
+void
+gibber_fd_transport_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (gibber_fd_transport_parent_class)->finalize (object);
+}
+
+static void
+_do_disconnect (GibberFdTransport *self)
+{
+  GibberFdTransportPrivate *priv = GIBBER_FD_TRANSPORT_GET_PRIVATE (self);
+
+  if (GIBBER_TRANSPORT(self)->state == GIBBER_TRANSPORT_DISCONNECTED)
+    {
+      return;
+    }
+
+  DEBUG ("Closing the fd transport");
+
+  if (priv->channel != NULL)
+    {
+      if (priv->watch_in != 0)
+        g_source_remove (priv->watch_in);
+
+      if (priv->watch_out)
+        g_source_remove (priv->watch_out);
+
+      g_source_remove (priv->watch_err);
+      g_io_channel_shutdown (priv->channel, FALSE, NULL);
+      g_io_channel_unref (priv->channel);
+      priv->channel = NULL;
+    }
+  else
+    {
+      close (self->fd);
+    }
+  self->fd = -1;
+
+  if (priv->output_buffer)
+    {
+      g_string_free (priv->output_buffer, TRUE);
+      priv->output_buffer = NULL;
+    }
+
+  if (!priv->dispose_has_run)
+    /* If we are disposing we don't care about the state anymore */
+    gibber_transport_set_state (GIBBER_TRANSPORT (self),
+        GIBBER_TRANSPORT_DISCONNECTED);
+}
+
+static gboolean
+_try_write (GibberFdTransport *self, const guint8 *data, int len,
+    gsize *written)
+{
+  GibberFdTransportPrivate *priv = GIBBER_FD_TRANSPORT_GET_PRIVATE (self);
+  GibberFdTransportClass *cls = GIBBER_FD_TRANSPORT_GET_CLASS (self);
+  GibberFdIOResult result;
+  GError *error = NULL;
+
+  result = cls->write (self, priv->channel, data, len, written, &error);
+
+  switch (result)
+    {
+      case GIBBER_FD_IO_RESULT_SUCCESS:
+      case GIBBER_FD_IO_RESULT_AGAIN:
+        break;
+      case GIBBER_FD_IO_RESULT_ERROR:
+        gibber_transport_emit_error (GIBBER_TRANSPORT (self), error);
+        /* fallthrough */
+      case GIBBER_FD_IO_RESULT_EOF:
+        DEBUG ("Writing data failed, closing the transport");
+        _do_disconnect (self);
+
+        return FALSE;
+        break;
+    }
+
+    return TRUE;
+}
+
+static void
+_writeout (GibberFdTransport *self, const guint8 *data, gsize len)
+{
+  GibberFdTransportPrivate *priv = GIBBER_FD_TRANSPORT_GET_PRIVATE (self);
+  gsize written = 0;
+
+  DEBUG ("Writing out %" G_GSIZE_FORMAT " bytes", len);
+  if (priv->output_buffer == NULL || priv->output_buffer->len == 0)
+    {
+      /* We've got nothing buffer yet so try to write out directly */
+      if (!_try_write (self, data, len, &written))
+        {
+          return;
+        }
+    }
+
+  if (written == len)
+    {
+      gibber_transport_emit_buffer_empty (GIBBER_TRANSPORT (self));
+      return;
+    }
+
+  if (priv->output_buffer)
+    {
+      g_string_append_len (priv->output_buffer, (gchar *)data + written,
+        len - written);
+    }
+  else
+    {
+      priv->output_buffer = g_string_new_len ((gchar *)data + written,
+          len - written);
+    }
+
+  if (!priv->watch_out)
+    {
+      priv->watch_out =
+        g_io_add_watch (priv->channel, G_IO_OUT, _channel_io_out, self);
+    }
+}
+
+static gboolean
+_channel_io_in (GIOChannel *source, GIOCondition condition, gpointer data)
+{
+  GibberFdTransport *self = GIBBER_FD_TRANSPORT (data);
+  GibberFdTransportPrivate *priv =
+     GIBBER_FD_TRANSPORT_GET_PRIVATE (self);
+  GibberFdIOResult result;
+  GError *error = NULL;
+  GibberFdTransportClass *cls = GIBBER_FD_TRANSPORT_GET_CLASS(self);
+
+  result = cls->read (self, priv->channel, &error);
+
+  switch (result)
+    {
+      case GIBBER_FD_IO_RESULT_SUCCESS:
+      case GIBBER_FD_IO_RESULT_AGAIN:
+        break;
+      case GIBBER_FD_IO_RESULT_ERROR:
+        gibber_transport_emit_error (GIBBER_TRANSPORT(self), error);
+      case GIBBER_FD_IO_RESULT_EOF:
+        DEBUG("Failed to read from the transport, closing..");
+        _do_disconnect (self);
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+static gboolean
+_channel_io_out (GIOChannel *source, GIOCondition condition, gpointer data)
+{
+  GibberFdTransport *self = GIBBER_FD_TRANSPORT (data);
+  GibberFdTransportPrivate *priv =
+     GIBBER_FD_TRANSPORT_GET_PRIVATE (self);
+  gsize written;
+
+  g_assert (priv->output_buffer);
+  if (!_try_write (self, (guint8 *)priv->output_buffer->str,
+                   priv->output_buffer->len, &written))
+    {
+      return FALSE;
+    }
+
+  if (written > 0 )
+    {
+      priv->output_buffer = g_string_erase (priv->output_buffer, 0, written);
+    }
+
+  if (priv->output_buffer->len == 0)
+    {
+      priv->watch_out = 0;
+      gibber_transport_emit_buffer_empty (GIBBER_TRANSPORT (self));
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static gboolean
+_channel_io_err (GIOChannel *source, GIOCondition condition, gpointer data)
+{
+  g_assert_not_reached ();
+  return TRUE;
+}
+
+/* Default read and write implementations */
+static GibberFdIOResult
+gibber_fd_transport_write (GibberFdTransport *fd_transport,
+    GIOChannel *channel, const guint8 *data, int len,
+    gsize *written, GError **error)
+{
+  GIOStatus status;
+
+  status = g_io_channel_write_chars (channel, (gchar *)data, len,
+    written, error);
+
+  switch (status)
+    {
+      case G_IO_STATUS_NORMAL:
+        return GIBBER_FD_IO_RESULT_SUCCESS;
+      case G_IO_STATUS_AGAIN:
+        return GIBBER_FD_IO_RESULT_AGAIN;
+      case G_IO_STATUS_ERROR:
+        return GIBBER_FD_IO_RESULT_ERROR;
+      case G_IO_STATUS_EOF:
+        return GIBBER_FD_IO_RESULT_EOF;
+    }
+
+    g_assert_not_reached ();
+}
+
+#define BUFSIZE 1024
+
+static GibberFdIOResult
+gibber_fd_transport_read (GibberFdTransport *transport,
+    GIOChannel *channel, GError **error)
+{
+  guint8  buf[BUFSIZE + 1];
+  GIOStatus status;
+  gsize bytes_read;
+
+  status = g_io_channel_read_chars (channel, (gchar *)buf, BUFSIZE,
+    &bytes_read, error);
+
+  switch (status)
+    {
+      case G_IO_STATUS_NORMAL:
+        buf[bytes_read] = '\0';
+        DEBUG ("Received %" G_GSIZE_FORMAT " bytes", bytes_read);
+        gibber_transport_received_data (GIBBER_TRANSPORT (transport),
+            buf, bytes_read);
+        return GIBBER_FD_IO_RESULT_SUCCESS;
+      case G_IO_STATUS_ERROR:
+        return GIBBER_FD_IO_RESULT_ERROR;
+      case G_IO_STATUS_EOF:
+        return GIBBER_FD_IO_RESULT_EOF;
+      case G_IO_STATUS_AGAIN:
+        return GIBBER_FD_IO_RESULT_AGAIN;
+    }
+
+  g_assert_not_reached ();
+}
+
+
+void
+gibber_fd_transport_set_fd (GibberFdTransport *self, int fd)
+{
+  GibberFdTransportPrivate *priv = GIBBER_FD_TRANSPORT_GET_PRIVATE (self);
+
+  g_assert (self->fd == -1 && fd >= 0);
+
+  self->fd = fd;
+  fcntl (fd, F_SETFL, O_NONBLOCK);
+  priv->channel = g_io_channel_unix_new (fd);
+  g_io_channel_set_close_on_unref (priv->channel, TRUE);
+  g_io_channel_set_encoding (priv->channel, NULL, NULL);
+  g_io_channel_set_buffered (priv->channel, FALSE);
+
+  priv->watch_in =
+    g_io_add_watch (priv->channel, G_IO_IN, _channel_io_in, self);
+  priv->watch_err =
+    g_io_add_watch (priv->channel, G_IO_ERR|G_IO_HUP, _channel_io_err, self);
+
+  gibber_transport_set_state (GIBBER_TRANSPORT(self),
+      GIBBER_TRANSPORT_CONNECTED);
+}
+
+gboolean
+gibber_fd_transport_send (GibberTransport *transport,
+    const guint8 *data, gsize size, GError **error)
+{
+  _writeout (GIBBER_FD_TRANSPORT (transport), data, size);
+  return TRUE;
+}
+
+void
+gibber_fd_transport_disconnect (GibberTransport *transport)
+{
+  DEBUG("Connection close requested");
+  _do_disconnect (GIBBER_FD_TRANSPORT (transport));
+}
+
+static gboolean
+gibber_fd_transport_get_sockaddr (GibberTransport *transport,
+    struct sockaddr_storage *addr, socklen_t *len)
+{
+  GibberFdTransport *self = GIBBER_FD_TRANSPORT (transport);
+
+  if (self->fd == -1)
+    {
+      DEBUG ("Someone requested the sockaddr while we're not connected");
+      return FALSE;
+    }
+
+   *len = sizeof (struct sockaddr_storage);
+
+   return (getpeername (self->fd, (struct sockaddr *)addr, len) == 0);
+}
+
+static gboolean
+gibber_fd_transport_buffer_is_empty (GibberTransport *transport)
+{
+  GibberFdTransport *self = GIBBER_FD_TRANSPORT (transport);
+  GibberFdTransportPrivate *priv =
+     GIBBER_FD_TRANSPORT_GET_PRIVATE (self);
+
+  return (priv->output_buffer == NULL || priv->output_buffer->len == 0);
+}
+
+static void
+gibber_fd_transport_block_receiving (GibberTransport *transport,
+    gboolean block)
+{
+  GibberFdTransport *self = GIBBER_FD_TRANSPORT (transport);
+  GibberFdTransportPrivate *priv = GIBBER_FD_TRANSPORT_GET_PRIVATE (self);
+
+  if (block && priv->watch_in != 0)
+    {
+      DEBUG ("block receiving from the transport");
+      g_source_remove (priv->watch_in);
+      priv->watch_in = 0;
+    }
+  else if (!block && priv->watch_in == 0)
+    {
+      DEBUG ("unblock receiving from the transport");
+      priv->watch_in = g_io_add_watch (priv->channel, G_IO_IN,
+          _channel_io_in, self);
+    }
+}
diff --git a/lib/gibber/gibber-fd-transport.h b/lib/gibber/gibber-fd-transport.h
new file mode 100644
index 0000000..3c2b7dd
--- /dev/null
+++ b/lib/gibber/gibber-fd-transport.h
@@ -0,0 +1,83 @@
+/*
+ * gibber-fd-transport.h - Header for GibberFdTransport
+ * Copyright (C) 2006 Collabora Ltd.
+ *   @author: Sjoerd Simons <sjoerd at luon.net>
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GIBBER_FD_TRANSPORT_H__
+#define __GIBBER_FD_TRANSPORT_H__
+
+#include <glib-object.h>
+
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include "gibber-transport.h"
+
+typedef enum {
+  GIBBER_FD_IO_RESULT_SUCCESS,
+  GIBBER_FD_IO_RESULT_AGAIN,
+  GIBBER_FD_IO_RESULT_ERROR,
+  GIBBER_FD_IO_RESULT_EOF,
+} GibberFdIOResult;
+
+G_BEGIN_DECLS
+
+typedef struct _GibberFdTransport GibberFdTransport;
+typedef struct _GibberFdTransportClass GibberFdTransportClass;
+
+
+struct _GibberFdTransportClass {
+    GibberTransportClass parent_class;
+    /* Called when fd is ready for reading */
+    GibberFdIOResult (*read) (GibberFdTransport *fd_transport,
+        GIOChannel *channel, GError **error);
+    /* Called when something needs to be written*/
+    GibberFdIOResult (*write) (GibberFdTransport *fd_transport,
+        GIOChannel *channel, const guint8 *data, int len,
+        gsize *written, GError **error);
+};
+
+struct _GibberFdTransport {
+    GibberTransport parent;
+    int fd;
+};
+
+GType gibber_fd_transport_get_type (void);
+
+/* TYPE MACROS */
+#define GIBBER_TYPE_FD_TRANSPORT \
+  (gibber_fd_transport_get_type ())
+#define GIBBER_FD_TRANSPORT(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GIBBER_TYPE_FD_TRANSPORT, \
+   GibberFdTransport))
+#define GIBBER_FD_TRANSPORT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GIBBER_TYPE_FD_TRANSPORT, \
+   GibberFdTransportClass))
+#define GIBBER_IS_FD_TRANSPORT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GIBBER_TYPE_FD_TRANSPORT))
+#define GIBBER_IS_FD_TRANSPORT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GIBBER_TYPE_FD_TRANSPORT))
+#define GIBBER_FD_TRANSPORT_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIBBER_TYPE_FD_TRANSPORT, \
+   GibberFdTransportClass))
+
+void
+gibber_fd_transport_set_fd (GibberFdTransport *fd_transport, int fd);
+G_END_DECLS
+
+#endif /* #ifndef __GIBBER_FD_TRANSPORT_H__*/
diff --git a/lib/gibber/gibber-linklocal-transport.c b/lib/gibber/gibber-linklocal-transport.c
new file mode 100644
index 0000000..cc02169
--- /dev/null
+++ b/lib/gibber/gibber-linklocal-transport.c
@@ -0,0 +1,194 @@
+/*
+ * gibber-linklocal-transport.c - Source for GibberLLTransport
+ * Copyright (C) 2006 Collabora Ltd.
+ *   @author: Sjoerd Simons <sjoerd at luon.net>
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+#include "gibber-linklocal-transport.h"
+#include "gibber-util.h"
+
+#define DEBUG_FLAG DEBUG_NET
+#include "gibber-debug.h"
+
+/* Buffer size used for reading input */
+#define BUFSIZE 1024
+
+G_DEFINE_TYPE(GibberLLTransport, gibber_ll_transport, GIBBER_TYPE_FD_TRANSPORT)
+
+GQuark
+gibber_ll_transport_error_quark (void)
+{
+  static GQuark quark = 0;
+
+  if (!quark)
+    quark = g_quark_from_static_string ("gibber_linklocal_transport_error");
+
+  return quark;
+}
+
+/* private structure */
+typedef struct _GibberLLTransportPrivate GibberLLTransportPrivate;
+
+struct _GibberLLTransportPrivate
+{
+  gboolean incoming;
+  gboolean dispose_has_run;
+};
+
+#define GIBBER_LL_TRANSPORT_GET_PRIVATE(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), GIBBER_TYPE_LL_TRANSPORT, GibberLLTransportPrivate))
+
+static void gibber_ll_transport_finalize (GObject *object);
+
+static void
+gibber_ll_transport_init (GibberLLTransport *self)
+{
+  GibberLLTransportPrivate *priv = GIBBER_LL_TRANSPORT_GET_PRIVATE (self);
+  priv->incoming = FALSE;
+}
+
+static void gibber_ll_transport_dispose (GObject *object);
+static void
+gibber_ll_transport_class_init (GibberLLTransportClass *gibber_ll_transport_class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (gibber_ll_transport_class);
+
+  g_type_class_add_private (gibber_ll_transport_class,
+                            sizeof (GibberLLTransportPrivate));
+
+  object_class->dispose = gibber_ll_transport_dispose;
+  object_class->finalize = gibber_ll_transport_finalize;
+}
+
+void
+gibber_ll_transport_dispose (GObject *object)
+{
+  GibberLLTransport *self = GIBBER_LL_TRANSPORT (object);
+  GibberLLTransportPrivate *priv = GIBBER_LL_TRANSPORT_GET_PRIVATE (self);
+
+  if (priv->dispose_has_run)
+    return;
+
+  priv->dispose_has_run = TRUE;
+
+  if (G_OBJECT_CLASS (gibber_ll_transport_parent_class)->dispose)
+    G_OBJECT_CLASS (gibber_ll_transport_parent_class)->dispose (object);
+}
+
+void
+gibber_ll_transport_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (gibber_ll_transport_parent_class)->finalize (object);
+}
+
+GibberLLTransport *
+gibber_ll_transport_new (void)
+{
+  return g_object_new (GIBBER_TYPE_LL_TRANSPORT, NULL);
+}
+
+void
+gibber_ll_transport_open_fd (GibberLLTransport *transport, int fd)
+{
+  GibberLLTransportPrivate *priv = GIBBER_LL_TRANSPORT_GET_PRIVATE (transport);
+
+  priv->incoming = TRUE;
+
+  gibber_transport_set_state (GIBBER_TRANSPORT (transport),
+      GIBBER_TRANSPORT_CONNECTING);
+  gibber_fd_transport_set_fd (GIBBER_FD_TRANSPORT (transport), fd);
+}
+
+gboolean
+gibber_ll_transport_open_sockaddr (GibberLLTransport *transport,
+    struct sockaddr_storage *addr, GError **error)
+{
+  GibberLLTransportPrivate *priv = GIBBER_LL_TRANSPORT_GET_PRIVATE (transport);
+  char host[NI_MAXHOST];
+  char port[NI_MAXSERV];
+  int fd;
+  int ret;
+
+  g_assert (!priv->incoming);
+
+  gibber_transport_set_state (GIBBER_TRANSPORT(transport),
+      GIBBER_TRANSPORT_CONNECTING);
+
+  if (getnameinfo ((struct sockaddr *)addr, sizeof (struct sockaddr_storage),
+      host, NI_MAXHOST, port, NI_MAXSERV,
+      NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
+    DEBUG("Trying to connect to %s port %s", host, port);
+  } else {
+    DEBUG("Connecting..");
+  }
+
+  fd = socket (addr->ss_family, SOCK_STREAM, 0);
+  if (fd < 0)
+    {
+      g_set_error (error, GIBBER_LL_TRANSPORT_ERROR,
+          GIBBER_LL_TRANSPORT_ERROR_FAILED,
+          "Getting socket failed: %s", g_strerror (errno));
+      DEBUG("Getting socket failed: %s", strerror(errno));
+      goto failed;
+    }
+
+  ret = connect (fd, (struct sockaddr *)addr,
+      sizeof (struct sockaddr_storage));
+  if (ret < 0)
+    {
+      g_set_error (error, GIBBER_LL_TRANSPORT_ERROR,
+          GIBBER_LL_TRANSPORT_ERROR_CONNECT_FAILED,
+          "Connect failed: %s", g_strerror (errno));
+      DEBUG("Connecting failed: %s", strerror (errno));
+      goto failed;
+    }
+
+  gibber_fd_transport_set_fd (GIBBER_FD_TRANSPORT (transport), fd);
+  return TRUE;
+
+failed:
+  gibber_transport_set_state (GIBBER_TRANSPORT (transport),
+      GIBBER_TRANSPORT_DISCONNECTED);
+  if (fd >= 0)
+    {
+      close (fd);
+    }
+  return FALSE;
+}
+
+gboolean
+gibber_ll_transport_is_incoming (GibberLLTransport *transport)
+{
+  GibberLLTransportPrivate *priv = GIBBER_LL_TRANSPORT_GET_PRIVATE (transport);
+  return priv->incoming;
+}
+
+void
+gibber_ll_transport_set_incoming (GibberLLTransport *transport,
+    gboolean incoming)
+{
+  GibberLLTransportPrivate *priv = GIBBER_LL_TRANSPORT_GET_PRIVATE (transport);
+  g_assert (
+    GIBBER_TRANSPORT (transport)->state == GIBBER_TRANSPORT_DISCONNECTED);
+  priv->incoming = incoming;
+}
diff --git a/lib/gibber/gibber-linklocal-transport.h b/lib/gibber/gibber-linklocal-transport.h
new file mode 100644
index 0000000..96ce20f
--- /dev/null
+++ b/lib/gibber/gibber-linklocal-transport.h
@@ -0,0 +1,84 @@
+/*
+ * gibber-linklocal-transport.h - Header for GibberLLTransport
+ * Copyright (C) 2006 Collabora Ltd.
+ *   @author: Sjoerd Simons <sjoerd at luon.net>
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GIBBER_LL_TRANSPORT_H__
+#define __GIBBER_LL_TRANSPORT_H__
+
+#include <glib-object.h>
+
+#include "gibber-fd-transport.h"
+
+G_BEGIN_DECLS
+
+GQuark gibber_ll_transport_error_quark (void);
+#define GIBBER_LL_TRANSPORT_ERROR gibber_ll_transport_error_quark()
+
+typedef enum
+{
+  GIBBER_LL_TRANSPORT_ERROR_CONNECT_FAILED,
+  GIBBER_LL_TRANSPORT_ERROR_FAILED,
+} GibberLLTransportError;
+
+typedef struct _GibberLLTransport GibberLLTransport;
+typedef struct _GibberLLTransportClass GibberLLTransportClass;
+
+
+struct _GibberLLTransportClass {
+    GibberFdTransportClass parent_class;
+};
+
+struct _GibberLLTransport {
+    GibberFdTransport parent;
+};
+
+GType gibber_ll_transport_get_type (void);
+
+/* TYPE MACROS */
+#define GIBBER_TYPE_LL_TRANSPORT \
+  (gibber_ll_transport_get_type ())
+#define GIBBER_LL_TRANSPORT(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GIBBER_TYPE_LL_TRANSPORT, \
+   GibberLLTransport))
+#define GIBBER_LL_TRANSPORT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GIBBER_TYPE_LL_TRANSPORT,  \
+   GibberLLTransportClass))
+#define GIBBER_IS_LL_TRANSPORT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GIBBER_TYPE_LL_TRANSPORT))
+#define GIBBER_IS_LL_TRANSPORT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GIBBER_TYPE_LL_TRANSPORT))
+#define GIBBER_LL_TRANSPORT_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIBBER_TYPE_LL_TRANSPORT, \
+   GibberLLTransportClass))
+
+GibberLLTransport * gibber_ll_transport_new (void);
+
+void gibber_ll_transport_open_fd (GibberLLTransport *connection, int fd);
+
+gboolean gibber_ll_transport_open_sockaddr (GibberLLTransport *connection,
+    struct sockaddr_storage *addr, GError **error);
+
+gboolean gibber_ll_transport_is_incoming (GibberLLTransport *connection);
+
+void gibber_ll_transport_set_incoming (GibberLLTransport *connetion,
+    gboolean incoming);
+
+G_END_DECLS
+
+#endif /* #ifndef __GIBBER_LL_TRANSPORT_H__*/
diff --git a/lib/gibber/gibber-listener.c b/lib/gibber/gibber-listener.c
new file mode 100644
index 0000000..278edad
--- /dev/null
+++ b/lib/gibber/gibber-listener.c
@@ -0,0 +1,524 @@
+/*
+ * gibber-listener.c - Source for GibberListener
+ * Copyright (C) 2007,2008 Collabora Ltd.
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <glib.h>
+
+#include "gibber-listener.h"
+#include "gibber-fd-transport.h"
+#include "gibber-util.h"
+
+#define DEBUG_FLAG DEBUG_NET
+#include "gibber-debug.h"
+
+#include "gibber-signals-marshal.h"
+
+G_DEFINE_TYPE (GibberListener, gibber_listener, \
+    G_TYPE_OBJECT);
+
+/* signals */
+enum
+{
+  NEW_CONNECTION,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = {0};
+
+typedef struct {
+  GIOChannel *listener;
+  guint io_watch_in;
+} Listener;
+
+typedef struct _GibberListenerPrivate GibberListenerPrivate;
+
+struct _GibberListenerPrivate
+{
+  GSList *listeners;
+
+  /* Don't allow to listen again if it is already listening */
+  gboolean listening;
+  int port;
+
+  gboolean dispose_has_run;
+};
+
+#define GIBBER_LISTENER_GET_PRIVATE(obj) \
+    ((GibberListenerPrivate *) obj->priv)
+
+GQuark
+gibber_listener_error_quark (void)
+{
+  static GQuark quark = 0;
+
+  if (!quark)
+    quark = g_quark_from_static_string (
+        "gibber_listener_error");
+
+  return quark;
+}
+
+static gboolean
+unimplemented (GError **error)
+{
+  g_set_error (error, GIBBER_LISTENER_ERROR, GIBBER_LISTENER_ERROR_FAILED,
+    "Unimplemented");
+
+  return FALSE;
+}
+
+static void
+gibber_listener_init (GibberListener *self)
+{
+  GibberListenerPrivate *priv =
+    G_TYPE_INSTANCE_GET_PRIVATE (self, GIBBER_TYPE_LISTENER,
+        GibberListenerPrivate);
+
+  self->priv = priv;
+
+  priv->dispose_has_run = FALSE;
+}
+
+static void
+gibber_listeners_clean_listeners (GibberListener *self)
+{
+  GibberListenerPrivate *priv = GIBBER_LISTENER_GET_PRIVATE (self);
+  GSList *t;
+
+  for (t = priv->listeners ; t != NULL ; t = g_slist_delete_link (t, t))
+    {
+      Listener *l = (Listener *)t->data;
+
+      g_io_channel_unref (l->listener);
+      g_source_remove (l->io_watch_in);
+      g_slice_free (Listener, l);
+    }
+
+  priv->listeners = NULL;
+  priv->listening = FALSE;
+  priv->port = 0;
+}
+
+static void
+gibber_listener_dispose (GObject *object)
+{
+  GibberListener *self =
+    GIBBER_LISTENER (object);
+
+  gibber_listeners_clean_listeners (self);
+
+  G_OBJECT_CLASS (gibber_listener_parent_class)->dispose (
+      object);
+}
+
+static void
+gibber_listener_class_init (
+    GibberListenerClass *gibber_listener_class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (
+      gibber_listener_class);
+
+  g_type_class_add_private (gibber_listener_class,
+      sizeof (GibberListenerPrivate));
+
+  object_class->dispose = gibber_listener_dispose;
+
+  signals[NEW_CONNECTION] =
+    g_signal_new (
+        "new-connection",
+        G_OBJECT_CLASS_TYPE (gibber_listener_class),
+        G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+        0,
+        NULL, NULL,
+        _gibber_signals_marshal_VOID__OBJECT_POINTER_UINT,
+        G_TYPE_NONE, 3, GIBBER_TYPE_TRANSPORT, G_TYPE_POINTER, G_TYPE_UINT);
+}
+
+GibberListener *
+gibber_listener_new (void)
+{
+  return g_object_new (GIBBER_TYPE_LISTENER,
+      NULL);
+}
+
+static gboolean
+listener_io_in_cb (GIOChannel *source,
+                   GIOCondition condition,
+                   gpointer user_data)
+{
+  GibberListener *self = GIBBER_LISTENER (user_data);
+  GibberFdTransport *transport;
+  int fd, nfd;
+  int ret;
+  char host[NI_MAXHOST];
+  char port[NI_MAXSERV];
+  struct sockaddr_storage addr;
+  socklen_t addrlen = sizeof (struct sockaddr_storage);
+
+  fd = g_io_channel_unix_get_fd (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)
+    {
+      /* UNIX sockets doesn't have port */
+      ret = getnameinfo ((struct sockaddr *) &addr, addrlen,
+          host, NI_MAXHOST, NULL, 0,
+          NI_NUMERICHOST);
+
+      port[0] = '\0';
+    }
+  else
+    {
+      ret = getnameinfo ((struct sockaddr *) &addr, addrlen,
+          host, NI_MAXHOST, port, NI_MAXSERV,
+          NI_NUMERICHOST | NI_NUMERICSERV);
+    }
+
+  if (ret == 0)
+    {
+      if (port[0] != '\0')
+        DEBUG ("New connection from %s port %s", host, port);
+      else
+        DEBUG ("New connection from %s", host);
+    }
+  else
+    {
+      DEBUG("New connection...");
+    }
+
+  g_signal_emit (self, signals[NEW_CONNECTION], 0, transport, &addr,
+      (guint) addrlen);
+
+  g_object_unref (transport);
+  return TRUE;
+}
+
+static gboolean
+add_listener (GibberListener *self, int family, int type, int protocol,
+  struct sockaddr *address, socklen_t addrlen, GError **error)
+{
+  #define BACKLOG 5
+  int fd = -1, ret, yes = 1;
+  Listener *l;
+  GibberListenerPrivate *priv = GIBBER_LISTENER_GET_PRIVATE (self);
+  char name [NI_MAXHOST], portname[NI_MAXSERV];
+  union {
+      struct sockaddr addr;
+      struct sockaddr_in in;
+      struct sockaddr_in6 in6;
+      struct sockaddr_storage storage;
+  } baddress;
+  socklen_t baddrlen = sizeof (baddress);
+
+  fd = socket (family, type, protocol);
+  if (fd == -1)
+    {
+      DEBUG ("socket failed: %s", g_strerror (errno));
+      g_set_error (error, GIBBER_LISTENER_ERROR,
+          errno == EAFNOSUPPORT ? GIBBER_LISTENER_ERROR_FAMILY_NOT_SUPPORTED :
+            GIBBER_LISTENER_ERROR_FAILED,
+          "%s", g_strerror (errno));
+      goto error;
+    }
+
+  ret = setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof (int));
+  if (ret == -1)
+    {
+      DEBUG ("setsockopt failed: %s", g_strerror (errno));
+      g_set_error (error, GIBBER_LISTENER_ERROR,
+          GIBBER_LISTENER_ERROR_FAILED,
+          "%s", g_strerror (errno));
+      goto error;
+    }
+
+#ifdef IPV6_V6ONLY
+  if (family == AF_INET6)
+    {
+      ret = setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof (int));
+      if (ret == -1)
+        {
+          DEBUG ("setsockopt failed: %s", g_strerror (errno));
+          g_set_error (error, GIBBER_LISTENER_ERROR,
+             GIBBER_LISTENER_ERROR_FAILED,
+             "%s", g_strerror (errno));
+          goto error;
+        }
+    }
+#endif
+
+  ret = bind (fd, address, addrlen);
+  if (ret  < 0)
+    {
+      DEBUG ("bind failed: %s", g_strerror (errno));
+      g_set_error (error, GIBBER_LISTENER_ERROR,
+          errno == EADDRINUSE ?
+          GIBBER_LISTENER_ERROR_ADDRESS_IN_USE :
+          GIBBER_LISTENER_ERROR_FAILED,
+          "%s", g_strerror (errno));
+      goto error;
+    }
+
+  ret = listen (fd, BACKLOG);
+  if (ret == -1)
+    {
+      DEBUG ("listen failed: %s", g_strerror (errno));
+      g_set_error (error, GIBBER_LISTENER_ERROR,
+          errno == EADDRINUSE ?
+          GIBBER_LISTENER_ERROR_ADDRESS_IN_USE :
+          GIBBER_LISTENER_ERROR_FAILED,
+          "%s", g_strerror (errno));
+      goto error;
+    }
+
+  getsockname (fd, &baddress.addr, &baddrlen);
+  getnameinfo (&baddress.addr, baddrlen, name, sizeof (name),
+      portname, sizeof (portname), NI_NUMERICHOST | NI_NUMERICSERV);
+
+  DEBUG ( "Listening on %s port %s...", name, portname);
+
+  switch (family)
+    {
+      case AF_INET:
+        priv->port = g_ntohs (baddress.in.sin_port);
+        break;
+      case AF_INET6:
+        priv->port = g_ntohs (baddress.in6.sin6_port);
+        break;
+      default:
+        priv->port = 0;
+        break;
+    }
+
+  l = g_slice_new (Listener);
+
+  l->listener = g_io_channel_unix_new (fd);
+  g_io_channel_set_close_on_unref (l->listener, TRUE);
+  l->io_watch_in = g_io_add_watch (l->listener, G_IO_IN,
+      listener_io_in_cb, self);
+
+  priv->listeners = g_slist_append (priv->listeners, l);
+
+  return TRUE;
+
+error:
+  if (fd > 0)
+    close (fd);
+  return FALSE;
+}
+
+/* port: if 0, choose a random port
+ */
+static gboolean
+listen_tcp_af (GibberListener *listener, int port, GibberAddressFamily family,
+    gboolean loopback, GError **error)
+{
+  GibberListenerPrivate *priv = GIBBER_LISTENER_GET_PRIVATE (listener);
+  struct addrinfo req, *ans = NULL, *a;
+  int ret;
+  gchar sport[6];
+
+  if (priv->listening)
+    {
+      g_set_error (error, GIBBER_LISTENER_ERROR,
+          GIBBER_LISTENER_ERROR_ALREADY_LISTENING,
+          "GibberListener is already listening");
+      return FALSE;
+    }
+
+  memset (&req, 0, sizeof (req));
+  if (!loopback)
+    req.ai_flags = AI_PASSIVE;
+
+  switch (family)
+    {
+      case GIBBER_AF_IPV4:
+        req.ai_family = AF_INET;
+        break;
+      case GIBBER_AF_IPV6:
+        req.ai_family = AF_INET6;
+        break;
+      case GIBBER_AF_ANY:
+        req.ai_family = AF_UNSPEC;
+        break;
+    }
+  req.ai_socktype = SOCK_STREAM;
+  req.ai_protocol = IPPROTO_TCP;
+
+  g_snprintf (sport, 6, "%d", port);
+
+  ret = getaddrinfo (NULL, sport, &req, &ans);
+  if (ret != 0)
+    {
+      DEBUG ("getaddrinfo failed: %s", gai_strerror (ret));
+      g_set_error (error, GIBBER_LISTENER_ERROR,
+          GIBBER_LISTENER_ERROR_FAILED,
+          "%s", gai_strerror (ret));
+      goto error;
+    }
+
+  priv->port = 0;
+  for (a = ans ; a != NULL ; a = a->ai_next)
+    {
+      union {
+          struct sockaddr *addr;
+          struct sockaddr_storage *storage;
+          struct sockaddr_in *in;
+          struct sockaddr_in6 *in6;
+      } addr;
+      gboolean ret_;
+      GError *terror = NULL;
+
+      addr.addr = a->ai_addr;
+
+      /* the caller let us choose a port and we are not in the first round */
+      if (port == 0 && priv->port != 0)
+        {
+          if (a->ai_family == AF_INET)
+            addr.in->sin_port = priv->port;
+          else if (a->ai_family == AF_INET6)
+            addr.in6->sin6_port = priv->port;
+          else
+            g_assert_not_reached ();
+        }
+
+      ret_ = add_listener (listener, a->ai_family, a->ai_socktype,
+        a->ai_protocol, a->ai_addr, a->ai_addrlen, &terror);
+
+      if (ret_ == FALSE)
+        {
+          gboolean fatal = !g_error_matches (terror, GIBBER_LISTENER_ERROR,
+              GIBBER_LISTENER_ERROR_FAMILY_NOT_SUPPORTED);
+
+          /* let error always point to the last error */
+          g_clear_error (error);
+          g_propagate_error (error, terror);
+
+          if (fatal)
+              goto error;
+        }
+      else
+        {
+          /* add_listener succeeded: don't allow to listen again */
+          priv->listening = TRUE;
+        }
+    }
+
+  /* If all listeners failed, report the last error */
+  if (priv->listeners == NULL)
+    goto error;
+
+  /* There was an error at some point, but it was not fatal. ignore it */
+  g_clear_error (error);
+
+  freeaddrinfo (ans);
+
+  return TRUE;
+
+error:
+  gibber_listeners_clean_listeners (listener);
+  if (ans != NULL)
+    freeaddrinfo (ans);
+
+  return FALSE;
+}
+
+gboolean
+gibber_listener_listen_tcp (GibberListener *listener, int port, GError **error)
+{
+  return gibber_listener_listen_tcp_af (listener, port, GIBBER_AF_ANY, error);
+}
+
+gboolean
+gibber_listener_listen_tcp_af (GibberListener *listener, int port,
+  GibberAddressFamily family, GError **error)
+{
+  return listen_tcp_af (listener, port, family, FALSE, error);
+}
+
+gboolean
+gibber_listener_listen_tcp_loopback (GibberListener *listener,
+  int port, GError **error)
+{
+  return gibber_listener_listen_tcp_loopback_af (listener, port,
+    GIBBER_AF_ANY, error);
+}
+
+gboolean
+gibber_listener_listen_tcp_loopback_af (GibberListener *listener,
+  int port, GibberAddressFamily family, GError **error)
+{
+  return listen_tcp_af (listener, port, family, TRUE, error);
+}
+
+gboolean
+gibber_listener_listen_socket (GibberListener *listener,
+  gchar *path, gboolean abstract, GError **error)
+{
+  GibberListenerPrivate *priv = GIBBER_LISTENER_GET_PRIVATE (listener);
+  struct sockaddr_un addr;
+  int ret;
+
+  if (priv->listening)
+    {
+      g_set_error (error, GIBBER_LISTENER_ERROR,
+          GIBBER_LISTENER_ERROR_ALREADY_LISTENING,
+          "GibberListener is already listening");
+      return FALSE;
+    }
+
+  if (abstract)
+    return unimplemented (error);
+
+  memset (&addr, 0, sizeof (addr));
+  addr.sun_family = PF_UNIX;
+  snprintf (addr.sun_path, sizeof (addr.sun_path) - 1, "%s", path);
+
+  ret = add_listener (listener, AF_UNIX, SOCK_STREAM, 0,
+      (struct sockaddr *) &addr, sizeof (addr), error);
+
+  if (ret == TRUE)
+    {
+      /* add_listener succeeded: don't allow to listen again */
+      priv->listening = TRUE;
+    }
+
+  return ret;
+}
+
+int
+gibber_listener_get_port (GibberListener *listener)
+{
+  GibberListenerPrivate *priv = GIBBER_LISTENER_GET_PRIVATE (listener);
+  return priv->port;
+}
diff --git a/lib/gibber/gibber-listener.h b/lib/gibber/gibber-listener.h
new file mode 100644
index 0000000..7ca1501
--- /dev/null
+++ b/lib/gibber/gibber-listener.h
@@ -0,0 +1,99 @@
+/*
+ * gibber-listener.h - Header for GibberListener
+ * Copyright (C) 2007, 2008 Collabora Ltd.
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _GIBBER_LISTENER_H_
+#define _GIBBER_LISTENER_H_
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+GQuark gibber_listener_error_quark (void);
+#define GIBBER_LISTENER_ERROR \
+  gibber_listener_error_quark ()
+
+typedef enum
+{
+  GIBBER_LISTENER_ERROR_ALREADY_LISTENING,
+  GIBBER_LISTENER_ERROR_ADDRESS_IN_USE,
+  GIBBER_LISTENER_ERROR_FAMILY_NOT_SUPPORTED,
+  GIBBER_LISTENER_ERROR_FAILED,
+} GibberListenerError;
+
+typedef enum
+{
+  GIBBER_AF_IPV4,
+  GIBBER_AF_IPV6,
+  GIBBER_AF_ANY
+} GibberAddressFamily;
+
+typedef struct _GibberListener GibberListener;
+typedef struct _GibberListenerClass GibberListenerClass;
+
+struct _GibberListenerClass {
+  GObjectClass parent_class;
+};
+
+struct _GibberListener {
+  GObject parent;
+
+  gpointer priv;
+};
+
+GType gibber_listener_get_type (void);
+
+/* TYPE MACROS */
+#define GIBBER_TYPE_LISTENER \
+  (gibber_listener_get_type ())
+#define GIBBER_LISTENER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GIBBER_TYPE_LISTENER,\
+                              GibberListener))
+#define GIBBER_LISTENER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GIBBER_TYPE_LISTENER,\
+                           GibberListenerClass))
+#define GIBBER_IS_LISTENER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GIBBER_TYPE_LISTENER))
+#define GIBBER_IS_LISTENER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GIBBER_TYPE_LISTENER))
+#define GIBBER_LISTENER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIBBER_TYPE_LISTENER,\
+                              GibberListenerClass))
+
+GibberListener *gibber_listener_new (void);
+
+gboolean gibber_listener_listen_tcp (GibberListener *listener,
+  int port, GError **error);
+
+gboolean gibber_listener_listen_tcp_af (GibberListener *listener,
+  int port, GibberAddressFamily family, GError **error);
+
+gboolean gibber_listener_listen_tcp_loopback (GibberListener *listener,
+  int port, GError **error);
+
+gboolean gibber_listener_listen_tcp_loopback_af (GibberListener *listener,
+  int port, GibberAddressFamily family, GError **error);
+
+gboolean gibber_listener_listen_socket (GibberListener *listener,
+  gchar *path, gboolean abstract, GError **error);
+
+int gibber_listener_get_port (GibberListener *listener);
+
+G_END_DECLS
+
+#endif /* #ifndef _GIBBER_LISTENER_H_ */
diff --git a/lib/gibber/gibber-tcp-transport.c b/lib/gibber/gibber-tcp-transport.c
new file mode 100644
index 0000000..7c3c531
--- /dev/null
+++ b/lib/gibber/gibber-tcp-transport.c
@@ -0,0 +1,181 @@
+/*
+ * gibber-tcp-transport.c - Source for GibberTCPTransport
+ * Copyright (C) 2006 Collabora Ltd.
+ * @author Sjoerd Simons <sjoerd at luon.net>
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string.h>
+
+#include "gibber-tcp-transport.h"
+
+#define DEBUG_FLAG DEBUG_NET
+#include "gibber-debug.h"
+
+#include "errno.h"
+
+G_DEFINE_TYPE(GibberTCPTransport, gibber_tcp_transport,
+              GIBBER_TYPE_FD_TRANSPORT)
+
+/* private structure */
+typedef struct _GibberTCPTransportPrivate GibberTCPTransportPrivate;
+
+struct _GibberTCPTransportPrivate
+{
+  gboolean dispose_has_run;
+};
+
+#define GIBBER_TCP_TRANSPORT_GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), GIBBER_TYPE_TCP_TRANSPORT, \
+   GibberTCPTransportPrivate))
+
+static void
+gibber_tcp_transport_init (GibberTCPTransport *obj)
+{
+  /* GibberTCPTransportPrivate *priv = GIBBER_TCP_TRANSPORT_GET_PRIVATE (obj);
+   */
+
+  /* allocate any data required by the object here */
+}
+
+static void gibber_tcp_transport_dispose (GObject *object);
+static void gibber_tcp_transport_finalize (GObject *object);
+
+static void
+gibber_tcp_transport_class_init (
+  GibberTCPTransportClass *gibber_tcp_transport_class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (gibber_tcp_transport_class);
+
+  g_type_class_add_private (gibber_tcp_transport_class,
+    sizeof (GibberTCPTransportPrivate));
+
+  object_class->dispose = gibber_tcp_transport_dispose;
+  object_class->finalize = gibber_tcp_transport_finalize;
+}
+
+void
+gibber_tcp_transport_dispose (GObject *object)
+{
+  GibberTCPTransport *self = GIBBER_TCP_TRANSPORT (object);
+  GibberTCPTransportPrivate *priv = GIBBER_TCP_TRANSPORT_GET_PRIVATE (self);
+
+  if (priv->dispose_has_run)
+    return;
+
+  priv->dispose_has_run = TRUE;
+
+  /* release any references held by the object here */
+
+  if (G_OBJECT_CLASS (gibber_tcp_transport_parent_class)->dispose)
+    G_OBJECT_CLASS (gibber_tcp_transport_parent_class)->dispose (object);
+}
+
+void
+gibber_tcp_transport_finalize (GObject *object)
+{
+  /*
+  GibberTCPTransport *self = GIBBER_TCP_TRANSPORT (object);
+  GibberTCPTransportPrivate *priv = GIBBER_TCP_TRANSPORT_GET_PRIVATE (self);
+  */
+
+  /* free any data held directly by the object here */
+
+  G_OBJECT_CLASS (gibber_tcp_transport_parent_class)->finalize (object);
+}
+
+GibberTCPTransport *
+gibber_tcp_transport_new ()
+{
+  return g_object_new (GIBBER_TYPE_TCP_TRANSPORT, NULL);
+}
+
+void
+gibber_tcp_transport_connect (GibberTCPTransport *tcp_transport,
+    const gchar *host, const gchar *port)
+{
+  int fd = -1, ret = -1;
+  struct addrinfo req, *ans = NULL, *tmpaddr;
+  char name[NI_MAXHOST], portname[NI_MAXSERV];
+
+  gibber_transport_set_state (GIBBER_TRANSPORT (tcp_transport),
+                             GIBBER_TRANSPORT_CONNECTING);
+
+  memset (&req, 0, sizeof (req));
+  req.ai_flags = 0;
+  req.ai_family = AF_UNSPEC;
+  req.ai_socktype = SOCK_STREAM;
+  req.ai_protocol = IPPROTO_TCP;
+
+  ret = getaddrinfo (host, port, &req, &ans);
+  if (ret != 0)
+    {
+      DEBUG("getaddrinfo failed: %s", gai_strerror (ret));
+      goto failed;
+    }
+
+  tmpaddr = ans;
+  while (tmpaddr != NULL)
+    {
+      getnameinfo (tmpaddr->ai_addr, tmpaddr->ai_addrlen,
+          name, sizeof (name), portname, sizeof (portname),
+          NI_NUMERICHOST | NI_NUMERICSERV);
+
+      DEBUG ( "Trying %s port %s...", name, portname);
+
+      fd = socket (tmpaddr->ai_family, tmpaddr->ai_socktype,
+          tmpaddr->ai_protocol);
+
+      if (fd < 0)
+        {
+          DEBUG("socket failed: %s", strerror (errno));
+        }
+      else if ((ret = connect (fd, tmpaddr->ai_addr, tmpaddr->ai_addrlen)) < 0)
+        {
+          DEBUG( "connect failed: %s", strerror (errno));
+        }
+      else
+        {
+          break;
+        }
+
+      tmpaddr = tmpaddr->ai_next;
+    }
+
+  if (ret != 0 || fd < 0)
+    {
+      goto failed;
+    }
+
+  DEBUG ("succeeded");
+
+  gibber_fd_transport_set_fd (GIBBER_FD_TRANSPORT (tcp_transport), fd);
+
+  freeaddrinfo (ans);
+  return;
+
+failed:
+  if (ans != NULL)
+    freeaddrinfo (ans);
+
+  gibber_transport_set_state (GIBBER_TRANSPORT (tcp_transport),
+      GIBBER_TRANSPORT_DISCONNECTED);
+
+}
diff --git a/lib/gibber/gibber-tcp-transport.h b/lib/gibber/gibber-tcp-transport.h
new file mode 100644
index 0000000..642fdcd
--- /dev/null
+++ b/lib/gibber/gibber-tcp-transport.h
@@ -0,0 +1,67 @@
+/*
+ * gibber-tcp-transport.h - Header for GibberTCPTransport
+ * Copyright (C) 2006 Collabora Ltd.
+ * @author Sjoerd Simons <sjoerd at luon.net>
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GIBBER_TCP_TRANSPORT_H__
+#define __GIBBER_TCP_TRANSPORT_H__
+
+#include <glib-object.h>
+#include "gibber-fd-transport.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GibberTCPTransport GibberTCPTransport;
+typedef struct _GibberTCPTransportClass GibberTCPTransportClass;
+
+struct _GibberTCPTransportClass {
+    GibberFdTransportClass parent_class;
+};
+
+struct _GibberTCPTransport {
+    GibberFdTransport parent;
+};
+
+GType gibber_tcp_transport_get_type (void);
+
+/* TYPE MACROS */
+#define GIBBER_TYPE_TCP_TRANSPORT \
+  (gibber_tcp_transport_get_type ())
+#define GIBBER_TCP_TRANSPORT(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GIBBER_TYPE_TCP_TRANSPORT, \
+   GibberTCPTransport))
+#define GIBBER_TCP_TRANSPORT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GIBBER_TYPE_TCP_TRANSPORT, \
+   GibberTCPTransportClass))
+#define GIBBER_IS_TCP_TRANSPORT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GIBBER_TYPE_TCP_TRANSPORT))
+#define GIBBER_IS_TCP_TRANSPORT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GIBBER_TYPE_TCP_TRANSPORT))
+#define GIBBER_TCP_TRANSPORT_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIBBER_TYPE_TCP_TRANSPORT, \
+   GibberTCPTransportClass))
+
+GibberTCPTransport *
+gibber_tcp_transport_new (void);
+
+void gibber_tcp_transport_connect (GibberTCPTransport *tcp_transport,
+    const gchar *host, const gchar *port);
+
+G_END_DECLS
+
+#endif /* #ifndef __GIBBER_TCP_TRANSPORT_H__*/
diff --git a/lib/gibber/gibber-transport.c b/lib/gibber/gibber-transport.c
new file mode 100644
index 0000000..248e629
--- /dev/null
+++ b/lib/gibber/gibber-transport.c
@@ -0,0 +1,284 @@
+/*
+ * gibber-transport.c - Source for GibberTransport
+ * Copyright (C) 2006 Collabora Ltd.
+ * @author Sjoerd Simons <sjoerd at luon.net>
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gibber-transport.h"
+#include "gibber-signals-marshal.h"
+
+#define DEBUG_FLAG DEBUG_TRANSPORT
+#include "gibber-debug.h"
+
+G_DEFINE_TYPE(GibberTransport, gibber_transport, G_TYPE_OBJECT)
+
+/* signal enum */
+enum
+{
+  CONNECTED,
+  CONNECTING,
+  DISCONNECTED,
+  DISCONNECTING,
+  ERROR,
+  BUFFER_EMPTY,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = {0};
+
+/* private structure */
+typedef struct _GibberTransportPrivate GibberTransportPrivate;
+
+struct _GibberTransportPrivate
+{
+  gboolean dispose_has_run;
+};
+
+#define GIBBER_TRANSPORT_GET_PRIVATE(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), GIBBER_TYPE_TRANSPORT, GibberTransportPrivate))
+
+static void
+gibber_transport_init (GibberTransport *obj)
+{
+  obj->state = GIBBER_TRANSPORT_DISCONNECTED;
+  obj->handler = NULL;
+}
+
+static void gibber_transport_dispose (GObject *object);
+static void gibber_transport_finalize (GObject *object);
+
+static void
+gibber_transport_class_init (GibberTransportClass *gibber_transport_class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (gibber_transport_class);
+
+  g_type_class_add_private (gibber_transport_class, sizeof (GibberTransportPrivate));
+
+  object_class->dispose = gibber_transport_dispose;
+  object_class->finalize = gibber_transport_finalize;
+
+  signals[BUFFER_EMPTY] =
+    g_signal_new ("buffer-empty",
+                  G_OBJECT_CLASS_TYPE (gibber_transport_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+                  0,
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  signals[CONNECTED] =
+    g_signal_new ("connected",
+                  G_OBJECT_CLASS_TYPE (gibber_transport_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+                  0,
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  signals[CONNECTING] =
+    g_signal_new ("connecting",
+                  G_OBJECT_CLASS_TYPE (gibber_transport_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+                  0,
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  signals[DISCONNECTING] =
+    g_signal_new ("disconnecting",
+                  G_OBJECT_CLASS_TYPE (gibber_transport_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+                  0,
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  signals[DISCONNECTED] =
+    g_signal_new ("disconnected",
+                  G_OBJECT_CLASS_TYPE (gibber_transport_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+                  0,
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  signals[ERROR] =
+    g_signal_new ("error",
+                  G_OBJECT_CLASS_TYPE (gibber_transport_class),
+                  G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+                  0,
+                  NULL, NULL,
+                  _gibber_signals_marshal_VOID__UINT_INT_STRING,
+                  G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_INT, G_TYPE_STRING);
+}
+
+void
+gibber_transport_dispose (GObject *object)
+{
+  GibberTransport *self = GIBBER_TRANSPORT (object);
+  GibberTransportPrivate *priv = GIBBER_TRANSPORT_GET_PRIVATE (self);
+
+  if (priv->dispose_has_run)
+    return;
+
+  priv->dispose_has_run = TRUE;
+
+  /* release any references held by the object here */
+
+  if (G_OBJECT_CLASS (gibber_transport_parent_class)->dispose)
+    G_OBJECT_CLASS (gibber_transport_parent_class)->dispose (object);
+}
+
+void
+gibber_transport_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (gibber_transport_parent_class)->finalize (object);
+}
+
+void
+gibber_transport_received_data (GibberTransport *transport,
+    const guint8 *data, gsize length)
+{
+  GibberBuffer buffer;
+  buffer.length = length;
+  buffer.data = data;
+
+  gibber_transport_received_data_custom (transport, &buffer);
+}
+
+void
+gibber_transport_received_data_custom (GibberTransport *transport,
+    GibberBuffer *buffer)
+{
+  if (G_UNLIKELY (transport->handler == NULL))
+    {
+      DEBUG("No handler for transport, dropping data!");
+    }
+  else
+    {
+      transport->handler (transport, buffer, transport->user_data);
+    }
+}
+
+void
+gibber_transport_set_state (GibberTransport *transport,
+    GibberTransportState state)
+{
+  if (state != transport->state)
+    {
+      transport->state = state;
+
+      switch (state)
+        {
+          case GIBBER_TRANSPORT_DISCONNECTED:
+            g_signal_emit (transport, signals[DISCONNECTED], 0);
+            break;
+          case GIBBER_TRANSPORT_CONNECTING:
+            g_signal_emit (transport, signals[CONNECTING], 0);
+            break;
+          case GIBBER_TRANSPORT_CONNECTED:
+            g_signal_emit (transport, signals[CONNECTED], 0);
+            break;
+          case GIBBER_TRANSPORT_DISCONNECTING:
+            g_signal_emit (transport, signals[DISCONNECTING], 0);
+            break;
+        }
+    }
+}
+
+GibberTransportState
+gibber_transport_get_state (GibberTransport *transport)
+{
+  return transport->state;
+}
+
+void
+gibber_transport_emit_error (GibberTransport *transport, GError *error)
+{
+  DEBUG ("Transport error: %s", error->message);
+  g_signal_emit (transport, signals[ERROR], 0,
+      error->domain, error->code, error->message);
+}
+
+gboolean
+gibber_transport_send (GibberTransport *transport, const guint8 *data,
+  gsize size, GError **error)
+{
+  GibberTransportClass *cls = GIBBER_TRANSPORT_GET_CLASS (transport);
+
+  g_assert (transport->state == GIBBER_TRANSPORT_CONNECTED);
+
+  return cls->send (transport, data, size, error);
+}
+
+void
+gibber_transport_disconnect (GibberTransport *transport)
+{
+  GibberTransportClass *cls = GIBBER_TRANSPORT_GET_CLASS (transport);
+  return cls->disconnect (transport);
+}
+
+void
+gibber_transport_set_handler (GibberTransport *transport,
+    GibberHandlerFunc func, gpointer user_data)
+{
+  g_assert (transport->handler == NULL || func == NULL);
+
+  transport->handler = func;
+  transport->user_data = user_data;
+}
+
+gboolean
+gibber_transport_get_sockaddr (GibberTransport *transport,
+   struct sockaddr_storage *addr, socklen_t *len)
+{
+  GibberTransportClass *cls = GIBBER_TRANSPORT_GET_CLASS (transport);
+
+  if (cls->get_sockaddr != NULL)
+    return cls->get_sockaddr (transport, addr, len);
+
+  return FALSE;
+}
+
+gboolean
+gibber_transport_buffer_is_empty (GibberTransport *transport)
+{
+  GibberTransportClass *cls = GIBBER_TRANSPORT_GET_CLASS (transport);
+
+  g_assert (cls->buffer_is_empty != NULL);
+  return cls->buffer_is_empty (transport);
+}
+
+void
+gibber_transport_emit_buffer_empty (GibberTransport *transport)
+{
+  g_signal_emit (transport, signals[BUFFER_EMPTY], 0);
+}
+
+void
+gibber_transport_block_receiving (GibberTransport *transport,
+                                  gboolean block)
+{
+  GibberTransportClass *cls = GIBBER_TRANSPORT_GET_CLASS (transport);
+
+  g_assert (cls->block_receiving != NULL);
+  cls->block_receiving (transport, block);
+}
+
diff --git a/lib/gibber/gibber-transport.h b/lib/gibber/gibber-transport.h
new file mode 100644
index 0000000..2455a37
--- /dev/null
+++ b/lib/gibber/gibber-transport.h
@@ -0,0 +1,125 @@
+/*
+ * gibber-transport.h - Header for GibberTransport
+ * Copyright (C) 2006 Collabora Ltd.
+ * @author Sjoerd Simons <sjoerd at luon.net>
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GIBBER_TRANSPORT_H__
+#define __GIBBER_TRANSPORT_H__
+
+#include <glib-object.h>
+
+#include <sys/socket.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+  GIBBER_TRANSPORT_DISCONNECTED = 0,
+  GIBBER_TRANSPORT_CONNECTING,
+  GIBBER_TRANSPORT_CONNECTED,
+  GIBBER_TRANSPORT_DISCONNECTING,
+} GibberTransportState;
+
+
+typedef struct _GibberTransport GibberTransport;
+typedef struct _GibberTransportClass GibberTransportClass;
+typedef struct _GibberBuffer GibberBuffer;
+typedef void (*GibberHandlerFunc) (GibberTransport *transport,
+                                   GibberBuffer *buffer,
+                                   gpointer user_data);
+
+struct _GibberBuffer {
+  const guint8 *data;
+  gsize length;
+};
+
+struct _GibberTransportClass {
+    GObjectClass parent_class;
+    gboolean (*send) (GibberTransport *transport,
+                          const guint8 *data, gsize length, GError **error);
+    void (*disconnect) (GibberTransport *transport);
+    gboolean (*get_sockaddr) (GibberTransport *transport,
+        struct sockaddr_storage *addr, socklen_t *len);
+    gboolean (*buffer_is_empty) (GibberTransport *transport);
+    void (*block_receiving) (GibberTransport *transport, gboolean block);
+};
+
+struct _GibberTransport {
+    GObject parent;
+    GibberTransportState state;
+
+    /* Maximum packet size for transports where it matters, 0 otherwise */
+    gsize max_packet_size;
+
+    /* FIXME Should be private... */
+    GibberHandlerFunc handler;
+    gpointer user_data;
+};
+
+GType gibber_transport_get_type (void);
+
+/* TYPE MACROS */
+#define GIBBER_TYPE_TRANSPORT  (gibber_transport_get_type ())
+#define GIBBER_TRANSPORT(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GIBBER_TYPE_TRANSPORT, GibberTransport))
+#define GIBBER_TRANSPORT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GIBBER_TYPE_TRANSPORT, \
+   GibberTransportClass))
+#define GIBBER_IS_TRANSPORT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GIBBER_TYPE_TRANSPORT))
+#define GIBBER_IS_TRANSPORT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GIBBER_TYPE_TRANSPORT))
+#define GIBBER_TRANSPORT_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIBBER_TYPE_TRANSPORT, \
+   GibberTransportClass))
+
+/* Utility functions for the classes based on GibberTransport   */
+void gibber_transport_received_data (GibberTransport *transport,
+    const guint8 *data, gsize length);
+
+void gibber_transport_received_data_custom (GibberTransport *transport,
+    GibberBuffer *buffer);
+
+void gibber_transport_set_state (GibberTransport *transport,
+    GibberTransportState state);
+
+void gibber_transport_emit_error (GibberTransport *transport, GError *error);
+
+/* Public api */
+GibberTransportState gibber_transport_get_state (GibberTransport *transport);
+
+gboolean gibber_transport_send (GibberTransport *transport, const guint8 *data,
+    gsize size, GError **error);
+
+void gibber_transport_disconnect (GibberTransport *transport);
+
+void gibber_transport_set_handler (GibberTransport *transport,
+    GibberHandlerFunc func, gpointer user_data);
+
+gboolean gibber_transport_get_sockaddr (GibberTransport *transport,
+    struct sockaddr_storage *addr, socklen_t *len);
+
+gboolean gibber_transport_buffer_is_empty (GibberTransport *transport);
+
+void gibber_transport_emit_buffer_empty (GibberTransport *transport);
+
+void gibber_transport_block_receiving (GibberTransport *transport,
+    gboolean block);
+
+G_END_DECLS
+
+#endif /* #ifndef __GIBBER_TRANSPORT_H__*/
diff --git a/lib/gibber/gibber-unix-transport.c b/lib/gibber/gibber-unix-transport.c
new file mode 100644
index 0000000..b1a6641
--- /dev/null
+++ b/lib/gibber/gibber-unix-transport.c
@@ -0,0 +1,166 @@
+/*
+ * gibber-linklocal-transport.c - Source for GibberLLTransport
+ * Copyright (C) 2006, 2008 Collabora Ltd.
+ *   @author: Sjoerd Simons <sjoerd at luon.net>
+ *   @author: Alban Crequy <alban.crequy at collabora.co.uk>
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "gibber-unix-transport.h"
+#include "gibber-util.h"
+
+#define DEBUG_FLAG DEBUG_NET
+#include "gibber-debug.h"
+
+G_DEFINE_TYPE(GibberUnixTransport, gibber_unix_transport, \
+    GIBBER_TYPE_FD_TRANSPORT)
+
+GQuark
+gibber_unix_transport_error_quark (void)
+{
+  static GQuark quark = 0;
+
+  if (!quark)
+    quark = g_quark_from_static_string ("gibber_unix_transport_error");
+
+  return quark;
+}
+
+/* private structure */
+typedef struct _GibberUnixTransportPrivate GibberUnixTransportPrivate;
+
+struct _GibberUnixTransportPrivate
+{
+  gboolean incoming;
+  gboolean dispose_has_run;
+};
+
+#define GIBBER_UNIX_TRANSPORT_GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), GIBBER_TYPE_UNIX_TRANSPORT, \
+     GibberUnixTransportPrivate))
+
+static void gibber_unix_transport_finalize (GObject *object);
+
+static void
+gibber_unix_transport_init (GibberUnixTransport *self)
+{
+  GibberUnixTransportPrivate *priv = GIBBER_UNIX_TRANSPORT_GET_PRIVATE (self);
+  priv->incoming = FALSE;
+}
+
+static void gibber_unix_transport_dispose (GObject *object);
+static void
+gibber_unix_transport_class_init (
+    GibberUnixTransportClass *gibber_unix_transport_class)
+{
+  GObjectClass *object_class = G_OBJECT_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;
+}
+
+void
+gibber_unix_transport_dispose (GObject *object)
+{
+  GibberUnixTransport *self = GIBBER_UNIX_TRANSPORT (object);
+  GibberUnixTransportPrivate *priv = GIBBER_UNIX_TRANSPORT_GET_PRIVATE (self);
+
+  if (priv->dispose_has_run)
+    return;
+
+  priv->dispose_has_run = TRUE;
+
+  if (G_OBJECT_CLASS (gibber_unix_transport_parent_class)->dispose)
+    G_OBJECT_CLASS (gibber_unix_transport_parent_class)->dispose (object);
+}
+
+void
+gibber_unix_transport_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (gibber_unix_transport_parent_class)->finalize (object);
+}
+
+GibberUnixTransport *
+gibber_unix_transport_new (void)
+{
+  return g_object_new (GIBBER_TYPE_UNIX_TRANSPORT, NULL);
+}
+
+gboolean
+gibber_unix_transport_connect (GibberUnixTransport *transport,
+                               const gchar *path,
+                               GError **error)
+{
+  union {
+      struct sockaddr_un un;
+      struct sockaddr addr;
+  } addr;
+  int fd;
+
+  gibber_transport_set_state (GIBBER_TRANSPORT (transport),
+      GIBBER_TRANSPORT_CONNECTING);
+
+  memset (&addr, 0, sizeof (addr));
+
+  fd = socket (PF_UNIX, SOCK_STREAM, 0);
+  if (fd == -1)
+    {
+      DEBUG ("Error creating socket: %s", g_strerror (errno));
+      g_set_error (error, GIBBER_UNIX_TRANSPORT_ERROR,
+          GIBBER_UNIX_TRANSPORT_ERROR_CONNECT_FAILED,
+          "Error creating socket: %s", g_strerror (errno));
+      goto failed;
+    }
+
+  addr.un.sun_family = PF_UNIX;
+  g_strlcpy (addr.un.sun_path, path, sizeof (addr.un.sun_path));
+
+  if (connect (fd, &addr.addr, sizeof (addr.un)) == -1)
+    {
+      g_set_error (error, GIBBER_UNIX_TRANSPORT_ERROR,
+          GIBBER_UNIX_TRANSPORT_ERROR_CONNECT_FAILED,
+          "Error connecting socket: %s", g_strerror (errno));
+      DEBUG ("Error connecting socket: %s", g_strerror (errno));
+      goto failed;
+    }
+  DEBUG ("Connected to socket");
+
+  gibber_fd_transport_set_fd (GIBBER_FD_TRANSPORT (transport), fd);
+
+  return TRUE;
+
+failed:
+  g_assert (error != NULL);
+  gibber_transport_emit_error (GIBBER_TRANSPORT(transport), *error);
+
+  gibber_transport_set_state (GIBBER_TRANSPORT (transport),
+      GIBBER_TRANSPORT_DISCONNECTED);
+  return FALSE;
+}
+
diff --git a/lib/gibber/gibber-unix-transport.h b/lib/gibber/gibber-unix-transport.h
new file mode 100644
index 0000000..e7ca190
--- /dev/null
+++ b/lib/gibber/gibber-unix-transport.h
@@ -0,0 +1,78 @@
+/*
+ * gibber-unix-transport.h - Header for GibberUnixTransport
+ * Copyright (C) 2006, 2008 Collabora Ltd.
+ *   @author: Sjoerd Simons <sjoerd at luon.net>
+ *   @author: Alban Crequy <alban.crequy at collabora.co.uk>
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GIBBER_UNIX_TRANSPORT_H__
+#define __GIBBER_UNIX_TRANSPORT_H__
+
+#include <glib-object.h>
+
+#include "gibber-fd-transport.h"
+
+G_BEGIN_DECLS
+
+GQuark gibber_unix_transport_error_quark (void);
+#define GIBBER_UNIX_TRANSPORT_ERROR gibber_unix_transport_error_quark()
+
+typedef enum
+{
+  GIBBER_UNIX_TRANSPORT_ERROR_CONNECT_FAILED,
+  GIBBER_UNIX_TRANSPORT_ERROR_FAILED,
+} GibberUnixTransportError;
+
+typedef struct _GibberUnixTransport GibberUnixTransport;
+typedef struct _GibberUnixTransportClass GibberUnixTransportClass;
+
+
+struct _GibberUnixTransportClass {
+    GibberFdTransportClass parent_class;
+};
+
+struct _GibberUnixTransport {
+    GibberFdTransport parent;
+};
+
+GType gibber_unix_transport_get_type (void);
+
+/* TYPE MACROS */
+#define GIBBER_TYPE_UNIX_TRANSPORT \
+  (gibber_unix_transport_get_type ())
+#define GIBBER_UNIX_TRANSPORT(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GIBBER_TYPE_UNIX_TRANSPORT, \
+   GibberUnixTransport))
+#define GIBBER_UNIX_TRANSPORT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GIBBER_TYPE_UNIX_TRANSPORT,  \
+   GibberUnixTransportClass))
+#define GIBBER_IS_UNIX_TRANSPORT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GIBBER_TYPE_UNIX_TRANSPORT))
+#define GIBBER_IS_UNIX_TRANSPORT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GIBBER_TYPE_UNIX_TRANSPORT))
+#define GIBBER_UNIX_TRANSPORT_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIBBER_TYPE_UNIX_TRANSPORT, \
+   GibberUnixTransportClass))
+
+GibberUnixTransport * gibber_unix_transport_new (void);
+
+gboolean gibber_unix_transport_connect (GibberUnixTransport *transport,
+    const gchar *path, GError **error);
+
+G_END_DECLS
+
+#endif /* #ifndef __GIBBER_UNIX_TRANSPORT_H__*/
diff --git a/lib/gibber/gibber-util.c b/lib/gibber/gibber-util.c
new file mode 100644
index 0000000..679406a
--- /dev/null
+++ b/lib/gibber/gibber-util.c
@@ -0,0 +1,72 @@
+/*
+ * gibber-util.c - Code for Gibber utility functions
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gibber-util.h"
+
+void
+gibber_normalize_address (struct sockaddr_storage *addr)
+{
+  struct sockaddr_in *s4 = (struct sockaddr_in *) addr;
+  struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) addr;
+
+  if (s6->sin6_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED (&(s6->sin6_addr)))
+    {
+      /* Normalize to ipv4 address */
+      u_int32_t addr_big_endian;
+      u_int16_t port;
+
+      memcpy (&addr_big_endian, s6->sin6_addr.s6_addr + 12, 4);
+      port = s6->sin6_port;
+
+      s4->sin_family = AF_INET;
+      s4->sin_addr.s_addr = addr_big_endian;
+      s4->sin_port = port;
+    }
+}
+
+/**
+ * gibber_strdiff:
+ * @left: The first string to compare (may be NULL)
+ * @right: The second string to compare (may be NULL)
+ *
+ * Return %TRUE if the given strings are different. Unlike #strcmp this
+ * function will handle null pointers, treating them as distinct from any
+ * string.
+ *
+ * Returns: %FALSE if @left and @right are both %NULL, or if
+ *          neither is %NULL and both have the same contents; %TRUE otherwise
+ */
+gboolean
+gibber_strdiff (const gchar *left, const gchar *right)
+{
+  if ((NULL == left) != (NULL == right))
+    return TRUE;
+
+  else if (left == right)
+    return FALSE;
+
+  else
+    return (0 != strcmp (left, right));
+}
diff --git a/lib/gibber/gibber-util.h b/lib/gibber/gibber-util.h
new file mode 100644
index 0000000..a611b8b
--- /dev/null
+++ b/lib/gibber/gibber-util.h
@@ -0,0 +1,34 @@
+/*
+ * gibber-util.h - Header for Gibber utility functions
+ * Copyright (C) 2007 Collabora Ltd.
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GIBBER_UTIL_H__
+#define __GIBBER_UTIL_H__
+
+#include <netdb.h>
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+void gibber_normalize_address (struct sockaddr_storage *addr);
+gboolean gibber_strdiff (const gchar *left, const gchar *right);
+
+G_END_DECLS
+
+#endif /* #ifndef __GIBBER_UTIL_H__ */
-- 
1.5.6.5




More information about the Telepathy-commits mailing list