Bug Summary

File:soa_static.c
Warning:line 329, column 15
Value stored to 'mT' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name soa_static.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-11/lib/clang/11.0.1 -D HAVE_CONFIG_H -I . -I ../.. -I ../../libsofia-sip-ua/su/sofia-sip -I ./../sdp -I ../sdp -I ./../sip -I ../sip -I ./../msg -I ../msg -I ./../url -I ../url -I ./../ipt -I ../ipt -I ./../bnf -I ../bnf -I ./../su -I ../su -I ../../s2check -D SU_DEBUG=0 -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-11/lib/clang/11.0.1/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /drone/src/libsofia-sip-ua/soa -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -faddrsig -o /drone/src/scan-build/2024-04-30-111602-13-1 -x c soa_static.c
1/*
2 * This file is part of the Sofia-SIP package
3 *
4 * Copyright (C) 2006 Nokia Corporation.
5 *
6 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25/**@CFILE soa_static.c
26 *
27 * @brief Static implementation of Sofia SDP Offer/Answer Engine
28 *
29 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
30 *
31 * @date Created: Tue Aug 16 17:06:06 EEST 2005
32 *
33 * @par Use-cases
34 * 1. no existing session
35 * a) generating offer (upgrade with user-SDP)
36 * b) generating answer (upgrade with remote-SDP, rejects with user-SDP)
37 * 2. session exists
38 * a) generating offer:
39 * upgrades with user-SDP
40 * b) generating answer:
41 * upgrades with remote-SDP, rejects with user-SDP
42 * c) processing answer:
43 * rejects with user-SDP, no upgrades
44 *
45 * Upgrading session with user SDP:
46 */
47
48#include "config.h"
49
50#include <stddef.h>
51#include <stdlib.h>
52#include <string.h>
53
54#include <assert.h>
55
56struct soa_static_complete;
57
58#define SU_MSG_ARG_Tstruct soa_static_completed struct soa_static_completed
59
60#include <sofia-sip/su_wait.h>
61#include <sofia-sip/su_tag_class.h>
62#include <sofia-sip/su_tag_class.h>
63#include <sofia-sip/su_tagarg.h>
64#include <sofia-sip/su_strlst.h>
65#include <sofia-sip/su_string.h>
66#include <sofia-sip/bnf.h>
67
68#include "sofia-sip/soa.h"
69#include <sofia-sip/sdp.h>
70#include "sofia-sip/soa_session.h"
71
72#define NONE((void *)-1) ((void *)-1)
73#define XXX((void) sizeof ((!"implemented") ? 1 : 0), __extension__ ({ if
(!"implemented") ; else __assert_fail ("!\"implemented\"", "soa_static.c"
, 73, __extension__ __PRETTY_FUNCTION__); }))
assert(!"implemented")((void) sizeof ((!"implemented") ? 1 : 0), __extension__ ({ if
(!"implemented") ; else __assert_fail ("!\"implemented\"", "soa_static.c"
, 73, __extension__ __PRETTY_FUNCTION__); }))
74
75typedef struct soa_static_session
76{
77 soa_session_t sss_session[1];
78 char *sss_audio_aux;
79 int sss_ordered_user; /**< User SDP is ordered */
80 int sss_reuse_rejected; /**< Try to reuse rejected media line slots */
81
82 /** Mapping from user SDP m= lines to session SDP m= lines */
83 int *sss_u2s;
84 /** Mapping from session SDP m= lines to user SDP m= lines */
85 int *sss_s2u;
86
87 /** State kept from SDP before current offer */
88 struct {
89 int *u2s, *s2u;
90 } sss_previous;
91
92 /** Our latest offer or answer */
93 sdp_session_t *sss_latest;
94}
95soa_static_session_t;
96
97#define U2S_NOT_USED(-1) (-1)
98#define U2S_SENTINEL(-2) (-2)
99
100static int soa_static_init(char const *, soa_session_t *, soa_session_t *);
101static void soa_static_deinit(soa_session_t *);
102static int soa_static_set_params(soa_session_t *ss, tagi_t const *tags);
103static int soa_static_get_params(soa_session_t const *ss, tagi_t *tags);
104static tagi_t *soa_static_get_paramlist(soa_session_t const *ss,
105 tag_type_t tag, tag_value_t value,
106 ...);
107static int soa_static_set_capability_sdp(soa_session_t *ss,
108 sdp_session_t *sdp,
109 char const *, isize_t);
110static int soa_static_set_remote_sdp(soa_session_t *ss,
111 int new_version,
112 sdp_session_t *sdp,
113 char const *, isize_t);
114static int soa_static_set_user_sdp(soa_session_t *ss,
115 sdp_session_t *sdp,
116 char const *, isize_t);
117static int soa_static_generate_offer(soa_session_t *ss, soa_callback_f *);
118static int soa_static_generate_answer(soa_session_t *ss, soa_callback_f *);
119static int soa_static_process_answer(soa_session_t *ss, soa_callback_f *);
120static int soa_static_process_reject(soa_session_t *ss, soa_callback_f *);
121
122static int soa_static_activate(soa_session_t *ss, char const *option);
123static int soa_static_deactivate(soa_session_t *ss, char const *option);
124static void soa_static_terminate(soa_session_t *ss, char const *option);
125
126struct soa_session_actions const soa_default_actions =
127 {
128 (sizeof soa_default_actions),
129 sizeof (struct soa_static_session),
130 "static",
131 soa_static_init,
132 soa_static_deinit,
133 soa_static_set_params,
134 soa_static_get_params,
135 soa_static_get_paramlist,
136 soa_base_media_features,
137 soa_base_sip_require,
138 soa_base_sip_supported,
139 soa_base_remote_sip_features,
140 soa_static_set_capability_sdp,
141 soa_static_set_remote_sdp,
142 soa_static_set_user_sdp,
143 soa_static_generate_offer,
144 soa_static_generate_answer,
145 soa_static_process_answer,
146 soa_static_process_reject,
147 soa_static_activate,
148 soa_static_deactivate,
149 soa_static_terminate
150 };
151
152/* Initialize session */
153static int soa_static_init(char const *name,
154 soa_session_t *ss,
155 soa_session_t *parent)
156{
157 return soa_base_init(name, ss, parent);
158}
159
160static void soa_static_deinit(soa_session_t *ss)
161{
162 soa_base_deinit(ss);
163}
164
165static int soa_static_set_params(soa_session_t *ss, tagi_t const *tags)
166{
167 soa_static_session_t *sss = (soa_static_session_t *)ss;
168 char const *audio_aux = sss->sss_audio_aux;
169 int ordered_user = sss->sss_ordered_user;
170 int reuse_rejected = sss->sss_reuse_rejected;
171 int n, m;
172
173 n = tl_gets(tags,
174 SOATAG_AUDIO_AUX_REF(audio_aux)soatag_audio_aux_ref, tag_str_vr(&(audio_aux)),
175 SOATAG_ORDERED_USER_REF(ordered_user)soatag_ordered_user_ref, tag_bool_vr(&(ordered_user)),
176 SOATAG_REUSE_REJECTED_REF(reuse_rejected)soatag_reuse_rejected_ref, tag_bool_vr(&(reuse_rejected)),
177 TAG_END()(tag_type_t)0, (tag_value_t)0);
178
179 if (n > 0 && !su_casematch(audio_aux, sss->sss_audio_aux)) {
180 char *s = su_strdup(ss->ss_home, audio_aux), *tbf = sss->sss_audio_aux;
181 if (s == NULL((void*)0) && audio_aux != NULL((void*)0))
182 return -1;
183 sss->sss_audio_aux = s;
184 if (tbf)
185 su_free(ss->ss_home, tbf);
186 }
187
188 sss->sss_ordered_user = ordered_user != 0;
189 sss->sss_reuse_rejected = reuse_rejected != 0;
190
191 m = soa_base_set_params(ss, tags);
192 if (m < 0)
193 return m;
194
195 return n + m;
196}
197
198static int soa_static_get_params(soa_session_t const *ss, tagi_t *tags)
199{
200 soa_static_session_t *sss = (soa_static_session_t *)ss;
201
202 int n, m;
203
204 n = tl_tgets(tags,
205 SOATAG_AUDIO_AUX(sss->sss_audio_aux)soatag_audio_aux, tag_str_v(sss->sss_audio_aux),
206 SOATAG_ORDERED_USER(sss->sss_ordered_user)soatag_ordered_user, tag_bool_v(sss->sss_ordered_user),
207 SOATAG_REUSE_REJECTED(sss->sss_reuse_rejected)soatag_reuse_rejected, tag_bool_v(sss->sss_reuse_rejected),
208 TAG_END()(tag_type_t)0, (tag_value_t)0);
209 m = soa_base_get_params(ss, tags);
210 if (m < 0)
211 return m;
212
213 return n + m;
214}
215
216static tagi_t *soa_static_get_paramlist(soa_session_t const *ss,
217 tag_type_t tag, tag_value_t value,
218 ...)
219{
220 soa_static_session_t *sss = (soa_static_session_t *)ss;
221
222 ta_list ta;
223 tagi_t *tl;
224
225 ta_start(ta, tag, value)do { tag_type_t ta_start__tag = (tag); tag_value_t ta_start__value
= (value); __builtin_va_start((ta).ap, (value)); while ((ta_start__tag
) == tag_next && (ta_start__value) != 0) { ta_start__tag
= ((tagi_t *)ta_start__value)->t_tag; if (ta_start__tag ==
tag_null || ta_start__tag == ((void*)0)) break; if (ta_start__tag
== tag_next) { ta_start__value = ((tagi_t *)ta_start__value)
->t_value; } else { ta_start__tag = tag_next; break; } } (
ta).tl->t_tag = ta_start__tag; (ta).tl->t_value = ta_start__value
; if (ta_start__tag != ((void*)0) && ta_start__tag !=
tag_null && ta_start__tag != tag_next) { va_list ta_start__ap
; __builtin_va_copy((ta_start__ap), ((ta).ap)); (ta).tl[1].t_tag
= tag_next; (ta).tl[1].t_value = (tag_value_t)tl_vlist(ta_start__ap
); __builtin_va_end(ta_start__ap); } else { (ta).tl[1].t_value
= 0; (ta).tl[1].t_value = (tag_value_t)0; } } while(0)
;
226
227 tl = soa_base_get_paramlist(ss,
228 TAG_IF(sss->sss_audio_aux,!(sss->sss_audio_aux) ? tag_skip : soatag_audio_aux, tag_str_v
(sss->sss_audio_aux)
229 SOATAG_AUDIO_AUX(sss->sss_audio_aux))!(sss->sss_audio_aux) ? tag_skip : soatag_audio_aux, tag_str_v
(sss->sss_audio_aux)
,
230 TAG_IF(sss->sss_ordered_user,!(sss->sss_ordered_user) ? tag_skip : soatag_ordered_user,
tag_bool_v(1)
231 SOATAG_ORDERED_USER(1))!(sss->sss_ordered_user) ? tag_skip : soatag_ordered_user,
tag_bool_v(1)
,
232 TAG_IF(sss->sss_reuse_rejected,!(sss->sss_reuse_rejected) ? tag_skip : soatag_reuse_rejected
, tag_bool_v(1)
233 SOATAG_REUSE_REJECTED(1))!(sss->sss_reuse_rejected) ? tag_skip : soatag_reuse_rejected
, tag_bool_v(1)
,
234 TAG_NEXT(ta_args(ta))tag_next, (tag_value_t)((ta).tl));
235
236 ta_end(ta)((((ta).tl[1].t_value) ? (tl_vfree((tagi_t *)((ta).tl[1].t_value
))) : (void)0), (ta).tl[1].t_value = 0, __builtin_va_end((ta)
.ap))
;
237
238 return tl;
239}
240
241static int soa_static_set_capability_sdp(soa_session_t *ss,
242 sdp_session_t *sdp,
243 char const *sdp_str,
244 isize_t sdp_len)
245{
246 return soa_base_set_capability_sdp(ss, sdp, sdp_str, sdp_len);
247}
248
249
250static int soa_static_set_remote_sdp(soa_session_t *ss,
251 int new_version,
252 sdp_session_t *sdp,
253 char const *sdp_str,
254 isize_t sdp_len)
255{
256 return soa_base_set_remote_sdp(ss, new_version, sdp, sdp_str, sdp_len);
257}
258
259
260static int soa_static_set_user_sdp(soa_session_t *ss,
261 sdp_session_t *sdp,
262 char const *sdp_str,
263 isize_t sdp_len)
264{
265 return soa_base_set_user_sdp(ss, sdp, sdp_str, sdp_len);
266}
267
268/** Generate a rejected m= line */
269static
270sdp_media_t *soa_sdp_make_rejected_media(su_home_t *home,
271 sdp_media_t const *m,
272 sdp_session_t *sdp,
273 int include_all_codecs)
274{
275 sdp_media_t rejected[1] = {{ sizeof (rejected) }};
276
277 rejected->m_type = m->m_type;
278 rejected->m_type_name = m->m_type_name;
279 rejected->m_port = 0;
280 rejected->m_proto = m->m_proto;
281 rejected->m_proto_name = m->m_proto_name;
282
283 if (include_all_codecs) {
284 if (m->m_rtpmaps) {
285 rejected->m_rtpmaps = m->m_rtpmaps;
286 }
287 else if (m->m_format) {
288 rejected->m_format = m->m_format;
289 }
290 }
291
292 rejected->m_rejected = 1;
293
294 return sdp_media_dup(home, rejected, sdp);
295}
296
297/** Expand a @a truncated SDP.
298 */
299static
300sdp_session_t *soa_sdp_expand_media(su_home_t *home,
301 sdp_session_t const *truncated,
302 sdp_session_t const *complete)
303{
304 sdp_session_t *tmp_truncated;
305 sdp_session_t *expanded;
306 sdp_media_t **mE;
307 sdp_media_t **mT;
308 sdp_media_t * const *mC;
309
310 /* Truncated list that we will be reducing */
311 tmp_truncated = sdp_session_dup(home, truncated);
312 /* New resulting list */
313 expanded = sdp_session_dup(home, truncated);
314
315 if (expanded) {
316 expanded->sdp_media = NULL((void*)0); /* Empty the list of medias */
317 mE = &expanded->sdp_media; /* Pointer to the beginning of the new list */
318
319 /* Loop through all items in the complete list to preserve complete list's order */
320 for (mC = &complete->sdp_media; *mC; mC = &(*mC)->m_next) {
321 /* Find the corresponding media in the truncated list */
322 if ((mT = sdp_media_exists(tmp_truncated, *mC))) {
323 /* Copy the corresponding media from the truncated list to the new list */
324 *mE = sdp_media_dup(home, *mT, expanded);
325 if (!*mE)
326 return NULL((void*)0);
327
328 /* Remove corresponding media from the truncated list */
329 mT = &(*mT)->m_next;
Value stored to 'mT' is never read
330 } else {
331 /* If the corresponding media was not found in the truncated list, add a rejected media */
332 *mE = soa_sdp_make_rejected_media(home, *mC, expanded, 0);
333 if (!*mE)
334 return NULL((void*)0);
335 }
336
337 /* Prepare pointer of the new list for a new item */
338 mE = &(*mE)->m_next;
339 }
340 }
341
342 return expanded;
343}
344
345/** Check if @a session should be upgraded with @a remote */
346int soa_sdp_upgrade_is_needed(sdp_session_t const *session,
347 sdp_session_t const *remote)
348{
349 sdp_media_t const *rm, *lm;
350
351 if (!remote)
352 return 0;
353 if (!session)
354 return 1;
355
356 for (rm = remote->sdp_media, lm = session->sdp_media;
357 rm && lm ; rm = rm->m_next, lm = lm->m_next) {
358 if (rm->m_rejected)
359 continue;
360 if (lm->m_rejected)
361 break;
362 }
363
364 return rm != NULL((void*)0);
365}
366
367/** Check if codec is in auxiliary list */
368static
369int soa_sdp_is_auxiliary_codec(sdp_rtpmap_t const *rm, char const *auxiliary)
370{
371 char const *codec;
372 size_t clen, alen;
373 char const *match;
374
375 if (!rm || !rm->rm_encoding || !auxiliary)
376 return 0;
377
378 codec = rm->rm_encoding;
379
380 clen = strlen(codec), alen = strlen(auxiliary);
381
382 if (clen > alen)
383 return 0;
384
385 for (match = auxiliary;
386 (match = su_strcasestr(match, codec));
387 match = match + 1) {
388 if (IS_ALPHANUM(match[clen])(match[clen] && (((match[clen]) >= '0' && (
match[clen]) <= '9') || (match[clen] && ((_bnf_table
[(unsigned char)match[clen]] & bnf_alpha)))))
|| match[clen] == '-')
389 continue;
390 if (match != auxiliary &&
391 (IS_ALPHANUM(match[-1])(match[-1] && (((match[-1]) >= '0' && (match
[-1]) <= '9') || (match[-1] && ((_bnf_table[(unsigned
char)match[-1]] & bnf_alpha)))))
|| match[-1] == '-'))
392 continue;
393 return 1;
394 }
395
396 return 0;
397}
398
399static
400sdp_rtpmap_t *soa_sdp_media_matching_rtpmap(sdp_rtpmap_t const *from,
401 sdp_rtpmap_t const *anylist,
402 char const *auxiliary)
403{
404 sdp_rtpmap_t const *rm;
405
406 for (rm = anylist; rm; rm = rm->rm_next) {
407 /* Ignore auxiliary codecs */
408 if (auxiliary && soa_sdp_is_auxiliary_codec(rm, auxiliary))
409 continue;
410
411 if (sdp_rtpmap_find_matching(from, rm))
412 return (sdp_rtpmap_t *)rm;
413 }
414
415 return NULL((void*)0);
416}
417
418#ifndef _MSC_VER
419#define SDP_MEDIA_NONE((sdp_media_t *)-1) ((sdp_media_t *)-1)
420#else
421#define SDP_MEDIA_NONE((sdp_media_t *)-1) ((sdp_media_t *)(INT_PTR)-1)
422#endif
423
424/** Find first matching media in table @a mm.
425 *
426 * - if allow_rtp_mismatch == 0, search for a matching codec
427 * - if allow_rtp_mismatch == 1, prefer m=line with matching codec
428 * - if allow_rtp_mismatch > 1, ignore codecs
429 */
430static
431int soa_sdp_matching_mindex(soa_session_t *ss,
432 sdp_media_t *mm[],
433 sdp_media_t const *with,
434 int *return_codec_mismatch)
435{
436 int i, j = -1;
437 soa_static_session_t *sss = (soa_static_session_t *)ss;
438 int rtp = sdp_media_uses_rtp(with), dummy;
439 char const *auxiliary = NULL((void*)0);
440
441 if (return_codec_mismatch == NULL((void*)0))
442 return_codec_mismatch = &dummy;
443
444 if (with->m_type == sdp_media_audio) {
445 auxiliary = sss->sss_audio_aux;
446 /* Looking for a single codec */
447 if (with->m_rtpmaps && with->m_rtpmaps->rm_next == NULL((void*)0))
448 auxiliary = NULL((void*)0);
449 }
450
451 for (i = 0; mm[i]; i++) {
452 if (mm[i] == SDP_MEDIA_NONE((sdp_media_t *)-1))
453 continue;
454
455 if (!sdp_media_match_with(mm[i], with))
456 continue;
457
458 if (!rtp)
459 break;
460
461 if (soa_sdp_media_matching_rtpmap(with->m_rtpmaps,
462 mm[i]->m_rtpmaps,
463 auxiliary))
464 break;
465
466 if (j == -1)
467 j = i;
468 }
469
470 if (mm[i])
471 return *return_codec_mismatch = 0, i;
472 else
473 return *return_codec_mismatch = 1, j;
474}
475
476/** Set payload types in @a l_m according to the values in @a r_m.
477 *
478 * @retval number of common codecs
479 */
480static
481int soa_sdp_set_rtpmap_pt(sdp_media_t *l_m,
482 sdp_media_t const *r_m)
483{
484 sdp_rtpmap_t *lrm, **next_lrm;
485 sdp_rtpmap_t const *rrm;
486
487 int local_codecs = 0, common_codecs = 0;
488
489 unsigned char dynamic_pt[128];
490 unsigned pt;
491
492 for (next_lrm = &l_m->m_rtpmaps; (lrm = *next_lrm); ) {
493 if (lrm->rm_any) {
494 /* Remove codecs known only by pt number */
495 *next_lrm = lrm->rm_next;
496 continue;
497 }
498 else {
499 next_lrm = &lrm->rm_next;
500 }
501
502 local_codecs++;
503
504 rrm = sdp_rtpmap_find_matching(r_m->m_rtpmaps, lrm);
505
506 /* XXX - do fmtp comparison */
507
508 if (rrm) {
509#if 0
510 /* Use same payload type as remote */
511 if (lrm->rm_pt != rrm->rm_pt) {
512 lrm->rm_predef = 0;
513 lrm->rm_pt = rrm->rm_pt;
514
515 }
516#endif
517 common_codecs++;
518 }
519 else {
520 /* Determine payload type later */
521 lrm->rm_any = 1;
522 }
523 }
524
525 if (local_codecs == common_codecs)
526 return common_codecs;
527
528 /* Select unique dynamic payload type for each payload */
529
530 memset(dynamic_pt, 0, sizeof dynamic_pt);
531
532 for (lrm = l_m->m_rtpmaps; lrm; lrm = lrm->rm_next) {
533 if (!lrm->rm_any)
534 dynamic_pt[lrm->rm_pt] = 1;
535 }
536
537 for (rrm = r_m->m_rtpmaps; rrm; rrm = rrm->rm_next) {
538 dynamic_pt[rrm->rm_pt] = 1;
539 }
540
541 for (next_lrm = &l_m->m_rtpmaps; (lrm = *next_lrm); ) {
542 if (!lrm->rm_any) {
543 next_lrm = &lrm->rm_next;
544 continue;
545 }
546
547 lrm->rm_any = 0;
548
549 pt = lrm->rm_pt;
550
551 if (dynamic_pt[pt]) {
552 for (pt = 96; pt < 128; pt++)
553 if (!dynamic_pt[pt])
554 break;
555
556 if (pt == 128) {
557 for (pt = 0; pt < 128; pt++)
558 if (!sdp_rtpmap_well_known[pt] && !dynamic_pt[pt])
559 break;
560 }
561
562 if (pt == 128) {
563 for (pt = 0; pt < 128; pt++)
564 if (!dynamic_pt[pt])
565 break;
566 }
567
568 if (pt == 128) {
569 /* Too many payload types */
570 *next_lrm = lrm->rm_next;
571 continue;
572 }
573
574 lrm->rm_pt = pt;
575 lrm->rm_predef = 0;
576 }
577
578 dynamic_pt[pt] = 1;
579
580 next_lrm = &lrm->rm_next;
581 }
582
583 return common_codecs;
584}
585
586
587/** Sort rtpmaps in @a inout_list according to the values in @a rrm.
588 *
589 * @return Number of common codecs
590 */
591static
592int soa_sdp_sort_rtpmap(sdp_rtpmap_t **inout_list,
593 sdp_rtpmap_t const *rrm,
594 char const *auxiliary)
595{
596 sdp_rtpmap_t *sorted = NULL((void*)0), **next = &sorted, **left;
597 sdp_rtpmap_t *aux = NULL((void*)0), **next_aux = &aux;
598
599 int common_codecs = 0;
600
601 assert(inout_list)((void) sizeof ((inout_list) ? 1 : 0), __extension__ ({ if (inout_list
) ; else __assert_fail ("inout_list", "soa_static.c", 601, __extension__
__PRETTY_FUNCTION__); }))
;
602 if (!inout_list)
603 return 0;
604
605 /* If remote has only single codec, ignore list of auxiliary codecs */
606 if (rrm && !rrm->rm_next)
607 auxiliary = NULL((void*)0);
608
609 /* Insertion sort from *inout_list to sorted */
610 for (; rrm && *inout_list; rrm = rrm->rm_next) {
611 for (left = inout_list; *left; left = &(*left)->rm_next) {
612 if (sdp_rtpmap_match(rrm, (*left)))
613 break;
614 }
615 if (!*left)
616 continue;
617
618 if (auxiliary && soa_sdp_is_auxiliary_codec(rrm, auxiliary)) {
619 *next_aux = *left, next_aux = &(*next_aux)->rm_next;
620 }
621 else {
622 common_codecs++;
623 *next = *left; next = &(*next)->rm_next;
624 }
625 *left = (*left)->rm_next;
626 }
627
628 /* Append common auxiliary codecs */
629 if (aux)
630 *next = aux, next = next_aux;
631
632 /* Append leftover codecs */
633 *next = *inout_list;
634
635 *inout_list = sorted;
636
637 return common_codecs;
638}
639
640
641/** Select rtpmaps in @a inout_list according to the values in @a rrm.
642 *
643 * @return Number of common codecs
644 */
645static
646int soa_sdp_select_rtpmap(sdp_rtpmap_t **inout_list,
647 sdp_rtpmap_t const *rrm,
648 char const *auxiliary,
649 int select_single)
650{
651 sdp_rtpmap_t **left;
652 sdp_rtpmap_t *aux = NULL((void*)0), **next_aux = &aux;
653
654 int common_codecs = 0;
655
656 assert(inout_list)((void) sizeof ((inout_list) ? 1 : 0), __extension__ ({ if (inout_list
) ; else __assert_fail ("inout_list", "soa_static.c", 656, __extension__
__PRETTY_FUNCTION__); }))
;
657 if (!inout_list)
658 return 0;
659
660 for (left = inout_list; *left; ) {
661 if (auxiliary && soa_sdp_is_auxiliary_codec(*left, auxiliary))
662 /* Insert into list of auxiliary codecs */
663 *next_aux = *left, *left = (*left)->rm_next,
664 next_aux = &(*next_aux)->rm_next;
665 else if (!(select_single && common_codecs > 0)
666 && sdp_rtpmap_find_matching(rrm, (*left)))
667 /* Select */
668 left = &(*left)->rm_next, common_codecs++;
669 else
670 /* Remove */
671 *left = (*left)->rm_next;
672 }
673
674 *left = aux, *next_aux = NULL((void*)0);
675
676 return common_codecs;
677}
678
679
680/** Sort and select rtpmaps */
681static
682int soa_sdp_media_upgrade_rtpmaps(soa_session_t *ss,
683 sdp_media_t *sm,
684 sdp_media_t const *rm)
685{
686 soa_static_session_t *sss = (soa_static_session_t *)ss;
687 char const *auxiliary = NULL((void*)0);
688 int common_codecs;
689
690 common_codecs = soa_sdp_set_rtpmap_pt(sm, rm);
691
692 if (rm->m_type == sdp_media_audio)
693 auxiliary = sss->sss_audio_aux;
694
695 if (ss->ss_rtp_sort == SOA_RTP_SORT_REMOTE ||
696 (ss->ss_rtp_sort == SOA_RTP_SORT_DEFAULT &&
697 rm->m_mode == sdp_recvonly)) {
698 soa_sdp_sort_rtpmap(&sm->m_rtpmaps, rm->m_rtpmaps, auxiliary);
699 }
700
701 if (common_codecs == 0)
702 ;
703 else if (ss->ss_rtp_select == SOA_RTP_SELECT_SINGLE) {
704 soa_sdp_select_rtpmap(&sm->m_rtpmaps, rm->m_rtpmaps, auxiliary, 1);
705 }
706 else if (ss->ss_rtp_select == SOA_RTP_SELECT_COMMON) {
707 soa_sdp_select_rtpmap(&sm->m_rtpmaps, rm->m_rtpmaps, auxiliary, 0);
708 }
709
710 return common_codecs;
711}
712
713
714/** Sort and select rtpmaps within session */
715static
716int soa_sdp_session_upgrade_rtpmaps(soa_session_t *ss,
717 sdp_session_t *session,
718 sdp_session_t const *remote)
719{
720 sdp_media_t *sm;
721 sdp_media_t const *rm;
722
723 for (sm = session->sdp_media, rm = remote->sdp_media;
724 sm && rm;
725 sm = sm->m_next, rm = rm->m_next) {
726 if (!sm->m_rejected && sdp_media_uses_rtp(sm))
727 soa_sdp_media_upgrade_rtpmaps(ss, sm, rm);
728 }
729
730 return 0;
731}
732
733/** Upgrade m= lines within session */
734static
735int soa_sdp_upgrade(soa_session_t *ss,
736 su_home_t *home,
737 sdp_session_t *session,
738 sdp_session_t const *user,
739 sdp_session_t const *remote,
740 int **return_u2s,
741 int **return_s2u)
742{
743 soa_static_session_t *sss = (soa_static_session_t *)ss;
744
745 int Ns, Nu, Nr, Nmax, n, i, j;
746 sdp_media_t *m, **mm, *um;
747 sdp_media_t **s_media, **o_media, **u_media;
748 sdp_media_t const *rm, **r_media;
749 int *u2s = NULL((void*)0), *s2u = NULL((void*)0);
750
751 if (session == NULL((void*)0) || user == NULL((void*)0))
752 return (errno(*__errno_location ()) = EFAULT14), -1;
753
754#ifdef __clang__1
755#pragma clang diagnostic push
756#pragma clang diagnostic ignored "-Wnon-literal-null-conversion"
757#endif
758
759 Ns = sdp_media_count(session, sdp_media_any, (sdp_text_t)0, (sdp_proto_e)0, (sdp_text_t)0);
760 Nu = sdp_media_count(user, sdp_media_any, (sdp_text_t)0, (sdp_proto_e)0, (sdp_text_t)0);
761 Nr = sdp_media_count(remote, sdp_media_any, (sdp_text_t)0, (sdp_proto_e)0, (sdp_text_t)0);
762
763#ifdef __clang__1
764#pragma clang diagnostic pop
765#endif
766
767 if (remote == NULL((void*)0))
768 Nmax = Ns + Nu;
769 else if (Ns < Nr)
770 Nmax = Nr;
771 else
772 Nmax = Ns;
773
774 s_media = su_zalloc(home, (Nmax + 1) * (sizeof *s_media));
775 o_media = su_zalloc(home, (Ns + 1) * (sizeof *o_media));
776 u_media = su_zalloc(home, (Nu + 1) * (sizeof *u_media));
777 r_media = su_zalloc(home, (Nr + 1) * (sizeof *r_media));
778 if (!s_media || !o_media || !u_media || !r_media)
779 return -1;
780
781 um = sdp_media_dup_all(home, user->sdp_media, session);
782 if (!um && user->sdp_media)
783 return -1;
784
785 u2s = su_alloc(home, (Nu + 1) * sizeof(*u2s));
786 s2u = su_alloc(home, (Nmax + 1) * sizeof(*s2u));
787 if (!u2s || !s2u)
788 return -1;
789
790 for (i = 0; i < Nu; i++)
791 u2s[i] = U2S_NOT_USED(-1);
792 u2s[Nu] = U2S_SENTINEL(-2);
793
794 for (i = 0; i < Nmax; i++)
795 s2u[i] = U2S_NOT_USED(-1);
796 s2u[Nmax] = U2S_SENTINEL(-2);
797
798 for (i = 0, m = session->sdp_media; m && i < Ns; m = m->m_next)
799 o_media[i++] = m;
800 assert(i == Ns)((void) sizeof ((i == Ns) ? 1 : 0), __extension__ ({ if (i ==
Ns) ; else __assert_fail ("i == Ns", "soa_static.c", 800, __extension__
__PRETTY_FUNCTION__); }))
;
801 for (i = 0, m = um; m && i < Nu; m = m->m_next)
802 u_media[i++] = m;
803 assert(i == Nu)((void) sizeof ((i == Nu) ? 1 : 0), __extension__ ({ if (i ==
Nu) ; else __assert_fail ("i == Nu", "soa_static.c", 803, __extension__
__PRETTY_FUNCTION__); }))
;
804 m = remote ? remote->sdp_media : NULL((void*)0);
805 for (i = 0; m && i < Nr; m = m->m_next)
806 r_media[i++] = m;
807 assert(i == Nr)((void) sizeof ((i == Nr) ? 1 : 0), __extension__ ({ if (i ==
Nr) ; else __assert_fail ("i == Nr", "soa_static.c", 807, __extension__
__PRETTY_FUNCTION__); }))
;
808
809 if (sss->sss_ordered_user && sss->sss_u2s) { /* User SDP is ordered */
810 for (j = 0; sss->sss_u2s[j] != U2S_SENTINEL(-2); j++) {
811 i = sss->sss_u2s[j];
812 if (i == U2S_NOT_USED(-1))
813 continue;
814 if (j >= Nu) /* lines removed from user SDP */
815 continue;
816 if (i >= Ns) /* I should never be called but somehow i and Ns are 0 here sometimes */
817 continue;
818 s_media[i] = u_media[j], u_media[j] = SDP_MEDIA_NONE((sdp_media_t *)-1);
819 u2s[j] = i, s2u[i] = j;
820 }
821 }
822
823 if (remote) {
824 /* Update session according to remote */
825 for (i = 0; i < Nr; i++) {
826 rm = r_media[i];
827 m = s_media[i];
828
829 if (!m) {
830 int codec_mismatch = 0;
831
832 if (!rm->m_rejected)
833 j = soa_sdp_matching_mindex(ss, u_media, rm, &codec_mismatch);
834 else
835 j = -1;
836
837 if (j == -1) {
838 s_media[i] = soa_sdp_make_rejected_media(home, rm, session, 0);
839 continue;
840 }
841 else if (codec_mismatch && !ss->ss_rtp_mismatch) {
842 m = soa_sdp_make_rejected_media(home, u_media[j], session, 1);
843 soa_sdp_set_rtpmap_pt(s_media[i] = m, rm);
844 continue;
845 }
846
847 s_media[i] = m = u_media[j]; u_media[j] = SDP_MEDIA_NONE((sdp_media_t *)-1);
848 u2s[j] = i, s2u[i] = j;
849 }
850
851 if (sdp_media_uses_rtp(rm))
852 soa_sdp_media_upgrade_rtpmaps(ss, m, rm);
853 }
854 }
855 else {
856
857 if (sss->sss_ordered_user) {
858 /* Update session with unused media in u_media */
859
860 if (!sss->sss_reuse_rejected) {
861 /* Mark previously used slots */
862 for (i = 0; i < Ns; i++) {
863 if (s_media[i])
864 continue;
865 s_media[i] =
866 soa_sdp_make_rejected_media(home, o_media[i], session, 0);
867 }
868 }
869
870 for (j = 0; j < Nu; j++) {
871 if (u_media[j] == SDP_MEDIA_NONE((sdp_media_t *)-1))
872 continue;
873
874 for (i = 0; i < Nmax; i++) {
875 if (s_media[i] == NULL((void*)0)) {
876 s_media[i] = u_media[j], u_media[j] = SDP_MEDIA_NONE((sdp_media_t *)-1);
877 u2s[j] = i, s2u[i] = j;
878 break;
879 }
880 }
881
882 assert(i != Nmax)((void) sizeof ((i != Nmax) ? 1 : 0), __extension__ ({ if (i !=
Nmax) ; else __assert_fail ("i != Nmax", "soa_static.c", 882
, __extension__ __PRETTY_FUNCTION__); }))
;
883 }
884 }
885
886 /* Match unused user media by media types with the existing session */
887 for (i = 0; i < Ns; i++) {
888 if (s_media[i])
889 continue;
890
891 j = soa_sdp_matching_mindex(ss, u_media, o_media[i], NULL((void*)0));
892 if (j == -1) {
893 s_media[i] = soa_sdp_make_rejected_media(home, o_media[i], session, 0);
894 continue;
895 }
896
897 s_media[i] = u_media[j], u_media[j] = SDP_MEDIA_NONE((sdp_media_t *)-1);
898 u2s[j] = i, s2u[i] = j;
899 }
900
901 /* Here we just append new media at the end */
902 for (j = 0; j < Nu; j++) {
903 if (u_media[j] != SDP_MEDIA_NONE((sdp_media_t *)-1)) {
904 s_media[i] = u_media[j], u_media[j] = SDP_MEDIA_NONE((sdp_media_t *)-1);
905 u2s[j] = i, s2u[i] = j;
906 i++;
907 }
908 }
909 assert(i <= Nmax)((void) sizeof ((i <= Nmax) ? 1 : 0), __extension__ ({ if (
i <= Nmax) ; else __assert_fail ("i <= Nmax", "soa_static.c"
, 909, __extension__ __PRETTY_FUNCTION__); }))
;
910 }
911
912 mm = &session->sdp_media;
913 for (i = 0; s_media[i]; i++) {
914 m = s_media[i]; *mm = m; mm = &m->m_next;
915 }
916 *mm = NULL((void*)0);
917
918 s2u[n = i] = U2S_SENTINEL(-2);
919 *return_u2s = u2s;
920 *return_s2u = s2u;
921
922#ifndef NDEBUG /* X check */
923 for (j = 0; j < Nu; j++) {
924 i = u2s[j];
925 assert(i == U2S_NOT_USED || s2u[i] == j)((void) sizeof ((i == (-1) || s2u[i] == j) ? 1 : 0), __extension__
({ if (i == (-1) || s2u[i] == j) ; else __assert_fail ("i == U2S_NOT_USED || s2u[i] == j"
, "soa_static.c", 925, __extension__ __PRETTY_FUNCTION__); })
)
;
926 }
927 for (i = 0; i < n; i++) {
928 j = s2u[i];
929 assert(j == U2S_NOT_USED || u2s[j] == i)((void) sizeof ((j == (-1) || u2s[j] == i) ? 1 : 0), __extension__
({ if (j == (-1) || u2s[j] == i) ; else __assert_fail ("j == U2S_NOT_USED || u2s[j] == i"
, "soa_static.c", 929, __extension__ __PRETTY_FUNCTION__); })
)
;
930 }
931#endif
932
933 return 0;
934}
935
936static
937int *u2s_alloc(su_home_t *home, int const *u2s)
938{
939 if (u2s) {
940 int i, *a;
941 for (i = 0; u2s[i] != U2S_SENTINEL(-2); i++)
942 ;
943 a = su_alloc(home, (i + 1) * (sizeof *u2s));
944 if (a)
945 memcpy(a, u2s, (i + 1) * (sizeof *u2s));
946 return a;
947 }
948
949 return NULL((void*)0);
950}
951
952/** Check if @a session contains media that are rejected by @a remote. */
953static
954int soa_sdp_reject_is_needed(sdp_session_t const *session,
955 sdp_session_t const *remote)
956{
957 sdp_media_t const *sm, *rm;
958
959 if (!remote)
960 return 1;
961 if (!session)
962 return 0;
963
964 for (sm = session->sdp_media, rm = remote->sdp_media;
965 sm && rm; sm = sm->m_next, rm = rm->m_next) {
966 if (rm->m_rejected) {
967 if (!sm->m_rejected)
968 return 1;
969 }
970 else {
971 /* Mode bits do not match */
972 if (((rm->m_mode & sdp_recvonly) == sdp_recvonly)
973 != ((sm->m_mode & sdp_sendonly) == sdp_sendonly))
974 return 1;
975 }
976 }
977
978 if (sm)
979 return 1;
980
981 return 0;
982}
983
984/** If m= line is rejected by remote mark m= line rejected within session */
985static
986int soa_sdp_reject(su_home_t *home,
987 sdp_session_t *session,
988 sdp_session_t const *remote)
989{
990 sdp_media_t *sm;
991 sdp_media_t const *rm;
992
993 if (!session || !session->sdp_media || !remote)
994 return 0;
995
996 rm = remote->sdp_media;
997
998 for (sm = session->sdp_media; sm; sm = sm->m_next) {
999 if (!rm || rm->m_rejected) {
1000 sm->m_rejected = 1;
1001 sm->m_mode = 0;
1002 sm->m_port = 0;
1003 sm->m_number_of_ports = 1;
1004 if (sm->m_format)
1005 sm->m_format->l_next = NULL((void*)0);
1006 if (sm->m_rtpmaps)
1007 sm->m_rtpmaps->rm_next = NULL((void*)0);
1008 sm->m_information = NULL((void*)0);
1009 if (sm->m_connections)
1010 sm->m_connections->c_next = NULL((void*)0);
1011 sm->m_bandwidths = NULL((void*)0);
1012 sm->m_key = NULL((void*)0);
1013 sm->m_attributes = NULL((void*)0);
1014 sm->m_user = NULL((void*)0);
1015 }
1016
1017 if (rm)
1018 rm = rm->m_next;
1019 }
1020
1021 return 0;
1022}
1023
1024
1025/** Update mode within session.
1026 *
1027 * @sa soatag_hold
1028 *
1029 * @retval 1 if session was changed (or to be changed, if @a dryrun is nonzero)
1030 */
1031static
1032int soa_sdp_mode_set(sdp_session_t const *user,
1033 int const *s2u,
1034 sdp_session_t *session,
1035 sdp_session_t const *remote,
1036 char const *hold,
1037 int dryrun)
1038{
1039 sdp_media_t *sm;
1040 sdp_media_t const *rm, *rm_next, *um;
1041 int retval = 0, i, j;
1042 int hold_all;
1043 int inactive_all;
1044 char const *hold_media = NULL((void*)0);
1045 sdp_mode_t send_mode, recv_mode;
1046
1047 SU_DEBUG_7(("soa_sdp_mode_set(%p, %p, \"%s\"): called\n",(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(soa_log, 7, "soa_static.c", (const char
*)__func__, 1048, "soa_sdp_mode_set(%p, %p, \"%s\"): called\n"
, (void *)session, (void *)remote, hold ? hold : "")) : (void
)0)
1048 (void *)session, (void *)remote, hold ? hold : ""))(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(soa_log, 7, "soa_static.c", (const char
*)__func__, 1048, "soa_sdp_mode_set(%p, %p, \"%s\"): called\n"
, (void *)session, (void *)remote, hold ? hold : "")) : (void
)0)
;
1049
1050 if (!session || !session->sdp_media)
1051 return 0;
1052
1053 rm = remote ? remote->sdp_media : NULL((void*)0), rm_next = NULL((void*)0);
1054
1055 hold_all = su_strmatch(hold, "*");
1056 inactive_all = su_strmatch(hold, "#");
1057
1058 i = 0;
1059
1060 for (sm = session->sdp_media; sm; sm = sm->m_next, rm = rm_next, i++) {
1061 rm_next = rm ? rm->m_next : NULL((void*)0);
1062
1063 if (sm->m_rejected)
1064 continue;
1065
1066 assert(s2u)((void) sizeof ((s2u) ? 1 : 0), __extension__ ({ if (s2u) ; else
__assert_fail ("s2u", "soa_static.c", 1066, __extension__ __PRETTY_FUNCTION__
); }))
;
1067
1068 for (j = 0, um = user->sdp_media; j != s2u[i]; um = um->m_next, j++) {
1069 if (!um) break;
1070 }
1071
1072 if (um == NULL((void*)0)) {
1073 if (dryrun)
1074 return 1;
1075 else
1076 retval = 1;
1077 sm->m_rejected = 1;
1078 sm->m_mode = sdp_inactive;
1079 sm->m_port = 0;
1080 continue;
1081 }
1082
1083 if (um->m_mode) { /* when its inactive, keep it inactive */
1084 send_mode = (sdp_mode_t)(um->m_mode & sdp_sendonly);
1085 if (rm)
1086 send_mode = (rm->m_mode & sdp_recvonly) ? sdp_sendonly : 0;
1087 } else send_mode = um->m_mode;
1088
1089 recv_mode = (sdp_mode_t)(um->m_mode & sdp_recvonly);
1090
1091 if (rm && rm->m_mode == sdp_inactive) {
1092 send_mode = recv_mode = (sdp_mode_t)0;
1093 }
1094 else if (inactive_all) {
1095 send_mode = recv_mode = (sdp_mode_t)0;
1096 }
1097 else if (hold_all) {
1098 recv_mode = (sdp_mode_t)0;
1099 }
1100 else if (hold && (hold_media = su_strcasestr(hold, sm->m_type_name))) {
1101 recv_mode = (sdp_mode_t)0;
1102 hold_media += strlen(sm->m_type_name);
1103 hold_media += strspn(hold_media, " \t");
1104 if (hold_media[0] == '=') {
1105 hold_media += strspn(hold, " \t");
1106 if (su_casenmatch(hold_media, "inactive", strlen("inactive")))
1107 recv_mode = send_mode = (sdp_mode_t)0;
1108 }
1109 }
1110
1111 if (sm->m_mode != (unsigned)(recv_mode | send_mode)) {
1112 if (dryrun)
1113 return 1;
1114 else
1115 retval = 1;
1116 sm->m_mode = recv_mode | send_mode;
1117 }
1118 }
1119
1120 return retval;
1121}
1122
1123enum offer_answer_action {
1124 generate_offer,
1125 generate_answer,
1126 process_answer
1127};
1128
1129/**
1130 * Updates the modified copy of local SDP based
1131 * on application provided local SDP and remote SDP.
1132 */
1133static int offer_answer_step(soa_session_t *ss,
1134 enum offer_answer_action action,
1135 char const *by)
1136{
1137 soa_static_session_t *sss = (soa_static_session_t *)ss;
1138
1139 sdp_session_t *local = ss->ss_local->ssd_sdp;
1140 sdp_session_t local0[1];
1141
1142 sdp_session_t *user = ss->ss_user->ssd_sdp;
1143 unsigned user_version = ss->ss_user_version;
1144
1145 sdp_session_t *remote = ss->ss_remote->ssd_sdp;
1146 unsigned remote_version = ss->ss_remote_version;
1147
1148 int fresh = 0;
1149
1150 sdp_origin_t o[1] = {{ sizeof(o) }};
1151 sdp_connection_t *c, c0[1] = {{ sizeof(c0) }};
1152 char c0_buffer[64];
1153
1154 sdp_time_t t[1] = {{ sizeof(t) }};
1155
1156 int *u2s = NULL((void*)0), *s2u = NULL((void*)0), *tbf;
1157
1158 sdp_session_t *latest = NULL((void*)0), *previous = NULL((void*)0);
1159
1160 char const *phrase = "Internal Media Error";
1161
1162 su_home_t tmphome[SU_HOME_AUTO_SIZE(8192)(((8192) + ((sizeof(su_home_t) + 7) & (size_t)~8) + ((3 *
sizeof (void *) + 4 * sizeof(unsigned) + 7 * (sizeof (long) +
sizeof(void *)) + 7) & (size_t)~8)) / sizeof(su_home_t))
];
1163
1164 su_home_auto(tmphome, sizeof tmphome);
1165
1166 SU_DEBUG_7(("soa_static_offer_answer_action(%p, %s): called\n",(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(soa_log, 7, "soa_static.c", (const char
*)__func__, 1167, "soa_static_offer_answer_action(%p, %s): called\n"
, (void *)ss, by)) : (void)0)
1167 (void *)ss, by))(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(soa_log, 7, "soa_static.c", (const char
*)__func__, 1167, "soa_static_offer_answer_action(%p, %s): called\n"
, (void *)ss, by)) : (void)0)
;
1168
1169 if (user == NULL((void*)0))
1170 return soa_set_status(ss, 500, "No session set by user");
1171
1172 if (action == generate_offer)
1173 remote = NULL((void*)0);
1174 else if (remote == NULL((void*)0))
1175 return soa_set_status(ss, 500, "No remote SDP");
1176
1177#ifdef __clang__1
1178#pragma clang diagnostic push
1179#pragma clang diagnostic ignored "-Wnon-literal-null-conversion"
1180#endif
1181
1182 /* Pre-negotiation Step: Expand truncated remote SDP */
1183 if (local && remote) switch (action) {
1184 case generate_answer:
1185 case process_answer:
1186 if (sdp_media_count(remote, sdp_media_any, "*", (sdp_proto_e)0, (sdp_text_t)0) <
1187 sdp_media_count(local, sdp_media_any, "*", (sdp_proto_e)0, (sdp_text_t)0)) {
1188 SU_DEBUG_5(("%s: remote %s is truncated: expanding\n",(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(soa_log, 5, "soa_static.c", (const char
*)__func__, 1189, "%s: remote %s is truncated: expanding\n",
by, action == generate_answer ? "offer" : "answer")) : (void
)0)
1189 by, action == generate_answer ? "offer" : "answer"))(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 5 ? (_su_llog(soa_log, 5, "soa_static.c", (const char
*)__func__, 1189, "%s: remote %s is truncated: expanding\n",
by, action == generate_answer ? "offer" : "answer")) : (void
)0)
;
1190 remote = soa_sdp_expand_media(tmphome, remote, local);
1191 if (remote == NULL((void*)0))
1192 return soa_set_status(ss, 500, "Cannot expand remote session");
1193 }
1194 default:
1195 break;
1196 }
1197
1198#ifdef __clang__1
1199#pragma clang diagnostic pop
1200#endif
1201
1202
1203 /* Step A: Create local SDP session (based on user-supplied SDP) */
1204 if (local == NULL((void*)0)) switch (action) {
1205 case generate_offer:
1206 case generate_answer:
1207 SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(soa_log, 7, "soa_static.c", (const char
*)__func__, 1208, "soa_static(%p, %s): %s\n", (void *)ss, by
, "generating local description")) : (void)0)
1208 "generating local description"))(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(soa_log, 7, "soa_static.c", (const char
*)__func__, 1208, "soa_static(%p, %s): %s\n", (void *)ss, by
, "generating local description")) : (void)0)
;
1209
1210 fresh = 1;
1211 local = local0;
1212 *local = *user, local->sdp_media = NULL((void*)0);
1213
1214 o->o_username = "-";
1215 o->o_address = c0;
1216 c0->c_address = c0_buffer;
1217
1218 if (!local->sdp_origin)
1219 local->sdp_origin = o;
1220 break;
1221
1222 case process_answer:
1223 default:
1224 goto internal_error;
1225 }
1226
1227 /* Step B: upgrade local SDP (add m= lines to it) */
1228 switch (action) {
1229 case generate_offer:
1230 /* Upgrade local SDP based on user SDP */
1231 if (local != local0 && ss->ss_local_user_version == user_version)
1232 break;
1233 if (local != local0)
1234 *local0 = *local, local = local0;
1235 SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(soa_log, 7, "soa_static.c", (const char
*)__func__, 1236, "soa_static(%p, %s): %s\n", (void *)ss, by
, "upgrade with local description")) : (void)0)
1236 "upgrade with local description"))(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(soa_log, 7, "soa_static.c", (const char
*)__func__, 1236, "soa_static(%p, %s): %s\n", (void *)ss, by
, "upgrade with local description")) : (void)0)
;
1237 if (soa_sdp_upgrade(ss, tmphome, local, user, NULL((void*)0), &u2s, &s2u) < 0)
1238 goto internal_error;
1239 break;
1240 case generate_answer:
1241 /* Upgrade local SDP based on remote SDP */
1242 if (ss->ss_local_user_version == user_version &&
1243 ss->ss_local_remote_version == remote_version)
1244 break;
1245 if (1) {
1246 if (local != local0)
1247 *local0 = *local, local = local0;
1248 SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(soa_log, 7, "soa_static.c", (const char
*)__func__, 1249, "soa_static(%p, %s): %s\n", (void *)ss, by
, "upgrade with remote description")) : (void)0)
1249 "upgrade with remote description"))(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(soa_log, 7, "soa_static.c", (const char
*)__func__, 1249, "soa_static(%p, %s): %s\n", (void *)ss, by
, "upgrade with remote description")) : (void)0)
;
1250 if (soa_sdp_upgrade(ss, tmphome, local, user, remote, &u2s, &s2u) < 0)
1251 goto internal_error;
1252 }
1253 break;
1254 case process_answer:
1255 default:
1256 break;
1257 }
1258
1259
1260 /* Step C: reject media */
1261 switch (action) {
1262 case generate_offer:
1263 /* Local media is marked as rejected already in upgrade phase */
1264 break;
1265 case generate_answer:
1266 case process_answer:
1267 if (ss->ss_local_remote_version == remote_version)
1268 break;
1269 if (soa_sdp_reject_is_needed(local, remote)) {
1270 if (local != local0) {
1271 *local0 = *local, local = local0;
1272#define DUP_LOCAL(local)do { if (!local->sdp_media) break; local->sdp_media = sdp_media_dup_all
(tmphome, local->sdp_media, local); if (!local->sdp_media
) goto internal_error; } while (0)
\
1273 do { \
1274 if (!local->sdp_media) break; \
1275 local->sdp_media = \
1276 sdp_media_dup_all(tmphome, local->sdp_media, local); \
1277 if (!local->sdp_media) \
1278 goto internal_error; \
1279 } while (0)
1280 DUP_LOCAL(local)do { if (!local->sdp_media) break; local->sdp_media = sdp_media_dup_all
(tmphome, local->sdp_media, local); if (!local->sdp_media
) goto internal_error; } while (0)
;
1281 }
1282 SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(soa_log, 7, "soa_static.c", (const char
*)__func__, 1283, "soa_static(%p, %s): %s\n", (void *)ss, by
, "marking rejected media")) : (void)0)
1283 "marking rejected media"))(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(soa_log, 7, "soa_static.c", (const char
*)__func__, 1283, "soa_static(%p, %s): %s\n", (void *)ss, by
, "marking rejected media")) : (void)0)
;
1284 soa_sdp_reject(tmphome, local, remote);
1285 }
1286 break;
1287 default:
1288 break;
1289 }
1290
1291 /* Step D: Set media mode bits */
1292 switch (action) {
1293 int const *s2u_;
1294
1295 case generate_offer:
1296 case generate_answer:
1297 case process_answer:
1298 s2u_ = s2u;
1299
1300 if (!s2u_) s2u_ = sss->sss_s2u;
1301
1302 if (soa_sdp_mode_set(user, s2u_, local, remote, ss->ss_hold, 1)) {
1303 if (local != local0) {
1304 *local0 = *local, local = local0;
1305 DUP_LOCAL(local)do { if (!local->sdp_media) break; local->sdp_media = sdp_media_dup_all
(tmphome, local->sdp_media, local); if (!local->sdp_media
) goto internal_error; } while (0)
;
1306 }
1307
1308 soa_sdp_mode_set(user, s2u_, local, remote, ss->ss_hold, 0);
1309 }
1310 break;
1311 default:
1312 break;
1313 }
1314
1315 /* Step E: Upgrade codecs by answer. */
1316 switch (action) {
1317 case process_answer:
1318 /* Upgrade local SDP based on remote SDP */
1319 if (ss->ss_local_remote_version == remote_version)
1320 break;
1321 if (1 /* We don't have good test for codecs */) {
1322 SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(soa_log, 7, "soa_static.c", (const char
*)__func__, 1323, "soa_static(%p, %s): %s\n", (void *)ss, by
, "upgrade codecs with remote description")) : (void)0)
1323 "upgrade codecs with remote description"))(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(soa_log, 7, "soa_static.c", (const char
*)__func__, 1323, "soa_static(%p, %s): %s\n", (void *)ss, by
, "upgrade codecs with remote description")) : (void)0)
;
1324 if (local != local0) {
1325 *local0 = *local, local = local0;
1326 DUP_LOCAL(local)do { if (!local->sdp_media) break; local->sdp_media = sdp_media_dup_all
(tmphome, local->sdp_media, local); if (!local->sdp_media
) goto internal_error; } while (0)
;
1327 }
1328 soa_sdp_session_upgrade_rtpmaps(ss, local, remote);
1329 }
1330 break;
1331 case generate_offer:
1332 case generate_answer:
1333 default:
1334 break;
1335 }
1336
1337 /* Step F0: Initialize o= line */
1338 if (fresh) {
1339 if (user->sdp_origin) {
1340 o->o_username = user->sdp_origin->o_username;
1341
1342 if (user->sdp_origin->o_address)
1343 o->o_address = user->sdp_origin->o_address;
1344
1345 if (user->sdp_origin->o_id)
1346 o->o_id = user->sdp_origin->o_id;
1347
1348 if (user->sdp_origin->o_version && user->sdp_origin->o_version != o->o_version) {
1349 o->o_version = user->sdp_origin->o_version;
1350 o->o_version--;
1351 }
1352 }
1353
1354 if (soa_init_sdp_origin_with_session(ss, o, c0_buffer, local) < 0) {
1355 phrase = "Cannot Get IP Address for Session Description";
1356 goto internal_error;
1357 }
1358
1359 local->sdp_origin = o;
1360 }
1361
1362 /* Step F: Update c= line(s) */
1363 switch (action) {
1364 sdp_connection_t *user_c, *local_c;
1365
1366 case generate_offer:
1367 case generate_answer:
1368 user_c = user->sdp_connection;
1369 if (!soa_check_sdp_connection(user_c))
1370 user_c = NULL((void*)0);
1371
1372 local_c = local->sdp_connection;
1373 if (!soa_check_sdp_connection(local_c))
1374 local_c = NULL((void*)0);
1375
1376 if (ss->ss_local_user_version != user_version ||
1377 local_c == NULL((void*)0) ||
1378 (user_c != NULL((void*)0) && sdp_connection_cmp(local_c, user_c))) {
1379 sdp_media_t *m;
1380
1381 if (user_c)
1382 c = user_c;
1383 else
1384 c = local->sdp_origin->o_address;
1385
1386 /* Every m= line (even rejected one) must have a c= line
1387 * or there must be a c= line at session level
1388 */
1389 for (m = local->sdp_media; m; m = m->m_next)
1390 if (m->m_connections == NULL((void*)0))
1391 break;
1392
1393 if (m) {
1394 if (local != local0) {
1395 *local0 = *local, local = local0;
1396 DUP_LOCAL(local)do { if (!local->sdp_media) break; local->sdp_media = sdp_media_dup_all
(tmphome, local->sdp_media, local); if (!local->sdp_media
) goto internal_error; } while (0)
;
1397 }
1398 local->sdp_connection = c;
1399 }
1400 }
1401 break;
1402
1403 default:
1404 break;
1405 }
1406
1407 soa_description_free(ss, ss->ss_previous);
1408 su_free(ss->ss_home, sss->sss_previous.u2s), sss->sss_previous.u2s = NULL((void*)0);
1409 su_free(ss->ss_home, sss->sss_previous.s2u), sss->sss_previous.s2u = NULL((void*)0);
1410
1411 if (u2s) {
1412 u2s = u2s_alloc(ss->ss_home, u2s);
1413 s2u = u2s_alloc(ss->ss_home, s2u);
1414 if (!u2s || !s2u)
1415 goto internal_error;
1416 }
1417
1418 if (ss->ss_local->ssd_sdp != local &&
1419 sdp_session_cmp(ss->ss_local->ssd_sdp, local)) {
1420 int bump;
1421
1422 switch (action) {
1423 case generate_offer:
1424 bump = sdp_session_cmp(local, sss->sss_latest);
1425 break;
1426 case generate_answer:
1427 bump = 1;
1428 break;
1429 case process_answer:
1430 default:
1431 bump = 0;
1432 break;
1433 }
1434
1435 if (bump) {
1436 /* Upgrade the version number */
1437 if (local->sdp_origin != o)
1438 *o = *local->sdp_origin, local->sdp_origin = o;
1439 o->o_version++;
1440 }
1441
1442 /* Do sanity checks for the created SDP */
1443 if (!local->sdp_subject) /* s= is mandatory */
1444 local->sdp_subject = "-";
1445 if (!local->sdp_time) /* t= is mandatory */
1446 local->sdp_time = t;
1447
1448 if (action == generate_offer) {
1449 /* Keep a copy of previous session state */
1450 int *previous_u2s = u2s_alloc(ss->ss_home, sss->sss_u2s);
1451 int *previous_s2u = u2s_alloc(ss->ss_home, sss->sss_s2u);
1452
1453 if ((sss->sss_u2s && !previous_u2s) || (sss->sss_s2u && !previous_s2u))
1454 goto internal_error;
1455
1456 *ss->ss_previous = *ss->ss_local;
1457 memset(ss->ss_local, 0, (sizeof *ss->ss_local));
1458 ss->ss_previous_user_version = ss->ss_local_user_version;
1459 ss->ss_previous_remote_version = ss->ss_local_remote_version;
1460 sss->sss_previous.u2s = previous_u2s;
1461 sss->sss_previous.s2u = previous_s2u;
1462 }
1463
1464 SU_DEBUG_7(("soa_static(%p, %s): %s\n", (void *)ss, by,(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(soa_log, 7, "soa_static.c", (const char
*)__func__, 1465, "soa_static(%p, %s): %s\n", (void *)ss, by
, "storing local description")) : (void)0)
1465 "storing local description"))(((soa_log != ((void*)0) && soa_log->log_init) == 0
? 9 : ((soa_log != ((void*)0) && soa_log->log_init
> 1) ? soa_log->log_level : su_log_default->log_level
)) >= 7 ? (_su_llog(soa_log, 7, "soa_static.c", (const char
*)__func__, 1465, "soa_static(%p, %s): %s\n", (void *)ss, by
, "storing local description")) : (void)0)
;
1466
1467 /* Update the unparsed and pretty-printed descriptions */
1468 if (soa_description_set(ss, ss->ss_local, local, NULL((void*)0), 0) < 0) {
1469 if (action == generate_offer) {
1470 /* Remove 2nd reference to local session state */
1471 memset(ss->ss_previous, 0, (sizeof *ss->ss_previous));
1472 ss->ss_previous_user_version = 0;
1473 ss->ss_previous_remote_version = 0;
1474 su_free(ss->ss_home, sss->sss_previous.u2s), sss->sss_previous.u2s = NULL((void*)0);
1475 su_free(ss->ss_home, sss->sss_previous.s2u), sss->sss_previous.s2u = NULL((void*)0);
1476 }
1477
1478 su_free(ss->ss_home, u2s), su_free(ss->ss_home, s2u);
1479
1480 goto internal_error;
1481 }
1482
1483 if (bump) {
1484 latest = sdp_session_dup(ss->ss_home, ss->ss_local->ssd_sdp);
1485 previous = sss->sss_latest;
1486 }
1487 }
1488
1489 if (u2s) {
1490 tbf = sss->sss_u2s, sss->sss_u2s = u2s, su_free(ss->ss_home, tbf);
1491 tbf = sss->sss_s2u, sss->sss_s2u = s2u, su_free(ss->ss_home, tbf);
1492 }
1493
1494 /* Update version numbers */
1495 switch (action) {
1496 case generate_offer:
1497 ss->ss_local_user_version = user_version;
1498 sss->sss_latest = latest;
1499 break;
1500 case generate_answer:
1501 ss->ss_local_user_version = user_version;
1502 ss->ss_local_remote_version = remote_version;
1503 sss->sss_latest = latest;
1504 break;
1505 case process_answer:
1506 ss->ss_local_remote_version = remote_version;
1507 default:
1508 break;
1509 }
1510
1511 if (previous)
1512 su_free(ss->ss_home, previous);
1513
1514 su_home_deinit(tmphome);
1515 return 0;
1516
1517 internal_error:
1518 su_home_deinit(tmphome);
1519 return soa_set_status(ss, 500, phrase);
1520}
1521
1522/**
1523 * Generates offer based on local SDP.
1524 */
1525static int soa_static_generate_offer(soa_session_t *ss,
1526 soa_callback_f *completed)
1527{
1528 if (!ss->ss_user->ssd_sdp)
1529 return soa_set_status(ss, 500, "No session set by user");
1530
1531 if (offer_answer_step(ss, generate_offer, "soa_generate_offer") < 0)
1532 return -1;
1533
1534 return soa_base_generate_offer(ss, NULL((void*)0));
1535}
1536
1537static int soa_static_generate_answer(soa_session_t *ss,
1538 soa_callback_f *completed)
1539{
1540 /* NOTE:
1541 * - local SDP might have changed
1542 * - remote SDP might have been updated
1543 */
1544
1545 if (offer_answer_step(ss, generate_answer, "soa_generate_answer") < 0)
1546 return -1;
1547
1548 return soa_base_generate_answer(ss, NULL((void*)0));
1549}
1550
1551static int soa_static_process_answer(soa_session_t *ss,
1552 soa_callback_f *completed)
1553{
1554 /* NOTE:
1555 * - both local and remote information is available
1556 * - local SDP might have changed
1557 * - remote SDP might have been updated
1558 */
1559 if (offer_answer_step(ss, process_answer, "soa_process_answer") < 0)
1560 return -1;
1561
1562 return soa_base_process_answer(ss, NULL((void*)0));
1563}
1564
1565/** Process rejected offer */
1566static int soa_static_process_reject(soa_session_t *ss,
1567 soa_callback_f *completed)
1568{
1569 soa_static_session_t *sss = (soa_static_session_t *)ss;
1570 struct soa_description d[1];
1571
1572 soa_base_process_reject(ss, NULL((void*)0));
1573
1574 *d = *ss->ss_local;
1575 *ss->ss_local = *ss->ss_previous;
1576 ss->ss_local_user_version = ss->ss_previous_user_version;
1577 ss->ss_local_remote_version = ss->ss_previous_remote_version;
1578
1579 memset(ss->ss_previous, 0, (sizeof *ss->ss_previous));
1580 soa_description_free(ss, d);
1581 su_free(ss->ss_home, sss->sss_previous.u2s), sss->sss_previous.u2s = NULL((void*)0);
1582 su_free(ss->ss_home, sss->sss_previous.s2u), sss->sss_previous.s2u = NULL((void*)0);
1583 ss->ss_previous_user_version = 0;
1584 ss->ss_previous_remote_version = 0;
1585
1586 su_free(ss->ss_home, sss->sss_latest), sss->sss_latest = NULL((void*)0);
1587
1588 return 0;
1589}
1590
1591static int soa_static_activate(soa_session_t *ss, char const *option)
1592{
1593 return soa_base_activate(ss, option);
1594}
1595
1596static int soa_static_deactivate(soa_session_t *ss, char const *option)
1597{
1598 return soa_base_deactivate(ss, option);
1599}
1600
1601static void soa_static_terminate(soa_session_t *ss, char const *option)
1602{
1603 soa_static_session_t *sss = (soa_static_session_t *)ss;
1604
1605 soa_description_free(ss, ss->ss_local);
1606 su_free(ss->ss_home, sss->sss_u2s), sss->sss_u2s = NULL((void*)0);
1607 su_free(ss->ss_home, sss->sss_s2u), sss->sss_s2u = NULL((void*)0);
1608
1609 soa_description_free(ss, ss->ss_previous);
1610 ss->ss_previous_user_version = 0;
1611 ss->ss_previous_remote_version = 0;
1612 su_free(ss->ss_home, sss->sss_previous.u2s), sss->sss_previous.u2s = NULL((void*)0);
1613 su_free(ss->ss_home, sss->sss_previous.s2u), sss->sss_previous.s2u = NULL((void*)0);
1614
1615 su_free(ss->ss_home, sss->sss_latest), sss->sss_latest = NULL((void*)0);
1616
1617 soa_base_terminate(ss, option);
1618}