[Telepathy-commits] [telepathy-gabble/master] Handle errors on the SOCKS5 bytestream

Marco Barisione marco at barisione.org
Tue Jan 6 08:41:26 PST 2009


---
 src/bytestream-socks5.c |  167 ++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 129 insertions(+), 38 deletions(-)

diff --git a/src/bytestream-socks5.c b/src/bytestream-socks5.c
index 7fb741d..38dee64 100644
--- a/src/bytestream-socks5.c
+++ b/src/bytestream-socks5.c
@@ -95,6 +95,7 @@ enum _Socks5State
   SOCKS5_STATE_CONNECTED,
   SOCKS5_STATE_AWAITING_AUTH_REQUEST,
   SOCKS5_STATE_AWAITING_COMMAND,
+  SOCKS5_STATE_ERROR
 };
 
 typedef enum _Socks5State Socks5State;
@@ -174,7 +175,7 @@ struct _GabbleBytestreamSocks5Private
 
 #define GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE(obj) ((obj)->priv)
 
-static void socks5_connect_next (GabbleBytestreamSocks5 *self);
+static gboolean socks5_connect (gpointer data);
 
 static void gabble_bytestream_socks5_close (GabbleBytestreamIface *iface,
     GError *error);
@@ -417,6 +418,47 @@ gabble_bytestream_socks5_class_init (
                   G_TYPE_NONE, 1, G_TYPE_UINT);
 }
 
