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
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
26 #include "glibcompat.h"
36 JingleTransport parent
;
41 GList
*local_candidates
;
42 GList
*remote_candidates
;
43 } JingleIceUdpPrivate
;
47 PROP_LOCAL_CANDIDATES
,
48 PROP_REMOTE_CANDIDATES
,
52 static GParamSpec
*properties
[PROP_LAST
];
54 G_DEFINE_DYNAMIC_TYPE_EXTENDED(
57 JINGLE_TYPE_TRANSPORT
,
59 G_ADD_PRIVATE_DYNAMIC(JingleIceUdp
)
62 /******************************************************************************
63 * JingleIceUdp Transport Implementation
64 *****************************************************************************/
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
;
74 JingleIceUdpCandidate
*iceudp_candidate
;
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
),
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
);
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
]);
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
]);
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
;
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
,
155 ret
= g_list_append(ret
, new_candidate
);
161 static JingleIceUdpCandidate
*
162 jingle_iceudp_get_remote_candidate_by_id(JingleIceUdp
*iceudp
,
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
)) {
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
,
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
)
220 iceudp_candidate
= jingle_iceudp_candidate_new(
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
);
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
,
263 if (candidate
->rem_known
== TRUE
)
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",
292 purple_xmlnode_set_attrib(xmltransport
, "rel-addr",
294 purple_xmlnode_set_attrib(xmltransport
, "rel-port",
299 purple_xmlnode_set_attrib(xmltransport
, "type", candidate
->type
);
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
);
319 /******************************************************************************
320 * JingleIceUdp GObject Implementation
321 *****************************************************************************/
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
);
329 case PROP_LOCAL_CANDIDATES
:
330 priv
->local_candidates
=
331 g_value_get_pointer(value
);
333 case PROP_REMOTE_CANDIDATES
:
334 priv
->remote_candidates
=
335 g_value_get_pointer(value
);
338 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
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
);
350 case PROP_LOCAL_CANDIDATES
:
351 g_value_set_pointer(value
, priv
->local_candidates
);
353 case PROP_REMOTE_CANDIDATES
:
354 g_value_set_pointer(value
, priv
->remote_candidates
);
357 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
363 jingle_iceudp_init (JingleIceUdp
*iceudp
)
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
);
377 jingle_iceudp_class_finalize (JingleIceUdpClass
*klass
)
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",
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",
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
;
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 /******************************************************************************
455 *****************************************************************************/
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
;