S5B: Use a GSocketListener to manage listener sockets.
authorNicolas Cornu <nicolas.cornu@ensi-bourges.fr>
Thu, 26 Aug 2010 17:25:22 +0200
changeset 161 fa1d993d05b6
parent 160 e149e868d501
child 162 6afab419ff88
S5B: Use a GSocketListener to manage listener sockets. Fix the random string generation functions.
jingle-ibb/ibb.c
jingle-s5b/socks5.c
jingle-s5b/socks5.h
jingle/action-handlers.c
jingle/jingle.c
jingle/register.h
jingle/sessions.c
--- a/jingle-ibb/ibb.c	Thu Aug 26 10:28:51 2010 +0200
+++ b/jingle-ibb/ibb.c	Thu Aug 26 17:25:22 2010 +0200
@@ -46,7 +46,7 @@
 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);
+static void init(session_content *sc, gconstpointer data);
 static void end(session_content *sc, gconstpointer data);
 static gchar *info(gconstpointer data);
 
@@ -336,7 +336,7 @@
   }
 }
 
-static void init(session_content *sc)
+static void init(session_content *sc, gconstpointer data)
 {
   return;
 }
--- a/jingle-s5b/socks5.c	Thu Aug 26 10:28:51 2010 +0200
+++ b/jingle-s5b/socks5.c	Thu Aug 26 17:25:22 2010 +0200
@@ -49,9 +49,12 @@
 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);
+static void init(session_content *sc, gconstpointer data);
 static void end(session_content *sc, gconstpointer data);
+static gchar *info(gconstpointer data);
 
+static void
+handle_listener_accept(GObject *_listener, GAsyncResult *res, gpointer userdata);
 static void handle_sock_io(GSocket *sock, GIOCondition cond, gpointer data);
 static GSList *get_all_local_ips();
 static gchar *gen_random_sid(void);
@@ -69,7 +72,8 @@
   .new            = new,
   .send           = NULL,
   .init           = init,
-  .end            = end
+  .end            = end,
+  .info           = info
 };
 
 module_info_t  info_jingle_s5b = {
@@ -84,10 +88,10 @@
 };
 
 static const gchar *jingle_s5b_types[] = {
+  "direct",
   "assisted",
-  "direct",
+  "tunnel",
   "proxy",
-  "tunnel",
   NULL
 };
 
