[Telepathy-commits] [telepathy-gabble/master] bytestream-socks5: use Gibber transports instead of GIOChannel

Guillaume Desmottes guillaume.desmottes at collabora.co.uk
Tue Jan 6 08:41:40 PST 2009


---
 src/bytestream-socks5.c |  548 ++++++++++++++++++++---------------------------
 1 files changed, 235 insertions(+), 313 deletions(-)

diff --git a/src/bytestream-socks5.c b/src/bytestream-socks5.c
index 4e25cc7..0d1afae 100644
--- a/src/bytestream-socks5.c
+++ b/src/bytestream-socks5.c
@@ -42,6 +42,10 @@
 #include <loudmouth/loudmouth.h>
 #include <telepathy-glib/interfaces.h>
 
+#include <gibber/gibber-transport.h>
+#include <gibber/gibber-tcp-transport.h>
+#include <gibber/gibber-listener.h>
+
 #define DEBUG_FLAG GABBLE_DEBUG_BYTESTREAM
 
 #include "base64.h"
@@ -106,14 +110,14 @@ struct _Streamhost
 {
   gchar *jid;
   gchar *host;
-  guint port;
+  gchar *port;
 };
 typedef struct _Streamhost Streamhost;
 
 static Streamhost *
 streamhost_new (const gchar *jid,
                 const gchar *host,
-                guint port)
+                const gchar *port)
 {
   Streamhost *streamhost;
 
@@ -123,7 +127,7 @@ streamhost_new (const gchar *jid,
   streamhost = g_slice_new0 (Streamhost);
   streamhost->jid = g_strdup (jid);
   streamhost->host = g_strdup (host);
-  streamhost->port = port;
+  streamhost->port = g_strdup (port);
 
   return streamhost;
 }
@@ -136,6 +140,7 @@ streamhost_free (Streamhost *streamhost)
 
   g_free (streamhost->jid);
   g_free (streamhost->host);
+  g_free (streamhost->port);
   g_slice_free (Streamhost, streamhost);
 }
 
@@ -156,33 +161,29 @@ struct _GabbleBytestreamSocks5Private
    * around */
   LmMessage *msg_for_acknowledge_connection;
 
-  GIOChannel *io_channel;
   Socks5State socks5_state;
+  GibberTransport *transport;
+  gboolean write_blocked;
+  gboolean read_blocked;
+  GibberListener *listener;
 
-  gint read_watch;
   GString *read_buffer;
 
-  gint write_watch;
-  GString *write_buffer;
-  gsize write_position;
-
-  gint error_watch;
-
   gboolean dispose_has_run;
 };
 
 #define GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE(obj) ((obj)->priv)
 
-static gboolean socks5_connect (gpointer data);
-
-static gboolean socks5_channel_readable_cb (GIOChannel *source,
-    GIOCondition condition, gpointer data);
-static gboolean socks5_channel_error_cb (GIOChannel *source,
-    GIOCondition condition, gpointer data);
+static void socks5_connect (GabbleBytestreamSocks5 *self);
 
 static void gabble_bytestream_socks5_close (GabbleBytestreamIface *iface,
     GError *error);
 
+static void socks5_error (GabbleBytestreamSocks5 *self);
+
+static void transport_handler (GibberTransport *transport,
+    GibberBuffer *data, gpointer user_data);
+
 static void
 gabble_bytestream_socks5_init (GabbleBytestreamSocks5 *self)
 {
@@ -213,6 +214,18 @@ gabble_bytestream_socks5_dispose (GObject *object)
       gabble_bytestream_iface_close (GABBLE_BYTESTREAM_IFACE (self), NULL);
     }
 
+  if (priv->transport != NULL)
+    {
+      g_object_unref (priv->transport);
+      priv->transport = NULL;
+    }
+
+  if (priv->listener != NULL)
+    {
+      g_object_unref (priv->listener);
+      priv->listener = NULL;
+    }
+
   G_OBJECT_CLASS (gabble_bytestream_socks5_parent_class)->dispose (object);
 }
 
@@ -410,61 +423,79 @@ gabble_bytestream_socks5_class_init (
       param_spec);
 }
 
