[telepathy-gabble/master] file-transfer-channel: use Gibber transports

Guillaume Desmottes guillaume.desmottes at collabora.co.uk
Fri Apr 3 09:26:08 PDT 2009


---
 src/file-transfer-channel.c |  262 ++++++++++++++++--------------------------
 1 files changed, 100 insertions(+), 162 deletions(-)

diff --git a/src/file-transfer-channel.c b/src/file-transfer-channel.c
index 8e04a24..c0ad6a0 100644
--- a/src/file-transfer-channel.c
+++ b/src/file-transfer-channel.c
@@ -33,6 +33,9 @@
 
 #include <loudmouth/loudmouth.h>
 
+#include <gibber/gibber-listener.h>
+#include <gibber/gibber-transport.h>
+
 #include "bytestream-factory.h"
 #include "connection.h"
 #include "file-transfer-channel.h"
@@ -119,9 +122,8 @@ struct _GabbleFileTransferChannelPrivate {
   gboolean remote_accepted;
 
   GabbleBytestreamIface *bytestream;
-  GIOChannel *channel;
-  /* the watch id on the channel */
-  guint watch_id;
+  GibberListener *listener;
+  GibberTransport *transport;
 
   /* properties */
   TpFileTransferState state;
@@ -767,16 +769,16 @@ gabble_file_transfer_channel_dispose (GObject *object)
       self->priv->bytestream = NULL;
     }
 
-  if (self->priv->watch_id != 0)
+  if (self->priv->listener != NULL)
     {
-      g_source_remove (self->priv->watch_id);
-      self->priv->watch_id = 0;
+      g_object_unref (self->priv->listener);
+      self->priv->listener = NULL;
     }
 
-  if (self->priv->channel != NULL)
+  if (self->priv->transport != NULL)
     {
-      g_io_channel_unref (self->priv->channel);
-      self->priv->channel = NULL;
+      g_object_unref (self->priv->transport);
+      self->priv->transport = NULL;
     }
 
   /* release any references held by the object here */
