summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Ruprecht <maiku@pidgin.im>2008-11-07 03:00:09 +0000
committerMichael Ruprecht <maiku@pidgin.im>2008-11-07 03:00:09 +0000
commita9476c6118cc0e51c8833a9d38df8730fd1c74e8 (patch)
tree129def341b95c2f22930b11dbffaef8b0a7ea649
parent8a4eb695e7268208835c537043f6e57d83f7c5e4 (diff)
downloadpidgin-a9476c6118cc0e51c8833a9d38df8730fd1c74e8.tar.gz
Update Jingle raw-udp to latest spec version.
-rw-r--r--libpurple/protocols/jabber/jingle/rawudp.c245
-rw-r--r--libpurple/protocols/jabber/jingle/rawudp.h19
-rw-r--r--libpurple/protocols/jabber/jingle/rtp.c81
3 files changed, 225 insertions, 120 deletions
diff --git a/libpurple/protocols/jabber/jingle/rawudp.c b/libpurple/protocols/jabber/jingle/rawudp.c
index c6e4c444ac..a11d5e77be 100644
--- a/libpurple/protocols/jabber/jingle/rawudp.c
+++ b/libpurple/protocols/jabber/jingle/rawudp.c
@@ -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 @@ static JingleTransportClass *parent_class = NULL;
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 @@ jingle_rawudp_class_init (JingleRawUdpClass *klass)
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_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_ID,
- g_param_spec_string("id",
- "Id",
- "The id for this transport.",
- NULL,
- G_PARAM_READWRITE));
-
- 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 @@ jingle_rawudp_init (JingleRawUdp *rawudp)
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 @@ jingle_rawudp_set_property (GObject *object, guint prop_id, const GValue *value,
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 @@ jingle_rawudp_get_property (GObject *object, guint prop_id, GValue *value, GPara
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 @@ jingle_rawudp_get_property (GObject *object, guint prop_id, GValue *value, GPara
}
}
-JingleRawUdp *
-jingle_rawudp_create(guint generation, const gchar *id, const gchar *ip, guint port)
+void
+jingle_rawudp_add_local_candidate(JingleRawUdp *rawudp, JingleRawUdpCandidate *candidate)
{
- return g_object_new(jingle_rawudp_get_type(),
- "generation", generation,
- "id", id,
- "ip", ip,
- "port", port, NULL);
+ 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_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 @@ jingle_rawudp_to_xml_internal(JingleTransport *transport, xmlnode *content, Jing
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 *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);
- 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_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);
+ g_free(port);
+ g_free(generation);
+ }
}
return node;
diff --git a/libpurple/protocols/jabber/jingle/rawudp.h b/libpurple/protocols/jabber/jingle/rawudp.h
index ea8359e131..0b40f79a68 100644
--- a/libpurple/protocols/jabber/jingle/rawudp.h
+++ b/libpurple/protocols/jabber/jingle/rawudp.h
@@ -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 _JingleRawUdp JingleRawUdp;
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 @@ struct _JingleRawUdp
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 @@ extern "C" {
*/
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 --git a/libpurple/protocols/jabber/jingle/rtp.c b/libpurple/protocols/jabber/jingle/rtp.c
index c32af11ec4..a44d604dd7 100644
--- a/libpurple/protocols/jabber/jingle/rtp.c
+++ b/libpurple/protocols/jabber/jingle/rtp.c
@@ -206,11 +206,22 @@ jingle_rtp_get_media(JingleSession *session)
}
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 @@ jingle_rtp_candidate_to_transport(GType type, guint generation, FsCandidate *can
}
}
-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 @@ static void
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 @@ jingle_rtp_handle_action_internal(JingleContent *content, xmlnode *xmlcontent, J
}
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_rtp_handle_action_internal(JingleContent *content, xmlnode *xmlcontent, J
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 @@ jingle_rtp_handle_action_internal(JingleContent *content, xmlnode *xmlcontent, J
}
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),