-static void
-socks5_setup_channel (GabbleBytestreamSocks5 *self,
-                      gint fd)
+static gboolean
+write_to_transport (GabbleBytestreamSocks5 *self,
+                    const gchar *data,
+                    guint len,
+                    GError **error)
 {
   GabbleBytestreamSocks5Private *priv =
       GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self);
-  gint socket_flags;
 
-  socket_flags = fcntl (fd, F_GETFL, 0);
-  fcntl (fd, F_SETFL, socket_flags | O_NONBLOCK);
+  if (!gibber_transport_send (priv->transport, (const guint8 *) data, len,
+        error))
+    {
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+transport_connected_cb (GibberTransport *transport,
+                        GabbleBytestreamSocks5 *self)
+{
+  GabbleBytestreamSocks5Private *priv =
+    GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self);
 
-  priv->io_channel = g_io_channel_unix_new (fd);
+  if (priv->socks5_state == SOCKS5_STATE_TRYING_CONNECT)
+    {
+      gchar msg[3];
 
-  g_io_channel_set_encoding (priv->io_channel, NULL, NULL);
-  g_io_channel_set_buffered (priv->io_channel, FALSE);
-  g_io_channel_set_close_on_unref (priv->io_channel, TRUE);
+      DEBUG ("transport is connected. Sending auth request");
 
-  priv->read_watch = g_io_add_watch (priv->io_channel, G_IO_IN,
-      socks5_channel_readable_cb, self);
-  priv->error_watch = g_io_add_watch (priv->io_channel, G_IO_HUP | G_IO_ERR,
-      socks5_channel_error_cb, self);
+      msg[0] = SOCKS5_VERSION;
+      /* Number of auth methods we are offering, we support just
+       * SOCKS5_AUTH_NONE */
+      msg[1] = 1;
+      msg[2] = SOCKS5_AUTH_NONE;
 
-  g_assert (priv->write_buffer == NULL);
-  priv->write_buffer = g_string_new ("");
+      write_to_transport (self, msg, 3, NULL);
 
-  g_assert (priv->read_buffer == NULL);
-  priv->read_buffer = g_string_sized_new (4096);
+      priv->socks5_state = SOCKS5_STATE_AUTH_REQUEST_SENT;
+    }
 }
 
 static void
-socks5_close_channel (GabbleBytestreamSocks5 *self)
+transport_disconnected_cb (GibberTransport *transport,
+                           GabbleBytestreamSocks5 *self)
+{
+  DEBUG ("Sock5 transport disconnected");
+  socks5_error (self);
+}
+
+static void
+change_write_blocked_state (GabbleBytestreamSocks5 *self,
+                            gboolean blocked)
 {
   GabbleBytestreamSocks5Private *priv =
       GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self);
 
-  if (priv->io_channel == NULL)
+  if (priv->write_blocked == blocked)
     return;
 
- if (priv->read_watch != 0)
-   {
-     g_source_remove (priv->read_watch);
-     priv->read_watch = 0;
-   }
+  priv->write_blocked = blocked;
+  g_signal_emit_by_name (self, "write-blocked", blocked);
+}
 
- if (priv->write_watch != 0)
-   {
-     g_source_remove (priv->write_watch);
-     priv->write_watch = 0;
-   }
+static void
+socks5_close_transport (GabbleBytestreamSocks5 *self)
+{
+  GabbleBytestreamSocks5Private *priv =
+      GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self);
 
- if (priv->error_watch != 0)
-   {
-     g_source_remove (priv->error_watch);
-     priv->error_watch = 0;
-   }
+  if (priv->transport == NULL)
+    return;
 
  if (priv->read_buffer)
    {
@@ -472,14 +503,59 @@ socks5_close_channel (GabbleBytestreamSocks5 *self)
      priv->read_buffer = NULL;
    }
 