@@ -100,6 +104,7 @@
 typedef struct {
   GInetAddress *address;
   guint32       priority;
+  JingleS5BType type;
 } LocalIP;
 
 /**
@@ -143,24 +148,25 @@
   for (node2 = node->children; node2; node2 = node2->next) {
     if (g_strcmp0(node->name, "candidate"))
         continue;
-    const gchar *portstr, *prioritystr, *typestr;
+    const gchar *hoststr, *portstr, *prioritystr, *typestr;
     S5BCandidate *cand = g_new0(S5BCandidate, 1);
     cand->cid    = g_strdup(lm_message_node_get_attribute(node2, "cid"));
-    cand->host   = g_strdup(lm_message_node_get_attribute(node2, "host"));
     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 || !cand->host || !cand->jid || !prioritystr) {
+    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) {
+    if (cand->type == -1 || cand->host == NULL) {
       g_free(cand);
       continue;
     }
@@ -179,7 +185,7 @@
     LocalIP *lcand = (LocalIP *)entry->data;
     S5BCandidate *cand = g_new0(S5BCandidate, 1);
     cand->cid      = gen_random_cid();
-    cand->host     = g_inet_address_to_string(lcand->address);
+    cand->host     = g_object_ref(lcand->address);
     cand->jid      = g_strdup(lm_connection_get_jid(lconnection));
     cand->port     = port;
     cand->priority = lcand->priority;
@@ -303,7 +309,7 @@
     priority = g_strdup_printf("%" G_GUINT64_FORMAT, js5c->priority);
     
     lm_message_node_set_attributes(node3, "cid", js5c->cid,
-                                   "host", js5c->host,
+                                   "host", g_inet_address_to_string(js5c->host),
                                    "jid", js5c->jid,
                                    "port", port,
                                    "priority", priority,
@@ -314,45 +320,95 @@
   }
 }
 
-static void init(session_content *sc)
+static void init(session_content *sc, gconstpointer data)
 {
-  JingleS5B *js5 = NULL;
-  GInetAddress *addr;
+  JingleS5B *js5b = (JingleS5B *)data;
   GSocketAddress *saddr;
-  GSource *socksource;
+  //GSource *socksource;
+  guint numlistening = 0; // number of addresses we are listening to
+  GSList *entry;
   GError *err = NULL;
-  g_assert(js5->sock == NULL);
+
+  // 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;
+
+    cand->sock = g_socket_new(g_inet_address_get_family(cand->host),
+                              G_SOCKET_TYPE_STREAM,
+                              G_SOCKET_PROTOCOL_TCP, &err);
+    if (cand->sock == NULL) {
+      scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Error while creating a new socket: %s",
+                   err->message != NULL ? err->message : "(no message)");
+      continue;
+    }
+    g_socket_set_blocking(cand->sock, FALSE);
 
-  addr = g_inet_address_new_from_string("127.0.0.1");
-  js5->sock = g_socket_new(g_inet_address_get_family(addr), G_SOCKET_TYPE_STREAM,
-                           G_SOCKET_PROTOCOL_TCP, &err);
-  if (js5->sock == NULL) {
-    scr_LogPrint(LPRINT_LOGNORM, "Jingle SOCKS5: Error while creating a new socket: %s",
-                 err->message != NULL ? err->message : "(no message)");
-    return; // TODO: we need a way to return errors...
-  }
-  g_socket_set_blocking(js5->sock, FALSE);
-  socksource = g_socket_create_source(js5->sock, ~0, NULL);
+    saddr = g_inet_socket_address_new(cand->host, cand->port);
+    if (!g_socket_bind(cand->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 != NULL ? err->message : "(no message)");
+      goto cleancontinue;
+    }
+    g_object_unref(saddr);
 
-  g_source_set_callback(socksource, (GSourceFunc)handle_sock_io, NULL, NULL);
-  g_source_attach(socksource, NULL);
-  g_source_unref(socksource);
+    if (!g_socket_listen(cand->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 != NULL ? err->message : "(no message)");
+      goto cleancontinue;
+    }
 
-  saddr = g_inet_socket_address_new(addr, 31337);
-  if (!g_socket_connect(js5->sock, saddr, NULL, &err)) {
-    scr_LogPrint(LPRINT_LOGNORM, "Jingle SOCKS5: Error while connecting to the host: %s",
-                 err->message != NULL ? err->message : "(no message)");
-    return;
+    if (!g_socket_listener_add_socket(js5b->listener, cand->sock, NULL, &err)) {
+      scr_LogPrint(LPRINT_LOGNORM, "Jingle S5B: Error while  to the host: %s",
+                   err->message != NULL ? err->message : "(no message)");
+      goto cleancontinue;
+	}
+
+	++numlistening;
+
+cleancontinue:
+      g_object_unref(saddr);
+      g_object_unref(cand->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.
+}
+
+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;
 }
 
+
 /**
- * Handle any event on a sock
+ * @brief Handle incoming connections
+ */
+static void
+handle_listener_accept(GObject *_listener, GAsyncResult *res, gpointer userdata)
+{
+  GError *err = NULL;
+  GSocketConnection *conn;
+  conn = g_socket_listener_accept_finish((GSocketListener *) _listener, res, NULL, &err);
+}
+
+/**
+ * @brief Handle any event on a sock
  */
 static void handle_sock_io(GSocket *sock, GIOCondition cond, gpointer data)
 {
@@ -387,7 +443,7 @@
   LocalIP *candidate;
 
   gint rval = getifaddrs(&first);
-  if (!rval)
+  if (rval != 0)
     return NULL;
 
   for (ifaddr = first; ifaddr; ifaddr = ifaddr->ifa_next) {
@@ -415,6 +471,7 @@
     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;
   }
@@ -430,7 +487,7 @@
   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]))];
+    str[i] = car[g_random_int_range(0, sizeof(car)/sizeof(car[0])-1)];
 
   str[len] = '\0';
   return str;	
