Mercurial > pidgin.yaz
comparison libpurple/protocols/jabber/jingle/iceudp.c @ 26042:bee5ab815291
Added a Jingle ice-udp transmitter.
author | Mike Ruprecht <maiku@soc.pidgin.im> |
---|---|
date | Mon, 24 Nov 2008 10:43:38 +0000 |
parents | |
children | db517c55c508 |
comparison
equal
deleted
inserted
replaced
26041:70ae1029bb70 | 26042:bee5ab815291 |
---|---|
1 /** | |
2 * @file iceudp.c | |
3 * | |
4 * purple | |
5 * | |
6 * This program is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
11 * This program is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License | |
17 * along with this program; if not, write to the Free Software | |
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA | |
19 */ | |
20 | |
21 #include "iceudp.h" | |
22 #include "jingle.h" | |
23 #include "debug.h" | |
24 | |
25 #include <string.h> | |
26 | |
27 struct _JingleIceUdpPrivate | |
28 { | |
29 GList *local_candidates; | |
30 GList *remote_candidates; | |
31 }; | |
32 | |
33 #define JINGLE_ICEUDP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), JINGLE_TYPE_ICEUDP, JingleIceUdpPrivate)) | |
34 | |
35 static void jingle_iceudp_class_init (JingleIceUdpClass *klass); | |
36 static void jingle_iceudp_init (JingleIceUdp *iceudp); | |
37 static void jingle_iceudp_finalize (GObject *object); | |
38 static void jingle_iceudp_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); | |
39 static void jingle_iceudp_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); | |
40 static JingleTransport *jingle_iceudp_parse_internal(xmlnode *iceudp); | |
41 static xmlnode *jingle_iceudp_to_xml_internal(JingleTransport *transport, xmlnode *content, JingleActionType action); | |
42 | |
43 static JingleTransportClass *parent_class = NULL; | |
44 | |
45 enum { | |
46 PROP_0, | |
47 PROP_LOCAL_CANDIDATES, | |
48 PROP_REMOTE_CANDIDATES, | |
49 }; | |
50 | |
51 static JingleIceUdpCandidate * | |
52 jingle_iceudp_candidate_copy(JingleIceUdpCandidate *candidate) | |
53 { | |
54 JingleIceUdpCandidate *new_candidate = g_new0(JingleIceUdpCandidate, 1); | |
55 new_candidate->component = candidate->component; | |
56 new_candidate->foundation = g_strdup(candidate->foundation); | |
57 new_candidate->generation = candidate->generation; | |
58 new_candidate->ip = g_strdup(candidate->ip); | |
59 new_candidate->network = candidate->network; | |
60 new_candidate->port = candidate->port; | |
61 new_candidate->priority = candidate->priority; | |
62 new_candidate->protocol = g_strdup(candidate->protocol); | |
63 new_candidate->type = g_strdup(candidate->type); | |
64 | |
65 new_candidate->username = g_strdup(candidate->username); | |
66 new_candidate->password = g_strdup(candidate->password); | |
67 | |
68 return new_candidate; | |
69 } | |
70 | |
71 static void | |
72 jingle_iceudp_candidate_free(JingleIceUdpCandidate *candidate) | |
73 { | |
74 g_free(candidate->foundation); | |
75 g_free(candidate->ip); | |
76 g_free(candidate->protocol); | |
77 g_free(candidate->type); | |
78 | |
79 g_free(candidate->username); | |
80 g_free(candidate->password); | |
81 } | |
82 | |
83 GType | |
84 jingle_iceudp_candidate_get_type() | |
85 { | |
86 static GType type = 0; | |
87 | |
88 if (type == 0) { | |
89 type = g_boxed_type_register_static("JingleIceUdpCandidate", | |
90 (GBoxedCopyFunc)jingle_iceudp_candidate_copy, | |
91 (GBoxedFreeFunc)jingle_iceudp_candidate_free); | |
92 } | |
93 return type; | |
94 } | |
95 | |
96 JingleIceUdpCandidate * | |
97 jingle_iceudp_candidate_new(guint component, const gchar *foundation, | |
98 guint generation, const gchar *ip, guint network, | |
99 guint port, guint priority, const gchar *protocol, | |
100 const gchar *type, const gchar *username, const gchar *password) | |
101 { | |
102 JingleIceUdpCandidate *candidate = g_new0(JingleIceUdpCandidate, 1); | |
103 candidate->component = component; | |
104 candidate->foundation = g_strdup(foundation); | |
105 candidate->generation = generation; | |
106 candidate->ip = g_strdup(ip); | |
107 candidate->network = network; | |
108 candidate->port = port; | |
109 candidate->priority = priority; | |
110 candidate->protocol = g_strdup(protocol); | |
111 candidate->type = g_strdup(type); | |
112 | |
113 candidate->username = g_strdup(username); | |
114 candidate->password = g_strdup(password); | |
115 return candidate; | |
116 } | |
117 | |
118 GType | |
119 jingle_iceudp_get_type() | |
120 { | |
121 static GType type = 0; | |
122 | |
123 if (type == 0) { | |
124 static const GTypeInfo info = { | |
125 sizeof(JingleIceUdpClass), | |
126 NULL, | |
127 NULL, | |
128 (GClassInitFunc) jingle_iceudp_class_init, | |
129 NULL, | |
130 NULL, | |
131 sizeof(JingleIceUdp), | |
132 0, | |
133 (GInstanceInitFunc) jingle_iceudp_init, | |
134 NULL | |
135 }; | |
136 type = g_type_register_static(JINGLE_TYPE_TRANSPORT, "JingleIceUdp", &info, 0); | |
137 } | |
138 return type; | |
139 } | |
140 | |
141 static void | |
142 jingle_iceudp_class_init (JingleIceUdpClass *klass) | |
143 { | |
144 GObjectClass *gobject_class = (GObjectClass*)klass; | |
145 parent_class = g_type_class_peek_parent(klass); | |
146 | |
147 gobject_class->finalize = jingle_iceudp_finalize; | |
148 gobject_class->set_property = jingle_iceudp_set_property; | |
149 gobject_class->get_property = jingle_iceudp_get_property; | |
150 klass->parent_class.to_xml = jingle_iceudp_to_xml_internal; | |
151 klass->parent_class.parse = jingle_iceudp_parse_internal; | |
152 klass->parent_class.transport_type = JINGLE_TRANSPORT_ICEUDP; | |
153 | |
154 g_object_class_install_property(gobject_class, PROP_LOCAL_CANDIDATES, | |
155 g_param_spec_pointer("local-candidates", | |
156 "Local candidates", | |
157 "The local candidates for this transport.", | |
158 G_PARAM_READABLE)); | |
159 | |
160 g_object_class_install_property(gobject_class, PROP_REMOTE_CANDIDATES, | |
161 g_param_spec_pointer("remote-candidates", | |
162 "Remote candidates", | |
163 "The remote candidates for this transport.", | |
164 G_PARAM_READABLE)); | |
165 | |
166 g_type_class_add_private(klass, sizeof(JingleIceUdpPrivate)); | |
167 } | |
168 | |
169 static void | |
170 jingle_iceudp_init (JingleIceUdp *iceudp) | |
171 { | |
172 iceudp->priv = JINGLE_ICEUDP_GET_PRIVATE(iceudp); | |
173 memset(iceudp->priv, 0, sizeof(iceudp->priv)); | |
174 } | |
175 | |
176 static void | |
177 jingle_iceudp_finalize (GObject *iceudp) | |
178 { | |
179 /* JingleIceUdpPrivate *priv = JINGLE_ICEUDP_GET_PRIVATE(iceudp); */ | |
180 purple_debug_info("jingle","jingle_iceudp_finalize\n"); | |
181 } | |
182 | |
183 static void | |
184 jingle_iceudp_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) | |
185 { | |
186 JingleIceUdp *iceudp; | |
187 g_return_if_fail(JINGLE_IS_ICEUDP(object)); | |
188 | |
189 iceudp = JINGLE_ICEUDP(object); | |
190 | |
191 switch (prop_id) { | |
192 case PROP_LOCAL_CANDIDATES: | |
193 iceudp->priv->local_candidates = | |
194 g_value_get_pointer(value); | |
195 break; | |
196 case PROP_REMOTE_CANDIDATES: | |
197 iceudp->priv->remote_candidates = | |
198 g_value_get_pointer(value); | |
199 break; | |
200 default: | |
201 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | |
202 break; | |
203 } | |
204 } | |
205 | |
206 static void | |
207 jingle_iceudp_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) | |
208 { | |
209 JingleIceUdp *iceudp; | |
210 g_return_if_fail(JINGLE_IS_ICEUDP(object)); | |
211 | |
212 iceudp = JINGLE_ICEUDP(object); | |
213 | |
214 switch (prop_id) { | |
215 case PROP_LOCAL_CANDIDATES: | |
216 g_value_set_pointer(value, iceudp->priv->local_candidates); | |
217 break; | |
218 case PROP_REMOTE_CANDIDATES: | |
219 g_value_set_pointer(value, iceudp->priv->remote_candidates); | |
220 break; | |
221 default: | |
222 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | |
223 break; | |
224 } | |
225 } | |
226 | |
227 void | |
228 jingle_iceudp_add_local_candidate(JingleIceUdp *iceudp, JingleIceUdpCandidate *candidate) | |
229 { | |
230 GList *iter = iceudp->priv->local_candidates; | |
231 | |
232 for (; iter; iter = g_list_next(iter)) { | |
233 JingleIceUdpCandidate *c = iter->data; | |
234 if ((c->component == candidate->component) && | |
235 !strcmp(c->foundation, candidate->foundation)) { | |
236 guint generation = c->generation + 1; | |
237 | |
238 g_boxed_free(JINGLE_TYPE_ICEUDP_CANDIDATE, c); | |
239 iceudp->priv->local_candidates = g_list_delete_link( | |
240 iceudp->priv->local_candidates, iter); | |
241 | |
242 candidate->generation = generation; | |
243 | |
244 iceudp->priv->local_candidates = g_list_append( | |
245 iceudp->priv->local_candidates, candidate); | |
246 return; | |
247 } | |
248 } | |
249 | |
250 iceudp->priv->local_candidates = g_list_append( | |
251 iceudp->priv->local_candidates, candidate); | |
252 } | |
253 | |
254 GList * | |
255 jingle_iceudp_get_remote_candidates(JingleIceUdp *iceudp) | |
256 { | |
257 return g_list_copy(iceudp->priv->remote_candidates); | |
258 } | |
259 | |
260 static JingleIceUdpCandidate * | |
261 jingle_iceudp_get_remote_candidate_by_id(JingleIceUdp *iceudp, | |
262 guint component, const gchar *foundation) | |
263 { | |
264 GList *iter = iceudp->priv->remote_candidates; | |
265 for (; iter; iter = g_list_next(iter)) { | |
266 JingleIceUdpCandidate *candidate = iter->data; | |
267 if ((candidate->component == component) && | |
268 !strcmp(candidate->foundation, foundation)) { | |
269 return candidate; | |
270 } | |
271 } | |
272 return NULL; | |
273 } | |
274 | |
275 static void | |
276 jingle_iceudp_add_remote_candidate(JingleIceUdp *iceudp, JingleIceUdpCandidate *candidate) | |
277 { | |
278 JingleIceUdpPrivate *priv = JINGLE_ICEUDP_GET_PRIVATE(iceudp); | |
279 JingleIceUdpCandidate *iceudp_candidate = | |
280 jingle_iceudp_get_remote_candidate_by_id(iceudp, | |
281 candidate->component, candidate->foundation); | |
282 if (iceudp_candidate != NULL) { | |
283 priv->remote_candidates = g_list_remove( | |
284 priv->remote_candidates, iceudp_candidate); | |
285 g_boxed_free(JINGLE_TYPE_ICEUDP_CANDIDATE, iceudp_candidate); | |
286 } | |
287 priv->remote_candidates = g_list_append(priv->remote_candidates, candidate); | |
288 } | |
289 | |
290 static JingleTransport * | |
291 jingle_iceudp_parse_internal(xmlnode *iceudp) | |
292 { | |
293 JingleTransport *transport = parent_class->parse(iceudp); | |
294 xmlnode *candidate = xmlnode_get_child(iceudp, "candidate"); | |
295 JingleIceUdpCandidate *iceudp_candidate = NULL; | |
296 | |
297 const gchar *username = xmlnode_get_attrib(iceudp, "ufrag"); | |
298 const gchar *password = xmlnode_get_attrib(iceudp, "pwd"); | |
299 | |
300 for (; candidate; candidate = xmlnode_get_next_twin(candidate)) { | |
301 iceudp_candidate = jingle_iceudp_candidate_new( | |
302 atoi(xmlnode_get_attrib(candidate, "component")), | |
303 xmlnode_get_attrib(candidate, "foundation"), | |
304 atoi(xmlnode_get_attrib(candidate, "generation")), | |
305 xmlnode_get_attrib(candidate, "ip"), | |
306 atoi(xmlnode_get_attrib(candidate, "network")), | |
307 atoi(xmlnode_get_attrib(candidate, "port")), | |
308 atoi(xmlnode_get_attrib(candidate, "priority")), | |
309 xmlnode_get_attrib(candidate, "protocol"), | |
310 xmlnode_get_attrib(candidate, "type"), | |
311 username, password); | |
312 jingle_iceudp_add_remote_candidate(JINGLE_ICEUDP(transport), iceudp_candidate); | |
313 } | |
314 | |
315 return transport; | |
316 } | |
317 | |
318 static xmlnode * | |
319 jingle_iceudp_to_xml_internal(JingleTransport *transport, xmlnode *content, JingleActionType action) | |
320 { | |
321 xmlnode *node = parent_class->to_xml(transport, content, action); | |
322 | |
323 if (action == JINGLE_SESSION_INITIATE || action == JINGLE_TRANSPORT_INFO || | |
324 action == JINGLE_CONTENT_ADD || action == JINGLE_TRANSPORT_REPLACE) { | |
325 JingleIceUdpCandidate *candidate = JINGLE_ICEUDP_GET_PRIVATE( | |
326 transport)->local_candidates->data; | |
327 xmlnode_set_attrib(node, "pwd", candidate->password); | |
328 xmlnode_set_attrib(node, "ufrag", candidate->username); | |
329 } | |
330 | |
331 if (action == JINGLE_TRANSPORT_INFO || action == JINGLE_SESSION_ACCEPT) { | |
332 JingleIceUdpPrivate *priv = JINGLE_ICEUDP_GET_PRIVATE(transport); | |
333 GList *iter = priv->local_candidates; | |
334 | |
335 for (; iter; iter = g_list_next(iter)) { | |
336 JingleIceUdpCandidate *candidate = iter->data; | |
337 | |
338 xmlnode *xmltransport = xmlnode_new_child(node, "candidate"); | |
339 gchar *component = g_strdup_printf("%d", candidate->component); | |
340 gchar *generation = g_strdup_printf("%d", candidate->generation); | |
341 gchar *network = g_strdup_printf("%d", candidate->network); | |
342 gchar *port = g_strdup_printf("%d", candidate->port); | |
343 gchar *priority = g_strdup_printf("%d", candidate->priority); | |
344 | |
345 xmlnode_set_attrib(xmltransport, "component", component); | |
346 xmlnode_set_attrib(xmltransport, "foundation", candidate->foundation); | |
347 xmlnode_set_attrib(xmltransport, "generation", generation); | |
348 xmlnode_set_attrib(xmltransport, "ip", candidate->ip); | |
349 xmlnode_set_attrib(xmltransport, "network", network); | |
350 xmlnode_set_attrib(xmltransport, "port", port); | |
351 xmlnode_set_attrib(xmltransport, "priority", priority); | |
352 xmlnode_set_attrib(xmltransport, "protocol", candidate->protocol); | |
353 | |
354 if (action == JINGLE_SESSION_ACCEPT) { | |
355 /* XXX: fix this, it's dummy data */ | |
356 xmlnode_set_attrib(xmltransport, "rel-addr", "10.0.1.1"); | |
357 xmlnode_set_attrib(xmltransport, "rel-port", "8998"); | |
358 xmlnode_set_attrib(xmltransport, "rem-addr", "192.0.2.1"); | |
359 xmlnode_set_attrib(xmltransport, "rem-port", "3478"); | |
360 } | |
361 | |
362 xmlnode_set_attrib(xmltransport, "type", candidate->type); | |
363 | |
364 g_free(component); | |
365 g_free(generation); | |
366 g_free(network); | |
367 g_free(port); | |
368 g_free(priority); | |
369 } | |
370 } | |
371 | |
372 return node; | |
373 } | |
374 |