diff options
Diffstat (limited to 'src/jingle-factory.c')
-rw-r--r-- | src/jingle-factory.c | 604 |
1 files changed, 0 insertions, 604 deletions
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; -} |