6 * Copyright (C) 2010 Jakub Adam <jakub.adam@tieto.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "sipe-backend.h"
30 #include "sipe-utils.h"
33 parse_attributes(struct sdpmsg
*smsg
, gchar
*msg
) {
34 gchar
**lines
= g_strsplit(msg
, "\r\n", 0);
35 GSList
*attributes
= NULL
;
38 for (ptr
= lines
; *ptr
!= NULL
; ++ptr
) {
39 if (g_str_has_prefix(*ptr
, "a=")) {
40 gchar
**parts
= g_strsplit(*ptr
+ 2, ":", 2);
44 sipe_utils_nameval_free(attributes
);
48 attributes
= sipe_utils_nameval_add(attributes
, parts
[0], parts
[1]);
51 } else if (g_str_has_prefix(*ptr
, "o=")) {
52 gchar
**parts
= g_strsplit(*ptr
+ 2, " ", 6);
53 smsg
->ip
= g_strdup(parts
[5]);
55 } else if (g_str_has_prefix(*ptr
, "m=")) {
56 gchar
**parts
= g_strsplit(*ptr
+ 2, " ", 3);
57 smsg
->port
= atoi(parts
[1]);
64 smsg
->attributes
= attributes
;
68 static void sdpcandidate_free(struct sdpcandidate
*candidate
);
71 parse_candidates(GSList
*attrs
)
73 GSList
*candidates
= NULL
;
77 while ((attr
= sipe_utils_nameval_find_instance(attrs
, "candidate", i
++))) {
78 struct sdpcandidate
*candidate
= g_new0(struct sdpcandidate
, 1);
79 gchar
**tokens
= g_strsplit_set(attr
, " ", 0);
81 candidate
->foundation
= g_strdup(tokens
[0]);
83 switch (atoi(tokens
[1])) {
85 candidate
->component
= SIPE_COMPONENT_RTP
;
88 candidate
->component
= SIPE_COMPONENT_RTCP
;
91 candidate
->component
= SIPE_COMPONENT_NONE
;
94 if (sipe_strequal(tokens
[2], "UDP"))
95 candidate
->protocol
= SIPE_NETWORK_PROTOCOL_UDP
;
97 // Ignore TCP candidates, at least for now...
98 // Also, if this is ICEv6 candidate list, candidates are dropped here
100 sdpcandidate_free(candidate
);
104 candidate
->priority
= atoi(tokens
[3]);
105 candidate
->ip
= g_strdup(tokens
[4]);
106 candidate
->port
= atoi(tokens
[5]);
108 if (sipe_strequal(tokens
[7], "host"))
109 candidate
->type
= SIPE_CANDIDATE_TYPE_HOST
;
110 else if (sipe_strequal(tokens
[7], "relay"))
111 candidate
->type
= SIPE_CANDIDATE_TYPE_RELAY
;
112 else if (sipe_strequal(tokens
[7], "srflx"))
113 candidate
->type
= SIPE_CANDIDATE_TYPE_SRFLX
;
114 else if (sipe_strequal(tokens
[7], "prflx"))
115 candidate
->type
= SIPE_CANDIDATE_TYPE_PRFLX
;
118 sdpcandidate_free(candidate
);
122 candidates
= g_slist_append(candidates
, candidate
);
131 create_legacy_candidates(gchar
*ip
, guint16 port
)
133 struct sdpcandidate
*candidate
;
134 GSList
*candidates
= NULL
;
136 candidate
= g_new0(struct sdpcandidate
, 1);
137 candidate
->foundation
= g_strdup("1");
138 candidate
->component
= SIPE_COMPONENT_RTP
;
139 candidate
->type
= SIPE_CANDIDATE_TYPE_HOST
;
140 candidate
->protocol
= SIPE_NETWORK_PROTOCOL_UDP
;
141 candidate
->ip
= g_strdup(ip
);
142 candidate
->port
= port
;
144 candidates
= g_slist_append(candidates
, candidate
);
146 candidate
= g_new0(struct sdpcandidate
, 1);
147 candidate
->foundation
= g_strdup("1");
148 candidate
->component
= SIPE_COMPONENT_RTCP
;
149 candidate
->type
= SIPE_CANDIDATE_TYPE_HOST
;
150 candidate
->protocol
= SIPE_NETWORK_PROTOCOL_UDP
;
151 candidate
->ip
= g_strdup(ip
);
152 candidate
->port
= port
+ 1;
154 candidates
= g_slist_append(candidates
, candidate
);
160 parse_codecs(GSList
*attrs
)
164 GSList
*codecs
= NULL
;
166 while ((attr
= sipe_utils_nameval_find_instance(attrs
, "rtpmap", i
++))) {
167 struct sdpcodec
*codec
= g_new0(struct sdpcodec
, 1);
168 gchar
**tokens
= g_strsplit_set(attr
, " /", 3);
173 codec
->id
= atoi(tokens
[0]);
174 codec
->name
= g_strdup(tokens
[1]);
175 codec
->clock_rate
= atoi(tokens
[2]);
176 codec
->type
= SIPE_MEDIA_AUDIO
;
178 // TODO: more secure and effective implementation
179 while((params
= sipe_utils_nameval_find_instance(attrs
, "fmtp", j
++))) {
180 gchar
**tokens
= g_strsplit_set(params
, " ", 0);
181 gchar
**next
= tokens
+ 1;
183 if (atoi(tokens
[0]) == codec
->id
) {
188 if (sscanf(*next
, "%[a-zA-Z0-9]=%s", name
, value
) == 2)
189 codec
->parameters
= sipe_utils_nameval_add(codec
->parameters
, name
, value
);
198 codecs
= g_slist_append(codecs
, codec
);
206 sdpmsg_parse_msg(gchar
*msg
)
208 struct sdpmsg
*smsg
= g_new0(struct sdpmsg
, 1);
209 smsg
->legacy
= FALSE
;
211 if (!parse_attributes(smsg
, msg
)) {
216 smsg
->candidates
= parse_candidates(smsg
->attributes
);
217 if (!smsg
->candidates
) {
218 // No a=candidate in SDP message, this seems to be pre-OC2007 R2 UAC
219 smsg
->candidates
= create_legacy_candidates(smsg
->ip
, smsg
->port
);
223 smsg
->codecs
= parse_codecs(smsg
->attributes
);
229 codecs_to_string(GSList
*codecs
)
231 GString
*result
= g_string_new(NULL
);
233 for (; codecs
; codecs
= codecs
->next
) {
234 struct sdpcodec
*c
= codecs
->data
;
235 GSList
*params
= c
->parameters
;
237 g_string_append_printf(result
,
238 "a=rtpmap:%d %s/%d\r\n",
244 g_string_append_printf(result
, "a=fmtp:%d", c
->id
);
246 for (; params
; params
= params
->next
) {
247 struct sipnameval
* par
= params
->data
;
248 g_string_append_printf(result
, " %s=%s",
249 par
->name
, par
->value
);
252 g_string_append(result
, "\r\n");
256 return g_string_free(result
, FALSE
);
260 codec_ids_to_string(GSList
*codecs
)
262 GString
*result
= g_string_new(NULL
);
264 for (; codecs
; codecs
= codecs
->next
) {
265 struct sdpcodec
*c
= codecs
->data
;
266 g_string_append_printf(result
, " %d", c
->id
);
269 return g_string_free(result
, FALSE
);
273 candidates_to_string(GSList
*candidates
)
275 GString
*result
= g_string_new("");
277 for (; candidates
; candidates
= candidates
->next
) {
278 struct sdpcandidate
*c
= candidates
->data
;
279 const gchar
*protocol
;
281 gchar
*related
= NULL
;
283 switch (c
->protocol
) {
284 case SIPE_NETWORK_PROTOCOL_TCP
:
287 case SIPE_NETWORK_PROTOCOL_UDP
:
293 case SIPE_CANDIDATE_TYPE_HOST
:
296 case SIPE_CANDIDATE_TYPE_RELAY
:
299 case SIPE_CANDIDATE_TYPE_SRFLX
:
301 related
= g_strdup_printf("raddr %s rport %d",
305 case SIPE_CANDIDATE_TYPE_PRFLX
:
309 // TODO: error unknown/unsupported type
313 g_string_append_printf(result
,
314 "a=candidate:%s %u %s %u %s %d typ %s %s\r\n",
322 related
? related
: "");
327 return g_string_free(result
, FALSE
);
331 candidate_compare_by_component_id(struct sdpcandidate
*c1
,
332 struct sdpcandidate
*c2
)
334 return c1
->component
- c2
->component
;
338 remote_candidates_to_string(GSList
*candidates
)
340 GString
*result
= g_string_new("");
342 candidates
= g_slist_copy(candidates
);
343 candidates
= g_slist_sort(candidates
,
344 (GCompareFunc
)candidate_compare_by_component_id
);
348 g_string_append(result
, "a=remote-candidates:");
350 for (i
= candidates
; i
; i
= i
->next
) {
351 struct sdpcandidate
*c
= i
->data
;
352 g_string_append_printf(result
, "%u %s %u ",
353 c
->component
, c
->ip
, c
->port
);
356 g_string_append(result
, "\r\n");
359 g_slist_free(candidates
);
361 return g_string_free(result
, FALSE
);
365 attributes_to_string(GSList
*attributes
)
367 GString
*result
= g_string_new("");
369 for (; attributes
; attributes
= attributes
->next
) {
370 struct sipnameval
*a
= attributes
->data
;
371 g_string_append_printf(result
, "a=%s", a
->name
);
373 g_string_append_printf(result
, ":%s", a
->value
);
374 g_string_append(result
, "\r\n");
377 return g_string_free(result
, FALSE
);
381 sdpmsg_to_string(const struct sdpmsg
*msg
)
385 gchar
*codecs_str
= codecs_to_string(msg
->codecs
);
386 gchar
*codec_ids_str
= codec_ids_to_string(msg
->codecs
);
388 gchar
*candidates_str
= msg
->legacy
? g_strdup("")
389 : candidates_to_string(msg
->candidates
);
390 gchar
*remote_candidates_str
= remote_candidates_to_string(msg
->remote_candidates
);
392 gchar
*attributes_str
= attributes_to_string(msg
->attributes
);
394 body
= g_strdup_printf(
396 "o=- 0 0 IN IP4 %s\r\n"
401 "m=audio %d RTP/AVP%s\r\n"
406 msg
->ip
, msg
->ip
, msg
->port
, codec_ids_str
,
407 candidates_str
, remote_candidates_str
,
412 g_free(codec_ids_str
);
413 g_free(candidates_str
);
414 g_free(remote_candidates_str
);
415 g_free(attributes_str
);
421 sdpcandidate_free(struct sdpcandidate
*candidate
)
424 g_free(candidate
->foundation
);
425 g_free(candidate
->ip
);
426 g_free(candidate
->base_ip
);
432 sdpcodec_free(struct sdpcodec
*codec
)
436 sipe_utils_nameval_free(codec
->parameters
);
442 sdpmsg_free(struct sdpmsg
*msg
)
447 sipe_utils_nameval_free(msg
->attributes
);
449 for (item
= msg
->candidates
; item
; item
= item
->next
)
450 sdpcandidate_free(item
->data
);
451 g_slist_free(msg
->candidates
);
453 for (item
= msg
->remote_candidates
; item
; item
= item
->next
)
454 sdpcandidate_free(item
->data
);
455 g_slist_free(msg
->remote_candidates
);
457 for (item
= msg
->codecs
; item
; item
= item
->next
)
458 sdpcodec_free(item
->data
);
459 g_slist_free(msg
->codecs
);