+static void
+socks5_error (GabbleBytestreamSocks5 *self)
+{
+  GabbleBytestreamSocks5 *self = GABBLE_BYTESTREAM_SOCKS5 (data);
+  GabbleBytestreamSocks5Private *priv = GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self);
+
+  priv->socks5_state = SOCKS5_STATE_ERROR;
+
+  if (priv->msg_for_acknowledge_connection)
+    {
+      /* The attempt for connect to the streamhost failed... */
+      g_assert (priv->streamhosts);
+      streamhost_free (priv->streamhosts->data);
+      priv->streamhosts = g_slist_delete_link (priv->streamhosts, priv->streamhosts);
+
+      if (priv->streamhosts != NULL)
+        {
+          /* ... so let's try to connect to the next one */
+          DEBUG ("connection to streamhost failed, trying the next one");
+
+          socks5_connect (self);
+          return;
+        }
+
+      /* ... but there are no more streamhosts */
+      DEBUG ("no more streamhosts to try");
+      _gabble_connection_send_iq_error (priv->conn,
+          priv->msg_for_acknowledge_connection, XMPP_ERROR_ITEM_NOT_FOUND,
+          "impossible to connect to any streamhost");
+
+      lm_message_unref (priv->msg_for_acknowledge_connection);
+      priv->msg_for_acknowledge_connection = NULL;
+    }
+
+  DEBUG ("error, closing the connection\n");
+
+  gabble_bytestream_socks5_close (GABBLE_BYTESTREAM_IFACE (self), NULL);
+
+  return;
+}
+
 static gboolean 
 socks5_channel_writable_cb (GIOChannel *source, 
                             GIOCondition condition,
@@ -447,7 +489,9 @@ socks5_channel_writable_cb (GIOChannel *source,
 
   if (status != G_IO_STATUS_NORMAL)
     {
-      /* FIXME handle errors. */
+      DEBUG ("Error writing on the SOCSK5 bytestream");
+
+      socks5_error (self);
       return FALSE;
     }
 
@@ -486,9 +530,14 @@ socks5_handle_received_data (GabbleBytestreamSocks5 *self,
         if (string->len < 2)
           return 0;
 
-        /* FIXME: do proper checking */
-        g_assert (string->str[0] == SOCKS5_VERSION &&
-            string->str[1] == SOCKS5_STATUS_OK);
+        if (string->str[0] != SOCKS5_VERSION ||
+            string->str[1] != SOCKS5_STATUS_OK)
+          {
+            DEBUG ("Authentication failed");
+
+            socks5_error (self);
+            return string->len;
+          }
 
         from = lm_message_node_get_attribute (
             priv->msg_for_acknowledge_connection->node, "from");
@@ -522,9 +571,14 @@ socks5_handle_received_data (GabbleBytestreamSocks5 *self,
         if (string->len < 2)
           return 0;
 
-        /* FIXME: handle errors */
-        g_assert (string->str[0] == SOCKS5_VERSION &&
-            string->str[1] == SOCKS5_STATUS_OK);
+        if (string->str[0] != SOCKS5_VERSION ||
+            string->str[1] != SOCKS5_STATUS_OK)
+          {
+            DEBUG ("Connection refused");
+
+            socks5_error (self);
+            return string->len;
+          }
 
         priv->socks5_state = SOCKS5_STATE_CONNECTED;
 
@@ -553,10 +607,16 @@ socks5_handle_received_data (GabbleBytestreamSocks5 *self,
         if (string->len < 3)
           return 0;
 
-        /* FIXME: handle errors */
-        g_assert (string->str[0] == SOCKS5_VERSION &&
-            string->str[1] == 1 &&
-            string->str[2] == SOCKS5_AUTH_NONE);
+        /* FIXME */
+        if (string->str[0] != SOCKS5_VERSION ||
+            string->str[1] != 1 ||
+            string->str[2] != SOCKS5_AUTH_NONE)
+          {
+            DEBUG ("Invalid authentication method requested");
+
+            socks5_error (self);
+            return string->len;
+          }
 
         msg[0] = SOCKS5_VERSION;
         msg[1] = SOCKS5_AUTH_NONE;
@@ -571,7 +631,19 @@ socks5_handle_received_data (GabbleBytestreamSocks5 *self,
         if (string->len < 47)
           return 0;
 
-        /* FIXME: check the values */
+        if (string->str[0] != SOCKS5_VERSION ||
+            string->str[1] != SOCKS5_CMD_CONNECT ||
+            string->str[2] != SOCKS5_RESERVED ||
+            string->str[3] != SOCKS5_ATYP_DOMAIN ||
+            string->str[4] != 40 ||
+            string->str[45] != 0 ||
+            string->str[46] != 0)
+          {
+            DEBUG ("Invalid SOCSK5 connect message");
+
+            socks5_error (self);
+            return string->len;
+          }
 
         msg[0] = SOCKS5_VERSION;
         msg[1] = SOCKS5_STATUS_OK;
@@ -587,10 +659,17 @@ socks5_handle_received_data (GabbleBytestreamSocks5 *self,
 
         return string->len;
 
-      default:
-        /* FIXME: handle errors */
+      case SOCKS5_STATE_ERROR:
+        /* An error occurred and the channel will be close in an idle
+         * callback, so let's just throw away the data we receive */
         return string->len;
+
+      case SOCKS5_STATE_INVALID:
+        break;
     }
+
+  g_assert_not_reached ();
+  return string->len;
 }
 
 static gboolean 
@@ -630,9 +709,11 @@ socks5_channel_error_cb (GIOChannel *source,
                          GIOCondition condition,
                          gpointer data) 
 {
-  /* FIXME: handle errors */
-  g_critical ("I/O error\n");
+  GabbleBytestreamSocks5 *self = GABBLE_BYTESTREAM_SOCKS5 (data);
 
+  DEBUG ("I/O error on a SOCKS5 channel");
+
+  socks5_error (self);
   return FALSE;
 }
 
@@ -657,8 +738,8 @@ socks5_connect (gpointer data)
   else
     {
       DEBUG ("No more streamhosts to streamhost, closing");
-      gabble_bytestream_socks5_close (GABBLE_BYTESTREAM_IFACE (self), NULL);
 
+      socks5_error (self);
       return FALSE;
     }
 
@@ -672,7 +753,7 @@ socks5_connect (gpointer data)
   if (getaddrinfo (streamhost->host, NULL, &req, &address_list) != 0)
     {
       DEBUG ("getaddrinfo on %s failed", streamhost->host);
-      socks5_connect_next (self);
+      socks5_error (self);
 
       return FALSE;
     }
@@ -713,8 +794,10 @@ socks5_connect (gpointer data)
 
   if (res < 0 && errno != EINPROGRESS)
     {
+      DEBUG ("connect failed");
+
       close (fd);
-      socks5_connect_next (self);
+      socks5_error (self);
 
       return FALSE;
     }
@@ -748,19 +831,6 @@ socks5_connect (gpointer data)
   return FALSE;
 }
 
-static void
-socks5_connect_next (GabbleBytestreamSocks5 *self)
-{
-  GabbleBytestreamSocks5Private *priv = GABBLE_BYTESTREAM_SOCKS5_GET_PRIVATE (self);
-
-  g_assert (priv->streamhosts != NULL);
-
-  streamhost_free (priv->streamhosts->data);
-  priv->streamhosts = g_slist_delete_link (priv->streamhosts, priv->streamhosts);
-
-  socks5_connect (self);
-}
-
 /**
  * gabble_bytestream_socks5_add_streamhost
  *
@@ -967,11 +1037,23 @@ gabble_bytestream_socks5_close (GabbleBytestreamIface *iface,
       if (priv->io_channel)
         {
           if (priv->read_watch != 0)
-            g_source_remove (priv->read_watch);
+            {
+              g_source_remove (priv->read_watch);
+              priv->read_watch = 0;
+            }
+
           if (priv->write_watch != 0)
-            g_source_remove (priv->write_watch);
+            {
+              g_source_remove (priv->write_watch);
+              priv->write_watch = 0;
+            }
+
           if (priv->error_watch != 0)
-            g_source_remove (priv->error_watch);
+            {
+              g_source_remove (priv->error_watch);
+              priv->error_watch = 0;
+            }
+
           g_io_channel_unref (priv->io_channel);
           priv->io_channel = NULL;
         }
@@ -1223,9 +1305,18 @@ gabble_bytestream_socks5_initiate (GabbleBytestreamIface *iface)
     }
 
   fd = socket (AF_INET, SOCK_STREAM, 0);
+  if (fd < 0)
+    {
+      DEBUG ("couldn't create socket");
+      return FALSE;
+    }
+
+  if (listen (fd, 5) < 0)
+    {
+      DEBUG ("couldn't listen on socket");
+      return FALSE;
+    }
 
-  /* FIXME: check the return values */
-  listen (fd, 5);
   channel = g_io_channel_unix_new (fd);
 
   g_io_channel_set_close_on_unref (channel, TRUE);
-- 
1.5.6.5




More information about the Telepathy-commits mailing list