diff options
author | Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | 2011-08-31 13:56:10 +0300 |
---|---|---|
committer | Mikhail Zabaluev <mikhail.zabaluev@nokia.com> | 2011-09-01 11:50:32 +0300 |
commit | 60b5bc0cf55ee60b0c66384e544a9f35d3b3688d (patch) | |
tree | bb8568f3db88afb931aa889f385e879698adf7bf | |
parent | 8569bab0c49f88e397aebc9fcf2d045a21b5be75 (diff) |
Isolated the Google relay resolution code in a separate source file
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/google-relay.c | 309 | ||||
-rw-r--r-- | src/google-relay.h | 45 | ||||
-rw-r--r-- | src/jingle-factory.c | 260 |
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); } |