[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