diff libpurple/protocols/jabber/jingle/rawudp.c @ 26030:365eb0b68d5f

Update Jingle raw-udp to latest spec version.
author Mike Ruprecht <maiku@soc.pidgin.im>
date Fri, 07 Nov 2008 03:00:09 +0000
parents 7252e3d0c627
children 835a7003eed3
line wrap: on
line diff
--- 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;