File: | soa_static.c |
Warning: | line 329, column 15 Value stored to 'mT' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |
56 | struct 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 | |
75 | typedef 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 | } |
95 | soa_static_session_t; |
96 | |
97 | #define U2S_NOT_USED(-1) (-1) |
98 | #define U2S_SENTINEL(-2) (-2) |
99 | |
100 | static int soa_static_init(char const *, soa_session_t *, soa_session_t *); |
101 | static void soa_static_deinit(soa_session_t *); |
102 | static int soa_static_set_params(soa_session_t *ss, tagi_t const *tags); |
103 | static int soa_static_get_params(soa_session_t const *ss, tagi_t *tags); |
104 | static tagi_t *soa_static_get_paramlist(soa_session_t const *ss, |
105 | tag_type_t tag, tag_value_t value, |
106 | ...); |
107 | static int soa_static_set_capability_sdp(soa_session_t *ss, |
108 | sdp_session_t *sdp, |
109 | char const *, isize_t); |
110 | static int soa_static_set_remote_sdp(soa_session_t *ss, |
111 | int new_version, |
112 | sdp_session_t *sdp, |
113 | char const *, isize_t); |
114 | static int soa_static_set_user_sdp(soa_session_t *ss, |
115 | sdp_session_t *sdp, |
116 | char const *, isize_t); |
117 | static int soa_static_generate_offer(soa_session_t *ss, soa_callback_f *); |
118 | static int soa_static_generate_answer(soa_session_t *ss, soa_callback_f *); |
119 | static int soa_static_process_answer(soa_session_t *ss, soa_callback_f *); |
120 | static int soa_static_process_reject(soa_session_t *ss, soa_callback_f *); |
121 | |
122 | static int soa_static_activate(soa_session_t *ss, char const *option); |
123 | static int soa_static_deactivate(soa_session_t *ss, char const *option); |
124 | static void soa_static_terminate(soa_session_t *ss, char const *option); |
125 | |
126 | struct 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 */ |
153 | static 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 | |
160 | static void soa_static_deinit(soa_session_t *ss) |
161 | { |
162 | soa_base_deinit(ss); |
163 | } |
164 | |
165 | static 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 | |
198 | static 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 | |
216 | static 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 | |
241 | static 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 | |
250 | static 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 | |
260 | static 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 */ |
269 | static |
270 | sdp_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 | */ |
299 | static |
300 | sdp_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 */ |
346 | int 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 */ |
368 | static |
369 | int 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 | |
399 | static |
400 | sdp_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 | */ |
430 | static |
431 | int 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 | */ |
480 | static |
481 | int 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 | */ |
591 | static |
592 | int 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 | */ |
645 | static |
646 | int 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 */ |
681 | static |
682 | int 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 */ |
715 | static |
716 | int 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 */ |
734 | static |
735 | int 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 | |
936 | static |
937 | int *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. */ |
953 | static |
954 | int 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 */ |
985 | static |
986 | int 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 | */ |
1031 | static |
1032 | int 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 | |
1123 | enum 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 | */ |
1133 | static 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 | */ |
1525 | static 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 | |
1537 | static 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 | |
1551 | static 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 */ |
1566 | static 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 | |
1591 | static int soa_static_activate(soa_session_t *ss, char const *option) |
1592 | { |
1593 | return soa_base_activate(ss, option); |
1594 | } |
1595 | |
1596 | static int soa_static_deactivate(soa_session_t *ss, char const *option) |
1597 | { |
1598 | return soa_base_deactivate(ss, option); |
1599 | } |
1600 | |
1601 | static 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 | } |