Rename socks5.c to s5b.c, remove remaining tabulation
authorNicolas Cornu <nicolas.cornu@ensi-bourges.fr>
Wed, 01 Sep 2010 20:34:23 +0200
changeset 166 c42c167a2a5c
parent 165 763c26abd99d
child 167 97f93fa3cd95
Rename socks5.c to s5b.c, remove remaining tabulation
jingle-ft/filetransfer.c
jingle-s5b/CMakeLists.txt
jingle-s5b/s5b.c
jingle-s5b/s5b.h
jingle-s5b/socks5.c
jingle-s5b/socks5.h
jingle/action-handlers.c
jingle/check.c
jingle/jingle.c
--- a/jingle-ft/filetransfer.c	Wed Sep 01 01:19:40 2010 +0200
+++ b/jingle-ft/filetransfer.c	Wed Sep 01 20:34:23 2010 +0200
@@ -215,8 +215,8 @@
         && !g_strcmp0(node->name, "hash")) {
       ((JingleFT *)data)->hash = g_strdup(lm_message_node_get_value(node));
       return JINGLE_STATUS_HANDLED;
-	}
-	return JINGLE_STATUS_NOT_HANDLED;
+    }
+    return JINGLE_STATUS_NOT_HANDLED;
   }
   return JINGLE_STATUS_NOT_HANDLED;
 }