--- a/jingle-s5b/socks5.h	Thu Aug 26 10:28:51 2010 +0200
+++ b/jingle-s5b/socks5.h	Thu Aug 26 17:25:22 2010 +0200
@@ -1,13 +1,17 @@
 #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_ASSISTED,
   JINGLE_S5B_DIRECT,
-  JINGLE_S5B_PROXY,
-  JINGLE_S5B_TUNNEL
+  JINGLE_S5B_ASSISTED,
+  JINGLE_S5B_TUNNEL,
+  JINGLE_S5B_PROXY
 } JingleS5BType;
 
 typedef enum {
@@ -20,7 +24,9 @@
 
   const gchar *sid;
 
-  GSocket *sock;
+  GSocketConnection *sock;
+
+  GSocketListener *listener;
 
   /**
    * This is the list of the other client's candidates.
@@ -37,7 +43,7 @@
 typedef struct {
   const gchar *cid;
 
-  const gchar *host;
+  GInetAddress *host;
 
   const gchar *jid;
 
@@ -46,6 +52,8 @@
   guint64 priority;
 
   JingleS5BType type;
+
+  GSocket *sock;
 } S5BCandidate;
 
 #endif
--- a/jingle/action-handlers.c	Thu Aug 26 10:28:51 2010 +0200
+++ b/jingle/action-handlers.c	Thu Aug 26 17:25:22 2010 +0200
@@ -246,7 +246,7 @@
     session_changestate_sessioncontent(sess, jc->name,
                                        JINGLE_SESSION_STATE_ACTIVE);
     sc->transfuncs->handle(JINGLE_SESSION_ACCEPT, sc->transport, jc->transport, NULL);
-    sc->transfuncs->init(sc2);
+    sc->transfuncs->init(sc2, sc->transport);
   }
 
   // We delete content who haven't been accepted
--- a/jingle/jingle.c	Thu Aug 26 10:28:51 2010 +0200
+++ b/jingle/jingle.c	Thu Aug 26 17:25:22 2010 +0200
@@ -496,11 +496,11 @@
 gchar *jingle_generate_sid(void)
 {
   gchar *sid;
-  gchar car[] = "azertyuiopqsdfghjklmwxcvbn1234567890AZERTYUIOPQSDFGHJKLMWXCVBN";
-  int i;
+  gchar car[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+  gint i;
   sid = g_new0(gchar, 11);
   for (i = 0; i < 10; i++)
-    sid[i] = car[g_random_int_range(0, sizeof(car)/sizeof(car[0]))];
+    sid[i] = car[g_random_int_range(0, sizeof(car)/sizeof(car[0])-1)];
 
   sid[10] = '\0';
   
--- a/jingle/register.h	Thu Aug 26 10:28:51 2010 +0200
+++ b/jingle/register.h	Thu Aug 26 17:25:22 2010 +0200
@@ -71,7 +71,7 @@
 typedef void (*JingleTransportToMessage) (gconstpointer data, LmMessageNode *node);
 typedef gconstpointer (*JingleTransportNew) (void);
 typedef void (*JingleTransportSend) (session_content *sc, gconstpointer data, gchar *buf, gsize size);
-typedef void (*JingleTransportInit) (session_content *sc);
+typedef void (*JingleTransportInit) (session_content *sc, gconstpointer data);
 typedef void (*JingleTransportEnd) (session_content *sc, gconstpointer data);
 typedef gchar* (*JingleTransportInfo) (gconstpointer data);
 
--- a/jingle/sessions.c	Thu Aug 26 10:28:51 2010 +0200
+++ b/jingle/sessions.c	Thu Aug 26 17:25:22 2010 +0200
@@ -74,7 +74,7 @@
   for (el = sessions; el; el = el->next) {
     js = (JingleSession*) el->data;
     recipient = (js->origin == JINGLE_SESSION_INCOMING) ? js->from : js->to;
-    if (!g_strcmp0(js->sid, sid) && !g_strcmp0(recipient, from)) {
+    if (!g_strcmp0(js->sid, sid) && !g_ascii_strcasecmp(recipient, from)) {
       return js;
     }
   }