summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikhail Zabaluev <mikhail.zabaluev@nokia.com>2011-08-31 13:56:10 +0300
committerMikhail Zabaluev <mikhail.zabaluev@nokia.com>2011-09-01 11:50:32 +0300
commit60b5bc0cf55ee60b0c66384e544a9f35d3b3688d (patch)
treebb8568f3db88afb931aa889f385e879698adf7bf
parent8569bab0c49f88e397aebc9fcf2d045a21b5be75 (diff)
Isolated the Google relay resolution code in a separate source file
-rw-r--r--src/Makefile.am2
-rw-r--r--src/google-relay.c309
-rw-r--r--src/google-relay.h45
-rw-r--r--src/jingle-factory.c260
4 files changed, 366 insertions, 250 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 00f802a1..c94cfaa0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -90,6 +90,8 @@ libgabble_convenience_la_SOURCES = \
ft-manager.h \
gabble.c \
gabble.h \
+ google-relay.c \
+ google-relay.h \
gtalk-file-collection.h \
gtalk-file-collection.c \
im-channel.h \
diff --git a/src/google-relay.c b/src/google-relay.c
new file mode 100644
index 00000000..82133625
--- /dev/null
+++ b/src/google-relay.c
@@ -0,0 +1,309 @@
+/*
+ * google-relay.c - Support for Google relays for Jingle
+ *
+ * Copyright (C) 2006-2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "google-relay.h"
+
+#include <string.h>
+#include <libsoup/soup.h>
+#include <telepathy-glib/util.h>
+
+#define DEBUG_FLAG GABBLE_DEBUG_MEDIA
+
+#include "debug.h"
+
+#define RELAY_HTTP_TIMEOUT 5
+
+struct _GabbleGoogleRelayResolver {
+ SoupSession *soup;
+};
+
+typedef struct
+{
+ GPtrArray *relays;
+ guint component;
+ guint requests_to_do;
+ GabbleJingleFactoryRelaySessionCb callback;
+ gpointer user_data;
+} RelaySessionData;
+
+static RelaySessionData *
+relay_session_data_new (guint requests_to_do,
+ GabbleJingleFactoryRelaySessionCb callback,
+ gpointer user_data)
+{
+ RelaySessionData *rsd = g_slice_new0 (RelaySessionData);
+
+ rsd->relays = g_ptr_array_sized_new (requests_to_do);
+ rsd->component = 1;
+ rsd->requests_to_do = requests_to_do;
+ rsd->callback = callback;
+ rsd->user_data = user_data;
+
+ return rsd;
+}
+
+/* This is a GSourceFunc */
+static gboolean
+relay_session_data_call (gpointer p)
+{
+ RelaySessionData *rsd = p;
+
+ g_assert (rsd->callback != NULL);
+
+ rsd->callback (rsd->relays, rsd->user_data);
+
+ return FALSE;
+}
+
+/* This is a GDestroyNotify */
+static void
+relay_session_data_destroy (gpointer p)
+{
+ RelaySessionData *rsd = p;
+
+ g_ptr_array_foreach (rsd->relays, (GFunc) g_hash_table_destroy, NULL);
+ g_ptr_array_free (rsd->relays, TRUE);
+
+ g_slice_free (RelaySessionData, rsd);
+}
+
+static void
+translate_relay_info (GPtrArray *relays,
+ const gchar *relay_ip,
+ const gchar *username,
+ const gchar *password,
+ const gchar *static_type,
+ const gchar *port_string,
+ guint component)
+{
+ GHashTable *asv;
+ guint64 portll;
+ guint port;
+
+ if (port_string == NULL)
+ {
+ DEBUG ("no relay port for %s found", static_type);
+ return;
+ }
+
+ portll = g_ascii_strtoull (port_string, NULL, 10);
+
+ if (portll == 0 || portll > G_MAXUINT16)
+ {
+ DEBUG ("failed to parse relay port '%s' for %s", port_string,
+ static_type);
+ return;
+ }
+ port = (guint) portll;
+
+ DEBUG ("type=%s ip=%s port=%u username=%s password=%s component=%u",
+ static_type, relay_ip, port, username, password, component);
+ /* keys are static, values are slice-allocated */
+ asv = g_hash_table_new_full (g_str_hash, g_str_equal,
+ NULL, (GDestroyNotify) tp_g_value_slice_free);
+ g_hash_table_insert (asv, "ip",
+ tp_g_value_slice_new_string (relay_ip));
+ g_hash_table_insert (asv, "type",
+ tp_g_value_slice_new_static_string (static_type));
+ g_hash_table_insert (asv, "port",
+ tp_g_value_slice_new_uint (port));
+ g_hash_table_insert (asv, "username",
+ tp_g_value_slice_new_string (username));
+ g_hash_table_insert (asv, "password",
+ tp_g_value_slice_new_string (password));
+ g_hash_table_insert (asv, "component",
+ tp_g_value_slice_new_uint (component));
+
+ g_ptr_array_add (relays, asv);
+}
+
+static void
+on_http_response (SoupSession *soup,
+ SoupMessage *msg,
+ gpointer user_data)
+{
+ RelaySessionData *rsd = user_data;
+
+ if (msg->status_code != 200)
+ {
+ DEBUG ("Google session creation failed, relaying not used: %d %s",
+ msg->status_code, msg->reason_phrase);
+ }
+ else
+ {
+ /* parse a=b lines into GHashTable
+ * (key, value both borrowed from items of the strv 'lines') */
+ GHashTable *map = g_hash_table_new (g_str_hash, g_str_equal);
+ gchar **lines;
+ guint i;
+ const gchar *relay_ip;
+ const gchar *relay_udp_port;
+ const gchar *relay_tcp_port;
+ const gchar *relay_ssltcp_port;
+ const gchar *username;
+ const gchar *password;
+ gchar *escaped_str;
+
+ escaped_str = g_strescape (msg->response_body->data, "\r\n");
+ DEBUG ("Response from Google:\n====\n%s\n====", escaped_str);
+ g_free (escaped_str);
+
+ lines = g_strsplit (msg->response_body->data, "\n", 0);
+
+ if (lines != NULL)
+ {
+ for (i = 0; lines[i] != NULL; i++)
+ {
+ gchar *delim = strchr (lines[i], '=');
+ size_t len;
+
+ if (delim == NULL || delim == lines[i])
+ {
+ /* ignore empty keys or lines without '=' */
+ continue;
+ }
+
+ len = strlen (lines[i]);
+
+ if (lines[i][len - 1] == '\r')
+ {
+ lines[i][len - 1] = '\0';
+ }
+
+ *delim = '\0';
+ g_hash_table_insert (map, lines[i], delim + 1);
+ }
+ }
+
+ relay_ip = g_hash_table_lookup (map, "relay.ip");
+ relay_udp_port = g_hash_table_lookup (map, "relay.udp_port");
+ relay_tcp_port = g_hash_table_lookup (map, "relay.tcp_port");
+ relay_ssltcp_port = g_hash_table_lookup (map, "relay.ssltcp_port");
+ username = g_hash_table_lookup (map, "username");
+ password = g_hash_table_lookup (map, "password");
+
+ if (relay_ip == NULL)
+ {
+ DEBUG ("No relay.ip found");
+ }
+ else if (username == NULL)
+ {
+ DEBUG ("No username found");
+ }
+ else if (password == NULL)
+ {
+ DEBUG ("No password found");
+ }
+ else
+ {
+ translate_relay_info (rsd->relays, relay_ip, username, password,
+ "udp", relay_udp_port, rsd->component);
+ translate_relay_info (rsd->relays, relay_ip, username, password,
+ "tcp", relay_tcp_port, rsd->component);
+ translate_relay_info (rsd->relays, relay_ip, username, password,
+ "tls", relay_ssltcp_port, rsd->component);
+ }
+
+ g_strfreev (lines);
+ g_hash_table_destroy (map);
+ }
+
+ rsd->component++;
+
+ if ((--rsd->requests_to_do) == 0)
+ {
+ relay_session_data_call (rsd);
+ relay_session_data_destroy (rsd);
+ }
+}
+
+GabbleGoogleRelayResolver *
+gabble_google_relay_resolver_new (void)
+{
+ GabbleGoogleRelayResolver *resolver =
+ g_slice_new0 (GabbleGoogleRelayResolver);
+
+ resolver->soup = soup_session_async_new ();
+
+ /* If we don't get answer in a few seconds, relay won't do
+ * us much help anyways. */
+ g_object_set (resolver->soup, "timeout", RELAY_HTTP_TIMEOUT, NULL);
+
+ return resolver;
+}
+
+void
+gabble_google_relay_resolver_destroy (GabbleGoogleRelayResolver *self)
+{
+ tp_clear_object (&self->soup);
+
+ g_slice_free (GabbleGoogleRelayResolver, self);
+}
+
+void
+gabble_google_relay_resolver_resolve (GabbleGoogleRelayResolver *self,
+ guint components,
+ const gchar *server,
+ guint16 port,
+ const gchar *token,
+ GabbleJingleFactoryRelaySessionCb callback,
+ gpointer user_data)
+{
+ RelaySessionData *rsd;
+ gchar *url;
+ guint i;
+
+ rsd = relay_session_data_new (components, callback, user_data);
+
+ if (server == NULL)
+ {
+ DEBUG ("No relay server provided, not creating google relay session");
+ g_idle_add_full (G_PRIORITY_DEFAULT, relay_session_data_call, rsd,
+ relay_session_data_destroy);
+ return;
+ }
+
+ if (token == NULL)
+ {
+ DEBUG ("No relay token provided, not creating google relay session");
+ g_idle_add_full (G_PRIORITY_DEFAULT, relay_session_data_call, rsd,
+ relay_session_data_destroy);
+ return;
+ }
+
+ url = g_strdup_printf ("http://%s:%u/create_session", server, (guint) port);
+
+ for (i = 0; i < components; i++)
+ {
+ SoupMessage *msg = soup_message_new ("GET", url);
+
+ DEBUG ("Trying to create a new relay session on %s", url);
+
+ /* libjingle sets both headers, so shall we */
+ soup_message_headers_append (msg->request_headers,
+ "X-Talk-Google-Relay-Auth", token);
+ soup_message_headers_append (msg->request_headers,
+ "X-Google-Relay-Auth", token);
+
+ soup_session_queue_message (self->soup, msg, on_http_response, rsd);
+ }
+
+ g_free (url);
+}
diff --git a/src/google-relay.h b/src/google-relay.h
new file mode 100644
index 00000000..6eb180e3
--- /dev/null
+++ b/src/google-relay.h
@@ -0,0 +1,45 @@
+/*
+ * google-relay.h - Header for GabbleGoogleRelaySession
+ *
+ * Copyright (C) 2006-2008 Collabora Ltd.
+ * Copyright (C) 2011 Nokia Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GABBLE_GOOGLE_RELAY_H__
+#define __GABBLE_GOOGLE_RELAY_H__
+
+#include <glib.h>
+
+#include "jingle-factory.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GabbleGoogleRelayResolver GabbleGoogleRelayResolver;
+
+GabbleGoogleRelayResolver * gabble_google_relay_resolver_new (void);
+void gabble_google_relay_resolver_destroy (GabbleGoogleRelayResolver *self);
+void gabble_google_relay_resolver_resolve (GabbleGoogleRelayResolver *self,
+ guint requests_to_do,
+ const gchar *server,
+ guint16 port,
+ const gchar *token,
+ GabbleJingleFactoryRelaySessionCb callback,
+ gpointer user_data);
+
+G_END_DECLS
+
+#endif /* __GABBLE_GOOGLE_RELAY_H__ */
diff --git a/src/jingle-factory.c b/src/jingle-factory.c
index 3c9152f9..99de4ee0 100644
--- a/src/jingle-factory.c
+++ b/src/jingle-factory.c
@@ -22,11 +22,9 @@
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <glib.h>
#include <wocky/wocky-c2s-porter.h>
-#include <libsoup/soup.h>
#define DEBUG_FLAG GABBLE_DEBUG_MEDIA
@@ -43,6 +41,8 @@
#include "namespaces.h"
#include "util.h"
+#include "google-relay.h"
+
G_DEFINE_TYPE(GabbleJingleFactory, gabble_jingle_factory, G_TYPE_OBJECT);
/* signal enum */
@@ -72,7 +72,8 @@ struct _GabbleJingleFactoryPrivate
/* instances of SESSION_MAP_KEY_FORMAT => GabbleJingleSession. */
GHashTable *sessions;
- SoupSession *soup;
+
+ GabbleGoogleRelayResolver *google_resolver;
gchar *stun_server;
guint16 stun_port;
@@ -112,8 +113,6 @@ static void connection_porter_available_cb (
WockyPorter *porter,
gpointer user_data);
-#define RELAY_HTTP_TIMEOUT 5
-
static gboolean test_mode = FALSE;
void
@@ -445,7 +444,7 @@ gabble_jingle_factory_dispose (GObject *object)
DEBUG ("dispose called");
priv->dispose_has_run = TRUE;
- tp_clear_object (&priv->soup);
+ tp_clear_pointer (&priv->google_resolver, gabble_google_relay_resolver_destroy);
tp_clear_pointer (&priv->sessions, g_hash_table_destroy);
tp_clear_pointer (&priv->content_types, g_hash_table_destroy);
tp_clear_pointer (&priv->transports, g_hash_table_destroy);
@@ -940,204 +939,6 @@ gabble_jingle_factory_get_stun_server (GabbleJingleFactory *self,
return TRUE;
}
-typedef struct
-{
- GPtrArray *relays;
- guint component;
- guint requests_to_do;
- GabbleJingleFactoryRelaySessionCb callback;
- gpointer user_data;
-} RelaySessionData;
-
-static RelaySessionData *
-relay_session_data_new (guint requests_to_do,
- GabbleJingleFactoryRelaySessionCb callback,
- gpointer user_data)
-{
- RelaySessionData *rsd = g_slice_new0 (RelaySessionData);
-
- rsd->relays = g_ptr_array_sized_new (requests_to_do);
- rsd->component = 1;
- rsd->requests_to_do = requests_to_do;
- rsd->callback = callback;
- rsd->user_data = user_data;
-
- return rsd;
-}
-
-/* This is a GSourceFunc */
-static gboolean
-relay_session_data_call (gpointer p)
-{
- RelaySessionData *rsd = p;
-
- g_assert (rsd->callback != NULL);
-
- rsd->callback (rsd->relays, rsd->user_data);
-
- return FALSE;
-}
-
-/* This is a GDestroyNotify */
-static void
-relay_session_data_destroy (gpointer p)
-{
- RelaySessionData *rsd = p;
-
- g_ptr_array_foreach (rsd->relays, (GFunc) g_hash_table_destroy, NULL);
- g_ptr_array_free (rsd->relays, TRUE);
-
- g_slice_free (RelaySessionData, rsd);
-}
-
-static void
-translate_relay_info (GPtrArray *relays,
- const gchar *relay_ip,
- const gchar *username,
- const gchar *password,
- const gchar *static_type,
- const gchar *port_string,
- guint component)
-{
- GHashTable *asv;
- guint port = 0;
-
- if (port_string == NULL)
- {
- DEBUG ("no relay port for %s found", static_type);
- return;
- }
-
- port = atoi (port_string);
-
- if (port == 0 || port > G_MAXUINT16)
- {
- DEBUG ("failed to parse relay port '%s' for %s", port_string,
- static_type);
- return;
- }
-
- DEBUG ("type=%s ip=%s port=%u username=%s password=%s component=%u",
- static_type, relay_ip, port, username, password, component);
- /* keys are static, values are slice-allocated */
- asv = g_hash_table_new_full (g_str_hash, g_str_equal,
- NULL, (GDestroyNotify) tp_g_value_slice_free);
- g_hash_table_insert (asv, "ip",
- tp_g_value_slice_new_string (relay_ip));
- g_hash_table_insert (asv, "type",
- tp_g_value_slice_new_static_string (static_type));
- g_hash_table_insert (asv, "port",
- tp_g_value_slice_new_uint (port));
- g_hash_table_insert (asv, "username",
- tp_g_value_slice_new_string (username));
- g_hash_table_insert (asv, "password",
- tp_g_value_slice_new_string (password));
- g_hash_table_insert (asv, "component",
- tp_g_value_slice_new_uint (component));
-
- g_ptr_array_add (relays, asv);
-}
-
-static void
-on_http_response (SoupSession *soup,
- SoupMessage *msg,
- gpointer user_data)
-{
- RelaySessionData *rsd = user_data;
-
- if (msg->status_code != 200)
- {
- DEBUG ("Google session creation failed, relaying not used: %d %s",
- msg->status_code, msg->reason_phrase);
- }
- else
- {
- /* parse a=b lines into GHashTable
- * (key, value both borrowed from items of the strv 'lines') */
- GHashTable *map = g_hash_table_new (g_str_hash, g_str_equal);
- gchar **lines;
- guint i;
- const gchar *relay_ip;
- const gchar *relay_udp_port;
- const gchar *relay_tcp_port;
- const gchar *relay_ssltcp_port;
- const gchar *username;
- const gchar *password;
- gchar *escaped_str;
-
- escaped_str = g_strescape (msg->response_body->data, "\r\n");
- DEBUG ("Response from Google:\n====\n%s\n====", escaped_str);
- g_free (escaped_str);
-
- lines = g_strsplit (msg->response_body->data, "\n", 0);
-
- if (lines != NULL)
- {
- for (i = 0; lines[i] != NULL; i++)
- {
- gchar *delim = strchr (lines[i], '=');
- size_t len;
-
- if (delim == NULL || delim == lines[i])
- {
- /* ignore empty keys or lines without '=' */
- continue;
- }
-
- len = strlen (lines[i]);
-
- if (lines[i][len - 1] == '\r')
- {
- lines[i][len - 1] = '\0';
- }
-
- *delim = '\0';
- g_hash_table_insert (map, lines[i], delim + 1);
- }
- }
-
- relay_ip = g_hash_table_lookup (map, "relay.ip");
- relay_udp_port = g_hash_table_lookup (map, "relay.udp_port");
- relay_tcp_port = g_hash_table_lookup (map, "relay.tcp_port");
- relay_ssltcp_port = g_hash_table_lookup (map, "relay.ssltcp_port");
- username = g_hash_table_lookup (map, "username");
- password = g_hash_table_lookup (map, "password");
-
- if (relay_ip == NULL)
- {
- DEBUG ("No relay.ip found");
- }
- else if (username == NULL)
- {
- DEBUG ("No username found");
- }
- else if (password == NULL)
- {
- DEBUG ("No password found");
- }
- else
- {
- translate_relay_info (rsd->relays, relay_ip, username, password,
- "udp", relay_udp_port, rsd->component);
- translate_relay_info (rsd->relays, relay_ip, username, password,
- "tcp", relay_tcp_port, rsd->component);
- translate_relay_info (rsd->relays, relay_ip, username, password,
- "tls", relay_ssltcp_port, rsd->component);
- }
-
- g_strfreev (lines);
- g_hash_table_destroy (map);
- }
-
- rsd->component++;
-
- if ((--rsd->requests_to_do) == 0)
- {
- relay_session_data_call (rsd);
- relay_session_data_destroy (rsd);
- }
-}
-
void
gabble_jingle_factory_create_google_relay_session (
GabbleJingleFactory *fac,
@@ -1146,56 +947,15 @@ gabble_jingle_factory_create_google_relay_session (
gpointer user_data)
{
GabbleJingleFactoryPrivate *priv = fac->priv;
- gchar *url;
- guint i;
- RelaySessionData *rsd;
g_return_if_fail (callback != NULL);
- rsd = relay_session_data_new (components, callback, user_data);
-
- if (fac->priv->relay_server == NULL)
+ if (priv->google_resolver == NULL)
{
- DEBUG ("No relay server provided, not creating google relay session");
- g_idle_add_full (G_PRIORITY_DEFAULT, relay_session_data_call, rsd,
- relay_session_data_destroy);
- return;
- }
-
- if (fac->priv->relay_token == NULL)
- {
- DEBUG ("No relay token provided, not creating google relay session");
- g_idle_add_full (G_PRIORITY_DEFAULT, relay_session_data_call, rsd,
- relay_session_data_destroy);
- return;
- }
-
- if (priv->soup == NULL)
- {
- priv->soup = soup_session_async_new ();
-
- /* If we don't get answer in a few seconds, relay won't do
- * us much help anyways. */
- g_object_set (priv->soup, "timeout", RELAY_HTTP_TIMEOUT, NULL);
- }
-
- url = g_strdup_printf ("http://%s:%d/create_session",
- fac->priv->relay_server, fac->priv->relay_http_port);
-
- for (i = 0; i < components; i++)
- {
- SoupMessage *msg = soup_message_new ("GET", url);
-
- DEBUG ("Trying to create a new relay session on %s", url);
-
- /* libjingle sets both headers, so shall we */
- soup_message_headers_append (msg->request_headers,
- "X-Talk-Google-Relay-Auth", fac->priv->relay_token);
- soup_message_headers_append (msg->request_headers,
- "X-Google-Relay-Auth", fac->priv->relay_token);
-
- soup_session_queue_message (priv->soup, msg, on_http_response, rsd);
+ priv->google_resolver = gabble_google_relay_resolver_new ();
}
- g_free (url);
+ gabble_google_relay_resolver_resolve (priv->google_resolver,
+ components, priv->relay_server, priv->relay_http_port, priv->relay_token,
+ callback, user_data);
}