# HG changeset patch # User Mike Ruprecht # Date 1226026809 0 # Node ID 365eb0b68d5fe2caa9604da57366e0a9a1cc3eab # Parent b9d4ab2c84c6138db590129f998d87347ca6c298 Update Jingle raw-udp to latest spec version. diff -r b9d4ab2c84c6 -r 365eb0b68d5f libpurple/protocols/jabber/jingle/rawudp.c --- a/libpurple/protocols/jabber/jingle/rawudp.c Thu Nov 06 08:26:14 2008 +0000 +++ b/libpurple/protocols/jabber/jingle/rawudp.c Fri Nov 07 03:00:09 2008 +0000 @@ -26,10 +26,8 @@ struct _JingleRawUdpPrivate { - guint generation; - gchar *id; - gchar *ip; - guint port; + GList *local_candidates; + GList *remote_candidates; }; #define JINGLE_RAWUDP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), JINGLE_TYPE_RAWUDP, JingleRawUdpPrivate)) @@ -46,12 +44,54 @@ enum { PROP_0, - PROP_GENERATION, - PROP_ID, - PROP_IP, - PROP_PORT, + PROP_LOCAL_CANDIDATES, + PROP_REMOTE_CANDIDATES, }; +static JingleRawUdpCandidate * +jingle_rawudp_candidate_copy(JingleRawUdpCandidate *candidate) +{ + JingleRawUdpCandidate *new_candidate = g_new0(JingleRawUdpCandidate, 1); + new_candidate->generation = candidate->generation; + new_candidate->component = candidate->component; + new_candidate->id = g_strdup(candidate->id); + new_candidate->ip = g_strdup(candidate->ip); + new_candidate->port = candidate->port; + return new_candidate; +} + +static void +jingle_rawudp_candidate_free(JingleRawUdpCandidate *candidate) +{ + g_free(candidate->id); + g_free(candidate->ip); +} + +GType +jingle_rawudp_candidate_get_type() +{ + static GType type = 0; + + if (type == 0) { + type = g_boxed_type_register_static("JingleRawUdpCandidate", + (GBoxedCopyFunc)jingle_rawudp_candidate_copy, + (GBoxedFreeFunc)jingle_rawudp_candidate_free); + } + return type; +} + +JingleRawUdpCandidate * +jingle_rawudp_candidate_new(const gchar *id, guint generation, guint component, const gchar *ip, guint port) +{ + JingleRawUdpCandidate *candidate = g_new0(JingleRawUdpCandidate, 1); + candidate->generation = generation; + candidate->component = component; + candidate->id = g_strdup(id); + candidate->ip = g_strdup(ip); + candidate->port = port; + return candidate; +} + GType jingle_rawudp_get_type() { @@ -88,37 +128,17 @@ klass->parent_class.parse = jingle_rawudp_parse_internal; klass->parent_class.transport_type = JINGLE_TRANSPORT_RAWUDP; - g_object_class_install_property(gobject_class, PROP_GENERATION, - g_param_spec_uint("generation", - "Generation", - "The generation for this transport.", - 0, - G_MAXUINT, - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property(gobject_class, PROP_ID, - g_param_spec_string("id", - "Id", - "The id for this transport.", - NULL, - G_PARAM_READWRITE)); + g_object_class_install_property(gobject_class, PROP_LOCAL_CANDIDATES, + g_param_spec_pointer("local-candidates", + "Local candidates", + "The local candidates for this transport.", + G_PARAM_READABLE)); - g_object_class_install_property(gobject_class, PROP_IP, - g_param_spec_string("ip", - "IP Address", - "The IP address for this transport.", - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property(gobject_class, PROP_PORT, - g_param_spec_uint("port", - "Port", - "The port for this transport.", - 0, - 65535, - 0, - G_PARAM_READWRITE)); + g_object_class_install_property(gobject_class, PROP_REMOTE_CANDIDATES, + g_param_spec_pointer("remote-candidates", + "Remote candidates", + "The remote candidates for this transport.", + G_PARAM_READABLE)); g_type_class_add_private(klass, sizeof(JingleRawUdpPrivate)); } @@ -133,11 +153,8 @@ static void jingle_rawudp_finalize (GObject *rawudp) { - JingleRawUdpPrivate *priv = JINGLE_RAWUDP_GET_PRIVATE(rawudp); +/* JingleRawUdpPrivate *priv = JINGLE_RAWUDP_GET_PRIVATE(rawudp); */ purple_debug_info("jingle","jingle_rawudp_finalize\n"); - - g_free(priv->id); - g_free(priv->ip); } static void @@ -149,19 +166,13 @@ rawudp = JINGLE_RAWUDP(object); switch (prop_id) { - case PROP_GENERATION: - rawudp->priv->generation = g_value_get_uint(value); - break; - case PROP_ID: - g_free(rawudp->priv->id); - rawudp->priv->id = g_value_dup_string(value); + case PROP_LOCAL_CANDIDATES: + rawudp->priv->local_candidates = + g_value_get_pointer(value); break; - case PROP_IP: - g_free(rawudp->priv->ip); - rawudp->priv->ip = g_value_dup_string(value); - break; - case PROP_PORT: - rawudp->priv->port = g_value_get_uint(value); + case PROP_REMOTE_CANDIDATES: + rawudp->priv->remote_candidates = + g_value_get_pointer(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -178,17 +189,11 @@ rawudp = JINGLE_RAWUDP(object); switch (prop_id) { - case PROP_GENERATION: - g_value_set_uint(value, rawudp->priv->generation); - break; - case PROP_ID: - g_value_set_string(value, rawudp->priv->id); + case PROP_LOCAL_CANDIDATES: + g_value_set_pointer(value, rawudp->priv->local_candidates); break; - case PROP_IP: - g_value_set_string(value, rawudp->priv->ip); - break; - case PROP_PORT: - g_value_set_uint(value, rawudp->priv->port); + case PROP_REMOTE_CANDIDATES: + g_value_set_pointer(value, rawudp->priv->remote_candidates); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -196,21 +201,91 @@ } } -JingleRawUdp * -jingle_rawudp_create(guint generation, const gchar *id, const gchar *ip, guint port) +void +jingle_rawudp_add_local_candidate(JingleRawUdp *rawudp, JingleRawUdpCandidate *candidate) +{ + GList *iter = rawudp->priv->local_candidates; + + for (; iter; iter = g_list_next(iter)) { + JingleRawUdpCandidate *c = iter->data; + if (!strcmp(c->id, candidate->id)) { + guint generation = c->generation + 1; + + g_boxed_free(JINGLE_TYPE_RAWUDP_CANDIDATE, c); + rawudp->priv->local_candidates = g_list_delete_link( + rawudp->priv->local_candidates, iter); + + candidate->generation = generation; + + rawudp->priv->local_candidates = g_list_append( + rawudp->priv->local_candidates, candidate); + return; + } + } + + rawudp->priv->local_candidates = g_list_append( + rawudp->priv->local_candidates, candidate); +} + +GList * +jingle_rawudp_get_remote_candidates(JingleRawUdp *rawudp) { - return g_object_new(jingle_rawudp_get_type(), - "generation", generation, - "id", id, - "ip", ip, - "port", port, NULL); + return g_list_copy(rawudp->priv->remote_candidates); +} + +static JingleRawUdpCandidate * +jingle_rawudp_get_remote_candidate_by_id(JingleRawUdp *rawudp, gchar *id) +{ + GList *iter = rawudp->priv->remote_candidates; + for (; iter; iter = g_list_next(iter)) { + JingleRawUdpCandidate *candidate = iter->data; + if (!strcmp(candidate->id, id)) { + return candidate; + } + } + return NULL; +} + +static void +jingle_rawudp_add_remote_candidate(JingleRawUdp *rawudp, JingleRawUdpCandidate *candidate) +{ + JingleRawUdpPrivate *priv = JINGLE_RAWUDP_GET_PRIVATE(rawudp); + JingleRawUdpCandidate *rawudp_candidate = + jingle_rawudp_get_remote_candidate_by_id(rawudp, candidate->id); + if (rawudp_candidate != NULL) { + priv->remote_candidates = g_list_remove( + priv->remote_candidates, rawudp_candidate); + g_boxed_free(JINGLE_TYPE_RAWUDP_CANDIDATE, rawudp_candidate); + } + priv->remote_candidates = g_list_append(priv->remote_candidates, candidate); } static JingleTransport * jingle_rawudp_parse_internal(xmlnode *rawudp) { JingleTransport *transport = parent_class->parse(rawudp); - + JingleRawUdpPrivate *priv = JINGLE_RAWUDP_GET_PRIVATE(transport); + xmlnode *candidate = xmlnode_get_child(rawudp, "candidate"); + JingleRawUdpCandidate *rawudp_candidate; + + for (; candidate; candidate = xmlnode_get_next_twin(candidate)) { + rawudp_candidate = jingle_rawudp_candidate_new( + xmlnode_get_attrib(candidate, "id"), + atoi(xmlnode_get_attrib(candidate, "generation")), + atoi(xmlnode_get_attrib(candidate, "component")), + xmlnode_get_attrib(candidate, "ip"), + atoi(xmlnode_get_attrib(candidate, "port"))); + jingle_rawudp_add_remote_candidate(JINGLE_RAWUDP(transport), rawudp_candidate); + } + + if (g_list_length(priv->remote_candidates) == 1) { + /* manufacture rtcp candidate */ + rawudp_candidate = g_boxed_copy(JINGLE_TYPE_RAWUDP_CANDIDATE, rawudp_candidate); + rawudp_candidate->component = 2; + rawudp_candidate->port = rawudp_candidate->port + 1; + jingle_rawudp_add_remote_candidate(JINGLE_RAWUDP(transport), rawudp_candidate); + } + return transport; } @@ -220,18 +295,26 @@ xmlnode *node = parent_class->to_xml(transport, content, action); if (action == JINGLE_SESSION_INITIATE || action == JINGLE_TRANSPORT_INFO) { - xmlnode *xmltransport = xmlnode_new_child(node, "candidate"); JingleRawUdpPrivate *priv = JINGLE_RAWUDP_GET_PRIVATE(transport); - gchar *generation = g_strdup_printf("%d", priv->generation); - gchar *port = g_strdup_printf("%d", priv->port); + GList *iter = priv->local_candidates; + + for (; iter; iter = g_list_next(iter)) { + JingleRawUdpCandidate *candidate = iter->data; - xmlnode_set_attrib(xmltransport, "generation", generation); - xmlnode_set_attrib(xmltransport, "id", priv->id); - xmlnode_set_attrib(xmltransport, "ip", priv->ip); - xmlnode_set_attrib(xmltransport, "port", port); + xmlnode *xmltransport = xmlnode_new_child(node, "candidate"); + gchar *generation = g_strdup_printf("%d", candidate->generation); + gchar *component = g_strdup_printf("%d", candidate->component); + gchar *port = g_strdup_printf("%d", candidate->port); - g_free(port); - g_free(generation); + xmlnode_set_attrib(xmltransport, "generation", generation); + xmlnode_set_attrib(xmltransport, "component", component); + xmlnode_set_attrib(xmltransport, "id", candidate->id); + xmlnode_set_attrib(xmltransport, "ip", candidate->ip); + xmlnode_set_attrib(xmltransport, "port", port); + + g_free(port); + g_free(generation); + } } return node; diff -r b9d4ab2c84c6 -r 365eb0b68d5f libpurple/protocols/jabber/jingle/rawudp.h --- a/libpurple/protocols/jabber/jingle/rawudp.h Thu Nov 06 08:26:14 2008 +0000 +++ b/libpurple/protocols/jabber/jingle/rawudp.h Fri Nov 07 03:00:09 2008 +0000 @@ -29,6 +29,7 @@ G_BEGIN_DECLS #define JINGLE_TYPE_RAWUDP (jingle_rawudp_get_type()) +#define JINGLE_TYPE_RAWUDP_CANDIDATE (jingle_rawudp_candidate_get_type()) #define JINGLE_RAWUDP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), JINGLE_TYPE_RAWUDP, JingleRawUdp)) #define JINGLE_RAWUDP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), JINGLE_TYPE_RAWUDP, JingleRawUdpClass)) #define JINGLE_IS_RAWUDP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), JINGLE_TYPE_RAWUDP)) @@ -41,6 +42,8 @@ typedef struct _JingleRawUdpClass JingleRawUdpClass; /** @copydoc _JingleRawUdpPrivate */ typedef struct _JingleRawUdpPrivate JingleRawUdpPrivate; +/** @copydoc _JingleRawUdpCandidate */ +typedef struct _JingleRawUdpCandidate JingleRawUdpCandidate; /** The rawudp class */ struct _JingleRawUdpClass @@ -58,10 +61,21 @@ JingleRawUdpPrivate *priv; /**< The private data of this object. */ }; +struct _JingleRawUdpCandidate +{ + guint generation; + guint component; + gchar *id; + gchar *ip; + guint port; +}; + #ifdef __cplusplus extern "C" { #endif +GType jingle_rawudp_candidate_get_type(void); + /** * Gets the rawudp class's GType * @@ -69,7 +83,10 @@ */ GType jingle_rawudp_get_type(void); -JingleRawUdp *jingle_rawudp_create(guint generation, const gchar *id, const gchar *ip, guint port); +JingleRawUdpCandidate *jingle_rawudp_candidate_new(const gchar *id, + guint generation, guint component, const gchar *ip, guint port); +void jingle_rawudp_add_local_candidate(JingleRawUdp *rawudp, JingleRawUdpCandidate *candidate); +GList *jingle_rawudp_get_remote_candidates(JingleRawUdp *rawudp); #ifdef __cplusplus } diff -r b9d4ab2c84c6 -r 365eb0b68d5f libpurple/protocols/jabber/jingle/rtp.c --- a/libpurple/protocols/jabber/jingle/rtp.c Thu Nov 06 08:26:14 2008 +0000 +++ b/libpurple/protocols/jabber/jingle/rtp.c Fri Nov 07 03:00:09 2008 +0000 @@ -206,11 +206,22 @@ } static JingleTransport * -jingle_rtp_candidate_to_transport(GType type, guint generation, FsCandidate *candidate) +jingle_rtp_candidates_to_transport(JingleSession *session, GType type, guint generation, GList *candidates) { if (type == JINGLE_TYPE_RAWUDP) { - return JINGLE_TRANSPORT(jingle_rawudp_create(generation, - candidate->foundation, candidate->ip, candidate->port)); + gchar *id = jabber_get_next_id(jingle_session_get_js(session)); + JingleTransport *transport = jingle_transport_create(JINGLE_TRANSPORT_RAWUDP); + JingleRawUdpCandidate *rawudp_candidate; + for (; candidates; candidates = g_list_next(candidates)) { + FsCandidate *candidate = candidates->data; + id = jabber_get_next_id(jingle_session_get_js(session)); + rawudp_candidate = jingle_rawudp_candidate_new(id, + generation, candidate->component_id, + candidate->ip, candidate->port); + jingle_rawudp_add_local_candidate(JINGLE_RAWUDP(transport), rawudp_candidate); + } + g_free(id); + return transport; #if 0 } else if (type == JINGLE_TYPE_ICEUDP) { return NULL; @@ -220,16 +231,22 @@ } } -static FsCandidate * -jingle_rtp_transport_to_candidate(xmlnode *transport) +static GList * +jingle_rtp_transport_to_candidates(JingleTransport *transport) { - xmlnode *candidate = xmlnode_get_child(transport, "candidate"); - const gchar *type = xmlnode_get_namespace(transport); + const gchar *type = jingle_transport_get_transport_type(transport); + GList *ret = NULL; if (!strcmp(type, JINGLE_TRANSPORT_RAWUDP)) { - return fs_candidate_new("", FS_COMPONENT_RTP, - FS_CANDIDATE_TYPE_SRFLX, FS_NETWORK_PROTOCOL_UDP, - xmlnode_get_attrib(candidate, "ip"), - atoi(xmlnode_get_attrib(candidate, "port"))); + GList *candidates = jingle_rawudp_get_remote_candidates(JINGLE_RAWUDP(transport)); + + for (; candidates; candidates = g_list_delete_link(candidates, candidates)) { + JingleRawUdpCandidate *candidate = candidates->data; + ret = g_list_append(ret, fs_candidate_new("", candidate->component, + FS_CANDIDATE_TYPE_SRFLX, FS_NETWORK_PROTOCOL_UDP, + candidate->ip, candidate->port)); + } + + return ret; #if 0 } else if (type == JINGLE_TRANSPORT_ICEUDP) { return NULL; @@ -264,23 +281,23 @@ jingle_rtp_new_candidate_cb(PurpleMedia *media, gchar *sid, gchar *name, FsCandidate *candidate, JingleSession *session) { purple_debug_info("jingle-rtp", "jingle_rtp_new_candidate_cb\n"); - - if (candidate->component_id == 1) { - JingleContent *content = jingle_session_find_content(session, sid, "initiator"); - JingleTransport *transport = - JINGLE_TRANSPORT(jingle_rtp_candidate_to_transport( - JINGLE_TYPE_RAWUDP, 0, candidate)); - jingle_content_set_pending_transport(content, transport); - jingle_content_accept_transport(content); - } } static void jingle_rtp_candidates_prepared_cb(PurpleMedia *media, gchar *sid, gchar *name, JingleSession *session) { JingleContent *content = jingle_session_find_content(session, sid, "initiator"); + GList *candidates = purple_media_get_local_candidates(media, sid, name); + JingleTransport *transport = + JINGLE_TRANSPORT(jingle_rtp_candidates_to_transport( + session, JINGLE_TYPE_RAWUDP, 0, candidates)); + g_list_free(candidates); + JINGLE_RTP_GET_PRIVATE(content)->candidates_ready = TRUE; + jingle_content_set_pending_transport(content, transport); + jingle_content_accept_transport(content); + if (jingle_rtp_ready_to_initiate(session, media)) jabber_iq_send(jingle_session_to_packet(session, JINGLE_SESSION_INITIATE)); } @@ -542,10 +559,10 @@ } case JINGLE_SESSION_INITIATE: { JingleSession *session = jingle_content_get_session(content); + JingleTransport *transport = jingle_transport_parse( + xmlnode_get_child(xmlcontent, "transport")); xmlnode *description = xmlnode_get_child(xmlcontent, "description"); - xmlnode *transport = xmlnode_get_child(xmlcontent, "transport"); - FsCandidate *candidate = jingle_rtp_transport_to_candidate(transport); - GList *candidates = g_list_append(NULL, candidate); + GList *candidates = jingle_rtp_transport_to_candidates(transport); GList *codecs = jingle_rtp_parse_codecs(description); jingle_rtp_init_media(content); @@ -554,12 +571,6 @@ jingle_content_get_name(content), jingle_session_get_remote_jid(session), codecs); - /* manufacture rtcp candidate */ - candidate = fs_candidate_copy(candidate); - candidate->component_id = 2; - candidate->port = candidate->port + 1; - candidates = g_list_append(candidates, candidate); - purple_media_add_remote_candidates(jingle_rtp_get_media(session), jingle_content_get_name(content), jingle_session_get_remote_jid(session), @@ -580,15 +591,9 @@ } case JINGLE_TRANSPORT_INFO: { JingleSession *session = jingle_content_get_session(content); - xmlnode *transport = xmlnode_get_child(xmlcontent, "transport"); - FsCandidate *candidate = jingle_rtp_transport_to_candidate(transport); - GList *candidates = g_list_append(NULL, candidate); - - /* manufacture rtcp candidate */ - candidate = fs_candidate_copy(candidate); - candidate->component_id = 2; - candidate->port = candidate->port + 1; - candidates = g_list_append(candidates, candidate); + JingleTransport *transport = jingle_transport_parse( + xmlnode_get_child(xmlcontent, "transport")); + GList *candidates = jingle_rtp_transport_to_candidates(transport); purple_media_add_remote_candidates(jingle_rtp_get_media(session), jingle_content_get_name(content),