diff options
author | Will Thompson <will.thompson@collabora.co.uk> | 2012-12-06 12:26:28 +0000 |
---|---|---|
committer | Will Thompson <will.thompson@collabora.co.uk> | 2012-12-06 12:26:28 +0000 |
commit | de8905b5bb098c6f0468e9a2856006d1583ad80c (patch) | |
tree | f90f10732584838536c3bc8bcd414ee8fe02a3a5 /src | |
parent | b735dc9c1320b9a6c206a0856758c60c130428a8 (diff) | |
parent | fbd33aa489c1d9c129e2815ed86678ceacb0ad0d (diff) |
Merge branch '25961-stun-srv'
https://bugs.freedesktop.org/show_bug.cgi?id=25961
https://bugs.freedesktop.org/show_bug.cgi?id=25385
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/call-stream.c | 18 | ||||
-rw-r--r-- | src/gtalk-file-collection.c | 18 | ||||
-rw-r--r-- | src/jingle-info-internal.h | 29 | ||||
-rw-r--r-- | src/jingle-info.c | 241 | ||||
-rw-r--r-- | src/jingle-info.h | 15 | ||||
-rw-r--r-- | src/jingle-mint.c | 11 | ||||
-rw-r--r-- | src/media-channel.c | 17 | ||||
-rw-r--r-- | src/media-stream.c | 27 |
9 files changed, 272 insertions, 106 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index b6c6e7740..bb88ed6f9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -163,6 +163,7 @@ libgabble_convenience_la_SOURCES += \ jingle-content.c \ jingle-factory.h \ jingle-factory.c \ + jingle-info-internal.h \ jingle-info.c \ jingle-info.h \ jingle-share.h \ @@ -203,6 +204,7 @@ endif enumtype_sources = \ $(top_srcdir)/src/connection.h \ $(top_srcdir)/src/jingle-types.h \ + $(top_srcdir)/src/jingle-info-internal.h \ $(top_srcdir)/src/room-config.h \ $(top_srcdir)/src/presence.h diff --git a/src/call-stream.c b/src/call-stream.c index ae9ac5e8f..c633a2711 100644 --- a/src/call-stream.c +++ b/src/call-stream.c @@ -101,24 +101,24 @@ get_stun_servers (GabbleCallStream *self) { GPtrArray *arr; GabbleJingleFactory *jf; - gchar *stun_server; - guint stun_port; + GList *stun_servers; arr = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free); jf = gabble_jingle_session_get_factory (self->priv->content->session); + stun_servers = gabble_jingle_info_get_stun_servers ( + gabble_jingle_factory_get_jingle_info (jf)); - /* maybe one day we'll support multiple STUN servers */ - if (gabble_jingle_info_get_stun_server ( - gabble_jingle_factory_get_jingle_info (jf), - &stun_server, &stun_port)) + while (stun_servers != NULL) { + GabbleStunServer *stun_server = stun_servers->data; GValueArray *va = tp_value_array_build (2, - G_TYPE_STRING, stun_server, - G_TYPE_UINT, stun_port, + G_TYPE_STRING, stun_server->address, + G_TYPE_UINT, (guint) stun_server->port, G_TYPE_INVALID); - g_free (stun_server); g_ptr_array_add (arr, va); + + stun_servers = g_list_delete_link (stun_servers, stun_servers); } return arr; diff --git a/src/gtalk-file-collection.c b/src/gtalk-file-collection.c index e13180fe0..b150ddaf5 100644 --- a/src/gtalk-file-collection.c +++ b/src/gtalk-file-collection.c @@ -904,8 +904,7 @@ content_new_share_channel_cb (GabbleJingleContent *content, const gchar *name, NiceAgent *agent = nice_agent_new_reliable (g_main_context_default (), NICE_COMPATIBILITY_GOOGLE); guint stream_id = nice_agent_add_stream (agent, 1); - gchar *stun_server; - guint stun_port; + GList *stun_servers; GoogleRelaySessionData *relay_data = NULL; DEBUG ("New Share channel %s was created and linked to id %d", name, @@ -945,15 +944,18 @@ content_new_share_channel_cb (GabbleJingleContent *content, const gchar *name, nice_agent_attach_recv (agent, stream_id, share_channel->component_id, g_main_context_default (), nice_data_received_cb, self); - if (gabble_jingle_info_get_stun_server ( - gabble_jingle_factory_get_jingle_info (self->priv->jingle_factory), - &stun_server, &stun_port)) + stun_servers = gabble_jingle_info_get_stun_servers ( + gabble_jingle_factory_get_jingle_info (self->priv->jingle_factory)); + if (stun_servers != NULL) { + GabbleStunServer *stun_server = stun_servers->data; + g_object_set (agent, - "stun-server", stun_server, - "stun-server-port", stun_port, + "stun-server", stun_server->address, + "stun-server-port", (guint) stun_server->port, NULL); - g_free (stun_server); + + g_list_free (stun_servers); } relay_data = g_slice_new0 (GoogleRelaySessionData); diff --git a/src/jingle-info-internal.h b/src/jingle-info-internal.h new file mode 100644 index 000000000..1f76ce3bc --- /dev/null +++ b/src/jingle-info-internal.h @@ -0,0 +1,29 @@ +/* + * jingle-info-internal.h - internal types for GabbleJingleInfo + * Copyright © 2012 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 + */ + +#ifndef GABBLE_JINGLE_INFO_INTERNAL_H +#define GABBLE_JINGLE_INFO_INTERNAL_H + +typedef enum { + GABBLE_STUN_SERVER_USER_SPECIFIED, + GABBLE_STUN_SERVER_DISCOVERED, + GABBLE_STUN_SERVER_FALLBACK +} GabbleStunServerSource; + +#endif /* GABBLE_JINGLE_INFO_INTERNAL_H */ diff --git a/src/jingle-info.c b/src/jingle-info.c index bd1f6865d..07f111436 100644 --- a/src/jingle-info.c +++ b/src/jingle-info.c @@ -20,6 +20,7 @@ #include "config.h" #include "jingle-info.h" +#include "jingle-info-internal.h" #include <stdlib.h> #include <telepathy-glib/telepathy-glib.h> @@ -27,6 +28,7 @@ #define DEBUG_FLAG GABBLE_DEBUG_MEDIA #include "debug.h" #include "google-relay.h" +#include "gabble-enumtypes.h" #include "gabble-signals-marshal.h" #include "namespaces.h" @@ -38,13 +40,13 @@ static gboolean jingle_info_cb ( struct _GabbleJingleInfoPrivate { WockyPorter *porter; guint jingle_info_handler_id; + gchar *jid_domain; GabbleGoogleRelayResolver *google_resolver; - gchar *stun_server; - guint16 stun_port; - gchar *fallback_stun_server; - guint16 fallback_stun_port; + GabbleStunServer *stun_server; + GabbleStunServer *fallback_stun_server; + gchar *relay_token; /* TRUE if the user has not explicitly specified a STUN server, and hence @@ -79,6 +81,26 @@ gabble_jingle_info_set_test_mode (void) test_mode = TRUE; } +static GabbleStunServer * +gabble_stun_server_new ( + gchar *address, + guint16 port) +{ + GabbleStunServer stun_server = { address, port }; + + return g_slice_dup (GabbleStunServer, &stun_server); +} + +static void +gabble_stun_server_free (GabbleStunServer *stun_server) +{ + if (stun_server != NULL) + { + g_free (stun_server->address); + g_slice_free (GabbleStunServer, stun_server); + } +} + G_DEFINE_TYPE (GabbleJingleInfo, gabble_jingle_info, G_TYPE_OBJECT) static void @@ -145,11 +167,10 @@ gabble_jingle_info_constructed (GObject *object) parent_class->constructed (object); g_assert (priv->porter != NULL); - priv->jingle_info_handler_id = wocky_c2s_porter_register_handler_from_server ( - WOCKY_C2S_PORTER (priv->porter), - WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET, - WOCKY_PORTER_HANDLER_PRIORITY_NORMAL, jingle_info_cb, self, - '(', "query", ':', NS_GOOGLE_JINGLE_INFO, ')', NULL); + + if (!wocky_decode_jid (wocky_porter_get_bare_jid (priv->porter), NULL, + &priv->jid_domain, NULL)) + g_assert_not_reached (); } static void @@ -161,8 +182,10 @@ gabble_jingle_info_dispose (GObject *object) if (priv->porter != NULL) { - g_assert (priv->jingle_info_handler_id != 0); - wocky_porter_unregister_handler (priv->porter, priv->jingle_info_handler_id); + if (priv->jingle_info_handler_id != 0) + wocky_porter_unregister_handler (priv->porter, + priv->jingle_info_handler_id); + g_clear_object (&priv->porter); } @@ -172,9 +195,11 @@ gabble_jingle_info_dispose (GObject *object) priv->google_resolver = NULL; } - g_free (priv->stun_server); + g_free (priv->jid_domain); + priv->jid_domain = NULL; + gabble_stun_server_free (priv->stun_server); priv->stun_server = NULL; - g_free (priv->fallback_stun_server); + gabble_stun_server_free (priv->fallback_stun_server); priv->fallback_stun_server = NULL; g_free (priv->relay_token); priv->relay_token = NULL; @@ -223,7 +248,7 @@ typedef struct { GabbleJingleInfo *factory; gchar *stun_server; guint16 stun_port; - gboolean fallback; + GabbleStunServerSource source; GCancellable *cancellable; } PendingStunServer; @@ -248,8 +273,10 @@ stun_server_resolved_cb (GObject *resolver, { PendingStunServer *data = user_data; GabbleJingleInfo *self = data->factory; + GabbleJingleInfoPrivate *priv = self->priv; GError *e = NULL; - gchar *stun_server; + GabbleStunServer *stun_server; + gchar *address; GList *entries; if (self != NULL) @@ -267,29 +294,29 @@ stun_server_resolved_cb (GObject *resolver, goto out; } - stun_server = g_inet_address_to_string (entries->data); + address = g_inet_address_to_string (entries->data); g_resolver_free_addresses (entries); DEBUG ("Resolved STUN server %s:%u to %s:%u", data->stun_server, - data->stun_port, stun_server, data->stun_port); + data->stun_port, address, data->stun_port); if (self == NULL) { - g_free (stun_server); + g_free (address); goto out; } - if (data->fallback) + stun_server = gabble_stun_server_new (address, data->stun_port); + + if (data->source == GABBLE_STUN_SERVER_FALLBACK) { - g_free (self->priv->fallback_stun_server); - self->priv->fallback_stun_server = stun_server; - self->priv->fallback_stun_port = data->stun_port; + gabble_stun_server_free (priv->fallback_stun_server); + priv->fallback_stun_server = stun_server; } else { - g_free (self->priv->stun_server); - self->priv->stun_server = stun_server; - self->priv->stun_port = data->stun_port; + gabble_stun_server_free (priv->stun_server); + priv->stun_server = stun_server; g_signal_emit (self, signals[STUN_SERVER_CHANGED], 0, stun_server, data->stun_port); @@ -300,12 +327,12 @@ out: g_object_unref (resolver); } -void -gabble_jingle_info_take_stun_server ( +static void +gabble_jingle_info_take_stun_server_internal ( GabbleJingleInfo *self, gchar *stun_server, guint16 stun_port, - gboolean is_fallback) + GabbleStunServerSource source) { GResolver *resolver; PendingStunServer *data; @@ -313,19 +340,20 @@ gabble_jingle_info_take_stun_server ( if (stun_server == NULL) return; - if (!is_fallback) + if (source == GABBLE_STUN_SERVER_USER_SPECIFIED) self->priv->get_stun_from_jingle = FALSE; resolver = g_resolver_get_default (); data = g_slice_new0 (PendingStunServer); DEBUG ("Resolving %s STUN server %s:%u", - is_fallback ? "fallback" : "primary", stun_server, stun_port); + wocky_enum_to_nick (GABBLE_TYPE_STUN_SERVER_SOURCE, data->source), + stun_server, stun_port); data->factory = self; g_object_add_weak_pointer (G_OBJECT (self), (gpointer *) &data->factory); data->stun_server = stun_server; data->stun_port = stun_port; - data->fallback = is_fallback; + data->source = source; data->cancellable = g_cancellable_new (); g_object_weak_ref (G_OBJECT (self), (GWeakNotify)g_cancellable_cancel, @@ -335,6 +363,30 @@ gabble_jingle_info_take_stun_server ( data->cancellable, stun_server_resolved_cb, data); } +/* + * gabble_jingle_info_take_stun_server: + * @self: a #GabbleJingleInfo object + * @stun_server: (transfer full): the STUN server's address + * @stun_port: the STUN server's port + * @is_fallback: %TRUE if this is a last resort; %FALSE if this STUN server was + * provided by the user (whether by explicitly setting one, or by asking the + * user's XMPP server). + */ +void +gabble_jingle_info_take_stun_server ( + GabbleJingleInfo *self, + gchar *stun_server, + guint16 stun_port, + gboolean is_fallback) +{ + GabbleStunServerSource source = is_fallback + ? GABBLE_STUN_SERVER_FALLBACK + : GABBLE_STUN_SERVER_USER_SPECIFIED; + + gabble_jingle_info_take_stun_server_internal (self, stun_server, stun_port, + source); +} + static void got_jingle_info_stanza ( GabbleJingleInfo *self, @@ -355,9 +407,11 @@ got_jingle_info_stanza ( if (node != NULL) { - node = wocky_node_get_child (node, "server"); + WockyNodeIter iter; - if (node != NULL) + /* TODO: use more than just the first stun server returned. */ + wocky_node_iter_init (&iter, node, "server", NULL); + if (wocky_node_iter_next (&iter, &node)) { const gchar *server; const gchar *port_attr; @@ -374,8 +428,8 @@ got_jingle_info_stanza ( { DEBUG ("jingle info: got stun server %s, port %u", server, port); - gabble_jingle_info_take_stun_server (self, - g_strdup (server), port, FALSE); + gabble_jingle_info_take_stun_server_internal (self, + g_strdup (server), port, GABBLE_STUN_SERVER_DISCOVERED); } } } @@ -504,8 +558,9 @@ jingle_info_reply_cb ( g_object_unref (self); } -void -gabble_jingle_info_send_request (GabbleJingleInfo *self) +static void +gabble_jingle_info_send_google_request ( + GabbleJingleInfo *self) { GabbleJingleInfoPrivate *priv = self->priv; WockyStanza *stanza = wocky_stanza_build ( @@ -516,36 +571,110 @@ gabble_jingle_info_send_request (GabbleJingleInfo *self) wocky_porter_send_iq_async (priv->porter, stanza, NULL, jingle_info_reply_cb, g_object_ref (self)); g_object_unref (stanza); + + priv->jingle_info_handler_id = wocky_c2s_porter_register_handler_from_server ( + WOCKY_C2S_PORTER (priv->porter), + WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET, + WOCKY_PORTER_HANDLER_PRIORITY_NORMAL, jingle_info_cb, self, + '(', "query", ':', NS_GOOGLE_JINGLE_INFO, ')', NULL); } -gboolean -gabble_jingle_info_get_stun_server ( - GabbleJingleInfo *self, - gchar **stun_server, - guint *stun_port) +static void +discover_stun_servers_cb (GObject *resolver, + GAsyncResult *result, + gpointer user_data) { - if (self->priv->stun_server == NULL || self->priv->stun_port == 0) + GabbleJingleInfo *self = GABBLE_JINGLE_INFO (user_data); + GabbleJingleInfoPrivate *priv = self->priv; + GError *error = NULL; + GList *targets; + + targets = g_resolver_lookup_service_finish (G_RESOLVER (resolver), + result, &error); + + if (error != NULL) + { + DEBUG ("Failed to discover STUN servers on %s: %s", + priv->jid_domain, error->message); + g_clear_error (&error); + } + else { - if (self->priv->fallback_stun_server == NULL || - self->priv->fallback_stun_port == 0) - return FALSE; + DEBUG ("Discovered %d STUN servers on %s", g_list_length (targets), + priv->jid_domain); + + /* TODO: use more than just the first. */ + if (targets != NULL) + { + GSrvTarget *target = targets->data; + const gchar *hostname = g_srv_target_get_hostname (target); + guint16 port = g_srv_target_get_port (target); - if (stun_server != NULL) - *stun_server = g_strdup (self->priv->fallback_stun_server); + DEBUG ("Found STUN server: %s:%d", hostname, port); - if (stun_port != NULL) - *stun_port = self->priv->fallback_stun_port; + gabble_jingle_info_take_stun_server (self, g_strdup (hostname), port, + FALSE); + } - return TRUE; + g_resolver_free_targets (targets); } - if (stun_server != NULL) - *stun_server = g_strdup (self->priv->stun_server); + g_object_unref (resolver); + g_object_unref (self); +} - if (stun_port != NULL) - *stun_port = self->priv->stun_port; +static void +gabble_jingle_info_lookup_srv ( + GabbleJingleInfo *self) +{ + GabbleJingleInfoPrivate *priv = self->priv; + GResolver *resolver; - return TRUE; + g_assert (priv->jid_domain != NULL); + DEBUG ("Discovering STUN servers on %s", priv->jid_domain); + + resolver = g_resolver_get_default (); + g_resolver_lookup_service_async (resolver, "stun", "udp", priv->jid_domain, + NULL, discover_stun_servers_cb, g_object_ref (self)); +} + +void +gabble_jingle_info_send_request ( + GabbleJingleInfo *self, + gboolean google_jingleinfo_supported) +{ + /* FIXME: we probably don't want to send either query if the user specified a + * stun server (that is, get_stun_from_jingle is FALSE). + */ + if (google_jingleinfo_supported) + gabble_jingle_info_send_google_request (self); + else + gabble_jingle_info_lookup_srv (self); +} + +/* + * gabble_jingle_info_get_stun_servers: + * + * Grabs the currently known and resolved stun servers. + * + * Returns: (transfer container): a list of GabbleJingleInfo structs + */ +GList * +gabble_jingle_info_get_stun_servers ( + GabbleJingleInfo *self) +{ + GabbleJingleInfoPrivate *priv = self->priv; + GQueue stun_servers = G_QUEUE_INIT; + + if (priv->stun_server != NULL) + g_queue_push_head (&stun_servers, priv->stun_server); + + /* Only add the fallback server as a last resort. */ + if (stun_servers.length == 0 && + priv->fallback_stun_server != NULL) + g_queue_push_tail (&stun_servers, priv->fallback_stun_server); + + return stun_servers.head; } const gchar * diff --git a/src/jingle-info.h b/src/jingle-info.h index 2ce8111c6..afac05610 100644 --- a/src/jingle-info.h +++ b/src/jingle-info.h @@ -47,12 +47,17 @@ void gabble_jingle_info_take_stun_server ( gchar *stun_server, guint16 stun_port, gboolean is_fallback); -void gabble_jingle_info_send_request (GabbleJingleInfo *self); - -gboolean gabble_jingle_info_get_stun_server ( +void gabble_jingle_info_send_request ( GabbleJingleInfo *self, - gchar **stun_server, - guint *stun_port); + gboolean google_jingleinfo_supported); + +typedef struct { + gchar *address; + guint16 port; +} GabbleStunServer; + +GList *gabble_jingle_info_get_stun_servers ( + GabbleJingleInfo *self); const gchar *gabble_jingle_info_get_google_relay_token ( GabbleJingleInfo *self); diff --git a/src/jingle-mint.c b/src/jingle-mint.c index f575cfd39..2cb6d0e9d 100644 --- a/src/jingle-mint.c +++ b/src/jingle-mint.c @@ -229,11 +229,12 @@ connection_status_changed_cb ( gabble_jingle_info_take_stun_server (info, stun_server, stun_port, TRUE); - if (priv->conn->features & - GABBLE_CONNECTION_FEATURES_GOOGLE_JINGLE_INFO) - { - gabble_jingle_info_send_request (info); - } + gabble_jingle_info_send_request (info, + /* FIXME: one day Wocky will know about caps and then we won't + * have to pass in a flag here. + */ + !!(priv->conn->features & + GABBLE_CONNECTION_FEATURES_GOOGLE_JINGLE_INFO)); } break; diff --git a/src/media-channel.c b/src/media-channel.c index 47c99d7a8..6b5ebd328 100644 --- a/src/media-channel.c +++ b/src/media-channel.c @@ -327,8 +327,7 @@ gabble_media_channel_constructor (GType type, guint n_props, TpHandleRepoIface *contact_handles; GabbleJingleInfo *ji; const gchar *relay_token; - gchar *stun_server; - guint stun_port; + GList *stun_servers; obj = G_OBJECT_CLASS (gabble_media_channel_parent_class)-> constructor (type, n_props, props); @@ -378,15 +377,17 @@ gabble_media_channel_constructor (GType type, guint n_props, /* Set up Google relay related properties */ ji = gabble_jingle_mint_get_info (priv->conn->jingle_mint); - - if (gabble_jingle_info_get_stun_server (ji, &stun_server, - &stun_port)) + stun_servers = gabble_jingle_info_get_stun_servers (ji); + if (stun_servers != NULL) { + GabbleStunServer *stun_server = stun_servers->data; + g_object_set (obj, - "stun-server", stun_server, - "stun-port", stun_port, + "stun-server", stun_server->address, + "stun-port", (guint) stun_server->port, NULL); - g_free (stun_server); + + g_list_free (stun_servers); } relay_token = gabble_jingle_info_get_google_relay_token (ji); diff --git a/src/media-stream.c b/src/media-stream.c index 300269214..d347c78eb 100644 --- a/src/media-stream.c +++ b/src/media-stream.c @@ -268,8 +268,7 @@ gabble_media_stream_constructor (GType type, guint n_props, GabbleMediaStream *stream; GabbleMediaStreamPrivate *priv; GabbleJingleFactory *jf; - gchar *stun_server; - guint stun_port; + GList *stun_servers; /* call base class constructor */ obj = G_OBJECT_CLASS (gabble_media_stream_parent_class)-> @@ -283,21 +282,19 @@ gabble_media_stream_constructor (GType type, guint n_props, * point in waiting for them - either they've already been resolved, or * we're too late to use them for this stream */ jf = gabble_jingle_session_get_factory (priv->content->session); - - /* maybe one day we'll support multiple STUN servers */ - if (gabble_jingle_info_get_stun_server ( - gabble_jingle_factory_get_jingle_info (jf), - &stun_server, &stun_port)) + stun_servers = gabble_jingle_info_get_stun_servers ( + gabble_jingle_factory_get_jingle_info (jf)); + while (stun_servers != NULL) { - GValueArray *va = g_value_array_new (2); - - g_value_array_append (va, NULL); - g_value_array_append (va, NULL); - g_value_init (va->values + 0, G_TYPE_STRING); - g_value_init (va->values + 1, G_TYPE_UINT); - g_value_take_string (va->values + 0, stun_server); - g_value_set_uint (va->values + 1, stun_port); + GabbleStunServer *stun_server = stun_servers->data; + GValueArray *va = tp_value_array_build (2, + G_TYPE_STRING, stun_server->address, + G_TYPE_UINT, (guint) stun_server->port, + G_TYPE_INVALID); + g_ptr_array_add (priv->stun_servers, va); + + stun_servers = g_list_delete_link (stun_servers, stun_servers); } /* go for the bus */ |