void gabble_jingle_content_parse_accept (GabbleJingleContent *c, WockyNode *content_node, gboolean google_mode, GError **error) { GabbleJingleContentPrivate *priv = c->priv; const gchar *senders; WockyNode *trans_node, *desc_node; JingleDialect dialect = gabble_jingle_session_get_dialect (c->session); JingleContentSenders 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 (GABBLE_IS_JINGLE_MEDIA_RTP (c) && JINGLE_IS_GOOGLE_DIALECT (dialect) && trans_node == NULL) { DEBUG ("no transport node, assuming GTalk3 dialect"); /* gtalk lj0.3 assumes google-p2p transport */ g_object_set (c->session, "dialect", JINGLE_DIALECT_GTALK3, NULL); } if (senders == NULL) newsenders = get_default_senders (c); else newsenders = parse_senders (senders); if (newsenders == 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 = JINGLE_CONTENT_STATE_ACKNOWLEDGED; g_object_notify ((GObject *) c, "state"); if (trans_node != NULL) { gabble_jingle_transport_iface_parse_candidates (priv->transport, trans_node, NULL); } }
void gabble_jingle_content_update_senders (GabbleJingleContent *c, WockyNode *content_node, GError **error) { GabbleJingleContentPrivate *priv = c->priv; JingleContentSenders senders; senders = parse_senders (wocky_node_get_attribute (content_node, "senders")); if (senders == JINGLE_CONTENT_SENDERS_NONE) { SET_BAD_REQ ("invalid content senders in stream"); return; } priv->senders = senders; g_object_notify ((GObject *) c, "senders"); }
void gabble_jingle_content_parse_description_info (GabbleJingleContent *c, WockyNode *content_node, GError **error) { GabbleJingleContentPrivate *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 < 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); }
static void parse_candidates (GabbleJingleTransportIface *obj, LmMessageNode *transport_node, GError **error) { GabbleJingleTransportGoogle *t = GABBLE_JINGLE_TRANSPORT_GOOGLE (obj); GabbleJingleTransportGooglePrivate *priv = t->priv; GList *candidates = NULL; NodeIter i; for (i = node_iter (transport_node); i; i = node_iter_next (i)) { LmMessageNode *node = node_iter_data (i); const gchar *name, *address, *user, *pass, *str; guint port, net, gen, component; int pref; JingleTransportProtocol proto; JingleCandidateType ctype; JingleCandidate *c; if (tp_strdiff (lm_message_node_get_name (node), "candidate")) continue; name = lm_message_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 = lm_message_node_get_attribute (node, "address"); if (address == NULL) break; str = lm_message_node_get_attribute (node, "port"); if (str == NULL) break; port = atoi (str); str = lm_message_node_get_attribute (node, "protocol"); if (str == NULL) break; if (!tp_strdiff (str, "udp")) { proto = JINGLE_TRANSPORT_PROTOCOL_UDP; } else if (!tp_strdiff (str, "tcp")) { /* candiates on port 443 must be "ssltcp" */ if (port == 443) break; proto = JINGLE_TRANSPORT_PROTOCOL_TCP; } else if (!tp_strdiff (str, "ssltcp")) { /* "ssltcp" must use port 443 */ if (port != 443) break; /* we really don't care about "ssltcp" otherwise */ proto = JINGLE_TRANSPORT_PROTOCOL_TCP; } else { /* unknown protocol */ DEBUG ("unknown protocol: %s", str); break; } str = lm_message_node_get_attribute (node, "preference"); if (str == NULL) break; pref = g_ascii_strtod (str, NULL) * 65536; str = lm_message_node_get_attribute (node, "type"); if (str == NULL) break; if (!tp_strdiff (str, "local")) { ctype = JINGLE_CANDIDATE_TYPE_LOCAL; } else if (!tp_strdiff (str, "stun")) { ctype = JINGLE_CANDIDATE_TYPE_STUN; } else if (!tp_strdiff (str, "relay")) { ctype = JINGLE_CANDIDATE_TYPE_RELAY; } else { /* unknown candidate type */ DEBUG ("unknown candidate type: %s", str); break; } user = lm_message_node_get_attribute (node, "username"); if (user == NULL) break; pass = lm_message_node_get_attribute (node, "password"); if (pass == NULL) break; str = lm_message_node_get_attribute (node, "network"); if (str == NULL) break; net = atoi (str); str = lm_message_node_get_attribute (node, "generation"); if (str == NULL) break; gen = atoi (str); str = lm_message_node_get_attribute (node, "component"); if (str != NULL) component = atoi (str); c = jingle_candidate_new (proto, ctype, NULL, component, address, port, gen, pref, user, pass, net); candidates = g_list_append (candidates, c); } if (i != NULL) { DEBUG ("not all nodes were processed, reporting error"); /* rollback these */ jingle_transport_free_candidates (candidates); SET_BAD_REQ ("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); }
void gabble_jingle_content_parse_add (GabbleJingleContent *c, WockyNode *content_node, gboolean google_mode, GError **error) { GabbleJingleContentPrivate *priv = c->priv; const gchar *name, *creator, *senders, *disposition; WockyNode *trans_node, *desc_node; GType transport_type = 0; GabbleJingleTransportIface *trans = NULL; JingleDialect dialect = gabble_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 = JINGLE_DIALECT_GTALK3; g_object_set (c->session, "dialect", JINGLE_DIALECT_GTALK3, NULL); transport_type = gabble_jingle_factory_lookup_transport ( gabble_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 && gabble_jingle_session_peer_has_cap (c->session, QUIRK_GOOGLE_WEBMAIL_CLIENT)) { if (gabble_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 = gabble_jingle_factory_lookup_transport ( gabble_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 == 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 = gabble_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) { gabble_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 = 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 == JINGLE_DIALECT_GTALK4) priv->gtalk4_event_id = g_idle_add (send_gtalk4_transport_accept, c); return; }