diff options
author | Will Thompson <will.thompson@collabora.co.uk> | 2012-12-12 16:08:34 +0000 |
---|---|---|
committer | Will Thompson <will.thompson@collabora.co.uk> | 2012-12-13 11:08:11 +0000 |
commit | e9cc205c266f628e74c47b4a1bb949be8cc4b8c3 (patch) | |
tree | ad4d5e34ef9682cec153b237a9143714f5a535cb | |
parent | f91a1063b57b8b50bd3301633e8620051be2e906 (diff) |
Delete all the Jingle code which moved to Wocky
The astute reader will notice that I added a call to
jingle_share_register() to jingle-mint.c.
-rw-r--r-- | src/Makefile.am | 24 | ||||
-rw-r--r-- | src/google-relay.c | 325 | ||||
-rw-r--r-- | src/google-relay.h | 45 | ||||
-rw-r--r-- | src/jingle-content.c | 1407 | ||||
-rw-r--r-- | src/jingle-content.h | 163 | ||||
-rw-r--r-- | src/jingle-factory.c | 604 | ||||
-rw-r--r-- | src/jingle-factory.h | 90 | ||||
-rw-r--r-- | src/jingle-info-internal.h | 29 | ||||
-rw-r--r-- | src/jingle-info.c | 730 | ||||
-rw-r--r-- | src/jingle-info.h | 121 | ||||
-rw-r--r-- | src/jingle-media-rtp.c | 1517 | ||||
-rw-r--r-- | src/jingle-media-rtp.h | 124 | ||||
-rw-r--r-- | src/jingle-mint.c | 3 | ||||
-rw-r--r-- | src/jingle-session.c | 2447 | ||||
-rw-r--r-- | src/jingle-session.h | 139 | ||||
-rw-r--r-- | src/jingle-transport-google.c | 644 | ||||
-rw-r--r-- | src/jingle-transport-google.h | 68 | ||||
-rw-r--r-- | src/jingle-transport-iceudp.c | 617 | ||||
-rw-r--r-- | src/jingle-transport-iceudp.h | 64 | ||||
-rw-r--r-- | src/jingle-transport-iface.c | 283 | ||||
-rw-r--r-- | src/jingle-transport-iface.h | 109 | ||||
-rw-r--r-- | src/jingle-transport-rawudp.c | 404 | ||||
-rw-r--r-- | src/jingle-transport-rawudp.h | 64 | ||||
-rw-r--r-- | src/jingle-types.h | 125 |
24 files changed, 3 insertions, 10143 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index bb88ed6f9..22a0278db 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -157,34 +157,12 @@ libgabble_convenience_la_SOURCES += \ call-member-content.c \ call-stream.h \ call-stream.c \ - google-relay.c \ - google-relay.h \ - jingle-content.h \ - jingle-content.c \ - jingle-factory.h \ - jingle-factory.c \ - jingle-info-internal.h \ - jingle-info.c \ - jingle-info.h \ jingle-share.h \ jingle-share.c \ - jingle-media-rtp.h \ - jingle-media-rtp.c \ jingle-mint.h \ jingle-mint.c \ - jingle-session.h \ - jingle-session.c \ jingle-tp-util.h \ jingle-tp-util.c \ - jingle-transport-google.h \ - jingle-transport-google.c \ - jingle-transport-rawudp.h \ - jingle-transport-rawudp.c \ - jingle-transport-iceudp.h \ - jingle-transport-iceudp.c \ - jingle-transport-iface.h \ - jingle-transport-iface.c \ - jingle-types.h \ media-channel.h \ media-channel-internal.h \ media-channel.c \ @@ -203,8 +181,6 @@ 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/google-relay.c b/src/google-relay.c deleted file mode 100644 index 000deaa86..000000000 --- a/src/google-relay.c +++ /dev/null @@ -1,325 +0,0 @@ -/* - * 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 "config.h" -#include "google-relay.h" - -#include <string.h> - -#ifdef ENABLE_GOOGLE_RELAY -#include <libsoup/soup.h> -#endif - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA - -#ifdef G_OS_WIN32 -#undef ERROR -#endif - -#include "debug.h" - -#define RELAY_HTTP_TIMEOUT 5 - -struct _WockyGoogleRelayResolver { -#ifdef ENABLE_GOOGLE_RELAY - SoupSession *soup; -#else - GObject *soup; -#endif -}; - -typedef struct -{ - GPtrArray *relays; - guint component; - guint requests_to_do; - WockyJingleInfoRelaySessionCb callback; - gpointer user_data; -} RelaySessionData; - -static RelaySessionData * -relay_session_data_new (guint requests_to_do, - WockyJingleInfoRelaySessionCb callback, - gpointer user_data) -{ - RelaySessionData *rsd = g_slice_new0 (RelaySessionData); - - rsd->relays = g_ptr_array_sized_new (requests_to_do); - g_ptr_array_set_free_func (rsd->relays, (GDestroyNotify) wocky_jingle_relay_free); - 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_unref (rsd->relays); - - g_slice_free (RelaySessionData, rsd); -} - -#ifdef ENABLE_GOOGLE_RELAY - -static void -translate_relay_info (GPtrArray *relays, - const gchar *relay_ip, - const gchar *username, - const gchar *password, - WockyJingleRelayType relay_type, - const gchar *port_string, - guint component) -{ - guint64 portll; - guint port; - - if (port_string == NULL) - { - DEBUG ("no relay port for %u found", relay_type); - return; - } - - portll = g_ascii_strtoull (port_string, NULL, 10); - - if (portll == 0 || portll > G_MAXUINT16) - { - DEBUG ("failed to parse relay port '%s' for %u", port_string, - relay_type); - return; - } - port = (guint) portll; - - DEBUG ("type=%u ip=%s port=%u username=%s password=%s component=%u", - relay_type, relay_ip, port, username, password, component); - - g_ptr_array_add (relays, - wocky_jingle_relay_new (relay_type, relay_ip, port, username, password, - component)); -} - -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, - WOCKY_JINGLE_RELAY_TYPE_UDP, relay_udp_port, rsd->component); - translate_relay_info (rsd->relays, relay_ip, username, password, - WOCKY_JINGLE_RELAY_TYPE_TCP, relay_tcp_port, rsd->component); - translate_relay_info (rsd->relays, relay_ip, username, password, - WOCKY_JINGLE_RELAY_TYPE_TLS, relay_ssltcp_port, rsd->component); - } - - g_strfreev (lines); - g_hash_table_unref (map); - } - - rsd->component++; - - if ((--rsd->requests_to_do) == 0) - { - relay_session_data_call (rsd); - relay_session_data_destroy (rsd); - } -} - -#endif /* ENABLE_GOOGLE_RELAY */ - -WockyGoogleRelayResolver * -wocky_google_relay_resolver_new (void) -{ - WockyGoogleRelayResolver *resolver = - g_slice_new0 (WockyGoogleRelayResolver); - -#ifdef ENABLE_GOOGLE_RELAY - - 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); - -#endif - - return resolver; -} - -void -wocky_google_relay_resolver_destroy (WockyGoogleRelayResolver *self) -{ - g_clear_object (&self->soup); - - g_slice_free (WockyGoogleRelayResolver, self); -} - -void -wocky_google_relay_resolver_resolve (WockyGoogleRelayResolver *self, - guint components, - const gchar *server, - guint16 port, - const gchar *token, - WockyJingleInfoRelaySessionCb callback, - gpointer user_data) -{ - RelaySessionData *rsd = - relay_session_data_new (components, callback, user_data); - -#ifdef ENABLE_GOOGLE_RELAY - - gchar *url; - guint i; - - 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); - -#else /* !ENABLE_GOOGLE_RELAY */ - - DEBUG ("Google relay service is not supported"); - - g_idle_add_full (G_PRIORITY_DEFAULT, relay_session_data_call, rsd, - relay_session_data_destroy); - -#endif -} diff --git a/src/google-relay.h b/src/google-relay.h deleted file mode 100644 index d8a5fe05a..000000000 --- a/src/google-relay.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * google-relay.h - Header for WockyGoogleRelaySession - * - * 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-info.h" - -G_BEGIN_DECLS - -typedef struct _WockyGoogleRelayResolver WockyGoogleRelayResolver; - -WockyGoogleRelayResolver * wocky_google_relay_resolver_new (void); -void wocky_google_relay_resolver_destroy (WockyGoogleRelayResolver *self); -void wocky_google_relay_resolver_resolve (WockyGoogleRelayResolver *self, - guint requests_to_do, - const gchar *server, - guint16 port, - const gchar *token, - WockyJingleInfoRelaySessionCb callback, - gpointer user_data); - -G_END_DECLS - -#endif /* __GABBLE_GOOGLE_RELAY_H__ */ diff --git a/src/jingle-content.c b/src/jingle-content.c deleted file mode 100644 index eb6f2f100..000000000 --- a/src/jingle-content.c +++ /dev/null @@ -1,1407 +0,0 @@ -/* - * gabble-jingle-content.c - Source for WockyJingleContent - * Copyright (C) 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 "config.h" -#include "jingle-content.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <glib.h> - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA - -#include "connection.h" -#include "debug.h" -#include "jingle-factory.h" -#include "jingle-session.h" -#include "jingle-transport-iface.h" -#include "jingle-transport-google.h" -#include "jingle-media-rtp.h" -#include "namespaces.h" -#include "gabble-signals-marshal.h" - -/* signal enum */ -enum -{ - READY, - NEW_CANDIDATES, - REMOVED, - NEW_SHARE_CHANNEL, - COMPLETED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -/* properties */ -enum -{ - PROP_SESSION = 1, - PROP_CONTENT_NS, - PROP_TRANSPORT_NS, - PROP_NAME, - PROP_SENDERS, - PROP_STATE, - PROP_DISPOSITION, - PROP_LOCALLY_CREATED, - LAST_PROPERTY -}; - -struct _WockyJingleContentPrivate -{ - gchar *name; - gchar *creator; - gboolean created_by_us; - WockyJingleContentState state; - WockyJingleContentSenders senders; - - gchar *content_ns; - gchar *transport_ns; - gchar *disposition; - - WockyJingleTransportIface *transport; - - /* Whether we've got the codecs (intersection) ready. */ - gboolean media_ready; - - /* Whether we have at least one local candidate. */ - gboolean have_local_candidates; - - guint gtalk4_event_id; - guint last_share_channel_component_id; - - gboolean dispose_has_run; -}; - -#define DEFAULT_CONTENT_TIMEOUT 60000 - -/* lookup tables */ - -G_DEFINE_TYPE(WockyJingleContent, wocky_jingle_content, G_TYPE_OBJECT); - -static void new_transport_candidates_cb (WockyJingleTransportIface *trans, - GList *candidates, WockyJingleContent *content); -static void _maybe_ready (WockyJingleContent *self); -static void transport_created (WockyJingleContent *c); - -static void -wocky_jingle_content_init (WockyJingleContent *obj) -{ - WockyJingleContentPrivate *priv = - G_TYPE_INSTANCE_GET_PRIVATE (obj, WOCKY_TYPE_JINGLE_CONTENT, - WockyJingleContentPrivate); - obj->priv = priv; - - DEBUG ("%p", obj); - - priv->state = WOCKY_JINGLE_CONTENT_STATE_EMPTY; - priv->created_by_us = TRUE; - priv->media_ready = FALSE; - priv->have_local_candidates = FALSE; - priv->gtalk4_event_id = 0; - priv->dispose_has_run = FALSE; - - obj->session = NULL; -} - -static void -wocky_jingle_content_dispose (GObject *object) -{ - WockyJingleContent *content = WOCKY_JINGLE_CONTENT (object); - WockyJingleContentPrivate *priv = content->priv; - - if (priv->dispose_has_run) - return; - - DEBUG ("%p", object); - priv->dispose_has_run = TRUE; - - if (priv->gtalk4_event_id != 0) - { - g_source_remove (priv->gtalk4_event_id); - priv->gtalk4_event_id = 0; - } - - g_free (priv->name); - priv->name = NULL; - - g_free (priv->creator); - priv->creator = NULL; - - g_free (priv->content_ns); - priv->content_ns = NULL; - - g_free (priv->transport_ns); - priv->transport_ns = NULL; - - g_free (priv->disposition); - priv->disposition = NULL; - - if (G_OBJECT_CLASS (wocky_jingle_content_parent_class)->dispose) - G_OBJECT_CLASS (wocky_jingle_content_parent_class)->dispose (object); -} - -static void -wocky_jingle_content_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - WockyJingleContent *self = WOCKY_JINGLE_CONTENT (object); - WockyJingleContentPrivate *priv = self->priv; - - switch (property_id) { - case PROP_SESSION: - g_value_set_object (value, self->session); - break; - case PROP_NAME: - g_value_set_string (value, priv->name); - break; - case PROP_SENDERS: - g_value_set_uint (value, priv->senders); - break; - case PROP_STATE: - g_value_set_uint (value, priv->state); - break; - case PROP_CONTENT_NS: - g_value_set_string (value, priv->content_ns); - break; - case PROP_TRANSPORT_NS: - g_value_set_string (value, priv->transport_ns); - break; - case PROP_DISPOSITION: - g_value_set_string (value, priv->disposition); - break; - case PROP_LOCALLY_CREATED: - g_value_set_boolean (value, priv->created_by_us); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -wocky_jingle_content_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - WockyJingleContent *self = WOCKY_JINGLE_CONTENT (object); - WockyJingleContentPrivate *priv = self->priv; - - switch (property_id) { - case PROP_SESSION: - self->session = g_value_get_object (value); - break; - case PROP_CONTENT_NS: - g_free (priv->content_ns); - priv->content_ns = g_value_dup_string (value); - break; - case PROP_TRANSPORT_NS: - g_free (priv->transport_ns); - priv->transport_ns = g_value_dup_string (value); - - /* We can't switch transports. */ - g_assert (priv->transport == NULL); - - if (priv->transport_ns != NULL) - { - GType transport_type = wocky_jingle_factory_lookup_transport ( - wocky_jingle_session_get_factory (self->session), - priv->transport_ns); - - g_assert (transport_type != 0); - - priv->transport = wocky_jingle_transport_iface_new (transport_type, - self, priv->transport_ns); - - g_signal_connect (priv->transport, "new-candidates", - (GCallback) new_transport_candidates_cb, self); - - transport_created (self); - } - break; - case PROP_NAME: - /* can't rename */ - g_assert (priv->name == NULL); - - priv->name = g_value_dup_string (value); - break; - case PROP_SENDERS: - priv->senders = g_value_get_uint (value); - break; - case PROP_STATE: - priv->state = g_value_get_uint (value); - break; - case PROP_DISPOSITION: - g_assert (priv->disposition == NULL); - priv->disposition = g_value_dup_string (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static WockyJingleContentSenders -get_default_senders_real (WockyJingleContent *c) -{ - return WOCKY_JINGLE_CONTENT_SENDERS_BOTH; -} - - -static void -wocky_jingle_content_class_init (WockyJingleContentClass *cls) -{ - GParamSpec *param_spec; - GObjectClass *object_class = G_OBJECT_CLASS (cls); - - g_type_class_add_private (cls, sizeof (WockyJingleContentPrivate)); - - object_class->get_property = wocky_jingle_content_get_property; - object_class->set_property = wocky_jingle_content_set_property; - object_class->dispose = wocky_jingle_content_dispose; - - cls->get_default_senders = get_default_senders_real; - - /* property definitions */ - param_spec = g_param_spec_object ("session", "WockyJingleSession object", - "Jingle session object that owns this content.", - WOCKY_TYPE_JINGLE_SESSION, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_SESSION, param_spec); - - param_spec = g_param_spec_string ("name", "Content name", - "A unique content name in the session.", - NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_NAME, param_spec); - - param_spec = g_param_spec_string ("content-ns", "Content namespace", - "Namespace identifying the content type.", - NULL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_CONTENT_NS, param_spec); - - param_spec = g_param_spec_string ("transport-ns", "Transport namespace", - "Namespace identifying the transport type.", - NULL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_TRANSPORT_NS, param_spec); - - param_spec = g_param_spec_uint ("senders", "Stream senders", - "Valid senders for the stream.", - 0, G_MAXUINT32, WOCKY_JINGLE_CONTENT_SENDERS_NONE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_SENDERS, param_spec); - - param_spec = g_param_spec_uint ("state", "Content state", - "The current state that the content is in.", - 0, G_MAXUINT32, WOCKY_JINGLE_CONTENT_STATE_EMPTY, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_STATE, param_spec); - - param_spec = g_param_spec_string ("disposition", "Content disposition", - "Distinguishes between 'session' and other contents.", - NULL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_DISPOSITION, param_spec); - - param_spec = g_param_spec_boolean ("locally-created", "Locally created", - "True if the content was created by the local client.", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_LOCALLY_CREATED, param_spec); - - /* signal definitions */ - - signals[READY] = g_signal_new ("ready", - G_OBJECT_CLASS_TYPE (cls), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[NEW_CANDIDATES] = g_signal_new ( - "new-candidates", - G_TYPE_FROM_CLASS (cls), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - - signals[NEW_SHARE_CHANNEL] = g_signal_new ( - "new-share-channel", - G_TYPE_FROM_CLASS (cls), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - gabble_marshal_VOID__STRING_UINT, - G_TYPE_NONE, - 2, - G_TYPE_STRING, G_TYPE_UINT); - - signals[COMPLETED] = g_signal_new ( - "completed", - G_TYPE_FROM_CLASS (cls), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - /* This signal serves as notification that the WockyJingleContent is now - * meaningless; everything holding a reference should drop it after receiving - * 'removed'. - */ - signals[REMOVED] = g_signal_new ("removed", - G_OBJECT_CLASS_TYPE (cls), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - - -static WockyJingleContentSenders -get_default_senders (WockyJingleContent *c) -{ - WockyJingleContentSenders (*virtual_method)(WockyJingleContent *) = \ - WOCKY_JINGLE_CONTENT_GET_CLASS (c)->get_default_senders; - - g_assert (virtual_method != NULL); - return virtual_method (c); -} - - -static WockyJingleContentSenders -parse_senders (const gchar *txt) -{ - if (txt == NULL) - return WOCKY_JINGLE_CONTENT_SENDERS_NONE; - - if (!wocky_strdiff (txt, "initiator")) - return WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR; - else if (!wocky_strdiff (txt, "responder")) - return WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER; - else if (!wocky_strdiff (txt, "both")) - return WOCKY_JINGLE_CONTENT_SENDERS_BOTH; - - return WOCKY_JINGLE_CONTENT_SENDERS_NONE; -} - -static const gchar * -produce_senders (WockyJingleContentSenders senders) -{ - switch (senders) { - case WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR: - return "initiator"; - case WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER: - return "responder"; - case WOCKY_JINGLE_CONTENT_SENDERS_BOTH: - return "both"; - default: - DEBUG ("invalid content senders %u", senders); - g_assert_not_reached (); - } - - /* to make gcc not complain */ - return NULL; -} - - -#define SET_BAD_REQ(txt) \ - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, txt) - -static void -new_transport_candidates_cb (WockyJingleTransportIface *trans, - GList *candidates, WockyJingleContent *content) -{ - /* just pass the signal on */ - g_signal_emit (content, signals[NEW_CANDIDATES], 0, candidates); -} - -static void -transport_created (WockyJingleContent *c) -{ - void (*virtual_method)(WockyJingleContent *, WockyJingleTransportIface *) = \ - WOCKY_JINGLE_CONTENT_GET_CLASS (c)->transport_created; - - if (virtual_method != NULL) - virtual_method (c, c->priv->transport); -} - - -static void -parse_description (WockyJingleContent *c, WockyNode *desc_node, - GError **error) -{ - void (*virtual_method)(WockyJingleContent *, WockyNode *, - GError **) = WOCKY_JINGLE_CONTENT_GET_CLASS (c)->parse_description; - - g_assert (virtual_method != NULL); - virtual_method (c, desc_node, error); -} - -static gboolean -send_gtalk4_transport_accept (gpointer user_data) -{ - WockyJingleContent *c = WOCKY_JINGLE_CONTENT (user_data); - WockyJingleContentPrivate *priv = c->priv; - WockyNode *sess_node; - WockyStanza *msg = wocky_jingle_session_new_message (c->session, - WOCKY_JINGLE_ACTION_TRANSPORT_ACCEPT, &sess_node); - - DEBUG ("Sending Gtalk4 'transport-accept' message to peer"); - wocky_node_add_child_ns (sess_node, "transport", priv->transport_ns); - - wocky_jingle_session_send (c->session, msg); - - return FALSE; -} - -void -wocky_jingle_content_parse_add (WockyJingleContent *c, - WockyNode *content_node, gboolean google_mode, GError **error) -{ - WockyJingleContentPrivate *priv = c->priv; - const gchar *name, *creator, *senders, *disposition; - WockyNode *trans_node, *desc_node; - GType transport_type = 0; - WockyJingleTransportIface *trans = NULL; - WockyJingleDialect dialect = wocky_jingle_session_get_dialect (c->session); - - priv->created_by_us = FALSE; - - desc_node = wocky_node_get_child (content_node, "description"); - trans_node = wocky_node_get_child (content_node, "transport"); - creator = wocky_node_get_attribute (content_node, "creator"); - name = wocky_node_get_attribute (content_node, "name"); - senders = wocky_node_get_attribute (content_node, "senders"); - - g_assert (priv->transport_ns == NULL); - - if (google_mode) - { - if (creator == NULL) - creator = "initiator"; - - /* the google protocols don't give the contents names, so put in a dummy - * value if none was set by the session*/ - if (priv->name == NULL) - name = priv->name = g_strdup ("gtalk"); - else - name = priv->name; - - if (trans_node == NULL) - { - /* gtalk lj0.3 assumes google-p2p transport */ - DEBUG ("detected GTalk3 dialect"); - - dialect = WOCKY_JINGLE_DIALECT_GTALK3; - g_object_set (c->session, "dialect", WOCKY_JINGLE_DIALECT_GTALK3, NULL); - transport_type = wocky_jingle_factory_lookup_transport ( - wocky_jingle_session_get_factory (c->session), - ""); - - /* in practice we do support gtalk-p2p, so this can't happen */ - if (G_UNLIKELY (transport_type == 0)) - { - SET_BAD_REQ ("gtalk-p2p transport unsupported"); - return; - } - - priv->transport_ns = g_strdup (""); - } - } - else - { - if (creator == NULL && - wocky_jingle_session_peer_has_cap (c->session, - QUIRK_GOOGLE_WEBMAIL_CLIENT)) - { - if (wocky_jingle_content_creator_is_initiator (c)) - creator = "initiator"; - else - creator = "responder"; - - DEBUG ("Working around GMail omitting creator=''; assuming '%s'", - creator); - } - - if ((trans_node == NULL) || (creator == NULL) || (name == NULL)) - { - SET_BAD_REQ ("missing required content attributes or elements"); - return; - } - - /* In proper protocols the name comes from the stanza */ - g_assert (priv->name == NULL); - priv->name = g_strdup (name); - } - - /* if we didn't set it to google-p2p implicitly already, detect it */ - if (transport_type == 0) - { - const gchar *ns = wocky_node_get_ns (trans_node); - - transport_type = wocky_jingle_factory_lookup_transport ( - wocky_jingle_session_get_factory (c->session), ns); - - if (transport_type == 0) - { - SET_BAD_REQ ("unsupported content transport"); - return; - } - - priv->transport_ns = g_strdup (ns); - } - - if (senders == NULL) - priv->senders = get_default_senders (c); - else - priv->senders = parse_senders (senders); - - if (priv->senders == WOCKY_JINGLE_CONTENT_SENDERS_NONE) - { - SET_BAD_REQ ("invalid content senders"); - return; - } - - parse_description (c, desc_node, error); - if (*error != NULL) - return; - - disposition = wocky_node_get_attribute (content_node, "disposition"); - if (disposition == NULL) - disposition = "session"; - - if (wocky_strdiff (disposition, priv->disposition)) - { - g_free (priv->disposition); - priv->disposition = g_strdup (disposition); - } - - DEBUG ("content creating new transport type %s", g_type_name (transport_type)); - - trans = wocky_jingle_transport_iface_new (transport_type, - c, priv->transport_ns); - - g_signal_connect (trans, "new-candidates", - (GCallback) new_transport_candidates_cb, c); - - /* Depending on transport, there may be initial candidates specified here */ - if (trans_node != NULL) - { - wocky_jingle_transport_iface_parse_candidates (trans, trans_node, error); - if (*error) - { - g_object_unref (trans); - return; - } - } - - g_assert (priv->transport == NULL); - priv->transport = trans; - transport_created (c); - - g_assert (priv->creator == NULL); - priv->creator = g_strdup (creator); - - priv->state = WOCKY_JINGLE_CONTENT_STATE_NEW; - - /* GTalk4 seems to require "transport-accept" for acknowledging - * the transport type. wjt confirms that this is apparently necessary for - * incoming calls to work. - */ - if (dialect == WOCKY_JINGLE_DIALECT_GTALK4) - priv->gtalk4_event_id = g_idle_add (send_gtalk4_transport_accept, c); - - return; -} - -static guint -new_share_channel (WockyJingleContent *c, const gchar *name) -{ - WockyJingleContentPrivate *priv = c->priv; - WockyJingleTransportGoogle *gtrans = NULL; - - if (priv->transport && - WOCKY_IS_JINGLE_TRANSPORT_GOOGLE (priv->transport)) - { - guint id = priv->last_share_channel_component_id + 1; - - gtrans = WOCKY_JINGLE_TRANSPORT_GOOGLE (priv->transport); - - if (!jingle_transport_google_set_component_name (gtrans, name, id)) - return 0; - - priv->last_share_channel_component_id++; - - DEBUG ("New Share channel '%s' with id : %d", name, id); - - g_signal_emit (c, signals[NEW_SHARE_CHANNEL], 0, name, id); - - return priv->last_share_channel_component_id; - } - return 0; -} - -guint -wocky_jingle_content_create_share_channel (WockyJingleContent *self, - const gchar *name) -{ - WockyJingleContentPrivate *priv = self->priv; - WockyNode *sess_node, *channel_node; - WockyStanza *msg = NULL; - - /* Send the info action before creating the channel, in case candidates need - to be sent on the signal emit. It doesn't matter if the channel already - exists anyways... */ - msg = wocky_jingle_session_new_message (self->session, - WOCKY_JINGLE_ACTION_INFO, &sess_node); - - DEBUG ("Sending 'info' message to peer : channel %s", name); - channel_node = wocky_node_add_child_ns (sess_node, "channel", - priv->content_ns); - wocky_node_set_attribute (channel_node, "name", name); - - wocky_jingle_session_send (self->session, msg); - - return new_share_channel (self, name); -} - -void -wocky_jingle_content_send_complete (WockyJingleContent *self) -{ - WockyJingleContentPrivate *priv = self->priv; - WockyNode *sess_node; - WockyStanza *msg = NULL; - - msg = wocky_jingle_session_new_message (self->session, - WOCKY_JINGLE_ACTION_INFO, &sess_node); - - DEBUG ("Sending 'info' message to peer : complete"); - wocky_node_add_child_ns (sess_node, "complete", priv->content_ns); - - wocky_jingle_session_send (self->session, msg); - -} - -void -wocky_jingle_content_parse_info (WockyJingleContent *c, - WockyNode *content_node, GError **error) -{ - WockyNode *channel_node; - WockyNode *complete_node; - - channel_node = wocky_node_get_child (content_node, "channel"); - complete_node = wocky_node_get_child (content_node, "complete"); - - DEBUG ("parsing info message : %p - %p", channel_node, complete_node); - if (channel_node) - { - const gchar *name; - name = wocky_node_get_attribute (channel_node, "name"); - if (name != NULL) - new_share_channel (c, name); - } - else if (complete_node) - { - g_signal_emit (c, signals[COMPLETED], 0); - } - -} - -void -wocky_jingle_content_parse_accept (WockyJingleContent *c, - WockyNode *content_node, gboolean google_mode, GError **error) -{ - WockyJingleContentPrivate *priv = c->priv; - const gchar *senders; - WockyNode *trans_node, *desc_node; - WockyJingleDialect dialect = wocky_jingle_session_get_dialect (c->session); - WockyJingleContentSenders newsenders; - - desc_node = wocky_node_get_child (content_node, "description"); - trans_node = wocky_node_get_child (content_node, "transport"); - senders = wocky_node_get_attribute (content_node, "senders"); - - if (WOCKY_IS_JINGLE_MEDIA_RTP (c) && - WOCKY_JINGLE_DIALECT_IS_GOOGLE (dialect) && trans_node == NULL) - { - DEBUG ("no transport node, assuming GTalk3 dialect"); - /* gtalk lj0.3 assumes google-p2p transport */ - g_object_set (c->session, "dialect", WOCKY_JINGLE_DIALECT_GTALK3, NULL); - } - - if (senders == NULL) - newsenders = get_default_senders (c); - else - newsenders = parse_senders (senders); - - if (newsenders == WOCKY_JINGLE_CONTENT_SENDERS_NONE) - { - SET_BAD_REQ ("invalid content senders"); - return; - } - - if (newsenders != priv->senders) - { - DEBUG ("changing senders from %s to %s", produce_senders (priv->senders), - produce_senders (newsenders)); - priv->senders = newsenders; - g_object_notify ((GObject *) c, "senders"); - } - - parse_description (c, desc_node, error); - if (*error != NULL) - return; - - priv->state = WOCKY_JINGLE_CONTENT_STATE_ACKNOWLEDGED; - g_object_notify ((GObject *) c, "state"); - - if (trans_node != NULL) - { - wocky_jingle_transport_iface_parse_candidates (priv->transport, - trans_node, NULL); - } -} - -void -wocky_jingle_content_parse_description_info (WockyJingleContent *c, - WockyNode *content_node, GError **error) -{ - WockyJingleContentPrivate *priv = c->priv; - WockyNode *desc_node; - desc_node = wocky_node_get_child (content_node, "description"); - if (desc_node == NULL) - { - SET_BAD_REQ ("invalid description-info action"); - return; - } - - if (priv->created_by_us && priv->state < WOCKY_JINGLE_CONTENT_STATE_ACKNOWLEDGED) - { - /* The stream was created by us and the other side didn't acknowledge it - * yet, thus we don't have their codec information, thus the - * description-info isn't meaningful and can be ignored */ - DEBUG ("Ignoring description-info as we didn't receive the codecs yet"); - return; - } - - parse_description (c, desc_node, error); -} - - -void -wocky_jingle_content_produce_node (WockyJingleContent *c, - WockyNode *parent, - gboolean include_description, - gboolean include_transport, - WockyNode **trans_node_out) -{ - WockyJingleContentPrivate *priv = c->priv; - WockyNode *content_node, *trans_node; - WockyJingleDialect dialect = wocky_jingle_session_get_dialect (c->session); - void (*produce_desc)(WockyJingleContent *, WockyNode *) = - WOCKY_JINGLE_CONTENT_GET_CLASS (c)->produce_description; - - if ((dialect == WOCKY_JINGLE_DIALECT_GTALK3) || - (dialect == WOCKY_JINGLE_DIALECT_GTALK4)) - { - content_node = parent; - } - else - { - content_node = wocky_node_add_child (parent, "content"); - wocky_node_set_attributes (content_node, - "name", priv->name, - "senders", produce_senders (priv->senders), - NULL); - - if (wocky_jingle_content_creator_is_initiator (c)) - wocky_node_set_attribute (content_node, "creator", "initiator"); - else - wocky_node_set_attribute (content_node, "creator", "responder"); - } - - if (include_description) - produce_desc (c, content_node); - - if (include_transport) - { - if (dialect == WOCKY_JINGLE_DIALECT_GTALK3) - { - /* GTalk 03 doesn't use a transport, but assumes gtalk-p2p */ - trans_node = parent; - } - else - { - trans_node = wocky_node_add_child_ns (content_node, "transport", - priv->transport_ns); - } - - if (trans_node_out != NULL) - *trans_node_out = trans_node; - } -} - -void -wocky_jingle_content_update_senders (WockyJingleContent *c, - WockyNode *content_node, GError **error) -{ - WockyJingleContentPrivate *priv = c->priv; - WockyJingleContentSenders senders; - - senders = parse_senders (wocky_node_get_attribute (content_node, "senders")); - - if (senders == WOCKY_JINGLE_CONTENT_SENDERS_NONE) - { - SET_BAD_REQ ("invalid content senders in stream"); - return; - } - - priv->senders = senders; - g_object_notify ((GObject *) c, "senders"); -} - -void -wocky_jingle_content_parse_transport_info (WockyJingleContent *self, - WockyNode *trans_node, GError **error) -{ - WockyJingleContentPrivate *priv = self->priv; - - wocky_jingle_transport_iface_parse_candidates (priv->transport, trans_node, error); -} - -/* Takes in a list of slice-allocated WockyJingleCandidate structs */ -void -wocky_jingle_content_add_candidates (WockyJingleContent *self, GList *li) -{ - WockyJingleContentPrivate *priv = self->priv; - - DEBUG ("called content: %s created_by_us: %d", priv->name, - priv->created_by_us); - - if (li == NULL) - return; - - wocky_jingle_transport_iface_new_local_candidates (priv->transport, li); - - if (!priv->have_local_candidates) - { - priv->have_local_candidates = TRUE; - /* Maybe we were waiting for at least one candidate? */ - _maybe_ready (self); - } - - /* If the content exists on the wire, let the transport send this candidate - * if it wants to. - */ - if (priv->state > WOCKY_JINGLE_CONTENT_STATE_EMPTY) - wocky_jingle_transport_iface_send_candidates (priv->transport, FALSE); -} - -/* Returns whether the content is ready to be signalled (initiated, for local - * streams, or acknowledged, for remote streams. */ -gboolean -wocky_jingle_content_is_ready (WockyJingleContent *self) -{ - WockyJingleContentPrivate *priv = self->priv; - - if (priv->created_by_us) - { - /* If it's created by us, media ready, not signalled, and we have - * at least one local candidate, it's ready to be added. */ - if (priv->media_ready && priv->state == WOCKY_JINGLE_CONTENT_STATE_EMPTY && - (!WOCKY_IS_JINGLE_MEDIA_RTP (self) || priv->have_local_candidates)) - return TRUE; - } - else - { - /* If it's created by peer, media and transports ready, - * and not acknowledged yet, it's ready for acceptance. */ - if (priv->media_ready && priv->state == WOCKY_JINGLE_CONTENT_STATE_NEW && - (!WOCKY_IS_JINGLE_MEDIA_RTP (self) || - wocky_jingle_transport_iface_can_accept (priv->transport))) - return TRUE; - } - - return FALSE; -} - -static void -send_content_add_or_accept (WockyJingleContent *self) -{ - WockyJingleContentPrivate *priv = self->priv; - WockyStanza *msg; - WockyNode *sess_node, *transport_node; - WockyJingleAction action; - WockyJingleContentState new_state = WOCKY_JINGLE_CONTENT_STATE_EMPTY; - - g_assert (wocky_jingle_content_is_ready (self)); - - if (priv->created_by_us) - { - /* TODO: set a timer for acknowledgement */ - action = WOCKY_JINGLE_ACTION_CONTENT_ADD; - new_state = WOCKY_JINGLE_CONTENT_STATE_SENT; - } - else - { - action = WOCKY_JINGLE_ACTION_CONTENT_ACCEPT; - new_state = WOCKY_JINGLE_CONTENT_STATE_ACKNOWLEDGED; - } - - msg = wocky_jingle_session_new_message (self->session, - action, &sess_node); - wocky_jingle_content_produce_node (self, sess_node, TRUE, TRUE, - &transport_node); - wocky_jingle_transport_iface_inject_candidates (priv->transport, - transport_node); - wocky_jingle_session_send (self->session, msg); - - priv->state = new_state; - g_object_notify (G_OBJECT (self), "state"); -} - -static void -_maybe_ready (WockyJingleContent *self) -{ - WockyJingleContentPrivate *priv = self->priv; - WockyJingleState state; - - if (!wocky_jingle_content_is_ready (self)) - return; - - /* If content disposition is session and session - * is not yet acknowledged/active, we signall - * the readiness to the session and let it take - * care of it. Otherwise, we can deal with it - * ourselves. */ - - g_object_get (self->session, "state", &state, NULL); - - if (!wocky_strdiff (priv->disposition, "session") && - (state < WOCKY_JINGLE_STATE_PENDING_ACCEPT_SENT)) - { - /* Notify the session that we're ready for - * session-initiate/session-accept */ - g_signal_emit (self, signals[READY], 0); - } - else - { - if (state >= WOCKY_JINGLE_STATE_PENDING_INITIATE_SENT) - { - send_content_add_or_accept (self); - - /* if neccessary, transmit the candidates */ - wocky_jingle_transport_iface_send_candidates (priv->transport, - FALSE); - } - else - { - /* non session-disposition content ready without session - * being initiated at all? */ - DEBUG ("session not initiated yet, ignoring non-session ready content"); - return; - } - } -} - -void -wocky_jingle_content_maybe_send_description (WockyJingleContent *self) -{ - WockyJingleContentPrivate *priv = self->priv; - - /* If we didn't send the content yet there is no reason to send a - * description-info to update it */ - if (priv->state < WOCKY_JINGLE_CONTENT_STATE_SENT) - return; - - if (wocky_jingle_session_defines_action (self->session, - WOCKY_JINGLE_ACTION_DESCRIPTION_INFO)) - { - WockyNode *sess_node; - WockyStanza *msg = wocky_jingle_session_new_message (self->session, - WOCKY_JINGLE_ACTION_DESCRIPTION_INFO, &sess_node); - - wocky_jingle_content_produce_node (self, sess_node, TRUE, FALSE, NULL); - wocky_jingle_session_send (self->session, msg); - } - else - { - DEBUG ("not sending description-info, speaking an old dialect"); - } -} - - -/* Used when session-initiate is sent (so all initial contents transmit their - * candidates), and when we detect gtalk3 after we've transmitted some - * candidates. */ -void -wocky_jingle_content_retransmit_candidates (WockyJingleContent *self, - gboolean all) -{ - wocky_jingle_transport_iface_send_candidates (self->priv->transport, all); -} - -void -wocky_jingle_content_inject_candidates (WockyJingleContent *self, - WockyNode *transport_node) -{ - wocky_jingle_transport_iface_inject_candidates (self->priv->transport, - transport_node); -} - - -/* Called by a subclass when the media is ready (e.g. we got local codecs) */ -void -_wocky_jingle_content_set_media_ready (WockyJingleContent *self) -{ - WockyJingleContentPrivate *priv = self->priv; - - DEBUG ("media ready on content: %s created_by_us: %d", priv->name, - priv->created_by_us); - - priv->media_ready = TRUE; - - _maybe_ready (self); -} - -void -wocky_jingle_content_set_transport_state (WockyJingleContent *self, - WockyJingleTransportState state) -{ - WockyJingleContentPrivate *priv = self->priv; - - g_object_set (priv->transport, "state", state, NULL); - - _maybe_ready (self); -} - -GList * -wocky_jingle_content_get_remote_candidates (WockyJingleContent *c) -{ - WockyJingleContentPrivate *priv = c->priv; - - return wocky_jingle_transport_iface_get_remote_candidates (priv->transport); -} - -GList * -wocky_jingle_content_get_local_candidates (WockyJingleContent *c) -{ - WockyJingleContentPrivate *priv = c->priv; - - return wocky_jingle_transport_iface_get_local_candidates (priv->transport); -} - -gboolean -wocky_jingle_content_get_credentials (WockyJingleContent *c, - gchar **ufrag, gchar **pwd) -{ - WockyJingleContentPrivate *priv = c->priv; - - return jingle_transport_get_credentials (priv->transport, ufrag, pwd); -} - -gboolean -wocky_jingle_content_change_direction (WockyJingleContent *c, - WockyJingleContentSenders senders) -{ - WockyJingleContentPrivate *priv = c->priv; - WockyStanza *msg; - WockyNode *sess_node; - WockyJingleDialect dialect = wocky_jingle_session_get_dialect (c->session); - - if (senders == priv->senders) - return TRUE; - - priv->senders = senders; - g_object_notify (G_OBJECT (c), "senders"); - - if (WOCKY_JINGLE_DIALECT_IS_GOOGLE (dialect)) - { - DEBUG ("ignoring direction change request for GTalk stream"); - return FALSE; - } - - if (priv->state >= WOCKY_JINGLE_CONTENT_STATE_SENT) - { - msg = wocky_jingle_session_new_message (c->session, - WOCKY_JINGLE_ACTION_CONTENT_MODIFY, &sess_node); - wocky_jingle_content_produce_node (c, sess_node, FALSE, FALSE, NULL); - wocky_jingle_session_send (c->session, msg); - } - - /* FIXME: actually check whether remote end accepts our content-modify */ - return TRUE; -} - -static void -_on_remove_reply ( - GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - WockyJingleContent *c = WOCKY_JINGLE_CONTENT (user_data); - WockyJingleContentPrivate *priv = c->priv; - - g_assert (priv->state == WOCKY_JINGLE_CONTENT_STATE_REMOVING); - - DEBUG ("%p", c); - - /* Everything holding a reference to a content should drop it after receiving - * 'removed'. - */ - g_signal_emit (c, signals[REMOVED], 0); - g_object_unref (c); -} - -static void -_content_remove (WockyJingleContent *c, - gboolean signal_peer, - WockyJingleReason reason) -{ - WockyJingleContentPrivate *priv = c->priv; - WockyStanza *msg; - WockyNode *sess_node; - - DEBUG ("called for %p (%s)", c, priv->name); - - /* If we were already signalled and removal is not a side-effect of - * something else (sesssion termination, or removal by peer), - * we have to signal removal to the peer. */ - if (signal_peer && (priv->state != WOCKY_JINGLE_CONTENT_STATE_EMPTY)) - { - if (priv->state == WOCKY_JINGLE_CONTENT_STATE_REMOVING) - { - DEBUG ("ignoring request to remove content which is already being removed"); - return; - } - - priv->state = WOCKY_JINGLE_CONTENT_STATE_REMOVING; - g_object_notify ((GObject *) c, "state"); - - msg = wocky_jingle_session_new_message (c->session, - reason == WOCKY_JINGLE_REASON_UNKNOWN ? - WOCKY_JINGLE_ACTION_CONTENT_REMOVE : WOCKY_JINGLE_ACTION_CONTENT_REJECT, - &sess_node); - - if (reason != WOCKY_JINGLE_REASON_UNKNOWN) - { - WockyNode *reason_node = wocky_node_add_child_with_content (sess_node, - "reason", NULL); - wocky_node_add_child_with_content (reason_node, - wocky_jingle_session_get_reason_name (reason), NULL); - } - - wocky_jingle_content_produce_node (c, sess_node, FALSE, FALSE, NULL); - wocky_porter_send_iq_async (wocky_jingle_session_get_porter (c->session), - msg, NULL, _on_remove_reply, g_object_ref (c)); - g_object_unref (msg); - } - else - { - DEBUG ("signalling removed with %u refs", G_OBJECT (c)->ref_count); - /* Everything holding a reference to a content should drop it after receiving - * 'removed'. - */ - g_signal_emit (c, signals[REMOVED], 0); - } -} - -void -wocky_jingle_content_remove (WockyJingleContent *c, - gboolean signal_peer) -{ - _content_remove (c, signal_peer, WOCKY_JINGLE_REASON_UNKNOWN); -} - -void -wocky_jingle_content_reject (WockyJingleContent *c, - WockyJingleReason reason) -{ - _content_remove (c, TRUE, reason); -} - -gboolean -wocky_jingle_content_is_created_by_us (WockyJingleContent *c) -{ - return c->priv->created_by_us; -} - -gboolean -wocky_jingle_content_creator_is_initiator (WockyJingleContent *c) -{ - gboolean session_created_by_us; - - g_object_get (c->session, "local-initiator", &session_created_by_us, NULL); - - return (c->priv->created_by_us == session_created_by_us); -} - -const gchar * -wocky_jingle_content_get_name (WockyJingleContent *self) -{ - return self->priv->name; -} - -const gchar * -wocky_jingle_content_get_ns (WockyJingleContent *self) -{ - return self->priv->content_ns; -} - -const gchar * -wocky_jingle_content_get_transport_ns (WockyJingleContent *self) -{ - return self->priv->transport_ns; -} - -const gchar * -wocky_jingle_content_get_disposition (WockyJingleContent *self) -{ - return self->priv->disposition; -} - -WockyJingleTransportType -wocky_jingle_content_get_transport_type (WockyJingleContent *c) -{ - return wocky_jingle_transport_iface_get_transport_type (c->priv->transport); -} - -static gboolean -jingle_content_has_direction (WockyJingleContent *self, - gboolean sending) -{ - WockyJingleContentPrivate *priv = self->priv; - gboolean initiated_by_us; - - g_object_get (self->session, "local-initiator", - &initiated_by_us, NULL); - - switch (priv->senders) - { - case WOCKY_JINGLE_CONTENT_SENDERS_BOTH: - return TRUE; - case WOCKY_JINGLE_CONTENT_SENDERS_NONE: - return FALSE; - case WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR: - return sending ? initiated_by_us : !initiated_by_us; - case WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER: - return sending ? !initiated_by_us : initiated_by_us; - } - - return FALSE; -} - -gboolean -wocky_jingle_content_sending (WockyJingleContent *self) -{ - return jingle_content_has_direction (self, TRUE); -} - -gboolean -wocky_jingle_content_receiving (WockyJingleContent *self) -{ - return jingle_content_has_direction (self, FALSE); -} - -void -wocky_jingle_content_set_sending (WockyJingleContent *self, - gboolean send) -{ - WockyJingleContentPrivate *priv = self->priv; - WockyJingleContentSenders senders; - gboolean initiated_by_us; - - if (send == wocky_jingle_content_sending (self)) - return; - - g_object_get (self->session, "local-initiator", - &initiated_by_us, NULL); - - if (send) - { - if (priv->senders == WOCKY_JINGLE_CONTENT_SENDERS_NONE) - senders = (initiated_by_us ? WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR : - WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER); - else - senders = WOCKY_JINGLE_CONTENT_SENDERS_BOTH; - } - else - { - if (priv->senders == WOCKY_JINGLE_CONTENT_SENDERS_BOTH) - senders = (initiated_by_us ? WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER : - WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR); - else - senders = WOCKY_JINGLE_CONTENT_SENDERS_NONE; - } - - if (senders == WOCKY_JINGLE_CONTENT_SENDERS_NONE) - wocky_jingle_content_remove (self, TRUE); - else - wocky_jingle_content_change_direction (self, senders); -} - - -void -wocky_jingle_content_request_receiving (WockyJingleContent *self, - gboolean receive) -{ - WockyJingleContentPrivate *priv = self->priv; - WockyJingleContentSenders senders; - gboolean initiated_by_us; - - if (receive == wocky_jingle_content_receiving (self)) - return; - - g_object_get (self->session, "local-initiator", - &initiated_by_us, NULL); - - if (receive) - { - if (priv->senders == WOCKY_JINGLE_CONTENT_SENDERS_NONE) - senders = (initiated_by_us ? WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER : - WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR); - else - senders = WOCKY_JINGLE_CONTENT_SENDERS_BOTH; - } - else - { - if (priv->senders == WOCKY_JINGLE_CONTENT_SENDERS_BOTH) - senders = (initiated_by_us ? WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR : - WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER); - else - senders = WOCKY_JINGLE_CONTENT_SENDERS_NONE; - } - - - if (senders == WOCKY_JINGLE_CONTENT_SENDERS_NONE) - wocky_jingle_content_remove (self, TRUE); - else - wocky_jingle_content_change_direction (self, senders); -} diff --git a/src/jingle-content.h b/src/jingle-content.h deleted file mode 100644 index f702c1190..000000000 --- a/src/jingle-content.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * jingle-content.h - Header for WockyJingleContent - * Copyright (C) 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 - */ - -#ifndef __JINGLE_CONTENT_H__ -#define __JINGLE_CONTENT_H__ - -#include <glib-object.h> - -#include "jingle-factory.h" -#include "jingle-transport-iface.h" -#include "jingle-types.h" - -G_BEGIN_DECLS - -typedef enum { - WOCKY_JINGLE_MEDIA_TYPE_NONE = 0, - WOCKY_JINGLE_MEDIA_TYPE_AUDIO, - WOCKY_JINGLE_MEDIA_TYPE_VIDEO, -} WockyJingleMediaType; - -typedef enum { - WOCKY_JINGLE_CONTENT_STATE_EMPTY = 0, - WOCKY_JINGLE_CONTENT_STATE_NEW, - WOCKY_JINGLE_CONTENT_STATE_SENT, - WOCKY_JINGLE_CONTENT_STATE_ACKNOWLEDGED, - WOCKY_JINGLE_CONTENT_STATE_REMOVING -} WockyJingleContentState; - -struct _WockyJingleCandidate { - WockyJingleTransportProtocol protocol; - WockyJingleCandidateType type; - - gchar *id; - gchar *address; - int port; - int component; - int generation; - - int preference; - gchar *username; - gchar *password; - int network; -}; - -typedef struct _WockyJingleContentClass WockyJingleContentClass; - -GType wocky_jingle_content_get_type (void); - -/* TYPE MACROS */ -#define WOCKY_TYPE_JINGLE_CONTENT \ - (wocky_jingle_content_get_type ()) -#define WOCKY_JINGLE_CONTENT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), WOCKY_TYPE_JINGLE_CONTENT, \ - WockyJingleContent)) -#define WOCKY_JINGLE_CONTENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), WOCKY_TYPE_JINGLE_CONTENT, \ - WockyJingleContentClass)) -#define WOCKY_IS_JINGLE_CONTENT(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), WOCKY_TYPE_JINGLE_CONTENT)) -#define WOCKY_IS_JINGLE_CONTENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), WOCKY_TYPE_JINGLE_CONTENT)) -#define WOCKY_JINGLE_CONTENT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), WOCKY_TYPE_JINGLE_CONTENT, \ - WockyJingleContentClass)) - -struct _WockyJingleContentClass { - GObjectClass parent_class; - - void (*parse_description) (WockyJingleContent *, WockyNode *, - GError **); - void (*produce_description) (WockyJingleContent *, WockyNode *); - void (*transport_created) (WockyJingleContent *, - WockyJingleTransportIface *); - WockyJingleContentSenders (*get_default_senders) (WockyJingleContent *); -}; - -typedef struct _WockyJingleContentPrivate WockyJingleContentPrivate; - -struct _WockyJingleContent { - GObject parent; - WockyJingleContentPrivate *priv; - - WockyJingleSession *session; -}; - -void wocky_jingle_content_parse_add (WockyJingleContent *c, - WockyNode *content_node, gboolean google_mode, GError **error); -void wocky_jingle_content_update_senders (WockyJingleContent *c, - WockyNode *content_node, GError **error); -void wocky_jingle_content_produce_node (WockyJingleContent *c, - WockyNode *parent, - gboolean include_description, - gboolean include_transport, - WockyNode **trans_node_out); -void wocky_jingle_content_parse_accept (WockyJingleContent *c, - WockyNode *content_node, gboolean google_mode, GError **error); - -void wocky_jingle_content_parse_info (WockyJingleContent *c, - WockyNode *content_node, GError **error); -void wocky_jingle_content_parse_transport_info (WockyJingleContent *self, - WockyNode *trans_node, GError **error); -void wocky_jingle_content_parse_description_info (WockyJingleContent *self, - WockyNode *trans_node, GError **error); -guint wocky_jingle_content_create_share_channel (WockyJingleContent *self, - const gchar *name); -void wocky_jingle_content_add_candidates (WockyJingleContent *self, GList *li); -void _wocky_jingle_content_set_media_ready (WockyJingleContent *self); -gboolean wocky_jingle_content_is_ready (WockyJingleContent *self); -void wocky_jingle_content_set_transport_state (WockyJingleContent *content, - WockyJingleTransportState state); -void wocky_jingle_content_remove (WockyJingleContent *c, gboolean signal_peer); -void wocky_jingle_content_reject (WockyJingleContent *c, - WockyJingleReason reason); - -GList *wocky_jingle_content_get_remote_candidates (WockyJingleContent *c); -GList *wocky_jingle_content_get_local_candidates (WockyJingleContent *c); -gboolean wocky_jingle_content_get_credentials (WockyJingleContent *c, - gchar **ufrag, gchar **pwd); -gboolean wocky_jingle_content_change_direction (WockyJingleContent *c, - WockyJingleContentSenders senders); -void wocky_jingle_content_retransmit_candidates (WockyJingleContent *self, - gboolean all); -void wocky_jingle_content_inject_candidates (WockyJingleContent *self, - WockyNode *transport_node); -gboolean wocky_jingle_content_is_created_by_us (WockyJingleContent *c); -gboolean wocky_jingle_content_creator_is_initiator (WockyJingleContent *c); - -const gchar *wocky_jingle_content_get_name (WockyJingleContent *self); -const gchar *wocky_jingle_content_get_ns (WockyJingleContent *self); -const gchar *wocky_jingle_content_get_disposition (WockyJingleContent *self); -WockyJingleTransportType wocky_jingle_content_get_transport_type (WockyJingleContent *c); -const gchar *wocky_jingle_content_get_transport_ns (WockyJingleContent *self); - -void wocky_jingle_content_maybe_send_description (WockyJingleContent *self); - -gboolean wocky_jingle_content_sending (WockyJingleContent *self); -gboolean wocky_jingle_content_receiving (WockyJingleContent *self); - -void wocky_jingle_content_set_sending (WockyJingleContent *self, - gboolean send); -void wocky_jingle_content_request_receiving (WockyJingleContent *self, - gboolean receive); - -void wocky_jingle_content_send_complete (WockyJingleContent *self); - -#endif /* __JINGLE_CONTENT_H__ */ - diff --git a/src/jingle-factory.c b/src/jingle-factory.c deleted file mode 100644 index f3ad394f7..000000000 --- a/src/jingle-factory.c +++ /dev/null @@ -1,604 +0,0 @@ -/* - * jingle-factory.c - Support for XEP-0166 (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 "config.h" -#include "jingle-factory.h" - -#include <stdio.h> -#include <string.h> -#include <glib.h> - -#include <wocky/wocky.h> - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA - -#include "debug.h" -#include "gabble-signals-marshal.h" -#include "jingle-share.h" -#include "jingle-media-rtp.h" -#include "jingle-session.h" -#include "jingle-transport-google.h" -#include "jingle-transport-rawudp.h" -#include "jingle-transport-iceudp.h" -#include "namespaces.h" - -#include "google-relay.h" - -G_DEFINE_TYPE(WockyJingleFactory, wocky_jingle_factory, G_TYPE_OBJECT); - -/* signal enum */ -enum -{ - NEW_SESSION, - QUERY_CAP, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -/* properties */ -enum -{ - PROP_SESSION = 1, - LAST_PROPERTY -}; - -struct _WockyJingleFactoryPrivate -{ - WockySession *session; - WockyPorter *porter; - guint jingle_handler_id; - GHashTable *content_types; - GHashTable *transports; - - /* instances of SESSION_MAP_KEY_FORMAT => WockyJingleSession. */ - GHashTable *sessions; - - WockyJingleInfo *jingle_info; - - gboolean dispose_has_run; -}; - -static gboolean jingle_cb ( - WockyPorter *porter, - WockyStanza *msg, - gpointer user_data); -static WockyJingleSession *create_session (WockyJingleFactory *fac, - const gchar *sid, - const gchar *jid, - WockyJingleDialect dialect, - gboolean local_hold); - -static gboolean session_query_cap_cb ( - WockyJingleSession *session, - WockyContact *contact, - const gchar *cap_or_quirk, - gpointer user_data); -static void session_terminated_cb (WockyJingleSession *sess, - gboolean local_terminator, - WockyJingleReason reason, - const gchar *text, - WockyJingleFactory *fac); - -static void attach_to_wocky_session (WockyJingleFactory *self); - -static void -wocky_jingle_factory_init (WockyJingleFactory *obj) -{ - WockyJingleFactoryPrivate *priv = - G_TYPE_INSTANCE_GET_PRIVATE (obj, WOCKY_TYPE_JINGLE_FACTORY, - WockyJingleFactoryPrivate); - obj->priv = priv; - - priv->sessions = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); - - priv->transports = g_hash_table_new_full (g_str_hash, g_str_equal, - NULL, NULL); - - priv->content_types = g_hash_table_new_full (g_str_hash, g_str_equal, - NULL, NULL); - - priv->dispose_has_run = FALSE; -} - -static void -wocky_jingle_factory_dispose (GObject *object) -{ - WockyJingleFactory *fac = WOCKY_JINGLE_FACTORY (object); - WockyJingleFactoryPrivate *priv = fac->priv; - GHashTableIter iter; - gpointer val; - - if (priv->dispose_has_run) - return; - - DEBUG ("dispose called"); - priv->dispose_has_run = TRUE; - - wocky_jingle_factory_stop (fac); - g_clear_object (&priv->session); - g_clear_object (&priv->porter); - - g_hash_table_iter_init (&iter, priv->sessions); - while (g_hash_table_iter_next (&iter, NULL, &val)) - g_signal_handlers_disconnect_by_func (val, session_query_cap_cb, fac); - g_hash_table_unref (priv->sessions); - priv->sessions = NULL; - - g_hash_table_unref (priv->content_types); - priv->content_types = NULL; - g_hash_table_unref (priv->transports); - priv->transports = NULL; - g_clear_object (&priv->jingle_info); - - if (G_OBJECT_CLASS (wocky_jingle_factory_parent_class)->dispose) - G_OBJECT_CLASS (wocky_jingle_factory_parent_class)->dispose (object); -} - -static void -wocky_jingle_factory_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - WockyJingleFactory *chan = WOCKY_JINGLE_FACTORY (object); - WockyJingleFactoryPrivate *priv = chan->priv; - - switch (property_id) { - case PROP_SESSION: - g_value_set_object (value, priv->session); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -wocky_jingle_factory_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - WockyJingleFactory *chan = WOCKY_JINGLE_FACTORY (object); - WockyJingleFactoryPrivate *priv = chan->priv; - - switch (property_id) { - case PROP_SESSION: - priv->session = g_value_dup_object (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -wocky_jingle_factory_constructed (GObject *obj) -{ - WockyJingleFactory *self = WOCKY_JINGLE_FACTORY (obj); - GObjectClass *parent = G_OBJECT_CLASS (wocky_jingle_factory_parent_class); - - if (parent->constructed != NULL) - parent->constructed (obj); - - attach_to_wocky_session (self); - - jingle_share_register (self); - jingle_media_rtp_register (self); - jingle_transport_google_register (self); - jingle_transport_rawudp_register (self); - jingle_transport_iceudp_register (self); -} - -static void -wocky_jingle_factory_class_init (WockyJingleFactoryClass *cls) -{ - GObjectClass *object_class = G_OBJECT_CLASS (cls); - GParamSpec *param_spec; - - g_type_class_add_private (cls, sizeof (WockyJingleFactoryPrivate)); - - object_class->constructed = wocky_jingle_factory_constructed; - object_class->get_property = wocky_jingle_factory_get_property; - object_class->set_property = wocky_jingle_factory_set_property; - object_class->dispose = wocky_jingle_factory_dispose; - - param_spec = g_param_spec_object ("session", "WockySession object", - "WockySession to listen for Jingle sessions on", - WOCKY_TYPE_SESSION, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_SESSION, param_spec); - - /* signal definitions */ - - /* - * @session: a fresh new Jingle session for your listening pleasure - * @initiated_locally: %TRUE if this is a new outgoing session; %FALSE if it - * is a new incoming session - */ - signals[NEW_SESSION] = g_signal_new ("new-session", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, gabble_marshal_VOID__OBJECT_BOOL, - G_TYPE_NONE, 2, WOCKY_TYPE_JINGLE_SESSION, G_TYPE_BOOLEAN); - - /* - * @contact: the peer in a call - * @cap: the XEP-0115 feature string the session is interested in. - * - * Emitted when a Jingle session wants to check whether the peer has a - * particular capability. The handler should return %TRUE if @contact has - * @cap. - */ - signals[QUERY_CAP] = g_signal_new ("query-cap", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, g_signal_accumulator_first_wins, NULL, - gabble_marshal_BOOLEAN__OBJECT_STRING, - G_TYPE_BOOLEAN, 2, WOCKY_TYPE_CONTACT, G_TYPE_STRING); -} - -WockyJingleFactory * -wocky_jingle_factory_new ( - WockySession *session) -{ - return g_object_new (WOCKY_TYPE_JINGLE_FACTORY, - "session", session, - NULL); -} - -static void -attach_to_wocky_session (WockyJingleFactory *self) -{ - WockyJingleFactoryPrivate *priv = self->priv; - - g_assert (priv->session != NULL); - - g_assert (priv->porter == NULL); - priv->porter = g_object_ref (wocky_session_get_porter (priv->session)); - - /* TODO: we could match different dialects here maybe? */ - priv->jingle_handler_id = wocky_porter_register_handler_from_anyone ( - priv->porter, - WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET, - WOCKY_PORTER_HANDLER_PRIORITY_NORMAL, jingle_cb, self, - NULL); - - priv->jingle_info = wocky_jingle_info_new (priv->porter); -} - -void -wocky_jingle_factory_stop (WockyJingleFactory *self) -{ - WockyJingleFactoryPrivate *priv = self->priv; - - if (priv->porter != NULL && - priv->jingle_handler_id != 0) - { - wocky_porter_unregister_handler (priv->porter, priv->jingle_handler_id); - priv->jingle_handler_id = 0; - } -} - -/* The 'session' map is keyed by: - * "<peer's jid>\n<session id>" - */ -#define SESSION_MAP_KEY_FORMAT "%s\n%s" - -static gchar * -make_session_map_key ( - const gchar *jid, - const gchar *sid) -{ - return g_strdup_printf (SESSION_MAP_KEY_FORMAT, jid, sid); -} - -static gchar * -get_unique_sid_for (WockyJingleFactory *factory, - const gchar *jid, - gchar **key) -{ - guint32 val; - gchar *sid = NULL; - gchar *key_ = NULL; - - do - { - val = g_random_int_range (1000000, G_MAXINT); - - g_free (sid); - g_free (key_); - sid = g_strdup_printf ("%u", val); - key_ = make_session_map_key (jid, sid); - } - while (g_hash_table_lookup (factory->priv->sessions, key_) != NULL); - - *key = key_; - return sid; -} - -static WockyJingleSession * -ensure_session (WockyJingleFactory *self, - const gchar *sid, - const gchar *from, - WockyJingleAction action, - WockyJingleDialect dialect, - gboolean *new_session, - GError **error) -{ - WockyJingleFactoryPrivate *priv = self->priv; - gchar *key; - WockyJingleSession *sess; - - if (!wocky_decode_jid (from, NULL, NULL, NULL)) - { - g_prefix_error (error, "Couldn't parse sender '%s': ", from); - return NULL; - } - - /* If we can ensure the handle, we can decode the jid */ - key = make_session_map_key (from, sid); - sess = g_hash_table_lookup (priv->sessions, key); - g_free (key); - - if (sess == NULL) - { - if (action == WOCKY_JINGLE_ACTION_SESSION_INITIATE) - { - sess = create_session (self, sid, from, dialect, FALSE); - *new_session = TRUE; - } - else - { - g_set_error (error, WOCKY_JINGLE_ERROR, - WOCKY_JINGLE_ERROR_UNKNOWN_SESSION, - "session %s is unknown", sid); - return NULL; - } - } - else - { - *new_session = FALSE; - } - - return sess; -} - -static gboolean -jingle_cb ( - WockyPorter *porter, - WockyStanza *msg, - gpointer user_data) -{ - WockyJingleFactory *self = WOCKY_JINGLE_FACTORY (user_data); - GError *error = NULL; - const gchar *sid, *from; - WockyJingleSession *sess; - gboolean new_session = FALSE; - WockyJingleAction action; - WockyJingleDialect dialect; - - /* see if it's a jingle message and detect dialect */ - sid = wocky_jingle_session_detect (msg, &action, &dialect); - from = wocky_stanza_get_from (msg); - - if (sid == NULL || from == NULL) - return FALSE; - - sess = ensure_session (self, sid, from, action, dialect, &new_session, - &error); - - if (sess == NULL) - goto REQUEST_ERROR; - - /* now act on the message */ - if (!wocky_jingle_session_parse (sess, action, msg, &error)) - goto REQUEST_ERROR; - - /* This has to be after the call to parse(), not inside create_session(): - * until the session has parsed the session-initiate stanza, it does not know - * about its own contents, and we don't even know if the content types are - * something we understand. So it's essentially half-alive and useless to - * signal listeners. - */ - if (new_session) - g_signal_emit (self, signals[NEW_SESSION], 0, sess, FALSE); - - /* all went well, we can acknowledge the IQ */ - wocky_porter_acknowledge_iq (porter, msg, NULL); - - return TRUE; - -REQUEST_ERROR: - g_assert (error != NULL); - DEBUG ("NAKing with error: %s", error->message); - wocky_porter_send_iq_gerror (porter, msg, error); - g_error_free (error); - - if (sess != NULL && new_session) - wocky_jingle_session_terminate (sess, WOCKY_JINGLE_REASON_UNKNOWN, NULL, NULL); - - return TRUE; -} - -static gboolean -session_query_cap_cb ( - WockyJingleSession *session, - WockyContact *contact, - const gchar *cap_or_quirk, - gpointer user_data) -{ - WockyJingleFactory *self = WOCKY_JINGLE_FACTORY (user_data); - gboolean ret; - - /* Propagate the query out to the application. We can't depend on the - * application connecting to ::query-cap on the session because caps queries - * may happen while parsing the session-initiate stanza, which must happen - * before the session is announced to the application. - */ - g_signal_emit (self, signals[QUERY_CAP], 0, contact, cap_or_quirk, &ret); - return ret; -} - -/* - * If sid is set to NULL a unique sid is generated and - * the "local-initiator" property of the newly created - * WockyJingleSession is set to true. - */ -static WockyJingleSession * -create_session (WockyJingleFactory *fac, - const gchar *sid, - const gchar *jid, - WockyJingleDialect dialect, - gboolean local_hold) -{ - WockyJingleFactoryPrivate *priv = fac->priv; - WockyJingleSession *sess; - gboolean local_initiator; - gchar *sid_, *key; - gpointer contact; - WockyContactFactory *factory; - - factory = wocky_session_get_contact_factory (priv->session); - g_assert (jid != NULL); - - if (strchr (jid, '/') != NULL) - contact = wocky_contact_factory_ensure_resource_contact (factory, jid); - else - contact = wocky_contact_factory_ensure_bare_contact (factory, jid); - - g_return_val_if_fail (contact != NULL, NULL); - g_return_val_if_fail (WOCKY_IS_CONTACT (contact), NULL); - - if (sid != NULL) - { - key = make_session_map_key (jid, sid); - sid_ = g_strdup (sid); - - local_initiator = FALSE; - } - else - { - sid_ = get_unique_sid_for (fac, jid, &key); - - local_initiator = TRUE; - } - - /* Either we should have found the existing session when the IQ arrived, or - * get_unique_sid_for should have ensured the key is fresh. */ - g_assert (NULL == g_hash_table_lookup (priv->sessions, key)); - - sess = wocky_jingle_session_new ( - fac, - priv->porter, - sid_, local_initiator, contact, dialect, local_hold); - g_signal_connect (sess, "terminated", - (GCallback) session_terminated_cb, fac); - - /* Takes ownership of key */ - g_hash_table_insert (priv->sessions, key, sess); - - DEBUG ("new session (%s, %s) @ %p", jid, sid_, sess); - - g_free (sid_); - g_object_unref (contact); - - g_signal_connect (sess, "query-cap", - (GCallback) session_query_cap_cb, (GObject *) fac); - - return sess; -} - -WockyJingleSession * -wocky_jingle_factory_create_session (WockyJingleFactory *fac, - const gchar *jid, - WockyJingleDialect dialect, - gboolean local_hold) -{ - WockyJingleSession *session = create_session (fac, NULL, jid, dialect, local_hold); - - g_signal_emit (fac, signals[NEW_SESSION], 0, session, TRUE); - return session; -} - -void -wocky_jingle_factory_register_transport (WockyJingleFactory *self, - gchar *xmlns, - GType transport_type) -{ - g_return_if_fail (g_type_is_a (transport_type, - WOCKY_TYPE_JINGLE_TRANSPORT_IFACE)); - - g_hash_table_insert (self->priv->transports, xmlns, - GSIZE_TO_POINTER (transport_type)); -} - -GType -wocky_jingle_factory_lookup_transport (WockyJingleFactory *self, - const gchar *xmlns) -{ - return GPOINTER_TO_SIZE (g_hash_table_lookup (self->priv->transports, - xmlns)); -} - -void -wocky_jingle_factory_register_content_type (WockyJingleFactory *self, - gchar *xmlns, - GType content_type) -{ - g_return_if_fail (g_type_is_a (content_type, WOCKY_TYPE_JINGLE_CONTENT)); - - g_hash_table_insert (self->priv->content_types, xmlns, - GSIZE_TO_POINTER (content_type)); -} - -GType -wocky_jingle_factory_lookup_content_type (WockyJingleFactory *self, - const gchar *xmlns) -{ - return GPOINTER_TO_SIZE (g_hash_table_lookup (self->priv->content_types, - xmlns)); -} - -static void -session_terminated_cb (WockyJingleSession *session, - gboolean local_terminator G_GNUC_UNUSED, - WockyJingleReason reason G_GNUC_UNUSED, - const gchar *text G_GNUC_UNUSED, - WockyJingleFactory *factory) -{ - gchar *key = make_session_map_key ( - wocky_jingle_session_get_peer_jid (session), - wocky_jingle_session_get_sid (session)); - - DEBUG ("removing terminated session with key %s", key); - - g_signal_handlers_disconnect_by_func (session, session_query_cap_cb, factory); - g_warn_if_fail (g_hash_table_remove (factory->priv->sessions, key)); - - g_free (key); -} - -WockyJingleInfo * -wocky_jingle_factory_get_jingle_info ( - WockyJingleFactory *self) -{ - return self->priv->jingle_info; -} diff --git a/src/jingle-factory.h b/src/jingle-factory.h deleted file mode 100644 index b715d1637..000000000 --- a/src/jingle-factory.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * jingle-factory.h - Header for WockyJingleFactory - * Copyright (C) 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 - */ - -#ifndef __JINGLE_FACTORY_H__ -#define __JINGLE_FACTORY_H__ - -#include <glib-object.h> - -#include "jingle-info.h" -#include "jingle-types.h" - -G_BEGIN_DECLS - -typedef struct _WockyJingleFactoryClass WockyJingleFactoryClass; - -GType wocky_jingle_factory_get_type (void); - -/* TYPE MACROS */ -#define WOCKY_TYPE_JINGLE_FACTORY \ - (wocky_jingle_factory_get_type ()) -#define WOCKY_JINGLE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), WOCKY_TYPE_JINGLE_FACTORY, \ - WockyJingleFactory)) -#define WOCKY_JINGLE_FACTORY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), WOCKY_TYPE_JINGLE_FACTORY, \ - WockyJingleFactoryClass)) -#define WOCKY_IS_JINGLE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), WOCKY_TYPE_JINGLE_FACTORY)) -#define WOCKY_IS_JINGLE_FACTORY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), WOCKY_TYPE_JINGLE_FACTORY)) -#define WOCKY_JINGLE_FACTORY_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), WOCKY_TYPE_JINGLE_FACTORY, \ - WockyJingleFactoryClass)) - -struct _WockyJingleFactoryClass { - GObjectClass parent_class; -}; - -typedef struct _WockyJingleFactoryPrivate WockyJingleFactoryPrivate; - -struct _WockyJingleFactory { - GObject parent; - - WockyJingleFactoryPrivate *priv; -}; - -WockyJingleFactory *wocky_jingle_factory_new ( - WockySession *session); - -void wocky_jingle_factory_stop (WockyJingleFactory *self); - -void wocky_jingle_factory_register_content_type (WockyJingleFactory *self, - gchar *xmlns, GType content_type); -GType wocky_jingle_factory_lookup_content_type (WockyJingleFactory *self, - const gchar *xmlns); - -void wocky_jingle_factory_register_transport (WockyJingleFactory *self, - gchar *xmlns, GType transport_type); -GType wocky_jingle_factory_lookup_transport (WockyJingleFactory *self, - const gchar *xmlns); - -WockyJingleSession *wocky_jingle_factory_create_session ( - WockyJingleFactory *fac, - const gchar *jid, - WockyJingleDialect dialect, - gboolean local_hold); - -WockyJingleInfo *wocky_jingle_factory_get_jingle_info ( - WockyJingleFactory *fac); - -G_END_DECLS; - -#endif /* __JINGLE_FACTORY_H__ */ - diff --git a/src/jingle-info-internal.h b/src/jingle-info-internal.h deleted file mode 100644 index fa0707bc7..000000000 --- a/src/jingle-info-internal.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * jingle-info-internal.h - internal types for WockyJingleInfo - * 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 WOCKY_JINGLE_INFO_INTERNAL_H -#define WOCKY_JINGLE_INFO_INTERNAL_H - -typedef enum { - WOCKY_STUN_SERVER_USER_SPECIFIED, - WOCKY_STUN_SERVER_DISCOVERED, - WOCKY_STUN_SERVER_FALLBACK -} WockyStunServerSource; - -#endif /* WOCKY_JINGLE_INFO_INTERNAL_H */ diff --git a/src/jingle-info.c b/src/jingle-info.c deleted file mode 100644 index 8855f1257..000000000 --- a/src/jingle-info.c +++ /dev/null @@ -1,730 +0,0 @@ -/* - * jingle-info.c - exciting times with Google's jingleinfo extension - * Copyright © 2008–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 - */ - -#include "config.h" - -#include "jingle-info.h" -#include "jingle-info-internal.h" - -#include <stdlib.h> -#include <telepathy-glib/telepathy-glib.h> - -#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" - -static gboolean jingle_info_cb ( - WockyPorter *porter, - WockyStanza *stanza, - gpointer user_data); - -struct _WockyJingleInfoPrivate { - WockyPorter *porter; - guint jingle_info_handler_id; - gchar *jid_domain; - - WockyGoogleRelayResolver *google_resolver; - - WockyStunServer *stun_server; - WockyStunServer *fallback_stun_server; - - gchar *relay_token; - - /* TRUE if the user has not explicitly specified a STUN server, and hence - * we should ask the XMPP server for one; FALSE if not. - */ - gboolean get_stun_from_jingle; - - gchar *relay_server; - guint16 relay_http_port; - guint16 relay_udp; - guint16 relay_tcp; - guint16 relay_ssltcp; - -}; - -enum { - PROP_PORTER = 1, -}; - -enum { - STUN_SERVER_CHANGED = 0, - N_SIGNALS -}; - -static guint signals[N_SIGNALS]; - -static gboolean test_mode = FALSE; - -void -wocky_jingle_info_set_test_mode (void) -{ - test_mode = TRUE; -} - -static WockyStunServer * -wocky_stun_server_new ( - gchar *address, - guint16 port) -{ - WockyStunServer stun_server = { address, port }; - - return g_slice_dup (WockyStunServer, &stun_server); -} - -static void -wocky_stun_server_free (WockyStunServer *stun_server) -{ - if (stun_server != NULL) - { - g_free (stun_server->address); - g_slice_free (WockyStunServer, stun_server); - } -} - -G_DEFINE_TYPE (WockyJingleInfo, wocky_jingle_info, G_TYPE_OBJECT) - -static void -wocky_jingle_info_init (WockyJingleInfo *self) -{ - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, WOCKY_TYPE_JINGLE_INFO, - WockyJingleInfoPrivate); - - self->priv->relay_http_port = 80; - self->priv->get_stun_from_jingle = TRUE; -} - -static void -wocky_jingle_info_get_property ( - GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - WockyJingleInfo *self = WOCKY_JINGLE_INFO (object); - WockyJingleInfoPrivate *priv = self->priv; - - switch (property_id) - { - case PROP_PORTER: - g_value_set_object (value, priv->porter); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - -static void -wocky_jingle_info_set_property ( - GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - WockyJingleInfo *self = WOCKY_JINGLE_INFO (object); - WockyJingleInfoPrivate *priv = self->priv; - - switch (property_id) - { - case PROP_PORTER: - g_assert (priv->porter == NULL); - priv->porter = g_value_dup_object (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - } -} - -static void -wocky_jingle_info_constructed (GObject *object) -{ - WockyJingleInfo *self = WOCKY_JINGLE_INFO (object); - WockyJingleInfoPrivate *priv = self->priv; - GObjectClass *parent_class = wocky_jingle_info_parent_class; - - if (parent_class->constructed != NULL) - parent_class->constructed (object); - - g_assert (priv->porter != NULL); - - if (!wocky_decode_jid (wocky_porter_get_bare_jid (priv->porter), NULL, - &priv->jid_domain, NULL)) - g_assert_not_reached (); -} - -static void -wocky_jingle_info_dispose (GObject *object) -{ - WockyJingleInfo *self = WOCKY_JINGLE_INFO (object); - WockyJingleInfoPrivate *priv = self->priv; - GObjectClass *parent_class = wocky_jingle_info_parent_class; - - if (priv->porter != NULL) - { - if (priv->jingle_info_handler_id != 0) - wocky_porter_unregister_handler (priv->porter, - priv->jingle_info_handler_id); - - g_clear_object (&priv->porter); - } - - if (priv->google_resolver != NULL) - { - wocky_google_relay_resolver_destroy (priv->google_resolver); - priv->google_resolver = NULL; - } - - g_free (priv->jid_domain); - priv->jid_domain = NULL; - wocky_stun_server_free (priv->stun_server); - priv->stun_server = NULL; - wocky_stun_server_free (priv->fallback_stun_server); - priv->fallback_stun_server = NULL; - g_free (priv->relay_token); - priv->relay_token = NULL; - g_free (priv->relay_server); - priv->relay_server = NULL; - - if (parent_class->dispose != NULL) - parent_class->dispose (object); -} - -static void -wocky_jingle_info_class_init (WockyJingleInfoClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GParamSpec *param_spec; - - object_class->get_property = wocky_jingle_info_get_property; - object_class->set_property = wocky_jingle_info_set_property; - object_class->constructed = wocky_jingle_info_constructed; - object_class->dispose = wocky_jingle_info_dispose; - - g_type_class_add_private (klass, sizeof (WockyJingleInfoPrivate)); - - param_spec = g_param_spec_object ("porter", "WockyC2SPorter", - "Porter for the current connection", - WOCKY_TYPE_C2S_PORTER, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_PORTER, param_spec); - - signals[STUN_SERVER_CHANGED] = g_signal_new ("stun-server-changed", - G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, gabble_marshal_VOID__STRING_UINT, - G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_UINT); -} - -WockyJingleInfo * -wocky_jingle_info_new ( - WockyPorter *porter) -{ - return g_object_new (WOCKY_TYPE_JINGLE_INFO, - "porter", porter, - NULL); -} - -typedef struct { - WockyJingleInfo *factory; - gchar *stun_server; - guint16 stun_port; - WockyStunServerSource source; - GCancellable *cancellable; -} PendingStunServer; - -static void -pending_stun_server_free (gpointer p) -{ - PendingStunServer *data = p; - - if (data->factory != NULL) - g_object_remove_weak_pointer (G_OBJECT (data->factory), - (gpointer)&data->factory); - - g_object_unref (data->cancellable); - g_free (data->stun_server); - g_slice_free (PendingStunServer, p); -} - -static void -stun_server_resolved_cb (GObject *resolver, - GAsyncResult *result, - gpointer user_data) -{ - PendingStunServer *data = user_data; - WockyJingleInfo *self = data->factory; - WockyJingleInfoPrivate *priv = self->priv; - GError *e = NULL; - WockyStunServer *stun_server; - gchar *address; - GList *entries; - - if (self != NULL) - g_object_weak_unref (G_OBJECT (self), - (GWeakNotify)g_cancellable_cancel, data->cancellable); - - entries = g_resolver_lookup_by_name_finish ( - G_RESOLVER (resolver), result, &e); - - if (entries == NULL) - { - DEBUG ("Failed to resolve STUN server %s:%u: %s", - data->stun_server, data->stun_port, e->message); - g_error_free (e); - goto out; - } - - 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, address, data->stun_port); - - if (self == NULL) - { - g_free (address); - goto out; - } - - stun_server = wocky_stun_server_new (address, data->stun_port); - - if (data->source == WOCKY_STUN_SERVER_FALLBACK) - { - wocky_stun_server_free (priv->fallback_stun_server); - priv->fallback_stun_server = stun_server; - } - else - { - wocky_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); - } - -out: - pending_stun_server_free (data); - g_object_unref (resolver); -} - -static void -wocky_jingle_info_take_stun_server_internal ( - WockyJingleInfo *self, - gchar *stun_server, - guint16 stun_port, - WockyStunServerSource source) -{ - GResolver *resolver; - PendingStunServer *data; - - if (stun_server == NULL) - return; - - if (source == WOCKY_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", - 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->source = source; - - data->cancellable = g_cancellable_new (); - g_object_weak_ref (G_OBJECT (self), (GWeakNotify)g_cancellable_cancel, - data->cancellable); - - g_resolver_lookup_by_name_async (resolver, stun_server, - data->cancellable, stun_server_resolved_cb, data); -} - -/* - * wocky_jingle_info_take_stun_server: - * @self: a #WockyJingleInfo 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 -wocky_jingle_info_take_stun_server ( - WockyJingleInfo *self, - gchar *stun_server, - guint16 stun_port, - gboolean is_fallback) -{ - WockyStunServerSource source = is_fallback - ? WOCKY_STUN_SERVER_FALLBACK - : WOCKY_STUN_SERVER_USER_SPECIFIED; - - wocky_jingle_info_take_stun_server_internal (self, stun_server, stun_port, - source); -} - -static void -got_jingle_info_stanza ( - WockyJingleInfo *self, - WockyStanza *stanza) -{ - WockyNode *node, *query_node; - - query_node = wocky_node_get_child_ns ( - wocky_stanza_get_top_node (stanza), "query", NS_GOOGLE_JINGLE_INFO); - - if (query_node == NULL) - return; - - if (self->priv->get_stun_from_jingle) - node = wocky_node_get_child (query_node, "stun"); - else - node = NULL; - - if (node != NULL) - { - WockyNodeIter iter; - - /* 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; - guint port = 0; - - server = wocky_node_get_attribute (node, "host"); - port_attr = wocky_node_get_attribute (node, "udp"); - - if (port_attr != NULL) - port = atoi (port_attr); - - if (server != NULL && - port_attr != NULL && port > 0 && port <= G_MAXUINT16) - { - DEBUG ("jingle info: got stun server %s, port %u", server, - port); - wocky_jingle_info_take_stun_server_internal (self, - g_strdup (server), port, WOCKY_STUN_SERVER_DISCOVERED); - } - } - } - -#ifdef ENABLE_GOOGLE_RELAY - node = wocky_node_get_child (query_node, "relay"); - - if (node != NULL) - { - WockyNode *subnode = wocky_node_get_child (node, "token"); - - if (subnode != NULL) - { - const gchar *token = subnode->content; - - if (token != NULL) - { - DEBUG ("jingle info: got Google relay token %s", token); - g_free (self->priv->relay_token); - self->priv->relay_token = g_strdup (token); - } - } - - subnode = wocky_node_get_child (node, "server"); - - if (subnode != NULL) - { - const gchar *server; - const gchar *port; - - server = wocky_node_get_attribute (subnode, "host"); - - if (server != NULL) - { - DEBUG ("jingle info: got relay server %s", server); - g_free (self->priv->relay_server); - self->priv->relay_server = g_strdup (server); - } - - if (test_mode) - { - /* this is not part of the real protocol, but we can't listen on - * port 80 in an unprivileged regression test */ - port = wocky_node_get_attribute (subnode, - "gabble-test-http-port"); - - if (port != NULL) - { - DEBUG ("jingle info: diverting 'Google' HTTP requests to " - "port %s", port); - self->priv->relay_http_port = atoi (port); - } - } - - /* FIXME: these are not really actually used anywhere at - * the moment, because we get the same info when creating - * relay session. */ - port = wocky_node_get_attribute (subnode, "udp"); - - if (port != NULL) - { - DEBUG ("jingle info: got relay udp port %s", port); - self->priv->relay_udp = atoi (port); - } - - port = wocky_node_get_attribute (subnode, "tcp"); - - if (port != NULL) - { - DEBUG ("jingle info: got relay tcp port %s", port); - self->priv->relay_tcp = atoi (port); - } - - port = wocky_node_get_attribute (subnode, "tcpssl"); - - if (port != NULL) - { - DEBUG ("jingle info: got relay tcpssl port %s", port); - self->priv->relay_ssltcp = atoi (port); - } - - } - - } -#endif /* ENABLE_GOOGLE_RELAY */ -} - -static gboolean -jingle_info_cb ( - WockyPorter *porter, - WockyStanza *stanza, - gpointer user_data) -{ - WockyJingleInfo *self = WOCKY_JINGLE_INFO (user_data); - - got_jingle_info_stanza (self, stanza); - wocky_porter_acknowledge_iq (porter, stanza, NULL); - - return TRUE; -} - -static void -jingle_info_reply_cb ( - GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - WockyPorter *porter = WOCKY_PORTER (source); - WockyJingleInfo *self = WOCKY_JINGLE_INFO (user_data); - WockyStanza *reply = NULL; - GError *error = NULL; - - reply = wocky_porter_send_iq_finish (porter, result, &error); - if (reply != NULL && - !wocky_stanza_extract_errors (reply, NULL, &error, NULL, NULL)) - { - got_jingle_info_stanza (self, reply); - } - else - { - DEBUG ("jingle info request failed: %s", error->message); - g_clear_error (&error); - } - - g_clear_object (&reply); - g_object_unref (self); -} - -static void -wocky_jingle_info_send_google_request ( - WockyJingleInfo *self) -{ - WockyJingleInfoPrivate *priv = self->priv; - WockyStanza *stanza = wocky_stanza_build ( - WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_GET, NULL, - wocky_porter_get_bare_jid (priv->porter), - '(', "query", ':', NS_GOOGLE_JINGLE_INFO, ')', NULL); - - 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); -} - -static void -discover_stun_servers_cb (GObject *resolver, - GAsyncResult *result, - gpointer user_data) -{ - WockyJingleInfo *self = WOCKY_JINGLE_INFO (user_data); - WockyJingleInfoPrivate *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 - { - 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); - - DEBUG ("Found STUN server: %s:%d", hostname, port); - - wocky_jingle_info_take_stun_server (self, g_strdup (hostname), port, - FALSE); - } - - g_resolver_free_targets (targets); - } - - g_object_unref (resolver); - g_object_unref (self); -} - -static void -wocky_jingle_info_lookup_srv ( - WockyJingleInfo *self) -{ - WockyJingleInfoPrivate *priv = self->priv; - GResolver *resolver; - - 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 -wocky_jingle_info_send_request ( - WockyJingleInfo *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) - wocky_jingle_info_send_google_request (self); - else - wocky_jingle_info_lookup_srv (self); -} - -/* - * wocky_jingle_info_get_stun_servers: - * - * Grabs the currently known and resolved stun servers. - * - * Returns: (transfer container): a list of WockyJingleInfo structs - */ -GList * -wocky_jingle_info_get_stun_servers ( - WockyJingleInfo *self) -{ - WockyJingleInfoPrivate *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 * -wocky_jingle_info_get_google_relay_token ( - WockyJingleInfo *self) -{ - return self->priv->relay_token; -} - -WockyJingleRelay * -wocky_jingle_relay_new ( - WockyJingleRelayType type, - const gchar *ip, - guint port, - const gchar *username, - const gchar *password, - guint component) -{ - WockyJingleRelay ret = { type, g_strdup (ip), port, g_strdup (username), - g_strdup (password), component }; - - return g_slice_dup (WockyJingleRelay, &ret); -} - -void -wocky_jingle_relay_free (WockyJingleRelay *relay) -{ - g_free (relay->ip); - g_free (relay->username); - g_free (relay->password); - g_slice_free (WockyJingleRelay, relay); -} - -void -wocky_jingle_info_create_google_relay_session ( - WockyJingleInfo *self, - guint components, - WockyJingleInfoRelaySessionCb callback, - gpointer user_data) -{ - WockyJingleInfoPrivate *priv = self->priv; - - g_return_if_fail (callback != NULL); - - if (priv->google_resolver == NULL) - { - priv->google_resolver = wocky_google_relay_resolver_new (); - } - - wocky_google_relay_resolver_resolve (priv->google_resolver, - components, priv->relay_server, priv->relay_http_port, priv->relay_token, - callback, user_data); -} diff --git a/src/jingle-info.h b/src/jingle-info.h deleted file mode 100644 index d006da44e..000000000 --- a/src/jingle-info.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * jingle-info.h - exciting times with Google's jingleinfo extension - * Copyright © 2008–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 WOCKY_JINGLE_INFO_H -#define WOCKY_JINGLE_INFO_H - -#include <glib-object.h> -#include <wocky/wocky.h> - -typedef struct _WockyJingleInfo WockyJingleInfo; -typedef struct _WockyJingleInfoClass WockyJingleInfoClass; -typedef struct _WockyJingleInfoPrivate WockyJingleInfoPrivate; - -struct _WockyJingleInfoClass { - GObjectClass parent_class; -}; - -struct _WockyJingleInfo { - GObject parent; - - WockyJingleInfoPrivate *priv; -}; - -GType wocky_jingle_info_get_type (void); - -WockyJingleInfo *wocky_jingle_info_new ( - WockyPorter *porter); - -void wocky_jingle_info_take_stun_server ( - WockyJingleInfo *self, - gchar *stun_server, - guint16 stun_port, - gboolean is_fallback); -void wocky_jingle_info_send_request ( - WockyJingleInfo *self, - gboolean google_jingleinfo_supported); - -typedef struct { - gchar *address; - guint16 port; -} WockyStunServer; - -GList *wocky_jingle_info_get_stun_servers ( - WockyJingleInfo *self); - -const gchar *wocky_jingle_info_get_google_relay_token ( - WockyJingleInfo *self); - -typedef enum { - WOCKY_JINGLE_RELAY_TYPE_UDP, - WOCKY_JINGLE_RELAY_TYPE_TCP, - WOCKY_JINGLE_RELAY_TYPE_TLS -} WockyJingleRelayType; -#define WOCKY_N_JINGLE_RELAY_TYPES 3 - -typedef struct { - WockyJingleRelayType type; - gchar *ip; - guint port; - gchar *username; - gchar *password; - guint component; -} WockyJingleRelay; - -WockyJingleRelay *wocky_jingle_relay_new ( - WockyJingleRelayType type, - const gchar *ip, - guint port, - const gchar *username, - const gchar *password, - guint component); -void wocky_jingle_relay_free (WockyJingleRelay *relay); - -/* - * @relays: (element-type WockyJingleRelay) (transfer none): a possibly-empty - * array of WockyJingleRelay structs. - */ -typedef void (*WockyJingleInfoRelaySessionCb) ( - GPtrArray *relays, - gpointer user_data); -void wocky_jingle_info_create_google_relay_session ( - WockyJingleInfo *self, - guint components, - WockyJingleInfoRelaySessionCb callback, - gpointer user_data); - -void wocky_jingle_info_set_test_mode (void); - -/* TYPE MACROS */ -#define WOCKY_TYPE_JINGLE_INFO \ - (wocky_jingle_info_get_type ()) -#define WOCKY_JINGLE_INFO(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), WOCKY_TYPE_JINGLE_INFO, WockyJingleInfo)) -#define WOCKY_JINGLE_INFO_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), WOCKY_TYPE_JINGLE_INFO,\ - WockyJingleInfoClass)) -#define WOCKY_IS_JINGLE_INFO(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), WOCKY_TYPE_JINGLE_INFO)) -#define WOCKY_IS_JINGLE_INFO_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), WOCKY_TYPE_JINGLE_INFO)) -#define WOCKY_JINGLE_INFO_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), WOCKY_TYPE_JINGLE_INFO, \ - WockyJingleInfoClass)) - -#endif /* WOCKY_JINGLE_INFO_H */ diff --git a/src/jingle-media-rtp.c b/src/jingle-media-rtp.c deleted file mode 100644 index 7bf80c6f8..000000000 --- a/src/jingle-media-rtp.c +++ /dev/null @@ -1,1517 +0,0 @@ -/* - * jingle-media-rtp.c - Source for WockyJingleMediaRtp - * - * Copyright (C) 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 - */ - -/* Media/RTP content type deals with audio/video content, ie. jingle calls. It - * supports standard Jingle drafts (v0.15, v0.26) and Google's jingle variants - * (libjingle 0.3/0.4). */ - -#include "config.h" -#include "jingle-media-rtp.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <glib.h> - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA - -#include "connection.h" -#include "debug.h" -#include "jingle-content.h" -#include "jingle-factory.h" -#include "jingle-session.h" -#include "namespaces.h" -#include "presence-cache.h" -#include "jingle-transport-google.h" - -G_DEFINE_TYPE (WockyJingleMediaRtp, - wocky_jingle_media_rtp, WOCKY_TYPE_JINGLE_CONTENT); - -/* signal enum */ -enum -{ - REMOTE_MEDIA_DESCRIPTION, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -/* properties */ -enum -{ - PROP_MEDIA_TYPE = 1, - PROP_REMOTE_MUTE, - LAST_PROPERTY -}; - -typedef enum { - WOCKY_JINGLE_MEDIA_PROFILE_RTP_AVP, -} WockyJingleMediaProfile; - -struct _WockyJingleMediaRtpPrivate -{ - WockyJingleMediaDescription *local_media_description; - - /* Holds (WockyJingleCodec *)'s borrowed from local_media_description, - * namely codecs which have changed from local_media_description's - * previous value. Since the contents are borrowed, this must be - * freed with g_list_free, not jingle_media_rtp_free_codecs(). - */ - GList *local_codec_updates; - - WockyJingleMediaDescription *remote_media_description; - WockyJingleMediaType media_type; - gboolean remote_mute; - - gboolean has_rtcp_fb; - gboolean has_rtp_hdrext; - - gboolean dispose_has_run; -}; - -static void -wocky_jingle_media_rtp_init (WockyJingleMediaRtp *obj) -{ - WockyJingleMediaRtpPrivate *priv = - G_TYPE_INSTANCE_GET_PRIVATE (obj, WOCKY_TYPE_JINGLE_MEDIA_RTP, - WockyJingleMediaRtpPrivate); - obj->priv = priv; - priv->dispose_has_run = FALSE; -} - -WockyJingleCodec * -jingle_media_rtp_codec_new (guint id, const gchar *name, - guint clockrate, guint channels, GHashTable *params) -{ - WockyJingleCodec *p = g_slice_new0 (WockyJingleCodec); - - p->id = id; - p->name = g_strdup (name); - p->clockrate = clockrate; - p->channels = channels; - p->trr_int = G_MAXUINT; - - if (params != NULL) - { - g_hash_table_ref (params); - p->params = params; - } - else - { - p->params = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, - g_free); - } - - return p; -} - - -static GList * -wocky_jingle_feedback_message_list_copy (GList *fbs) -{ - GQueue new = G_QUEUE_INIT; - GList *li; - - for (li = fbs; li; li = li->next) - { - WockyJingleFeedbackMessage *fb = li->data; - - g_queue_push_tail (&new, wocky_jingle_feedback_message_new (fb->type, - fb->subtype)); - } - - return new.head; -} - -static void -wocky_jingle_feedback_message_list_free (GList *fbs) -{ - while (fbs != NULL) - { - wocky_jingle_feedback_message_free (fbs->data); - fbs = g_list_delete_link (fbs, fbs); - } -} - -void -jingle_media_rtp_codec_free (WockyJingleCodec *p) -{ - g_hash_table_unref (p->params); - g_free (p->name); - wocky_jingle_feedback_message_list_free (p->feedback_msgs); - g_slice_free (WockyJingleCodec, p); -} - -static void -add_codec_to_table (WockyJingleCodec *codec, - GHashTable *table) -{ - g_hash_table_insert (table, GUINT_TO_POINTER ((guint) codec->id), codec); -} - -static GHashTable * -build_codec_table (GList *codecs) -{ - GHashTable *table = g_hash_table_new (NULL, NULL); - - g_list_foreach (codecs, (GFunc) add_codec_to_table, table); - return table; -} - -GList * -jingle_media_rtp_copy_codecs (GList *codecs) -{ - GList *ret = NULL, *l; - - for (l = codecs; l != NULL; l = g_list_next (l)) - { - WockyJingleCodec *c = l->data; - WockyJingleCodec *newc = jingle_media_rtp_codec_new (c->id, - c->name, c->clockrate, c->channels, c->params); - newc->trr_int = c->trr_int; - ret = g_list_append (ret, newc); - } - - return ret; -} - -void -jingle_media_rtp_free_codecs (GList *codecs) -{ - while (codecs != NULL) - { - jingle_media_rtp_codec_free (codecs->data); - codecs = g_list_delete_link (codecs, codecs); - } -} - -static void -wocky_jingle_media_rtp_dispose (GObject *object) -{ - WockyJingleMediaRtp *trans = WOCKY_JINGLE_MEDIA_RTP (object); - WockyJingleMediaRtpPrivate *priv = trans->priv; - - if (priv->dispose_has_run) - return; - - DEBUG ("dispose called"); - priv->dispose_has_run = TRUE; - - if (priv->remote_media_description != NULL) - wocky_jingle_media_description_free (priv->remote_media_description); - priv->remote_media_description = NULL; - - if (priv->local_media_description != NULL) - wocky_jingle_media_description_free (priv->local_media_description); - priv->local_media_description = NULL; - - if (priv->local_codec_updates != NULL) - { - DEBUG ("We have an unsent codec parameter update! Weird."); - - g_list_free (priv->local_codec_updates); - priv->local_codec_updates = NULL; - } - - if (G_OBJECT_CLASS (wocky_jingle_media_rtp_parent_class)->dispose) - G_OBJECT_CLASS (wocky_jingle_media_rtp_parent_class)->dispose (object); -} - -static void -wocky_jingle_media_rtp_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - WockyJingleMediaRtp *trans = WOCKY_JINGLE_MEDIA_RTP (object); - WockyJingleMediaRtpPrivate *priv = trans->priv; - - switch (property_id) { - case PROP_MEDIA_TYPE: - g_value_set_uint (value, priv->media_type); - break; - case PROP_REMOTE_MUTE: - g_value_set_boolean (value, priv->remote_mute); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -wocky_jingle_media_rtp_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - WockyJingleMediaRtp *trans = WOCKY_JINGLE_MEDIA_RTP (object); - WockyJingleMediaRtpPrivate *priv = trans->priv; - - switch (property_id) { - case PROP_MEDIA_TYPE: - priv->media_type = g_value_get_uint (value); - break; - case PROP_REMOTE_MUTE: - priv->remote_mute = g_value_get_boolean (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void parse_description (WockyJingleContent *content, - WockyNode *desc_node, GError **error); -static void produce_description (WockyJingleContent *obj, - WockyNode *content_node); -static void transport_created (WockyJingleContent *obj, - WockyJingleTransportIface *transport); - -static void -wocky_jingle_media_rtp_class_init (WockyJingleMediaRtpClass *cls) -{ - GObjectClass *object_class = G_OBJECT_CLASS (cls); - WockyJingleContentClass *content_class = WOCKY_JINGLE_CONTENT_CLASS (cls); - GParamSpec *param_spec; - - g_type_class_add_private (cls, sizeof (WockyJingleMediaRtpPrivate)); - - object_class->get_property = wocky_jingle_media_rtp_get_property; - object_class->set_property = wocky_jingle_media_rtp_set_property; - object_class->dispose = wocky_jingle_media_rtp_dispose; - - content_class->parse_description = parse_description; - content_class->produce_description = produce_description; - content_class->transport_created = transport_created; - - param_spec = g_param_spec_uint ("media-type", "RTP media type", - "Media type.", - WOCKY_JINGLE_MEDIA_TYPE_NONE, G_MAXUINT32, WOCKY_JINGLE_MEDIA_TYPE_NONE, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_MEDIA_TYPE, param_spec); - - param_spec = g_param_spec_boolean ("remote-mute", "Remote mute", - "TRUE if the peer has muted this stream", FALSE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_REMOTE_MUTE, param_spec); - - /* signal definitions */ - - signals[REMOTE_MEDIA_DESCRIPTION] = g_signal_new ("remote-media-description", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); -} - -static void transport_created (WockyJingleContent *content, - WockyJingleTransportIface *transport) -{ - WockyJingleMediaRtp *self = WOCKY_JINGLE_MEDIA_RTP (content); - WockyJingleMediaRtpPrivate *priv = self->priv; - WockyJingleTransportGoogle *gtrans = NULL; - WockyJingleDialect dialect; - - if (WOCKY_IS_JINGLE_TRANSPORT_GOOGLE (transport)) - { - gtrans = WOCKY_JINGLE_TRANSPORT_GOOGLE (transport); - dialect = wocky_jingle_session_get_dialect (content->session); - - if (priv->media_type == WOCKY_JINGLE_MEDIA_TYPE_VIDEO && - (WOCKY_JINGLE_DIALECT_IS_GOOGLE (dialect) || - wocky_jingle_session_peer_has_cap (content->session, - QUIRK_GOOGLE_WEBMAIL_CLIENT) || - wocky_jingle_session_peer_has_cap (content->session, - QUIRK_ANDROID_GTALK_CLIENT))) - { - jingle_transport_google_set_component_name (gtrans, "video_rtp", 1); - jingle_transport_google_set_component_name (gtrans, "video_rtcp", 2); - } - else - { - jingle_transport_google_set_component_name (gtrans, "rtp", 1); - jingle_transport_google_set_component_name (gtrans, "rtcp", 2); - } - } -} - - -static WockyJingleMediaType -extract_media_type (WockyNode *desc_node, - GError **error) -{ - if (wocky_node_has_ns (desc_node, NS_JINGLE_RTP)) - { - const gchar *type = wocky_node_get_attribute (desc_node, "media"); - - if (type == NULL) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "missing required media type attribute"); - return WOCKY_JINGLE_MEDIA_TYPE_NONE; - } - - if (!wocky_strdiff (type, "audio")) - return WOCKY_JINGLE_MEDIA_TYPE_AUDIO; - - if (!wocky_strdiff (type, "video")) - return WOCKY_JINGLE_MEDIA_TYPE_VIDEO; - - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "unknown media type %s", type); - return WOCKY_JINGLE_MEDIA_TYPE_NONE; - } - - if (wocky_node_has_ns (desc_node, NS_JINGLE_DESCRIPTION_AUDIO)) - return WOCKY_JINGLE_MEDIA_TYPE_AUDIO; - - if (wocky_node_has_ns (desc_node, NS_JINGLE_DESCRIPTION_VIDEO)) - return WOCKY_JINGLE_MEDIA_TYPE_VIDEO; - - if (wocky_node_has_ns (desc_node, NS_GOOGLE_SESSION_PHONE)) - return WOCKY_JINGLE_MEDIA_TYPE_AUDIO; - - if (wocky_node_has_ns (desc_node, NS_GOOGLE_SESSION_VIDEO)) - return WOCKY_JINGLE_MEDIA_TYPE_VIDEO; - - /* If we get here, namespace in use is not one of namespaces we signed up - * with, so obviously a bug somewhere. - */ - g_assert_not_reached (); -} - -static WockyJingleFeedbackMessage * -parse_rtcp_fb (WockyJingleContent *content, WockyNode *node) -{ - const gchar *pt_ns = wocky_node_get_ns (node); - const gchar *type; - const gchar *subtype; - - if (wocky_strdiff (pt_ns, NS_JINGLE_RTCP_FB)) - return NULL; - - type = wocky_node_get_attribute (node, "type"); - if (type == NULL) - return NULL; - - subtype = wocky_node_get_attribute (node, "subtype"); - - /* This is optional, defaults to "" */ - if (subtype == NULL) - subtype = ""; - - return wocky_jingle_feedback_message_new (type, subtype); -} - - -/* - * Returns G_MAXUINT on error - */ -static guint -parse_rtcp_fb_trr_int (WockyJingleContent *content, WockyNode *node) -{ - const gchar *pt_ns = wocky_node_get_ns (node); - const gchar *txt; - guint trr_int; - gchar *endptr = NULL; - - if (wocky_strdiff (pt_ns, NS_JINGLE_RTCP_FB)) - return G_MAXUINT; - - txt = wocky_node_get_attribute (node, "value"); - if (txt == NULL) - return G_MAXUINT; - - trr_int = strtol (txt, &endptr, 10); - if (endptr == NULL || endptr == txt) - return G_MAXUINT; - - return trr_int; -} - - -/** - * parse_payload_type: - * @node: a <payload-type> node. - * - * Returns: a newly-allocated WockyJingleCodec if parsing succeeds, or %NULL - * otherwise. - */ -static WockyJingleCodec * -parse_payload_type (WockyJingleContent *content, - WockyNode *node) -{ - WockyJingleMediaRtp *self = WOCKY_JINGLE_MEDIA_RTP (content); - WockyJingleMediaRtpPrivate *priv = self->priv; - WockyJingleCodec *p; - const char *txt; - guint8 id; - const gchar *name; - guint clockrate = 0; - guint channels = 0; - WockyNode *param; - WockyNodeIter i; - - txt = wocky_node_get_attribute (node, "id"); - if (txt == NULL) - return NULL; - - id = atoi (txt); - - name = wocky_node_get_attribute (node, "name"); - if (name == NULL) - name = ""; - - /* xep-0167 v0.22, gtalk libjingle 0.3/0.4 use "clockrate" */ - txt = wocky_node_get_attribute (node, "clockrate"); - /* older jingle rtp used "rate" ? */ - if (txt == NULL) - txt = wocky_node_get_attribute (node, "rate"); - - if (txt != NULL) - clockrate = atoi (txt); - - txt = wocky_node_get_attribute (node, "channels"); - if (txt != NULL) - channels = atoi (txt); - - p = jingle_media_rtp_codec_new (id, name, clockrate, channels, NULL); - - wocky_node_iter_init (&i, node, NULL, NULL); - while (wocky_node_iter_next (&i, ¶m)) - { - if (!wocky_strdiff (param->name, "parameter")) - { - const gchar *param_name, *param_value; - - param_name = wocky_node_get_attribute (param, "name"); - param_value = wocky_node_get_attribute (param, "value"); - - if (param_name == NULL || param_value == NULL) - continue; - - g_hash_table_insert (p->params, g_strdup (param_name), - g_strdup (param_value)); - } - else if (!wocky_strdiff (param->name, "rtcp-fb")) - { - WockyJingleFeedbackMessage *fb = parse_rtcp_fb (content, param); - - if (fb != NULL) - { - p->feedback_msgs = g_list_append (p->feedback_msgs, fb); - priv->has_rtcp_fb = TRUE; - } - } - else if (!wocky_strdiff (param->name, - "rtcp-fb-trr-int")) - { - guint trr_int = parse_rtcp_fb_trr_int (content, param); - - if (trr_int != G_MAXUINT) - { - p->trr_int = trr_int; - priv->has_rtcp_fb = TRUE; - } - } - } - - DEBUG ("new remote codec: id = %u, name = %s, clockrate = %u, channels = %u", - p->id, p->name, p->clockrate, p->channels); - - return p; -} - -static WockyJingleRtpHeaderExtension * -parse_rtp_header_extension (WockyNode *node) -{ - guint id; - WockyJingleContentSenders senders; - const gchar *uri; - const char *txt; - - txt = wocky_node_get_attribute (node, "id"); - if (txt == NULL) - return NULL; - - id = atoi (txt); - - /* Only valid ranges are 1-256 and 4096-4351 */ - if ((id < 1 || id > 256) && (id < 4096 || id > 4351)) - return NULL; - - txt = wocky_node_get_attribute (node, "senders"); - - if (txt == NULL || !g_ascii_strcasecmp (txt, "both")) - senders = WOCKY_JINGLE_CONTENT_SENDERS_BOTH; - else if (!g_ascii_strcasecmp (txt, "initiator")) - senders = WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR; - else if (!g_ascii_strcasecmp (txt, "responder")) - senders = WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER; - else - return NULL; - - uri = wocky_node_get_attribute (node, "uri"); - - if (uri == NULL) - return NULL; - - return wocky_jingle_rtp_header_extension_new (id, senders, uri); -} - - -/** - * codec_update_coherent: - * @old_c: Gabble's old cache of the codec, or %NULL if it hasn't heard of it. - * @new_c: the proposed update, whose id must equal that of @old_c if the - * latter is non-NULL. - * @domain: the error domain to set @e to if necessary - * @code: the error code to set @e to if necessary - * @e: location to hold an error - * - * Compares @old_c and @new_c, which are assumed to have the same id, to check - * that the name, clockrate and number of channels hasn't changed. If they - * have, returns %FALSE and sets @e. - */ -static gboolean -codec_update_coherent (const WockyJingleCodec *old_c, - const WockyJingleCodec *new_c, - GError **e) -{ - const GQuark domain = WOCKY_XMPP_ERROR; - const gint code = WOCKY_XMPP_ERROR_BAD_REQUEST; - - if (old_c == NULL) - { - g_set_error (e, domain, code, "Codec with id %u ('%s') unknown", - new_c->id, new_c->name); - return FALSE; - } - - if (g_ascii_strcasecmp (new_c->name, old_c->name)) - { - g_set_error (e, domain, code, - "tried to change codec %u's name from %s to %s", - new_c->id, old_c->name, new_c->name); - return FALSE; - } - - if (new_c->clockrate != old_c->clockrate) - { - g_set_error (e, domain, code, - "tried to change codec %u (%s)'s clockrate from %u to %u", - new_c->id, new_c->name, old_c->clockrate, new_c->clockrate); - return FALSE; - } - - if (old_c->channels != 0 && - new_c->channels != old_c->channels) - { - g_set_error (e, domain, code, - "tried to change codec %u (%s)'s channels from %u to %u", - new_c->id, new_c->name, new_c->channels, old_c->channels); - return FALSE; - } - - return TRUE; -} - -static void -update_remote_media_description (WockyJingleMediaRtp *self, - WockyJingleMediaDescription *new_media_description, - GError **error) -{ - WockyJingleMediaRtpPrivate *priv = self->priv; - GHashTable *rc = NULL; - WockyJingleCodec *old_c, *new_c; - GList *l; - GError *e = NULL; - - if (priv->remote_media_description == NULL) - { - priv->remote_media_description = new_media_description; - new_media_description = NULL; - goto out; - } - - rc = build_codec_table (priv->remote_media_description->codecs); - - /* We already know some remote codecs, so this is just the other end updating - * some parameters. - */ - for (l = new_media_description->codecs; l != NULL; l = l->next) - { - new_c = l->data; - old_c = g_hash_table_lookup (rc, GUINT_TO_POINTER ((guint) new_c->id)); - - if (!codec_update_coherent (old_c, new_c, &e)) - goto out; - } - - /* Okay, all the updates are cool. Let's switch the parameters around. */ - for (l = new_media_description->codecs; l != NULL; l = l->next) - { - GHashTable *params; - - new_c = l->data; - old_c = g_hash_table_lookup (rc, GUINT_TO_POINTER ((guint) new_c->id)); - - params = old_c->params; - old_c->params = new_c->params; - new_c->params = params; - } - -out: - if (new_media_description != NULL) - wocky_jingle_media_description_free (new_media_description); - - if (rc != NULL) - g_hash_table_unref (rc); - - if (e != NULL) - { - DEBUG ("Rejecting codec update: %s", e->message); - g_propagate_error (error, e); - } - else - { - DEBUG ("Emitting remote-media-description signal"); - g_signal_emit (self, signals[REMOTE_MEDIA_DESCRIPTION], 0, - priv->remote_media_description); - } -} - -static void -parse_description (WockyJingleContent *content, - WockyNode *desc_node, GError **error) -{ - WockyJingleMediaRtp *self = WOCKY_JINGLE_MEDIA_RTP (content); - WockyJingleMediaRtpPrivate *priv = self->priv; - WockyJingleMediaType mtype; - WockyJingleMediaDescription *md; - WockyJingleCodec *p; - WockyJingleDialect dialect = wocky_jingle_session_get_dialect (content->session); - gboolean video_session = FALSE; - WockyNodeIter i; - WockyNode *node; - gboolean description_error = FALSE; - gboolean is_avpf = FALSE; - - DEBUG ("node: %s", desc_node->name); - - if (priv->media_type == WOCKY_JINGLE_MEDIA_TYPE_NONE) - mtype = extract_media_type (desc_node, error); - else - mtype = priv->media_type; - - if (mtype == WOCKY_JINGLE_MEDIA_TYPE_NONE) - return; - - DEBUG ("detected media type %u", mtype); - - if (dialect == WOCKY_JINGLE_DIALECT_GTALK3) - { - const gchar *desc_ns = - wocky_node_get_ns (desc_node); - video_session = !wocky_strdiff (desc_ns, NS_GOOGLE_SESSION_VIDEO); - } - - md = wocky_jingle_media_description_new (); - - wocky_node_iter_init (&i, desc_node, NULL, NULL); - while (wocky_node_iter_next (&i, &node) && !description_error) - { - if (!wocky_strdiff (node->name, "payload-type")) - { - if (dialect == WOCKY_JINGLE_DIALECT_GTALK3) - { - const gchar *pt_ns = wocky_node_get_ns (node); - - if (priv->media_type == WOCKY_JINGLE_MEDIA_TYPE_AUDIO) - { - if (video_session && - wocky_strdiff (pt_ns, NS_GOOGLE_SESSION_PHONE)) - continue; - } - else if (priv->media_type == WOCKY_JINGLE_MEDIA_TYPE_VIDEO) - { - if (!(video_session && pt_ns == NULL) - && wocky_strdiff (pt_ns, NS_GOOGLE_SESSION_VIDEO)) - continue; - } - } - - p = parse_payload_type (content, node); - - if (p == NULL) - { - description_error = TRUE; - } - else - { - md->codecs = g_list_append (md->codecs, p); - if (p->trr_int != G_MAXUINT || p->feedback_msgs) - is_avpf = TRUE; - } - } - else if (!wocky_strdiff (node->name, "rtp-hdrext")) - { - const gchar *pt_ns = wocky_node_get_ns (node); - WockyJingleRtpHeaderExtension *hdrext; - - if (wocky_strdiff (pt_ns, NS_JINGLE_RTP_HDREXT)) - continue; - - hdrext = parse_rtp_header_extension (node); - - if (hdrext == NULL) - { - description_error = TRUE; - } - else - { - md->hdrexts = g_list_append (md->hdrexts, hdrext); - priv->has_rtp_hdrext = TRUE; - } - - } - else if (!wocky_strdiff (node->name, "rtcp-fb")) - { - WockyJingleFeedbackMessage *fb = parse_rtcp_fb (content, node); - - if (fb == NULL) - { - description_error = TRUE; - } - else - { - md->feedback_msgs = g_list_append (md->feedback_msgs, fb); - is_avpf = TRUE; - priv->has_rtcp_fb = TRUE; - } - } - else if (!wocky_strdiff (node->name, "rtcp-fb-trr-int")) - { - guint trr_int = parse_rtcp_fb_trr_int (content, node); - - if (trr_int == G_MAXUINT) - { - description_error = TRUE; - } - else - { - md->trr_int = trr_int; - is_avpf = TRUE; - priv->has_rtcp_fb = TRUE; - } - } - } - - if (description_error) - { - /* rollback these */ - wocky_jingle_media_description_free (md); - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "invalid description"); - return; - } - - /* If the profile is AVPF, the trr-int default to 0 */ - if (is_avpf && md->trr_int == G_MAXUINT) - md->trr_int = 0; - - priv->media_type = mtype; - - update_remote_media_description (self, md, error); -} - -/* The Google Talk desktop client is picky about the case of codec names, even - * though SDP defines them to be case-insensitive. The particular case that was - * causing problems was ILBC vs iLBC, but it seems safer to special-case the - * lot. This list is taken from the initiate sent by the desktop client on - * 2009-07-01. - */ -static const gchar * const codec_cases[] = { - "CN", - "EG711A", - "EG711U", - "G723", - "IPCMWB", - "ISAC", - "PCMA", - "PCMU", - "iLBC", - "speex", - "telephone-event", - NULL -}; - -static const gchar * -gtalk_case (const gchar *codec) -{ - const gchar * const *ret = codec_cases; - - for (; *ret != NULL; ret++) - if (g_ascii_strcasecmp (*ret, codec) == 0) - return *ret; - - return codec; -} - -static void -_produce_extra_param (gpointer key, gpointer value, gpointer user_data) -{ - WockyNode *pt_node = user_data; - WockyNode *param; - gchar *param_name = key; - gchar *param_value = value; - - param = wocky_node_add_child (pt_node, "parameter"); - wocky_node_set_attribute (param, "name", param_name); - wocky_node_set_attribute (param, "value", param_value); -} - -static void -produce_rtcp_fb_trr_int (WockyNode *node, - guint trr_int) -{ - WockyNode *trr_int_node; - gchar tmp[10]; - - if (trr_int == G_MAXUINT || trr_int == 0) - return; - - trr_int_node = wocky_node_add_child_ns (node, "rtcp-fb-trr-int", - NS_JINGLE_RTCP_FB); - snprintf (tmp, 9, "%d", trr_int); - wocky_node_set_attribute (trr_int_node, "value", tmp); -} - - -static void -produce_rtcp_fb (WockyJingleFeedbackMessage *fb, WockyNode *node) -{ - WockyNode *fb_node; - - fb_node = wocky_node_add_child (node, "rtcp-fb"); - - wocky_node_set_attribute (fb_node, "xmlns", NS_JINGLE_RTCP_FB); - wocky_node_set_attribute (fb_node, "type", fb->type); - - if (fb->subtype != NULL && fb->subtype[0] != 0) - wocky_node_set_attribute (fb_node, "subtype", fb->subtype); -} - -static void -produce_payload_type (WockyJingleContent *content, - WockyNode *desc_node, - WockyJingleMediaType type, - WockyJingleCodec *p, - WockyJingleDialect dialect) -{ - WockyJingleMediaRtp *self = WOCKY_JINGLE_MEDIA_RTP (content); - WockyJingleMediaRtpPrivate *priv = self->priv; - WockyNode *pt_node; - gchar buf[16]; - - pt_node = wocky_node_add_child (desc_node, "payload-type"); - - /* id: required */ - sprintf (buf, "%d", p->id); - wocky_node_set_attribute (pt_node, "id", buf); - - if (dialect == WOCKY_JINGLE_DIALECT_GTALK3) - { - if (type == WOCKY_JINGLE_MEDIA_TYPE_AUDIO) - { - /* Gtalk 03 has either an audio or a video session, in case of a - * video session the audio codecs need to set their namespace to - * NS_GOOGLE_SESSION_PHONE. In the case of an audio session it - * doesn't matter, so just always set the namespace on audio - * payloads. - */ - pt_node->ns = g_quark_from_static_string ( - NS_GOOGLE_SESSION_PHONE); - } - else - { - /* If width, height and framerate aren't set the google server ignore - * our initiate.. These are a recv parameters, to it doesn't matter - * for what we're sending, just for what we're getting.. 320x240 - * seems a sane enough default */ - wocky_node_set_attributes (pt_node, - "width", "320", - "height", "240", - "framerate", "30", - NULL); - } - - } - - /* name: optional */ - if (*p->name != '\0') - { - if (WOCKY_JINGLE_DIALECT_IS_GOOGLE (dialect)) - wocky_node_set_attribute (pt_node, "name", gtalk_case (p->name)); - else - wocky_node_set_attribute (pt_node, "name", p->name); - } - - /* clock rate: optional */ - if (p->clockrate != 0) - { - const gchar *attname = "clockrate"; - - if (dialect == WOCKY_JINGLE_DIALECT_V015) - attname = "rate"; - - sprintf (buf, "%u", p->clockrate); - wocky_node_set_attribute (pt_node, attname, buf); - } - - if (p->channels != 0) - { - sprintf (buf, "%u", p->channels); - wocky_node_set_attribute (pt_node, "channels", buf); - } - - if (p->params != NULL) - g_hash_table_foreach (p->params, _produce_extra_param, pt_node); - - - if (priv->has_rtcp_fb) - { - g_list_foreach (p->feedback_msgs, (GFunc) produce_rtcp_fb, pt_node); - produce_rtcp_fb_trr_int (pt_node, p->trr_int); - } -} - -static WockyNode * -produce_description_node (WockyJingleDialect dialect, WockyJingleMediaType media_type, - WockyNode *content_node) -{ - WockyNode *desc_node; - const gchar *xmlns = NULL, *media_attr = NULL; - - if (dialect == WOCKY_JINGLE_DIALECT_GTALK3) - return NULL; - - switch (dialect) - { - case WOCKY_JINGLE_DIALECT_GTALK4: - g_assert (media_type == WOCKY_JINGLE_MEDIA_TYPE_AUDIO); - xmlns = NS_GOOGLE_SESSION_PHONE; - break; - case WOCKY_JINGLE_DIALECT_V015: - if (media_type == WOCKY_JINGLE_MEDIA_TYPE_AUDIO) - xmlns = NS_JINGLE_DESCRIPTION_AUDIO; - else if (media_type == WOCKY_JINGLE_MEDIA_TYPE_VIDEO) - xmlns = NS_JINGLE_DESCRIPTION_VIDEO; - else - { - DEBUG ("unknown media type %u", media_type); - xmlns = ""; - } - break; - default: - xmlns = NS_JINGLE_RTP; - if (media_type == WOCKY_JINGLE_MEDIA_TYPE_AUDIO) - media_attr = "audio"; - else if (media_type == WOCKY_JINGLE_MEDIA_TYPE_VIDEO) - media_attr = "video"; - else - g_assert_not_reached (); - break; - } - - desc_node = wocky_node_add_child_ns (content_node, "description", xmlns); - - if (media_attr != NULL) - wocky_node_set_attribute (desc_node, "media", media_attr); - - return desc_node; -} - -static void -produce_hdrext (gpointer data, gpointer user_data) -{ - WockyJingleRtpHeaderExtension *hdrext = data; - WockyNode *desc_node = user_data; - WockyNode *hdrext_node; - gchar buf[16]; - - hdrext_node = wocky_node_add_child (desc_node, "rtp-hdrext"); - - /* id: required */ - sprintf (buf, "%d", hdrext->id); - wocky_node_set_attribute (hdrext_node, "id", buf); - wocky_node_set_attribute (hdrext_node, "uri", hdrext->uri); - - if (hdrext->senders == WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR) - wocky_node_set_attribute (hdrext_node, "senders", "initiator"); - else if (hdrext->senders == WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER) - wocky_node_set_attribute (hdrext_node, "senders", "responder"); - - wocky_node_set_attribute (hdrext_node, "xmlns", NS_JINGLE_RTP_HDREXT); -} - -static void -produce_description (WockyJingleContent *content, WockyNode *content_node) -{ - WockyJingleMediaRtp *self = WOCKY_JINGLE_MEDIA_RTP (content); - WockyJingleMediaRtpPrivate *priv = self->priv; - GList *li; - WockyJingleDialect dialect = wocky_jingle_session_get_dialect (content->session); - WockyNode *desc_node; - - if (wocky_jingle_session_peer_has_cap (content->session, NS_JINGLE_RTCP_FB)) - priv->has_rtcp_fb = TRUE; - - if (wocky_jingle_session_peer_has_cap (content->session, NS_JINGLE_RTP_HDREXT)) - priv->has_rtp_hdrext = TRUE; - - desc_node = produce_description_node (dialect, priv->media_type, - content_node); - - /* For GTalk3 the description is added by the session */ - if (desc_node == NULL) - desc_node = content_node; - - /* If we're only updating our codec parameters, only generate payload-types - * for those. - */ - if (priv->local_codec_updates != NULL) - li = priv->local_codec_updates; - else - li = priv->local_media_description->codecs; - - for (; li != NULL; li = li->next) - produce_payload_type (content, desc_node, priv->media_type, li->data, - dialect); - - if (priv->has_rtp_hdrext && priv->local_media_description->hdrexts) - g_list_foreach (priv->local_media_description->hdrexts, produce_hdrext, - desc_node); - - if (priv->has_rtcp_fb) - { - g_list_foreach (priv->local_media_description->feedback_msgs, - (GFunc) produce_rtcp_fb, desc_node); - produce_rtcp_fb_trr_int (desc_node, - priv->local_media_description->trr_int); - } -} - -/** - * string_string_maps_equal: - * - * Returns: TRUE iff @a and @b contain exactly the same keys and values when - * compared as strings. - */ -static gboolean -string_string_maps_equal (GHashTable *a, - GHashTable *b) -{ - GHashTableIter iter; - gpointer a_key, a_value, b_value; - - if (g_hash_table_size (a) != g_hash_table_size (b)) - return FALSE; - - g_hash_table_iter_init (&iter, a); - - while (g_hash_table_iter_next (&iter, &a_key, &a_value)) - { - if (!g_hash_table_lookup_extended (b, a_key, NULL, &b_value)) - return FALSE; - - if (wocky_strdiff (a_value, b_value)) - return FALSE; - } - - return TRUE; -} - -/** - * compare_codecs: - * @old: previous local codecs - * @new: new local codecs supplied by streaming implementation - * @changed: location at which to store the changed codecs - * @error: location at which to store an error if the update was invalid - * - * Returns: %TRUE if the update made sense, %FALSE with @error set otherwise - */ -gboolean -jingle_media_rtp_compare_codecs (GList *old, - GList *new, - GList **changed, - GError **e) -{ - gboolean ret = FALSE; - GHashTable *old_table = build_codec_table (old); - GList *l; - WockyJingleCodec *old_c, *new_c; - - g_assert (changed != NULL && *changed == NULL); - - for (l = new; l != NULL; l = l->next) - { - new_c = l->data; - old_c = g_hash_table_lookup (old_table, GUINT_TO_POINTER ( - (guint) new_c->id)); - - if (!codec_update_coherent (old_c, new_c, e)) - goto out; - - if (!string_string_maps_equal (old_c->params, new_c->params)) - *changed = g_list_prepend (*changed, new_c); - } - - ret = TRUE; - -out: - if (!ret) - { - g_list_free (*changed); - *changed = NULL; - } - - g_hash_table_unref (old_table); - return ret; -} - -/* - * @self: a content in an RTP session - * @md: (transfer full): new media description for this content - * @ready: whether the codecs can regarded as ready to sent from now on - * @error: used to return a %WOCKY_XMPP_ERROR if the codec update is illegal. - * - * Sets or updates the media description (codecs, feedback messages, etc) for - * @self. - * - * Returns: %TRUE if no description was previously set, or if the update is - * compatible with the existing description; %FALSE if the update is illegal - * (due to adding previously-unknown codecs or renaming an existing codec, for - * example) - */ -gboolean -jingle_media_rtp_set_local_media_description (WockyJingleMediaRtp *self, - WockyJingleMediaDescription *md, - gboolean ready, - GError **error) -{ - WockyJingleMediaRtpPrivate *priv = self->priv; - - DEBUG ("setting new local media description"); - - if (priv->local_media_description != NULL) - { - GList *changed = NULL; - GError *err = NULL; - - g_assert (priv->local_codec_updates == NULL); - - if (!jingle_media_rtp_compare_codecs ( - priv->local_media_description->codecs, - md->codecs, &changed, &err)) - { - DEBUG ("codec update was illegal: %s", err->message); - wocky_jingle_media_description_free (md); - g_propagate_error (error, err); - return FALSE; - } - - if (changed == NULL) - { - DEBUG ("codec update changed nothing!"); - wocky_jingle_media_description_free (md); - goto out; - } - - DEBUG ("%u codecs changed", g_list_length (changed)); - priv->local_codec_updates = changed; - - wocky_jingle_media_description_free (priv->local_media_description); - } - - priv->local_media_description = md; - - /* Codecs have changed, sending a fresh description might be necessary */ - wocky_jingle_content_maybe_send_description (WOCKY_JINGLE_CONTENT (self)); - - /* Update done if any, free the changed codecs if any */ - g_list_free (priv->local_codec_updates); - priv->local_codec_updates = NULL; - -out: - if (ready) - _wocky_jingle_content_set_media_ready (WOCKY_JINGLE_CONTENT (self)); - - return TRUE; -} - -void -jingle_media_rtp_register (WockyJingleFactory *factory) -{ - /* Current (v0.25) Jingle draft URI */ - wocky_jingle_factory_register_content_type (factory, - NS_JINGLE_RTP, WOCKY_TYPE_JINGLE_MEDIA_RTP); - - /* Old Jingle audio/video namespaces */ - wocky_jingle_factory_register_content_type (factory, - NS_JINGLE_DESCRIPTION_AUDIO, - WOCKY_TYPE_JINGLE_MEDIA_RTP); - - wocky_jingle_factory_register_content_type (factory, - NS_JINGLE_DESCRIPTION_VIDEO, - WOCKY_TYPE_JINGLE_MEDIA_RTP); - - /* GTalk audio call namespace */ - wocky_jingle_factory_register_content_type (factory, - NS_GOOGLE_SESSION_PHONE, - WOCKY_TYPE_JINGLE_MEDIA_RTP); - - /* GTalk video call namespace */ - wocky_jingle_factory_register_content_type (factory, - NS_GOOGLE_SESSION_VIDEO, - WOCKY_TYPE_JINGLE_MEDIA_RTP); -} - -/* We can't get remote media description when they're signalled, because - * the signal is emitted immediately upon JingleContent creation, - * and parsing, which is before a corresponding MediaStream is - * created. */ -WockyJingleMediaDescription * -wocky_jingle_media_rtp_get_remote_media_description ( - WockyJingleMediaRtp *self) -{ - WockyJingleMediaRtpPrivate *priv = self->priv; - - return priv->remote_media_description; -} - -WockyJingleMediaDescription * -wocky_jingle_media_description_new (void) -{ - WockyJingleMediaDescription *md = g_slice_new0 (WockyJingleMediaDescription); - - md->trr_int = G_MAXUINT; - - return md; -} - -void -wocky_jingle_media_description_free (WockyJingleMediaDescription *md) -{ - jingle_media_rtp_free_codecs (md->codecs); - - while (md->hdrexts != NULL) - { - wocky_jingle_rtp_header_extension_free (md->hdrexts->data); - md->hdrexts = g_list_delete_link (md->hdrexts, md->hdrexts); - } - - g_slice_free (WockyJingleMediaDescription, md); -} - -WockyJingleMediaDescription * -wocky_jingle_media_description_copy (WockyJingleMediaDescription *md) -{ - WockyJingleMediaDescription *newmd = g_slice_new0 (WockyJingleMediaDescription); - GList *li; - - newmd->codecs = jingle_media_rtp_copy_codecs (md->codecs); - newmd->feedback_msgs = wocky_jingle_feedback_message_list_copy (md->feedback_msgs); - newmd->trr_int = md->trr_int; - - for (li = md->hdrexts; li; li = li->next) - { - WockyJingleRtpHeaderExtension *h = li->data; - - newmd->hdrexts = g_list_append (newmd->hdrexts, - wocky_jingle_rtp_header_extension_new (h->id, h->senders, h->uri)); - } - - return newmd; -} - -WockyJingleRtpHeaderExtension * -wocky_jingle_rtp_header_extension_new (guint id, WockyJingleContentSenders senders, - const gchar *uri) -{ - WockyJingleRtpHeaderExtension *hdrext = g_slice_new (WockyJingleRtpHeaderExtension); - - hdrext->id = id; - hdrext->senders = senders; - hdrext->uri = g_strdup (uri); - - return hdrext; -} - -void -wocky_jingle_rtp_header_extension_free (WockyJingleRtpHeaderExtension *hdrext) -{ - g_free (hdrext->uri); - g_slice_free (WockyJingleRtpHeaderExtension, hdrext); -} - -WockyJingleFeedbackMessage * -wocky_jingle_feedback_message_new (const gchar *type, const gchar *subtype) -{ - WockyJingleFeedbackMessage *fb = g_slice_new0 (WockyJingleFeedbackMessage); - - fb->type = g_strdup (type); - fb->subtype = g_strdup (subtype); - - return fb; -} - -void -wocky_jingle_feedback_message_free (WockyJingleFeedbackMessage *fb) -{ - g_free (fb->type); - g_free (fb->subtype); - g_slice_free (WockyJingleFeedbackMessage, fb); -} - - -static gint -wocky_jingle_feedback_message_compare (const WockyJingleFeedbackMessage *fb1, - const WockyJingleFeedbackMessage *fb2) -{ - if (!g_ascii_strcasecmp (fb1->type, fb2->type) && - !g_ascii_strcasecmp (fb1->subtype, fb2->subtype)) - return 0; - else - return 1; -} - -/** - * wocky_jingle_media_description_simplify: - * - * Removes duplicated Feedback message and put them in the global structure - * - * This function will iterate over every codec in a description and look for - * feedback messages that are exactly the same in every codec and will instead - * put the in the list in the description and remove them from the childs. - * This limits the amount of duplication in the resulting XML. - */ - -void -wocky_jingle_media_description_simplify (WockyJingleMediaDescription *md) -{ - GList *item; - guint trr_int = 0; - gboolean trr_int_all_same = TRUE; - gboolean init = FALSE; - GList *identical_fbs = NULL; - - for (item = md->codecs; item; item = item->next) - { - WockyJingleCodec *c = item->data; - - if (!init) - { - /* For the first codec, it stores the trr_int and the list - * of feedback messages */ - trr_int = c->trr_int; - identical_fbs = g_list_copy (c->feedback_msgs); - init = TRUE; - } - else - { - GList *item2; - - /* For every subsequent codec, we check if the trr_int is the same */ - - if (trr_int != c->trr_int) - trr_int_all_same = FALSE; - - /* We also intersect the remembered list of feedback messages with - * the list for that codec and remove any feedback message that isn't - * in both - */ - - for (item2 = identical_fbs; item2;) - { - WockyJingleFeedbackMessage *fb = identical_fbs->data; - GList *next = item2->next; - - if (!g_list_find_custom (c->feedback_msgs, fb, - (GCompareFunc) wocky_jingle_feedback_message_compare)) - identical_fbs = g_list_delete_link (identical_fbs, item2); - - item2 = next; - } - - /* If the trr_int is not the same everywhere and there are not common - * feedback messages, then stop - */ - if (!trr_int_all_same && identical_fbs == NULL) - break; - } - } - - if (trr_int_all_same && trr_int == G_MAXUINT) - trr_int_all_same = FALSE; - - /* if the trr_int is the same everywhere, lets set it globally */ - if (trr_int_all_same) - md->trr_int = trr_int; - - /* If there are feedback messages that are in every codec, put a copy of them - * in the global structure - */ - if (identical_fbs) - { - md->feedback_msgs = wocky_jingle_feedback_message_list_copy (identical_fbs); - g_list_free (identical_fbs); - } - - if (trr_int_all_same || md->feedback_msgs != NULL) - for (item = md->codecs; item; item = item->next) - { - WockyJingleCodec *c = item->data; - GList *item2; - - /* If the trr_int is the same everywhere, lets put the default on - * each codec, we have it in the main structure - */ - if (trr_int_all_same) - c->trr_int = G_MAXUINT; - - /* Find the feedback messages that were put in the main structure and - * remove them from each codec - */ - for (item2 = md->feedback_msgs; item2; item2 = item2->next) - { - GList *duplicated; - WockyJingleFeedbackMessage *fb = item2->data; - - while ((duplicated = g_list_find_custom (c->feedback_msgs, fb, - (GCompareFunc) wocky_jingle_feedback_message_compare)) != NULL) - { - wocky_jingle_feedback_message_free (duplicated->data); - c->feedback_msgs = g_list_delete_link (c->feedback_msgs, - duplicated); - } - } - } -} diff --git a/src/jingle-media-rtp.h b/src/jingle-media-rtp.h deleted file mode 100644 index 4854b790f..000000000 --- a/src/jingle-media-rtp.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * jingle-media-rtp.h - Header for WockyJingleMediaRtp - * Copyright (C) 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 - */ - -#ifndef __JINGLE_MEDIA_RTP_H__ -#define __JINGLE_MEDIA_RTP_H__ - -#include <glib-object.h> - -#include "jingle-content.h" -#include "jingle-types.h" - -G_BEGIN_DECLS - -typedef struct _WockyJingleMediaRtpClass WockyJingleMediaRtpClass; - -GType wocky_jingle_media_rtp_get_type (void); - -/* TYPE MACROS */ -#define WOCKY_TYPE_JINGLE_MEDIA_RTP \ - (wocky_jingle_media_rtp_get_type ()) -#define WOCKY_JINGLE_MEDIA_RTP(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), WOCKY_TYPE_JINGLE_MEDIA_RTP, \ - WockyJingleMediaRtp)) -#define WOCKY_JINGLE_MEDIA_RTP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), WOCKY_TYPE_JINGLE_MEDIA_RTP, \ - WockyJingleMediaRtpClass)) -#define WOCKY_IS_JINGLE_MEDIA_RTP(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), WOCKY_TYPE_JINGLE_MEDIA_RTP)) -#define WOCKY_IS_JINGLE_MEDIA_RTP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), WOCKY_TYPE_JINGLE_MEDIA_RTP)) -#define WOCKY_JINGLE_MEDIA_RTP_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), WOCKY_TYPE_JINGLE_MEDIA_RTP, \ - WockyJingleMediaRtpClass)) - -struct _WockyJingleMediaRtpClass { - WockyJingleContentClass parent_class; -}; - -typedef struct _WockyJingleMediaRtpPrivate WockyJingleMediaRtpPrivate; - -struct _WockyJingleMediaRtp { - WockyJingleContent parent; - WockyJingleMediaRtpPrivate *priv; -}; - -typedef struct { - guint id; - gchar *name; - guint clockrate; - guint channels; - GHashTable *params; - guint trr_int; - GList *feedback_msgs; -} WockyJingleCodec; - -typedef struct { - gchar *type; - gchar *subtype; -} WockyJingleFeedbackMessage; - -typedef struct { - guint id; - WockyJingleContentSenders senders; - gchar *uri; -} WockyJingleRtpHeaderExtension; - -typedef struct { - GList *codecs; - GList *hdrexts; - guint trr_int; - GList *feedback_msgs; -} WockyJingleMediaDescription; - -void jingle_media_rtp_register (WockyJingleFactory *factory); -gboolean jingle_media_rtp_set_local_media_description ( - WockyJingleMediaRtp *self, WockyJingleMediaDescription *md, gboolean ready, - GError **error); -WockyJingleMediaDescription *wocky_jingle_media_rtp_get_remote_media_description ( - WockyJingleMediaRtp *self); - -WockyJingleCodec * jingle_media_rtp_codec_new (guint id, const gchar *name, - guint clockrate, guint channels, GHashTable *params); -void jingle_media_rtp_codec_free (WockyJingleCodec *p); -void jingle_media_rtp_free_codecs (GList *codecs); -GList * jingle_media_rtp_copy_codecs (GList *codecs); - -gboolean jingle_media_rtp_compare_codecs (GList *old, - GList *new, - GList **changed, - GError **e); - -WockyJingleMediaDescription *wocky_jingle_media_description_new (void); -void wocky_jingle_media_description_free (WockyJingleMediaDescription *md); -WockyJingleMediaDescription *wocky_jingle_media_description_copy ( - WockyJingleMediaDescription *md); - -WockyJingleRtpHeaderExtension *wocky_jingle_rtp_header_extension_new (guint id, - WockyJingleContentSenders senders, const gchar *uri); -void wocky_jingle_rtp_header_extension_free (WockyJingleRtpHeaderExtension *hdrext); - - -WockyJingleFeedbackMessage *wocky_jingle_feedback_message_new (const gchar *type, - const gchar *subtype); -void wocky_jingle_feedback_message_free (WockyJingleFeedbackMessage *fb); -void wocky_jingle_media_description_simplify (WockyJingleMediaDescription *md); - -#endif /* __JINGLE_MEDIA_RTP_H__ */ - diff --git a/src/jingle-mint.c b/src/jingle-mint.c index b45992efc..2362cdec0 100644 --- a/src/jingle-mint.c +++ b/src/jingle-mint.c @@ -34,6 +34,7 @@ #include "conn-presence.h" #include "jingle-factory.h" #include "jingle-session.h" +#include "jingle-share.h" #include "presence-cache.h" struct _GabbleJingleMintPrivate { @@ -260,6 +261,8 @@ connection_porter_available_cb ( g_assert (priv->factory == NULL); priv->factory = wocky_jingle_factory_new (conn->session); + jingle_share_register (priv->factory); + tp_g_signal_connect_object (priv->factory, "new-session", (GCallback) factory_new_session_cb, self, 0); tp_g_signal_connect_object (priv->factory, "query-cap", diff --git a/src/jingle-session.c b/src/jingle-session.c deleted file mode 100644 index e8fea568a..000000000 --- a/src/jingle-session.c +++ /dev/null @@ -1,2447 +0,0 @@ -/* - * gabble-jingle-session.c - Source for WockyJingleSession - * Copyright (C) 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 "config.h" -#include "jingle-session.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <glib.h> - -#include <wocky/wocky.h> - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA - -#include "gabble/capabilities.h" -#include "debug.h" -#include "gabble-signals-marshal.h" -#include "gabble-enumtypes.h" -#include "jingle-content.h" -#include "jingle-factory.h" -/* FIXME: the RTP-specific bits of this file should be separated from the - * generic Jingle code. - */ -#include "jingle-media-rtp.h" -#include "namespaces.h" - -G_DEFINE_TYPE(WockyJingleSession, wocky_jingle_session, G_TYPE_OBJECT); - -/* signal enum */ -enum -{ - NEW_CONTENT, - REMOTE_STATE_CHANGED, - TERMINATED, - CONTENT_REJECTED, - QUERY_CAP, - ABOUT_TO_INITIATE, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -/* properties */ -enum -{ - PROP_JINGLE_FACTORY = 1, - PROP_PORTER, - PROP_SESSION_ID, - PROP_PEER_CONTACT, - PROP_LOCAL_INITIATOR, - PROP_STATE, - PROP_DIALECT, - PROP_LOCAL_HOLD, - PROP_REMOTE_HOLD, - PROP_REMOTE_RINGING, - LAST_PROPERTY -}; - -struct _WockyJingleSessionPrivate -{ - /* Borrowed; the factory owns us. */ - WockyJingleFactory *jingle_factory; - WockyPorter *porter; - - WockyContact *peer_contact; - /* Borrowed from peer_contact if it's a WockyResourceContact. */ - const gchar *peer_resource; - gchar *peer_jid; - /* Either borrowed from 'porter' or equal to peer_jid. */ - const gchar *initiator; - gboolean local_initiator; - - /* WockyJingleContent objects keyed by content name. - * Table owns references to these objects. */ - GHashTable *initiator_contents; - GHashTable *responder_contents; - - WockyJingleDialect dialect; - WockyJingleState state; - gchar *sid; - - gboolean locally_accepted; - gboolean locally_terminated; - - gboolean local_hold; - - gboolean remote_hold; - gboolean remote_ringing; - - gboolean dispose_has_run; -}; - -typedef struct { - WockyJingleState state; - WockyJingleAction *actions; -} WockyJingleStateActions; - -/* gcc should be able to figure this out from the table below, but.. */ -#define MAX_ACTIONS_PER_STATE 12 - -/* NB: WOCKY_JINGLE_ACTION_UNKNOWN is used as a terminator here. */ -static WockyJingleAction allowed_actions[WOCKY_N_JINGLE_STATES][MAX_ACTIONS_PER_STATE] = { - /* WOCKY_JINGLE_STATE_PENDING_CREATED */ - { WOCKY_JINGLE_ACTION_SESSION_INITIATE, WOCKY_JINGLE_ACTION_UNKNOWN }, - /* WOCKY_JINGLE_STATE_PENDING_INITIATE_SENT */ - { WOCKY_JINGLE_ACTION_SESSION_TERMINATE, WOCKY_JINGLE_ACTION_SESSION_ACCEPT, - WOCKY_JINGLE_ACTION_TRANSPORT_ACCEPT, /* required for GTalk4 */ - WOCKY_JINGLE_ACTION_DESCRIPTION_INFO, WOCKY_JINGLE_ACTION_SESSION_INFO, - WOCKY_JINGLE_ACTION_TRANSPORT_INFO, WOCKY_JINGLE_ACTION_INFO, - WOCKY_JINGLE_ACTION_UNKNOWN }, - /* WOCKY_JINGLE_STATE_PENDING_INITIATED */ - { WOCKY_JINGLE_ACTION_SESSION_ACCEPT, WOCKY_JINGLE_ACTION_SESSION_TERMINATE, - WOCKY_JINGLE_ACTION_TRANSPORT_INFO, WOCKY_JINGLE_ACTION_CONTENT_REJECT, - WOCKY_JINGLE_ACTION_CONTENT_MODIFY, WOCKY_JINGLE_ACTION_CONTENT_ACCEPT, - WOCKY_JINGLE_ACTION_CONTENT_REMOVE, WOCKY_JINGLE_ACTION_DESCRIPTION_INFO, - WOCKY_JINGLE_ACTION_TRANSPORT_ACCEPT, WOCKY_JINGLE_ACTION_SESSION_INFO, - WOCKY_JINGLE_ACTION_INFO, - WOCKY_JINGLE_ACTION_UNKNOWN }, - /* WOCKY_JINGLE_STATE_PENDING_ACCEPT_SENT */ - { WOCKY_JINGLE_ACTION_TRANSPORT_INFO, WOCKY_JINGLE_ACTION_DESCRIPTION_INFO, - WOCKY_JINGLE_ACTION_SESSION_TERMINATE, WOCKY_JINGLE_ACTION_SESSION_INFO, - WOCKY_JINGLE_ACTION_INFO, - WOCKY_JINGLE_ACTION_UNKNOWN }, - /* WOCKY_JINGLE_STATE_ACTIVE */ - { WOCKY_JINGLE_ACTION_CONTENT_MODIFY, WOCKY_JINGLE_ACTION_CONTENT_ADD, - WOCKY_JINGLE_ACTION_CONTENT_REMOVE, WOCKY_JINGLE_ACTION_CONTENT_REPLACE, - WOCKY_JINGLE_ACTION_CONTENT_ACCEPT, WOCKY_JINGLE_ACTION_CONTENT_REJECT, - WOCKY_JINGLE_ACTION_SESSION_INFO, WOCKY_JINGLE_ACTION_TRANSPORT_INFO, - WOCKY_JINGLE_ACTION_DESCRIPTION_INFO, WOCKY_JINGLE_ACTION_INFO, - WOCKY_JINGLE_ACTION_SESSION_TERMINATE, WOCKY_JINGLE_ACTION_UNKNOWN }, - /* WOCKY_JINGLE_STATE_ENDED */ - { WOCKY_JINGLE_ACTION_UNKNOWN } -}; - -gboolean -wocky_jingle_session_defines_action (WockyJingleSession *sess, - WockyJingleAction a) -{ - WockyJingleDialect d = sess->priv->dialect; - - if (a == WOCKY_JINGLE_ACTION_UNKNOWN) - return FALSE; - - switch (d) - { - case WOCKY_JINGLE_DIALECT_V032: - return TRUE; - case WOCKY_JINGLE_DIALECT_V015: - return (a != WOCKY_JINGLE_ACTION_DESCRIPTION_INFO && - a != WOCKY_JINGLE_ACTION_SESSION_INFO); - case WOCKY_JINGLE_DIALECT_GTALK4: - if (a == WOCKY_JINGLE_ACTION_TRANSPORT_ACCEPT || - a == WOCKY_JINGLE_ACTION_INFO ) - return TRUE; - case WOCKY_JINGLE_DIALECT_GTALK3: - return (a == WOCKY_JINGLE_ACTION_SESSION_ACCEPT || - a == WOCKY_JINGLE_ACTION_SESSION_INITIATE || - a == WOCKY_JINGLE_ACTION_SESSION_TERMINATE || - a == WOCKY_JINGLE_ACTION_TRANSPORT_INFO || - a == WOCKY_JINGLE_ACTION_INFO); - default: - return FALSE; - } -} - -static void wocky_jingle_session_send_held (WockyJingleSession *sess); -static void content_ready_cb (WockyJingleContent *c, gpointer user_data); -static void content_removed_cb (WockyJingleContent *c, gpointer user_data); - -static void -wocky_jingle_session_init (WockyJingleSession *obj) -{ - WockyJingleSessionPrivate *priv = - G_TYPE_INSTANCE_GET_PRIVATE (obj, WOCKY_TYPE_JINGLE_SESSION, - WockyJingleSessionPrivate); - obj->priv = priv; - - DEBUG ("Initializing the jingle session %p", obj); - - priv->initiator_contents = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); - priv->responder_contents = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); - - priv->state = WOCKY_JINGLE_STATE_PENDING_CREATED; - priv->locally_accepted = FALSE; - priv->locally_terminated = FALSE; - priv->dispose_has_run = FALSE; -} - -static void -dispose_content_hash ( - WockyJingleSession *sess, - GHashTable **contents) -{ - GHashTableIter iter; - gpointer content; - - g_hash_table_iter_init (&iter, *contents); - while (g_hash_table_iter_next (&iter, NULL, &content)) - { - g_signal_handlers_disconnect_by_func (content, content_ready_cb, sess); - g_signal_handlers_disconnect_by_func (content, content_removed_cb, sess); - g_hash_table_iter_remove (&iter); - } - - g_hash_table_unref (*contents); - *contents = NULL; -} - -static void -wocky_jingle_session_dispose (GObject *object) -{ - WockyJingleSession *sess = WOCKY_JINGLE_SESSION (object); - WockyJingleSessionPrivate *priv = sess->priv; - - if (priv->dispose_has_run) - return; - - DEBUG ("called"); - priv->dispose_has_run = TRUE; - - g_assert ((priv->state == WOCKY_JINGLE_STATE_PENDING_CREATED) || - (priv->state == WOCKY_JINGLE_STATE_ENDED)); - - dispose_content_hash (sess, &priv->initiator_contents); - dispose_content_hash (sess, &priv->responder_contents); - - g_clear_object (&priv->peer_contact); - g_clear_object (&priv->porter); - - g_free (priv->sid); - priv->sid = NULL; - - g_free (priv->peer_jid); - priv->peer_jid = NULL; - - if (G_OBJECT_CLASS (wocky_jingle_session_parent_class)->dispose) - G_OBJECT_CLASS (wocky_jingle_session_parent_class)->dispose (object); -} - -static void -wocky_jingle_session_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - WockyJingleSession *sess = WOCKY_JINGLE_SESSION (object); - WockyJingleSessionPrivate *priv = sess->priv; - - switch (property_id) { - case PROP_JINGLE_FACTORY: - g_value_set_object (value, priv->jingle_factory); - break; - case PROP_PORTER: - g_value_set_object (value, priv->porter); - break; - case PROP_SESSION_ID: - g_value_set_string (value, priv->sid); - break; - case PROP_LOCAL_INITIATOR: - g_value_set_boolean (value, priv->local_initiator); - break; - case PROP_PEER_CONTACT: - g_value_set_object (value, priv->peer_contact); - break; - case PROP_STATE: - g_value_set_uint (value, priv->state); - break; - case PROP_DIALECT: - g_value_set_uint (value, priv->dialect); - break; - case PROP_LOCAL_HOLD: - g_value_set_boolean (value, priv->local_hold); - break; - case PROP_REMOTE_HOLD: - g_value_set_boolean (value, priv->remote_hold); - break; - case PROP_REMOTE_RINGING: - g_value_set_boolean (value, priv->remote_ringing); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -wocky_jingle_session_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - WockyJingleSession *sess = WOCKY_JINGLE_SESSION (object); - WockyJingleSessionPrivate *priv = sess->priv; - - switch (property_id) { - case PROP_JINGLE_FACTORY: - priv->jingle_factory = g_value_get_object (value); - g_assert (priv->jingle_factory != NULL); - break; - case PROP_PORTER: - priv->porter = g_value_dup_object (value); - g_assert (priv->porter != NULL); - break; - case PROP_SESSION_ID: - g_free (priv->sid); - priv->sid = g_value_dup_string (value); - break; - case PROP_LOCAL_INITIATOR: - priv->local_initiator = g_value_get_boolean (value); - break; - case PROP_DIALECT: - priv->dialect = g_value_get_uint (value); - break; - case PROP_PEER_CONTACT: - priv->peer_contact = g_value_dup_object (value); - break; - case PROP_LOCAL_HOLD: - { - gboolean local_hold = g_value_get_boolean (value); - - if (priv->local_hold != local_hold) - { - priv->local_hold = local_hold; - - if (priv->state >= WOCKY_JINGLE_STATE_PENDING_INITIATED && - priv->state < WOCKY_JINGLE_STATE_ENDED) - wocky_jingle_session_send_held (sess); - - /* else, we'll send this in set_state when we move to PENDING_INITIATED or - * better. - */ - } - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - g_assert_not_reached (); - break; - } -} - -static void -wocky_jingle_session_constructed (GObject *object) -{ - void (*chain_up) (GObject *) = - G_OBJECT_CLASS (wocky_jingle_session_parent_class)->constructed; - WockyJingleSession *self = WOCKY_JINGLE_SESSION (object); - WockyJingleSessionPrivate *priv = self->priv; - - if (chain_up != NULL) - chain_up (object); - - g_assert (priv->jingle_factory != NULL); - g_assert (priv->porter != NULL); - g_assert (priv->peer_contact != NULL); - g_assert (priv->sid != NULL); - - priv->peer_jid = wocky_contact_dup_jid (priv->peer_contact); - - if (priv->local_initiator) - priv->initiator = wocky_porter_get_full_jid (priv->porter); - else - priv->initiator = priv->peer_jid; - - if (WOCKY_IS_RESOURCE_CONTACT (priv->peer_contact)) - priv->peer_resource = wocky_resource_contact_get_resource ( - WOCKY_RESOURCE_CONTACT (priv->peer_contact)); -} - -WockyJingleSession * -wocky_jingle_session_new ( - WockyJingleFactory *factory, - WockyPorter *porter, - const gchar *session_id, - gboolean local_initiator, - WockyContact *peer, - WockyJingleDialect dialect, - gboolean local_hold) -{ - return g_object_new (WOCKY_TYPE_JINGLE_SESSION, - "session-id", session_id, - "jingle-factory", factory, - "porter", porter, - "local-initiator", local_initiator, - "peer-contact", peer, - "dialect", dialect, - "local-hold", local_hold, - NULL); -} - -static void -wocky_jingle_session_class_init (WockyJingleSessionClass *cls) -{ - GObjectClass *object_class = G_OBJECT_CLASS (cls); - GParamSpec *param_spec; - - g_type_class_add_private (cls, sizeof (WockyJingleSessionPrivate)); - - object_class->constructed = wocky_jingle_session_constructed; - object_class->get_property = wocky_jingle_session_get_property; - object_class->set_property = wocky_jingle_session_set_property; - object_class->dispose = wocky_jingle_session_dispose; - - /* property definitions */ - param_spec = g_param_spec_object ("jingle-factory", - "WockyJingleFactory object", - "The Jingle factory which created this session", - WOCKY_TYPE_JINGLE_FACTORY, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_JINGLE_FACTORY, param_spec); - - param_spec = g_param_spec_object ("porter", "WockyPorter", - "The WockyPorter for the current connection", - WOCKY_TYPE_PORTER, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_PORTER, param_spec); - - param_spec = g_param_spec_string ("session-id", "Session ID", - "A unique session identifier used throughout all communication.", - NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_SESSION_ID, param_spec); - - param_spec = g_param_spec_boolean ("local-initiator", "Session initiator", - "Specifies if local end initiated the session.", - TRUE, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_LOCAL_INITIATOR, - param_spec); - - /** - * WockyJingleSession:peer-contact: - * - * The #WockyContact representing the other party in the session. Note that - * if this is a #WockyBareContact (as opposed to a #WockyResourceContact) the - * session is with the contact's bare JID. - */ - param_spec = g_param_spec_object ("peer-contact", "Session peer", - "The WockyContact representing the other party in the session.", - WOCKY_TYPE_CONTACT, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_PEER_CONTACT, param_spec); - - param_spec = g_param_spec_uint ("state", "Session state", - "The current state that the session is in.", - 0, G_MAXUINT32, WOCKY_JINGLE_STATE_PENDING_CREATED, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_STATE, param_spec); - - param_spec = g_param_spec_uint ("dialect", "Jingle dialect", - "Jingle dialect used for this session.", - 0, G_MAXUINT32, WOCKY_JINGLE_DIALECT_ERROR, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_DIALECT, param_spec); - - param_spec = g_param_spec_boolean ("local-hold", "Local hold", - "TRUE if we've placed the peer on hold", FALSE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_LOCAL_HOLD, param_spec); - - param_spec = g_param_spec_boolean ("remote-hold", "Remote hold", - "TRUE if the peer has placed us on hold", FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_REMOTE_HOLD, param_spec); - - param_spec = g_param_spec_boolean ("remote-ringing", "Remote ringing", - "TRUE if the peer's client is ringing", FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_REMOTE_RINGING, - param_spec); - - /* signal definitions */ - - signals[NEW_CONTENT] = g_signal_new ("new-content", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - - signals[TERMINATED] = g_signal_new ("terminated", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, gabble_marshal_VOID__BOOLEAN_UINT_STRING, - G_TYPE_NONE, 3, G_TYPE_BOOLEAN, G_TYPE_UINT, G_TYPE_STRING); - - signals[REMOTE_STATE_CHANGED] = g_signal_new ("remote-state-changed", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[CONTENT_REJECTED] = g_signal_new ("content-rejected", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, gabble_marshal_VOID__OBJECT_UINT_STRING, - G_TYPE_NONE, 3, G_TYPE_OBJECT, G_TYPE_UINT, G_TYPE_STRING); - - /* - * @contact: this call's peer (the artist commonly known as - * wocky_jingle_session_get_peer_contact()) - * @cap: the XEP-0115 feature string the session is interested in. - * - * Emitted when the session wants to check whether the peer has a particular - * capability. The handler should return %TRUE if @contact has @cap. - */ - signals[QUERY_CAP] = g_signal_new ("query-cap", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, g_signal_accumulator_first_wins, NULL, - gabble_marshal_BOOLEAN__OBJECT_STRING, - G_TYPE_BOOLEAN, 2, WOCKY_TYPE_CONTACT, G_TYPE_STRING); - - signals[ABOUT_TO_INITIATE] = g_signal_new ("about-to-initiate", - G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -typedef void (*HandlerFunc)(WockyJingleSession *sess, - WockyNode *node, GError **error); -typedef void (*ContentHandlerFunc)(WockyJingleSession *sess, - WockyJingleContent *c, WockyNode *content_node, gpointer user_data, - GError **error); - -static gboolean -extract_reason (WockyNode *node, WockyJingleReason *reason, gchar **message) -{ - WockyJingleReason _reason = WOCKY_JINGLE_REASON_UNKNOWN; - WockyNode *child; - WockyNodeIter iter; - - g_return_val_if_fail (node != NULL, FALSE); - - if (message != NULL) - *message = g_strdup (wocky_node_get_content_from_child (node, "text")); - - wocky_node_iter_init (&iter, node, NULL, NULL); - - while (wocky_node_iter_next (&iter, &child)) - { - if (wocky_enum_from_nick ( - wocky_jingle_reason_get_type (), child->name, (gint *) &_reason)) - { - if (reason != NULL) - *reason = _reason; - return TRUE; - } - } - - return FALSE; -} - -static WockyJingleAction -parse_action (const gchar *txt) -{ - if (txt == NULL) - return WOCKY_JINGLE_ACTION_UNKNOWN; - - /* synonyms, best deal with them right now */ - if (!wocky_strdiff (txt, "initiate") || - !wocky_strdiff (txt, "session-initiate")) - return WOCKY_JINGLE_ACTION_SESSION_INITIATE; - else if (!wocky_strdiff (txt, "terminate") || - !wocky_strdiff (txt, "session-terminate") || - !wocky_strdiff (txt, "reject")) - return WOCKY_JINGLE_ACTION_SESSION_TERMINATE; - else if (!wocky_strdiff (txt, "accept") || - !wocky_strdiff (txt, "session-accept")) - return WOCKY_JINGLE_ACTION_SESSION_ACCEPT; - else if (!wocky_strdiff (txt, "candidates") || - !wocky_strdiff (txt, "transport-info")) - return WOCKY_JINGLE_ACTION_TRANSPORT_INFO; - else if (!wocky_strdiff (txt, "content-accept")) - return WOCKY_JINGLE_ACTION_CONTENT_ACCEPT; - else if (!wocky_strdiff (txt, "content-add")) - return WOCKY_JINGLE_ACTION_CONTENT_ADD; - else if (!wocky_strdiff (txt, "content-modify")) - return WOCKY_JINGLE_ACTION_CONTENT_MODIFY; - else if (!wocky_strdiff (txt, "content-replace")) - return WOCKY_JINGLE_ACTION_CONTENT_REPLACE; - else if (!wocky_strdiff (txt, "content-reject")) - return WOCKY_JINGLE_ACTION_CONTENT_REJECT; - else if (!wocky_strdiff (txt, "content-remove")) - return WOCKY_JINGLE_ACTION_CONTENT_REMOVE; - else if (!wocky_strdiff (txt, "session-info")) - return WOCKY_JINGLE_ACTION_SESSION_INFO; - else if (!wocky_strdiff (txt, "transport-accept")) - return WOCKY_JINGLE_ACTION_TRANSPORT_ACCEPT; - else if (!wocky_strdiff (txt, "description-info")) - return WOCKY_JINGLE_ACTION_DESCRIPTION_INFO; - else if (!wocky_strdiff (txt, "info")) - return WOCKY_JINGLE_ACTION_INFO; - - return WOCKY_JINGLE_ACTION_UNKNOWN; -} - -static const gchar * -produce_action (WockyJingleAction action, WockyJingleDialect dialect) -{ - gboolean gmode = (dialect == WOCKY_JINGLE_DIALECT_GTALK3) || - (dialect == WOCKY_JINGLE_DIALECT_GTALK4); - - g_return_val_if_fail (action != WOCKY_JINGLE_ACTION_UNKNOWN, NULL); - - switch (action) { - case WOCKY_JINGLE_ACTION_SESSION_INITIATE: - return (gmode) ? "initiate" : "session-initiate"; - case WOCKY_JINGLE_ACTION_SESSION_TERMINATE: - return (gmode) ? "terminate" : "session-terminate"; - case WOCKY_JINGLE_ACTION_SESSION_ACCEPT: - return (gmode) ? "accept" : "session-accept"; - case WOCKY_JINGLE_ACTION_TRANSPORT_INFO: - return (dialect == WOCKY_JINGLE_DIALECT_GTALK3) ? - "candidates" : "transport-info"; - case WOCKY_JINGLE_ACTION_CONTENT_ACCEPT: - return "content-accept"; - case WOCKY_JINGLE_ACTION_CONTENT_ADD: - return "content-add"; - case WOCKY_JINGLE_ACTION_CONTENT_MODIFY: - return "content-modify"; - case WOCKY_JINGLE_ACTION_CONTENT_REMOVE: - return "content-remove"; - case WOCKY_JINGLE_ACTION_CONTENT_REPLACE: - return "content-replace"; - case WOCKY_JINGLE_ACTION_CONTENT_REJECT: - return "content-reject"; - case WOCKY_JINGLE_ACTION_SESSION_INFO: - return "session-info"; - case WOCKY_JINGLE_ACTION_TRANSPORT_ACCEPT: - return "transport-accept"; - case WOCKY_JINGLE_ACTION_DESCRIPTION_INFO: - return "description-info"; - case WOCKY_JINGLE_ACTION_INFO: - return "info"; - default: - /* only reached if g_return_val_if_fail is disabled */ - DEBUG ("unknown action %u", action); - return NULL; - } -} - -static gboolean -action_is_allowed (WockyJingleAction action, WockyJingleState state) -{ - guint i; - - for (i = 0; allowed_actions[state][i] != WOCKY_JINGLE_ACTION_UNKNOWN; i++) - { - if (allowed_actions[state][i] == action) - return TRUE; - } - - return FALSE; -} - -static void wocky_jingle_session_send_rtp_info (WockyJingleSession *sess, - const gchar *name); -static void set_state (WockyJingleSession *sess, - WockyJingleState state, WockyJingleReason termination_reason, const gchar *text); -static WockyJingleContent *_get_any_content (WockyJingleSession *session); - -gboolean -wocky_jingle_session_peer_has_cap ( - WockyJingleSession *self, - const gchar *cap_or_quirk) -{ - WockyJingleSessionPrivate *priv = self->priv; - gboolean ret; - - g_signal_emit (self, signals[QUERY_CAP], 0, - priv->peer_contact, cap_or_quirk, - &ret); - return ret; -} - -static gboolean -lookup_content (WockyJingleSession *sess, - const gchar *name, - const gchar *creator, - gboolean fail_if_missing, - WockyJingleContent **c, - GError **error) -{ - WockyJingleSessionPrivate *priv = sess->priv; - - if (name == NULL) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "'name' attribute unset"); - return FALSE; - } - - if (WOCKY_JINGLE_DIALECT_IS_GOOGLE (priv->dialect)) - { - /* Only the initiator can create contents on GTalk. */ - *c = g_hash_table_lookup (priv->initiator_contents, name); - } - else - { - /* Versions of Gabble between 0.7.16 and 0.7.28 (inclusive) omitted the - * 'creator' attribute from transport-info (and possibly other) stanzas. - * We try to detect contacts using such a version of Gabble from their - * caps; if 'creator' is missing and the peer has that caps flag, we look - * up the content in both hashes. - * - * While this doesn't deal with the case where the content is found in - * both hashes, this isn't a problem in practice: the versions of Gabble - * we're working around didn't allow this to happen (they'd either reject - * the second stream, or let it replace the first, depending on the phase - * of the moon, and get kind of confused in the process), and we try to - * pick globally-unique content names. - */ - if (creator == NULL && - wocky_jingle_session_peer_has_cap (sess, - QUIRK_OMITS_CONTENT_CREATORS)) - { - DEBUG ("working around missing 'creator' attribute"); - - *c = g_hash_table_lookup (priv->initiator_contents, name); - - if (*c == NULL) - *c = g_hash_table_lookup (priv->responder_contents, name); - } - else if (!wocky_strdiff (creator, "initiator")) - { - *c = g_hash_table_lookup (priv->initiator_contents, name); - } - else if (!wocky_strdiff (creator, "responder")) - { - *c = g_hash_table_lookup (priv->responder_contents, name); - } - else - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "'creator' attribute %s", - (creator == NULL ? "missing" : "invalid")); - return FALSE; - } - } - - if (fail_if_missing && *c == NULL) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "Content '%s' (created by %s) does not exist", name, creator); - return FALSE; - } - - return TRUE; -} - -static void -_foreach_content (WockyJingleSession *sess, - WockyNode *node, - gboolean fail_if_missing, - ContentHandlerFunc func, - gpointer user_data, - GError **error) -{ - WockyJingleContent *c; - WockyNode *content_node; - WockyNodeIter iter; - - wocky_node_iter_init (&iter, node, "content", NULL); - while (wocky_node_iter_next (&iter, &content_node)) - { - if (!lookup_content (sess, - wocky_node_get_attribute (content_node, "name"), - wocky_node_get_attribute (content_node, "creator"), - fail_if_missing, &c, error)) - return; - - func (sess, c, content_node, user_data, error); - if (*error != NULL) - return; - } -} - -struct idle_content_reject_ctx { - WockyJingleSession *session; - WockyStanza *msg; -}; - -static gboolean -idle_content_reject (gpointer data) -{ - struct idle_content_reject_ctx *ctx = data; - - wocky_jingle_session_send (ctx->session, ctx->msg); - - g_object_unref (ctx->session); - g_free (ctx); - - return FALSE; -} - -static void -fire_idle_content_reject (WockyJingleSession *sess, const gchar *name, - const gchar *creator) -{ - struct idle_content_reject_ctx *ctx = g_new0 (struct idle_content_reject_ctx, 1); - WockyNode *sess_node, *node; - - if (creator == NULL) - creator = ""; - - ctx->session = g_object_ref (sess); - ctx->msg = wocky_jingle_session_new_message (ctx->session, - WOCKY_JINGLE_ACTION_CONTENT_REJECT, &sess_node); - - g_debug ("name = %s, initiator = %s", name, creator); - - node = wocky_node_add_child (sess_node, "content"); - wocky_node_set_attributes (node, - "name", name, "creator", creator, NULL); - - /* FIXME: add API for ordering IQs rather than using g_idle_add. */ - g_idle_add (idle_content_reject, ctx); -} - -static WockyJingleContent * -create_content (WockyJingleSession *sess, GType content_type, - WockyJingleMediaType type, WockyJingleContentSenders senders, - const gchar *content_ns, const gchar *transport_ns, - const gchar *name, WockyNode *content_node, GError **error) -{ - WockyJingleSessionPrivate *priv = sess->priv; - WockyJingleContent *c; - GHashTable *contents; - - DEBUG ("session creating new content name %s, type %d", name, type); - - /* FIXME: media-type is introduced by GabbleJingleMediaRTP, not by the - * superclass, so this call is unsafe in the general case */ - c = g_object_new (content_type, - "session", sess, - "content-ns", content_ns, - "transport-ns", transport_ns, - "media-type", type, - "name", name, - "disposition", "session", - "senders", senders, - NULL); - - g_signal_connect (c, "ready", - (GCallback) content_ready_cb, sess); - g_signal_connect (c, "removed", - (GCallback) content_removed_cb, sess); - - /* if we are called by parser, parse content add */ - if (content_node != NULL) - { - wocky_jingle_content_parse_add (c, content_node, - WOCKY_JINGLE_DIALECT_IS_GOOGLE (priv->dialect), error); - - if (*error != NULL) - { - g_object_unref (c); - return NULL; - } - - /* gtalk streams don't have name, so use whatever Content came up with */ - if (name == NULL) - name = wocky_jingle_content_get_name (c); - } - - if (priv->local_initiator == wocky_jingle_content_is_created_by_us (c)) - { - DEBUG ("inserting content %s into initiator_contents", name); - contents = priv->initiator_contents; - } - else - { - DEBUG ("inserting content %s into responder_contents", name); - contents = priv->responder_contents; - } - - /* If the content already existed, either we shouldn't have picked the name - * we did (if we're creating it) or _each_content_add should have already - * said no. - */ - g_assert (g_hash_table_lookup (contents, name) == NULL); - g_hash_table_insert (contents, g_strdup (name), c); - g_signal_emit (sess, signals[NEW_CONTENT], 0, c); - return c; -} - - -static void -_each_content_add (WockyJingleSession *sess, WockyJingleContent *c, - WockyNode *content_node, gpointer user_data, GError **error) -{ - WockyJingleSessionPrivate *priv = sess->priv; - const gchar *name = wocky_node_get_attribute (content_node, "name"); - WockyNode *desc_node = wocky_node_get_child (content_node, - "description"); - GType content_type = 0; - const gchar *content_ns = NULL; - - if (desc_node != NULL) - { - content_ns = wocky_node_get_ns (desc_node); - DEBUG ("namespace: %s", content_ns); - content_type = wocky_jingle_factory_lookup_content_type ( - wocky_jingle_session_get_factory (sess), - content_ns); - } - - if (content_type == 0) - { - /* if this is session-initiate, we should return error, otherwise, - * we should respond with content-reject */ - if (priv->state < WOCKY_JINGLE_STATE_PENDING_INITIATED) - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "unsupported content type with ns %s", content_ns); - else - fire_idle_content_reject (sess, name, - wocky_node_get_attribute (content_node, "creator")); - - return; - } - - if (c != NULL) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "content '%s' already exists", name); - return; - } - - create_content (sess, content_type, WOCKY_JINGLE_MEDIA_TYPE_NONE, - WOCKY_JINGLE_CONTENT_SENDERS_BOTH, content_ns, NULL, NULL, content_node, - error); -} - -static void -_each_content_remove (WockyJingleSession *sess, WockyJingleContent *c, - WockyNode *content_node, gpointer user_data, GError **error) -{ - g_assert (c != NULL); - - wocky_jingle_content_remove (c, FALSE); -} - -static void -_each_content_rejected (WockyJingleSession *sess, WockyJingleContent *c, - WockyNode *content_node, gpointer user_data, GError **error) -{ - WockyJingleReason reason = GPOINTER_TO_UINT (user_data); - g_assert (c != NULL); - - g_signal_emit (sess, signals[CONTENT_REJECTED], 0, c, reason, ""); - - wocky_jingle_content_remove (c, FALSE); -} - -static void -_each_content_modify (WockyJingleSession *sess, WockyJingleContent *c, - WockyNode *content_node, gpointer user_data, GError **error) -{ - g_assert (c != NULL); - - wocky_jingle_content_update_senders (c, content_node, error); - - if (*error != NULL) - return; -} - -static void -_each_content_replace (WockyJingleSession *sess, WockyJingleContent *c, - WockyNode *content_node, gpointer user_data, GError **error) -{ - _each_content_remove (sess, c, content_node, NULL, error); - - if (*error != NULL) - return; - - _each_content_add (sess, c, content_node, NULL, error); -} - -static void -_each_content_accept (WockyJingleSession *sess, WockyJingleContent *c, - WockyNode *content_node, gpointer user_data, GError **error) -{ - WockyJingleSessionPrivate *priv = sess->priv; - WockyJingleContentState state; - - g_assert (c != NULL); - - g_object_get (c, "state", &state, NULL); - if (state != WOCKY_JINGLE_CONTENT_STATE_SENT) - { -#ifdef ENABLE_DEBUG - const gchar *name = wocky_node_get_attribute (content_node, "name"); - DEBUG ("ignoring content \"%s\"s acceptance for content not in SENT state", name); -#endif - return; - } - - wocky_jingle_content_parse_accept (c, content_node, - WOCKY_JINGLE_DIALECT_IS_GOOGLE (priv->dialect), error); -} - -static void -_each_description_info (WockyJingleSession *sess, WockyJingleContent *c, - WockyNode *content_node, gpointer user_data, GError **error) -{ - wocky_jingle_content_parse_description_info (c, content_node, error); -} - -static void -on_session_initiate (WockyJingleSession *sess, WockyNode *node, - GError **error) -{ - WockyJingleSessionPrivate *priv = sess->priv; - - /* we can't call ourselves at the moment */ - if (priv->local_initiator) - { - /* We ignore initiate from us, and terminate the session immediately - * afterwards */ - wocky_jingle_session_terminate (sess, WOCKY_JINGLE_REASON_BUSY, NULL, NULL); - return; - } - - if ((priv->dialect == WOCKY_JINGLE_DIALECT_GTALK3)) - { - const gchar *content_ns = NULL; - WockyNode *desc_node = - wocky_node_get_child (node, "description"); - content_ns = wocky_node_get_ns (desc_node); - - if (!wocky_strdiff (content_ns, NS_GOOGLE_SESSION_VIDEO)) - { - WockyJingleFactory *factory = - wocky_jingle_session_get_factory (sess); - GType content_type = 0; - - DEBUG ("GTalk v3 session with audio and video"); - - /* audio and video content */ - content_type = wocky_jingle_factory_lookup_content_type ( - factory, content_ns); - create_content (sess, content_type, WOCKY_JINGLE_MEDIA_TYPE_VIDEO, - WOCKY_JINGLE_CONTENT_SENDERS_BOTH, NS_GOOGLE_SESSION_VIDEO, NULL, - "video", node, error); - - content_type = wocky_jingle_factory_lookup_content_type ( - factory, NS_GOOGLE_SESSION_PHONE); - create_content (sess, content_type, WOCKY_JINGLE_MEDIA_TYPE_AUDIO, - WOCKY_JINGLE_CONTENT_SENDERS_BOTH, NS_GOOGLE_SESSION_PHONE, NULL, - "audio", node, error); - } - else - { - _each_content_add (sess, NULL, node, NULL, error); - } - } - else if (priv->dialect == WOCKY_JINGLE_DIALECT_GTALK4) - { - /* in this case we implicitly have just one content */ - _each_content_add (sess, NULL, node, NULL, error); - } - else - { - _foreach_content (sess, node, FALSE, _each_content_add, NULL, error); - } - - if (*error == NULL) - { - /* FIXME: contents defined here should always have "session" content - * disposition; resolve this as soon as the proper procedure is defined - * in XEP-0166. */ - - set_state (sess, WOCKY_JINGLE_STATE_PENDING_INITIATED, WOCKY_JINGLE_REASON_UNKNOWN, - NULL); - - wocky_jingle_session_send_rtp_info (sess, "ringing"); - } -} - -static void -on_content_add (WockyJingleSession *sess, WockyNode *node, - GError **error) -{ - _foreach_content (sess, node, FALSE, _each_content_add, NULL, error); -} - -static void -on_content_modify (WockyJingleSession *sess, WockyNode *node, - GError **error) -{ - _foreach_content (sess, node, TRUE, _each_content_modify, NULL, error); -} - -static void -on_content_remove (WockyJingleSession *sess, WockyNode *node, - GError **error) -{ - _foreach_content (sess, node, TRUE, _each_content_remove, NULL, error); -} - -static void -on_content_replace (WockyJingleSession *sess, WockyNode *node, - GError **error) -{ - _foreach_content (sess, node, TRUE, _each_content_replace, NULL, error); -} - -static void -on_content_reject (WockyJingleSession *sess, WockyNode *node, - GError **error) -{ - WockyNode *n = wocky_node_get_child (node, "reason"); - WockyJingleReason reason = WOCKY_JINGLE_REASON_UNKNOWN; - - DEBUG (" "); - - if (n != NULL) - extract_reason (n, &reason, NULL); - - if (reason == WOCKY_JINGLE_REASON_UNKNOWN) - reason = WOCKY_JINGLE_REASON_GENERAL_ERROR; - - _foreach_content (sess, node, TRUE, _each_content_rejected, - GUINT_TO_POINTER (reason), error); -} - -static void -on_content_accept (WockyJingleSession *sess, WockyNode *node, - GError **error) -{ - _foreach_content (sess, node, TRUE, _each_content_accept, NULL, error); -} - -static void -on_session_accept (WockyJingleSession *sess, WockyNode *node, - GError **error) -{ - WockyJingleSessionPrivate *priv = sess->priv; - - DEBUG ("called"); - - if ((priv->dialect == WOCKY_JINGLE_DIALECT_GTALK3) || - (priv->dialect == WOCKY_JINGLE_DIALECT_GTALK4)) - { - /* Google Talk calls don't have contents per se; they just have - * <payload-type>s in different namespaces for audio and video, in the - * same <description> stanza. So we need to feed the whole stanza to each - * content in turn. - */ - GList *cs = wocky_jingle_session_get_contents (sess); - GList *l; - - for (l = cs; l != NULL; l = l->next) - _each_content_accept (sess, l->data, node, NULL, error); - - g_list_free (cs); - } - else - { - _foreach_content (sess, node, TRUE, _each_content_accept, NULL, error); - } - - if (*error != NULL) - return; - - set_state (sess, WOCKY_JINGLE_STATE_ACTIVE, WOCKY_JINGLE_REASON_UNKNOWN, NULL); - - /* Make sure each content knows the session is active */ - g_list_foreach (wocky_jingle_session_get_contents (sess), - (GFunc) g_object_notify, "state"); - - - if (priv->dialect != WOCKY_JINGLE_DIALECT_V032) - { - /* If this is a dialect that doesn't support <active/>, we treat - * session-accept as the cue to remove the ringing flag. - */ - priv->remote_ringing = FALSE; - g_signal_emit (sess, signals[REMOTE_STATE_CHANGED], 0); - } -} - -static void -mute_all_foreach (gpointer key, - gpointer value, - gpointer mute) -{ - if (G_OBJECT_TYPE (value) == WOCKY_TYPE_JINGLE_MEDIA_RTP) - g_object_set (value, "remote-mute", GPOINTER_TO_INT (mute), NULL); -} - -static void -mute_all (WockyJingleSession *sess, - gboolean mute) -{ - g_hash_table_foreach (sess->priv->initiator_contents, mute_all_foreach, - GINT_TO_POINTER (mute)); - g_hash_table_foreach (sess->priv->responder_contents, mute_all_foreach, - GINT_TO_POINTER (mute)); -} - -static gboolean -set_mute (WockyJingleSession *sess, - const gchar *name, - const gchar *creator, - gboolean mute, - GError **error) -{ - WockyJingleContent *c; - - if (name == NULL) - { - mute_all (sess, mute); - return TRUE; - } - - if (!lookup_content (sess, name, creator, TRUE /* fail if missing */, &c, - error)) - return FALSE; - - if (G_OBJECT_TYPE (c) != WOCKY_TYPE_JINGLE_MEDIA_RTP) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "content '%s' isn't an RTP session", name); - return FALSE; - } - - g_object_set (c, "remote-mute", mute, NULL); - return TRUE; -} - -static void -set_hold (WockyJingleSession *sess, - gboolean hold) -{ - sess->priv->remote_hold = hold; -} - -static void -set_ringing (WockyJingleSession *sess, - gboolean ringing) -{ - sess->priv->remote_ringing = ringing; -} - -static gboolean -handle_payload (WockyJingleSession *sess, - WockyNode *payload, - gboolean *handled, - GError **error) -{ - const gchar *ns = wocky_node_get_ns (payload); - const gchar *elt = payload->name; - const gchar *name = wocky_node_get_attribute (payload, "name"); - const gchar *creator = wocky_node_get_attribute (payload, "creator"); - - if (wocky_strdiff (ns, NS_JINGLE_RTP_INFO)) - { - *handled = FALSE; - return TRUE; - } - - *handled = TRUE; - - if (!wocky_strdiff (elt, "active")) - { - /* Clear all states, we're active */ - mute_all (sess, FALSE); - set_ringing (sess, FALSE); - set_hold (sess, FALSE); - } - else if (!wocky_strdiff (elt, "ringing")) - { - set_ringing (sess, TRUE); - } - else if (!wocky_strdiff (elt, "hold")) - { - set_hold (sess, TRUE); - } - else if (!wocky_strdiff (elt, "unhold")) - { - set_hold (sess, FALSE); - } - /* XEP-0178 says that only <mute/> and <unmute/> can have a name='' - * attribute. - */ - else if (!wocky_strdiff (elt, "mute")) - { - return set_mute (sess, name, creator, TRUE, error); - } - else if (!wocky_strdiff (elt, "unmute")) - { - return set_mute (sess, name, creator, FALSE, error); - } - else - { - g_set_error (error, WOCKY_JINGLE_ERROR, - WOCKY_JINGLE_ERROR_UNSUPPORTED_INFO, - "<%s> is not known in namespace %s", elt, ns); - return FALSE; - } - - return TRUE; -} - -static void -on_session_info (WockyJingleSession *sess, - WockyNode *node, - GError **error) -{ - gboolean understood_a_payload = FALSE; - gboolean hit_an_error = FALSE; - WockyNodeIter i; - WockyNode *n; - - /* if this is a ping, just ack it. */ - if (wocky_node_get_first_child (node) == NULL) - return; - - wocky_node_iter_init (&i, node, NULL, NULL); - while (wocky_node_iter_next (&i, &n)) - { - gboolean handled; - GError *e = NULL; - - if (handle_payload (sess, n, &handled, &e)) - { - understood_a_payload = understood_a_payload || handled; - } - else if (hit_an_error) - { - DEBUG ("already got another error; ignoring %s", e->message); - g_error_free (e); - } - else - { - DEBUG ("hit an error: %s", e->message); - hit_an_error = TRUE; - g_propagate_error (error, e); - } - } - - /* If we understood something, the remote state (may have) changed. Else, - * return an error to the peer. - */ - if (understood_a_payload) - g_signal_emit (sess, signals[REMOTE_STATE_CHANGED], 0); - else if (!hit_an_error) - g_set_error (error, WOCKY_JINGLE_ERROR, WOCKY_JINGLE_ERROR_UNSUPPORTED_INFO, - "no recognized session-info payloads"); -} - -static void -on_session_terminate (WockyJingleSession *sess, WockyNode *node, - GError **error) -{ - gchar *text = NULL; - WockyNode *n = wocky_node_get_child (node, "reason"); - WockyJingleReason wocky_jingle_reason = WOCKY_JINGLE_REASON_UNKNOWN; - - if (n != NULL) - extract_reason (n, &wocky_jingle_reason, &text); - - DEBUG ("remote end terminated the session with reason %s and text '%s'", - wocky_jingle_session_get_reason_name (wocky_jingle_reason), - (text != NULL ? text : "(none)")); - - set_state (sess, WOCKY_JINGLE_STATE_ENDED, wocky_jingle_reason, text); - - g_free (text); -} - -static void -on_transport_info (WockyJingleSession *sess, WockyNode *node, - GError **error) -{ - WockyJingleSessionPrivate *priv = sess->priv; - WockyJingleContent *c = NULL; - - if (WOCKY_JINGLE_DIALECT_IS_GOOGLE (priv->dialect)) - { - GHashTableIter iter; - gpointer value; - - if (priv->dialect == WOCKY_JINGLE_DIALECT_GTALK4) - { - if (!wocky_strdiff (wocky_node_get_attribute (node, "type"), - "candidates")) - { - GList *contents = wocky_jingle_session_get_contents (sess); - GList *l; - - DEBUG ("switching to gtalk3 dialect and retransmiting our candidates"); - priv->dialect = WOCKY_JINGLE_DIALECT_GTALK3; - - for (l = contents; l != NULL; l = l->next) - wocky_jingle_content_retransmit_candidates (l->data, TRUE); - - g_list_free (contents); - } - else - { - node = wocky_node_get_child (node, "transport"); - - if (node == NULL) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "transport-info stanza without a <transport/>"); - return; - } - } - } - - g_hash_table_iter_init (&iter, priv->initiator_contents); - while (g_hash_table_iter_next (&iter, NULL, &value)) - { - c = value; - wocky_jingle_content_parse_transport_info (c, node, error); - if (error != NULL && *error != NULL) - break; - } - } - else - { - WockyNodeIter i; - WockyNode *content_node; - GError *e = NULL; - - wocky_node_iter_init (&i, node, "content", NULL); - - while (wocky_node_iter_next (&i, &content_node)) - { - WockyNode *transport_node; - - if (lookup_content (sess, - wocky_node_get_attribute (content_node, "name"), - wocky_node_get_attribute (content_node, "creator"), - TRUE /* fail_if_missing */, &c, &e)) - { - /* we need transport child of content node */ - transport_node = wocky_node_get_child ( - content_node, "transport"); - wocky_jingle_content_parse_transport_info (c, - transport_node, &e); - } - - /* Save the first error we encounter, but go through all remaining - * contents anyway to try and recover as much info as we can */ - if (e != NULL && error != NULL && *error == NULL) - { - *error = e; - e = NULL; - } - g_clear_error (&e); - } - } - -} - -static void -on_transport_accept (WockyJingleSession *sess, WockyNode *node, - GError **error) -{ - DEBUG ("Ignoring 'transport-accept' action from peer"); -} - -static void -on_description_info (WockyJingleSession *sess, WockyNode *node, - GError **error) -{ - _foreach_content (sess, node, TRUE, _each_description_info, NULL, error); -} - -static void -on_info (WockyJingleSession *sess, WockyNode *node, - GError **error) -{ - WockyJingleSessionPrivate *priv = sess->priv; - WockyJingleContent *c = NULL; - - DEBUG ("received info "); - if (WOCKY_JINGLE_DIALECT_IS_GOOGLE (priv->dialect)) - { - GHashTableIter iter; - g_hash_table_iter_init (&iter, priv->initiator_contents); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &c)) - { - wocky_jingle_content_parse_info (c, node, error); - if (error != NULL && *error != NULL) - break; - } - } -} - -static HandlerFunc handlers[] = { - NULL, /* for unknown action */ - on_content_accept, - on_content_add, - on_content_modify, - on_content_remove, - on_content_replace, - on_content_reject, - on_session_accept, /* jingle_on_session_accept */ - on_session_info, - on_session_initiate, - on_session_terminate, /* jingle_on_session_terminate */ - on_transport_info, /* jingle_on_transport_info */ - on_transport_accept, - on_description_info, - on_info -}; - -static void -wocky_jingle_state_machine_dance (WockyJingleSession *sess, - WockyJingleAction action, - WockyNode *node, - GError **error) -{ - WockyJingleSessionPrivate *priv = sess->priv; - - /* parser should've checked this already */ - g_assert (action_is_allowed (action, priv->state)); - g_assert (handlers[action] != NULL); - - handlers[action] (sess, node, error); -} - -static WockyJingleDialect -detect_google_dialect (WockyNode *session_node) -{ - /* The GTALK3 dialect is the only one that supports video at this time */ - if (wocky_node_get_child_ns (session_node, - "description", NS_GOOGLE_SESSION_VIDEO) != NULL) - return WOCKY_JINGLE_DIALECT_GTALK3; - - /* GTalk4 has a transport item, GTalk3 doesn't */ - if (wocky_node_get_child_ns (session_node, - "transport", NS_GOOGLE_TRANSPORT_P2P) == NULL) - return WOCKY_JINGLE_DIALECT_GTALK3; - - return WOCKY_JINGLE_DIALECT_GTALK4; -} - -const gchar * -wocky_jingle_session_detect ( - WockyStanza *stanza, - WockyJingleAction *action, - WockyJingleDialect *dialect) -{ - const gchar *actxt, *sid; - WockyNode *iq_node, *session_node; - WockyStanzaSubType sub_type; - gboolean google_mode = FALSE; - - /* all jingle actions are sets */ - wocky_stanza_get_type_info (stanza, NULL, &sub_type); - if (sub_type != WOCKY_STANZA_SUB_TYPE_SET) - return NULL; - - iq_node = wocky_stanza_get_top_node (stanza); - - if ((NULL == wocky_stanza_get_from (stanza)) || - (NULL == wocky_stanza_get_to (stanza))) - return NULL; - - /* first, we try standard jingle */ - session_node = wocky_node_get_child_ns (iq_node, "jingle", NS_JINGLE032); - - if (session_node != NULL) - { - *dialect = WOCKY_JINGLE_DIALECT_V032; - } - else - { - /* then, we try a bit older jingle version */ - session_node = wocky_node_get_child_ns (iq_node, "jingle", NS_JINGLE015); - - if (session_node != NULL) - { - *dialect = WOCKY_JINGLE_DIALECT_V015; - } - else - { - /* next, we try googletalk */ - session_node = wocky_node_get_child_ns (iq_node, - "session", NS_GOOGLE_SESSION); - - if (session_node != NULL) - { - *dialect = detect_google_dialect (session_node); - google_mode = TRUE; - } - else - { - return NULL; - } - } - } - - if (google_mode) - { - actxt = wocky_node_get_attribute (session_node, "type"); - sid = wocky_node_get_attribute (session_node, "id"); - } - else - { - actxt = wocky_node_get_attribute (session_node, "action"); - sid = wocky_node_get_attribute (session_node, "sid"); - } - - *action = parse_action (actxt); - - return sid; -} - -gboolean -wocky_jingle_session_parse ( - WockyJingleSession *sess, - WockyJingleAction action, - WockyStanza *stanza, - GError **error) -{ - WockyJingleSessionPrivate *priv = sess->priv; - WockyNode *iq_node, *session_node; - const gchar *from, *action_name; - - /* IQ from/to can come in handy */ - from = wocky_stanza_get_from (stanza); - iq_node = wocky_stanza_get_top_node (stanza); - - if (action == WOCKY_JINGLE_ACTION_UNKNOWN) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "unknown session action"); - return FALSE; - } - - action_name = produce_action (action, priv->dialect); - - DEBUG ("jingle action '%s' from '%s' in session '%s' dialect %u state %u", - action_name, from, priv->sid, priv->dialect, priv->state); - - switch (priv->dialect) { - case WOCKY_JINGLE_DIALECT_V032: - session_node = wocky_node_get_child_ns (iq_node, - "jingle", NS_JINGLE032); - break; - case WOCKY_JINGLE_DIALECT_V015: - session_node = wocky_node_get_child_ns (iq_node, - "jingle", NS_JINGLE015); - break; - case WOCKY_JINGLE_DIALECT_GTALK3: - case WOCKY_JINGLE_DIALECT_GTALK4: - session_node = wocky_node_get_child_ns (iq_node, - "session", NS_GOOGLE_SESSION); - break; - default: - /* just to make gcc happy about dealing with default case */ - session_node = NULL; - } - - if (session_node == NULL) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "malformed jingle stanza"); - return FALSE; - } - - if (!wocky_jingle_session_defines_action (sess, action)) - { - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "action '%s' unknown (using dialect %u)", action_name, priv->dialect); - return FALSE; - } - - if (!action_is_allowed (action, priv->state)) - { - g_set_error (error, WOCKY_JINGLE_ERROR, WOCKY_JINGLE_ERROR_OUT_OF_ORDER, - "action '%s' not allowed in current state", action_name); - return FALSE; - } - - wocky_jingle_state_machine_dance (sess, action, session_node, error); - - if (*error != NULL) - return FALSE; - - return TRUE; -} - -WockyStanza * -wocky_jingle_session_new_message (WockyJingleSession *sess, - WockyJingleAction action, WockyNode **sess_node) -{ - WockyJingleSessionPrivate *priv = sess->priv; - WockyStanza *stanza; - WockyNode *session_node; - gchar *el = NULL, *ns = NULL; - gboolean gtalk_mode = FALSE; - - g_return_val_if_fail (action != WOCKY_JINGLE_ACTION_UNKNOWN, NULL); - - g_assert ((action == WOCKY_JINGLE_ACTION_SESSION_INITIATE) || - (priv->state > WOCKY_JINGLE_STATE_PENDING_CREATED)); - g_assert (WOCKY_IS_JINGLE_SESSION (sess)); - - switch (priv->dialect) - { - case WOCKY_JINGLE_DIALECT_V032: - el = "jingle"; - ns = NS_JINGLE032; - break; - case WOCKY_JINGLE_DIALECT_V015: - el = "jingle"; - ns = NS_JINGLE015; - break; - case WOCKY_JINGLE_DIALECT_GTALK3: - case WOCKY_JINGLE_DIALECT_GTALK4: - el = "session"; - ns = NS_GOOGLE_SESSION; - gtalk_mode = TRUE; - break; - case WOCKY_JINGLE_DIALECT_ERROR: - g_assert_not_reached (); - } - - stanza = wocky_stanza_build ( - WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET, - NULL, priv->peer_jid, - '(', el, ':', ns, - '*', &session_node, - ')', NULL); - - wocky_node_set_attributes (session_node, - "initiator", priv->initiator, - (gtalk_mode) ? "id" : "sid", priv->sid, - (gtalk_mode) ? "type" : "action", - produce_action (action, priv->dialect), - NULL); - - if (sess_node != NULL) - *sess_node = session_node; - - return stanza; -} - -typedef void (*ContentMapperFunc) (WockyJingleSession *sess, - WockyJingleContent *c, gpointer user_data); - -static void -_map_initial_contents (WockyJingleSession *sess, ContentMapperFunc mapper, - gpointer user_data) -{ - GList *li; - GList *contents = wocky_jingle_session_get_contents (sess); - - for (li = contents; li; li = li->next) - { - WockyJingleContent *c = WOCKY_JINGLE_CONTENT (li->data); - const gchar *disposition = wocky_jingle_content_get_disposition (c); - - if (!wocky_strdiff (disposition, "session")) - mapper (sess, c, user_data); - } - - g_list_free (contents); -} - -static void -_check_content_ready (WockyJingleSession *sess, - WockyJingleContent *c, gpointer user_data) -{ - gboolean *ready = (gboolean *) user_data; - - if (!wocky_jingle_content_is_ready (c)) - { - *ready = FALSE; - } -} - -static void -_transmit_candidates (WockyJingleSession *sess, - WockyJingleContent *c, - gpointer user_data) -{ - wocky_jingle_content_retransmit_candidates (c, FALSE); -} - -static void -_fill_content (WockyJingleSession *sess, - WockyJingleContent *c, gpointer user_data) -{ - WockyNode *sess_node = user_data; - WockyNode *transport_node; - WockyJingleContentState state; - - wocky_jingle_content_produce_node (c, sess_node, TRUE, TRUE, - &transport_node); - wocky_jingle_content_inject_candidates (c, transport_node); - - g_object_get (c, "state", &state, NULL); - - if (state == WOCKY_JINGLE_CONTENT_STATE_EMPTY) - { - g_object_set (c, "state", WOCKY_JINGLE_CONTENT_STATE_SENT, NULL); - } - else if (state == WOCKY_JINGLE_CONTENT_STATE_NEW) - { - g_object_set (c, "state", WOCKY_JINGLE_CONTENT_STATE_ACKNOWLEDGED, NULL); - } - else - { - DEBUG ("content %p is in state %u", c, state); - g_assert_not_reached (); - } -} - -/** - * wocky_jingle_session_send: - * @sess: a session - * @stanza: (transfer full): a stanza, of which this function will take ownership - * - * A shorthand for sending a Jingle IQ without waiting for the reply. - */ -void -wocky_jingle_session_send (WockyJingleSession *sess, - WockyStanza *stanza) -{ - wocky_porter_send_iq_async (sess->priv->porter, - stanza, NULL, NULL, NULL); - g_object_unref (stanza); -} - -static void -_on_initiate_reply ( - GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - WockyPorter *porter = WOCKY_PORTER (source); - WockyJingleSession *sess = WOCKY_JINGLE_SESSION (user_data); - WockyJingleSessionPrivate *priv = sess->priv; - WockyStanza *reply; - - if (priv->state != WOCKY_JINGLE_STATE_PENDING_INITIATE_SENT) - { - DEBUG ("Ignoring session-initiate reply; session %p is in state %u.", - sess, priv->state); - g_object_unref (sess); - return; - } - - reply = wocky_porter_send_iq_finish (porter, result, NULL); - if (reply != NULL && - !wocky_stanza_extract_errors (reply, NULL, NULL, NULL, NULL)) - { - set_state (sess, WOCKY_JINGLE_STATE_PENDING_INITIATED, 0, NULL); - - if (priv->dialect != WOCKY_JINGLE_DIALECT_V032) - { - /* If this is a dialect that doesn't support <ringing/>, we treat the - * session-initiate being acked as the cue to say we're ringing. - */ - priv->remote_ringing = TRUE; - g_signal_emit (sess, signals[REMOTE_STATE_CHANGED], 0); - } - } - else - { - set_state (sess, WOCKY_JINGLE_STATE_ENDED, WOCKY_JINGLE_REASON_UNKNOWN, - NULL); - } - - g_clear_object (&reply); - g_object_unref (sess); -} - -static void -_on_accept_reply ( - GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - WockyPorter *porter = WOCKY_PORTER (source); - WockyJingleSession *sess = WOCKY_JINGLE_SESSION (user_data); - WockyJingleSessionPrivate *priv = sess->priv; - WockyStanza *reply; - - if (priv->state != WOCKY_JINGLE_STATE_PENDING_ACCEPT_SENT) - { - DEBUG ("Ignoring session-accept reply; session %p is in state %u.", - sess, priv->state); - g_object_unref (sess); - return; - } - - reply = wocky_porter_send_iq_finish (porter, result, NULL); - if (reply != NULL && - !wocky_stanza_extract_errors (reply, NULL, NULL, NULL, NULL)) - { - set_state (sess, WOCKY_JINGLE_STATE_ACTIVE, 0, NULL); - wocky_jingle_session_send_rtp_info (sess, "active"); - } - else - { - set_state (sess, WOCKY_JINGLE_STATE_ENDED, WOCKY_JINGLE_REASON_UNKNOWN, - NULL); - } - - g_clear_object (&reply); - g_object_unref (sess); -} - -static void -try_session_initiate_or_accept (WockyJingleSession *sess) -{ - WockyJingleSessionPrivate *priv = sess->priv; - WockyStanza *msg; - WockyNode *sess_node; - gboolean contents_ready = TRUE; - WockyJingleAction action; - WockyJingleState new_state; - GAsyncReadyCallback handler; - - DEBUG ("Trying initiate or accept"); - - /* If there are no contents yet, we shouldn't have been called at all. */ - g_assert (g_hash_table_size (priv->initiator_contents) + - g_hash_table_size (priv->responder_contents) > 0); - - if (priv->local_initiator) - { - if (priv->state != WOCKY_JINGLE_STATE_PENDING_CREATED) - { - DEBUG ("session is in state %u, won't try to initiate", priv->state); - return; - } - - if (!priv->locally_accepted) - { - DEBUG ("session not locally accepted yet, not initiating"); - return; - } - - g_signal_emit (sess, signals[ABOUT_TO_INITIATE], 0); - - action = WOCKY_JINGLE_ACTION_SESSION_INITIATE; - new_state = WOCKY_JINGLE_STATE_PENDING_INITIATE_SENT; - handler = _on_initiate_reply; - } - else - { - if (priv->state != WOCKY_JINGLE_STATE_PENDING_INITIATED) - { - DEBUG ("session is in state %u, won't try to accept", priv->state); - return; - } - - if (!priv->locally_accepted) - { - DEBUG ("session not locally accepted yet, not accepting"); - return; - } - - action = WOCKY_JINGLE_ACTION_SESSION_ACCEPT; - new_state = WOCKY_JINGLE_STATE_PENDING_ACCEPT_SENT; - handler = _on_accept_reply; - } - - _map_initial_contents (sess, _check_content_ready, &contents_ready); - - DEBUG ("Contents are ready: %s", contents_ready ? "yes" : "no"); - - if (!contents_ready) - { - DEBUG ("Contents not yet ready, not initiating/accepting now.."); - return; - } - - msg = wocky_jingle_session_new_message (sess, action, &sess_node); - - if (priv->dialect == WOCKY_JINGLE_DIALECT_GTALK3) - { - gboolean has_video = FALSE; - gboolean has_audio = FALSE; - GHashTableIter iter; - gpointer value; - - g_hash_table_iter_init (&iter, priv->initiator_contents); - while (g_hash_table_iter_next (&iter, NULL, &value)) - { - WockyJingleMediaType type; - - g_object_get (value, "media-type", &type, NULL); - - if (type == WOCKY_JINGLE_MEDIA_TYPE_VIDEO) - { - has_video = TRUE; - } - else if (type == WOCKY_JINGLE_MEDIA_TYPE_AUDIO) - { - has_audio = TRUE; - } - } - - if (has_video || has_audio) - { - sess_node = wocky_node_add_child_ns_q (sess_node, "description", - g_quark_from_static_string (has_video - ? NS_GOOGLE_SESSION_VIDEO : NS_GOOGLE_SESSION_PHONE)); - } - } - - - _map_initial_contents (sess, _fill_content, sess_node); - wocky_porter_send_iq_async (priv->porter, - msg, NULL, handler, g_object_ref (sess)); - g_object_unref (msg); - set_state (sess, new_state, 0, NULL); - - /* now all initial contents can transmit their candidates */ - _map_initial_contents (sess, _transmit_candidates, NULL); -} - -/** - * set_state: - * @sess: a jingle session - * @state: the new state for the session - * @termination_reason: if @state is WOCKY_JINGLE_STATE_ENDED, the reason the session - * ended. Otherwise, must be WOCKY_JINGLE_REASON_UNKNOWN. - * @text: if @state is WOCKY_JINGLE_STATE_ENDED, the human-readable reason the session - * ended. - */ -static void -set_state (WockyJingleSession *sess, - WockyJingleState state, - WockyJingleReason termination_reason, - const gchar *text) -{ - WockyJingleSessionPrivate *priv = sess->priv; - - if (state <= priv->state) - { - DEBUG ("ignoring request to set state from %u back to %u", priv->state, state); - return; - } - - if (state != WOCKY_JINGLE_STATE_ENDED) - g_assert (termination_reason == WOCKY_JINGLE_REASON_UNKNOWN); - - DEBUG ("Setting state of JingleSession: %p (priv = %p) from %u to %u", sess, priv, priv->state, state); - - priv->state = state; - g_object_notify (G_OBJECT (sess), "state"); - - /* If we have an outstanding "you're on hold notification", send it */ - if (priv->local_hold && - state >= WOCKY_JINGLE_STATE_PENDING_INITIATED && - state < WOCKY_JINGLE_STATE_ENDED) - wocky_jingle_session_send_held (sess); - - if (state == WOCKY_JINGLE_STATE_ENDED) - g_signal_emit (sess, signals[TERMINATED], 0, priv->locally_terminated, - termination_reason, text); -} - -void -wocky_jingle_session_accept (WockyJingleSession *sess) -{ - WockyJingleSessionPrivate *priv = sess->priv; - - priv->locally_accepted = TRUE; - - try_session_initiate_or_accept (sess); -} - -const gchar * -wocky_jingle_session_get_reason_name (WockyJingleReason reason) -{ - GEnumClass *klass = g_type_class_ref (wocky_jingle_reason_get_type ()); - GEnumValue *enum_value = g_enum_get_value (klass, (gint) reason); - - g_return_val_if_fail (enum_value != NULL, NULL); - - return enum_value->value_nick; -} - -gboolean -wocky_jingle_session_terminate (WockyJingleSession *sess, - WockyJingleReason reason, - const gchar *text, - GError **error) -{ - WockyJingleSessionPrivate *priv = sess->priv; - const gchar *reason_elt; - - if (priv->state == WOCKY_JINGLE_STATE_ENDED) - { - DEBUG ("session already terminated, ignoring terminate request"); - return TRUE; - } - - if (reason == WOCKY_JINGLE_REASON_UNKNOWN) - reason = (priv->state == WOCKY_JINGLE_STATE_ACTIVE) ? - WOCKY_JINGLE_REASON_SUCCESS : WOCKY_JINGLE_REASON_CANCEL; - - reason_elt = wocky_jingle_session_get_reason_name (reason); - - if (priv->state != WOCKY_JINGLE_STATE_PENDING_CREATED) - { - WockyNode *session_node; - WockyStanza *msg = wocky_jingle_session_new_message (sess, - WOCKY_JINGLE_ACTION_SESSION_TERMINATE, &session_node); - - if (priv->dialect == WOCKY_JINGLE_DIALECT_V032 && reason_elt != NULL) - { - WockyNode *r = wocky_node_add_child_with_content (session_node, "reason", - NULL); - - wocky_node_add_child (r, reason_elt); - - if (text != NULL && *text != '\0') - wocky_node_add_child_with_content (r, "text", text); - } - - wocky_jingle_session_send (sess, msg); - } - - /* NOTE: on "terminated", jingle factory and media channel will unref - * it, bringing refcount to 0, so dispose will be called, and it - * takes care of cleanup */ - - DEBUG ("we are terminating this session"); - priv->locally_terminated = TRUE; - set_state (sess, WOCKY_JINGLE_STATE_ENDED, reason, text); - - return TRUE; -} - -static void -_foreach_count_active_contents (gpointer key, gpointer value, gpointer user_data) -{ - WockyJingleContent *c = value; - guint *n_contents = user_data; - WockyJingleContentState state; - - g_object_get (c, "state", &state, NULL); - if ((state >= WOCKY_JINGLE_CONTENT_STATE_NEW) && - (state < WOCKY_JINGLE_CONTENT_STATE_REMOVING)) - { - *n_contents = *n_contents + 1; - } -} - -static gboolean -count_active_contents (WockyJingleSession *sess) -{ - WockyJingleSessionPrivate *priv = sess->priv; - guint n_contents = 0; - - g_hash_table_foreach (priv->initiator_contents, _foreach_count_active_contents, - &n_contents); - g_hash_table_foreach (priv->responder_contents, _foreach_count_active_contents, - &n_contents); - - return n_contents; -} - -static void -content_removed_cb (WockyJingleContent *c, gpointer user_data) -{ - WockyJingleSession *sess = WOCKY_JINGLE_SESSION (user_data); - WockyJingleSessionPrivate *priv = sess->priv; - const gchar *name = wocky_jingle_content_get_name (c); - - if (wocky_jingle_content_creator_is_initiator (c)) - g_hash_table_remove (priv->initiator_contents, name); - else - g_hash_table_remove (priv->responder_contents, name); - - if (priv->state == WOCKY_JINGLE_STATE_ENDED) - return; - - if (count_active_contents (sess) == 0) - { - wocky_jingle_session_terminate (sess, - WOCKY_JINGLE_REASON_UNKNOWN, NULL, NULL); - } - else - { - /* It's possible the content now removed was - * blocking us from creating or accepting the - * session, so we might as well try now. */ - try_session_initiate_or_accept (sess); - } -} - - -void -wocky_jingle_session_remove_content (WockyJingleSession *sess, - WockyJingleContent *c) -{ - if (count_active_contents (sess) > 1) - { - wocky_jingle_content_remove (c, TRUE); - } - else - { - /* session will be terminated when the content gets marked as removed */ - DEBUG ("called for last active content, doing session-terminate instead"); - wocky_jingle_content_remove (c, FALSE); - } -} - -WockyJingleContent * -wocky_jingle_session_add_content (WockyJingleSession *sess, - WockyJingleMediaType mtype, - WockyJingleContentSenders senders, - const gchar *name, - const gchar *content_ns, - const gchar *transport_ns) -{ - WockyJingleSessionPrivate *priv = sess->priv; - WockyJingleContent *c; - GType content_type; - GHashTable *contents = priv->local_initiator ? priv->initiator_contents - : priv->responder_contents; - guint id = g_hash_table_size (contents) + 1; - gchar *cname = NULL; - - if (name == NULL || *name == '\0') - name = (mtype == WOCKY_JINGLE_MEDIA_TYPE_AUDIO ? "Audio" : "Video"); - - cname = g_strdup (name); - - while (g_hash_table_lookup (priv->initiator_contents, cname) != NULL - || g_hash_table_lookup (priv->responder_contents, cname) != NULL) - { - g_free (cname); - cname = g_strdup_printf ("%s_%d", name, id++); - } - - content_type = wocky_jingle_factory_lookup_content_type ( - wocky_jingle_session_get_factory (sess), - content_ns); - - g_assert (content_type != 0); - - c = create_content (sess, content_type, mtype, senders, - content_ns, transport_ns, cname, NULL, NULL); - - /* The new content better have ended up in the set we thought it would... */ - g_assert (g_hash_table_lookup (contents, cname) != NULL); - - g_free (cname); - - return c; -} - -/* Get any content. Either we're in google mode (so we only have one content - * anyways), or we just need any content type to figure out what use case - * we're in (media, ft, etc). */ -static WockyJingleContent * -_get_any_content (WockyJingleSession *session) -{ - WockyJingleContent *c; - - GList *li = wocky_jingle_session_get_contents (session); - - if (li == NULL) - return NULL; - - c = li->data; - g_list_free (li); - - return c; -} - -/* Note: if there are multiple content types, not guaranteed which one will - * be returned. Typically, the same GType will know how to handle related - * contents found in a session (e.g. media-rtp for audio/video), so that - * should not be a problem. Returns 0 if there are no contents yet. */ -GType -wocky_jingle_session_get_content_type (WockyJingleSession *sess) -{ - WockyJingleContent *c = _get_any_content (sess); - - if (c == NULL) - return 0; - - return G_OBJECT_TYPE (c); -} - -/* FIXME: probably should make this into a property */ -GList * -wocky_jingle_session_get_contents (WockyJingleSession *sess) -{ - WockyJingleSessionPrivate *priv = sess->priv; - - return g_list_concat (g_hash_table_get_values (priv->initiator_contents), - g_hash_table_get_values (priv->responder_contents)); -} - -const gchar * -wocky_jingle_session_get_peer_resource (WockyJingleSession *sess) -{ - return sess->priv->peer_resource; -} - -const gchar * -wocky_jingle_session_get_initiator (WockyJingleSession *sess) -{ - return sess->priv->initiator; -} - -const gchar * -wocky_jingle_session_get_sid (WockyJingleSession *sess) -{ - return sess->priv->sid; -} - -static void -content_ready_cb (WockyJingleContent *c, gpointer user_data) -{ - WockyJingleSession *sess = WOCKY_JINGLE_SESSION (user_data); - const gchar *disposition; - - DEBUG ("called"); - - disposition = wocky_jingle_content_get_disposition (c); - /* This assertion is actually safe, because 'ready' is only emitted by - * contents with disposition "session". But this is crazy. - */ - g_assert (!wocky_strdiff (disposition, "session")); - - try_session_initiate_or_accept (sess); -} - -static void -wocky_jingle_session_send_rtp_info (WockyJingleSession *sess, - const gchar *name) -{ - WockyStanza *message; - WockyNode *jingle; - - if (!wocky_jingle_session_defines_action (sess, WOCKY_JINGLE_ACTION_SESSION_INFO)) - { - DEBUG ("Not sending <%s/>; not using modern Jingle", name); - return; - } - - message = wocky_jingle_session_new_message (sess, - WOCKY_JINGLE_ACTION_SESSION_INFO, &jingle); - wocky_node_add_child_ns_q (jingle, name, - g_quark_from_static_string (NS_JINGLE_RTP_INFO)); - - /* This is just informational, so ignoring the reply. */ - wocky_jingle_session_send (sess, message); -} - -static void -wocky_jingle_session_send_held (WockyJingleSession *sess) -{ - const gchar *s = (sess->priv->local_hold ? "hold" : "unhold"); - - wocky_jingle_session_send_rtp_info (sess, s); -} - -void -wocky_jingle_session_set_local_hold (WockyJingleSession *sess, - gboolean held) -{ - g_object_set (sess, "local-hold", held, NULL); -} - -gboolean -wocky_jingle_session_get_remote_hold (WockyJingleSession *sess) -{ - g_assert (WOCKY_IS_JINGLE_SESSION (sess)); - - return sess->priv->remote_hold; -} - -gboolean -wocky_jingle_session_get_remote_ringing (WockyJingleSession *sess) -{ - g_assert (WOCKY_IS_JINGLE_SESSION (sess)); - - return sess->priv->remote_ringing; -} - -gboolean -wocky_jingle_session_can_modify_contents (WockyJingleSession *sess) -{ - return !WOCKY_JINGLE_DIALECT_IS_GOOGLE (sess->priv->dialect) && - !wocky_jingle_session_peer_has_cap (sess, QUIRK_GOOGLE_WEBMAIL_CLIENT); -} - -WockyJingleDialect -wocky_jingle_session_get_dialect (WockyJingleSession *sess) -{ - return sess->priv->dialect; -} - -WockyContact * -wocky_jingle_session_get_peer_contact (WockyJingleSession *self) -{ - return self->priv->peer_contact; -} - -/* - * wocky_jingle_session_get_peer_jid: - * @sess: a jingle session - * - * Returns: the full JID of the remote contact. - */ -const gchar * -wocky_jingle_session_get_peer_jid (WockyJingleSession *sess) -{ - return sess->priv->peer_jid; -} - -WockyJingleFactory * -wocky_jingle_session_get_factory (WockyJingleSession *self) -{ - return self->priv->jingle_factory; -} - -WockyPorter * -wocky_jingle_session_get_porter (WockyJingleSession *self) -{ - return self->priv->porter; -} diff --git a/src/jingle-session.h b/src/jingle-session.h deleted file mode 100644 index c49ede2f7..000000000 --- a/src/jingle-session.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * jingle-session.h - Header for WockyJingleSession - * Copyright (C) 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 - */ - -#ifndef __JINGLE_SESSION_H__ -#define __JINGLE_SESSION_H__ - -#include <glib-object.h> -#include <wocky/wocky.h> - -#include "jingle-content.h" -#include "jingle-factory.h" -#include "jingle-types.h" - -G_BEGIN_DECLS - -typedef enum -{ - MODE_GOOGLE, - MODE_JINGLE -} GabbleMediaSessionMode; - -typedef struct _WockyJingleSessionClass WockyJingleSessionClass; - -GType wocky_jingle_session_get_type (void); - -/* TYPE MACROS */ -#define WOCKY_TYPE_JINGLE_SESSION \ - (wocky_jingle_session_get_type ()) -#define WOCKY_JINGLE_SESSION(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), WOCKY_TYPE_JINGLE_SESSION, \ - WockyJingleSession)) -#define WOCKY_JINGLE_SESSION_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), WOCKY_TYPE_JINGLE_SESSION, \ - WockyJingleSessionClass)) -#define WOCKY_IS_JINGLE_SESSION(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), WOCKY_TYPE_JINGLE_SESSION)) -#define WOCKY_IS_JINGLE_SESSION_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), WOCKY_TYPE_JINGLE_SESSION)) -#define WOCKY_JINGLE_SESSION_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), WOCKY_TYPE_JINGLE_SESSION, \ - WockyJingleSessionClass)) - -struct _WockyJingleSessionClass { - GObjectClass parent_class; -}; - -typedef struct _WockyJingleSessionPrivate WockyJingleSessionPrivate; - -struct _WockyJingleSession { - GObject parent; - WockyJingleSessionPrivate *priv; -}; - -WockyJingleSession *wocky_jingle_session_new ( - WockyJingleFactory *factory, - WockyPorter *porter, - const gchar *session_id, - gboolean local_initiator, - WockyContact *peer, - WockyJingleDialect dialect, - gboolean local_hold); - -const gchar * wocky_jingle_session_detect (WockyStanza *stanza, - WockyJingleAction *action, WockyJingleDialect *dialect); -gboolean wocky_jingle_session_parse (WockyJingleSession *sess, - WockyJingleAction action, WockyStanza *stanza, GError **error); -WockyStanza *wocky_jingle_session_new_message (WockyJingleSession *sess, - WockyJingleAction action, WockyNode **sess_node); - -void wocky_jingle_session_accept (WockyJingleSession *sess); -gboolean wocky_jingle_session_terminate (WockyJingleSession *sess, - WockyJingleReason reason, - const gchar *text, - GError **error); -void wocky_jingle_session_remove_content (WockyJingleSession *sess, - WockyJingleContent *c); - -WockyJingleContent * -wocky_jingle_session_add_content (WockyJingleSession *sess, - WockyJingleMediaType mtype, - WockyJingleContentSenders senders, - const char *name, - const gchar *content_ns, - const gchar *transport_ns); - -GType wocky_jingle_session_get_content_type (WockyJingleSession *); -GList *wocky_jingle_session_get_contents (WockyJingleSession *sess); -const gchar *wocky_jingle_session_get_peer_resource ( - WockyJingleSession *sess); -const gchar *wocky_jingle_session_get_initiator ( - WockyJingleSession *sess); -const gchar *wocky_jingle_session_get_sid (WockyJingleSession *sess); -WockyJingleDialect wocky_jingle_session_get_dialect (WockyJingleSession *sess); - -gboolean wocky_jingle_session_can_modify_contents (WockyJingleSession *sess); -gboolean wocky_jingle_session_peer_has_cap ( - WockyJingleSession *self, - const gchar *cap_or_quirk); - -void wocky_jingle_session_send ( - WockyJingleSession *sess, - WockyStanza *stanza); - -void wocky_jingle_session_set_local_hold (WockyJingleSession *sess, - gboolean held); - -gboolean wocky_jingle_session_get_remote_hold (WockyJingleSession *sess); - -gboolean wocky_jingle_session_get_remote_ringing (WockyJingleSession *sess); - -gboolean wocky_jingle_session_defines_action (WockyJingleSession *sess, - WockyJingleAction action); - -WockyContact *wocky_jingle_session_get_peer_contact (WockyJingleSession *self); -const gchar *wocky_jingle_session_get_peer_jid (WockyJingleSession *sess); - -const gchar *wocky_jingle_session_get_reason_name (WockyJingleReason reason); - -WockyJingleFactory *wocky_jingle_session_get_factory (WockyJingleSession *self); -WockyPorter *wocky_jingle_session_get_porter (WockyJingleSession *self); - -#endif /* __JINGLE_SESSION_H__ */ - diff --git a/src/jingle-transport-google.c b/src/jingle-transport-google.c deleted file mode 100644 index 59e166d53..000000000 --- a/src/jingle-transport-google.c +++ /dev/null @@ -1,644 +0,0 @@ -/* - * jingle-transport-google.c - Source for WockyJingleTransportGoogle - * - * Copyright (C) 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 "config.h" -#include "jingle-transport-google.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <glib.h> - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA - -#include "debug.h" -#include "jingle-content.h" -#include "jingle-factory.h" -#include "jingle-session.h" -#include "namespaces.h" - -static void -transport_iface_init (gpointer g_iface, gpointer iface_data); - -G_DEFINE_TYPE_WITH_CODE (WockyJingleTransportGoogle, - wocky_jingle_transport_google, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (WOCKY_TYPE_JINGLE_TRANSPORT_IFACE, - transport_iface_init)); - -/* signal enum */ -enum -{ - NEW_CANDIDATES, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -/* properties */ -enum -{ - PROP_CONTENT = 1, - PROP_TRANSPORT_NS, - PROP_STATE, - LAST_PROPERTY -}; - -struct _WockyJingleTransportGooglePrivate -{ - WockyJingleContent *content; - WockyJingleTransportState state; - gchar *transport_ns; - - /* Component names or jingle-share transport 'channels' - g_strdup'd component name => GINT_TO_POINTER (component id) */ - GHashTable *component_names; - - GList *local_candidates; - - /* A pointer into "local_candidates" list to mark the - * candidates that are still not transmitted, or NULL - * if all of them are transmitted. */ - - GList *pending_candidates; - GList *remote_candidates; - gboolean dispose_has_run; -}; - -static void -wocky_jingle_transport_google_init (WockyJingleTransportGoogle *obj) -{ - WockyJingleTransportGooglePrivate *priv = - G_TYPE_INSTANCE_GET_PRIVATE (obj, WOCKY_TYPE_JINGLE_TRANSPORT_GOOGLE, - WockyJingleTransportGooglePrivate); - obj->priv = priv; - - priv->component_names = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, NULL); - - priv->dispose_has_run = FALSE; -} - -static void -wocky_jingle_transport_google_dispose (GObject *object) -{ - WockyJingleTransportGoogle *trans = WOCKY_JINGLE_TRANSPORT_GOOGLE (object); - WockyJingleTransportGooglePrivate *priv = trans->priv; - - if (priv->dispose_has_run) - return; - - DEBUG ("dispose called"); - priv->dispose_has_run = TRUE; - - g_hash_table_unref (priv->component_names); - priv->component_names = NULL; - - jingle_transport_free_candidates (priv->remote_candidates); - priv->remote_candidates = NULL; - - jingle_transport_free_candidates (priv->local_candidates); - priv->local_candidates = NULL; - - g_free (priv->transport_ns); - priv->transport_ns = NULL; - - if (G_OBJECT_CLASS (wocky_jingle_transport_google_parent_class)->dispose) - G_OBJECT_CLASS (wocky_jingle_transport_google_parent_class)->dispose (object); -} - -static void -wocky_jingle_transport_google_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - WockyJingleTransportGoogle *trans = WOCKY_JINGLE_TRANSPORT_GOOGLE (object); - WockyJingleTransportGooglePrivate *priv = trans->priv; - - switch (property_id) { - case PROP_CONTENT: - g_value_set_object (value, priv->content); - break; - case PROP_TRANSPORT_NS: - g_value_set_string (value, priv->transport_ns); - break; - case PROP_STATE: - g_value_set_uint (value, priv->state); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -wocky_jingle_transport_google_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - WockyJingleTransportGoogle *trans = WOCKY_JINGLE_TRANSPORT_GOOGLE (object); - WockyJingleTransportGooglePrivate *priv = trans->priv; - - switch (property_id) { - case PROP_CONTENT: - priv->content = g_value_get_object (value); - break; - case PROP_TRANSPORT_NS: - g_free (priv->transport_ns); - priv->transport_ns = g_value_dup_string (value); - break; - case PROP_STATE: - priv->state = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -wocky_jingle_transport_google_class_init (WockyJingleTransportGoogleClass *cls) -{ - GObjectClass *object_class = G_OBJECT_CLASS (cls); - GParamSpec *param_spec; - - g_type_class_add_private (cls, sizeof (WockyJingleTransportGooglePrivate)); - - object_class->get_property = wocky_jingle_transport_google_get_property; - object_class->set_property = wocky_jingle_transport_google_set_property; - object_class->dispose = wocky_jingle_transport_google_dispose; - - /* property definitions */ - param_spec = g_param_spec_object ("content", "WockyJingleContent object", - "Jingle content object using this transport.", - WOCKY_TYPE_JINGLE_CONTENT, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_CONTENT, param_spec); - - param_spec = g_param_spec_string ("transport-ns", "Transport namespace", - "Namespace identifying the transport type.", - NULL, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_TRANSPORT_NS, param_spec); - - param_spec = g_param_spec_uint ("state", - "Connection state for the transport.", - "Enum specifying the connection state of the transport.", - WOCKY_JINGLE_TRANSPORT_STATE_DISCONNECTED, - WOCKY_JINGLE_TRANSPORT_STATE_CONNECTED, - WOCKY_JINGLE_TRANSPORT_STATE_DISCONNECTED, - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_STATE, param_spec); - - /* signal definitions */ - signals[NEW_CANDIDATES] = g_signal_new ( - "new-candidates", - G_TYPE_FROM_CLASS (cls), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - -} - -static void -parse_candidates (WockyJingleTransportIface *obj, - WockyNode *transport_node, GError **error) -{ - WockyJingleTransportGoogle *t = WOCKY_JINGLE_TRANSPORT_GOOGLE (obj); - WockyJingleTransportGooglePrivate *priv = t->priv; - GList *candidates = NULL; - WockyNodeIter i; - WockyNode *node; - - wocky_node_iter_init (&i, transport_node, "candidate", NULL); - while (wocky_node_iter_next (&i, &node)) - { - const gchar *name, *address, *user, *pass, *str; - guint port, net, gen, component; - int pref; - WockyJingleTransportProtocol proto; - WockyJingleCandidateType ctype; - WockyJingleCandidate *c; - - name = wocky_node_get_attribute (node, "name"); - if (name == NULL) - break; - - if (!g_hash_table_lookup_extended (priv->component_names, name, - NULL, NULL)) - { - DEBUG ("component name %s unknown to this transport", name); - continue; - } - - component = GPOINTER_TO_INT (g_hash_table_lookup (priv->component_names, - name)); - address = wocky_node_get_attribute (node, "address"); - if (address == NULL) - break; - - str = wocky_node_get_attribute (node, "port"); - if (str == NULL) - break; - port = atoi (str); - - str = wocky_node_get_attribute (node, "protocol"); - if (str == NULL) - break; - - if (!wocky_strdiff (str, "udp")) - { - proto = WOCKY_JINGLE_TRANSPORT_PROTOCOL_UDP; - } - else if (!wocky_strdiff (str, "tcp")) - { - /* candiates on port 443 must be "ssltcp" */ - if (port == 443) - break; - - proto = WOCKY_JINGLE_TRANSPORT_PROTOCOL_TCP; - } - else if (!wocky_strdiff (str, "ssltcp")) - { - /* "ssltcp" must use port 443 */ - if (port != 443) - break; - - /* we really don't care about "ssltcp" otherwise */ - proto = WOCKY_JINGLE_TRANSPORT_PROTOCOL_TCP; - } - else - { - /* unknown protocol */ - DEBUG ("unknown protocol: %s", str); - break; - } - - str = wocky_node_get_attribute (node, "preference"); - if (str == NULL) - break; - - pref = g_ascii_strtod (str, NULL) * 65536; - - str = wocky_node_get_attribute (node, "type"); - if (str == NULL) - break; - - if (!wocky_strdiff (str, "local")) - { - ctype = WOCKY_JINGLE_CANDIDATE_TYPE_LOCAL; - } - else if (!wocky_strdiff (str, "stun")) - { - ctype = WOCKY_JINGLE_CANDIDATE_TYPE_STUN; - } - else if (!wocky_strdiff (str, "relay")) - { - ctype = WOCKY_JINGLE_CANDIDATE_TYPE_RELAY; - } - else - { - /* unknown candidate type */ - DEBUG ("unknown candidate type: %s", str); - break; - } - - user = wocky_node_get_attribute (node, "username"); - if (user == NULL) - break; - - pass = wocky_node_get_attribute (node, "password"); - if (pass == NULL) - break; - - str = wocky_node_get_attribute (node, "network"); - if (str == NULL) - break; - net = atoi (str); - - str = wocky_node_get_attribute (node, "generation"); - if (str == NULL) - break; - gen = atoi (str); - - str = wocky_node_get_attribute (node, "component"); - if (str != NULL) - component = atoi (str); - - c = wocky_jingle_candidate_new (proto, ctype, NULL, component, - address, port, gen, pref, user, pass, net); - - candidates = g_list_append (candidates, c); - } - - if (wocky_node_iter_next (&i, NULL)) - { - DEBUG ("not all nodes were processed, reporting error"); - /* rollback these */ - jingle_transport_free_candidates (candidates); - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "invalid candidate"); - return; - } - - DEBUG ("emitting %d new remote candidates", g_list_length (candidates)); - - g_signal_emit (obj, signals[NEW_CANDIDATES], 0, candidates); - - /* append them to the known remote candidates */ - priv->remote_candidates = g_list_concat (priv->remote_candidates, candidates); -} - -static void -transmit_candidates (WockyJingleTransportGoogle *transport, - const gchar *name, - GList *candidates) -{ - WockyJingleTransportGooglePrivate *priv = transport->priv; - GList *li; - WockyStanza *msg; - WockyNode *trans_node, *sess_node; - - if (candidates == NULL) - return; - - msg = wocky_jingle_session_new_message (priv->content->session, - WOCKY_JINGLE_ACTION_TRANSPORT_INFO, &sess_node); - - wocky_jingle_content_produce_node (priv->content, sess_node, FALSE, TRUE, - &trans_node); - - for (li = candidates; li; li = li->next) - { - WockyJingleCandidate *c = (WockyJingleCandidate *) li->data; - gchar port_str[16], pref_str[16], comp_str[16], *type_str, *proto_str; - WockyNode *cnode; - - sprintf (port_str, "%d", c->port); - sprintf (pref_str, "%lf", c->preference / 65536.0); - sprintf (comp_str, "%d", c->component); - - switch (c->type) { - case WOCKY_JINGLE_CANDIDATE_TYPE_LOCAL: - type_str = "local"; - break; - case WOCKY_JINGLE_CANDIDATE_TYPE_STUN: - type_str = "stun"; - break; - case WOCKY_JINGLE_CANDIDATE_TYPE_RELAY: - type_str = "relay"; - break; - default: - g_assert_not_reached (); - } - - switch (c->protocol) { - case WOCKY_JINGLE_TRANSPORT_PROTOCOL_UDP: - proto_str = "udp"; - break; - case WOCKY_JINGLE_TRANSPORT_PROTOCOL_TCP: - if ((c->port == 443) && (c->type == WOCKY_JINGLE_CANDIDATE_TYPE_RELAY)) - proto_str = "ssltcp"; - else - proto_str = "tcp"; - break; - default: - g_assert_not_reached (); - } - - cnode = wocky_node_add_child (trans_node, "candidate"); - wocky_node_set_attributes (cnode, - "address", c->address, - "port", port_str, - "username", c->username, - "password", c->password != NULL ? c->password : "", - "preference", pref_str, - "protocol", proto_str, - "type", type_str, - "component", comp_str, - "network", "0", - "generation", "0", - NULL); - - wocky_node_set_attribute (cnode, "name", name); - } - - wocky_porter_send_iq_async ( - wocky_jingle_session_get_porter (priv->content->session), msg, - NULL, NULL, NULL); - g_object_unref (msg); -} - -/* Groups @candidates into rtp and rtcp and sends each group in its own - * transport-info. This works around old Gabble, which rejected transport-info - * stanzas containing non-rtp candidates. - */ -static void -group_and_transmit_candidates (WockyJingleTransportGoogle *transport, - GList *candidates) -{ - WockyJingleTransportGooglePrivate *priv = transport->priv; - GList *all_candidates = NULL; - WockyJingleMediaType media; - GList *li; - GList *cands; - - for (li = candidates; li != NULL; li = g_list_next (li)) - { - WockyJingleCandidate *c = li->data; - - for (cands = all_candidates; cands != NULL; cands = g_list_next (cands)) - { - WockyJingleCandidate *c2 = ((GList *) cands->data)->data; - - if (c->component == c2->component) - { - break; - } - } - if (cands == NULL) - { - all_candidates = g_list_prepend (all_candidates, NULL); - cands = all_candidates; - } - - cands->data = g_list_prepend (cands->data, c); - } - - g_object_get (priv->content, "media-type", &media, NULL); - - for (cands = all_candidates; cands != NULL; cands = g_list_next (cands)) - { - GHashTableIter iter; - gpointer key, value; - gchar *name = NULL; - WockyJingleCandidate *c = ((GList *) cands->data)->data; - - g_hash_table_iter_init (&iter, priv->component_names); - while (g_hash_table_iter_next (&iter, &key, &value)) - { - if (GPOINTER_TO_INT (value) == c->component) - { - name = key; - break; - } - } - if (name) - { - transmit_candidates (transport, name, cands->data); - } - else - { - DEBUG ("Ignoring unknown component %d", c->component); - } - g_list_free (cands->data); - } - - g_list_free (all_candidates); -} - -/* Takes in a list of slice-allocated WockyJingleCandidate structs */ -static void -new_local_candidates (WockyJingleTransportIface *obj, GList *new_candidates) -{ - WockyJingleTransportGoogle *transport = - WOCKY_JINGLE_TRANSPORT_GOOGLE (obj); - WockyJingleTransportGooglePrivate *priv = transport->priv; - - priv->local_candidates = g_list_concat (priv->local_candidates, - new_candidates); - - /* If all previous candidates have been signalled, set the new - * ones as pending. If there are existing pending candidates, - * the new ones will just be appended to that list. */ - if (priv->pending_candidates == NULL) - priv->pending_candidates = new_candidates; -} - -static void -send_candidates (WockyJingleTransportIface *obj, gboolean all) -{ - WockyJingleTransportGoogle *transport = - WOCKY_JINGLE_TRANSPORT_GOOGLE (obj); - WockyJingleTransportGooglePrivate *priv = transport->priv; - - if (all) - { - /* for gtalk3, we might have to retransmit everything */ - group_and_transmit_candidates (transport, priv->local_candidates); - priv->pending_candidates = NULL; - } - else - { - /* If the content became ready after we wanted to transmit - * these originally, we are called to transmit when it them */ - if (priv->pending_candidates != NULL) - { - group_and_transmit_candidates (transport, priv->pending_candidates); - priv->pending_candidates = NULL; - } - } -} - -static GList * -get_local_candidates (WockyJingleTransportIface *iface) -{ - WockyJingleTransportGoogle *transport = - WOCKY_JINGLE_TRANSPORT_GOOGLE (iface); - WockyJingleTransportGooglePrivate *priv = transport->priv; - - return priv->local_candidates; -} - -static GList * -get_remote_candidates (WockyJingleTransportIface *iface) -{ - WockyJingleTransportGoogle *transport = - WOCKY_JINGLE_TRANSPORT_GOOGLE (iface); - WockyJingleTransportGooglePrivate *priv = transport->priv; - - return priv->remote_candidates; -} - -static WockyJingleTransportType -get_transport_type (void) -{ - return JINGLE_TRANSPORT_GOOGLE_P2P; -} - -static void -transport_iface_init (gpointer g_iface, gpointer iface_data) -{ - WockyJingleTransportIfaceClass *klass = (WockyJingleTransportIfaceClass *) g_iface; - - klass->parse_candidates = parse_candidates; - - klass->new_local_candidates = new_local_candidates; - /* Not implementing inject_candidates: gtalk-p2p candidates are always sent - * in transport-info or equivalent. - */ - klass->send_candidates = send_candidates; - - klass->get_remote_candidates = get_remote_candidates; - klass->get_local_candidates = get_local_candidates; - klass->get_transport_type = get_transport_type; -} - -/* Returns FALSE if the component name already exists */ -gboolean -jingle_transport_google_set_component_name ( - WockyJingleTransportGoogle *transport, - const gchar *name, guint component_id) -{ - WockyJingleTransportGooglePrivate *priv = transport->priv; - - if (g_hash_table_lookup_extended (priv->component_names, name, NULL, NULL)) - return FALSE; - - g_hash_table_insert (priv->component_names, g_strdup (name), - GINT_TO_POINTER (component_id)); - - return TRUE; -} - -void -jingle_transport_google_register (WockyJingleFactory *factory) -{ - /* GTalk libjingle0.3 dialect */ - wocky_jingle_factory_register_transport (factory, "", - WOCKY_TYPE_JINGLE_TRANSPORT_GOOGLE); - - /* GTalk libjingle0.4 dialect */ - wocky_jingle_factory_register_transport (factory, - NS_GOOGLE_TRANSPORT_P2P, - WOCKY_TYPE_JINGLE_TRANSPORT_GOOGLE); -} - diff --git a/src/jingle-transport-google.h b/src/jingle-transport-google.h deleted file mode 100644 index ee2313969..000000000 --- a/src/jingle-transport-google.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * jingle-transport-google.h - Header for WockyJingleTransportGoogle - * Copyright (C) 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 - */ - -#ifndef __JINGLE_TRANSPORT_GOOGLE_H__ -#define __JINGLE_TRANSPORT_GOOGLE_H__ - -#include <glib-object.h> - -#include "jingle-types.h" - -G_BEGIN_DECLS - -typedef struct _WockyJingleTransportGoogleClass WockyJingleTransportGoogleClass; - -GType wocky_jingle_transport_google_get_type (void); - -/* TYPE MACROS */ -#define WOCKY_TYPE_JINGLE_TRANSPORT_GOOGLE \ - (wocky_jingle_transport_google_get_type ()) -#define WOCKY_JINGLE_TRANSPORT_GOOGLE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), WOCKY_TYPE_JINGLE_TRANSPORT_GOOGLE, \ - WockyJingleTransportGoogle)) -#define WOCKY_JINGLE_TRANSPORT_GOOGLE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), WOCKY_TYPE_JINGLE_TRANSPORT_GOOGLE, \ - WockyJingleTransportGoogleClass)) -#define WOCKY_IS_JINGLE_TRANSPORT_GOOGLE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), WOCKY_TYPE_JINGLE_TRANSPORT_GOOGLE)) -#define WOCKY_IS_JINGLE_TRANSPORT_GOOGLE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), WOCKY_TYPE_JINGLE_TRANSPORT_GOOGLE)) -#define WOCKY_JINGLE_TRANSPORT_GOOGLE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), WOCKY_TYPE_JINGLE_TRANSPORT_GOOGLE, \ - WockyJingleTransportGoogleClass)) - -struct _WockyJingleTransportGoogleClass { - GObjectClass parent_class; -}; - -typedef struct _WockyJingleTransportGooglePrivate WockyJingleTransportGooglePrivate; - -struct _WockyJingleTransportGoogle { - GObject parent; - WockyJingleTransportGooglePrivate *priv; -}; - -void jingle_transport_google_register (WockyJingleFactory *factory); - -gboolean jingle_transport_google_set_component_name ( - WockyJingleTransportGoogle *transport, - const gchar *name, guint component_id); - -#endif /* __JINGLE_TRANSPORT_GOOGLE_H__ */ - diff --git a/src/jingle-transport-iceudp.c b/src/jingle-transport-iceudp.c deleted file mode 100644 index 55b3f396c..000000000 --- a/src/jingle-transport-iceudp.c +++ /dev/null @@ -1,617 +0,0 @@ -/* - * jingle-transport-iceudp.c - Source for WockyJingleTransportIceUdp - * - * Copyright (C) 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 "config.h" -#include "jingle-transport-iceudp.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <glib.h> - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA - -#include "debug.h" -#include "jingle-content.h" -#include "jingle-factory.h" -#include "jingle-session.h" -#include "namespaces.h" - -static void -transport_iface_init (gpointer g_iface, gpointer iface_data); - -G_DEFINE_TYPE_WITH_CODE (WockyJingleTransportIceUdp, - wocky_jingle_transport_iceudp, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (WOCKY_TYPE_JINGLE_TRANSPORT_IFACE, - transport_iface_init)); - -/* signal enum */ -enum -{ - NEW_CANDIDATES, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -/* properties */ -enum -{ - PROP_CONTENT = 1, - PROP_TRANSPORT_NS, - PROP_STATE, - LAST_PROPERTY -}; - -struct _WockyJingleTransportIceUdpPrivate -{ - WockyJingleContent *content; - WockyJingleTransportState state; - gchar *transport_ns; - - GList *local_candidates; - - /* A pointer into "local_candidates" list to mark the - * candidates that are still not transmitted, or NULL - * if all of them are transmitted. */ - - GList *pending_candidates; - GList *remote_candidates; - - gchar *ufrag; - gchar *pwd; - - /* next ID to send with a candidate */ - int id_sequence; - - gboolean dispose_has_run; -}; - -static void -wocky_jingle_transport_iceudp_init (WockyJingleTransportIceUdp *obj) -{ - WockyJingleTransportIceUdpPrivate *priv = - G_TYPE_INSTANCE_GET_PRIVATE (obj, WOCKY_TYPE_JINGLE_TRANSPORT_ICEUDP, - WockyJingleTransportIceUdpPrivate); - obj->priv = priv; - - priv->id_sequence = 1; - priv->dispose_has_run = FALSE; -} - -static void -wocky_jingle_transport_iceudp_dispose (GObject *object) -{ - WockyJingleTransportIceUdp *trans = WOCKY_JINGLE_TRANSPORT_ICEUDP (object); - WockyJingleTransportIceUdpPrivate *priv = trans->priv; - - if (priv->dispose_has_run) - return; - - DEBUG ("dispose called"); - priv->dispose_has_run = TRUE; - - jingle_transport_free_candidates (priv->remote_candidates); - priv->remote_candidates = NULL; - - jingle_transport_free_candidates (priv->local_candidates); - priv->local_candidates = NULL; - - g_free (priv->transport_ns); - priv->transport_ns = NULL; - - g_free (priv->ufrag); - priv->ufrag = NULL; - - g_free (priv->pwd); - priv->pwd = NULL; - - if (G_OBJECT_CLASS (wocky_jingle_transport_iceudp_parent_class)->dispose) - G_OBJECT_CLASS (wocky_jingle_transport_iceudp_parent_class)->dispose (object); -} - -static void -wocky_jingle_transport_iceudp_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - WockyJingleTransportIceUdp *trans = WOCKY_JINGLE_TRANSPORT_ICEUDP (object); - WockyJingleTransportIceUdpPrivate *priv = trans->priv; - - switch (property_id) { - case PROP_CONTENT: - g_value_set_object (value, priv->content); - break; - case PROP_TRANSPORT_NS: - g_value_set_string (value, priv->transport_ns); - break; - case PROP_STATE: - g_value_set_uint (value, priv->state); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -wocky_jingle_transport_iceudp_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - WockyJingleTransportIceUdp *trans = WOCKY_JINGLE_TRANSPORT_ICEUDP (object); - WockyJingleTransportIceUdpPrivate *priv = trans->priv; - - switch (property_id) { - case PROP_CONTENT: - priv->content = g_value_get_object (value); - break; - case PROP_TRANSPORT_NS: - g_free (priv->transport_ns); - priv->transport_ns = g_value_dup_string (value); - break; - case PROP_STATE: - priv->state = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -wocky_jingle_transport_iceudp_class_init (WockyJingleTransportIceUdpClass *cls) -{ - GObjectClass *object_class = G_OBJECT_CLASS (cls); - GParamSpec *param_spec; - - g_type_class_add_private (cls, sizeof (WockyJingleTransportIceUdpPrivate)); - - object_class->get_property = wocky_jingle_transport_iceudp_get_property; - object_class->set_property = wocky_jingle_transport_iceudp_set_property; - object_class->dispose = wocky_jingle_transport_iceudp_dispose; - - /* property definitions */ - param_spec = g_param_spec_object ("content", "WockyJingleContent object", - "Jingle content object using this transport.", - WOCKY_TYPE_JINGLE_CONTENT, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_CONTENT, param_spec); - - param_spec = g_param_spec_string ("transport-ns", "Transport namespace", - "Namespace identifying the transport type.", - NULL, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_TRANSPORT_NS, param_spec); - - param_spec = g_param_spec_uint ("state", - "Connection state for the transport.", - "Enum specifying the connection state of the transport.", - WOCKY_JINGLE_TRANSPORT_STATE_DISCONNECTED, - WOCKY_JINGLE_TRANSPORT_STATE_CONNECTED, - WOCKY_JINGLE_TRANSPORT_STATE_DISCONNECTED, - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_STATE, param_spec); - - /* signal definitions */ - signals[NEW_CANDIDATES] = g_signal_new ( - "new-candidates", - G_TYPE_FROM_CLASS (cls), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - -} - -static void -parse_candidates (WockyJingleTransportIface *obj, - WockyNode *transport_node, GError **error) -{ - WockyJingleTransportIceUdp *t = WOCKY_JINGLE_TRANSPORT_ICEUDP (obj); - WockyJingleTransportIceUdpPrivate *priv = t->priv; - gboolean node_contains_a_candidate = FALSE; - GList *candidates = NULL; - WockyNodeIter i; - WockyNode *node; - - DEBUG ("called"); - - wocky_node_iter_init (&i, transport_node, "candidate", NULL); - while (wocky_node_iter_next (&i, &node)) - { - const gchar *id, *address, *user, *pass, *str; - guint port, net, gen, component = 1; - gdouble pref; - WockyJingleTransportProtocol proto; - WockyJingleCandidateType ctype; - WockyJingleCandidate *c; - - node_contains_a_candidate = TRUE; - - id = wocky_node_get_attribute (node, "foundation"); - if (id == NULL) - { - DEBUG ("candidate doesn't contain foundation"); - continue; - } - - address = wocky_node_get_attribute (node, "ip"); - if (address == NULL) - { - DEBUG ("candidate doesn't contain ip"); - continue; - } - - str = wocky_node_get_attribute (node, "port"); - if (str == NULL) - { - DEBUG ("candidate doesn't contain port"); - continue; - } - port = atoi (str); - - str = wocky_node_get_attribute (node, "protocol"); - if (str == NULL) - { - DEBUG ("candidate doesn't contain protocol"); - continue; - } - - if (!wocky_strdiff (str, "udp")) - { - proto = WOCKY_JINGLE_TRANSPORT_PROTOCOL_UDP; - } - else - { - /* unknown protocol */ - DEBUG ("unknown protocol: %s", str); - continue; - } - - str = wocky_node_get_attribute (node, "priority"); - if (str == NULL) - { - DEBUG ("candidate doesn't contain priority"); - continue; - } - pref = g_ascii_strtod (str, NULL); - - str = wocky_node_get_attribute (node, "type"); - if (str == NULL) - { - DEBUG ("candidate doesn't contain type"); - continue; - } - - if (!wocky_strdiff (str, "host")) - { - ctype = WOCKY_JINGLE_CANDIDATE_TYPE_LOCAL; - } - else if (!wocky_strdiff (str, "srflx") || !wocky_strdiff (str, "prflx")) - { - /* FIXME Strictly speaking a prflx candidate should be a different - * type, but the TP spec has now way to distinguish and it doesn't - * matter much anyway.. */ - ctype = WOCKY_JINGLE_CANDIDATE_TYPE_STUN; - } - else if (!wocky_strdiff (str, "relay")) - { - ctype = WOCKY_JINGLE_CANDIDATE_TYPE_RELAY; - } - else - { - /* unknown candidate type */ - DEBUG ("unknown candidate type: %s", str); - continue; - } - - user = wocky_node_get_attribute (transport_node, "ufrag"); - if (user == NULL) - { - DEBUG ("transport doesn't contain ufrag"); - continue; - } - - pass = wocky_node_get_attribute (transport_node, "pwd"); - if (pass == NULL) - { - DEBUG ("transport doesn't contain pwd"); - continue; - } - - str = wocky_node_get_attribute (node, "network"); - if (str == NULL) - { - DEBUG ("candidate doesn't contain network"); - continue; - } - net = atoi (str); - - str = wocky_node_get_attribute (node, "generation"); - if (str == NULL) - { - DEBUG ("candidate doesn't contain generation"); - continue; - } - gen = atoi (str); - - str = wocky_node_get_attribute (node, "component"); - if (str == NULL) - { - DEBUG ("candidate doesn't contain component"); - continue; - } - component = atoi (str); - - if (priv->ufrag == NULL || strcmp (priv->ufrag, user)) - { - g_free (priv->ufrag); - priv->ufrag = g_strdup (user); - } - - if (priv->pwd == NULL || strcmp (priv->pwd, pass)) - { - g_free (priv->pwd); - priv->pwd = g_strdup (pass); - } - - c = wocky_jingle_candidate_new (proto, ctype, id, component, - address, port, gen, pref, user, pass, net); - - candidates = g_list_append (candidates, c); - } - - if (candidates == NULL) - { - if (node_contains_a_candidate) - { - NODE_DEBUG (transport_node, - "couldn't parse any of the given candidates"); - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "could not parse any of the given candidates"); - } - else - { - DEBUG ("no candidates in this stanza"); - } - } - else - { - DEBUG ("emitting %d new remote candidates", g_list_length (candidates)); - - g_signal_emit (obj, signals[NEW_CANDIDATES], 0, candidates); - - priv->remote_candidates = g_list_concat (priv->remote_candidates, - candidates); - } -} - -static void -inject_candidates (WockyJingleTransportIface *obj, - WockyNode *transport_node) -{ - WockyJingleTransportIceUdp *self = WOCKY_JINGLE_TRANSPORT_ICEUDP (obj); - WockyJingleTransportIceUdpPrivate *priv = self->priv; - const gchar *username = NULL; - - for (; priv->pending_candidates != NULL; - priv->pending_candidates = priv->pending_candidates->next) - { - WockyJingleCandidate *c = (WockyJingleCandidate *) priv->pending_candidates->data; - gchar port_str[16], pref_str[16], comp_str[16], id_str[16], - *type_str, *proto_str; - WockyNode *cnode; - - if (username == NULL) - { - username = c->username; - } - else if (wocky_strdiff (username, c->username)) - { - DEBUG ("found a candidate with a different username (%s not %s); " - "will send in a separate batch", c->username, username); - break; - } - - sprintf (pref_str, "%d", c->preference); - sprintf (port_str, "%d", c->port); - sprintf (comp_str, "%d", c->component); - sprintf (id_str, "%d", priv->id_sequence++); - - switch (c->type) { - case WOCKY_JINGLE_CANDIDATE_TYPE_LOCAL: - type_str = "host"; - break; - case WOCKY_JINGLE_CANDIDATE_TYPE_STUN: - type_str = "srflx"; - break; - case WOCKY_JINGLE_CANDIDATE_TYPE_RELAY: - type_str = "relay"; - break; - default: - DEBUG ("skipping candidate with unknown type %u", c->type); - continue; - } - - switch (c->protocol) { - case WOCKY_JINGLE_TRANSPORT_PROTOCOL_UDP: - proto_str = "udp"; - break; - case WOCKY_JINGLE_TRANSPORT_PROTOCOL_TCP: - DEBUG ("ignoring TCP candidate"); - continue; - default: - DEBUG ("skipping candidate with unknown protocol %u", c->protocol); - continue; - } - - wocky_node_set_attributes (transport_node, - "ufrag", c->username, - "pwd", c->password, - NULL); - - cnode = wocky_node_add_child (transport_node, "candidate"); - wocky_node_set_attributes (cnode, - "ip", c->address, - "port", port_str, - "priority", pref_str, - "protocol", proto_str, - "type", type_str, - "component", comp_str, - "foundation", c->id, - "id", id_str, - "network", "0", - "generation", "0", - NULL); - } -} - -/* We never have to retransmit candidates we've already sent, so we ignore - * @all. - */ -static void -send_candidates (WockyJingleTransportIface *iface, - gboolean all G_GNUC_UNUSED) -{ - WockyJingleTransportIceUdp *self = WOCKY_JINGLE_TRANSPORT_ICEUDP (iface); - WockyJingleTransportIceUdpPrivate *priv = self->priv; - - while (priv->pending_candidates != NULL) - { - WockyNode *trans_node, *sess_node; - WockyStanza *msg; - - msg = wocky_jingle_session_new_message (priv->content->session, - WOCKY_JINGLE_ACTION_TRANSPORT_INFO, &sess_node); - - wocky_jingle_content_produce_node (priv->content, sess_node, FALSE, - TRUE, &trans_node); - inject_candidates (iface, trans_node); - - wocky_porter_send_iq_async ( - wocky_jingle_session_get_porter (priv->content->session), msg, - NULL, NULL, NULL); - g_object_unref (msg); - } - - DEBUG ("sent all pending candidates"); -} - -/* Takes in a list of slice-allocated WockyJingleCandidate structs */ -static void -new_local_candidates (WockyJingleTransportIface *obj, GList *new_candidates) -{ - WockyJingleTransportIceUdp *transport = - WOCKY_JINGLE_TRANSPORT_ICEUDP (obj); - WockyJingleTransportIceUdpPrivate *priv = transport->priv; - - priv->local_candidates = g_list_concat (priv->local_candidates, - new_candidates); - - /* If all previous candidates have been signalled, set the new - * ones as pending. If there are existing pending candidates, - * the new ones will just be appended to that list. */ - if (priv->pending_candidates == NULL) - priv->pending_candidates = new_candidates; -} - -static GList * -get_remote_candidates (WockyJingleTransportIface *iface) -{ - WockyJingleTransportIceUdp *transport = - WOCKY_JINGLE_TRANSPORT_ICEUDP (iface); - WockyJingleTransportIceUdpPrivate *priv = transport->priv; - - return priv->remote_candidates; -} - -static GList * -get_local_candidates (WockyJingleTransportIface *iface) -{ - WockyJingleTransportIceUdp *transport = - WOCKY_JINGLE_TRANSPORT_ICEUDP (iface); - WockyJingleTransportIceUdpPrivate *priv = transport->priv; - - return priv->local_candidates; -} - -static WockyJingleTransportType -get_transport_type (void) -{ - return JINGLE_TRANSPORT_ICE_UDP; -} - -static gboolean -get_credentials (WockyJingleTransportIface *iface, - gchar **ufrag, gchar **pwd) -{ - WockyJingleTransportIceUdp *transport = - WOCKY_JINGLE_TRANSPORT_ICEUDP (iface); - WockyJingleTransportIceUdpPrivate *priv = transport->priv; - - if (!priv->ufrag || !priv->pwd) - return FALSE; - - if (ufrag) - *ufrag = priv->ufrag; - if (pwd) - *pwd = priv->pwd; - - return TRUE; -} - - -static void -transport_iface_init (gpointer g_iface, gpointer iface_data) -{ - WockyJingleTransportIfaceClass *klass = (WockyJingleTransportIfaceClass *) g_iface; - - klass->parse_candidates = parse_candidates; - - klass->new_local_candidates = new_local_candidates; - klass->inject_candidates = inject_candidates; - klass->send_candidates = send_candidates; - - klass->get_remote_candidates = get_remote_candidates; - klass->get_local_candidates = get_local_candidates; - klass->get_transport_type = get_transport_type; - klass->get_credentials = get_credentials; -} - -void -jingle_transport_iceudp_register (WockyJingleFactory *factory) -{ - wocky_jingle_factory_register_transport (factory, - NS_JINGLE_TRANSPORT_ICEUDP, - WOCKY_TYPE_JINGLE_TRANSPORT_ICEUDP); -} - diff --git a/src/jingle-transport-iceudp.h b/src/jingle-transport-iceudp.h deleted file mode 100644 index 35540a0fe..000000000 --- a/src/jingle-transport-iceudp.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * jingle-transport-iceudp.h - Header for WockyJingleTransportIceUdp - * Copyright (C) 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 - */ - -#ifndef __JINGLE_TRANSPORT_ICEUDP_H__ -#define __JINGLE_TRANSPORT_ICEUDP_H__ - -#include <glib-object.h> - -#include "jingle-types.h" - -G_BEGIN_DECLS - -typedef struct _WockyJingleTransportIceUdpClass WockyJingleTransportIceUdpClass; - -GType wocky_jingle_transport_iceudp_get_type (void); - -/* TYPE MACROS */ -#define WOCKY_TYPE_JINGLE_TRANSPORT_ICEUDP \ - (wocky_jingle_transport_iceudp_get_type ()) -#define WOCKY_JINGLE_TRANSPORT_ICEUDP(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), WOCKY_TYPE_JINGLE_TRANSPORT_ICEUDP, \ - WockyJingleTransportIceUdp)) -#define WOCKY_JINGLE_TRANSPORT_ICEUDP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), WOCKY_TYPE_JINGLE_TRANSPORT_ICEUDP, \ - WockyJingleTransportIceUdpClass)) -#define WOCKY_IS_JINGLE_TRANSPORT_ICEUDP(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), WOCKY_TYPE_JINGLE_TRANSPORT_ICEUDP)) -#define WOCKY_IS_JINGLE_TRANSPORT_ICEUDP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), WOCKY_TYPE_JINGLE_TRANSPORT_ICEUDP)) -#define WOCKY_JINGLE_TRANSPORT_ICEUDP_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), WOCKY_TYPE_JINGLE_TRANSPORT_ICEUDP, \ - WockyJingleTransportIceUdpClass)) - -struct _WockyJingleTransportIceUdpClass { - GObjectClass parent_class; -}; - -typedef struct _WockyJingleTransportIceUdpPrivate WockyJingleTransportIceUdpPrivate; - -struct _WockyJingleTransportIceUdp { - GObject parent; - WockyJingleTransportIceUdpPrivate *priv; -}; - -void jingle_transport_iceudp_register (WockyJingleFactory *factory); - -#endif /* __JINGLE_TRANSPORT_ICEUDP_H__ */ - diff --git a/src/jingle-transport-iface.c b/src/jingle-transport-iface.c deleted file mode 100644 index 58ca76924..000000000 --- a/src/jingle-transport-iface.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * jingle-transport-iface.c - Source for WockyJingleTransportIface - * Copyright (C) 2007-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 "config.h" -#include "jingle-transport-iface.h" - -#include <glib.h> - -#include "connection.h" -#include "jingle-content.h" -#include "jingle-session.h" - -WockyJingleTransportIface * -wocky_jingle_transport_iface_new (GType type, - WockyJingleContent *content, - const gchar *transport_ns) -{ - g_return_val_if_fail (g_type_is_a (type, WOCKY_TYPE_JINGLE_TRANSPORT_IFACE), - NULL); - - return g_object_new (type, - "content", content, - "transport-ns", transport_ns, - NULL); -} - -void -wocky_jingle_transport_iface_parse_candidates (WockyJingleTransportIface *self, - WockyNode *node, GError **error) -{ - void (*virtual_method)(WockyJingleTransportIface *, - WockyNode *, GError **) = - WOCKY_JINGLE_TRANSPORT_IFACE_GET_CLASS (self)->parse_candidates; - - g_assert (virtual_method != NULL); - return virtual_method (self, node, error); -} - -/* Takes in a list of slice-allocated WockyJingleCandidate structs */ -void -wocky_jingle_transport_iface_new_local_candidates (WockyJingleTransportIface *self, - GList *candidates) -{ - void (*virtual_method)(WockyJingleTransportIface *, - GList *) = - WOCKY_JINGLE_TRANSPORT_IFACE_GET_CLASS (self)->new_local_candidates; - - g_assert (virtual_method != NULL); - virtual_method (self, candidates); -} - -/* Inserts candidates into the given <transport/> node, or equivalent, of a - * session-initiate, session-accept, content-add or content-accept action. - */ -void -wocky_jingle_transport_iface_inject_candidates ( - WockyJingleTransportIface *self, - WockyNode *transport_node) -{ - void (*virtual_method)(WockyJingleTransportIface *, WockyNode *) = - WOCKY_JINGLE_TRANSPORT_IFACE_GET_CLASS (self)->inject_candidates; - - if (virtual_method != NULL) - virtual_method (self, transport_node); -} - -/* Transmits outstanding or all candidates (if applicable and @all is set). */ -void -wocky_jingle_transport_iface_send_candidates ( - WockyJingleTransportIface *self, - gboolean all) -{ - void (*virtual_method) (WockyJingleTransportIface *, gboolean) = - WOCKY_JINGLE_TRANSPORT_IFACE_GET_CLASS (self)->send_candidates; - - if (virtual_method != NULL) - virtual_method (self, all); -} - -/* Returns TRUE if and only if @self has enough candidates to inject into a - * {session,content}-accept, and is connected. - */ -gboolean -wocky_jingle_transport_iface_can_accept (WockyJingleTransportIface *self) -{ - WockyJingleTransportState state; - gboolean (*m) (WockyJingleTransportIface *) = - WOCKY_JINGLE_TRANSPORT_IFACE_GET_CLASS (self)->can_accept; - - g_object_get (self, "state", &state, NULL); - - if (state != WOCKY_JINGLE_TRANSPORT_STATE_CONNECTED) - return FALSE; - - /* Only Raw UDP *needs* candidates in order to accept. */ - if (m != NULL) - return m (self); - else - return TRUE; -} - -GList * -wocky_jingle_transport_iface_get_remote_candidates ( - WockyJingleTransportIface *self) -{ - GList * (*virtual_method)(WockyJingleTransportIface *) = - WOCKY_JINGLE_TRANSPORT_IFACE_GET_CLASS (self)->get_remote_candidates; - - g_assert (virtual_method != NULL); - return virtual_method (self); -} - -GList * -wocky_jingle_transport_iface_get_local_candidates ( - WockyJingleTransportIface *self) -{ - GList * (*virtual_method)(WockyJingleTransportIface *) = - WOCKY_JINGLE_TRANSPORT_IFACE_GET_CLASS (self)->get_local_candidates; - - g_assert (virtual_method != NULL); - return virtual_method (self); -} - -gboolean -jingle_transport_get_credentials (WockyJingleTransportIface *self, - gchar **ufrag, gchar **pwd) -{ - WockyJingleTransportIfaceClass *klass = - WOCKY_JINGLE_TRANSPORT_IFACE_GET_CLASS (self); - - if (klass->get_credentials) - return klass->get_credentials (self, ufrag, pwd); - else - return FALSE; -} - -WockyJingleTransportType -wocky_jingle_transport_iface_get_transport_type (WockyJingleTransportIface *self) -{ - WockyJingleTransportType (*virtual_method)(void) = - WOCKY_JINGLE_TRANSPORT_IFACE_GET_CLASS (self)->get_transport_type; - - g_assert (virtual_method != NULL); - return virtual_method (); -} - -static void -wocky_jingle_transport_iface_base_init (gpointer klass) -{ - static gboolean initialized = FALSE; - - if (!initialized) - { - GParamSpec *param_spec; - - param_spec = g_param_spec_object ( - "content", - "WockyJingleContent object", - "Jingle content that's using this jingle transport object.", - WOCKY_TYPE_JINGLE_CONTENT, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_interface_install_property (klass, param_spec); - - param_spec = g_param_spec_string ( - "transport-ns", - "Transport namespace", - "Namespace identifying the transport type.", - NULL, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_interface_install_property (klass, param_spec); - - param_spec = g_param_spec_uint ( - "state", - "Connection state for the transport.", - "Enum specifying the connection state of the transport.", - WOCKY_JINGLE_TRANSPORT_STATE_DISCONNECTED, - WOCKY_JINGLE_TRANSPORT_STATE_CONNECTED, - WOCKY_JINGLE_TRANSPORT_STATE_DISCONNECTED, - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - - g_object_interface_install_property (klass, param_spec); - - initialized = TRUE; - } -} - -GType -wocky_jingle_transport_iface_get_type (void) -{ - static GType type = 0; - - if (type == 0) { - static const GTypeInfo info = { - sizeof (WockyJingleTransportIfaceClass), - wocky_jingle_transport_iface_base_init, /* base_init */ - NULL, /* base_finalize */ - NULL, /* class_init */ - NULL, /* class_finalize */ - NULL, /* class_data */ - 0, - 0, /* n_preallocs */ - NULL /* instance_init */ - }; - - type = g_type_register_static (G_TYPE_INTERFACE, "WockyJingleTransportIface", - &info, 0); - } - - return type; -} - -WockyJingleCandidate * -wocky_jingle_candidate_new (WockyJingleTransportProtocol protocol, - WockyJingleCandidateType type, const gchar *id, int component, - const gchar *address, int port, int generation, int preference, - const gchar *username, const gchar *password, int network) -{ - WockyJingleCandidate *c = g_slice_new0 (WockyJingleCandidate); - - c->protocol = protocol; - c->type = type; - c->id = g_strdup (id); - c->address = g_strdup (address); - c->component = component; - c->port = port; - c->generation = generation; - c->preference = preference; - c->username = g_strdup (username); - c->password = g_strdup (password); - c->network = network; - - return c; -} - -void -wocky_jingle_candidate_free (WockyJingleCandidate *c) -{ - g_free (c->id); - g_free (c->address); - g_free (c->username); - g_free (c->password); - - g_slice_free (WockyJingleCandidate, c); -} - -void -jingle_transport_free_candidates (GList *candidates) -{ - while (candidates != NULL) - { - WockyJingleCandidate *c = (WockyJingleCandidate *) candidates->data; - wocky_jingle_candidate_free (c); - candidates = g_list_remove (candidates, c); - } -} - diff --git a/src/jingle-transport-iface.h b/src/jingle-transport-iface.h deleted file mode 100644 index 0801e28ce..000000000 --- a/src/jingle-transport-iface.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * jingle-transport-iface.h - Header for WockyJingleTransportIface - * Copyright (C) 2007-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 - */ - -#ifndef __WOCKY_JINGLE_TRANSPORT_IFACE_H__ -#define __WOCKY_JINGLE_TRANSPORT_IFACE_H__ - -#include <glib-object.h> -#include <wocky/wocky.h> - -#include "jingle-factory.h" -#include "jingle-types.h" - -G_BEGIN_DECLS - -typedef enum -{ - WOCKY_JINGLE_TRANSPORT_STATE_DISCONNECTED, - WOCKY_JINGLE_TRANSPORT_STATE_CONNECTING, - WOCKY_JINGLE_TRANSPORT_STATE_CONNECTED -} WockyJingleTransportState; - -typedef struct _WockyJingleTransportIface WockyJingleTransportIface; -typedef struct _WockyJingleTransportIfaceClass WockyJingleTransportIfaceClass; - -struct _WockyJingleTransportIfaceClass { - GTypeInterface parent; - - void (*parse_candidates) (WockyJingleTransportIface *, - WockyNode *, GError **); - - void (*new_local_candidates) (WockyJingleTransportIface *, GList *); - void (*inject_candidates) (WockyJingleTransportIface *, - WockyNode *transport_node); - void (*send_candidates) (WockyJingleTransportIface *, gboolean all); - gboolean (*can_accept) (WockyJingleTransportIface *); - - GList * (*get_remote_candidates) (WockyJingleTransportIface *); - GList * (*get_local_candidates) (WockyJingleTransportIface *); - gboolean (*get_credentials) (WockyJingleTransportIface *, - gchar **ufrag, gchar **pwd); - - WockyJingleTransportType (*get_transport_type) (void); -}; - -GType wocky_jingle_transport_iface_get_type (void); - -/* TYPE MACROS */ -#define WOCKY_TYPE_JINGLE_TRANSPORT_IFACE \ - (wocky_jingle_transport_iface_get_type ()) -#define WOCKY_JINGLE_TRANSPORT_IFACE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), WOCKY_TYPE_JINGLE_TRANSPORT_IFACE, WockyJingleTransportIface)) -#define WOCKY_IS_JINGLE_TRANSPORT_IFACE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), WOCKY_TYPE_JINGLE_TRANSPORT_IFACE)) -#define WOCKY_JINGLE_TRANSPORT_IFACE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_INTERFACE ((obj), WOCKY_TYPE_JINGLE_TRANSPORT_IFACE,\ - WockyJingleTransportIfaceClass)) - -void wocky_jingle_transport_iface_parse_candidates (WockyJingleTransportIface *, - WockyNode *, GError **); - -void wocky_jingle_transport_iface_new_local_candidates ( - WockyJingleTransportIface *self, - GList *candidates); -void wocky_jingle_transport_iface_inject_candidates ( - WockyJingleTransportIface *self, - WockyNode *transport_node); -void wocky_jingle_transport_iface_send_candidates ( - WockyJingleTransportIface *self, - gboolean all); -gboolean wocky_jingle_transport_iface_can_accept ( - WockyJingleTransportIface *self); - -GList *wocky_jingle_transport_iface_get_remote_candidates (WockyJingleTransportIface *); -GList *wocky_jingle_transport_iface_get_local_candidates (WockyJingleTransportIface *); -WockyJingleTransportType wocky_jingle_transport_iface_get_transport_type (WockyJingleTransportIface *); -gboolean jingle_transport_get_credentials (WockyJingleTransportIface *, - gchar **ufrag, gchar **pwd); - -WockyJingleTransportIface *wocky_jingle_transport_iface_new ( - GType type, WockyJingleContent *content, const gchar *transport_ns); - -WockyJingleCandidate *wocky_jingle_candidate_new (WockyJingleTransportProtocol protocol, - WockyJingleCandidateType type, const gchar *id, int component, - const gchar *address, int port, int generation, int preference, - const gchar *username, const gchar *password, int network); - -void wocky_jingle_candidate_free (WockyJingleCandidate *c); -void jingle_transport_free_candidates (GList *candidates); - - -G_END_DECLS - -#endif /* #ifndef __WOCKY_JINGLE_TRANSPORT_IFACE_H__ */ diff --git a/src/jingle-transport-rawudp.c b/src/jingle-transport-rawudp.c deleted file mode 100644 index 668a8afd9..000000000 --- a/src/jingle-transport-rawudp.c +++ /dev/null @@ -1,404 +0,0 @@ -/* - * jingle-transport-rawudp.c - Source for WockyJingleTransportRawUdp - * - * Copyright (C) 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 "config.h" -#include "jingle-transport-rawudp.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <glib.h> - -#define DEBUG_FLAG GABBLE_DEBUG_MEDIA - -#include "connection.h" -#include "debug.h" -#include "jingle-content.h" -#include "jingle-factory.h" -#include "jingle-session.h" -#include "namespaces.h" - -static void -transport_iface_init (gpointer g_iface, gpointer iface_data); - -G_DEFINE_TYPE_WITH_CODE (WockyJingleTransportRawUdp, - wocky_jingle_transport_rawudp, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (WOCKY_TYPE_JINGLE_TRANSPORT_IFACE, - transport_iface_init)); - -/* signal enum */ -enum -{ - NEW_CANDIDATES, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -/* properties */ -enum -{ - PROP_CONTENT = 1, - PROP_TRANSPORT_NS, - PROP_STATE, - LAST_PROPERTY -}; - -struct _WockyJingleTransportRawUdpPrivate -{ - WockyJingleContent *content; - WockyJingleTransportState state; - gchar *transport_ns; - - GList *local_candidates; - GList *remote_candidates; - gboolean dispose_has_run; -}; - -static void -wocky_jingle_transport_rawudp_init (WockyJingleTransportRawUdp *obj) -{ - WockyJingleTransportRawUdpPrivate *priv = - G_TYPE_INSTANCE_GET_PRIVATE (obj, WOCKY_TYPE_JINGLE_TRANSPORT_RAWUDP, - WockyJingleTransportRawUdpPrivate); - obj->priv = priv; - - priv->dispose_has_run = FALSE; -} - -static void -wocky_jingle_transport_rawudp_dispose (GObject *object) -{ - WockyJingleTransportRawUdp *trans = WOCKY_JINGLE_TRANSPORT_RAWUDP (object); - WockyJingleTransportRawUdpPrivate *priv = trans->priv; - - if (priv->dispose_has_run) - return; - - DEBUG ("dispose called"); - priv->dispose_has_run = TRUE; - - jingle_transport_free_candidates (priv->remote_candidates); - priv->remote_candidates = NULL; - - jingle_transport_free_candidates (priv->local_candidates); - priv->local_candidates = NULL; - - g_free (priv->transport_ns); - priv->transport_ns = NULL; - - if (G_OBJECT_CLASS (wocky_jingle_transport_rawudp_parent_class)->dispose) - G_OBJECT_CLASS (wocky_jingle_transport_rawudp_parent_class)->dispose (object); -} - -static void -wocky_jingle_transport_rawudp_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - WockyJingleTransportRawUdp *trans = WOCKY_JINGLE_TRANSPORT_RAWUDP (object); - WockyJingleTransportRawUdpPrivate *priv = trans->priv; - - switch (property_id) { - case PROP_CONTENT: - g_value_set_object (value, priv->content); - break; - case PROP_TRANSPORT_NS: - g_value_set_string (value, priv->transport_ns); - break; - case PROP_STATE: - g_value_set_uint (value, priv->state); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -wocky_jingle_transport_rawudp_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - WockyJingleTransportRawUdp *trans = WOCKY_JINGLE_TRANSPORT_RAWUDP (object); - WockyJingleTransportRawUdpPrivate *priv = trans->priv; - - switch (property_id) { - case PROP_CONTENT: - priv->content = g_value_get_object (value); - break; - case PROP_TRANSPORT_NS: - g_free (priv->transport_ns); - priv->transport_ns = g_value_dup_string (value); - break; - case PROP_STATE: - priv->state = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -wocky_jingle_transport_rawudp_class_init (WockyJingleTransportRawUdpClass *cls) -{ - GObjectClass *object_class = G_OBJECT_CLASS (cls); - GParamSpec *param_spec; - - g_type_class_add_private (cls, sizeof (WockyJingleTransportRawUdpPrivate)); - - object_class->get_property = wocky_jingle_transport_rawudp_get_property; - object_class->set_property = wocky_jingle_transport_rawudp_set_property; - object_class->dispose = wocky_jingle_transport_rawudp_dispose; - - /* property definitions */ - param_spec = g_param_spec_object ("content", "WockyJingleContent object", - "Jingle content object using this transport.", - WOCKY_TYPE_JINGLE_CONTENT, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_CONTENT, param_spec); - - param_spec = g_param_spec_string ("transport-ns", "Transport namespace", - "Namespace identifying the transport type.", - NULL, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_TRANSPORT_NS, param_spec); - - param_spec = g_param_spec_uint ("state", - "Connection state for the transport.", - "Enum specifying the connection state of the transport.", - WOCKY_JINGLE_TRANSPORT_STATE_DISCONNECTED, - WOCKY_JINGLE_TRANSPORT_STATE_CONNECTED, - WOCKY_JINGLE_TRANSPORT_STATE_DISCONNECTED, - G_PARAM_READWRITE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB); - g_object_class_install_property (object_class, PROP_STATE, param_spec); - - /* signal definitions */ - signals[NEW_CANDIDATES] = g_signal_new ( - "new-candidates", - G_TYPE_FROM_CLASS (cls), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - -} - -static void -parse_candidates (WockyJingleTransportIface *obj, - WockyNode *transport_node, GError **error) -{ - WockyJingleTransportRawUdp *t = WOCKY_JINGLE_TRANSPORT_RAWUDP (obj); - WockyJingleTransportRawUdpPrivate *priv = t->priv; - GList *candidates = NULL; - WockyNodeIter i; - WockyNode *node; - - DEBUG ("called"); - - if (priv->remote_candidates != NULL) - { - DEBUG ("already have raw udp candidates, ignoring extra ones"); - return; - } - - wocky_node_iter_init (&i, transport_node, "candidate", NULL); - while (wocky_node_iter_next (&i, &node)) - { - const gchar *id, *ip, *str; - guint port, gen, component = 1; - WockyJingleCandidate *c; - - str = wocky_node_get_attribute (node, "component"); - if (str != NULL) - component = atoi (str); - - if ((component != 1) && (component != 2)) - { - DEBUG ("Ignoring non-RTP/RTCP component %d", component); - continue; - } - - id = wocky_node_get_attribute (node, "id"); - if (id == NULL) - break; - - ip = wocky_node_get_attribute (node, "ip"); - if (ip == NULL) - break; - - str = wocky_node_get_attribute (node, "port"); - if (str == NULL) - break; - port = atoi (str); - - str = wocky_node_get_attribute (node, "generation"); - if (str == NULL) - break; - gen = atoi (str); - - c = wocky_jingle_candidate_new (WOCKY_JINGLE_TRANSPORT_PROTOCOL_UDP, - WOCKY_JINGLE_CANDIDATE_TYPE_LOCAL, id, component, ip, port, - gen, 1.0, NULL, NULL, 0); - - candidates = g_list_append (candidates, c); - } - - if (wocky_node_iter_next (&i, NULL)) - { - DEBUG ("not all nodes were processed, reporting error"); - /* rollback these */ - jingle_transport_free_candidates (candidates); - g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST, - "invalid candidate"); - return; - } - - DEBUG ("emitting %d new remote candidates", g_list_length (candidates)); - g_signal_emit (obj, signals[NEW_CANDIDATES], 0, candidates); - priv->remote_candidates = candidates; -} - -static void -inject_candidates (WockyJingleTransportIface *obj, - WockyNode *transport_node) -{ - WockyJingleTransportRawUdp *self = WOCKY_JINGLE_TRANSPORT_RAWUDP (obj); - WockyJingleTransportRawUdpPrivate *priv = self->priv; - WockyJingleCandidate *c; - GList *li; - gchar port_str[16], comp_str[16]; - WockyNode *cnode; - - /* If we don't have the local candidates yet, we should've waited with - * the session initiation, or can_accept would have returned FALSE. - */ - g_assert (priv->local_candidates != NULL); - - for (li = priv->local_candidates; li != NULL; li = li->next) - { - c = (WockyJingleCandidate *) li->data; - sprintf (port_str, "%d", c->port); - sprintf (comp_str, "%d", c->component); - - cnode = wocky_node_add_child (transport_node, "candidate"); - wocky_node_set_attributes (cnode, - "ip", c->address, - "port", port_str, - "generation", "0", - "id", c->id, - "component", comp_str, - NULL); - } -} - -/* Takes in a list of slice-allocated WockyJingleCandidate structs */ -static void -new_local_candidates (WockyJingleTransportIface *obj, GList *new_candidates) -{ - WockyJingleTransportRawUdp *transport = - WOCKY_JINGLE_TRANSPORT_RAWUDP (obj); - WockyJingleTransportRawUdpPrivate *priv = transport->priv; - - if (priv->local_candidates != NULL) - { - DEBUG ("ignoring new local candidates for RAW UDP"); - jingle_transport_free_candidates (new_candidates); - return; - } - - priv->local_candidates = new_candidates; -} - -static gboolean -can_accept (WockyJingleTransportIface *iface) -{ - WockyJingleTransportRawUdp *self = WOCKY_JINGLE_TRANSPORT_RAWUDP (iface); - - return (self->priv->local_candidates != NULL); -} - -static GList * -get_local_candidates (WockyJingleTransportIface *iface) -{ - WockyJingleTransportRawUdp *transport = - WOCKY_JINGLE_TRANSPORT_RAWUDP (iface); - WockyJingleTransportRawUdpPrivate *priv = transport->priv; - - return priv->local_candidates; -} - -static GList * -get_remote_candidates (WockyJingleTransportIface *iface) -{ - WockyJingleTransportRawUdp *transport = - WOCKY_JINGLE_TRANSPORT_RAWUDP (iface); - WockyJingleTransportRawUdpPrivate *priv = transport->priv; - - return priv->remote_candidates; -} - -static WockyJingleTransportType -get_transport_type (void) -{ - DEBUG ("called"); - - return JINGLE_TRANSPORT_RAW_UDP; -} - -static void -transport_iface_init (gpointer g_iface, gpointer iface_data) -{ - WockyJingleTransportIfaceClass *klass = (WockyJingleTransportIfaceClass *) g_iface; - - klass->parse_candidates = parse_candidates; - - klass->new_local_candidates = new_local_candidates; - klass->inject_candidates = inject_candidates; - /* Not implementing _send: XEP-0177 says that the candidates live in - * content-{add,accept}, not in transport-info. - */ - klass->can_accept = can_accept; - - klass->get_remote_candidates = get_remote_candidates; - klass->get_local_candidates = get_local_candidates; - klass->get_transport_type = get_transport_type; -} - -void -jingle_transport_rawudp_register (WockyJingleFactory *factory) -{ - wocky_jingle_factory_register_transport (factory, - NS_JINGLE_TRANSPORT_RAWUDP, - WOCKY_TYPE_JINGLE_TRANSPORT_RAWUDP); -} - diff --git a/src/jingle-transport-rawudp.h b/src/jingle-transport-rawudp.h deleted file mode 100644 index ff10815a1..000000000 --- a/src/jingle-transport-rawudp.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * jingle-transport-rawudp.h - Header for WockyJingleTransportRawUdp - * Copyright (C) 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 - */ - -#ifndef __JINGLE_TRANSPORT_RAWUDP_H__ -#define __JINGLE_TRANSPORT_RAWUDP_H__ - -#include <glib-object.h> - -#include "jingle-types.h" - -G_BEGIN_DECLS - -typedef struct _WockyJingleTransportRawUdpClass WockyJingleTransportRawUdpClass; - -GType wocky_jingle_transport_rawudp_get_type (void); - -/* TYPE MACROS */ -#define WOCKY_TYPE_JINGLE_TRANSPORT_RAWUDP \ - (wocky_jingle_transport_rawudp_get_type ()) -#define WOCKY_JINGLE_TRANSPORT_RAWUDP(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), WOCKY_TYPE_JINGLE_TRANSPORT_RAWUDP, \ - WockyJingleTransportRawUdp)) -#define WOCKY_JINGLE_TRANSPORT_RAWUDP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), WOCKY_TYPE_JINGLE_TRANSPORT_RAWUDP, \ - WockyJingleTransportRawUdpClass)) -#define WOCKY_IS_JINGLE_TRANSPORT_RAWUDP(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), WOCKY_TYPE_JINGLE_TRANSPORT_RAWUDP)) -#define WOCKY_IS_JINGLE_TRANSPORT_RAWUDP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), WOCKY_TYPE_JINGLE_TRANSPORT_RAWUDP)) -#define WOCKY_JINGLE_TRANSPORT_RAWUDP_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), WOCKY_TYPE_JINGLE_TRANSPORT_RAWUDP, \ - WockyJingleTransportRawUdpClass)) - -struct _WockyJingleTransportRawUdpClass { - GObjectClass parent_class; -}; - -typedef struct _WockyJingleTransportRawUdpPrivate WockyJingleTransportRawUdpPrivate; - -struct _WockyJingleTransportRawUdp { - GObject parent; - WockyJingleTransportRawUdpPrivate *priv; -}; - -void jingle_transport_rawudp_register (WockyJingleFactory *factory); - -#endif /* __JINGLE_TRANSPORT_RAWUDP_H__ */ - diff --git a/src/jingle-types.h b/src/jingle-types.h deleted file mode 100644 index 50f4ef7f0..000000000 --- a/src/jingle-types.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * jingle-types.h - Header for Jingle-related enums and typedefs - * Copyright © 2008–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_ENUMS_H -#define GABBLE_JINGLE_ENUMS_H - -typedef struct _WockyJingleFactory WockyJingleFactory; -typedef struct _WockyJingleSession WockyJingleSession; -typedef struct _WockyJingleContent WockyJingleContent; -typedef struct _WockyJingleTransportGoogle WockyJingleTransportGoogle; -typedef struct _WockyJingleTransportRawUdp WockyJingleTransportRawUdp; -typedef struct _WockyJingleTransportIceUdp WockyJingleTransportIceUdp; -typedef struct _WockyJingleMediaRtp WockyJingleMediaRtp; -typedef struct _WockyJingleCandidate WockyJingleCandidate; - -typedef enum { /*< skip >*/ - /* not a jingle message */ - WOCKY_JINGLE_DIALECT_ERROR, - /* old libjingle3 gtalk variant */ - WOCKY_JINGLE_DIALECT_GTALK3, - /* new gtalk variant */ - WOCKY_JINGLE_DIALECT_GTALK4, - /* jingle in the old 0.15 version days */ - WOCKY_JINGLE_DIALECT_V015, - /* current jingle standard */ - WOCKY_JINGLE_DIALECT_V032 -} WockyJingleDialect; - -#define WOCKY_JINGLE_DIALECT_IS_GOOGLE(d)\ - ((d == WOCKY_JINGLE_DIALECT_GTALK3) || (d == WOCKY_JINGLE_DIALECT_GTALK4)) - -typedef enum { /*< skip >*/ - WOCKY_JINGLE_STATE_INVALID = -1, - WOCKY_JINGLE_STATE_PENDING_CREATED = 0, - WOCKY_JINGLE_STATE_PENDING_INITIATE_SENT, - WOCKY_JINGLE_STATE_PENDING_INITIATED, - WOCKY_JINGLE_STATE_PENDING_ACCEPT_SENT, - WOCKY_JINGLE_STATE_ACTIVE, - WOCKY_JINGLE_STATE_ENDED, - WOCKY_N_JINGLE_STATES -} WockyJingleState; - -typedef enum { /*< skip >*/ - WOCKY_JINGLE_ACTION_UNKNOWN, - WOCKY_JINGLE_ACTION_CONTENT_ACCEPT, - WOCKY_JINGLE_ACTION_CONTENT_ADD, - WOCKY_JINGLE_ACTION_CONTENT_MODIFY, - WOCKY_JINGLE_ACTION_CONTENT_REMOVE, - WOCKY_JINGLE_ACTION_CONTENT_REPLACE, - WOCKY_JINGLE_ACTION_CONTENT_REJECT, - WOCKY_JINGLE_ACTION_SESSION_ACCEPT, - WOCKY_JINGLE_ACTION_SESSION_INFO, - WOCKY_JINGLE_ACTION_SESSION_INITIATE, - WOCKY_JINGLE_ACTION_SESSION_TERMINATE, - WOCKY_JINGLE_ACTION_TRANSPORT_INFO, - WOCKY_JINGLE_ACTION_TRANSPORT_ACCEPT, - WOCKY_JINGLE_ACTION_DESCRIPTION_INFO, - WOCKY_JINGLE_ACTION_INFO -} WockyJingleAction; - -typedef enum { /*< skip >*/ - WOCKY_JINGLE_CONTENT_SENDERS_NONE, - WOCKY_JINGLE_CONTENT_SENDERS_INITIATOR, - WOCKY_JINGLE_CONTENT_SENDERS_RESPONDER, - WOCKY_JINGLE_CONTENT_SENDERS_BOTH -} WockyJingleContentSenders; - -typedef enum { /*< skip >*/ - JINGLE_TRANSPORT_UNKNOWN, - JINGLE_TRANSPORT_GOOGLE_P2P, - JINGLE_TRANSPORT_RAW_UDP, - JINGLE_TRANSPORT_ICE_UDP, -} WockyJingleTransportType; - -typedef enum { /*< skip >*/ - WOCKY_JINGLE_TRANSPORT_PROTOCOL_UDP, - WOCKY_JINGLE_TRANSPORT_PROTOCOL_TCP -} WockyJingleTransportProtocol; - -typedef enum { /*< skip >*/ - WOCKY_JINGLE_CANDIDATE_TYPE_LOCAL, - WOCKY_JINGLE_CANDIDATE_TYPE_STUN, - WOCKY_JINGLE_CANDIDATE_TYPE_RELAY -} WockyJingleCandidateType; - -typedef enum -{ - WOCKY_JINGLE_REASON_UNKNOWN, - WOCKY_JINGLE_REASON_ALTERNATIVE_SESSION, - WOCKY_JINGLE_REASON_BUSY, - WOCKY_JINGLE_REASON_CANCEL, - WOCKY_JINGLE_REASON_CONNECTIVITY_ERROR, - WOCKY_JINGLE_REASON_DECLINE, - WOCKY_JINGLE_REASON_EXPIRED, - WOCKY_JINGLE_REASON_FAILED_APPLICATION, - WOCKY_JINGLE_REASON_FAILED_TRANSPORT, - WOCKY_JINGLE_REASON_GENERAL_ERROR, - WOCKY_JINGLE_REASON_GONE, - WOCKY_JINGLE_REASON_INCOMPATIBLE_PARAMETERS, - WOCKY_JINGLE_REASON_MEDIA_ERROR, - WOCKY_JINGLE_REASON_SECURITY_ERROR, - WOCKY_JINGLE_REASON_SUCCESS, - WOCKY_JINGLE_REASON_TIMEOUT, - WOCKY_JINGLE_REASON_UNSUPPORTED_APPLICATIONS, - WOCKY_JINGLE_REASON_UNSUPPORTED_TRANSPORTS -} WockyJingleReason; - - -#endif /* GABBLE_JINGLE_ENUMS_H */ |