jingle-s5b/socks5.c
changeset 161 fa1d993d05b6
parent 159 1df5f5e3f1e7
child 162 6afab419ff88
--- 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;