Use g_list_free_full instead of manual iterations
[pidgin-git.git] / libpurple / protocols / jabber / jingle / rawudp.c
blob68e12d7795becb2f61fa8d9dbe5c4e00353189e2
1 /**
2 * @file rawudp.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 "rawudp.h"
29 #include "jingle.h"
30 #include "debug.h"
32 #include <string.h>
34 struct _JingleRawUdp
36 JingleTransport parent;
39 typedef struct
41 GList *local_candidates;
42 GList *remote_candidates;
43 } JingleRawUdpPrivate;
45 enum {
46 PROP_0,
47 PROP_LOCAL_CANDIDATES,
48 PROP_REMOTE_CANDIDATES,
49 PROP_LAST
51 static GParamSpec *properties[PROP_LAST];
53 G_DEFINE_DYNAMIC_TYPE_EXTENDED(
54 JingleRawUdp,
55 jingle_rawudp,
56 JINGLE_TYPE_TRANSPORT,
58 G_ADD_PRIVATE_DYNAMIC(JingleRawUdp)
61 /******************************************************************************
62 * JingleRawUdp Transport Implementation
63 *****************************************************************************/
64 static GList *
65 jingle_rawudp_get_remote_candidates(JingleTransport *transport)
67 JingleRawUdp *rawudp = JINGLE_RAWUDP(transport);
68 JingleRawUdpPrivate *priv = jingle_rawudp_get_instance_private(rawudp);
69 GList *candidates = priv->remote_candidates;
70 GList *ret = NULL;
72 for (; candidates; candidates = g_list_next(candidates)) {
73 JingleRawUdpCandidate *candidate = candidates->data;
74 ret = g_list_append(ret, purple_media_candidate_new("",
75 candidate->component,
76 PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX,
77 PURPLE_MEDIA_NETWORK_PROTOCOL_UDP,
78 candidate->ip, candidate->port));
81 return ret;
84 static JingleRawUdpCandidate *
85 jingle_rawudp_get_remote_candidate_by_id(JingleRawUdp *rawudp, gchar *id)
87 JingleRawUdpPrivate *priv = jingle_rawudp_get_instance_private(rawudp);
89 GList *iter = priv->remote_candidates;
90 for (; iter; iter = g_list_next(iter)) {
91 JingleRawUdpCandidate *candidate = iter->data;
92 if (purple_strequal(candidate->id, id)) {
93 return candidate;
96 return NULL;
99 static void
100 jingle_rawudp_add_remote_candidate(JingleRawUdp *rawudp, JingleRawUdpCandidate *candidate)
102 JingleRawUdpPrivate *priv = jingle_rawudp_get_instance_private(rawudp);
103 JingleRawUdpCandidate *rawudp_candidate =
104 jingle_rawudp_get_remote_candidate_by_id(rawudp, candidate->id);
105 if (rawudp_candidate != NULL) {
106 priv->remote_candidates = g_list_remove(
107 priv->remote_candidates, rawudp_candidate);
108 g_boxed_free(JINGLE_TYPE_RAWUDP_CANDIDATE, rawudp_candidate);
110 priv->remote_candidates = g_list_append(priv->remote_candidates, candidate);
112 g_object_notify_by_pspec(G_OBJECT(rawudp), properties[PROP_REMOTE_CANDIDATES]);
115 static PurpleXmlNode *
116 jingle_rawudp_to_xml_internal(JingleTransport *transport, PurpleXmlNode *content, JingleActionType action)
118 PurpleXmlNode *node = JINGLE_TRANSPORT_CLASS(jingle_rawudp_parent_class)->to_xml(transport, content, action);
120 if (action == JINGLE_SESSION_INITIATE ||
121 action == JINGLE_TRANSPORT_INFO ||
122 action == JINGLE_SESSION_ACCEPT) {
123 JingleRawUdpPrivate *priv = jingle_rawudp_get_instance_private(JINGLE_RAWUDP(transport));
124 GList *iter = priv->local_candidates;
126 for (; iter; iter = g_list_next(iter)) {
127 JingleRawUdpCandidate *candidate = iter->data;
128 PurpleXmlNode *xmltransport;
129 gchar *generation, *component, *port;
131 if (candidate->rem_known == TRUE)
132 continue;
133 candidate->rem_known = TRUE;
135 xmltransport = purple_xmlnode_new_child(node, "candidate");
136 generation = g_strdup_printf("%d", candidate->generation);
137 component = g_strdup_printf("%d", candidate->component);
138 port = g_strdup_printf("%d", candidate->port);
140 purple_xmlnode_set_attrib(xmltransport, "generation", generation);
141 purple_xmlnode_set_attrib(xmltransport, "component", component);
142 purple_xmlnode_set_attrib(xmltransport, "id", candidate->id);
143 purple_xmlnode_set_attrib(xmltransport, "ip", candidate->ip);
144 purple_xmlnode_set_attrib(xmltransport, "port", port);
146 g_free(port);
147 g_free(generation);
151 return node;
154 static JingleTransport *
155 jingle_rawudp_parse_internal(PurpleXmlNode *rawudp)
157 JingleTransport *transport = JINGLE_TRANSPORT_CLASS(jingle_rawudp_parent_class)->parse(rawudp);
158 JingleRawUdpPrivate *priv = jingle_rawudp_get_instance_private(JINGLE_RAWUDP(transport));
159 PurpleXmlNode *candidate = purple_xmlnode_get_child(rawudp, "candidate");
160 JingleRawUdpCandidate *rawudp_candidate = NULL;
162 for (; candidate; candidate = purple_xmlnode_get_next_twin(candidate)) {
163 const gchar *id = purple_xmlnode_get_attrib(candidate, "id");
164 const gchar *generation = purple_xmlnode_get_attrib(candidate, "generation");
165 const gchar *component = purple_xmlnode_get_attrib(candidate, "component");
166 const gchar *ip = purple_xmlnode_get_attrib(candidate, "ip");
167 const gchar *port = purple_xmlnode_get_attrib(candidate, "port");
169 if (!id || !generation || !component || !ip || !port)
170 continue;
172 rawudp_candidate = jingle_rawudp_candidate_new(
174 atoi(generation),
175 atoi(component),
177 atoi(port));
178 rawudp_candidate->rem_known = TRUE;
179 jingle_rawudp_add_remote_candidate(JINGLE_RAWUDP(transport), rawudp_candidate);
182 if (rawudp_candidate != NULL &&
183 g_list_length(priv->remote_candidates) == 1) {
184 /* manufacture rtcp candidate */
185 rawudp_candidate = g_boxed_copy(JINGLE_TYPE_RAWUDP_CANDIDATE, rawudp_candidate);
186 rawudp_candidate->component = 2;
187 rawudp_candidate->port = rawudp_candidate->port + 1;
188 rawudp_candidate->rem_known = TRUE;
189 jingle_rawudp_add_remote_candidate(JINGLE_RAWUDP(transport), rawudp_candidate);
192 return transport;
195 static void
196 jingle_rawudp_add_local_candidate(JingleTransport *transport, const gchar *id, guint generation, PurpleMediaCandidate *candidate)
198 JingleRawUdp *rawudp = JINGLE_RAWUDP(transport);
199 JingleRawUdpPrivate *priv = jingle_rawudp_get_instance_private(rawudp);
200 gchar *ip;
201 JingleRawUdpCandidate *rawudp_candidate;
202 GList *iter;
204 ip = purple_media_candidate_get_ip(candidate);
205 rawudp_candidate = jingle_rawudp_candidate_new(id, generation,
206 purple_media_candidate_get_component_id(candidate),
207 ip, purple_media_candidate_get_port(candidate));
208 g_free(ip);
210 for (iter = priv->local_candidates; iter; iter = g_list_next(iter)) {
211 JingleRawUdpCandidate *c = iter->data;
212 if (purple_strequal(c->id, id)) {
213 generation = c->generation + 1;
215 g_boxed_free(JINGLE_TYPE_RAWUDP_CANDIDATE, c);
216 priv->local_candidates = g_list_delete_link(
217 priv->local_candidates, iter);
219 rawudp_candidate->generation = generation;
221 priv->local_candidates = g_list_append(
222 priv->local_candidates, rawudp_candidate);
224 g_object_notify_by_pspec(G_OBJECT(rawudp), properties[PROP_LOCAL_CANDIDATES]);
226 return;
230 priv->local_candidates = g_list_append(
231 priv->local_candidates, rawudp_candidate);
233 g_object_notify_by_pspec(G_OBJECT(rawudp), properties[PROP_LOCAL_CANDIDATES]);
236 /******************************************************************************
237 * JingleRawUdp GObject Stuff
238 *****************************************************************************/
239 static void
240 jingle_rawudp_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
242 JingleRawUdp *rawudp = JINGLE_RAWUDP(object);
243 JingleRawUdpPrivate *priv = jingle_rawudp_get_instance_private(rawudp);
245 switch (prop_id) {
246 case PROP_LOCAL_CANDIDATES:
247 priv->local_candidates = g_value_get_pointer(value);
248 break;
249 case PROP_REMOTE_CANDIDATES:
250 priv->remote_candidates = g_value_get_pointer(value);
251 break;
252 default:
253 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
254 break;
258 static void
259 jingle_rawudp_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
261 JingleRawUdp *rawudp = JINGLE_RAWUDP(object);
262 JingleRawUdpPrivate *priv = jingle_rawudp_get_instance_private(rawudp);
264 switch (prop_id) {
265 case PROP_LOCAL_CANDIDATES:
266 g_value_set_pointer(value, priv->local_candidates);
267 break;
268 case PROP_REMOTE_CANDIDATES:
269 g_value_set_pointer(value, priv->remote_candidates);
270 break;
271 default:
272 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
273 break;
277 static void
278 jingle_rawudp_init (JingleRawUdp *rawudp)
282 static void
283 jingle_rawudp_finalize (GObject *rawudp)
285 /* JingleRawUdpPrivate *priv = JINGLE_RAWUDP_GET_PRIVATE(rawudp); */
286 purple_debug_info("jingle","jingle_rawudp_finalize\n");
288 G_OBJECT_CLASS(jingle_rawudp_parent_class)->finalize(rawudp);
291 static void
292 jingle_rawudp_class_finalize(JingleRawUdpClass *klass) {
295 static void
296 jingle_rawudp_class_init (JingleRawUdpClass *klass)
298 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
299 JingleTransportClass *transport_class = JINGLE_TRANSPORT_CLASS(klass);
301 obj_class->finalize = jingle_rawudp_finalize;
302 obj_class->set_property = jingle_rawudp_set_property;
303 obj_class->get_property = jingle_rawudp_get_property;
305 transport_class->to_xml = jingle_rawudp_to_xml_internal;
306 transport_class->parse = jingle_rawudp_parse_internal;
307 transport_class->transport_type = JINGLE_TRANSPORT_RAWUDP;
308 transport_class->add_local_candidate = jingle_rawudp_add_local_candidate;
309 transport_class->get_remote_candidates = jingle_rawudp_get_remote_candidates;
311 properties[PROP_LOCAL_CANDIDATES] = g_param_spec_pointer("local-candidates",
312 "Local candidates",
313 "The local candidates for this transport.",
314 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
316 properties[PROP_REMOTE_CANDIDATES] = g_param_spec_pointer("remote-candidates",
317 "Remote candidates",
318 "The remote candidates for this transport.",
319 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
321 g_object_class_install_properties(obj_class, PROP_LAST, properties);
324 /******************************************************************************
325 * JingleRawUdpCandidate Boxed Type
326 *****************************************************************************/
327 static JingleRawUdpCandidate *
328 jingle_rawudp_candidate_copy(JingleRawUdpCandidate *candidate)
330 JingleRawUdpCandidate *new_candidate = g_new0(JingleRawUdpCandidate, 1);
331 new_candidate->generation = candidate->generation;
332 new_candidate->component = candidate->component;
333 new_candidate->id = g_strdup(candidate->id);
334 new_candidate->ip = g_strdup(candidate->ip);
335 new_candidate->port = candidate->port;
337 new_candidate->rem_known = candidate->rem_known;
338 return new_candidate;
341 static void
342 jingle_rawudp_candidate_free(JingleRawUdpCandidate *candidate)
344 g_free(candidate->id);
345 g_free(candidate->ip);
348 G_DEFINE_BOXED_TYPE(JingleRawUdpCandidate, jingle_rawudp_candidate,
349 jingle_rawudp_candidate_copy, jingle_rawudp_candidate_free)
351 /******************************************************************************
352 * Public API
353 *****************************************************************************/
354 void
355 jingle_rawudp_register(PurplePlugin *plugin) {
356 jingle_rawudp_register_type(G_TYPE_MODULE(plugin));
359 JingleRawUdpCandidate *
360 jingle_rawudp_candidate_new(const gchar *id, guint generation, guint component, const gchar *ip, guint port)
362 JingleRawUdpCandidate *candidate = g_new0(JingleRawUdpCandidate, 1);
363 candidate->generation = generation;
364 candidate->component = component;
365 candidate->id = g_strdup(id);
366 candidate->ip = g_strdup(ip);
367 candidate->port = port;
369 candidate->rem_known = FALSE;
370 return candidate;