Coverage Report

Created: 2025-12-31 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pidgin/libpurple/protocols/jabber/jingle/rawudp.c
Line
Count
Source
1
/**
2
 * @file rawudp.c
3
 *
4
 * purple
5
 *
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.
9
 *
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.
14
 *
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.
19
 *
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
23
 */
24
25
#include "internal.h"
26
27
#include "rawudp.h"
28
#include "jingle.h"
29
#include "debug.h"
30
31
#include <string.h>
32
33
struct _JingleRawUdpPrivate
34
{
35
  GList *local_candidates;
36
  GList *remote_candidates;
37
};
38
39
0
#define JINGLE_RAWUDP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), JINGLE_TYPE_RAWUDP, JingleRawUdpPrivate))
40
41
static void jingle_rawudp_class_init (JingleRawUdpClass *klass);
42
static void jingle_rawudp_init (JingleRawUdp *rawudp);
43
static void jingle_rawudp_finalize (GObject *object);
44
static void jingle_rawudp_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
45
static void jingle_rawudp_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
46
static JingleTransport *jingle_rawudp_parse_internal(xmlnode *rawudp);
47
static xmlnode *jingle_rawudp_to_xml_internal(JingleTransport *transport, xmlnode *content, JingleActionType action);
48
49
static JingleTransportClass *parent_class = NULL;
50
51
enum {
52
  PROP_0,
53
  PROP_LOCAL_CANDIDATES,
54
  PROP_REMOTE_CANDIDATES,
55
};
56
57
static JingleRawUdpCandidate *
58
jingle_rawudp_candidate_copy(JingleRawUdpCandidate *candidate)
59
0
{
60
0
  JingleRawUdpCandidate *new_candidate = g_new0(JingleRawUdpCandidate, 1);
61
0
  new_candidate->generation = candidate->generation;
62
0
  new_candidate->component = candidate->component;
63
0
  new_candidate->id = g_strdup(candidate->id);
64
0
  new_candidate->ip = g_strdup(candidate->ip);
65
0
  new_candidate->port = candidate->port;
66
67
0
  new_candidate->rem_known = candidate->rem_known;
68
0
  return new_candidate;
69
0
}
70
71
static void
72
jingle_rawudp_candidate_free(JingleRawUdpCandidate *candidate)
73
0
{
74
0
  g_free(candidate->id);
75
0
  g_free(candidate->ip);
76
0
}
77
78
GType
79
jingle_rawudp_candidate_get_type()
80
0
{
81
0
  static GType type = 0;
82
83
0
  if (type == 0) {
84
0
    type = g_boxed_type_register_static("JingleRawUdpCandidate",
85
0
        (GBoxedCopyFunc)jingle_rawudp_candidate_copy,
86
0
        (GBoxedFreeFunc)jingle_rawudp_candidate_free);
87
0
  }
88
0
  return type;
89
0
}
90
91
JingleRawUdpCandidate *
92
jingle_rawudp_candidate_new(const gchar *id, guint generation, guint component, const gchar *ip, guint port)
93
0
{
94
0
  JingleRawUdpCandidate *candidate = g_new0(JingleRawUdpCandidate, 1);
95
0
  candidate->generation = generation;
96
0
  candidate->component = component;
97
0
  candidate->id = g_strdup(id);
98
0
  candidate->ip = g_strdup(ip);
99
0
  candidate->port = port;
100
101
0
  candidate->rem_known = FALSE;
102
0
  return candidate;
103
0
}
104
105
GType
106
jingle_rawudp_get_type()
107
0
{
108
0
  static GType type = 0;
109
110
0
  if (type == 0) {
111
0
    static const GTypeInfo info = {
112
0
      sizeof(JingleRawUdpClass),
113
0
      NULL,
114
0
      NULL,
115
0
      (GClassInitFunc) jingle_rawudp_class_init,
116
0
      NULL,
117
0
      NULL,
118
0
      sizeof(JingleRawUdp),
119
0
      0,
120
0
      (GInstanceInitFunc) jingle_rawudp_init,
121
0
      NULL
122
0
    };
123
0
    type = g_type_register_static(JINGLE_TYPE_TRANSPORT, "JingleRawUdp", &info, 0);
124
0
  }
125
0
  return type;
126
0
}
127
128
static void
129
jingle_rawudp_class_init (JingleRawUdpClass *klass)
130
0
{
131
0
  GObjectClass *gobject_class = (GObjectClass*)klass;
132
0
  parent_class = g_type_class_peek_parent(klass);
133
134
0
  gobject_class->finalize = jingle_rawudp_finalize;
135
0
  gobject_class->set_property = jingle_rawudp_set_property;
136
0
  gobject_class->get_property = jingle_rawudp_get_property;
137
0
  klass->parent_class.to_xml = jingle_rawudp_to_xml_internal;
138
0
  klass->parent_class.parse = jingle_rawudp_parse_internal;
139
0
  klass->parent_class.transport_type = JINGLE_TRANSPORT_RAWUDP;
140
141
0
  g_object_class_install_property(gobject_class, PROP_LOCAL_CANDIDATES,
142
0
      g_param_spec_pointer("local-candidates",
143
0
      "Local candidates",
144
0
      "The local candidates for this transport.",
145
0
      G_PARAM_READABLE));
146
147
0
  g_object_class_install_property(gobject_class, PROP_REMOTE_CANDIDATES,
148
0
      g_param_spec_pointer("remote-candidates",
149
0
      "Remote candidates",
150
0
      "The remote candidates for this transport.",
151
0
      G_PARAM_READABLE));
152
153
0
  g_type_class_add_private(klass, sizeof(JingleRawUdpPrivate));
154
0
}
155
156
static void
157
jingle_rawudp_init (JingleRawUdp *rawudp)
158
0
{
159
0
  rawudp->priv = JINGLE_RAWUDP_GET_PRIVATE(rawudp);
160
0
  rawudp->priv->local_candidates = NULL;
161
0
  rawudp->priv->remote_candidates = NULL;
162
0
}
163
164
static void
165
jingle_rawudp_finalize (GObject *rawudp)
166
0
{
167
/*  JingleRawUdpPrivate *priv = JINGLE_RAWUDP_GET_PRIVATE(rawudp); */
168
0
  purple_debug_info("jingle","jingle_rawudp_finalize\n");
169
170
0
  G_OBJECT_CLASS(parent_class)->finalize(rawudp);
171
0
}
172
173
static void
174
jingle_rawudp_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
175
0
{
176
0
  JingleRawUdp *rawudp;
177
178
0
  g_return_if_fail(object != NULL);
179
0
  g_return_if_fail(JINGLE_IS_RAWUDP(object));
180
181
0
  rawudp = JINGLE_RAWUDP(object);
182
183
0
  switch (prop_id) {
184
0
    case PROP_LOCAL_CANDIDATES:
185
0
      rawudp->priv->local_candidates =
186
0
          g_value_get_pointer(value);
187
0
      break;
188
0
    case PROP_REMOTE_CANDIDATES:
189
0
      rawudp->priv->remote_candidates =
190
0
          g_value_get_pointer(value);
191
0
      break;
192
0
    default:
193
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
194
0
      break;
195
0
  }
196
0
}
197
198
static void
199
jingle_rawudp_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
200
0
{
201
0
  JingleRawUdp *rawudp;
202
203
0
  g_return_if_fail(object != NULL);
204
0
  g_return_if_fail(JINGLE_IS_RAWUDP(object));
205
206
0
  rawudp = JINGLE_RAWUDP(object);
207
208
0
  switch (prop_id) {
209
0
    case PROP_LOCAL_CANDIDATES:
210
0
      g_value_set_pointer(value, rawudp->priv->local_candidates);
211
0
      break;
212
0
    case PROP_REMOTE_CANDIDATES:
213
0
      g_value_set_pointer(value, rawudp->priv->remote_candidates);
214
0
      break;
215
0
    default:
216
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
217
0
      break;
218
0
  }
219
0
}
220
221
void
222
jingle_rawudp_add_local_candidate(JingleRawUdp *rawudp, JingleRawUdpCandidate *candidate)
223
0
{
224
0
  GList *iter = rawudp->priv->local_candidates;
225
226
0
  for (; iter; iter = g_list_next(iter)) {
227
0
    JingleRawUdpCandidate *c = iter->data;
228
0
    if (purple_strequal(c->id, candidate->id)) {
229
0
      guint generation = c->generation + 1;
230
231
0
      g_boxed_free(JINGLE_TYPE_RAWUDP_CANDIDATE, c);
232
0
      rawudp->priv->local_candidates = g_list_delete_link(
233
0
          rawudp->priv->local_candidates, iter);
234
235
0
      candidate->generation = generation;
236
237
0
      rawudp->priv->local_candidates = g_list_append(
238
0
          rawudp->priv->local_candidates, candidate);
239
0
      return;
240
0
    }
241
0
  }
242
243
0
  rawudp->priv->local_candidates = g_list_append(
244
0
      rawudp->priv->local_candidates, candidate);
245
0
}
246
247
GList *
248
jingle_rawudp_get_remote_candidates(JingleRawUdp *rawudp)
249
0
{
250
0
  return g_list_copy(rawudp->priv->remote_candidates);
251
0
}
252
253
static JingleRawUdpCandidate *
254
jingle_rawudp_get_remote_candidate_by_id(JingleRawUdp *rawudp, gchar *id)
255
0
{
256
0
  GList *iter = rawudp->priv->remote_candidates;
257
0
  for (; iter; iter = g_list_next(iter)) {
258
0
    JingleRawUdpCandidate *candidate = iter->data;
259
0
    if (purple_strequal(candidate->id, id)) {
260
0
      return candidate;
261
0
    }
262
0
  }
263
0
  return NULL;
264
0
}
265
266
static void
267
jingle_rawudp_add_remote_candidate(JingleRawUdp *rawudp, JingleRawUdpCandidate *candidate)
268
0
{
269
0
  JingleRawUdpPrivate *priv = JINGLE_RAWUDP_GET_PRIVATE(rawudp);
270
0
  JingleRawUdpCandidate *rawudp_candidate =
271
0
      jingle_rawudp_get_remote_candidate_by_id(rawudp, candidate->id);
272
0
  if (rawudp_candidate != NULL) {
273
0
    priv->remote_candidates = g_list_remove(
274
0
        priv->remote_candidates, rawudp_candidate);
275
0
    g_boxed_free(JINGLE_TYPE_RAWUDP_CANDIDATE, rawudp_candidate);
276
0
  }
277
0
  priv->remote_candidates = g_list_append(priv->remote_candidates, candidate);
278
0
}
279
280
static JingleTransport *
281
jingle_rawudp_parse_internal(xmlnode *rawudp)
282
0
{
283
0
  JingleTransport *transport = parent_class->parse(rawudp);
284
0
  JingleRawUdpPrivate *priv = JINGLE_RAWUDP_GET_PRIVATE(transport);
285
0
  xmlnode *candidate = xmlnode_get_child(rawudp, "candidate");
286
0
  JingleRawUdpCandidate *rawudp_candidate = NULL;
287
288
0
  for (; candidate; candidate = xmlnode_get_next_twin(candidate)) {
289
0
    const gchar *id = xmlnode_get_attrib(candidate, "id");
290
0
    const gchar *generation = xmlnode_get_attrib(candidate, "generation");
291
0
    const gchar *component = xmlnode_get_attrib(candidate, "component");
292
0
    const gchar *ip = xmlnode_get_attrib(candidate, "ip");
293
0
    const gchar *port = xmlnode_get_attrib(candidate, "port");
294
295
0
    if (!id || !generation || !component || !ip || !port)
296
0
      continue;
297
298
0
    rawudp_candidate = jingle_rawudp_candidate_new(
299
0
        id,
300
0
        atoi(generation),
301
0
        atoi(component),
302
0
        ip,
303
0
        atoi(port));
304
0
    rawudp_candidate->rem_known = TRUE;
305
0
    jingle_rawudp_add_remote_candidate(JINGLE_RAWUDP(transport), rawudp_candidate);
306
0
  }
307
308
0
  if (rawudp_candidate != NULL &&
309
0
      g_list_length(priv->remote_candidates) == 1) {
310
    /* manufacture rtcp candidate */
311
0
    rawudp_candidate = g_boxed_copy(JINGLE_TYPE_RAWUDP_CANDIDATE, rawudp_candidate);
312
0
    rawudp_candidate->component = 2;
313
0
    rawudp_candidate->port = rawudp_candidate->port + 1;
314
0
    rawudp_candidate->rem_known = TRUE;
315
0
    jingle_rawudp_add_remote_candidate(JINGLE_RAWUDP(transport), rawudp_candidate);
316
0
  }
317
318
0
  return transport;
319
0
}
320
321
static xmlnode *
322
jingle_rawudp_to_xml_internal(JingleTransport *transport, xmlnode *content, JingleActionType action)
323
0
{
324
0
  xmlnode *node = parent_class->to_xml(transport, content, action);
325
326
0
  if (action == JINGLE_SESSION_INITIATE ||
327
0
      action == JINGLE_TRANSPORT_INFO ||
328
0
      action == JINGLE_SESSION_ACCEPT) {
329
0
    JingleRawUdpPrivate *priv = JINGLE_RAWUDP_GET_PRIVATE(transport);
330
0
    GList *iter = priv->local_candidates;
331
332
0
    for (; iter; iter = g_list_next(iter)) {
333
0
      JingleRawUdpCandidate *candidate = iter->data;
334
0
      xmlnode *xmltransport;
335
0
      gchar *generation, *component, *port;
336
337
0
      if (candidate->rem_known == TRUE)
338
0
        continue;
339
0
      candidate->rem_known = TRUE;
340
341
0
      xmltransport = xmlnode_new_child(node, "candidate");
342
0
      generation = g_strdup_printf("%d", candidate->generation);
343
0
      component = g_strdup_printf("%d", candidate->component);
344
0
      port = g_strdup_printf("%d", candidate->port);
345
346
0
      xmlnode_set_attrib(xmltransport, "generation", generation);
347
0
      xmlnode_set_attrib(xmltransport, "component", component);
348
0
      xmlnode_set_attrib(xmltransport, "id", candidate->id);
349
0
      xmlnode_set_attrib(xmltransport, "ip", candidate->ip);
350
0
      xmlnode_set_attrib(xmltransport, "port", port);
351
352
0
      g_free(port);
353
0
      g_free(generation);
354
0
    }
355
0
  }
356
357
0
  return node;
358
0
}
359