rename accountopt.[ch] to purpleaccountoption.[ch]
[pidgin-git.git] / libpurple / protocols / jabber / jingle / iceudp.c
bloba52be2ff3e683c9c6419e74e1f6e15e5955c460c
1 /**
2 * @file iceudp.c
4 * purple
6 * Purple is the legal property of its developers, whose names are too numerous
7 * to list here. Please refer to the COPYRIGHT file distributed with this
8 * source distribution.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
25 #include "internal.h"
26 #include "glibcompat.h"
28 #include "iceudp.h"
29 #include "jingle.h"
30 #include "debug.h"
32 #include <string.h>
34 struct _JingleIceUdp
36 JingleTransport parent;
39 typedef struct
41 GList *local_candidates;
42 GList *remote_candidates;
43 } JingleIceUdpPrivate;
45 enum {
46 PROP_0,
47 PROP_LOCAL_CANDIDATES,
48 PROP_REMOTE_CANDIDATES,
49 PROP_LAST
52 static GParamSpec *properties[PROP_LAST];
54 G_DEFINE_DYNAMIC_TYPE_EXTENDED(
55 JingleIceUdp,
56 jingle_iceudp,
57 JINGLE_TYPE_TRANSPORT,
59 G_ADD_PRIVATE_DYNAMIC(JingleIceUdp)
62 /******************************************************************************
63 * JingleIceUdp Transport Implementation
64 *****************************************************************************/
65 static void
66 jingle_iceudp_add_local_candidate(JingleTransport *transport, const gchar *id, guint generation, PurpleMediaCandidate *candidate)
68 JingleIceUdp *iceudp = JINGLE_ICEUDP(transport);
69 JingleIceUdpPrivate *priv = jingle_iceudp_get_instance_private(iceudp);
70 PurpleMediaCandidateType type;
71 gchar *ip;
72 gchar *username;
73 gchar *password;
74 JingleIceUdpCandidate *iceudp_candidate;
75 GList *iter;
77 ip = purple_media_candidate_get_ip(candidate);
78 username = purple_media_candidate_get_username(candidate);
79 password = purple_media_candidate_get_password(candidate);
80 type = purple_media_candidate_get_candidate_type(candidate);
82 iceudp_candidate = jingle_iceudp_candidate_new(id,
83 purple_media_candidate_get_component_id(candidate),
84 purple_media_candidate_get_foundation(candidate),
85 generation, ip, 0,
86 purple_media_candidate_get_port(candidate),
87 purple_media_candidate_get_priority(candidate), "udp",
88 type == PURPLE_MEDIA_CANDIDATE_TYPE_HOST ? "host" :
89 type == PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX ? "srflx" :
90 type == PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX ? "prflx" :
91 type == PURPLE_MEDIA_CANDIDATE_TYPE_RELAY ? "relay" :
92 "", username, password);
93 iceudp_candidate->reladdr = purple_media_candidate_get_base_ip(candidate);
94 iceudp_candidate->relport = purple_media_candidate_get_base_port(candidate);
96 g_free(password);
97 g_free(username);
98 g_free(ip);
100 for (iter = priv->local_candidates; iter; iter = g_list_next(iter)) {
101 JingleIceUdpCandidate *c = iter->data;
102 if (purple_strequal(c->id, id)) {
103 generation = c->generation + 1;
105 g_boxed_free(JINGLE_TYPE_ICEUDP_CANDIDATE, c);
106 priv->local_candidates = g_list_delete_link(
107 priv->local_candidates, iter);
109 iceudp_candidate->generation = generation;
111 priv->local_candidates = g_list_append(
112 priv->local_candidates, iceudp_candidate);
114 g_object_notify_by_pspec(G_OBJECT(iceudp), properties[PROP_LOCAL_CANDIDATES]);
116 return;
120 priv->local_candidates = g_list_append(
121 priv->local_candidates, iceudp_candidate);
123 g_object_notify_by_pspec(G_OBJECT(iceudp), properties[PROP_LOCAL_CANDIDATES]);
126 static GList *
127 jingle_iceudp_get_remote_candidates(JingleTransport *transport)
129 JingleIceUdp *iceudp = JINGLE_ICEUDP(transport);
130 JingleIceUdpPrivate *priv = jingle_iceudp_get_instance_private(iceudp);
131 GList *candidates = priv->remote_candidates;
132 GList *ret = NULL;
134 for (; candidates; candidates = g_list_next(candidates)) {
135 JingleIceUdpCandidate *candidate = candidates->data;
136 PurpleMediaCandidate *new_candidate = purple_media_candidate_new(
137 candidate->foundation, candidate->component,
138 purple_strequal(candidate->type, "host") ?
139 PURPLE_MEDIA_CANDIDATE_TYPE_HOST :
140 purple_strequal(candidate->type, "srflx") ?
141 PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX :
142 purple_strequal(candidate->type, "prflx") ?
143 PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX :
144 purple_strequal(candidate->type, "relay") ?
145 PURPLE_MEDIA_CANDIDATE_TYPE_RELAY : 0,
146 PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
147 candidate->ip, candidate->port);
148 g_object_set(new_candidate,
149 "base-ip", candidate->reladdr,
150 "base-port", candidate->relport,
151 "username", candidate->username,
152 "password", candidate->password,
153 "priority", candidate->priority,
154 NULL);
155 ret = g_list_append(ret, new_candidate);
158 return ret;
161 static JingleIceUdpCandidate *
162 jingle_iceudp_get_remote_candidate_by_id(JingleIceUdp *iceudp,
163 const gchar *id)
165 JingleIceUdpPrivate *priv = jingle_iceudp_get_instance_private(iceudp);
166 GList *iter = priv->remote_candidates;
167 for (; iter; iter = g_list_next(iter)) {
168 JingleIceUdpCandidate *candidate = iter->data;
169 if (purple_strequal(candidate->id, id)) {
170 return candidate;
173 return NULL;
176 static void
177 jingle_iceudp_add_remote_candidate(JingleIceUdp *iceudp, JingleIceUdpCandidate *candidate)
179 JingleIceUdpPrivate *priv = jingle_iceudp_get_instance_private(iceudp);
180 JingleIceUdpCandidate *iceudp_candidate =
181 jingle_iceudp_get_remote_candidate_by_id(iceudp,
182 candidate->id);
183 if (iceudp_candidate != NULL) {
184 priv->remote_candidates = g_list_remove(
185 priv->remote_candidates, iceudp_candidate);
186 g_boxed_free(JINGLE_TYPE_ICEUDP_CANDIDATE, iceudp_candidate);
188 priv->remote_candidates = g_list_append(priv->remote_candidates, candidate);
190 g_object_notify_by_pspec(G_OBJECT(iceudp), properties[PROP_REMOTE_CANDIDATES]);
193 static JingleTransport *
194 jingle_iceudp_parse_internal(PurpleXmlNode *iceudp)
196 JingleTransport *transport = JINGLE_TRANSPORT_CLASS(jingle_iceudp_parent_class)->parse(iceudp);
197 PurpleXmlNode *candidate = purple_xmlnode_get_child(iceudp, "candidate");
198 JingleIceUdpCandidate *iceudp_candidate = NULL;
200 const gchar *username = purple_xmlnode_get_attrib(iceudp, "ufrag");
201 const gchar *password = purple_xmlnode_get_attrib(iceudp, "pwd");
203 for (; candidate; candidate = purple_xmlnode_get_next_twin(candidate)) {
204 const gchar *relport = purple_xmlnode_get_attrib(candidate, "rel-port");
205 const gchar *component = purple_xmlnode_get_attrib(candidate, "component");
206 const gchar *foundation = purple_xmlnode_get_attrib(candidate, "foundation");
207 const gchar *generation = purple_xmlnode_get_attrib(candidate, "generation");
208 const gchar *id = purple_xmlnode_get_attrib(candidate, "id");
209 const gchar *ip = purple_xmlnode_get_attrib(candidate, "ip");
210 const gchar *network = purple_xmlnode_get_attrib(candidate, "network");
211 const gchar *port = purple_xmlnode_get_attrib(candidate, "port");
212 const gchar *priority = purple_xmlnode_get_attrib(candidate, "priority");
213 const gchar *protocol = purple_xmlnode_get_attrib(candidate, "protocol");
214 const gchar *type = purple_xmlnode_get_attrib(candidate, "type");
216 if (!component || !foundation || !generation || !id || !ip ||
217 !network || !port || !priority || !protocol || !type)
218 continue;
220 iceudp_candidate = jingle_iceudp_candidate_new(
222 atoi(component),
223 foundation,
224 atoi(generation),
226 atoi(network),
227 atoi(port),
228 atoi(priority),
229 protocol,
230 type,
231 username, password);
232 iceudp_candidate->reladdr = g_strdup(
233 purple_xmlnode_get_attrib(candidate, "rel-addr"));
234 iceudp_candidate->relport =
235 relport != NULL ? atoi(relport) : 0;
236 iceudp_candidate->rem_known = TRUE;
237 jingle_iceudp_add_remote_candidate(JINGLE_ICEUDP(transport), iceudp_candidate);
240 return transport;
243 static PurpleXmlNode *
244 jingle_iceudp_to_xml_internal(JingleTransport *transport, PurpleXmlNode *content, JingleActionType action)
246 PurpleXmlNode *node = JINGLE_TRANSPORT_CLASS(jingle_iceudp_parent_class)->to_xml(transport, content, action);
248 if (action == JINGLE_SESSION_INITIATE ||
249 action == JINGLE_SESSION_ACCEPT ||
250 action == JINGLE_TRANSPORT_INFO ||
251 action == JINGLE_CONTENT_ADD ||
252 action == JINGLE_TRANSPORT_REPLACE) {
253 JingleIceUdpPrivate *priv = jingle_iceudp_get_instance_private(JINGLE_ICEUDP(transport));
254 GList *iter = priv->local_candidates;
255 gboolean used_candidate = FALSE;
257 for (; iter; iter = g_list_next(iter)) {
258 JingleIceUdpCandidate *candidate = iter->data;
259 PurpleXmlNode *xmltransport;
260 gchar *component, *generation, *network,
261 *port, *priority;
263 if (candidate->rem_known == TRUE)
264 continue;
266 used_candidate = TRUE;
267 candidate->rem_known = TRUE;
269 xmltransport = purple_xmlnode_new_child(node, "candidate");
270 component = g_strdup_printf("%d", candidate->component);
271 generation = g_strdup_printf("%d",
272 candidate->generation);
273 network = g_strdup_printf("%d", candidate->network);
274 port = g_strdup_printf("%d", candidate->port);
275 priority = g_strdup_printf("%d", candidate->priority);
277 purple_xmlnode_set_attrib(xmltransport, "component", component);
278 purple_xmlnode_set_attrib(xmltransport, "foundation", candidate->foundation);
279 purple_xmlnode_set_attrib(xmltransport, "generation", generation);
280 purple_xmlnode_set_attrib(xmltransport, "id", candidate->id);
281 purple_xmlnode_set_attrib(xmltransport, "ip", candidate->ip);
282 purple_xmlnode_set_attrib(xmltransport, "network", network);
283 purple_xmlnode_set_attrib(xmltransport, "port", port);
284 purple_xmlnode_set_attrib(xmltransport, "priority", priority);
285 purple_xmlnode_set_attrib(xmltransport, "protocol", candidate->protocol);
287 if (candidate->reladdr != NULL &&
288 (!purple_strequal(candidate->ip, candidate->reladdr) ||
289 (candidate->port != candidate->relport))) {
290 gchar *relport = g_strdup_printf("%d",
291 candidate->relport);
292 purple_xmlnode_set_attrib(xmltransport, "rel-addr",
293 candidate->reladdr);
294 purple_xmlnode_set_attrib(xmltransport, "rel-port",
295 relport);
296 g_free(relport);
299 purple_xmlnode_set_attrib(xmltransport, "type", candidate->type);
301 g_free(component);
302 g_free(generation);
303 g_free(network);
304 g_free(port);
305 g_free(priority);
308 if (used_candidate == TRUE) {
309 JingleIceUdpCandidate *candidate =
310 priv->local_candidates->data;
311 purple_xmlnode_set_attrib(node, "pwd", candidate->password);
312 purple_xmlnode_set_attrib(node, "ufrag", candidate->username);
316 return node;
319 /******************************************************************************
320 * JingleIceUdp GObject Implementation
321 *****************************************************************************/
322 static void
323 jingle_iceudp_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
325 JingleIceUdp *iceudp = JINGLE_ICEUDP(object);
326 JingleIceUdpPrivate *priv = jingle_iceudp_get_instance_private(iceudp);
328 switch (prop_id) {
329 case PROP_LOCAL_CANDIDATES:
330 priv->local_candidates =
331 g_value_get_pointer(value);
332 break;
333 case PROP_REMOTE_CANDIDATES:
334 priv->remote_candidates =
335 g_value_get_pointer(value);
336 break;
337 default:
338 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
339 break;
343 static void
344 jingle_iceudp_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
346 JingleIceUdp *iceudp = JINGLE_ICEUDP(object);
347 JingleIceUdpPrivate *priv = jingle_iceudp_get_instance_private(iceudp);
349 switch (prop_id) {
350 case PROP_LOCAL_CANDIDATES:
351 g_value_set_pointer(value, priv->local_candidates);
352 break;
353 case PROP_REMOTE_CANDIDATES:
354 g_value_set_pointer(value, priv->remote_candidates);
355 break;
356 default:
357 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
358 break;
362 static void
363 jingle_iceudp_init (JingleIceUdp *iceudp)
367 static void
368 jingle_iceudp_finalize (GObject *iceudp)
370 /* JingleIceUdpPrivate *priv = JINGLE_ICEUDP_GET_PRIVATE(iceudp); */
371 purple_debug_info("jingle","jingle_iceudp_finalize\n");
373 G_OBJECT_CLASS(jingle_iceudp_parent_class)->finalize(iceudp);
376 static void
377 jingle_iceudp_class_finalize (JingleIceUdpClass *klass)
381 static void
382 jingle_iceudp_class_init (JingleIceUdpClass *klass)
384 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
385 JingleTransportClass *transport_class = JINGLE_TRANSPORT_CLASS(klass);
387 obj_class->finalize = jingle_iceudp_finalize;
388 obj_class->set_property = jingle_iceudp_set_property;
389 obj_class->get_property = jingle_iceudp_get_property;
391 transport_class->to_xml = jingle_iceudp_to_xml_internal;
392 transport_class->parse = jingle_iceudp_parse_internal;
393 transport_class->transport_type = JINGLE_TRANSPORT_ICEUDP;
394 transport_class->add_local_candidate = jingle_iceudp_add_local_candidate;
395 transport_class->get_remote_candidates = jingle_iceudp_get_remote_candidates;
397 properties[PROP_LOCAL_CANDIDATES] = g_param_spec_pointer("local-candidates",
398 "Local candidates",
399 "The local candidates for this transport.",
400 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
402 properties[PROP_REMOTE_CANDIDATES] = g_param_spec_pointer("remote-candidates",
403 "Remote candidates",
404 "The remote candidates for this transport.",
405 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
407 g_object_class_install_properties(obj_class, PROP_LAST, properties);
410 /******************************************************************************
411 * JingleIceUdpCandidate Boxed Implementation
412 *****************************************************************************/
413 static JingleIceUdpCandidate *
414 jingle_iceudp_candidate_copy(JingleIceUdpCandidate *candidate)
416 JingleIceUdpCandidate *new_candidate = g_new0(JingleIceUdpCandidate, 1);
417 new_candidate->id = g_strdup(candidate->id);
418 new_candidate->component = candidate->component;
419 new_candidate->foundation = g_strdup(candidate->foundation);
420 new_candidate->generation = candidate->generation;
421 new_candidate->ip = g_strdup(candidate->ip);
422 new_candidate->network = candidate->network;
423 new_candidate->port = candidate->port;
424 new_candidate->priority = candidate->priority;
425 new_candidate->protocol = g_strdup(candidate->protocol);
426 new_candidate->type = g_strdup(candidate->type);
428 new_candidate->username = g_strdup(candidate->username);
429 new_candidate->password = g_strdup(candidate->password);
431 new_candidate->rem_known = candidate->rem_known;
433 return new_candidate;
436 static void
437 jingle_iceudp_candidate_free(JingleIceUdpCandidate *candidate)
439 g_free(candidate->foundation);
440 g_free(candidate->id);
441 g_free(candidate->ip);
442 g_free(candidate->protocol);
443 g_free(candidate->reladdr);
444 g_free(candidate->type);
446 g_free(candidate->username);
447 g_free(candidate->password);
450 G_DEFINE_BOXED_TYPE(JingleIceUdpCandidate, jingle_iceudp_candidate,
451 jingle_iceudp_candidate_copy, jingle_iceudp_candidate_free)
453 /******************************************************************************
454 * Public API
455 *****************************************************************************/
456 void
457 jingle_iceudp_register(PurplePlugin *plugin) {
458 jingle_iceudp_register_type(G_TYPE_MODULE(plugin));
461 JingleIceUdpCandidate *
462 jingle_iceudp_candidate_new(const gchar *id,
463 guint component, const gchar *foundation,
464 guint generation, const gchar *ip,
465 guint network, guint port, guint priority,
466 const gchar *protocol, const gchar *type,
467 const gchar *username, const gchar *password)
469 JingleIceUdpCandidate *candidate = g_new0(JingleIceUdpCandidate, 1);
470 candidate->id = g_strdup(id);
471 candidate->component = component;
472 candidate->foundation = g_strdup(foundation);
473 candidate->generation = generation;
474 candidate->ip = g_strdup(ip);
475 candidate->network = network;
476 candidate->port = port;
477 candidate->priority = priority;
478 candidate->protocol = g_strdup(protocol);
479 candidate->type = g_strdup(type);
481 candidate->username = g_strdup(username);
482 candidate->password = g_strdup(password);
484 candidate->rem_known = FALSE;
485 return candidate;