@@ -1239,13 +1241,24 @@ data_received_cb (GabbleBytestreamIface *stream,
                   gpointer user_data)
 {
   GabbleFileTransferChannel *self = GABBLE_FILE_TRANSFER_CHANNEL (user_data);
-  GIOStatus status;
+  GError *error = NULL;
+
+  g_assert (self->priv->transport != NULL);
+
+  if (!gibber_transport_send (self->priv->transport, (const guint8 *) data->str,
+        data->len, &error))
+    {
+      DEBUG ("sending to transport failed: %s", error->message);
+      g_error_free (error);
 
-  g_assert (self->priv->channel != NULL);
+      gabble_file_transfer_channel_set_state (
+          TP_SVC_CHANNEL_TYPE_FILE_TRANSFER (self),
+          TP_FILE_TRANSFER_STATE_CANCELLED,
+          TP_FILE_TRANSFER_STATE_CHANGE_REASON_LOCAL_ERROR);
+      return;
+    }
 
   DEBUG ("received %u bytes from bytestream. Writing to socket", data->len);
-  status = g_io_channel_write_chars (self->priv->channel, data->str,
-      data->len, NULL, NULL);
 
   transferred_chunk (self, (guint64) data->len);
 
@@ -1448,130 +1461,46 @@ get_local_unix_socket_path (GabbleFileTransferChannel *self)
 }
 
 /*
- * Return a GIOChannel for the local unix socket path.
- */
-static GIOChannel *
-get_socket_channel (GabbleFileTransferChannel *self)
-{
-  gint fd;
-  const gchar *path;
-  size_t path_len;
-  struct sockaddr_un addr;
-  GIOChannel *io_channel;
-
-  path = get_local_unix_socket_path (self);
-
-  /* FIXME: should use the socket type and access control chosen by
-   * the user. */
-  fd = socket (PF_UNIX, SOCK_STREAM, 0);
-  if (fd < 0)
-    {
-      DEBUG("socket() failed");
-      return NULL;
-    }
-
-  memset (&addr, 0, sizeof (addr));
-  addr.sun_family = AF_UNIX;
-  path_len = strlen (path);
-  strncpy (addr.sun_path, path, path_len);
-  g_unlink (path);
-
-  if (bind (fd, (struct sockaddr*) &addr,
-        G_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0)
-    {
-      DEBUG ("bind failed");
-      close (fd);
-      return NULL;
-    }
-
-  if (listen (fd, 1) < 0)
-    {
-      DEBUG ("listen failed");
-      close (fd);
-      return NULL;
-    }
-
-  io_channel = g_io_channel_unix_new (fd);
-  g_io_channel_set_close_on_unref (io_channel, TRUE);
-  return io_channel;
-}
-
-/*
  * Data is available from the channel so we can send it.
  */
-static gboolean
-input_channel_readable_cb (GIOChannel *source,
-                           GIOCondition condition,
-                           gpointer user_data)
+static void
+transport_handler (GibberTransport *transport,
+                   GibberBuffer *data,
+                   gpointer user_data)
 {
   GabbleFileTransferChannel *self = GABBLE_FILE_TRANSFER_CHANNEL (user_data);
-  GIOStatus status;
 
-#define BUFF_SIZE 4096
+  DEBUG("Data available, writing a %"G_GSIZE_FORMAT" bytes chunk",
+      data->length);
 
-  if (condition & G_IO_IN)
+  if (!gabble_bytestream_iface_send (self->priv->bytestream, data->length,
+        (const gchar *) data->data))
     {
-      gchar *buff;
-      gsize bytes_read;
-
-      buff = g_malloc (BUFF_SIZE);
-      status = g_io_channel_read_chars (source, buff, BUFF_SIZE,
-          &bytes_read, NULL);
-      switch (status)
-        {
-        case G_IO_STATUS_NORMAL:
-          if (!gabble_bytestream_iface_send (self->priv->bytestream, bytes_read,
-              buff))
-            {
-              DEBUG ("Sending failed. Closing the bytestream");
-              gabble_bytestream_iface_close (self->priv->bytestream, NULL);
-              return FALSE;
-            }
+      DEBUG ("Sending failed. Closing the bytestream");
+      gabble_bytestream_iface_close (self->priv->bytestream, NULL);
+      return;
+    }
 
-          DEBUG("Data available, writing a %"G_GSIZE_FORMAT" bytes chunk",
-              bytes_read);
-          transferred_chunk (self, (guint64) bytes_read);
+  transferred_chunk (self, (guint64) data->length);
 
-          if (self->priv->transferred_bytes >= self->priv->size)
-            {
-              DEBUG ("All the file has been sent. Closing the bytestream");
+  if (self->priv->transferred_bytes >= self->priv->size)
+    {
+      DEBUG ("All the file has been sent. Closing the bytestream");
 
-              gabble_file_transfer_channel_set_state (
-                  TP_SVC_CHANNEL_TYPE_FILE_TRANSFER (self),
-                  TP_FILE_TRANSFER_STATE_COMPLETED,
-                  TP_FILE_TRANSFER_STATE_CHANGE_REASON_NONE);
+      gabble_file_transfer_channel_set_state (
+          TP_SVC_CHANNEL_TYPE_FILE_TRANSFER (self),
+          TP_FILE_TRANSFER_STATE_COMPLETED,
+          TP_FILE_TRANSFER_STATE_CHANGE_REASON_NONE);
 
-              gabble_bytestream_iface_close (self->priv->bytestream, NULL);
-              return FALSE;
-            }
-          return TRUE;
-        case G_IO_STATUS_AGAIN:
-          DEBUG("Data available, try again");
-          g_free (buff);
-          return TRUE;
-        case G_IO_STATUS_EOF:
-          DEBUG("EOF received on input");
-          break;
-        default:
-          DEBUG ("Read from the channel failed");
-      }
-      g_free (buff);
+      gabble_bytestream_iface_close (self->priv->bytestream, NULL);
+      return;
     }
-
-#undef BUFF_SIZE
-
-  DEBUG("Closing transfer");
-
-  g_io_channel_unref (self->priv->channel);
-  self->priv->channel = NULL;
-  return FALSE;
 }
 
 static void
 file_transfer_send (GabbleFileTransferChannel *self)
 {
-  self->priv->watch_id = g_io_add_watch (self->priv->channel,
-          G_IO_IN | G_IO_HUP, input_channel_readable_cb, self);
+  gibber_transport_set_handler (self->priv->transport, transport_handler, self);
 }
 
 static void
@@ -1582,68 +1511,77 @@ file_transfer_receive (GabbleFileTransferChannel *self)
   gabble_bytestream_iface_block_reading (self->priv->bytestream, FALSE);
 }
 