- if (priv->write_buffer)
-   {
-     g_string_free (priv->write_buffer, TRUE);
-     priv->write_buffer = NULL;
-   }
+ g_signal_handlers_disconnect_matched (priv->transport,
+        G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
 
- g_io_channel_unref (priv->io_channel);
- priv->io_channel = NULL;
+ g_object_unref (priv->transport);
+ priv->transport = NULL;
+}
+
+static void
+bytestream_closed (GabbleBytestreamSocks5 *self)
+{
+  socks5_close_transport (self);
+  g_object_set (self, "state", GABBLE_BYTESTREAM_STATE_CLOSED, NULL);
+}
+
+static void
+transport_buffer_empty_cb (GibberTransport *transport,
+                           GabbleBytestreamSocks5 *self)
+{
+  GabbleBytestreamSocks5Private *priv = GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE
+      (self);
+
+  if (priv->bytestream_state == GABBLE_BYTESTREAM_STATE_CLOSING)
+    {
+      DEBUG ("buffer is now empty. Bytestream can be closed");
+      bytestream_closed (self);
+    }
+  else if (priv->write_blocked)
+    {
+      DEBUG ("buffer is empty, unblock write to the bytestream");
+      change_write_blocked_state (self, FALSE);
+    }
+}
+
+static void
+set_transport (GabbleBytestreamSocks5 *self,
+               GibberTransport *transport)
+{
+  GabbleBytestreamSocks5Private *priv =
+      GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self);
+
+  priv->transport = g_object_ref (transport);
+
+  g_assert (priv->read_buffer == NULL);
+  priv->read_buffer = g_string_sized_new (4096);
+
+  gibber_transport_set_handler (transport, transport_handler, self);
+
+  g_signal_connect (transport, "connected",
+      G_CALLBACK (transport_connected_cb), self);
+  g_signal_connect (transport, "disconnected",
+      G_CALLBACK (transport_disconnected_cb), self);
+  g_signal_connect (priv->transport, "buffer-empty",
+      G_CALLBACK (transport_buffer_empty_cb), self);
 }
 
 static void
@@ -497,7 +573,7 @@ socks5_error (GabbleBytestreamSocks5 *self)
       previous_state == SOCKS5_STATE_CONNECT_REQUESTED)
     {
       /* The attempt for connect to the streamhost failed */
-      socks5_close_channel (self);
+      socks5_close_transport (self);
 
       /* Remove the failed streamhost */
       g_assert (priv->streamhosts);
@@ -531,61 +607,6 @@ socks5_error (GabbleBytestreamSocks5 *self)
   return;
 }
 
-static gboolean
-socks5_channel_writable_cb (GIOChannel *source,
-                            GIOCondition condition,
-                            gpointer data)
-{
-  GabbleBytestreamSocks5 *self = GABBLE_BYTESTREAM_SOCKS5 (data);
-  GabbleBytestreamSocks5Private *priv =
-      GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self);
-  gsize remaining_length = priv->write_buffer->len - priv->write_position;
-  GIOStatus status;
-  gsize bytes_written;
-
-  g_assert (remaining_length > 0);
-
-  status = g_io_channel_write_chars (priv->io_channel,
-      &priv->write_buffer->str [priv->write_position], remaining_length,
-      &bytes_written, NULL);
-
-  remaining_length -= bytes_written;
-  if (remaining_length == 0)
-    {
-      g_string_truncate (priv->write_buffer, 0);
-      priv->write_position = 0;
-      priv->write_watch = 0;
-      return FALSE;
-    }
-
-  priv->write_position += bytes_written;
-
-  if (status != G_IO_STATUS_NORMAL)
-    {
-      DEBUG ("Error writing on the SOCKS5 bytestream");
-
-      socks5_error (self);
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
-static void
-socks5_schedule_write (GabbleBytestreamSocks5 *self,
-                       const gchar *msg,
-                       gsize len)
-{
-  GabbleBytestreamSocks5Private *priv =
-      GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self);
-
-  g_string_append_len (priv->write_buffer, msg, len);
-
-  if (!priv->write_watch)
-    priv->write_watch = g_io_add_watch (priv->io_channel, G_IO_OUT,
-        socks5_channel_writable_cb, self);
-}
-
 /* Process the received data and returns the number of bytes that have been
  * used */
 static gsize