--- a/jingle-s5b/CMakeLists.txt	Wed Sep 01 01:19:40 2010 +0200
+++ b/jingle-s5b/CMakeLists.txt	Wed Sep 01 20:34:23 2010 +0200
@@ -1,4 +1,4 @@
-add_library(jingle-s5b MODULE socks5.c socks5.h)
+add_library(jingle-s5b MODULE s5b.c s5b.h)
 pkg_check_modules(GIO REQUIRED gio-2.0)
 link_directories(${GIO_LIBRARY_DIRS})
 include_directories(SYSTEM ${GIO_SOURCE_DIR})
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jingle-s5b/s5b.c	Wed Sep 01 20:34:23 2010 +0200
@@ -0,0 +1,696 @@
+/*
+ * socks5.c
+ *
+ * Copyrigth (C) 2010 Nicolas Cornu <nicolas.cornu@ensi-bourges.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <sys/types.h>
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <mcabber/xmpp.h>
+#include <mcabber/modules.h>
+#include <mcabber/utils.h>
+#include <mcabber/xmpp_helper.h>
+#include <mcabber/settings.h>
+#include <mcabber/logprint.h>
+#include <mcabber/hooks.h>
+
+#include <jingle/jingle.h>
+#include <jingle/check.h>
+#include <jingle/register.h>
+
+#include "s5b.h"
+
+static gconstpointer newfrommessage(JingleContent *cn, GError **err);
+static JingleHandleStatus handle(JingleAction action, gconstpointer data,
+                                 LmMessageNode *node, GError **err);
+static void tomessage(gconstpointer data, LmMessageNode *node);
+static gconstpointer new(void);
+static void _send(session_content *sc, gconstpointer data, gchar *buf, gsize size);
+static void init(session_content *sc, gconstpointer data);
+static void end(session_content *sc, gconstpointer data);
+static gchar *info(gconstpointer data);
+
+static void connect_candidate(JingleS5B *js5b, S5BCandidate *cand);
+static void connect_next_candidate(JingleS5B *js5b, S5BCandidate *cand);
+static void
+handle_listener_accept(GObject *_listener, GAsyncResult *res, gpointer data);
+static void
+handle_client_connect(GObject *_client, GAsyncResult *res, gpointer data);
+static void handle_sock_io(GSocket *sock, GIOCondition cond, gpointer data);
+static GSList *get_all_local_ips();
+static gchar *gen_random_sid(void);
+static gchar *gen_random_cid(void);
+static void jingle_socks5_init(void);
+static void jingle_socks5_uninit(void);
+
+
+const gchar *deps[] = { "jingle", NULL };
+
+static JingleTransportFuncs funcs = {
+  .newfrommessage = newfrommessage,
+  .handle         = handle,
+  .tomessage      = tomessage,
+  .new            = new,
+  .send           = _send,
+  .init           = init,
+  .end            = end,
+  .info           = info
+};
+
+module_info_t  info_jingle_s5b = {
+  .branch          = MCABBER_BRANCH,
+  .api             = MCABBER_API_VERSION,
+  .version         = PROJECT_VERSION,
+  .description     = "Jingle SOCKS5 Bytestream (XEP-0260)\n",
+  .requires        = deps,
+  .init            = jingle_socks5_init,
+  .uninit          = jingle_socks5_uninit,
+  .next            = NULL,
+};
+
+static const gchar *jingle_s5b_types[] = {
+  "direct",
+  "assisted",
+  "tunnel",
+  "proxy",
+  NULL
+};
+
+static const gchar *jingle_s5b_modes[] = {
+  "tcp",
+  "udp",
+  NULL
+};
+
+typedef struct {
+  GInetAddress *address;
+  guint32       priority;
+  JingleS5BType type;
+} LocalIP;
+
+/**
+ * @brief Linked list of candidates to send on session-initiate
+ */
+static GSList *local_ips = NULL;
+
+
+static gint index_in_array(const gchar *str, const gchar **array)
+{
+  gint i;
+  for (i = 0; array[i]; i++) {
+    if (!g_strcmp0(array[i], str)) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+static gint prioritycmp(gconstpointer a, gconstpointer b)
+{
+  S5BCandidate *s1 = (S5BCandidate *)a, *s2 = (S5BCandidate *)b;
+  if (s1->priority < s2->priority) {
+    return 1;
+  } else if (s1->priority > s2->priority) {
+    return -1;
+  } else {
+    return 0;
+  }
+}
+
+/**
+ * @brief Parse a list of <candidate> elements
+ * @return a list of S5BCandidate
+ */
+static GSList *parse_candidates(LmMessageNode *node)
+{
+  LmMessageNode *node2;
+  GSList *list = NULL;
+
+  for (node2 = node->children; node2; node2 = node2->next) {
+    if (g_strcmp0(node->name, "candidate"))
+        continue;
+    const gchar *hoststr, *portstr, *prioritystr, *typestr;
+    S5BCandidate *cand = g_new0(S5BCandidate, 1);
+    cand->cid    = g_strdup(lm_message_node_get_attribute(node2, "cid"));
+    cand->jid    = g_strdup(lm_message_node_get_attribute(node2, "jid"));
+    hoststr      = lm_message_node_get_attribute(node2, "host");
+    portstr      = lm_message_node_get_attribute(node2, "port");
+    prioritystr  = lm_message_node_get_attribute(node2, "priority");
+    typestr      = lm_message_node_get_attribute(node2, "type");
+
+    if (!cand->cid || !hoststr || !cand->jid || !prioritystr) {
+      g_free(cand);
+      continue;
+    }
+    cand->host     = g_inet_address_new_from_string(hoststr);
+    cand->port     = g_ascii_strtoull(portstr, NULL, 10);
+    cand->priority = g_ascii_strtoull(prioritystr, NULL, 10);
+    cand->type     = index_in_array(typestr, jingle_s5b_types);
+
+    if (cand->type == -1 || cand->host == NULL) {
+      g_free(cand);
+      continue;
+    }
+
+    list = g_slist_prepend(list, cand);
+  }
+  list = g_slist_sort(list, prioritycmp);
+  return list;
+}
+
+static GSList *get_our_candidates(guint16 port)
+{
+  GSList *our_candidates = NULL, *entry;
+
+  for (entry = local_ips; entry; entry = entry->next) {
+    LocalIP *lcand = (LocalIP *)entry->data;
+    S5BCandidate *cand = g_new0(S5BCandidate, 1);
+    cand->cid      = gen_random_cid();
+    cand->host     = g_object_ref(lcand->address);
+    cand->jid      = g_strdup(lm_connection_get_jid(lconnection));
+    cand->port     = port;
+    cand->priority = lcand->priority;
+
+    our_candidates = g_slist_prepend(our_candidates, cand);
+  }
+  our_candidates = g_slist_sort(our_candidates, prioritycmp);
+  return our_candidates;
+}
+
+/**
+ * @brief Get a port number by settings or randomly
+ * @return A guint16 containing the port number
+ * */
+static guint16 get_port(void)
+{
+  // TODO: find a way to make sure the port is not already used
+  guint64 portstart, portend;
+  guint16 port;
+  const gchar *port_range = settings_opt_get("js5b_portrange");
+
+  if (port_range != NULL) {
+    sscanf(port_range, "%" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT, &portstart, &portend);
+
+    if ((portstart >= 1024 && portstart <= (guint16)~0) &&
+        (portend >= 1024 && portend <= (guint16)~0) && portstart <= portend) {
+      port = g_random_int_range(portstart, portend);
+    } else {
+      scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Invalid port range specified");
+      port = g_random_int_range(1024, (guint16)~0);
+    }
+  } else {
+    port = g_random_int_range(1024, (guint16)~0);
+  }
+
+  return port;
+}
+
+static gconstpointer newfrommessage(JingleContent *cn, GError **err)
+{
+  JingleS5B *js5b;
+  LmMessageNode *node = cn->transport;
+  const gchar *modestr;
+
+  js5b = g_new0(JingleS5B, 1);
+  modestr    = lm_message_node_get_attribute(node, "mode");
+  js5b->mode = index_in_array(modestr, jingle_s5b_modes);
+  js5b->sid  = g_strdup(lm_message_node_get_attribute(node, "sid"));
+
+  if (!js5b->sid) {
+    g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_MISSING,
+                "an attribute of the transport element is missing");
+    g_free(js5b);
+    return NULL;
+  }
+
+  js5b->candidates = parse_candidates(node);
+  js5b->ourcandidates = get_our_candidates(get_port());
+
+  return (gconstpointer) js5b;
+}
+
+static gconstpointer new(void)
+{
+  JingleS5B *js5b = g_new0(JingleS5B, 1);
+
+  js5b->mode = JINGLE_S5B_TCP;
+  js5b->sid  = gen_random_sid();
+
+  js5b->ourcandidates = get_our_candidates(get_port());
+
+  return js5b;
+}
+
+static JingleHandleStatus handle(JingleAction action, gconstpointer data,
+                                 LmMessageNode *node, GError **err)
+{
+  JingleS5B *js5b = (JingleS5B *)data;
+
+  if (action == JINGLE_SESSION_ACCEPT) {
+    js5b->candidates = parse_candidates(node);
+    return JINGLE_STATUS_HANDLED;
+  } else if (action == JINGLE_TRANSPORT_INFO) {
+    LmMessageNode *errorn, *usedn;
+    if (g_strcmp0(lm_message_node_get_attribute(node, "sid"), js5b->sid))
+      return JINGLE_STATUS_HANDLED; // huh.. not the same socks5 sid ?
+
+    errorn = lm_message_node_get_child(node, "candidate-error");
+    usedn = lm_message_node_get_child(node, "candidate-used");
+    if (errorn != FALSE) {
+      //got_candidate_error
+    } else if (usedn != FALSE) {
+      //got_candidate_used
+    }
+    return JINGLE_STATUS_HANDLED;
+  }
+  return JINGLE_STATUS_NOT_HANDLED;
+}
+
+static void tomessage(gconstpointer data, LmMessageNode *node)
+{
+  JingleS5B *js5 = (JingleS5B *)data;
+  S5BCandidate *js5c;
+  
+  LmMessageNode *node2, *node3;
+  gchar *port;
+  gchar *priority;
+  GSList *el;
+  
+  if (lm_message_node_get_child(node, "transport") != NULL)
+    return;
+  
+  node2 = lm_message_node_add_child(node, "transport", NULL);
+
+  lm_message_node_set_attributes(node2, "xmlns", NS_JINGLE_TRANSPORT_SOCKS5,
+                                 "sid", js5->sid,
+                                 "mode", jingle_s5b_modes[js5->mode],
+                                 NULL);
+  for (el = js5->ourcandidates; el; el = el->next) {
+    js5c = (S5BCandidate*) el->data;
+    node3 = lm_message_node_add_child(node2, "candidate", NULL);
+    
+    port = g_strdup_printf("%" G_GUINT16_FORMAT, js5c->port);
+    priority = g_strdup_printf("%" G_GUINT64_FORMAT, js5c->priority);
+    
+    lm_message_node_set_attributes(node3, "cid", js5c->cid,
+                                   "host", g_inet_address_to_string(js5c->host),
+                                   "jid", js5c->jid,
+                                   "port", port,
+                                   "priority", priority,
+                                   "type", jingle_s5b_types[js5c->type],
+                                   NULL);
+    g_free(port);
+    g_free(priority);
+  }
+}
+
+static void init(session_content *sc, gconstpointer data)
+{
+  JingleS5B *js5b = (JingleS5B *)data;
+  GSocketAddress *saddr;
+  guint numlistening = 0; // number of addresses we are listening to
+  GSList *entry;
+  GError *err = NULL;
+  GSocket *sock;
+
+  // First, we listen on all ips
+  js5b->listener = g_socket_listener_new();
+  for (entry = js5b->ourcandidates; entry; entry = entry->next) {
+    S5BCandidate *cand = (S5BCandidate *)entry->data;
+
+    sock = g_socket_new(g_inet_address_get_family(cand->host),
+                        G_SOCKET_TYPE_STREAM,
+                        G_SOCKET_PROTOCOL_TCP, &err);
+    if (sock == NULL) {
+      scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Error while creating a new socket: %s",
+                   err->message ? err->message : "(no message)");
+      continue;
+    }
+    g_socket_set_blocking(sock, FALSE);
+
+    saddr = g_inet_socket_address_new(cand->host, cand->port);
+    if (!g_socket_bind(sock, saddr, TRUE, &err)) {
+      scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Unable to bind a socket on %s port %u: %s",
+                   g_inet_address_to_string(cand->host),
+                   cand->port,
+                   err->message ? err->message : "(no message)");
+      goto cleancontinue;
+    }
+
+    if (!g_socket_listen(sock, &err)) {
+      scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Unable to listen on %s port %u: %s",
+                   g_inet_address_to_string(cand->host),
+                   cand->port,
+                   err->message ? err->message : "(no message)");
+      goto cleancontinue;
+    }
+
+    if (!g_socket_listener_add_socket(js5b->listener, sock, NULL, &err)) {
+      scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Unable to add our socket to the"
+                   " GSocketListener: %s",
+                   err->message ? err->message : "(no message)");
+      goto cleancontinue;
+    }
+
+    scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Listening on %s:%u",
+                 g_inet_address_to_string(cand->host),
+                 cand->port);
+    ++numlistening;
+
+cleancontinue:
+      if (err != NULL) g_clear_error(&err);
+      g_object_unref(saddr);
+      g_object_unref(sock);
+  }
+
+  if (numlistening > 0) {
+    g_socket_listener_accept_async(js5b->listener, NULL, handle_listener_accept, NULL);
+  } else {
+      g_object_unref(js5b->listener);
+  }
+
+  // Then, we start connecting to the other entity's candidates, if any.
+  if (js5b->candidates) {
+    js5b->client = g_socket_client_new();
+    S5BCandidate *cand = (S5BCandidate *)js5b->candidates->data;
+    connect_candidate(js5b, cand);
+  }
+}
+
+/**
+ * @brief Called when a connection was established
+ * 
+ * This function free/unref everything created by init like
+ * the GSocketListener and GClientSocket objects.
+ */
+static void free_after_connection(JingleS5B *js5b)
+{
+  g_socket_listener_close(js5b->listener);
+  g_object_unref(js5b->listener);
+  g_object_unref(js5b->client);
+}
+
+/**
+ * @brief Cancel an ongoing connection after 5 seconds
+ * @param data  A GPtrArray
+ * 
+ * "A client SHOULD NOT wait for a TCP timeout on connect.
+ * If it is unable to connect to any candidate within 5 seconds
+ * it SHOULD send a candidate-error to the other party."
+ */
+static gboolean connect_cancel_timeout(gpointer data)
+{
+  GPtrArray *args = (GPtrArray *)data;
+  JingleS5B *js5b = g_ptr_array_index(args, 0);
+  //S5BCandidate *cand = g_ptr_array_index(args, 1);
+  g_ptr_array_unref(args);
+
+  g_cancellable_cancel(js5b->cancelconnect);
+  // we need to send a candidate-error in case we cannot connect.
+  return FALSE;
+}
+
+static void connect_candidate(JingleS5B *js5b, S5BCandidate *cand)
+{
+  GSocketAddress *saddr;
+  GPtrArray *args;
+  guint eventid;
+
+  args = g_ptr_array_sized_new(2);
+  g_ptr_array_add(args, js5b);
+  g_ptr_array_add(args, cand);
+
+  saddr = g_inet_socket_address_new(cand->host, cand->port);
+  js5b->cancelconnect = g_cancellable_new();
+
+  eventid = g_timeout_add_seconds(5, connect_cancel_timeout, g_ptr_array_ref(args));
+  g_ptr_array_add(args, GUINT_TO_POINTER(eventid));
+  g_socket_client_connect_async(js5b->client, G_SOCKET_CONNECTABLE(saddr),
+                                js5b->cancelconnect, handle_client_connect, args);
+  g_object_unref(saddr);
+}
+
+/**
+ * Convenience function that find the next candidate to try and
+ * call connect_candidate
+ */
+static void connect_next_candidate(JingleS5B *js5b, S5BCandidate *cand)
+{
+  GSList *link = g_slist_find(js5b->candidates, cand);
+  if (js5b->cancelconnect != NULL)
+    g_object_unref(js5b->cancelconnect);
+  g_assert(link != NULL);
+  if (link->next == NULL) {
+    // there is no next candidate to try.
+  }
+  connect_candidate(js5b, (S5BCandidate *)link->next->data);
+  return;
+}
+
+static gchar *info(gconstpointer data)
+{
+  //JingleS5B *js5b = (JingleS5B *)data;
+  gchar *info = g_strdup_printf("S5B");
+  return info;
+}
+
+static void end(session_content *sc, gconstpointer data) {
+  return;
+}
+
+/**
+ * @brief Handle incoming connections
+ */
+static void
+handle_listener_accept(GObject *_listener, GAsyncResult *res, gpointer data)
+{
+  GError *err = NULL;
+  GSocketConnection *conn;
+  //scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Got Incoming Connection");
+  conn = g_socket_listener_accept_finish(G_SOCKET_LISTENER(_listener), res, NULL, &err);
+}
+
+/**
+ * @brief Handle outgoing connections
+ */
+static void
+handle_client_connect(GObject *_client, GAsyncResult *res, gpointer data)
+{
+  GError *err = NULL;
+  GSocketConnection *conn;
+  GPtrArray *args;
+  JingleS5B *js5b;
+  S5BCandidate *cand;
+  //scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Got Outgoing Connection");
+  
+  args = (GPtrArray *)data;
+  js5b = g_ptr_array_index(args, 0);
+  cand = g_ptr_array_index(args, 1);
+  g_ptr_array_unref(args);
+
+  conn = g_socket_client_connect_finish(G_SOCKET_CLIENT(_client), res, &err);
+
+  if (!g_error_matches(err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+    // if we did not received a CANCELLED error, then the time limit was not
+    // reached and we need to clean up the GSource and unref args a second time.
+    guint eventid = GPOINTER_TO_UINT(g_ptr_array_index(args, 2));
+    GSource *s = g_main_context_find_source_by_id(NULL, eventid);
+    g_source_destroy(s);
+    g_ptr_array_unref(args);
+    connect_next_candidate(js5b, cand);
+    return;
+  }
+
+  if (err != NULL) {
+    if (err->domain == G_IO_ERROR)
+      scr_LogPrint(LPRINT_DEBUG, "Jingle S5B: IO Error (%s)",
+                   err->message ? err->message : "no message");
+    else
+      scr_LogPrint(LPRINT_DEBUG, "Jingle S5B: %s Error (%s)",
+                   g_quark_to_string (err->domain),
+                   err->message ? err->message : "no message");
+
+    g_error_free(err);
+    connect_next_candidate(js5b, cand);
+    return;
+  }
+  js5b->connection = conn; // we have a valid connection
+  // TODO: send transport-info activated IQ
+}
+
+/**
+ * @brief Handle any event on a sock
+ */
+static void handle_sock_io(GSocket *sock, GIOCondition cond, gpointer data)
+{
+  switch (cond) {
+    case G_IO_IN:
+      break;
+    case G_IO_OUT:
+      break;
+    case G_IO_ERR:
+      break;
+    case G_IO_HUP:
+      break;
+    default:
+      ;
+      // ?!
+  }
+}
+
+static void _send(session_content *sc, gconstpointer data, gchar *buf, gsize size)
+{
+  return;
+}
+
+/**
+ * @brief Discover all IPs of this computer
+ * @return A linked list of GInetAddress
+ */
+static GSList *get_all_local_ips(void) {
+  GSList *addresses = NULL;
+  GInetAddress *thisaddr;
+  GSocketFamily family;
+  struct ifaddrs *first, *ifaddr;
+  struct sockaddr_in *native;
+  struct sockaddr_in6 *native6;
+  const guint8 *addrdata;
+  guint16 ifacecounter = 0; // for lack of a better method
+  LocalIP *candidate;
+  gchar **ifblacklist;
+  guint ifblkcnt;
+
+  gint rval = getifaddrs(&first);
+  if (rval != 0) {
+    scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Unable to retreive local ip addresses");
+    return NULL;
+  }
+
+  if (settings_opt_get("js5b_iface_blacklist") != NULL) {
+    ifblacklist = g_strsplit(settings_opt_get("js5b_iface_blacklist"), ",", 0);
+  } else {
+    ifblacklist = (gchar*[]){NULL};
+  }
+
+  for (ifaddr = first; ifaddr; ifaddr = ifaddr->ifa_next) {
+    gboolean continueloop = FALSE;
+    if (!(ifaddr->ifa_flags & IFF_UP) || ifaddr->ifa_flags & IFF_LOOPBACK)
+      continue;
+
+    for (ifblkcnt = 0; ifblacklist[ifblkcnt]; ifblkcnt++)
+      if (!g_strcmp0(ifaddr->ifa_name, ifblacklist[ifblkcnt])) {
+        continueloop = TRUE;
+        break;
+      }
+    
+    if (continueloop) continue;
+
+    if (ifaddr->ifa_addr->sa_family == AF_INET) {
+      native = (struct sockaddr_in *)ifaddr->ifa_addr;
+      addrdata = (const guint8 *)&native->sin_addr.s_addr;
+      family = G_SOCKET_FAMILY_IPV4;
+    } else if (ifaddr->ifa_addr->sa_family == AF_INET6) {
+      native6 = (struct sockaddr_in6 *)ifaddr->ifa_addr;
+      addrdata = (const guint8 *)&native6->sin6_addr.s6_addr;
+      family = G_SOCKET_FAMILY_IPV6;
+    } else
+      continue;
+
+    thisaddr = g_inet_address_new_from_bytes(addrdata, family);
+    if (g_inet_address_get_is_link_local(thisaddr)) {
+      g_object_unref(thisaddr);
+      continue;
+    }/* else if (g_inset_address_get_is_site_local(thisaddr)) {
+      // TODO: should we offer a way to filter the offer of LAN ips ?
+    } */
+    candidate = g_new0(LocalIP, 1);
+    candidate->address  = thisaddr;
+    candidate->priority = (1<<16)*126+ifacecounter;
+    candidate->type     = JINGLE_S5B_DIRECT;
+    addresses = g_slist_prepend(addresses, candidate);
+    ++ifacecounter;
+  }
+  freeifaddrs(first);
+
+  return addresses;
+}
+
+static gchar *random_str(guint len)
+{
+  gchar *str;
+  gchar car[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+  gint i;
+  str = g_new0(gchar, 8);
+  for (i = 0; i < len; i++)
+    str[i] = car[g_random_int_range(0, sizeof(car)/sizeof(car[0])-1)];
+
+  str[len] = '\0';
+  return str;
+}
+
+static gchar *gen_random_sid(void)
+{
+  return random_str(7);
+}
+
+static gchar *gen_random_cid(void)
+{
+  return random_str(7);
+}
+
+static void free_localip(LocalIP *l) {
+  g_object_unref(l->address);
+  g_free(l);
+}
+
+static void jingle_socks5_init(void)
+{
+  // ugly hack to fix the segfault when quitting:
+  // mcabber doesn't load gthread or gobject but they are required by gio,
+  // and cannot be unloaded once they are loaded or a segfault occur.
+  // We dlopen gio with global | nodelete flags. This will also load gobject
+  // and gthread as dependencies. g_type_init will init gobject/gthread (and
+  // set threads_got_initialized to true).
+  if (g_threads_got_initialized == FALSE) {
+    void *dlopen(const char *filename, int flag);
+    // RTLD_LAZY | RTLD_GLOBAL | RTLD_NODELETE
+    dlopen("libgio-2.0.so", 0x00001 | 0x00100 | 0x01000);
+    g_type_init();
+  }
+  jingle_register_transport(NS_JINGLE_TRANSPORT_SOCKS5, &funcs,
+                            JINGLE_TRANSPORT_STREAMING,
+                            JINGLE_TRANSPORT_PRIO_HIGH);
+  xmpp_add_feature(NS_JINGLE_TRANSPORT_SOCKS5);
+  local_ips = get_all_local_ips();
+}
+
+static void jingle_socks5_uninit(void)
+{
+  xmpp_del_feature(NS_JINGLE_TRANSPORT_SOCKS5);
+  jingle_unregister_transport(NS_JINGLE_TRANSPORT_SOCKS5);
+  g_slist_foreach(local_ips, (GFunc)free_localip, NULL);
+  g_slist_free(local_ips);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jingle-s5b/s5b.h	Wed Sep 01 20:34:23 2010 +0200
@@ -0,0 +1,62 @@
+#ifndef __JINGLESOCKS5_H__
+#define __JINGLESOCKS5_H__ 1
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#define NS_JINGLE_TRANSPORT_SOCKS5 "urn:xmpp:jingle:transports:s5b:1"
+
+
+typedef enum {
+  JINGLE_S5B_DIRECT,
+  JINGLE_S5B_ASSISTED,
+  JINGLE_S5B_TUNNEL,
+  JINGLE_S5B_PROXY
+} JingleS5BType;
+
+typedef enum {
+  JINGLE_S5B_TCP,
+  JINGLE_S5B_UDP
+} JingleS5BModes;
+
+typedef struct {
+  JingleS5BModes mode;
+
+  const gchar *sid;
+
+  GSocketConnection *connection;
+
+  GCancellable *cancelconnect;
+
+  GSocketListener *listener;
+
+  GSocketClient *client;
+
+  /**
+   * @brief This is the list of the other client's candidates
+   * 
+   * It should always be priority ordered.
+   */
+  GSList *candidates;
+
+  /**
+   * @brief This is our list of candidates
+   */
+  GSList *ourcandidates;
+} JingleS5B;
+ 
+typedef struct {
+  const gchar *cid;
+
+  GInetAddress *host;
+
+  const gchar *jid;
+
+  guint16 port;
+
+  guint64 priority;
+
+  JingleS5BType type;
+} S5BCandidate;
+
+#endif
--- a/jingle-s5b/socks5.c	Wed Sep 01 01:19:40 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,696 +0,0 @@
-/*
- * socks5.c
- *
- * Copyrigth (C) 2010 Nicolas Cornu <nicolas.cornu@ensi-bourges.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program 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
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
- */
-
-#include "config.h"
-
-#include <glib.h>
-#include <gio/gio.h>
-
-#include <sys/types.h>
-#include <ifaddrs.h>
-#include <net/if.h>
-#include <netinet/in.h>
-
-#include <mcabber/xmpp.h>
-#include <mcabber/modules.h>
-#include <mcabber/utils.h>
-#include <mcabber/xmpp_helper.h>
-#include <mcabber/settings.h>
-#include <mcabber/logprint.h>
-#include <mcabber/hooks.h>
-
-#include <jingle/jingle.h>
-#include <jingle/check.h>
-#include <jingle/register.h>
-
-#include "socks5.h"
-
-static gconstpointer newfrommessage(JingleContent *cn, GError **err);
-static JingleHandleStatus handle(JingleAction action, gconstpointer data,
-                                 LmMessageNode *node, GError **err);
-static void tomessage(gconstpointer data, LmMessageNode *node);
-static gconstpointer new(void);
-static void _send(session_content *sc, gconstpointer data, gchar *buf, gsize size);
-static void init(session_content *sc, gconstpointer data);
-static void end(session_content *sc, gconstpointer data);
-static gchar *info(gconstpointer data);
-
-static void connect_candidate(JingleS5B *js5b, S5BCandidate *cand);
-static void connect_next_candidate(JingleS5B *js5b, S5BCandidate *cand);
-static void
-handle_listener_accept(GObject *_listener, GAsyncResult *res, gpointer data);
-static void
-handle_client_connect(GObject *_client, GAsyncResult *res, gpointer data);
-static void handle_sock_io(GSocket *sock, GIOCondition cond, gpointer data);
-static GSList *get_all_local_ips();
-static gchar *gen_random_sid(void);
-static gchar *gen_random_cid(void);
-static void jingle_socks5_init(void);
-static void jingle_socks5_uninit(void);
-
-
-const gchar *deps[] = { "jingle", NULL };
-
-static JingleTransportFuncs funcs = {
-  .newfrommessage = newfrommessage,
-  .handle         = handle,
-  .tomessage      = tomessage,
-  .new            = new,
-  .send           = _send,
-  .init           = init,
-  .end            = end,
-  .info           = info
-};
-
-module_info_t  info_jingle_s5b = {
-  .branch          = MCABBER_BRANCH,
-  .api             = MCABBER_API_VERSION,
-  .version         = PROJECT_VERSION,
-  .description     = "Jingle SOCKS5 Bytestream (XEP-0260)\n",
-  .requires        = deps,
-  .init            = jingle_socks5_init,
-  .uninit          = jingle_socks5_uninit,
-  .next            = NULL,
-};
-
-static const gchar *jingle_s5b_types[] = {
-  "direct",
-  "assisted",
-  "tunnel",
-  "proxy",
-  NULL
-};
-
-static const gchar *jingle_s5b_modes[] = {
-  "tcp",
-  "udp",
-  NULL
-};
-
-typedef struct {
-  GInetAddress *address;
-  guint32       priority;
-  JingleS5BType type;
-} LocalIP;
-
-/**
- * @brief Linked list of candidates to send on session-initiate
- */
-static GSList *local_ips = NULL;
-
-
-static gint index_in_array(const gchar *str, const gchar **array)
-{
-  gint i;
-  for (i = 0; array[i]; i++) {
-    if (!g_strcmp0(array[i], str)) {
-      return i;
-    }
-  }
-  return -1;
-}
-
-static gint prioritycmp(gconstpointer a, gconstpointer b)
-{
-  S5BCandidate *s1 = (S5BCandidate *)a, *s2 = (S5BCandidate *)b;
-  if (s1->priority < s2->priority) {
-    return 1;
-  } else if (s1->priority > s2->priority) {
-    return -1;
-  } else {
-    return 0;
-  }
-}
-
-/**
- * @brief Parse a list of <candidate> elements
- * @return a list of S5BCandidate
- */
-static GSList *parse_candidates(LmMessageNode *node)
-{
-  LmMessageNode *node2;
-  GSList *list = NULL;
-
-  for (node2 = node->children; node2; node2 = node2->next) {
-    if (g_strcmp0(node->name, "candidate"))
-        continue;
-    const gchar *hoststr, *portstr, *prioritystr, *typestr;
-    S5BCandidate *cand = g_new0(S5BCandidate, 1);
-    cand->cid    = g_strdup(lm_message_node_get_attribute(node2, "cid"));
-    cand->jid    = g_strdup(lm_message_node_get_attribute(node2, "jid"));
-    hoststr      = lm_message_node_get_attribute(node2, "host");
-    portstr      = lm_message_node_get_attribute(node2, "port");
-    prioritystr  = lm_message_node_get_attribute(node2, "priority");
-    typestr      = lm_message_node_get_attribute(node2, "type");
-
-    if (!cand->cid || !hoststr || !cand->jid || !prioritystr) {
-      g_free(cand);
-      continue;
-    }
-    cand->host     = g_inet_address_new_from_string(hoststr);
-    cand->port     = g_ascii_strtoull(portstr, NULL, 10);
-    cand->priority = g_ascii_strtoull(prioritystr, NULL, 10);
-    cand->type     = index_in_array(typestr, jingle_s5b_types);
-
-    if (cand->type == -1 || cand->host == NULL) {
-      g_free(cand);
-      continue;
-    }
-
-    list = g_slist_prepend(list, cand);
-  }
-  list = g_slist_sort(list, prioritycmp);
-  return list;
-}
-
-static GSList *get_our_candidates(guint16 port)
-{
-  GSList *our_candidates = NULL, *entry;
-
-  for (entry = local_ips; entry; entry = entry->next) {
-    LocalIP *lcand = (LocalIP *)entry->data;
-    S5BCandidate *cand = g_new0(S5BCandidate, 1);
-    cand->cid      = gen_random_cid();
-    cand->host     = g_object_ref(lcand->address);
-    cand->jid      = g_strdup(lm_connection_get_jid(lconnection));
-    cand->port     = port;
-    cand->priority = lcand->priority;
-
-    our_candidates = g_slist_prepend(our_candidates, cand);
-  }
-  our_candidates = g_slist_sort(our_candidates, prioritycmp);
-  return our_candidates;
-}
-
-/**
- * @brief Get a port number by settings or randomly
- * @return A guint16 containing the port number
- * */
-static guint16 get_port(void)
-{
-  // TODO: find a way to make sure the port is not already used
-  guint64 portstart, portend;
-  guint16 port;
-  const gchar *port_range = settings_opt_get("js5b_portrange");
-
-  if (port_range != NULL) {
-    sscanf(port_range, "%" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT, &portstart, &portend);
-
-    if ((portstart >= 1024 && portstart <= (guint16)~0) &&
-        (portend >= 1024 && portend <= (guint16)~0) && portstart <= portend) {
-      port = g_random_int_range(portstart, portend);
-    } else {
-      scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Invalid port range specified");
-      port = g_random_int_range(1024, (guint16)~0);
-    }
-  } else {
-    port = g_random_int_range(1024, (guint16)~0);
-  }
-
-  return port;
-}
-
-static gconstpointer newfrommessage(JingleContent *cn, GError **err)
-{
-  JingleS5B *js5b;
-  LmMessageNode *node = cn->transport;
-  const gchar *modestr;
-
-  js5b = g_new0(JingleS5B, 1);
-  modestr    = lm_message_node_get_attribute(node, "mode");
-  js5b->mode = index_in_array(modestr, jingle_s5b_modes);
-  js5b->sid  = g_strdup(lm_message_node_get_attribute(node, "sid"));
-
-  if (!js5b->sid) {
-    g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_MISSING,
-                "an attribute of the transport element is missing");
-    g_free(js5b);
-    return NULL;
-  }
-
-  js5b->candidates = parse_candidates(node);
-  js5b->ourcandidates = get_our_candidates(get_port());
-
-  return (gconstpointer) js5b;
-}
-
-static gconstpointer new(void)
-{
-  JingleS5B *js5b = g_new0(JingleS5B, 1);
-
-  js5b->mode = JINGLE_S5B_TCP;
-  js5b->sid  = gen_random_sid();
-
-  js5b->ourcandidates = get_our_candidates(get_port());
-
-  return js5b;
-}
-
-static JingleHandleStatus handle(JingleAction action, gconstpointer data,
-                                 LmMessageNode *node, GError **err)
-{
-  JingleS5B *js5b = (JingleS5B *)data;
-
-  if (action == JINGLE_SESSION_ACCEPT) {
-    js5b->candidates = parse_candidates(node);
-    return JINGLE_STATUS_HANDLED;
-  } else if (action == JINGLE_TRANSPORT_INFO) {
-    LmMessageNode *errorn, *usedn;
-    if (g_strcmp0(lm_message_node_get_attribute(node, "sid"), js5b->sid))
-      return JINGLE_STATUS_HANDLED; // huh.. not the same socks5 sid ?
-
-    errorn = lm_message_node_get_child(node, "candidate-error");
-    usedn = lm_message_node_get_child(node, "candidate-used");
-    if (errorn != FALSE) {
-      //got_candidate_error
-    } else if (usedn != FALSE) {
-      //got_candidate_used
-    }
-    return JINGLE_STATUS_HANDLED;
-  }
-  return JINGLE_STATUS_NOT_HANDLED;
-}
-
-static void tomessage(gconstpointer data, LmMessageNode *node)
-{
-  JingleS5B *js5 = (JingleS5B *)data;
-  S5BCandidate *js5c;
-  
-  LmMessageNode *node2, *node3;
-  gchar *port;
-  gchar *priority;
-  GSList *el;
-  
-  if (lm_message_node_get_child(node, "transport") != NULL)
-    return;
-  
-  node2 = lm_message_node_add_child(node, "transport", NULL);
-
-  lm_message_node_set_attributes(node2, "xmlns", NS_JINGLE_TRANSPORT_SOCKS5,
-                                 "sid", js5->sid,
-                                 "mode", jingle_s5b_modes[js5->mode],
-                                 NULL);
-  for (el = js5->ourcandidates; el; el = el->next) {
-    js5c = (S5BCandidate*) el->data;
-    node3 = lm_message_node_add_child(node2, "candidate", NULL);
-    
-    port = g_strdup_printf("%" G_GUINT16_FORMAT, js5c->port);
-    priority = g_strdup_printf("%" G_GUINT64_FORMAT, js5c->priority);
-    
-    lm_message_node_set_attributes(node3, "cid", js5c->cid,
-                                   "host", g_inet_address_to_string(js5c->host),
-                                   "jid", js5c->jid,
-                                   "port", port,
-                                   "priority", priority,
-                                   "type", jingle_s5b_types[js5c->type],
-                                   NULL);
-    g_free(port);
-    g_free(priority);
-  }
-}
-
-static void init(session_content *sc, gconstpointer data)
-{
-  JingleS5B *js5b = (JingleS5B *)data;
-  GSocketAddress *saddr;
-  guint numlistening = 0; // number of addresses we are listening to
-  GSList *entry;
-  GError *err = NULL;
-  GSocket *sock;
-
-  // First, we listen on all ips
-  js5b->listener = g_socket_listener_new();
-  for (entry = js5b->ourcandidates; entry; entry = entry->next) {
-    S5BCandidate *cand = (S5BCandidate *)entry->data;
-
-    sock = g_socket_new(g_inet_address_get_family(cand->host),
-                        G_SOCKET_TYPE_STREAM,
-                        G_SOCKET_PROTOCOL_TCP, &err);
-    if (sock == NULL) {
-      scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Error while creating a new socket: %s",
-                   err->message ? err->message : "(no message)");
-      continue;
-    }
-    g_socket_set_blocking(sock, FALSE);
-
-    saddr = g_inet_socket_address_new(cand->host, cand->port);
-    if (!g_socket_bind(sock, saddr, TRUE, &err)) {
-      scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Unable to bind a socket on %s port %u: %s",
-                   g_inet_address_to_string(cand->host),
-                   cand->port,
-                   err->message ? err->message : "(no message)");
-      goto cleancontinue;
-    }
-
-    if (!g_socket_listen(sock, &err)) {
-      scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Unable to listen on %s port %u: %s",
-                   g_inet_address_to_string(cand->host),
-                   cand->port,
-                   err->message ? err->message : "(no message)");
-      goto cleancontinue;
-    }
-
-    if (!g_socket_listener_add_socket(js5b->listener, sock, NULL, &err)) {
-      scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Unable to add our socket to the"
-                   " GSocketListener: %s",
-                   err->message ? err->message : "(no message)");
-      goto cleancontinue;
-	}
-
-    scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Listening on %s:%u",
-                 g_inet_address_to_string(cand->host),
-                 cand->port);
-	++numlistening;
-
-cleancontinue:
-      if (err != NULL) g_clear_error(&err);
-      g_object_unref(saddr);
-      g_object_unref(sock);
-  }
-
-  if (numlistening > 0) {
-    g_socket_listener_accept_async(js5b->listener, NULL, handle_listener_accept, NULL);
-  } else {
-      g_object_unref(js5b->listener);
-  }
-
-  // Then, we start connecting to the other entity's candidates, if any.
-  if (js5b->candidates) {
-    js5b->client = g_socket_client_new();
-    S5BCandidate *cand = (S5BCandidate *)js5b->candidates->data;
-    connect_candidate(js5b, cand);
-  }
-}
-
-/**
- * @brief Called when a connection was established
- * 
- * This function free/unref everything created by init like
- * the GSocketListener and GClientSocket objects.
- */
-static void free_after_connection(JingleS5B *js5b)
-{
-  g_socket_listener_close(js5b->listener);
-  g_object_unref(js5b->listener);
-  g_object_unref(js5b->client);
-}
-
-/**
- * @brief Cancel an ongoing connection after 5 seconds
- * @param data  A GPtrArray
- * 
- * "A client SHOULD NOT wait for a TCP timeout on connect.
- * If it is unable to connect to any candidate within 5 seconds
- * it SHOULD send a candidate-error to the other party."
- */
-static gboolean connect_cancel_timeout(gpointer data)
-{
-  GPtrArray *args = (GPtrArray *)data;
-  JingleS5B *js5b = g_ptr_array_index(args, 0);
-  //S5BCandidate *cand = g_ptr_array_index(args, 1);
-  g_ptr_array_unref(args);
-
-  g_cancellable_cancel(js5b->cancelconnect);
-  // we need to send a candidate-error in case we cannot connect.
-  return FALSE;
-}
-
-static void connect_candidate(JingleS5B *js5b, S5BCandidate *cand)
-{
-  GSocketAddress *saddr;
-  GPtrArray *args;
-  guint eventid;
-
-  args = g_ptr_array_sized_new(2);
-  g_ptr_array_add(args, js5b);
-  g_ptr_array_add(args, cand);
-
-  saddr = g_inet_socket_address_new(cand->host, cand->port);
-  js5b->cancelconnect = g_cancellable_new();
-
-  eventid = g_timeout_add_seconds(5, connect_cancel_timeout, g_ptr_array_ref(args));
-  g_ptr_array_add(args, GUINT_TO_POINTER(eventid));
-  g_socket_client_connect_async(js5b->client, G_SOCKET_CONNECTABLE(saddr),
-                                js5b->cancelconnect, handle_client_connect, args);
-  g_object_unref(saddr);
-}
-
-/**
- * Convenience function that find the next candidate to try and
- * call connect_candidate
- */
-static void connect_next_candidate(JingleS5B *js5b, S5BCandidate *cand)
-{
-  GSList *link = g_slist_find(js5b->candidates, cand);
-  if (js5b->cancelconnect != NULL)
-    g_object_unref(js5b->cancelconnect);
-  g_assert(link != NULL);
-  if (link->next == NULL) {
-    // there is no next candidate to try.
-  }
-  connect_candidate(js5b, (S5BCandidate *)link->next->data);
-  return;
-}
-
-static gchar *info(gconstpointer data)
-{
-  //JingleS5B *js5b = (JingleS5B *)data;
-  gchar *info = g_strdup_printf("S5B");
-  return info;
-}
-
-static void end(session_content *sc, gconstpointer data) {
-  return;
-}
-
-/**
- * @brief Handle incoming connections
- */
-static void
-handle_listener_accept(GObject *_listener, GAsyncResult *res, gpointer data)
-{
-  GError *err = NULL;
-  GSocketConnection *conn;
-  //scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Got Incoming Connection");
-  conn = g_socket_listener_accept_finish(G_SOCKET_LISTENER(_listener), res, NULL, &err);
-}
-
-/**
- * @brief Handle outgoing connections
- */
-static void
-handle_client_connect(GObject *_client, GAsyncResult *res, gpointer data)
-{
-  GError *err = NULL;
-  GSocketConnection *conn;
-  GPtrArray *args;
-  JingleS5B *js5b;
-  S5BCandidate *cand;
-  //scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Got Outgoing Connection");
-  
-  args = (GPtrArray *)data;
-  js5b = g_ptr_array_index(args, 0);
-  cand = g_ptr_array_index(args, 1);
-  g_ptr_array_unref(args);
-
-  conn = g_socket_client_connect_finish(G_SOCKET_CLIENT(_client), res, &err);
-
-  if (!g_error_matches(err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-    // if we did not received a CANCELLED error, then the time limit was not
-    // reached and we need to clean up the GSource and unref args a second time.
-    guint eventid = GPOINTER_TO_UINT(g_ptr_array_index(args, 2));
-    GSource *s = g_main_context_find_source_by_id(NULL, eventid);
-    g_source_destroy(s);
-    g_ptr_array_unref(args);
-    connect_next_candidate(js5b, cand);
-    return;
-  }
-
-  if (err != NULL) {
-    if (err->domain == G_IO_ERROR)
-      scr_LogPrint(LPRINT_DEBUG, "Jingle S5B: IO Error (%s)",
-                   err->message ? err->message : "no message");
-    else
-      scr_LogPrint(LPRINT_DEBUG, "Jingle S5B: %s Error (%s)",
-                   g_quark_to_string (err->domain),
-                   err->message ? err->message : "no message");
-
-    g_error_free(err);
-    connect_next_candidate(js5b, cand);
-    return;
-  }
-  js5b->connection = conn; // we have a valid connection
-  // TODO: send transport-info activated IQ
-}
-
-/**
- * @brief Handle any event on a sock
- */
-static void handle_sock_io(GSocket *sock, GIOCondition cond, gpointer data)
-{
-  switch (cond) {
-    case G_IO_IN:
-      break;
-    case G_IO_OUT:
-      break;
-    case G_IO_ERR:
-      break;
-    case G_IO_HUP:
-      break;
-    default:
-      ;
-      // ?!
-  }
-}
-
-static void _send(session_content *sc, gconstpointer data, gchar *buf, gsize size)
-{
-  return;
-}
-
-/**
- * @brief Discover all IPs of this computer
- * @return A linked list of GInetAddress
- */
-static GSList *get_all_local_ips(void) {
-  GSList *addresses = NULL;
-  GInetAddress *thisaddr;
-  GSocketFamily family;
-  struct ifaddrs *first, *ifaddr;
-  struct sockaddr_in *native;
-  struct sockaddr_in6 *native6;
-  const guint8 *addrdata;
-  guint16 ifacecounter = 0; // for lack of a better method
-  LocalIP *candidate;
-  gchar **ifblacklist;
-  guint ifblkcnt;
-
-  gint rval = getifaddrs(&first);
-  if (rval != 0) {
-    scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Unable to retreive local ip addresses");
-    return NULL;
-  }
-
-  if (settings_opt_get("js5b_iface_blacklist") != NULL) {
-    ifblacklist = g_strsplit(settings_opt_get("js5b_iface_blacklist"), ",", 0);
-  } else {
-    ifblacklist = (gchar*[]){NULL};
-  }
-
-  for (ifaddr = first; ifaddr; ifaddr = ifaddr->ifa_next) {
-    gboolean continueloop = FALSE;
-    if (!(ifaddr->ifa_flags & IFF_UP) || ifaddr->ifa_flags & IFF_LOOPBACK)
-      continue;
-
-    for (ifblkcnt = 0; ifblacklist[ifblkcnt]; ifblkcnt++)
-      if (!g_strcmp0(ifaddr->ifa_name, ifblacklist[ifblkcnt])) {
-        continueloop = TRUE;
-        break;
-      }
-    
-    if (continueloop) continue;
-
-    if (ifaddr->ifa_addr->sa_family == AF_INET) {
-      native = (struct sockaddr_in *)ifaddr->ifa_addr;
-      addrdata = (const guint8 *)&native->sin_addr.s_addr;
-      family = G_SOCKET_FAMILY_IPV4;
-    } else if (ifaddr->ifa_addr->sa_family == AF_INET6) {
-      native6 = (struct sockaddr_in6 *)ifaddr->ifa_addr;
-      addrdata = (const guint8 *)&native6->sin6_addr.s6_addr;
-      family = G_SOCKET_FAMILY_IPV6;
-    } else
-      continue;
-
-    thisaddr = g_inet_address_new_from_bytes(addrdata, family);
-    if (g_inet_address_get_is_link_local(thisaddr)) {
-      g_object_unref(thisaddr);
-      continue;
-    }/* else if (g_inset_address_get_is_site_local(thisaddr)) {
-      // TODO: should we offer a way to filter the offer of LAN ips ?
-    } */
-    candidate = g_new0(LocalIP, 1);
-    candidate->address  = thisaddr;
-    candidate->priority = (1<<16)*126+ifacecounter;
-    candidate->type     = JINGLE_S5B_DIRECT;
-    addresses = g_slist_prepend(addresses, candidate);
-    ++ifacecounter;
-  }
-  freeifaddrs(first);
-
-  return addresses;
-}
-
-static gchar *random_str(guint len)
-{
-  gchar *str;
-  gchar car[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
-  gint i;
-  str = g_new0(gchar, 8);
-  for (i = 0; i < len; i++)
-    str[i] = car[g_random_int_range(0, sizeof(car)/sizeof(car[0])-1)];
-
-  str[len] = '\0';
-  return str;	
-}
-
-static gchar *gen_random_sid(void)
-{
-  return random_str(7);
-}
-
-static gchar *gen_random_cid(void)
-{
-  return random_str(7);
-}
-
-static void free_localip(LocalIP *l) {
-  g_object_unref(l->address);
-  g_free(l);
-}
-
-static void jingle_socks5_init(void)
-{
-  // ugly hack to fix the segfault when quitting:
-  // mcabber doesn't load gthread or gobject but they are required by gio,
-  // and cannot be unloaded once they are loaded or a segfault occur.
-  // We dlopen gio with global | nodelete flags. This will also load gobject
-  // and gthread as dependencies. g_type_init will init gobject/gthread (and
-  // set threads_got_initialized to true).
-  if (g_threads_got_initialized == FALSE) {
-    void *dlopen(const char *filename, int flag);
-    // RTLD_LAZY | RTLD_GLOBAL | RTLD_NODELETE
-    dlopen("libgio-2.0.so", 0x00001 | 0x00100 | 0x01000);
-    g_type_init();
-  }
-  jingle_register_transport(NS_JINGLE_TRANSPORT_SOCKS5, &funcs,
-                            JINGLE_TRANSPORT_STREAMING,
-                            JINGLE_TRANSPORT_PRIO_HIGH);
-  xmpp_add_feature(NS_JINGLE_TRANSPORT_SOCKS5);
-  local_ips = get_all_local_ips();
-}
-
-static void jingle_socks5_uninit(void)
-{
-  xmpp_del_feature(NS_JINGLE_TRANSPORT_SOCKS5);
-  jingle_unregister_transport(NS_JINGLE_TRANSPORT_SOCKS5);
-  g_slist_foreach(local_ips, (GFunc)free_localip, NULL);
-  g_slist_free(local_ips);
-}
--- a/jingle-s5b/socks5.h	Wed Sep 01 01:19:40 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-#ifndef __JINGLESOCKS5_H__
-#define __JINGLESOCKS5_H__ 1
-
-#include <glib.h>
-#include <gio/gio.h>
-
-#define NS_JINGLE_TRANSPORT_SOCKS5 "urn:xmpp:jingle:transports:s5b:1"
-
-
-typedef enum {
-  JINGLE_S5B_DIRECT,
-  JINGLE_S5B_ASSISTED,
-  JINGLE_S5B_TUNNEL,
-  JINGLE_S5B_PROXY
-} JingleS5BType;
-
-typedef enum {
-  JINGLE_S5B_TCP,
-  JINGLE_S5B_UDP
-} JingleS5BModes;
-
-typedef struct {
-  JingleS5BModes mode;
-
-  const gchar *sid;
-
-  GSocketConnection *connection;
-
-  GCancellable *cancelconnect;
-
-  GSocketListener *listener;
-
-  GSocketClient *client;
-
-  /**
-   * @brief This is the list of the other client's candidates
-   * 
-   * It should always be priority ordered.
-   */
-  GSList *candidates;
-
-  /**
-   * @brief This is our list of candidates
-   */
-  GSList *ourcandidates;
-} JingleS5B;
- 
-typedef struct {
-  const gchar *cid;
-
-  GInetAddress *host;
-
-  const gchar *jid;
-
-  guint16 port;
-
-  guint64 priority;
-
-  JingleS5BType type;
-} S5BCandidate;
-
-#endif
--- a/jingle/action-handlers.c	Wed Sep 01 01:19:40 2010 +0200
+++ b/jingle/action-handlers.c	Wed Sep 01 20:34:23 2010 +0200
@@ -199,7 +199,7 @@
                              jn->node->children, NULL)) {
       jingle_ack_iq(jn->message);
       return;
-	}
+    }
   }
   /* "If the party that receives an informational message
    * does not understand the payload, it MUST return a
--- a/jingle/check.c	Wed Sep 01 01:19:40 2010 +0200
+++ b/jingle/check.c	Wed Sep 01 20:34:23 2010 +0200
@@ -130,12 +130,12 @@
     if(tmp < 0) {
       g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_BADVALUE,
                   "the creator attribute is invalid");
-	}
+    }
     cn->creator = (JingleCreator)tmp;
   }
   
   if (sendersstr == NULL) {
-	  cn->senders = JINGLE_SENDERS_BOTH;
+      cn->senders = JINGLE_SENDERS_BOTH;
   } else {
     tmp2 = index_in_array(sendersstr, jingle_content_senders);
     if (tmp2 < 0) {
--- a/jingle/jingle.c	Wed Sep 01 01:19:40 2010 +0200
+++ b/jingle/jingle.c	Wed Sep 01 20:34:23 2010 +0200
@@ -198,7 +198,7 @@
 LmMessageHandler *jingle_new_ack_handler(JingleAckHandle *ah)
 {
   if(ack_timeout_checker == 0)
-	  ack_timeout_checker = g_timeout_add_seconds(3, jingle_ack_timeout_checker, NULL);
+      ack_timeout_checker = g_timeout_add_seconds(3, jingle_ack_timeout_checker, NULL);
   
   ah->_inserted = time(NULL);
   ah->_handler = lm_message_handler_new(jingle_handle_ack_iq,
@@ -360,8 +360,8 @@
       gchar *tmp = buddy_resource_getcaps(roster_usr->data, thisres->data);
       if (!caps_has_feature(tmp, (gchar *)ns[indexns]))
         found = FALSE;
-	 }
-	 if (!found) continue;
+      }
+      if (!found) continue;
 
     choosenres = g_strdup(thisres->data);
     g_slist_foreach(reslist, (GFunc)g_free, NULL);