+static void
+transport_disconnected_cb (GibberTransport *transport,
+                           GabbleFileTransferChannel *self)
+{
+  DEBUG ("transport to local socket has been disconnected");
+
+  gabble_file_transfer_channel_set_state (
+      TP_SVC_CHANNEL_TYPE_FILE_TRANSFER (self),
+      TP_FILE_TRANSFER_STATE_CANCELLED,
+      TP_FILE_TRANSFER_STATE_CHANGE_REASON_LOCAL_ERROR);
+}
+
 /*
  * Some client is connecting to the Unix socket.
  */
-static gboolean
-accept_local_socket_connection (GIOChannel *source,
-                                GIOCondition condition,
-                                gpointer user_data)
+static void
+new_connection_cb (GibberListener *listener,
+                   GibberTransport *transport,
+                   struct sockaddr_storage *addr,
+                   guint size,
+                   gpointer user_data)
 {
   GabbleFileTransferChannel *self = GABBLE_FILE_TRANSFER_CHANNEL (user_data);
-  int new_fd;
-  struct sockaddr_un addr;
-  socklen_t addrlen;
+  gboolean requested;
+  TpBaseConnection *base_conn = (TpBaseConnection *) \
+      self->priv->connection;
 
-  if (condition & G_IO_IN)
-    {
-      gboolean requested;
-      TpBaseConnection *base_conn = (TpBaseConnection *) \
-          self->priv->connection;
-
-      DEBUG ("Client connected to local socket");
-
-      addrlen = sizeof (addr);
-      new_fd = accept (g_io_channel_unix_get_fd (source),
-          (struct sockaddr *) &addr, &addrlen);
-      if (new_fd < 0)
-        {
-          DEBUG ("accept() failed");
-          return FALSE;
-        }
+  DEBUG ("Client connected to local socket");
 
-      self->priv->channel = g_io_channel_unix_new (new_fd);
-      g_io_channel_set_close_on_unref (self->priv->channel, TRUE);
-      g_io_channel_set_encoding (self->priv->channel, NULL, NULL);
-      g_io_channel_set_buffered (self->priv->channel, FALSE);
+  self->priv->transport = g_object_ref (transport);
+  gabble_signal_connect_weak (transport, "disconnected",
+    G_CALLBACK (transport_disconnected_cb), G_OBJECT (self));
 
-      requested = (self->priv->initiator == base_conn->self_handle);
+  requested = (self->priv->initiator == base_conn->self_handle);
 
-      if (!requested)
-        /* Incoming file transfer */
-        file_transfer_receive (self);
-      else
-        /* Outgoing file transfer */
-        file_transfer_send (self);
-    }
+  if (!requested)
+    /* Incoming file transfer */
+    file_transfer_receive (self);
+  else
+    /* Outgoing file transfer */
+    file_transfer_send (self);
 
-  return FALSE;
+  /* stop listening on local socket */
+  g_object_unref (self->priv->listener);
+  self->priv->listener = NULL;
 }
 
 static gboolean
 setup_local_socket (GabbleFileTransferChannel *self)
 {
-  GIOChannel *io_channel;
+  const gchar *path;
+  GError *error = NULL;
+
+  path = get_local_unix_socket_path (self);
 
-  io_channel = get_socket_channel (self);
-  if (io_channel == NULL)
+  self->priv->listener = gibber_listener_new ();
+
+  /* FIXME: should use the socket type and access control chosen by
+   * the user. */
+  if (!gibber_listener_listen_socket (self->priv->listener, (gchar *) path,
+        FALSE, &error))
     {
+      DEBUG ("listen_socket failed: %s", error->message);
+      g_error_free (error);
+      g_object_unref (self->priv->listener);
+      self->priv->listener = NULL;
       return FALSE;
     }
 
-  g_io_add_watch (io_channel, G_IO_IN | G_IO_HUP,
-      accept_local_socket_connection, self);
-  g_io_channel_unref (io_channel);
+  g_signal_connect (self->priv->listener, "new-connection",
+    G_CALLBACK (new_connection_cb), self);
 
   return TRUE;
 }
-- 
1.5.6.5




More information about the telepathy-commits mailing list