@@ -644,7 +665,7 @@ socks5_handle_received_data (GabbleBytestreamSocks5 *self,
         g_free (domain);
         g_free (unhashed_domain);
 
-        socks5_schedule_write (self, msg, SOCKS5_CONNECT_LENGTH);
+        write_to_transport (self, msg, SOCKS5_CONNECT_LENGTH, NULL);
 
         priv->socks5_state = SOCKS5_STATE_CONNECT_REQUESTED;
 
@@ -721,7 +742,7 @@ socks5_handle_received_data (GabbleBytestreamSocks5 *self,
                 /* Authorize the connection */
                 msg[0] = SOCKS5_VERSION;
                 msg[1] = SOCKS5_AUTH_NONE;
-                socks5_schedule_write (self, msg, 2);
+                write_to_transport (self, msg, 2, NULL);
 
                 priv->socks5_state = SOCKS5_STATE_AWAITING_COMMAND;
 
@@ -765,7 +786,7 @@ socks5_handle_received_data (GabbleBytestreamSocks5 *self,
         msg[0] = SOCKS5_VERSION;
         msg[1] = SOCKS5_STATUS_OK;
 
-        socks5_schedule_write (self, msg, 2);
+        write_to_transport (self, msg, 2, NULL);
 
         priv->socks5_state = SOCKS5_STATE_CONNECTED;
 
@@ -785,7 +806,8 @@ socks5_handle_received_data (GabbleBytestreamSocks5 *self,
         return string->len;
 
       case SOCKS5_STATE_TRYING_CONNECT:
-        DEBUG ("Impossible to receive data when not yet connected to the socket");
+        DEBUG ("Impossible to receive data when not yet connected to the "
+            "socket");
         break;
 
       case SOCKS5_STATE_INVALID:
@@ -797,45 +819,21 @@ socks5_handle_received_data (GabbleBytestreamSocks5 *self,
   return string->len;
 }
 
-static gboolean
-socks5_channel_readable_cb (GIOChannel *source,
-                            GIOCondition condition,
-                            gpointer data)
+static void
+transport_handler (GibberTransport *transport,
+                   GibberBuffer *data,
+                   gpointer user_data)
+
 {
-  GabbleBytestreamSocks5 *self = GABBLE_BYTESTREAM_SOCKS5 (data);
+  GabbleBytestreamSocks5 *self = GABBLE_BYTESTREAM_SOCKS5 (user_data);
   GabbleBytestreamSocks5Private *priv =
       GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self);
-  gsize available_length =
-    priv->read_buffer->allocated_len - priv->read_buffer->len - 1;
-  GIOStatus status;
-  gsize bytes_read;
   gsize used_bytes;
 
-  if (available_length == 0)
-    {
-      g_string_set_size (priv->read_buffer, priv->read_buffer->len * 2);
-      available_length = priv->read_buffer->allocated_len -
-          priv->read_buffer->len - 1;
-    }
+  DEBUG ("got %u bytes from sock5 transport", data->length);
 
-  status = g_io_channel_read_chars (source,
-      &priv->read_buffer->str [priv->read_buffer->len], available_length,
-      &bytes_read, NULL);
-
-  switch (status)
-    {
-      case G_IO_STATUS_AGAIN:
-        return TRUE;
-      case G_IO_STATUS_ERROR:
-      case G_IO_STATUS_EOF:
-        socks5_error (self);
-        return FALSE;
-      case G_IO_STATUS_NORMAL:
-        break;
-    }
-
-  priv->read_buffer->len += bytes_read;
-  priv->read_buffer->str[priv->read_buffer->len] = '\0';
+  g_string_append_len (priv->read_buffer, (const gchar *) data->data,
+      data->length);
 
   do
     {
@@ -843,39 +841,24 @@ socks5_channel_readable_cb (GIOChannel *source,
        * number of bytes that have been used. 0 means that there is not enough
        * data to do anything, so we just wait for more data from the socket */
       used_bytes = socks5_handle_received_data (self, priv->read_buffer);
+
+      if (priv->read_buffer == NULL)
+        /* If something did wrong in socks5_handle_received_data, the
+         * bytestream can be closed and so destroyed. */
+        return;
+
       g_string_erase (priv->read_buffer, 0, used_bytes);
     }
   while (used_bytes > 0 && priv->read_buffer->len > 0);
-
-  return TRUE;
 }
 
-static gboolean
-socks5_channel_error_cb (GIOChannel *source,
-                         GIOCondition condition,
-                         gpointer data)
-{
-  GabbleBytestreamSocks5 *self = GABBLE_BYTESTREAM_SOCKS5 (data);
-
-  DEBUG ("I/O error on a SOCKS5 channel");
-
-  socks5_error (self);
-  return FALSE;
-}
-
-static gboolean
-socks5_connect (gpointer data)
+static void
+socks5_connect (GabbleBytestreamSocks5 *self)
 {
-  GabbleBytestreamSocks5 *self = GABBLE_BYTESTREAM_SOCKS5 (data);
   GabbleBytestreamSocks5Private *priv =
       GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self);
   Streamhost* streamhost;
-  struct addrinfo req = {0};
-  struct addrinfo *address_list;
-  struct addrinfo *streamhost_address;
-  gint fd;
-  gint res;
-  gchar msg[3];
+  GibberTCPTransport *transport;
 
   priv->socks5_state = SOCKS5_STATE_TRYING_CONNECT;
 
@@ -888,79 +871,20 @@ socks5_connect (gpointer data)
       DEBUG ("No more streamhosts to try, closing");
 
       socks5_error (self);
-      return FALSE;
+      return;
     }
 
-  DEBUG ("Trying streamhost %s on port %d", streamhost->host,
+  DEBUG ("Trying streamhost %s on port %s", streamhost->host,
       streamhost->port);
 
-  req.ai_family = AF_UNSPEC;
-  req.ai_socktype = SOCK_STREAM;
-  req.ai_protocol = IPPROTO_TCP;
-
-  if (getaddrinfo (streamhost->host, NULL, &req, &address_list) != 0)
-    {
-      DEBUG ("getaddrinfo on %s failed", streamhost->host);
-      socks5_error (self);
-
-      return FALSE;
-    }
-
-  fd = -1;
-  streamhost_address = address_list;
-
-  /* getaddrinfo returns a list of addrinfo structures that identify the
-   * host. Try them in order and stop when the call to socket() succeeds */
-  while (fd < 0 && streamhost_address)
-    {
-      ((struct sockaddr_in *) streamhost_address->ai_addr)->sin_port =
-        htons (streamhost->port);
-
-      fd = socket (streamhost_address->ai_family,
-          streamhost_address->ai_socktype, streamhost_address->ai_protocol);
-
-      if (fd >= 0)
-        break;
-
-      streamhost_address = streamhost_address->ai_next;
-    }
-
-
-  if (fd < 0)
-    {
-      gabble_bytestream_socks5_close (GABBLE_BYTESTREAM_IFACE (self), NULL);
-      freeaddrinfo (address_list);
-
-      return FALSE;
-    }
-
-  socks5_setup_channel (self, fd);
-
-  res = connect (fd, (struct sockaddr*)streamhost_address->ai_addr,
-      streamhost_address->ai_addrlen);
+  transport = gibber_tcp_transport_new ();
+  set_transport (self, GIBBER_TRANSPORT (transport));
+  g_object_unref (transport);
 
-  freeaddrinfo (address_list);
-
-  if (res < 0 && errno != EINPROGRESS)
-    {
-      DEBUG ("connect failed");
-
-      socks5_error (self);
-      return FALSE;
-    }
-
-
-  msg[0] = SOCKS5_VERSION;
-  /* Number of auth methods we are offering, we support just
-   * SOCKS5_AUTH_NONE */
-  msg[1] = 1;
-  msg[2] = SOCKS5_AUTH_NONE;
-
-  socks5_schedule_write (self, msg, 3);
-
-  priv->socks5_state = SOCKS5_STATE_AUTH_REQUEST_SENT;
+  gibber_tcp_transport_connect (transport, streamhost->host,
+      streamhost->port);
 
-  return FALSE;
+  /* We'll send the auth request once the transport is connected */
 }
 
 /**
@@ -978,7 +902,6 @@ gabble_bytestream_socks5_add_streamhost (GabbleBytestreamSocks5 *self,
   const gchar *jid;
   const gchar *host;
   const gchar *port;
-  guint numeric_port;
   Streamhost *streamhost;
 
   g_return_if_fail (!tp_strdiff (streamhost_node->name, "streamhost"));
@@ -1012,17 +935,10 @@ gabble_bytestream_socks5_add_streamhost (GabbleBytestreamSocks5 *self,
       return;
     }
 
-  numeric_port = strtoul (port, NULL, 10);
-  if (numeric_port <= 0)
-    {
-      DEBUG ("streamhost contain an invalid port: %s", port);
-      return;
-    }
-
-  DEBUG ("streamhost with jid %s, host %s and port %d added", jid, host,
-      numeric_port);
+  DEBUG ("streamhost with jid %s, host %s and port %s added", jid, host,
+      port);
 
-  streamhost = streamhost_new (jid, host, numeric_port);
+  streamhost = streamhost_new (jid, host, port);
   priv->streamhosts = g_slist_append (priv->streamhosts, streamhost);
 }
 
@@ -1041,7 +957,7 @@ gabble_bytestream_socks5_connect_to_streamhost (GabbleBytestreamSocks5 *self,
 
   priv->msg_for_acknowledge_connection = lm_message_ref (msg);
 
-  g_idle_add (socks5_connect, self);
+  socks5_connect (self);
 }
 
 /*
@@ -1057,6 +973,7 @@ gabble_bytestream_socks5_send (GabbleBytestreamIface *iface,
   GabbleBytestreamSocks5 *self = GABBLE_BYTESTREAM_SOCKS5 (iface);
   GabbleBytestreamSocks5Private *priv =
       GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self);
+  GError *error = NULL;
 
   if (priv->bytestream_state != GABBLE_BYTESTREAM_STATE_OPEN)
     {
@@ -1065,7 +982,27 @@ gabble_bytestream_socks5_send (GabbleBytestreamIface *iface,
       return FALSE;
     }
 
-  socks5_schedule_write (self, str, len);
+  if (priv->write_blocked)
+    {
+      DEBUG ("sending data while the bytestream was blocked");
+    }
+
+  DEBUG ("send %u bytes through bytestream", len);
+  if (!write_to_transport (self, str, len, &error))
+    {
+      DEBUG ("sending failed: %s", error->message);
+
+      g_error_free (error);
+      gabble_bytestream_iface_close (GABBLE_BYTESTREAM_IFACE (self), NULL);
+      return FALSE;
+    }
+
+  if (!gibber_transport_buffer_is_empty (priv->transport))
+    {
+      /* We >don't want to send more data while the buffer isn't empty */
+      DEBUG ("buffer isn't empty. Block write to the bytestream");
+      change_write_blocked_state (self, TRUE);
+    }
 
   return TRUE;
 }
@@ -1174,8 +1111,6 @@ gabble_bytestream_socks5_close (GabbleBytestreamIface *iface,
 
       DEBUG ("send Socks5 close stanza");
 
-      socks5_close_channel (self);
-
       msg = lm_message_build (priv->peer_jid, LM_MESSAGE_TYPE_IQ,
           '@', "type", "set",
           '(', "close", "",
@@ -1190,7 +1125,17 @@ gabble_bytestream_socks5_close (GabbleBytestreamIface *iface,
 
       lm_message_unref (msg);
 
-      g_object_set (self, "state", GABBLE_BYTESTREAM_STATE_CLOSED, NULL);
+      g_object_set (self, "state", GABBLE_BYTESTREAM_STATE_CLOSING, NULL);
+      if (priv->transport != NULL &&
+          !gibber_transport_buffer_is_empty (priv->transport))
+        {
+          DEBUG ("Wait transport buffer is empty before close the bytestream");
+        }
+      else
+        {
+          DEBUG ("Transport buffer is empty, we can close the bytestream");
+          bytestream_closed (self);
+        }
     }
 }
 
@@ -1218,35 +1163,6 @@ socks5_init_reply_cb (GabbleConnection *conn,
   return LM_HANDLER_RESULT_REMOVE_MESSAGE;
 }
 
-static gboolean
-socks5_listen_cb (GIOChannel *source,
-                  GIOCondition condition,
-                  gpointer data)
-{
-  GabbleBytestreamSocks5 *self = GABBLE_BYTESTREAM_SOCKS5 (data);
-  GabbleBytestreamSocks5Private *priv =
-      GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self);
-  gint fd;
-  struct sockaddr_in addr;
-  guint addr_len = sizeof (addr);
-
-  if (condition & G_IO_ERR || condition & G_IO_HUP)
-    {
-      socks5_error (self);
-
-      return FALSE;
-    }
-
-  fd = accept (g_io_channel_unix_get_fd (source), (struct sockaddr *) &addr,
-      &addr_len);
-
-  socks5_setup_channel (self, fd);
-
-  priv->socks5_state = SOCKS5_STATE_AWAITING_AUTH_REQUEST;
-
-  return FALSE;
-}
-
 /* get_local_interfaces_ips copied from Farsight 2 (function
  * fs_interfaces_get_local_ips in /gst-libs/gst/farsight/fs-interfaces.c).
  *   Copyright (C) 2006 Youness Alaoui <kakaroto at kakaroto.homelinux.net>
@@ -1384,6 +1300,25 @@ get_local_interfaces_ips (gboolean include_loopback)
 
 #endif /* ! HAVE_GETIFADDRS */
 
+static void
+new_connection_cb (GibberListener *listener,
+                   GibberTransport *transport,
+                   struct sockaddr *addr,
+                   guint size,
+                   gpointer user_data)
+{
+  GabbleBytestreamSocks5 *self = GABBLE_BYTESTREAM_SOCKS5 (user_data);
+  GabbleBytestreamSocks5Private *priv =
+    GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self);
+
+  DEBUG ("New connection...");
+
+  priv->socks5_state = SOCKS5_STATE_AWAITING_AUTH_REQUEST;
+  set_transport (self, transport);
+
+  /* FIXME: we should stop to listen at some point */
+}
+
 /*
  * gabble_bytestream_socks5_initiate
  *
@@ -1395,11 +1330,8 @@ gabble_bytestream_socks5_initiate (GabbleBytestreamIface *iface)
   GabbleBytestreamSocks5 *self = GABBLE_BYTESTREAM_SOCKS5 (iface);
   GabbleBytestreamSocks5Private *priv =
       GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self);
-  struct sockaddr_in addr;
-  guint addr_len;
-  gint fd;
-  GIOChannel *channel;
-  gchar port[G_ASCII_DTOSTR_BUF_SIZE];
+  gchar *port;
+  gint port_num;
   LmMessage *msg;
   GList *ips;
   GList *ip;
@@ -1411,31 +1343,20 @@ gabble_bytestream_socks5_initiate (GabbleBytestreamIface *iface)
       return FALSE;
     }
 
-  fd = socket (AF_INET, SOCK_STREAM, 0);
-  if (fd < 0)
-    {
-      DEBUG ("couldn't create socket");
-      return FALSE;
-    }
+  g_assert (priv->listener == NULL);
+  priv->listener = gibber_listener_new ();
+
+  g_signal_connect (priv->listener, "new-connection",
+      G_CALLBACK (new_connection_cb), self);
 
-  if (listen (fd, 1) < 0)
+  if (!gibber_listener_listen_tcp (priv->listener, 0, NULL))
     {
-      DEBUG ("couldn't listen on socket");
+      DEBUG ("can't listen for incoming connection");
       return FALSE;
     }
 
-  channel = g_io_channel_unix_new (fd);
-
-  g_io_channel_set_close_on_unref (channel, TRUE);
-
-  priv->read_watch = g_io_add_watch (channel, G_IO_IN | G_IO_HUP | G_IO_ERR,
-      socks5_listen_cb, self);
-
-  g_io_channel_unref (channel);
-
-  addr_len = sizeof (addr);
-  getsockname (fd, (struct sockaddr *) &addr, &addr_len);
-  g_ascii_dtostr (port, G_N_ELEMENTS (port), ntohs (addr.sin_port));
+  port_num = gibber_listener_get_port (priv->listener);
+  port = g_strdup_printf ("%d", port_num);
 
   msg = lm_message_build (priv->peer_jid, LM_MESSAGE_TYPE_IQ,
       '@', "type", "set",
@@ -1460,6 +1381,7 @@ gabble_bytestream_socks5_initiate (GabbleBytestreamIface *iface)
       ip = ip->next;
     }
   g_list_free (ips);
+  g_free (port);
 
   /* FIXME: for now we support only direct connections, we should also
    * add support for external proxies to have more chances to make the
-- 
1.5.6.5




More information about the Telepathy-commits mailing list