Bug Summary

File:soa/soa.c
Warning:line 2108, column 12
Access to field 'ssd_sdp' results in a dereference of a null pointer (loaded from variable 'ssd')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name soa.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-eagerly-assume -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 -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/lib/llvm-7/lib/clang/7.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-7/lib/clang/7.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 -fmessage-length 0 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -o /drone/src/scan-build/2021-08-26-205203-363-1 -x c soa.c -faddrsig
1/*
2 * This file is part of the Sofia-SIP package
3 *
4 * Copyright (C) 2005 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.c
26 * @brief Sofia SDP Offer/Answer Engine interface
27 *
28 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
29 *
30 * @date Created: Wed Aug 3 20:27:15 EEST 2005
31 */
32
33#include "config.h"
34
35#include <stddef.h>
36#include <stdlib.h>
37#include <string.h>
38#include <errno(*__errno_location ()).h>
39
40#include <assert.h>
41
42#include <sofia-sip/su_tag_class.h>
43#include <sofia-sip/su_wait.h>
44
45#include "sofia-sip/soa.h"
46#include "sofia-sip/sdp.h"
47#include "sofia-sip/soa_session.h"
48#include "sofia-sip/soa_add.h"
49
50#include <sofia-sip/hostdomain.h>
51#include <sofia-sip/bnf.h>
52#include <sofia-sip/su_tagarg.h>
53#include <sofia-sip/su_localinfo.h>
54#include <sofia-sip/su_uniqueid.h>
55
56#include <sofia-sip/su_string.h>
57#include <sofia-sip/su_errno.h>
58
59#ifndef _MSC_VER
60#define NONE((void *)-1) ((void *)-1)
61#else
62#define NONE((void *)-1) ((void *)(INT_PTR)-1)
63#endif
64#define XXX((void) sizeof ((!"implemented") ? 1 : 0), __extension__ ({ if
(!"implemented") ; else __assert_fail ("!\"implemented\"", "soa.c"
, 64, __extension__ __PRETTY_FUNCTION__); }))
assert(!"implemented")((void) sizeof ((!"implemented") ? 1 : 0), __extension__ ({ if
(!"implemented") ; else __assert_fail ("!\"implemented\"", "soa.c"
, 64, __extension__ __PRETTY_FUNCTION__); }))
65
66typedef unsigned longlonglong long ull;
67
68#if HAVE_FUNC1
69#elif HAVE_FUNCTION1
70#define __func__ __FUNCTION__
71#else
72static char const __func__[] = "soa";
73#endif
74
75/* ======================================================================== */
76
77/* Internal prototypes */
78enum soa_sdp_kind {
79 soa_capability_sdp_kind,
80 soa_user_sdp_kind,
81 soa_remote_sdp_kind
82};
83
84static int soa_set_sdp(soa_session_t *ss,
85 enum soa_sdp_kind what,
86 sdp_session_t const *sdp0,
87 char const *sdp_str, issize_t str_len);
88
89/* ======================================================================== */
90
91#define SOA_VALID_ACTIONS(a)((a)->sizeof_soa_session_actions >= (int)sizeof (*actions
) && (a)->sizeof_soa_session >= (int)sizeof(soa_session_t
) && (a)->soa_name != ((void*)0) && (a)->
soa_init != ((void*)0) && (a)->soa_deinit != ((void
*)0) && (a)->soa_set_params != ((void*)0) &&
(a)->soa_get_params != ((void*)0) && (a)->soa_get_paramlist
!= ((void*)0) && (a)->soa_media_features != ((void
*)0) && (a)->soa_sip_require != ((void*)0) &&
(a)->soa_sip_supported != ((void*)0) && (a)->soa_remote_sip_features
!= ((void*)0) && (a)->soa_set_capability_sdp != (
(void*)0) && (a)->soa_set_remote_sdp != ((void*)0)
&& (a)->soa_set_user_sdp != ((void*)0) &&
(a)->soa_generate_offer != ((void*)0) && (a)->
soa_generate_answer != ((void*)0) && (a)->soa_process_answer
!= ((void*)0) && (a)->soa_process_reject != ((void
*)0) && (a)->soa_activate_session != ((void*)0) &&
(a)->soa_deactivate_session != ((void*)0) && (a)->
soa_terminate_session != ((void*)0))
\
92 ((a)->sizeof_soa_session_actions >= (int)sizeof (*actions) && \
93 (a)->sizeof_soa_session >= (int)sizeof(soa_session_t) && \
94 (a)->soa_name != NULL((void*)0) && \
95 (a)->soa_init != NULL((void*)0) && \
96 (a)->soa_deinit != NULL((void*)0) && \
97 (a)->soa_set_params != NULL((void*)0) && \
98 (a)->soa_get_params != NULL((void*)0) && \
99 (a)->soa_get_paramlist != NULL((void*)0) && \
100 (a)->soa_media_features != NULL((void*)0) && \
101 (a)->soa_sip_require != NULL((void*)0) && \
102 (a)->soa_sip_supported != NULL((void*)0) && \
103 (a)->soa_remote_sip_features != NULL((void*)0) && \
104 (a)->soa_set_capability_sdp != NULL((void*)0) && \
105 (a)->soa_set_remote_sdp != NULL((void*)0) && \
106 (a)->soa_set_user_sdp != NULL((void*)0) && \
107 (a)->soa_generate_offer != NULL((void*)0) && \
108 (a)->soa_generate_answer != NULL((void*)0) && \
109 (a)->soa_process_answer != NULL((void*)0) && \
110 (a)->soa_process_reject != NULL((void*)0) && \
111 (a)->soa_activate_session != NULL((void*)0) && \
112 (a)->soa_deactivate_session != NULL((void*)0) && \
113 (a)->soa_terminate_session != NULL((void*)0))
114
115/* ======================================================================== */
116
117/**@var SOA_DEBUG
118 *
119 * Environment variable determining the default debug log level.
120 *
121 * The SOA_DEBUG environment variable is used to determine the default
122 * debug logging level. The normal level is 3.
123 *
124 * @sa <sofia-sip/su_debug.h>, su_log_global, SOFIA_DEBUG
125 */
126extern char const SOA_DEBUG[];
127
128#ifndef SU_DEBUG0
129#define SU_DEBUG0 3
130#endif
131
132/**Debug log for @b soa module.
133 *
134 * The soa_log is the log object used by @b soa module. The level of
135 * #soa_log is set using #SOA_DEBUG environment variable.
136 */
137su_log_t soa_log[] = { SU_LOG_INIT("soa", "SOA_DEBUG", SU_DEBUG){ sizeof(su_log_t), "soa", "SOA_DEBUG", 0, SU_LOG_MAX, 0, ((void
*)0), ((void*)0), }
};
138
139/* Add " around string */
140#define NICE(s)s ? "\"" : "", s ? s : "(nil)", s ? "\"" : "" s ? "\"" : "", s ? s : "(nil)", s ? "\"" : ""
141
142/* ======================================================================== */
143
144/* API Functions */
145
146struct soa_namenode
147{
148 struct soa_namenode const *next;
149 char const *basename;
150 struct soa_session_actions const *actions;
151};
152
153#define SOA_NAMELISTLEN(16) (16)
154
155static struct soa_namenode const soa_default_node =
156 {
157 NULL((void*)0), "default", &soa_default_actions
158 };
159
160static struct soa_namenode const *soa_namelist = &soa_default_node;
161
162/** Add a named soa backend */
163int soa_add(char const *name,
164 struct soa_session_actions const *actions)
165{
166 struct soa_namenode const *n;
167 struct soa_namenode *e;
168
169 SU_DEBUG_9(("soa_add(%s%s%s, %p) called\n", NICE(name), (void *)actions))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 169, "soa_add(%s%s%s, %p) called\n", name ? "\"" : "", name
? name : "(nil)", name ? "\"" : "", (void *)actions)) : (void
)0)
;
170
171 if (name == NULL((void*)0) || actions == NULL((void*)0))
172 return su_seterrno(EFAULT14);
173
174 if (!SOA_VALID_ACTIONS(actions)((actions)->sizeof_soa_session_actions >= (int)sizeof (
*actions) && (actions)->sizeof_soa_session >= (
int)sizeof(soa_session_t) && (actions)->soa_name !=
((void*)0) && (actions)->soa_init != ((void*)0) &&
(actions)->soa_deinit != ((void*)0) && (actions)->
soa_set_params != ((void*)0) && (actions)->soa_get_params
!= ((void*)0) && (actions)->soa_get_paramlist != (
(void*)0) && (actions)->soa_media_features != ((void
*)0) && (actions)->soa_sip_require != ((void*)0) &&
(actions)->soa_sip_supported != ((void*)0) && (actions
)->soa_remote_sip_features != ((void*)0) && (actions
)->soa_set_capability_sdp != ((void*)0) && (actions
)->soa_set_remote_sdp != ((void*)0) && (actions)->
soa_set_user_sdp != ((void*)0) && (actions)->soa_generate_offer
!= ((void*)0) && (actions)->soa_generate_answer !=
((void*)0) && (actions)->soa_process_answer != ((
void*)0) && (actions)->soa_process_reject != ((void
*)0) && (actions)->soa_activate_session != ((void*
)0) && (actions)->soa_deactivate_session != ((void
*)0) && (actions)->soa_terminate_session != ((void
*)0))
)
175 return su_seterrno(EINVAL22);
176
177 for (n = soa_namelist; n; n = n->next) {
178 if (su_casematch(name, n->basename))
179 return 0;
180 }
181
182 e = malloc(sizeof *e); if (!e) return -1;
183
184 e->next = soa_namelist;
185 e->basename = name;
186 e->actions = actions;
187
188 soa_namelist = e;
189
190 return 0;
191}
192
193/** Search for a named backend */
194struct soa_session_actions const *soa_find(char const *name)
195{
196 SU_DEBUG_9(("soa_find(%s%s%s) called\n", NICE(name)))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 196, "soa_find(%s%s%s) called\n", name ? "\"" : "", name ? name
: "(nil)", name ? "\"" : "")) : (void)0)
;
197
198 if (name) {
199 struct soa_namenode const *n;
200 size_t baselen = strcspn(name, ":/");
201
202 for (n = soa_namelist; n; n = n->next) {
203 if (su_casenmatch(name, n->basename, baselen))
204 break;
205 }
206
207 if (n == NULL((void*)0))
208 return (void)su_seterrno(ENOENT2), NULL((void*)0);
209
210 return n->actions;
211 }
212
213 return NULL((void*)0);
214}
215
216/* ======================================================================== */
217
218/** Create a soa session. */
219soa_session_t *soa_create(char const *name,
220 su_root_t *root,
221 soa_magic_t *magic)
222{
223 struct soa_session_actions const *actions = &soa_default_actions;
224
225 soa_session_t *ss;
226 size_t namelen;
227
228 SU_DEBUG_9(("soa_create(\"%s\", %p, %p) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 229, "soa_create(\"%s\", %p, %p) called\n", name ? name : "default"
, (void *)root, (void *)magic)) : (void)0)
229 name ? name : "default", (void *)root, (void *)magic))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 229, "soa_create(\"%s\", %p, %p) called\n", name ? name : "default"
, (void *)root, (void *)magic)) : (void)0)
;
230
231 if (name && name[0]) {
232 struct soa_namenode const *n;
233 size_t baselen = strcspn(name, ":/");
234
235 for (n = soa_namelist; n; n = n->next) {
236 if (su_casenmatch(name, n->basename, baselen))
237 break;
238 }
239 if (n == NULL((void*)0))
240 return (void)su_seterrno(ENOENT2), NULL((void*)0);
241
242 actions = n->actions; assert(actions)((void) sizeof ((actions) ? 1 : 0), __extension__ ({ if (actions
) ; else __assert_fail ("actions", "soa.c", 242, __extension__
__PRETTY_FUNCTION__); }))
;
243 }
244 else
245 name = "default";
246
247 assert(SOA_VALID_ACTIONS(actions))((void) sizeof ((((actions)->sizeof_soa_session_actions >=
(int)sizeof (*actions) && (actions)->sizeof_soa_session
>= (int)sizeof(soa_session_t) && (actions)->soa_name
!= ((void*)0) && (actions)->soa_init != ((void*)0
) && (actions)->soa_deinit != ((void*)0) &&
(actions)->soa_set_params != ((void*)0) && (actions
)->soa_get_params != ((void*)0) && (actions)->soa_get_paramlist
!= ((void*)0) && (actions)->soa_media_features !=
((void*)0) && (actions)->soa_sip_require != ((void
*)0) && (actions)->soa_sip_supported != ((void*)0)
&& (actions)->soa_remote_sip_features != ((void*)
0) && (actions)->soa_set_capability_sdp != ((void*
)0) && (actions)->soa_set_remote_sdp != ((void*)0)
&& (actions)->soa_set_user_sdp != ((void*)0) &&
(actions)->soa_generate_offer != ((void*)0) && (actions
)->soa_generate_answer != ((void*)0) && (actions)->
soa_process_answer != ((void*)0) && (actions)->soa_process_reject
!= ((void*)0) && (actions)->soa_activate_session !=
((void*)0) && (actions)->soa_deactivate_session !=
((void*)0) && (actions)->soa_terminate_session !=
((void*)0))) ? 1 : 0), __extension__ ({ if (((actions)->sizeof_soa_session_actions
>= (int)sizeof (*actions) && (actions)->sizeof_soa_session
>= (int)sizeof(soa_session_t) && (actions)->soa_name
!= ((void*)0) && (actions)->soa_init != ((void*)0
) && (actions)->soa_deinit != ((void*)0) &&
(actions)->soa_set_params != ((void*)0) && (actions
)->soa_get_params != ((void*)0) && (actions)->soa_get_paramlist
!= ((void*)0) && (actions)->soa_media_features !=
((void*)0) && (actions)->soa_sip_require != ((void
*)0) && (actions)->soa_sip_supported != ((void*)0)
&& (actions)->soa_remote_sip_features != ((void*)
0) && (actions)->soa_set_capability_sdp != ((void*
)0) && (actions)->soa_set_remote_sdp != ((void*)0)
&& (actions)->soa_set_user_sdp != ((void*)0) &&
(actions)->soa_generate_offer != ((void*)0) && (actions
)->soa_generate_answer != ((void*)0) && (actions)->
soa_process_answer != ((void*)0) && (actions)->soa_process_reject
!= ((void*)0) && (actions)->soa_activate_session !=
((void*)0) && (actions)->soa_deactivate_session !=
((void*)0) && (actions)->soa_terminate_session !=
((void*)0))) ; else __assert_fail ("SOA_VALID_ACTIONS(actions)"
, "soa.c", 247, __extension__ __PRETTY_FUNCTION__); }))
;
248
249 if (root == NULL((void*)0))
250 return (void)su_seterrno(EFAULT14), NULL((void*)0);
251
252 namelen = strlen(name) + 1;
253
254 ss = su_home_new(actions->sizeof_soa_session + namelen);
255 if (ss) {
256 ss->ss_root = root;
257 ss->ss_magic = magic;
258 ss->ss_actions = actions;
259 ss->ss_name = strcpy((char *)ss + actions->sizeof_soa_session, name);
260
261 /* Calls soa_static_init by default */
262 if (ss->ss_actions->soa_init(name, ss, NULL((void*)0)) < 0)
263 /* Calls soa_static_deinit by default */
264 ss->ss_actions->soa_deinit(ss), ss = NULL((void*)0);
265 }
266
267 return ss;
268}
269
270/** Create a copy of a @soa session object. */
271soa_session_t *soa_clone(soa_session_t *parent_ss,
272 su_root_t *root,
273 soa_magic_t *magic)
274{
275 soa_session_t *ss;
276 size_t namelen;
277
278 SU_DEBUG_9(("soa_clone(%s::%p, %p, %p) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 280, "soa_clone(%s::%p, %p, %p) called\n", parent_ss ? parent_ss
->ss_actions->soa_name : "", (void *)parent_ss, (void *
)root, (void *)magic)) : (void)0)
279 parent_ss ? parent_ss->ss_actions->soa_name : "",(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 280, "soa_clone(%s::%p, %p, %p) called\n", parent_ss ? parent_ss
->ss_actions->soa_name : "", (void *)parent_ss, (void *
)root, (void *)magic)) : (void)0)
280 (void *)parent_ss, (void *)root, (void *)magic))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 280, "soa_clone(%s::%p, %p, %p) called\n", parent_ss ? parent_ss
->ss_actions->soa_name : "", (void *)parent_ss, (void *
)root, (void *)magic)) : (void)0)
;
281
282 if (parent_ss == NULL((void*)0) || root == NULL((void*)0))
283 return (void)su_seterrno(EFAULT14), NULL((void*)0);
284
285 namelen = strlen(parent_ss->ss_name) + 1;
286
287 ss = su_home_new(parent_ss->ss_actions->sizeof_soa_session + namelen);
288 if (ss) {
289 ss->ss_root = root;
290 ss->ss_magic = magic;
291 ss->ss_actions = parent_ss->ss_actions;
292 ss->ss_name = strcpy((char *)ss + ss->ss_actions->sizeof_soa_session,
293 parent_ss->ss_name);
294
295 /* Calls soa_static_init by default */
296 if (ss->ss_actions->soa_init(NULL((void*)0), ss, parent_ss) < 0)
297 /* Calls soa_static_deinit by default */
298 ss->ss_actions->soa_deinit(ss), ss = NULL((void*)0);
299 }
300
301 return ss;
302}
303
304/** Increase reference count */
305soa_session_t *soa_session_ref(soa_session_t *ss)
306{
307 SU_DEBUG_9(("soa_session_ref(%s::%p) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 308, "soa_session_ref(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
308 ss ? ss->ss_actions->soa_name : "", (void *)ss))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 308, "soa_session_ref(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
;
309 return su_home_ref(ss->ss_home);
310}
311
312/** Decrease reference count */
313void soa_session_unref(soa_session_t *ss)
314{
315 SU_DEBUG_9(("soa_session_unref(%s::%p) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 316, "soa_session_unref(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
316 ss ? ss->ss_actions->soa_name : "", (void *)ss))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 316, "soa_session_unref(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
;
317 su_home_unref(ss->ss_home);
318}
319
320/* Initialize session */
321int soa_base_init(char const *name,
322 soa_session_t *ss,
323 soa_session_t *parent)
324{
325 if (parent) {
326#define DUP(d, dup, s)if ((s) && !((d) = dup(ss->ss_home, (s)))) return -
1
if ((s) && !((d) = dup(ss->ss_home, (s)))) return -1
327 su_home_t *home = ss->ss_home;
328
329 if (soa_description_dup(home, ss->ss_caps, parent->ss_caps) < 0)
330 return -1;
331 if (soa_description_dup(home, ss->ss_user, parent->ss_user) < 0)
332 return -1;
333 if (soa_description_dup(home, ss->ss_local, parent->ss_local) < 0)
334 return -1;
335 if (soa_description_dup(home, ss->ss_remote, parent->ss_remote) < 0)
336 return -1;
337
338 DUP(ss->ss_address, su_strdup, parent->ss_address)if ((parent->ss_address) && !((ss->ss_address) =
su_strdup(ss->ss_home, (parent->ss_address)))) return -
1
;
339 ss->ss_af = parent->ss_af;
340 DUP(ss->ss_hold, su_strdup, parent->ss_hold)if ((parent->ss_hold) && !((ss->ss_hold) = su_strdup
(ss->ss_home, (parent->ss_hold)))) return -1
;
341
342 DUP(ss->ss_cname, su_strdup, parent->ss_cname)if ((parent->ss_cname) && !((ss->ss_cname) = su_strdup
(ss->ss_home, (parent->ss_cname)))) return -1
;
343
344 ss->ss_srtp_enable = parent->ss_srtp_enable;
345 ss->ss_srtp_confidentiality = parent->ss_srtp_confidentiality;
346 ss->ss_srtp_integrity = parent->ss_srtp_integrity;
347 }
348
349 return 0;
350}
351
352/** Destroy a session. */
353void soa_destroy(soa_session_t *ss)
354{
355 SU_DEBUG_9(("soa_destroy(%s::%p) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 356, "soa_destroy(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
356 ss ? ss->ss_actions->soa_name : "", (void *)ss))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 356, "soa_destroy(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
;
357
358 if (ss) {
359 ss->ss_active = 0;
360 ss->ss_terminated++;
361 /* Calls soa_static_deinit() by default. */
362 ss->ss_actions->soa_deinit(ss);
363 su_home_unref(ss->ss_home);
364 }
365}
366
367void soa_base_deinit(soa_session_t *ss)
368{
369 (void)ss;
370}
371
372/** Set parameters.
373 *
374 * @param ss soa session object
375 * @param tag, value, ... tagged parameter list
376 *
377 * @return Number of parameters set, or -1 upon an error.
378 *
379 * @TAGS
380 * SOATAG_CAPS_SDP(),
381 * SOATAG_CAPS_SDP_STR(),
382 * SOATAG_USER_SDP(),
383 * SOATAG_USER_SDP_STR(),
384 * SOATAG_REMOTE_SDP(),
385 * SOATAG_REMOTE_SDP_STR(),
386 * SOATAG_AF(),
387 * SOATAG_ADDRESS(),
388 * SOATAG_AUDIO_AUX() (currently for "default" only),
389 * SOATAG_HOLD(),
390 * SOATAG_RTP_SELECT(),
391 * SOATAG_RTP_SORT(),
392 * SOATAG_RTP_MISMATCH(),
393 * SOATAG_SRTP_ENABLE(),
394 * SOATAG_SRTP_CONFIDENTIALITY(), and
395 * SOATAG_SRTP_INTEGRITY().
396 */
397int soa_set_params(soa_session_t *ss, tag_type_t tag, tag_value_t value, ...)
398{
399 ta_list ta;
400 int n;
401
402 SU_DEBUG_9(("soa_set_params(%s::%p, ...) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 403, "soa_set_params(%s::%p, ...) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
403 ss ? ss->ss_actions->soa_name : "", (void *)ss))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 403, "soa_set_params(%s::%p, ...) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
;
404
405 if (ss == NULL((void*)0))
406 return su_seterrno(EFAULT14), -1;
407
408 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)
;
409
410 /* Calls soa_static_set_params() by default. */
411 n = ss->ss_actions->soa_set_params(ss, ta_args(ta)(ta).tl);
412
413 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))
;
414
415 return n;
416}
417
418/**Base method for setting parameters.
419 *
420 * @param ss soa session object
421 * @param tags tag item list
422 *
423 * @return Number of parameters set, or -1 upon an error.
424 *
425 * @TAGS
426 * SOATAG_CAPS_SDP(),
427 * SOATAG_CAPS_SDP_STR(),
428 * SOATAG_USER_SDP(),
429 * SOATAG_USER_SDP_STR(),
430 * SOATAG_REMOTE_SDP(),
431 * SOATAG_REMOTE_SDP_STR(),
432 * SOATAG_AF(),
433 * SOATAG_ADDRESS(),
434 * SOATAG_HOLD(),
435 * SOATAG_RTP_SELECT(),
436 * SOATAG_RTP_SORT(),
437 * SOATAG_RTP_MISMATCH(),
438 * SOATAG_SRTP_ENABLE(),
439 * SOATAG_SRTP_CONFIDENTIALITY(), and
440 * SOATAG_SRTP_INTEGRITY().
441 */
442int soa_base_set_params(soa_session_t *ss, tagi_t const *tags)
443{
444 int n, change_session = 0;
445
446 sdp_session_t const *caps_sdp, *user_sdp;
447 char const *caps_sdp_str, *user_sdp_str;
448
449 int af;
450 char const *media_address, *hold;
451 int rtp_select, rtp_sort;
452 int rtp_mismatch;
453 int srtp_enable, srtp_confidentiality, srtp_integrity;
454
455 af = ss->ss_af;
456
457 hold = ss->ss_hold;
458 media_address = ss->ss_address;
459
460 rtp_select = (int)ss->ss_rtp_select;
461 rtp_sort = (int)ss->ss_rtp_sort;
462 rtp_mismatch = ss->ss_rtp_mismatch;
463
464 srtp_enable = ss->ss_srtp_enable;
465 srtp_confidentiality = ss->ss_srtp_confidentiality;
466 srtp_integrity = ss->ss_srtp_integrity;
467
468 caps_sdp = user_sdp = NONE((void *)-1);
469 caps_sdp_str = user_sdp_str = NONE((void *)-1);
470
471 n = tl_gets(tags,
472
473 SOATAG_CAPS_SDP_REF(caps_sdp)soatag_caps_sdp_ref, sdptag_session_vr(&(caps_sdp)),
474 SOATAG_CAPS_SDP_STR_REF(caps_sdp_str)soatag_caps_sdp_str_ref, tag_str_vr(&(caps_sdp_str)),
475
476 SOATAG_USER_SDP_REF(user_sdp)soatag_user_sdp_ref, sdptag_session_vr(&(user_sdp)),
477 SOATAG_USER_SDP_STR_REF(user_sdp_str)soatag_user_sdp_str_ref, tag_str_vr(&(user_sdp_str)),
478
479 SOATAG_AF_REF(af)soatag_af_ref, tag_int_vr(&(af)),
480 SOATAG_ADDRESS_REF(media_address)soatag_address_ref, tag_str_vr(&(media_address)),
481 SOATAG_HOLD_REF(hold)soatag_hold_ref, tag_str_vr(&(hold)),
482
483 SOATAG_RTP_SELECT_REF(rtp_select)soatag_rtp_select_ref, tag_int_vr(&(rtp_select)),
484 SOATAG_RTP_SORT_REF(rtp_sort)soatag_rtp_sort_ref, tag_int_vr(&(rtp_sort)),
485 SOATAG_RTP_MISMATCH_REF(rtp_mismatch)soatag_rtp_mismatch_ref, tag_bool_vr(&(rtp_mismatch)),
486
487 SOATAG_SRTP_ENABLE_REF(srtp_enable)soatag_srtp_enable_ref, tag_bool_vr(&(srtp_enable)),
488 SOATAG_SRTP_CONFIDENTIALITY_REF(srtp_confidentiality)soatag_srtp_confidentiality_ref, tag_bool_vr(&(srtp_confidentiality
))
,
489 SOATAG_SRTP_INTEGRITY_REF(srtp_integrity)soatag_srtp_integrity_ref, tag_bool_vr(&(srtp_integrity)),
490
491 TAG_END()(tag_type_t)0, (tag_value_t)0);
492
493 if (n <= 0)
494 return n;
495
496 if (caps_sdp != NONE((void *)-1) || caps_sdp_str != NONE((void *)-1)) {
497 if (caps_sdp == NONE((void *)-1)) caps_sdp = NULL((void*)0);
498 if (caps_sdp_str == NONE((void *)-1)) caps_sdp_str = NULL((void*)0);
499
500 if (caps_sdp || caps_sdp_str) {
501 if (soa_set_capability_sdp(ss, caps_sdp, caps_sdp_str, -1) < 0) {
502 return -1;
503 }
504 }
505 else {
506 soa_description_free(ss, ss->ss_caps);
507 }
508 }
509
510 if (user_sdp != NONE((void *)-1) || user_sdp_str != NONE((void *)-1)) {
511 if (user_sdp == NONE((void *)-1)) user_sdp = NULL((void*)0);
512 if (user_sdp_str == NONE((void *)-1)) user_sdp_str = NULL((void*)0);
513
514 if (user_sdp || user_sdp_str) {
515 if (soa_set_user_sdp(ss, user_sdp, user_sdp_str, -1) < 0) {
516 return -1;
517 }
518 if (ss->ss_caps->ssd_str == NULL((void*)0))
519 soa_set_capability_sdp(ss, user_sdp, user_sdp_str, -1);
520 }
521 else {
522 soa_description_free(ss, ss->ss_user);
523 }
524 }
525
526 if (af < SOA_AF_ANYSOA_AF_ANY || af > SOA_AF_IP6_IP4SOA_AF_IP6_IP4)
527 af = ss->ss_af;
528
529 if (rtp_select < SOA_RTP_SELECT_SINGLE || rtp_select > SOA_RTP_SELECT_ALL)
530 rtp_select = (int)ss->ss_rtp_select;
531 if (rtp_sort < SOA_RTP_SORT_DEFAULT || rtp_sort > SOA_RTP_SORT_REMOTE)
532 rtp_sort = (int)ss->ss_rtp_sort;
533 rtp_mismatch = rtp_mismatch != 0;
534
535 srtp_enable = srtp_enable != 0;
536 srtp_confidentiality = srtp_confidentiality != 0;
537 srtp_integrity = srtp_integrity != 0;
538
539 change_session
540 = af != (int)ss->ss_af
541 || rtp_select != (int)ss->ss_rtp_select
542 || rtp_sort != (int)ss->ss_rtp_sort
543 || rtp_mismatch != (int)ss->ss_rtp_mismatch
544 || srtp_enable != (int)ss->ss_srtp_enable
545 || srtp_confidentiality != (int)ss->ss_srtp_confidentiality
546 || srtp_integrity != (int)ss->ss_srtp_integrity
547 ;
548
549 ss->ss_af = (enum soa_af)af;
550
551 ss->ss_rtp_select = rtp_select;
552 ss->ss_rtp_sort = rtp_sort;
553 ss->ss_rtp_mismatch = rtp_mismatch;
554
555 ss->ss_srtp_enable = srtp_enable;
556 ss->ss_srtp_confidentiality = srtp_confidentiality;
557 ss->ss_srtp_integrity = srtp_integrity;
558
559 if (!su_casematch(media_address, ss->ss_address)) {
560 char const *addr = ss->ss_address;
561 ss->ss_address = su_strdup(ss->ss_home, media_address);
562 su_free(ss->ss_home, (void *)addr);
563 change_session = 1;
564 }
565
566 if (hold == (char const *)1)
567 hold = "*";
568
569 if (!su_casematch(hold, ss->ss_hold)) {
570 char const *h = ss->ss_hold;
571 ss->ss_hold = su_strdup(ss->ss_home, hold);
572 su_free(ss->ss_home, (void *)h);
573 change_session = 1;
574 }
575
576 if (change_session)
577 ss->ss_user_version++;
578
579 return n;
580}
581
582/** Get tagged parameters.
583 *
584 * @param ss soa session object
585 * @param tag, value, ... tagged parameter list
586 *
587 * @return Number of parameters get, or -1 upon an error.
588 *
589 * @TAGS
590 * SOATAG_CAPS_SDP(),
591 * SOATAG_CAPS_SDP_STR(),
592 * SOATAG_USER_SDP(),
593 * SOATAG_USER_SDP_STR(),
594 * SOATAG_LOCAL_SDP(),
595 * SOATAG_LOCAL_SDP_STR(),
596 * SOATAG_REMOTE_SDP(),
597 * SOATAG_REMOTE_SDP_STR(),
598 * SOATAG_AF(),
599 * SOATAG_ADDRESS(),
600 * SOATAG_AUDIO_AUX() (currently for "default" only),
601 * SOATAG_HOLD(),
602 * SOATAG_RTP_SELECT(),
603 * SOATAG_RTP_SORT(),
604 * SOATAG_RTP_MISMATCH(),
605 * SOATAG_SRTP_ENABLE(),
606 * SOATAG_SRTP_CONFIDENTIALITY(), and
607 * SOATAG_SRTP_INTEGRITY().
608 */
609int soa_get_params(soa_session_t const *ss,
610 tag_type_t tag, tag_value_t value, ...)
611{
612 ta_list ta;
613 int n;
614
615 SU_DEBUG_9(("soa_get_params(%s::%p, ...) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 616, "soa_get_params(%s::%p, ...) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
616 ss ? ss->ss_actions->soa_name : "", (void *)ss))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 616, "soa_get_params(%s::%p, ...) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
;
617
618 if (ss == NULL((void*)0))
619 return su_seterrno(EFAULT14), -1;
620
621 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)
;
622
623 /* Calls soa_static_get_params() by default. */
624 n = ss->ss_actions->soa_get_params(ss, ta_args(ta)(ta).tl);
625
626 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))
;
627
628 return n;
629}
630
631/**Base method for getting tagged parameters.
632 *
633 * @param ss soa session object
634 * @param tags tag item list
635 *
636 * @return Number of parameters get, or -1 upon an error.
637 *
638 * @TAGS
639 * SOATAG_CAPS_SDP(),
640 * SOATAG_CAPS_SDP_STR(),
641 * SOATAG_USER_SDP(),
642 * SOATAG_USER_SDP_STR(),
643 * SOATAG_LOCAL_SDP(),
644 * SOATAG_LOCAL_SDP_STR(),
645 * SOATAG_REMOTE_SDP(),
646 * SOATAG_REMOTE_SDP_STR(),
647 * SOATAG_AF(),
648 * SOATAG_ADDRESS(),
649 * SOATAG_HOLD(),
650 * SOATAG_RTP_SELECT(),
651 * SOATAG_RTP_SORT(),
652 * SOATAG_RTP_MISMATCH(),
653 * SOATAG_SRTP_ENABLE(),
654 * SOATAG_SRTP_CONFIDENTIALITY(), and
655 * SOATAG_SRTP_INTEGRITY().
656 */
657int soa_base_get_params(soa_session_t const *ss, tagi_t *tags)
658{
659 int n;
660
661 n = tl_tgets(tags,
662 SOATAG_CAPS_SDP(ss->ss_caps->ssd_sdp)soatag_caps_sdp, sdptag_session_v(ss->ss_caps->ssd_sdp),
663 SOATAG_CAPS_SDP_STR(ss->ss_caps->ssd_str)soatag_caps_sdp_str, tag_str_v(ss->ss_caps->ssd_str),
664
665 SOATAG_USER_SDP(ss->ss_user->ssd_sdp)soatag_user_sdp, sdptag_session_v(ss->ss_user->ssd_sdp),
666 SOATAG_USER_SDP_STR(ss->ss_user->ssd_str)soatag_user_sdp_str, tag_str_v(ss->ss_user->ssd_str),
667
668 SOATAG_LOCAL_SDP(ss->ss_local->ssd_sdp)soatag_local_sdp, sdptag_session_v(ss->ss_local->ssd_sdp
)
,
669 SOATAG_LOCAL_SDP_STR(ss->ss_local->ssd_str)soatag_local_sdp_str, tag_str_v(ss->ss_local->ssd_str),
670
671 SOATAG_REMOTE_SDP(ss->ss_remote->ssd_sdp)soatag_remote_sdp, sdptag_session_v(ss->ss_remote->ssd_sdp
)
,
672 SOATAG_REMOTE_SDP_STR(ss->ss_remote->ssd_unparsed)soatag_remote_sdp_str, tag_str_v(ss->ss_remote->ssd_unparsed
)
,
673
674 SOATAG_AF(ss->ss_af)soatag_af, tag_int_v((ss->ss_af)),
675 SOATAG_ADDRESS(ss->ss_address)soatag_address, tag_str_v(ss->ss_address),
676 SOATAG_HOLD(ss->ss_hold)soatag_hold, tag_str_v(ss->ss_hold),
677
678 SOATAG_RTP_SELECT((int)ss->ss_rtp_select)soatag_rtp_select, tag_int_v((int)ss->ss_rtp_select),
679 SOATAG_RTP_SORT((int)ss->ss_rtp_sort)soatag_rtp_sort, tag_int_v((int)ss->ss_rtp_sort),
680 SOATAG_RTP_MISMATCH(ss->ss_rtp_mismatch)soatag_rtp_mismatch, tag_bool_v(ss->ss_rtp_mismatch),
681
682 SOATAG_SRTP_ENABLE(ss->ss_srtp_enable)soatag_srtp_enable, tag_bool_v(ss->ss_srtp_enable),
683 SOATAG_SRTP_CONFIDENTIALITY(ss->ss_srtp_confidentiality)soatag_srtp_confidentiality, tag_bool_v(ss->ss_srtp_confidentiality
)
,
684 SOATAG_SRTP_INTEGRITY(ss->ss_srtp_integrity)soatag_srtp_integrity, tag_bool_v(ss->ss_srtp_integrity),
685
686 TAG_END()(tag_type_t)0, (tag_value_t)0);
687
688 return n;
689}
690
691/** Return a list of parameters. */
692tagi_t *soa_get_paramlist(soa_session_t const *ss,
693 tag_type_t tag, tag_value_t value, ...)
694{
695 ta_list ta;
696 tagi_t *params = NULL((void*)0);
697
698 SU_DEBUG_9(("soa_get_paramlist(%s::%p, ...) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 699, "soa_get_paramlist(%s::%p, ...) called\n", ss ? ss->
ss_actions->soa_name : "", (void *)ss)) : (void)0)
699 ss ? ss->ss_actions->soa_name : "", (void *)ss))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 699, "soa_get_paramlist(%s::%p, ...) called\n", ss ? ss->
ss_actions->soa_name : "", (void *)ss)) : (void)0)
;
700
701 if (ss) {
702 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)
;
703 /* Calls soa_static_get_paramlist() by default. */
704 params = ss->ss_actions->soa_get_paramlist(ss, ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
705 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))
;
706 }
707
708 return params;
709}
710
711
712/** Base bethod for getting list of parameters. */
713tagi_t *soa_base_get_paramlist(soa_session_t const *ss,
714 tag_type_t tag, tag_value_t value,
715 ...)
716{
717 ta_list ta;
718 tagi_t *params;
719
720 if (ss == NULL((void*)0))
721 return NULL((void*)0);
722
723 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)
;
724
725 params = tl_llist(
726 TAG_IF(ss->ss_caps->ssd_sdp,!(ss->ss_caps->ssd_sdp) ? tag_skip : soatag_caps_sdp, sdptag_session_v
(ss->ss_caps->ssd_sdp)
727 SOATAG_CAPS_SDP(ss->ss_caps->ssd_sdp))!(ss->ss_caps->ssd_sdp) ? tag_skip : soatag_caps_sdp, sdptag_session_v
(ss->ss_caps->ssd_sdp)
,
728 TAG_IF(ss->ss_caps->ssd_str,!(ss->ss_caps->ssd_str) ? tag_skip : soatag_caps_sdp_str
, tag_str_v(ss->ss_caps->ssd_str)
729 SOATAG_CAPS_SDP_STR(ss->ss_caps->ssd_str))!(ss->ss_caps->ssd_str) ? tag_skip : soatag_caps_sdp_str
, tag_str_v(ss->ss_caps->ssd_str)
,
730
731 TAG_IF(ss->ss_user->ssd_sdp,!(ss->ss_user->ssd_sdp) ? tag_skip : soatag_user_sdp, sdptag_session_v
(ss->ss_user->ssd_sdp)
732 SOATAG_USER_SDP(ss->ss_user->ssd_sdp))!(ss->ss_user->ssd_sdp) ? tag_skip : soatag_user_sdp, sdptag_session_v
(ss->ss_user->ssd_sdp)
,
733 TAG_IF(ss->ss_user->ssd_str,!(ss->ss_user->ssd_str) ? tag_skip : soatag_user_sdp_str
, tag_str_v(ss->ss_user->ssd_str)
734 SOATAG_USER_SDP_STR(ss->ss_user->ssd_str))!(ss->ss_user->ssd_str) ? tag_skip : soatag_user_sdp_str
, tag_str_v(ss->ss_user->ssd_str)
,
735
736 TAG_IF(ss->ss_local->ssd_sdp,!(ss->ss_local->ssd_sdp) ? tag_skip : soatag_local_sdp,
sdptag_session_v(ss->ss_local->ssd_sdp)
737 SOATAG_LOCAL_SDP(ss->ss_local->ssd_sdp))!(ss->ss_local->ssd_sdp) ? tag_skip : soatag_local_sdp,
sdptag_session_v(ss->ss_local->ssd_sdp)
,
738 TAG_IF(ss->ss_user->ssd_str,!(ss->ss_user->ssd_str) ? tag_skip : soatag_local_sdp_str
, tag_str_v(ss->ss_local->ssd_str)
739 SOATAG_LOCAL_SDP_STR(ss->ss_local->ssd_str))!(ss->ss_user->ssd_str) ? tag_skip : soatag_local_sdp_str
, tag_str_v(ss->ss_local->ssd_str)
,
740
741 TAG_IF(ss->ss_remote->ssd_sdp,!(ss->ss_remote->ssd_sdp) ? tag_skip : soatag_remote_sdp
, sdptag_session_v(ss->ss_remote->ssd_sdp)
742 SOATAG_REMOTE_SDP(ss->ss_remote->ssd_sdp))!(ss->ss_remote->ssd_sdp) ? tag_skip : soatag_remote_sdp
, sdptag_session_v(ss->ss_remote->ssd_sdp)
,
743 TAG_IF(ss->ss_remote->ssd_str,!(ss->ss_remote->ssd_str) ? tag_skip : soatag_remote_sdp_str
, tag_str_v(ss->ss_remote->ssd_unparsed)
744 SOATAG_REMOTE_SDP_STR(ss->ss_remote->ssd_unparsed))!(ss->ss_remote->ssd_str) ? tag_skip : soatag_remote_sdp_str
, tag_str_v(ss->ss_remote->ssd_unparsed)
,
745
746 SOATAG_AF(ss->ss_af)soatag_af, tag_int_v((ss->ss_af)),
747 TAG_IF(ss->ss_address,!(ss->ss_address) ? tag_skip : soatag_address, tag_str_v(ss
->ss_address)
748 SOATAG_ADDRESS(ss->ss_address))!(ss->ss_address) ? tag_skip : soatag_address, tag_str_v(ss
->ss_address)
,
749
750 SOATAG_SRTP_ENABLE(ss->ss_srtp_enable)soatag_srtp_enable, tag_bool_v(ss->ss_srtp_enable),
751 SOATAG_SRTP_CONFIDENTIALITY(ss->ss_srtp_confidentiality)soatag_srtp_confidentiality, tag_bool_v(ss->ss_srtp_confidentiality
)
,
752 SOATAG_SRTP_INTEGRITY(ss->ss_srtp_integrity)soatag_srtp_integrity, tag_bool_v(ss->ss_srtp_integrity),
753
754 ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta).
tl[1].t_value
);
755
756 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))
;
757
758 return params;
759}
760
761#include <sofia-sip/sip_status.h>
762
763/** Convert @soa error to a SIP response code and phrase. */
764int soa_error_as_sip_response(soa_session_t *ss,
765 char const **return_phrase)
766{
767 SU_DEBUG_9(("soa_error_as_sip_response(%s::%p, ...) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 768, "soa_error_as_sip_response(%s::%p, ...) called\n", ss ?
ss->ss_actions->soa_name : "", (void *)ss)) : (void)0)
768 ss ? ss->ss_actions->soa_name : "", (void *)ss))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 768, "soa_error_as_sip_response(%s::%p, ...) called\n", ss ?
ss->ss_actions->soa_name : "", (void *)ss)) : (void)0)
;
769
770 if (ss == NULL((void*)0) || ss->ss_status < 400 || ss->ss_status >= 700) {
771 if (return_phrase)
772 *return_phrase = sip_500_Internal_server_error;
773 return 500;
774 }
775
776 if (return_phrase)
777 *return_phrase = ss->ss_phrase;
778 return ss->ss_status;
779}
780
781/** Convert @soa error to a SIP @Reason header. */
782char const *soa_error_as_sip_reason(soa_session_t *ss)
783{
784 char const *phrase;
785 int status;
786 char *reason;
787
788 SU_DEBUG_9(("soa_error_as_sip_reason(%s::%p) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 789, "soa_error_as_sip_reason(%s::%p) called\n", ss ? ss->
ss_actions->soa_name : "", (void *)ss)) : (void)0)
789 ss ? ss->ss_actions->soa_name : "", (void *)ss))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 789, "soa_error_as_sip_reason(%s::%p) called\n", ss ? ss->
ss_actions->soa_name : "", (void *)ss)) : (void)0)
;
790
791 if (ss == NULL((void*)0))
792 return "SIP;cause=500;text=\"Internal Server Error\"";
793
794 status = soa_error_as_sip_response(ss, &phrase);
795
796 reason = su_sprintf(ss->ss_home, "SIP;cause=%u;text=\"%s\"", status, phrase);
797
798 if (ss->ss_reason)
799 su_free(ss->ss_home, reason);
800
801 return ss->ss_reason = reason;
802}
803
804
805/** Return SIP @Warning code and text. */
806int soa_get_warning(soa_session_t *ss, char const **return_text)
807{
808 if (!ss)
809 return 0;
810
811 if (!ss->ss_wcode)
812 return 0;
813
814 if (return_text)
815 *return_text = ss->ss_warning;
816
817 return ss->ss_wcode;
818}
819
820/** Return SDP description of capabilities.
821 *
822 * @param ss pointer to @soa session
823 * @param return_sdp return value for capability SDP structure
824 * @param return_sdp_str return value for capability SDP string
825 * @param return_len return value for length of capability SDP string
826 *
827 * @retval 0 if there is no description to return
828 * @retval 1 if description is returned
829 * @retval -1 upon an error
830 *
831 * @sa @RFC3261 section 11, soa_set_capability_sdp(),
832 * SOATAG_CAPS_SDP(), SOATAG_CAPS_SDP_STR(),
833 * nua_options(), #nua_i_options
834 */
835int soa_get_capability_sdp(soa_session_t const *ss,
836 struct sdp_session_s const **return_sdp,
837 char const **return_sdp_str,
838 isize_t *return_len)
839{
840 sdp_session_t const *sdp;
841 char const *sdp_str;
842
843 SU_DEBUG_9(("soa_get_capability_sdp(%s::%p, [%p], [%p], [%p]) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 845, "soa_get_capability_sdp(%s::%p, [%p], [%p], [%p]) called\n"
, ss ? ss->ss_actions->soa_name : "", (void *)ss, (void
*)return_sdp, (void *)return_sdp_str, (void *)return_len)) :
(void)0)
844 ss ? ss->ss_actions->soa_name : "", (void *)ss,(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 845, "soa_get_capability_sdp(%s::%p, [%p], [%p], [%p]) called\n"
, ss ? ss->ss_actions->soa_name : "", (void *)ss, (void
*)return_sdp, (void *)return_sdp_str, (void *)return_len)) :
(void)0)
845 (void *)return_sdp, (void *)return_sdp_str, (void *)return_len))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 845, "soa_get_capability_sdp(%s::%p, [%p], [%p], [%p]) called\n"
, ss ? ss->ss_actions->soa_name : "", (void *)ss, (void
*)return_sdp, (void *)return_sdp_str, (void *)return_len)) :
(void)0)
;
846
847 if (ss == NULL((void*)0))
848 return (void)su_seterrno(EFAULT14), -1;
849
850 sdp = ss->ss_caps->ssd_sdp;
851 sdp_str = ss->ss_caps->ssd_str;
852
853 if (sdp == NULL((void*)0))
854 return 0;
855 if (return_sdp)
856 *return_sdp = sdp;
857 if (return_sdp_str)
858 *return_sdp_str = sdp_str;
859 if (return_len)
860 *return_len = strlen(sdp_str);
861
862 return 1;
863}
864
865
866/** Set capability SDP.
867 *
868 * Capability SDP is used instead of user SDP when generating OPTIONS
869 * responses describing media capabilities.
870 *
871 * @param ss pointer to @soa session
872 * @param sdp pointer to SDP session structure
873 * @param str pointer to string containing SDP session description
874 * @param len lenght of string @a str
875 *
876 * @retval 1 when SDP is stored and it differs from previously stored
877 * @retval 0 when SDP is identical to previously stored one (and user version
878 * returned by soa_get_user_version() is not incremented)
879 * @retval -1 upon an error
880 *
881 * @sa @RFC3261 section 11, soa_get_capability_sdp(),
882 * SOATAG_CAPS_SDP(), SOATAG_CAPS_SDP_STR(),
883 * nua_options(), #nua_i_options
884 */
885int soa_set_capability_sdp(soa_session_t *ss,
886 struct sdp_session_s const *sdp,
887 char const *str, issize_t len)
888{
889 SU_DEBUG_9(("soa_set_capability_sdp(%s::%p, %p, %p, "MOD_ZD") 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 890, "soa_set_capability_sdp(%s::%p, %p, %p, ""%zd"") called\n"
, ss ? ss->ss_actions->soa_name : "", (void *)ss, (void
*)sdp, (void *)str, (ssize_t)len)) : (void)0)
890 ss ? ss->ss_actions->soa_name : "", (void *)ss, (void *)sdp, (void *)str, (ssize_t)len))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 890, "soa_set_capability_sdp(%s::%p, %p, %p, ""%zd"") called\n"
, ss ? ss->ss_actions->soa_name : "", (void *)ss, (void
*)sdp, (void *)str, (ssize_t)len)) : (void)0)
;
891
892 return soa_set_sdp(ss, soa_capability_sdp_kind, sdp, str, len);
893}
894
895/** Set capabilities */
896int
897soa_base_set_capability_sdp(soa_session_t *ss,
898 sdp_session_t *_sdp,
899 char const *str0, isize_t len0)
900{
901 sdp_session_t sdp[1];
902 sdp_origin_t o[1] = {{ sizeof(o) }};
903 sdp_connection_t *c, c0[1] = {{ sizeof(c0) }};
904 char c_address[64];
905 sdp_time_t t[1] = {{ sizeof(t) }};
906 sdp_media_t *m;
907
908 *sdp = *_sdp;
909
910 if (sdp->sdp_origin)
1
Assuming the condition is false
2
Taking false branch
911 *o = *sdp->sdp_origin;
912 else
913 o->o_address = c0;
914
915 if (soa_init_sdp_origin(ss, o, c_address) < 0)
3
Assuming the condition is false
4
Taking false branch
916 return -1;
917
918 sdp->sdp_origin = o;
919
920 if (!sdp->sdp_subject)
5
Assuming the condition is false
6
Taking false branch
921 sdp->sdp_subject = "-"; /* s=- */
922
923 sdp->sdp_time = t; /* t=0 0 */
924
925 /* Set port to zero - or should we check that port is already zero? */
926 for (m = sdp->sdp_media; m; m = m->m_next)
7
Loop condition is false. Execution continues on line 929
927 m->m_port = 0;
928
929 if (sdp->sdp_connection == NULL((void*)0)) {
8
Assuming the condition is false
9
Taking false branch
930 c = sdp->sdp_origin->o_address;
931
932 for (m = sdp->sdp_media; m; m = m->m_next)
933 if (m->m_connections == NULL((void*)0))
934 break;
935 if (m)
936 sdp->sdp_connection = c;
937 }
938
939 return soa_description_set(ss, ss->ss_caps, sdp, str0, len0);
10
Passing null pointer value via 2nd parameter 'ssd'
11
Calling 'soa_description_set'
940}
941
942/**Return user SDP description.
943 *
944 * <i>User SDP</i> is used as basis for SDP Offer/Answer negotiation. It can
945 * be very minimal template, consisting just m= line containing media name,
946 * transport protocol, port number and list of supported codecs.
947 *
948 * The SDP used as an offer or answer (generated by soa_generate_answer() or
949 * soa_generate_offer()) is known as <i>local SDP</i> and it is available
950 * with soa_get_local_sdp() or SOATAG_LOCAL_SDP()/SOATAG_LOCAL_SDP_STR()
951 * tags.
952 *
953 * @param ss pointer to @soa session
954 * @param return_sdp SDP session structure return value
955 * @param return_sdp_str return value for pointer to string
956 * containing the user SDP session description
957 * @param return_len return value for user SDP session description string
958 * length
959 *
960 * Any of the parameters @a return_sdp, @a return_sdp_str, or @a return_len
961 * may be NULL.
962 *
963 * @retval 0 if there is no description to return
964 * @retval 1 if description is returned
965 * @retval -1 upon an error
966 *
967 * @sa soa_get_local_sdp(), soa_set_user_sdp(), soa_get_user_version(),
968 * SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(), soa_get_remote_sdp(),
969 * soa_get_capability_sdp()
970 */
971int soa_get_user_sdp(soa_session_t const *ss,
972 struct sdp_session_s const **return_sdp,
973 char const **return_sdp_str,
974 isize_t *return_len)
975{
976 sdp_session_t const *sdp;
977 char const *sdp_str;
978
979 SU_DEBUG_9(("soa_get_user_sdp(%s::%p, [%p], [%p], [%p]) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 981, "soa_get_user_sdp(%s::%p, [%p], [%p], [%p]) called\n",
ss ? ss->ss_actions->soa_name : "", (void *)ss, (void *
)return_sdp, (void *)return_sdp_str, (void *)return_len)) : (
void)0)
980 ss ? ss->ss_actions->soa_name : "", (void *)ss,(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 981, "soa_get_user_sdp(%s::%p, [%p], [%p], [%p]) called\n",
ss ? ss->ss_actions->soa_name : "", (void *)ss, (void *
)return_sdp, (void *)return_sdp_str, (void *)return_len)) : (
void)0)
981 (void *)return_sdp, (void *)return_sdp_str, (void *)return_len))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 981, "soa_get_user_sdp(%s::%p, [%p], [%p], [%p]) called\n",
ss ? ss->ss_actions->soa_name : "", (void *)ss, (void *
)return_sdp, (void *)return_sdp_str, (void *)return_len)) : (
void)0)
;
982
983 if (ss == NULL((void*)0))
984 return (void)su_seterrno(EFAULT14), -1;
985
986 sdp = ss->ss_user->ssd_sdp;
987 sdp_str = ss->ss_user->ssd_str;
988
989 if (sdp == NULL((void*)0))
990 return 0;
991 if (return_sdp)
992 *return_sdp = sdp;
993 if (return_sdp_str)
994 *return_sdp_str = sdp_str;
995 if (return_len)
996 *return_len = strlen(sdp_str);
997
998 return 1;
999}
1000
1001/**Returns the version number of user session description. The version
1002 * numbering starts from zero and it is incremented each time
1003 * soa_set_user_sdp() or soa_set_params() modifies user SDP.
1004 *
1005 * @param ss pointer to @soa session
1006
1007 * @return Sequence number of user SDP.
1008 *
1009 * @sa soa_set_user_sdp(), soa_get_user_sdp(), soa_set_params(),
1010 * SOATAG_USER_SDP(), SOATAG_USER_SDP_STR()
1011 */
1012int soa_get_user_version(soa_session_t const *ss)
1013{
1014 assert(ss != NULL)((void) sizeof ((ss != ((void*)0)) ? 1 : 0), __extension__ ({
if (ss != ((void*)0)) ; else __assert_fail ("ss != NULL", "soa.c"
, 1014, __extension__ __PRETTY_FUNCTION__); }))
;
1015 return ss ? (int)ss->ss_user_version : -1;
1016}
1017
1018/**Store user SDP to soa session.
1019 *
1020 * User SDP is used as basis for SDP Offer/Answer negotiation. It can be
1021 * very minimal, consisting just m= line containing media name, transport
1022 * protocol port number and list of supported codecs.
1023 *
1024 * The SDP used as an offer or answer (generated by soa_generate_answer() or
1025 * soa_generate_offer()) is known as <i>local SDP</i> and it is available
1026 * with soa_get_local_sdp() or SOATAG_LOCAL_SDP()/SOATAG_LOCAL_SDP_STR()
1027 * tags.
1028 *
1029 * @param ss pointer to @soa session
1030 * @param sdp pointer to SDP session structure
1031 * @param str pointer to string containing SDP session description
1032 * @param len lenght of string @a str
1033 *
1034 * Either @a sdp or @a str must be non-NULL. If @a len is -1, length of
1035 * string @a str is calculated using strlen().
1036 *
1037 * @retval 1 when SDP is stored and it differs from previously stored
1038 * @retval 0 when SDP is identical to previously stored one (and user version
1039 * returned by soa_get_user_version() is not incremented)
1040 * @retval -1 upon an error
1041 *
1042 * @sa soa_get_user_sdp(), soa_get_user_version(), soa_set_params(),
1043 * SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(), soa_generate_offer(),
1044 * soa_generate_answer(), soa_get_local_sdp(), soa_set_capability_sdp(),
1045 * soa_set_remote_sdp()
1046 */
1047int soa_set_user_sdp(soa_session_t *ss,
1048 struct sdp_session_s const *sdp,
1049 char const *str, issize_t len)
1050{
1051 SU_DEBUG_9(("soa_set_user_sdp(%s::%p, %p, %p, "MOD_ZD") 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1052, "soa_set_user_sdp(%s::%p, %p, %p, ""%zd"") called\n",
ss ? ss->ss_actions->soa_name : "", (void *)ss, (void *
)sdp, (void *)str, (ssize_t)len)) : (void)0)
1052 ss ? ss->ss_actions->soa_name : "", (void *)ss, (void *)sdp, (void *)str, (ssize_t)len))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1052, "soa_set_user_sdp(%s::%p, %p, %p, ""%zd"") called\n",
ss ? ss->ss_actions->soa_name : "", (void *)ss, (void *
)sdp, (void *)str, (ssize_t)len)) : (void)0)
;
1053
1054 return soa_set_sdp(ss, soa_user_sdp_kind, sdp, str, len);
1055}
1056
1057/** Set user SDP (base version). */
1058int soa_base_set_user_sdp(soa_session_t *ss,
1059 sdp_session_t *sdp, char const *str0, isize_t len0)
1060{
1061 ++ss->ss_user_version;
1062 return soa_description_set(ss, ss->ss_user, sdp, str0, len0);
1063}
1064
1065/**Return remote SDP description of the session.
1066 *
1067 * <i>Remote SDP</i> is used, together with <i>User SDP</i> as basis for SDP
1068 * Offer/Answer negotiation.
1069 *
1070 * @param ss pointer to @soa session
1071 * @param return_sdp SDP session structure return value
1072 * @param return_sdp_str return value for pointer to string
1073 * containing the user SDP session description
1074 * @param return_len return value for user SDP session descrioption string
1075 * length
1076 *
1077 * Any of the parameters @a return_sdp, @a return_sdp_str, or @a return_len
1078 * may be NULL.
1079 *
1080 * @retval 0 if there is no description to return
1081 * @retval 1 if description is returned
1082 * @retval -1 upon an error
1083 *
1084 * @sa soa_set_remote_sdp(), soa_get_remote_version(), soa_get_params(),
1085 * soa_get_paramlist(), SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR(),
1086 * soa_get_local_sdp(), soa_get_user_sdp(), soa_get_capability_sdp().
1087 */
1088int soa_get_remote_sdp(soa_session_t const *ss,
1089 struct sdp_session_s const **return_sdp,
1090 char const **return_sdp_str,
1091 isize_t *return_len)
1092{
1093 sdp_session_t const *sdp;
1094 char const *sdp_str;
1095
1096 SU_DEBUG_9(("soa_get_remote_sdp(%s::%p, [%p], [%p], [%p]) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1098, "soa_get_remote_sdp(%s::%p, [%p], [%p], [%p]) called\n"
, ss ? ss->ss_actions->soa_name : "", (void *)ss, (void
*)return_sdp, (void *)return_sdp_str, (void *)return_len)) :
(void)0)
1097 ss ? ss->ss_actions->soa_name : "", (void *)ss,(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1098, "soa_get_remote_sdp(%s::%p, [%p], [%p], [%p]) called\n"
, ss ? ss->ss_actions->soa_name : "", (void *)ss, (void
*)return_sdp, (void *)return_sdp_str, (void *)return_len)) :
(void)0)
1098 (void *)return_sdp, (void *)return_sdp_str, (void *)return_len))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1098, "soa_get_remote_sdp(%s::%p, [%p], [%p], [%p]) called\n"
, ss ? ss->ss_actions->soa_name : "", (void *)ss, (void
*)return_sdp, (void *)return_sdp_str, (void *)return_len)) :
(void)0)
;
1099
1100 if (ss == NULL((void*)0))
1101 return (void)su_seterrno(EFAULT14), -1;
1102
1103 sdp = ss->ss_remote->ssd_sdp;
1104 sdp_str = ss->ss_remote->ssd_str;
1105
1106 if (sdp == NULL((void*)0))
1107 return 0;
1108 if (return_sdp)
1109 *return_sdp = sdp;
1110 if (return_sdp_str)
1111 *return_sdp_str = sdp_str;
1112 if (return_len)
1113 *return_len = strlen(sdp_str);
1114
1115 return 1;
1116}
1117
1118/**Returns the version number of remote session description. The version
1119 * numbering starts from zero and it is incremented each time
1120 * soa_set_remote_sdp() or soa_set_params() modifies remote SDP.
1121 *
1122 * @param ss pointer to @soa session
1123
1124 * @return Sequence number of remote SDP.
1125 *
1126 * @sa soa_set_remote_sdp(), soa_get_remote_sdp(), soa_set_params(),
1127 * SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR()
1128 */
1129int soa_get_remote_version(soa_session_t const *ss)
1130{
1131 assert(ss != NULL)((void) sizeof ((ss != ((void*)0)) ? 1 : 0), __extension__ ({
if (ss != ((void*)0)) ; else __assert_fail ("ss != NULL", "soa.c"
, 1131, __extension__ __PRETTY_FUNCTION__); }))
;
1132 return ss->ss_remote_version;
1133}
1134
1135/** Set remote SDP (offer or answer).
1136 *
1137 * <i>Remote SDP</i> is an SDP offer or answer received from the remote end.
1138 * It is used together with <i>User SDP</i> as basis for SDP Offer/Answer
1139 * negotiation in soa_generate_answer() or soa_process_answer(). Remote SDP
1140 * can be set using soa_set_params() and SOATAG_REMOTE_SDP() or
1141 * SOATAG_REMOTE_SDP_STR() tags, too.
1142 *
1143 * If the SDP Offer/Answer negotiation step cannot be completed and the
1144 * received remote offer or answer should be ignored, call
1145 * soa_clear_remote_sdp().
1146 *
1147 * @param ss pointer to @soa session
1148 * @param sdp pointer to SDP session structure
1149 * @param str pointer to string containing SDP session description
1150 * @param len lenght of string @a str
1151 *
1152 * Either @a sdp or @a str must be non-NULL. If @a len is -1, length of
1153 * string @a str is calculated using strlen().
1154 *
1155 * @retval 1 when SDP is stored and it differs from previously stored
1156 * @retval 0 when SDP is identical to previously stored one (and remote version
1157 * returned by soa_get_remote_version() is not incremented)
1158 * @retval -1 upon an error
1159 *
1160 * @sa soa_has_received_sdp(), soa_get_remote_sdp(),
1161 * soa_get_remote_version(), soa_set_params(), SOATAG_REMOTE_SDP(),
1162 * SOATAG_REMOTE_SDP_STR(), soa_generate_answer(), soa_process_answer(),
1163 * soa_clear_remote_sdp(), soa_init_offer_answer(), soa_get_local_sdp(),
1164 * soa_set_user_sdp(), soa_set_capability_sdp().
1165 */
1166int soa_set_remote_sdp(soa_session_t *ss,
1167 struct sdp_session_s const *sdp,
1168 char const *str, issize_t len)
1169{
1170 SU_DEBUG_9(("soa_set_remote_sdp(%s::%p, %p, %p, "MOD_ZD") 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1171, "soa_set_remote_sdp(%s::%p, %p, %p, ""%zd"") called\n"
, ss ? ss->ss_actions->soa_name : "", (void *)ss, (void
*)sdp, (void *)str, (ssize_t)len)) : (void)0)
1171 ss ? ss->ss_actions->soa_name : "", (void *)ss, (void *)sdp, (void *)str, (ssize_t)len))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1171, "soa_set_remote_sdp(%s::%p, %p, %p, ""%zd"") called\n"
, ss ? ss->ss_actions->soa_name : "", (void *)ss, (void
*)sdp, (void *)str, (ssize_t)len)) : (void)0)
;
1172
1173 return soa_set_sdp(ss, soa_remote_sdp_kind, sdp, str, len);
1174}
1175
1176/** Base method for setting the remote SDP (offer or answer). */
1177int soa_base_set_remote_sdp(soa_session_t *ss,
1178 int new_version,
1179 sdp_session_t *sdp, char const *str0, isize_t len0)
1180{
1181 /* This is cleared in soa_generate_answer() or soa_process_answer(). */
1182 ss->ss_unprocessed_remote = 1;
1183
1184 if (!new_version)
1185 return 0;
1186
1187 soa_set_activity(ss, sdp->sdp_media, soa_activity_remote);
1188
1189 ss->ss_remote_version++;
1190
1191 return soa_description_set(ss, ss->ss_remote, sdp, str0, len0);
1192}
1193
1194/** Clear remote SDP.
1195 *
1196 * Remote SDP (offer or answer) should be cleared after a it has been stored
1197 * in the SDP session object using soa_set_remote_sdp() or soa_set_params(),
1198 * but the SDP Offer/Answer negotiation step (soa_generate_answer() or
1199 * soa_process_answer()) cannot be completed.
1200 *
1201 * @param ss pointer to @soa session
1202 *
1203 * @retval 0 when successful
1204 * @retval -1 upon an error
1205 *
1206 * @sa soa_init_offer_answer(), soa_set_remote_sdp(),
1207 * soa_has_received_sdp(), soa_set_params(), SOATAG_REMOTE_SDP(),
1208 * SOATAG_REMOTE_SDP_STR(), soa_generate_answer(), soa_process_answer(),
1209 * soa_process_reject().
1210 */
1211int soa_clear_remote_sdp(soa_session_t *ss)
1212{
1213 SU_DEBUG_9(("soa_clear_remote_sdp(%s::%p) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1214, "soa_clear_remote_sdp(%s::%p) called\n", ss ? ss->
ss_actions->soa_name : "", (void *)ss)) : (void)0)
1214 ss ? ss->ss_actions->soa_name : "", (void *)ss))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1214, "soa_clear_remote_sdp(%s::%p) called\n", ss ? ss->
ss_actions->soa_name : "", (void *)ss)) : (void)0)
;
1215
1216 if (!ss)
1217 return (void)su_seterrno(EFAULT14), -1;
1218
1219 ss->ss_unprocessed_remote = 0;
1220
1221 return 0;
1222}
1223
1224/** Check if remote SDP has been saved but it has not been processed.
1225 *
1226 * @sa soa_init_offer_answer(), soa_set_remote_sdp(), soa_generate_answer(),
1227 * soa_process_answer(), soa_clear_remote_sdp().
1228 */
1229int soa_has_received_sdp(soa_session_t const *ss)
1230{
1231 return ss && ss->ss_unprocessed_remote;
1232}
1233
1234
1235/**Get local SDP.
1236 *
1237 * The <i>local SDP</i> is used as an offer or answer and it is generated by
1238 * soa_generate_offer() or soa_generate_answer(), respectively. It can be
1239 * retrieved using soa_get_params() or soa_get_paramlist() with
1240 * SOATAG_LOCAL_SDP() or SOATAG_LOCAL_SDP_STR() tags.
1241 *
1242 * @param ss pointer to @soa session
1243 * @param return_sdp SDP session structure return value
1244 * @param return_sdp_str return value for pointer to string
1245 * containing the user SDP session description
1246 * @param return_len return value for user SDP session descrioption string
1247 * length
1248 *
1249 * Any of the parameters @a return_sdp, @a return_sdp_str, or @a return_len
1250 * may be NULL.
1251 *
1252 * @retval 0 if there is no description to return
1253 * @retval 1 if description is returned
1254 * @retval -1 upon an error
1255 *
1256 * @sa soa_generate_offer(), soa_generate_answer(), soa_get_params(),
1257 * soa_get_paramlist(), SOATAG_LOCAL_SDP(), SOATAG_LOCAL_SDP_STR(),
1258 * soa_get_user_sdp(), soa_get_remote_sdp(), soa_get_capability_sdp().
1259 */
1260int soa_get_local_sdp(soa_session_t const *ss,
1261 struct sdp_session_s const **return_sdp,
1262 char const **return_sdp_str,
1263 isize_t *return_len)
1264{
1265 sdp_session_t const *sdp;
1266 char const *sdp_str;
1267
1268 SU_DEBUG_9(("soa_get_local_sdp(%s::%p, [%p], [%p], [%p]) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1270, "soa_get_local_sdp(%s::%p, [%p], [%p], [%p]) called\n"
, ss ? ss->ss_actions->soa_name : "", (void *)ss, (void
*)return_sdp, (void *)return_sdp_str, (void *)return_len)) :
(void)0)
1269 ss ? ss->ss_actions->soa_name : "", (void *)ss,(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1270, "soa_get_local_sdp(%s::%p, [%p], [%p], [%p]) called\n"
, ss ? ss->ss_actions->soa_name : "", (void *)ss, (void
*)return_sdp, (void *)return_sdp_str, (void *)return_len)) :
(void)0)
1270 (void *)return_sdp, (void *)return_sdp_str, (void *)return_len))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1270, "soa_get_local_sdp(%s::%p, [%p], [%p], [%p]) called\n"
, ss ? ss->ss_actions->soa_name : "", (void *)ss, (void
*)return_sdp, (void *)return_sdp_str, (void *)return_len)) :
(void)0)
;
1271
1272 if (ss == NULL((void*)0))
1273 return (void)su_seterrno(EFAULT14), -1;
1274
1275 sdp = ss->ss_local->ssd_sdp;
1276 sdp_str = ss->ss_local->ssd_str;
1277
1278 if (sdp == NULL((void*)0))
1279 return 0;
1280 if (return_sdp)
1281 *return_sdp = sdp;
1282 if (return_sdp_str)
1283 *return_sdp_str = sdp_str;
1284 if (return_len)
1285 *return_len = strlen(sdp_str);
1286
1287 return 1;
1288}
1289
1290/**Initialize the offer/answer state machine.
1291 *
1292 * @param ss pointer to @soa session
1293 *
1294 * @retval 0 when successful
1295 * @retval -1 upon an error
1296 */
1297int soa_init_offer_answer(soa_session_t *ss)
1298{
1299 int complete;
1300
1301 SU_DEBUG_9(("soa_init_offer_answer(%s::%p) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1302, "soa_init_offer_answer(%s::%p) called\n", ss ? ss->
ss_actions->soa_name : "", (void *)ss)) : (void)0)
1302 ss ? ss->ss_actions->soa_name : "", (void *)ss))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1302, "soa_init_offer_answer(%s::%p) called\n", ss ? ss->
ss_actions->soa_name : "", (void *)ss)) : (void)0)
;
1303
1304 if (!ss)
1305 return 0;
1306
1307 complete = ss->ss_complete;
1308
1309 ss->ss_complete = 0;
1310 ss->ss_offer_sent = 0;
1311 ss->ss_offer_recv = 0;
1312 ss->ss_answer_sent = 0;
1313 ss->ss_answer_recv = 0;
1314
1315 ss->ss_unprocessed_remote = 0;
1316
1317 return complete;
1318}
1319
1320/** Return list of media fetures. */
1321char **soa_media_features(soa_session_t *ss, int live, su_home_t *home)
1322{
1323 SU_DEBUG_9(("soa_media_features(%s::%p, %u, %p) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1324, "soa_media_features(%s::%p, %u, %p) called\n", ss ? ss
->ss_actions->soa_name : "", (void *)ss, live, (void *)
home)) : (void)0)
1324 ss ? ss->ss_actions->soa_name : "", (void *)ss, live, (void *)home))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1324, "soa_media_features(%s::%p, %u, %p) called\n", ss ? ss
->ss_actions->soa_name : "", (void *)ss, live, (void *)
home)) : (void)0)
;
1325
1326 if (ss)
1327 /* Calls soa_base_media_features() by default. */
1328 return ss->ss_actions->soa_media_features(ss, live, home);
1329 else
1330 return (void)su_seterrno(EFAULT14), NULL((void*)0);
1331}
1332
1333char **soa_base_media_features(soa_session_t *ss, int live, su_home_t *home)
1334{
1335 return su_zalloc(home, 8 * sizeof (char **));
1336}
1337
1338char const * const * soa_sip_require(soa_session_t const *ss)
1339{
1340 SU_DEBUG_9(("soa_sip_require(%s::%p) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1341, "soa_sip_require(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
1341 ss ? ss->ss_actions->soa_name : "", (void *)ss))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1341, "soa_sip_require(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
;
1342
1343 if (ss)
1344 /* Calls soa_base_sip_require() by default */
1345 return ss->ss_actions->soa_sip_require(ss);
1346 else
1347 return (void)su_seterrno(EFAULT14), NULL((void*)0);
1348}
1349
1350char const * const * soa_base_sip_require(soa_session_t const *ss)
1351{
1352 static char const *null = NULL((void*)0);
1353 return &null;
1354}
1355
1356char const * const * soa_sip_supported(soa_session_t const *ss)
1357{
1358 SU_DEBUG_9(("soa_sip_supported(%s::%p) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1359, "soa_sip_supported(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
1359 ss ? ss->ss_actions->soa_name : "", (void *)ss))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1359, "soa_sip_supported(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
;
1360
1361 if (ss)
1362 /* Calls soa_base_sip_supported() by default */
1363 return ss->ss_actions->soa_sip_supported(ss);
1364 else
1365 return (void)su_seterrno(EFAULT14), NULL((void*)0);
1366}
1367
1368char const * const * soa_base_sip_supported(soa_session_t const *ss)
1369{
1370 static char const *null = NULL((void*)0);
1371 return &null;
1372}
1373
1374int soa_remote_sip_features(soa_session_t *ss,
1375 char const * const * supported,
1376 char const * const * require)
1377{
1378 SU_DEBUG_9(("soa_remote_sip_features(%s::%p, %p, %p) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1379, "soa_remote_sip_features(%s::%p, %p, %p) called\n", ss
? ss->ss_actions->soa_name : "", (void *)ss, (void *)supported
, (void *)require)) : (void)0)
1379 ss ? ss->ss_actions->soa_name : "", (void *)ss, (void *)supported, (void *)require))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1379, "soa_remote_sip_features(%s::%p, %p, %p) called\n", ss
? ss->ss_actions->soa_name : "", (void *)ss, (void *)supported
, (void *)require)) : (void)0)
;
1380
1381 if (ss)
1382 /* Calls soa_base_remote_sip_features() by default */
1383 return ss->ss_actions->soa_remote_sip_features(ss, supported, require);
1384 else
1385 return (void)su_seterrno(EFAULT14), -1;
1386}
1387
1388int soa_base_remote_sip_features(soa_session_t *ss,
1389 char const * const * supported,
1390 char const * const * require)
1391{
1392 return 0;
1393}
1394
1395
1396/**Generate offer.
1397 *
1398 * When generating the offer the user SDP is augmented with the required SDP
1399 * lines (v=, o=, t=, c=, a=rtpmap, etc.).
1400 *
1401 * The resulting SDP is also known as <i>local SDP</i>. It is available with
1402 * soa_get_local_sdp() or with soa_get_params() and soa_get_paramlist() tags
1403 * SOATAG_LOCAL_SDP() or SOATAG_LOCAL_SDP_STR().
1404 *
1405 * The user SDP has been stored to the soa session with soa_set_user_sdp()
1406 * or with soa_set_params() tags SOATAG_USER_SDP() or SOATAG_USER_SDP_STR().
1407 * There are various other parameters directing the generation of offer, set
1408 * by soa_set_params().
1409 *
1410 * @param ss pointer to session object
1411 * @param always always send offer (even if offer/answer has been completed)
1412 * @param completed pointer to callback function which is invoked when
1413 * operation is completed (currently not in use)
1414 *
1415 * @retval 1 when operation is successful
1416 * @retval 0 when operation was not needed
1417 * @retval -1 upon an error
1418 *
1419 * @ERRORS
1420 */
1421int soa_generate_offer(soa_session_t *ss,
1422 int always,
1423 soa_callback_f *completed)
1424{
1425 SU_DEBUG_9(("soa_generate_offer(%s::%p, %u) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1426, "soa_generate_offer(%s::%p, %u) called\n", ss ? ss->
ss_actions->soa_name : "", (void *)ss, always)) : (void)0)
1426 ss ? ss->ss_actions->soa_name : "", (void *)ss, always))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1426, "soa_generate_offer(%s::%p, %u) called\n", ss ? ss->
ss_actions->soa_name : "", (void *)ss, always)) : (void)0)
;
1427
1428 /** @ERROR EFAULT Bad address. */
1429 if (ss == NULL((void*)0))
1430 return su_seterrno(EFAULT14), -1;
1431
1432 /** @ERROR EALREADY An operation is already in progress */
1433 if (ss->ss_in_progress)
1434 return su_seterrno(EALREADY114), -1;
1435
1436 /** @ERROR EPROTO We have received offer, now we should send answer */
1437 if (ss->ss_offer_recv && !ss->ss_answer_sent)
1438 return su_seterrno(EPROTO71), -1;
1439
1440 /** @ERROR EPROTO We have received SDP, but it has not been processed */
1441 if (soa_has_received_sdp(ss))
1442 return su_seterrno(EPROTO71), -1;
1443
1444 /** @ERROR EPROTO We have sent an offer, but have received no answer */
1445 if (ss->ss_offer_sent && !ss->ss_answer_recv)
1446 return su_seterrno(EPROTO71), -1;
1447
1448 /** @ERROR EPROTO We have received offer. */
1449 if (ss->ss_unprocessed_remote)
1450 return su_seterrno(EPROTO71), -1;
1451
1452 /* We should avoid actual operation unless always is true */
1453 (void)always; /* We always regenerate offer */
1454
1455 /* Calls soa_static_generate_offer() by default. */
1456 return ss->ss_actions->soa_generate_offer(ss, completed);
1457
1458 /** @sa soa_init_offer_answer(), soa_set_user_sdp(), soa_get_local_sdp(),
1459 * soa_set_remote_sdp(), soa_process_answer(), soa_process_reject(),
1460 * soa_generate_answer(), soa_set_params(), soa_get_params(),
1461 * soa_get_paramlist(), SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(),
1462 * SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR().
1463 */
1464}
1465
1466int soa_base_generate_offer(soa_session_t *ss,
1467 soa_callback_f *completed)
1468{
1469 sdp_session_t const *sdp = ss->ss_local->ssd_sdp;
1470
1471 (void)completed;
1472
1473 if (!sdp)
1474 return -1;
1475
1476 soa_set_activity(ss, sdp->sdp_media, soa_activity_local); /* Wanted activity */
1477
1478 ss->ss_offer_sent = 1;
1479 ss->ss_answer_recv = 0;
1480
1481 return 0;
1482}
1483
1484/**Process offer, generate answer.
1485 *
1486 * When generating the offer the soa session combines remote offer with
1487 * <i>user SDP</i>. There are various other parameters directing the
1488 * generation of answer, set by soa_set_params().
1489 *
1490 * Before calling soa_generate_answer() the remote SDP offer should have
1491 * been stored into the soa session @a ss with soa_set_remote_sdp() or with
1492 * the soa_set_params() tags SOATAG_REMOTE_SDP() or SOATAG_REMOTE_SDP_STR().
1493 *
1494 * Also, the <i>user SDP</i> should have been stored into @a ss with
1495 * soa_set_user_sdp() or with the soa_set_params() tags SOATAG_USER_SDP() or
1496 * SOATAG_USER_SDP_STR().
1497 *
1498 * The resulting SDP is also known as <i>local SDP</i>. It is available with
1499 * soa_get_local_sdp() or with the soa_get_params() or soa_get_paramlist()
1500 * tags SOATAG_LOCAL_SDP() and SOATAG_LOCAL_SDP_STR().
1501 *
1502 * @param ss pointer to session object
1503 * @param completed pointer to callback function which is invoked when
1504 * operation is completed (currently not in use)
1505 *
1506 * @retval 0 when operation is successful
1507 * @retval -1 upon an error
1508 *
1509 * @ERRORS
1510 */
1511int soa_generate_answer(soa_session_t *ss,
1512 soa_callback_f *completed)
1513{
1514 SU_DEBUG_9(("soa_generate_answer(%s::%p) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1515, "soa_generate_answer(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
1515 ss ? ss->ss_actions->soa_name : "", (void *)ss))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1515, "soa_generate_answer(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
;
1516
1517 /** @ERROR EFAULT Bad address as @a ss. */
1518 if (ss == NULL((void*)0))
1519 return su_seterrno(EFAULT14), -1;
1520
1521 /** @ERROR EALREADY An operation is already in progress. */
1522 if (ss->ss_in_progress)
1523 return su_seterrno(EALREADY114), -1;
1524
1525 /** @ERROR EPROTO We have sent an offer, but have received no answer. */
1526 if (ss->ss_offer_sent && !ss->ss_answer_recv)
1527 return su_seterrno(EPROTO71), -1;
1528
1529 /** @ERROR EPROTO We have not received offer. */
1530 if (!ss->ss_unprocessed_remote)
1531 return su_seterrno(EPROTO71), -1;
1532
1533 /* Calls soa_static_generate_answer() by default. */
1534 return ss->ss_actions->soa_generate_answer(ss, completed);
1535
1536 /**@sa soa_init_offer_answer(), soa_set_user_sdp(), soa_set_remote_sdp(),
1537 * soa_get_local_sdp(), soa_process_reject(), soa_generate_offer(),
1538 * soa_set_params(), soa_get_params(), soa_get_paramlist(),
1539 * SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(), SOATAG_REMOTE_SDP(),
1540 * SOATAG_REMOTE_SDP_STR().
1541 */
1542}
1543
1544/** Base method for processing offer, generating answer. */
1545int soa_base_generate_answer(soa_session_t *ss,
1546 soa_callback_f *completed)
1547{
1548 sdp_session_t const *l_sdp = ss->ss_local->ssd_sdp;
1549 sdp_session_t const *r_sdp = ss->ss_remote->ssd_sdp;
1550 sdp_session_t *rsession;
1551
1552 (void)completed;
1553
1554 if (!l_sdp || !r_sdp)
1555 return -1;
1556 rsession = sdp_session_dup(ss->ss_home, r_sdp);
1557 if (!rsession)
1558 return -1;
1559
1560 if (ss->ss_rsession)
1561 su_free(ss->ss_home, ss->ss_rsession);
1562 ss->ss_rsession = rsession;
1563
1564 soa_set_activity(ss, l_sdp->sdp_media, soa_activity_session);
1565
1566 ss->ss_offer_recv = 1;
1567 ss->ss_answer_sent = 1;
1568 ss->ss_complete = 1;
1569 ss->ss_unprocessed_remote = 0;
1570
1571 return 0;
1572}
1573
1574/** Complete offer-answer after receiving answer.
1575 *
1576 * The SDP offer/answer negotiation is completed after receiving answer from
1577 * remote end. The answer is combined with the offer, and the application
1578 * should activate the media and codecs according to the negotiation result,
1579 * available as <i>local SDP</i>.
1580 *
1581 * @param ss pointer to session object
1582 * @param completed pointer to callback function which is invoked when
1583 * operation is completed (currently not in use)
1584 *
1585 * @retval 1 when operation is successful
1586 * @retval 0 when operation was not needed
1587 * @retval -1 upon an error
1588 *
1589 * @ERRORS
1590 */
1591int soa_process_answer(soa_session_t *ss,
1592 soa_callback_f *completed)
1593{
1594 SU_DEBUG_9(("soa_process_answer(%s::%p) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1595, "soa_process_answer(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
1595 ss ? ss->ss_actions->soa_name : "", (void *)ss))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1595, "soa_process_answer(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
;
1596
1597 /** @ERROR EFAULT Bad address as @a ss. */
1598 if (ss == NULL((void*)0))
1599 return su_seterrno(EFAULT14), -1;
1600
1601 /** @ERROR EALREADY An operation is already in progress. */
1602 if (ss->ss_in_progress)
1603 return su_seterrno(EALREADY114), -1;
1604
1605 /** @ERROR EPROTO We have not sent an offer
1606 or already have received answer. */
1607 if (!ss->ss_offer_sent || ss->ss_answer_recv)
1608 return su_seterrno(EPROTO71), -1;
1609
1610 /** @ERROR EPROTO We have not received answer. */
1611 if (!ss->ss_unprocessed_remote)
1612 return su_seterrno(EPROTO71), -1;
1613
1614 /**@sa soa_init_offer_answer(), soa_set_user_sdp(), soa_set_remote_sdp(),
1615 * soa_get_local_sdp(), soa_generate_offer(), soa_generate_answer(),
1616 * soa_process_reject(), soa_set_params(), soa_get_params(),
1617 * soa_get_paramlist(), SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(),
1618 * SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR().
1619 */
1620
1621 /* Calls soa_static_process_answer() by default. */
1622 return ss->ss_actions->soa_process_answer(ss, completed);
1623}
1624
1625/** Base method for completing offer-answer after receiving answer.
1626 */
1627int soa_base_process_answer(soa_session_t *ss,
1628 soa_callback_f *completed)
1629{
1630 sdp_session_t const *l_sdp = ss->ss_local->ssd_sdp;
1631 sdp_session_t const *r_sdp = ss->ss_remote->ssd_sdp;
1632 sdp_session_t *rsession;
1633
1634 (void)completed;
1635
1636 if (!l_sdp || !r_sdp)
1637 return -1;
1638 rsession = sdp_session_dup(ss->ss_home, r_sdp);
1639 if (!rsession)
1640 return -1;
1641
1642 if (ss->ss_rsession)
1643 su_free(ss->ss_home, ss->ss_rsession);
1644 ss->ss_rsession = rsession;
1645
1646 soa_set_activity(ss, l_sdp->sdp_media, soa_activity_session);
1647
1648 ss->ss_answer_recv = 1;
1649 ss->ss_complete = 1;
1650 ss->ss_unprocessed_remote = 0;
1651
1652 return 0;
1653}
1654
1655/** Process rejection of offer.
1656 *
1657 * If the SDP offer was rejected (e.g., an offer in re-INVITE asked remote
1658 * end to add video to the session but the request was rejected), the
1659 * session should be restored to the state it was before last offer-answer
1660 * negotation round with soa_process_reject().
1661 *
1662 * @param ss pointer to session object
1663 * @param completed pointer to callback function which is invoked when
1664 * operation is completed (currently not in use)
1665 *
1666 * @retval 1 when operation is successful
1667 * @retval 0 when operation was not needed
1668 * @retval -1 upon an error
1669 *
1670 * @ERRORS
1671 */
1672int soa_process_reject(soa_session_t *ss,
1673 soa_callback_f *completed)
1674{
1675 SU_DEBUG_9(("soa_process_reject(%s::%p) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1676, "soa_process_reject(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
1676 ss ? ss->ss_actions->soa_name : "", (void *)ss))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1676, "soa_process_reject(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
;
1677
1678 /** @ERROR EFAULT Bad address as @a ss. */
1679 if (ss == NULL((void*)0))
1680 return su_seterrno(EFAULT14), -1;
1681
1682 /** @ERROR EALREADY An operation is already in progress. */
1683 if (ss->ss_in_progress)
1684 return su_seterrno(EALREADY114), -1;
1685
1686 /** @ERROR EPROTO We have not sent an offer
1687 or already have received answer. */
1688 if (!ss->ss_offer_sent || ss->ss_answer_recv)
1689 return su_seterrno(EPROTO71), -1;
1690
1691 /**@sa soa_init_offer_answer(), soa_set_user_sdp(), soa_set_remote_sdp(),
1692 * soa_get_local_sdp(), soa_generate_offer(), soa_generate_answer(),
1693 * soa_process_answer(), soa_set_params(), soa_get_params(),
1694 * soa_get_paramlist(), SOATAG_USER_SDP(), SOATAG_USER_SDP_STR(),
1695 * SOATAG_REMOTE_SDP(), SOATAG_REMOTE_SDP_STR().
1696 */
1697
1698 /* Calls soa_static_process_reject() by default. */
1699 return ss->ss_actions->soa_process_reject(ss, completed);
1700}
1701
1702/** Base method for processing rejection of offer.
1703 */
1704int soa_base_process_reject(soa_session_t *ss,
1705 soa_callback_f *completed)
1706{
1707 sdp_session_t const *l_sdp = ss->ss_local->ssd_sdp;
1708
1709 (void)completed;
1710
1711 ss->ss_offer_sent = 0;
1712
1713 soa_set_activity(ss, l_sdp ? l_sdp->sdp_media : NULL((void*)0), soa_activity_session);
1714
1715 return 0;
1716}
1717
1718/** Activate session.
1719 *
1720 * Mark soa session as active.
1721 *
1722 * @retval 0 when operation was successful
1723 * @retval -1 upon an error
1724 *
1725 * @ERRORS
1726 */
1727int soa_activate(soa_session_t *ss, char const *option)
1728{
1729 SU_DEBUG_9(("soa_activate(%s::%p, %s%s%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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1730, "soa_activate(%s::%p, %s%s%s) called\n", ss ? ss->
ss_actions->soa_name : "", (void *)ss, option ? "\"" : "",
option ? option : "(nil)", option ? "\"" : "")) : (void)0)
1730 ss ? ss->ss_actions->soa_name : "", (void *)ss, NICE(option)))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1730, "soa_activate(%s::%p, %s%s%s) called\n", ss ? ss->
ss_actions->soa_name : "", (void *)ss, option ? "\"" : "",
option ? option : "(nil)", option ? "\"" : "")) : (void)0)
;
1731
1732 /** @ERROR EFAULT Bad address as @a ss. */
1733 if (ss == NULL((void*)0))
1734 return -1;
1735
1736 ss->ss_active = 1;
1737
1738 /* Calls soa_static_activate() by default. */
1739 return ss->ss_actions->soa_activate_session(ss, option);
1740}
1741
1742int soa_base_activate(soa_session_t *ss, char const *option)
1743{
1744 (void)ss;
1745 (void)option;
1746 return 0;
1747}
1748
1749/** Deactivate session.
1750 *
1751 * Mark soa session as inactive.
1752 *
1753 * @retval 0 when operation was successful
1754 * @retval -1 upon an error
1755 *
1756 * @ERRORS
1757 */
1758int soa_deactivate(soa_session_t *ss, char const *option)
1759{
1760 SU_DEBUG_9(("soa_deactivate(%s::%p, %s%s%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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1761, "soa_deactivate(%s::%p, %s%s%s) called\n", ss ? ss->
ss_actions->soa_name : "", (void *)ss, option ? "\"" : "",
option ? option : "(nil)", option ? "\"" : "")) : (void)0)
1761 ss ? ss->ss_actions->soa_name : "", (void *)ss, NICE(option)))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1761, "soa_deactivate(%s::%p, %s%s%s) called\n", ss ? ss->
ss_actions->soa_name : "", (void *)ss, option ? "\"" : "",
option ? option : "(nil)", option ? "\"" : "")) : (void)0)
;
1762
1763 /** @ERROR EFAULT Bad address as @a ss. */
1764 if (ss == NULL((void*)0))
1765 return -1;
1766
1767 ss->ss_active = 0;
1768
1769 /* Calls soa_static_deactivate() by default. */
1770 return ss->ss_actions->soa_deactivate_session(ss, option);
1771}
1772
1773int soa_base_deactivate(soa_session_t *ss, char const *option)
1774{
1775 (void)ss;
1776 (void)option;
1777 return 0;
1778}
1779
1780/** Terminate session. */
1781void soa_terminate(soa_session_t *ss, char const *option)
1782{
1783 SU_DEBUG_9(("soa_terminate(%s::%p) 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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1784, "soa_terminate(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
1784 ss ? ss->ss_actions->soa_name : "", (void *)ss))(((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
)) >= 9 ? (_su_llog(soa_log, 9, "soa.c", (const char *)__func__
, 1784, "soa_terminate(%s::%p) called\n", ss ? ss->ss_actions
->soa_name : "", (void *)ss)) : (void)0)
;
1785
1786 /** @ERROR EFAULT Bad address as @a ss. */
1787 if (ss == NULL((void*)0))
1788 return;
1789
1790 ss->ss_active = 0;
1791 ss->ss_terminated++;
1792
1793 /* Calls soa_static_terminate() by default. */
1794 ss->ss_actions->soa_terminate_session(ss, option);
1795}
1796
1797void soa_base_terminate(soa_session_t *ss, char const *option)
1798{
1799 (void)option;
1800
1801 soa_init_offer_answer(ss);
1802 ss->ss_oa_rounds = 0;
1803
1804 soa_description_free(ss, ss->ss_remote);
1805 soa_set_activity(ss, NULL((void*)0), soa_activity_session);
1806}
1807
1808/** Return true if the SDP Offer/Answer negotation is complete.
1809 *
1810 * The soa_init_offer_answer() clears the completion flag.
1811 */
1812int soa_is_complete(soa_session_t const *ss)
1813{
1814 return ss && ss->ss_complete;
1815}
1816
1817/** Return true if audio has been activated. */
1818int soa_is_audio_active(soa_session_t const *ss)
1819{
1820 int ma = ss ? ss->ss_local_activity->ma_audio : SOA_ACTIVE_DISABLEDSOA_ACTIVE_DISABLED;
1821 if (ma >= 4) ma |= -8;
1822 return ma;
1823}
1824
1825/** Return true if video has been activated. */
1826int soa_is_video_active(soa_session_t const *ss)
1827{
1828 int ma = ss ? ss->ss_local_activity->ma_video : SOA_ACTIVE_DISABLEDSOA_ACTIVE_DISABLED;
1829 if (ma >= 4) ma |= -8;
1830 return ma;
1831}
1832
1833/** Return true if image sharing has been activated. */
1834int soa_is_image_active(soa_session_t const *ss)
1835{
1836 int ma = ss ? ss->ss_local_activity->ma_image : SOA_ACTIVE_DISABLEDSOA_ACTIVE_DISABLED;
1837 if (ma >= 4) ma |= -8;
1838 return ma;
1839}
1840
1841/** Return true if messaging session has been activated. */
1842int soa_is_chat_active(soa_session_t const *ss)
1843{
1844 int ma = ss ? ss->ss_local_activity->ma_chat : SOA_ACTIVE_DISABLEDSOA_ACTIVE_DISABLED;
1845 if (ma >= 4) ma |= -8;
1846 return ma;
1847}
1848
1849/** Return true if remote audio is active (not on hold). */
1850int soa_is_remote_audio_active(soa_session_t const *ss)
1851{
1852 int ma = ss ? ss->ss_remote_activity->ma_audio : SOA_ACTIVE_DISABLEDSOA_ACTIVE_DISABLED;
1853 if (ma >= 4) ma |= -8;
1854 return ma;
1855}
1856
1857/** Return true if remote video is active (not on hold). */
1858int soa_is_remote_video_active(soa_session_t const *ss)
1859{
1860 int ma = ss ? ss->ss_remote_activity->ma_video : SOA_ACTIVE_DISABLEDSOA_ACTIVE_DISABLED;
1861 if (ma >= 4) ma |= -8;
1862 return ma;
1863}
1864
1865/** Return true if image sharing is active (not on hold). */
1866int soa_is_remote_image_active(soa_session_t const *ss)
1867{
1868 int ma = ss ? ss->ss_remote_activity->ma_image : SOA_ACTIVE_DISABLEDSOA_ACTIVE_DISABLED;
1869 if (ma >= 4) ma |= -8;
1870 return ma;
1871}
1872
1873/** Return true if chat session is active (not on hold). */
1874int soa_is_remote_chat_active(soa_session_t const *ss)
1875{
1876 int ma = ss ? ss->ss_remote_activity->ma_chat : SOA_ACTIVE_DISABLEDSOA_ACTIVE_DISABLED;
1877 if (ma >= 4) ma |= -8;
1878 return ma;
1879}
1880
1881/* ======================================================================== */
1882/* Methods used by soa instances */
1883
1884int soa_set_status(soa_session_t *ss, int status, char const *phrase)
1885{
1886 if (ss) {
1887 ss->ss_status = status, ss->ss_phrase = phrase;
1888 ss->ss_wcode = 0, ss->ss_warning = NULL((void*)0);
1889 }
1890 return -1;
1891}
1892
1893int soa_set_warning(soa_session_t *ss, int code, char const *text)
1894{
1895 if (ss)
1896 ss->ss_wcode = code, ss->ss_warning = text;
1897 return -1;
1898}
1899
1900void soa_set_activity(soa_session_t *ss,
1901 sdp_media_t const *m,
1902 enum soa_activity activity)
1903{
1904 struct soa_media_activity *ma;
1905 sdp_connection_t const *c;
1906 int mode, swap;
1907 int l_audio = SOA_ACTIVE_DISABLEDSOA_ACTIVE_DISABLED, r_audio = SOA_ACTIVE_DISABLEDSOA_ACTIVE_DISABLED;
1908 int l_video = SOA_ACTIVE_DISABLEDSOA_ACTIVE_DISABLED, r_video = SOA_ACTIVE_DISABLEDSOA_ACTIVE_DISABLED;
1909 int l_chat = SOA_ACTIVE_DISABLEDSOA_ACTIVE_DISABLED, r_chat = SOA_ACTIVE_DISABLEDSOA_ACTIVE_DISABLED;
1910 int l_image = SOA_ACTIVE_DISABLEDSOA_ACTIVE_DISABLED, r_image = SOA_ACTIVE_DISABLEDSOA_ACTIVE_DISABLED;
1911
1912 int *l, *r;
1913
1914 for (; m; m = m->m_next) {
1915 if (m->m_type == sdp_media_audio)
1916 l = &l_audio, r = &r_audio;
1917 else if (m->m_type == sdp_media_video)
1918 l = &l_video, r = &r_video;
1919 else if (m->m_type == sdp_media_image)
1920 l = &l_image, r = &r_image;
1921 else if (su_casematch(m->m_type_name, "message"))
1922 l = &l_chat, r = &r_chat;
1923 else
1924 continue;
1925
1926 if (m->m_rejected) {
1927 if (*l < 0) *l = SOA_ACTIVE_REJECTEDSOA_ACTIVE_REJECTED;
1928 if (*r < 0) *r = SOA_ACTIVE_REJECTEDSOA_ACTIVE_REJECTED;
1929 continue;
1930 }
1931
1932 mode = m->m_mode, swap = ((mode << 1) & 2) | ((mode >> 1) & 1);
1933
1934 c = sdp_media_connections((sdp_media_t *)m);
1935
1936 switch (activity) {
1937 case soa_activity_local:
1938 *l &= SOA_ACTIVE_SENDRECVSOA_ACTIVE_SENDRECV;
1939 *l |= c && c->c_mcast ? swap : mode;
1940 break;
1941 case soa_activity_remote:
1942 *r &= SOA_ACTIVE_SENDRECVSOA_ACTIVE_SENDRECV;
1943 *r = c && c->c_mcast ? mode : swap;
1944 break;
1945 case soa_activity_session:
1946 *l &= SOA_ACTIVE_SENDRECVSOA_ACTIVE_SENDRECV;
1947 *l |= c && c->c_mcast ? swap : mode;
1948 *r &= SOA_ACTIVE_SENDRECVSOA_ACTIVE_SENDRECV;
1949 *r = c && c->c_mcast ? swap : mode;
1950 break;
1951 }
1952 }
1953
1954 if (activity == soa_activity_local ||
1955 activity == soa_activity_session) {
1956 ma = ss->ss_local_activity;
1957 ma->ma_audio = l_audio;
1958 ma->ma_video = l_video;
1959 ma->ma_image = l_image;
1960 ma->ma_chat = l_chat;
1961 }
1962
1963 if (activity == soa_activity_remote ||
1964 activity == soa_activity_session) {
1965 ma = ss->ss_remote_activity;
1966 ma->ma_audio = r_audio;
1967 ma->ma_video = r_video;
1968 ma->ma_image = r_image;
1969 ma->ma_chat = r_chat;
1970 }
1971}
1972
1973/* ----------------------------------------------------------------------*/
1974/* Handle SDP */
1975
1976
1977/**
1978 * Parses and stores session description
1979 *
1980 * @param ss instance pointer
1981 * @param what caps, local or remote
1982 * @param sdp0 new sdp (parsed)
1983 * @param sdp_str new sdp (unparsed)
1984 * @param str_len length on unparsed data
1985 **/
1986static
1987int soa_set_sdp(soa_session_t *ss,
1988 enum soa_sdp_kind what,
1989 sdp_session_t const *sdp0,
1990 char const *sdp_str, issize_t str_len)
1991{
1992 struct soa_description *ssd;
1993 int flags, new_version, retval;
1994 sdp_parser_t *parser = NULL((void*)0);
1995 sdp_session_t sdp[1];
1996
1997 if (ss == NULL((void*)0))
1998 return -1;
1999
2000 switch (what) {
2001 case soa_capability_sdp_kind:
2002 ssd = ss->ss_caps;
2003 flags = sdp_f_config;
2004 break;
2005 case soa_user_sdp_kind:
2006 ssd = ss->ss_user;
2007 flags = sdp_f_config;
2008 break;
2009 case soa_remote_sdp_kind:
2010 ssd = ss->ss_remote;
2011 flags = sdp_f_mode_0000;
2012 break;
2013 default:
2014 return -1;
2015 }
2016
2017 if (sdp0) {
2018 new_version = sdp_session_cmp(sdp0, ssd->ssd_sdp) != 0;
2019 sdp_str = NULL((void*)0), str_len = -1;
2020 }
2021 else if (sdp_str) {
2022 if (str_len == -1)
2023 str_len = strlen(sdp_str);
2024 new_version = !su_strnmatch(sdp_str, ssd->ssd_unparsed, str_len + 1);
2025 }
2026 else
2027 return (void)su_seterrno(EINVAL22), -1;
2028
2029 if (!new_version) {
2030 if (what == soa_remote_sdp_kind) {
2031 *sdp = *ssd->ssd_sdp;
2032 /* Calls soa_static_set_remote_sdp() by default */
2033 return ss->ss_actions->soa_set_remote_sdp(ss, new_version,
2034 sdp, sdp_str, str_len);
2035 /* XXX - should check changes by soa_set_remote_sdp */
2036 }
2037 return 0;
2038 }
2039
2040 if (sdp0) {
2041 /* note: case 1 - src in parsed form */
2042 *sdp = *sdp0;
2043 }
2044 else /* if (sdp_str) */ {
2045 /* note: case 2 - src in unparsed form */
2046 parser = sdp_parse(ss->ss_home, sdp_str, str_len, flags | sdp_f_anynet);
2047
2048 if (sdp_parsing_error(parser)) {
2049 sdp_parser_free(parser);
2050 return soa_set_status(ss, 400, "Bad Session Description");
2051 }
2052
2053 *sdp = *sdp_session(parser);
2054 }
2055
2056 switch (what) {
2057 case soa_capability_sdp_kind:
2058 /* Calls soa_static_set_capability_sdp() by default */
2059 retval = ss->ss_actions->soa_set_capability_sdp(ss, sdp, sdp_str, str_len);
2060 break;
2061 case soa_user_sdp_kind:
2062 /* Calls soa_static_set_user_sdp() by default */
2063 retval = ss->ss_actions->soa_set_user_sdp(ss, sdp, sdp_str, str_len);
2064 break;
2065 case soa_remote_sdp_kind:
2066 /* Calls soa_static_set_remote_sdp() by default */
2067 retval = ss->ss_actions->soa_set_remote_sdp(ss, 1, sdp, sdp_str, str_len);
2068 break;
2069 default:
2070 retval = soa_set_status(ss, 500, "Internal Error");
2071 break;
2072 }
2073
2074 if (parser)
2075 sdp_parser_free(parser);
2076
2077 return retval;
2078}
2079
2080
2081/** Set session descriptions. */
2082int soa_description_set(soa_session_t *ss,
2083 struct soa_description *ssd,
2084 sdp_session_t *sdp,
2085 char const *sdp_str,
2086 isize_t str_len)
2087{
2088 int retval = -1;
2089
2090 sdp_printer_t *printer = NULL((void*)0);
2091 sdp_session_t *sdp_new;
2092 char *sdp_str_new;
2093 char *sdp_str0_new;
2094
2095 void *tbf1, *tbf2, *tbf3, *tbf4;
2096
2097 /* Store description in three forms: unparsed, parsed and reprinted */
2098
2099 sdp_new = sdp_session_dup(ss->ss_home, sdp);
2100 printer = sdp_print(ss->ss_home, sdp, NULL((void*)0), 0, 0);
2101 sdp_str_new = (char *)sdp_message(printer);
2102 if (sdp_str)
12
Assuming 'sdp_str' is null
13
Taking false branch
2103 sdp_str0_new = su_strndup(ss->ss_home, sdp_str, str_len);
2104 else
2105 sdp_str0_new = sdp_str_new;
2106
2107 if (sdp_new && printer && sdp_str_new && sdp_str0_new) {
14
Assuming 'sdp_new' is non-null
15
Assuming 'printer' is non-null
16
Assuming 'sdp_str_new' is non-null
17
Taking true branch
2108 tbf1 = ssd->ssd_sdp, tbf2 = ssd->ssd_printer;
18
Access to field 'ssd_sdp' results in a dereference of a null pointer (loaded from variable 'ssd')
2109 tbf3 = (void *)ssd->ssd_str, tbf4 = (void *)ssd->ssd_unparsed;
2110
2111 ssd->ssd_sdp = sdp_new;
2112 ssd->ssd_printer = printer;
2113 ssd->ssd_str = sdp_str_new;
2114 ssd->ssd_unparsed = sdp_str0_new;
2115
2116 retval = 1;
2117 }
2118 else {
2119 tbf1 = sdp_new, tbf2 = printer, tbf3 = sdp_str_new, tbf4 = sdp_str0_new;
2120 }
2121
2122 su_free(ss->ss_home, tbf1);
2123 sdp_printer_free(tbf2);
2124 if (tbf3 != tbf4)
2125 su_free(ss->ss_home, tbf4);
2126
2127 return retval;
2128}
2129
2130
2131/** Duplicate a session descriptions. */
2132int soa_description_dup(su_home_t *home,
2133 struct soa_description *ssd,
2134 struct soa_description const *ssd0)
2135{
2136 if (ssd0->ssd_sdp) {
2137 ssd->ssd_sdp = sdp_session_dup(home, ssd0->ssd_sdp);
2138 ssd->ssd_printer = sdp_print(home, ssd->ssd_sdp, NULL((void*)0), 0, 0);
2139 ssd->ssd_str = (char *)sdp_message(ssd->ssd_printer);
2140 if (ssd0->ssd_str != ssd0->ssd_unparsed)
2141 ssd->ssd_unparsed = su_strdup(home, ssd0->ssd_unparsed);
2142 else
2143 ssd->ssd_unparsed = ssd->ssd_str;
2144 }
2145
2146 return 0;
2147}
2148
2149/** Free session descriptions. */
2150void soa_description_free(soa_session_t *ss,
2151 struct soa_description *ssd)
2152{
2153 void *tbf1, *tbf2, *tbf3, *tbf4;
2154
2155 tbf1 = ssd->ssd_sdp, tbf2 = ssd->ssd_printer;
2156 tbf3 = (void *)ssd->ssd_str, tbf4 = (void *)ssd->ssd_unparsed;
2157
2158 memset(ssd, 0, sizeof *ssd);
2159
2160 su_free(ss->ss_home, tbf1);
2161 sdp_printer_free(tbf2);
2162 if (tbf3 != tbf4)
2163 su_free(ss->ss_home, tbf4);
2164}
2165
2166/** Initialize SDP o= line */
2167int
2168soa_init_sdp_origin(soa_session_t *ss, sdp_origin_t *o, char buffer[64])
2169{
2170 return soa_init_sdp_origin_with_session(ss, o, buffer, NULL((void*)0));
2171}
2172
2173
2174/** Check if c= has valid address
2175 */
2176int
2177soa_check_sdp_connection(sdp_connection_t const *c)
2178{
2179 return c != NULL((void*)0) &&
2180 c->c_nettype &&c->c_address &&
2181 strcmp(c->c_address, "") &&
2182 strcmp(c->c_address, "0.0.0.0") &&
2183 strcmp(c->c_address, "::");
2184}
2185
2186
2187/** Initialize SDP o= line with values from @a sdp session. */
2188int
2189soa_init_sdp_origin_with_session(soa_session_t *ss,
2190 sdp_origin_t *o,
2191 char buffer[64],
2192 sdp_session_t const *sdp)
2193{
2194 if (ss == NULL((void*)0) || o == NULL((void*)0) || buffer == NULL((void*)0))
2195 return su_seterrno(EFAULT14);
2196
2197 assert(o->o_address)((void) sizeof ((o->o_address) ? 1 : 0), __extension__ ({ if
(o->o_address) ; else __assert_fail ("o->o_address", "soa.c"
, 2197, __extension__ __PRETTY_FUNCTION__); }))
;
2198
2199 if (!o->o_username)
2200 o->o_username = "-";
2201
2202 if (o->o_id == 0)
2203 su_randmem(&o->o_id, sizeof o->o_id);
2204 o->o_id &= ((unsigned longlonglong long)1 << 63) - 1;
2205
2206 if (o->o_version == 0)
2207 su_randmem(&o->o_version, sizeof o->o_version);
2208 o->o_version &= ((unsigned longlonglong long)1 << 63) - 1;
2209
2210 if (!soa_check_sdp_connection(o->o_address) ||
2211 host_is_local(o->o_address->c_address))
2212 return soa_init_sdp_connection_with_session(ss, o->o_address, buffer, sdp);
2213
2214 return 0;
2215}
2216
2217
2218/** Obtain a local address for SDP connection structure */
2219int
2220soa_init_sdp_connection(soa_session_t *ss,
2221 sdp_connection_t *c,
2222 char buffer[64])
2223{
2224 return soa_init_sdp_connection_with_session(ss, c, buffer, NULL((void*)0));
2225}
2226
2227static su_localinfo_t const *best_listed_address_in_localinfo(
2228 su_localinfo_t const *res, char const *address, int ip4, int ip6);
2229static sdp_connection_t const *best_listed_address_in_session(
2230 sdp_session_t const *sdp, char const *address0, int ip4, int ip6);
2231static su_localinfo_t const *best_listed_address(
2232 su_localinfo_t *li0, char const *address, int ip4, int ip6);
2233
2234
2235/** Obtain a local address for SDP connection structure.
2236 *
2237 * Prefer an address already found in @a sdp.
2238 */
2239int
2240soa_init_sdp_connection_with_session(soa_session_t *ss,
2241 sdp_connection_t *c,
2242 char buffer[64],
2243 sdp_session_t const *sdp)
2244{
2245 su_localinfo_t *res, hints[1] = {{ LI_CANONNAME | LI_NUMERIC }}, li0[1];
2246 su_localinfo_t const *li, *li4, *li6;
2247 char const *address;
2248 char const *source = NULL((void*)0);
2249 int ip4, ip6, error;
2250 char abuffer[64]; /* getting value from ss_address */
2251
2252 if (ss == NULL((void*)0) || c == NULL((void*)0) || buffer == NULL((void*)0))
2253 return su_seterrno(EFAULT14), -1;
2254
2255 address = ss->ss_address;
2256
2257 if (host_is_ip_address(address)) {
2258 /* Use the application-specified address -
2259 * do not check that it is found from the local address list */
2260 c->c_nettype = sdp_net_in;
2261
2262 if (host_is_ip4_address(address))
2263 c->c_addrtype = sdp_addr_ip4;
2264 else
2265 c->c_addrtype = sdp_addr_ip6;
2266
2267 if (!host_is_ip6_reference(address)) {
2268 c->c_address = strcpy(buffer, address);
2269 }
2270 else {
2271 /* Remove brackets [] around the reference */
2272 size_t len = strlen(address + 1);
2273 c->c_address = memcpy(buffer, address + 1, len - 1);
2274 buffer[len - 1] = '\0';
2275 }
2276
2277 SU_DEBUG_5(("%s: using SOATAG_ADDRESS(\"%s\")\n", __func__, c->c_address))(((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.c", (const char *)__func__
, 2277, "%s: using SOATAG_ADDRESS(\"%s\")\n", __func__, c->
c_address)) : (void)0)
;
2278
2279 return 0;
2280 }
2281
2282 /* XXX - using LI_SCOPE_LINK requires some tweaking */
2283 hints->li_scope = LI_SCOPE_GLOBAL | LI_SCOPE_SITE /* | LI_SCOPE_LINK */;
2284
2285 for (res = NULL((void*)0); res == NULL((void*)0);) {
2286 if ((error = su_getlocalinfo(hints, &res)) < 0
2287 && error != ELI_NOADDRESS) {
2288 SU_DEBUG_1(("%s: su_localinfo: %s\n", __func__,(((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
)) >= 1 ? (_su_llog(soa_log, 1, "soa.c", (const char *)__func__
, 2289, "%s: su_localinfo: %s\n", __func__, su_gli_strerror(error
))) : (void)0)
2289 su_gli_strerror(error)))(((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
)) >= 1 ? (_su_llog(soa_log, 1, "soa.c", (const char *)__func__
, 2289, "%s: su_localinfo: %s\n", __func__, su_gli_strerror(error
))) : (void)0)
;
2290 return -1;
2291 }
2292 if (hints->li_scope & LI_SCOPE_HOST)
2293 break;
2294 hints->li_scope |= LI_SCOPE_HOST;
2295 }
2296
2297 if (c->c_nettype != sdp_net_in ||
2298 (c->c_addrtype != sdp_addr_ip4 && c->c_addrtype != sdp_addr_ip6)) {
2299 c->c_nettype = sdp_net_in, c->c_addrtype = (sdp_addrtype_e)0;
2300 c->c_address = strcpy(buffer, "");
2301 }
2302
2303 switch (ss->ss_af) {
2304 case SOA_AF_IP4_ONLYSOA_AF_IP4_ONLY:
2305 ip4 = 1, ip6 = 0;
2306 break;
2307 case SOA_AF_IP6_ONLYSOA_AF_IP6_ONLY:
2308 ip6 = 1, ip4 = 0;
2309 break;
2310 case SOA_AF_IP4_IP6SOA_AF_IP4_IP6:
2311 ip4 = 2, ip6 = 1;
2312 break;
2313 case SOA_AF_IP6_IP4SOA_AF_IP6_IP4:
2314 ip4 = 1, ip6 = 2;
2315 break;
2316 default:
2317 ip4 = ip6 = 1;
2318 }
2319
2320 if (ip4 && ip6) {
2321 /* Prefer address family already used in session, if any */
2322 sdp_addrtype_e addrtype = (sdp_addrtype_e)0;
2323 char const *because = "error";
2324
2325 if (sdp && sdp->sdp_connection &&
2326 sdp->sdp_connection->c_nettype == sdp_net_in) {
2327 addrtype = sdp->sdp_connection->c_addrtype;
2328 because = "an existing c= line";
2329 }
2330 else if (sdp) {
2331 int mip4 = 0, mip6 = 0;
2332 sdp_media_t const *m;
2333
2334 for (m = sdp->sdp_media; m; m = m->m_next) {
2335 sdp_connection_t const *mc;
2336
2337 if (m->m_rejected)
2338 continue;
2339
2340 for (mc = m->m_connections; mc; mc = mc->c_next) {
2341 if (mc->c_nettype == sdp_net_in) {
2342 if (mc->c_addrtype == sdp_addr_ip4)
2343 mip4++;
2344 else if (mc->c_addrtype == sdp_addr_ip6)
2345 mip6++;
2346 }
2347 }
2348 }
2349
2350 if (mip4 && mip6)
2351 /* Mixed. */;
2352 else if (mip4)
2353 addrtype = sdp_addr_ip4, because = "an existing c= line under m=";
2354 else if (mip6)
2355 addrtype = sdp_addr_ip6, because = "an existing c= line under m=";
2356 }
2357
2358 if (addrtype == 0)
2359 addrtype = c->c_addrtype, because = "the user sdp";
2360
2361 if (addrtype == sdp_addr_ip4) {
2362 if (ip6 >= ip4)
2363 SU_DEBUG_5(("%s: prefer %s because of %s\n", __func__, "IP4", because))(((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.c", (const char *)__func__
, 2363, "%s: prefer %s because of %s\n", __func__, "IP4", because
)) : (void)0)
;
2364 ip4 = 2, ip6 = 1;
2365 }
2366 else if (addrtype == sdp_addr_ip6) {
2367 if (ip4 >= ip6)
2368 SU_DEBUG_5(("%s: prefer %s because of %s\n", __func__, "IP4", because))(((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.c", (const char *)__func__
, 2368, "%s: prefer %s because of %s\n", __func__, "IP4", because
)) : (void)0)
;
2369 ip6 = 2, ip4 = 1;
2370 }
2371 }
2372
2373 li = NULL((void*)0), li4 = NULL((void*)0), li6 = NULL((void*)0);
2374
2375 if (li == NULL((void*)0) && ss->ss_address) {
2376 li = best_listed_address_in_localinfo(res, ss->ss_address, ip4, ip6);
2377 if (li)
2378 source = "local address from SOATAG_ADDRESS() list";
2379 }
2380
2381 if (li == NULL((void*)0) && ss->ss_address && sdp) {
2382 sdp_connection_t const *c;
2383 c = best_listed_address_in_session(sdp, ss->ss_address, ip4, ip6);
2384 if (c) {
2385 li = memset(li0, 0, sizeof li0);
2386 if (c->c_addrtype == sdp_addr_ip4)
2387 li0->li_family = AF_INET2;
2388#if SU_HAVE_IN61
2389 else
2390 li0->li_family = AF_INET610;
2391#endif
2392 li0->li_canonname = (char *)c->c_address;
2393 source = "address from SOATAG_ADDRESS() list already in session";
2394 }
2395 }
2396
2397 if (li == NULL((void*)0) && ss->ss_address) {
2398 memset(li0, 0, sizeof li0);
2399 li0->li_canonname = abuffer;
2400 li = best_listed_address(li0, ss->ss_address, ip4, ip6);
2401 if (li)
2402 source = "address from SOATAG_ADDRESS() list";
2403 }
2404
2405 if (li == NULL((void*)0)) {
2406 for (li = res; li; li = li->li_next) {
2407 if (su_casematch(li->li_canonname, c->c_address))
2408 break;
2409 }
2410 if (li)
2411 source = "the proposed local address";
2412 }
2413
2414 /* Check if session-level c= address is local */
2415 if (li == NULL((void*)0) && sdp && sdp->sdp_connection) {
2416 for (li = res; li; li = li->li_next) {
2417 if (!su_casematch(li->li_canonname, sdp->sdp_connection->c_address))
2418 continue;
2419#if HAVE_SIN61
2420 if (li->li_family == AF_INET610) {
2421 if (ip6 >= ip4)
2422 break;
2423 else if (!li6)
2424 li6 = li; /* Best IP6 address */
2425 }
2426#endif
2427 else if (li->li_family == AF_INET2) {
2428 if (ip4 >= ip6)
2429 break;
2430 else if (!li4)
2431 li4 = li; /* Best IP4 address */
2432 }
2433 }
2434
2435 if (li == NULL((void*)0) && ip4)
2436 li = li4;
2437 if (li == NULL((void*)0) && ip6)
2438 li = li6;
2439 if (li)
2440 source = "an existing session-level c= line";
2441 }
2442
2443 /* Check for best local media-level c= address */
2444 if (li == NULL((void*)0) && sdp) {
2445 sdp_media_t const *m;
2446
2447 for (m = sdp->sdp_media; m; m = m->m_next) {
2448 sdp_connection_t const *mc;
2449
2450 if (m->m_rejected)
2451 continue;
2452
2453 for (mc = m->m_connections; mc; mc = mc->c_next) {
2454 for (li = res; li; li = li->li_next) {
2455 if (!su_casematch(li->li_canonname, mc->c_address))
2456 continue;
2457#if HAVE_SIN61
2458 if (li->li_family == AF_INET610) {
2459 if (ip6 > ip4)
2460 break;
2461 else if (!li6)
2462 li6 = li; /* Best IP6 address */
2463 }
2464#endif
2465 else if (li->li_family == AF_INET2) {
2466 if (ip4 > ip6)
2467 break;
2468 else if (!li4)
2469 li4 = li; /* Best IP4 address */
2470 }
2471 }
2472 }
2473
2474 if (li)
2475 break;
2476 }
2477
2478 if (li == NULL((void*)0) && ip4)
2479 li = li4;
2480 if (li == NULL((void*)0) && ip6)
2481 li = li6;
2482 if (li)
2483 source = "an existing c= address from media descriptions";
2484 }
2485
2486 /* Check if o= address is local */
2487 if (li == NULL((void*)0) && sdp && sdp->sdp_origin) {
2488 char const *address = sdp->sdp_origin->o_address->c_address;
2489
2490 for (li = res; li; li = li->li_next) {
2491 if (!su_casematch(li->li_canonname, address))
2492 continue;
2493#if HAVE_SIN61
2494 if (li->li_family == AF_INET610) {
2495 if (ip6 >= ip4)
2496 break;
2497 else if (!li6)
2498 li6 = li; /* Best IP6 address */
2499 }
2500#endif
2501 else if (li->li_family == AF_INET2) {
2502 if (ip4 >= ip6)
2503 break;
2504 else if (!li4)
2505 li4 = li; /* Best IP4 address */
2506 }
2507 }
2508
2509 if (li == NULL((void*)0) && ip4)
2510 li = li4;
2511 if (li == NULL((void*)0) && ip6)
2512 li = li6;
2513 if (li)
2514 source = "an existing address from o= line";
2515 }
2516
2517 if (li == NULL((void*)0)) {
2518 for (li = res; li; li = li->li_next) {
2519 if (li->li_family == AF_INET2) {
2520 if (ip4 >= ip6)
2521 break;
2522 else if (!li4)
2523 li4 = li; /* Best IP4 address */
2524 }
2525#if HAVE_SIN61
2526 else if (li->li_family == AF_INET610) {
2527 if (ip6 >= ip4)
2528 break;
2529 else if (!li6)
2530 li6 = li; /* Best IP6 address */
2531 }
2532#endif
2533 }
2534
2535 if (li == NULL((void*)0) && ip4)
2536 li = li4;
2537 if (li == NULL((void*)0) && ip6)
2538 li = li6;
2539
2540 if (li)
2541 source = "a local address";
2542 }
2543
2544 if (li) {
2545 char const *typename;
2546
2547 if (li->li_family == AF_INET2)
2548 c->c_nettype = sdp_net_in, c->c_addrtype = sdp_addr_ip4, typename = "IP4";
2549#if HAVE_SIN61
2550 else if (li->li_family == AF_INET610)
2551 c->c_nettype = sdp_net_in, c->c_addrtype = sdp_addr_ip6, typename = "IP6";
2552#endif
2553 else
2554 typename = "???";
2555
2556 assert(strlen(li->li_canonname) < 64)((void) sizeof ((strlen(li->li_canonname) < 64) ? 1 : 0
), __extension__ ({ if (strlen(li->li_canonname) < 64) ;
else __assert_fail ("strlen(li->li_canonname) < 64", "soa.c"
, 2556, __extension__ __PRETTY_FUNCTION__); }))
;
2557 c->c_address = strcpy(buffer, li->li_canonname);
2558
2559 SU_DEBUG_5(("%s: selected IN %s %s (%s)\n", __func__,(((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.c", (const char *)__func__
, 2560, "%s: selected IN %s %s (%s)\n", __func__, typename, li
->li_canonname, source)) : (void)0)
2560 typename, li->li_canonname, source))(((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.c", (const char *)__func__
, 2560, "%s: selected IN %s %s (%s)\n", __func__, typename, li
->li_canonname, source)) : (void)0)
;
2561 }
2562
2563 su_freelocalinfo(res);
2564
2565 if (!li)
2566 return -1;
2567 else
2568 return 0;
2569}
2570
2571/* Search for first entry from SOATAG_ADDRESS() list on localinfo list */
2572static su_localinfo_t const *
2573best_listed_address_in_localinfo(su_localinfo_t const *res,
2574 char const *address,
2575 int ip4,
2576 int ip6)
2577{
2578 su_localinfo_t const *li = NULL((void*)0), *best = NULL((void*)0);
2579 size_t n;
2580
2581 SU_DEBUG_3(("%s: searching for %s from list \"%s\"\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
)) >= 3 ? (_su_llog(soa_log, 3, "soa.c", (const char *)__func__
, 2583, "%s: searching for %s from list \"%s\"\n", __func__, ip6
&& !ip4 ? "IP6 " : !ip6 && ip4 ? "IP4 " : ""
, address)) : (void)0)
2582 __func__, ip6 && !ip4 ? "IP6 " : !ip6 && ip4 ? "IP4 " : "",(((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
)) >= 3 ? (_su_llog(soa_log, 3, "soa.c", (const char *)__func__
, 2583, "%s: searching for %s from list \"%s\"\n", __func__, ip6
&& !ip4 ? "IP6 " : !ip6 && ip4 ? "IP4 " : ""
, address)) : (void)0)
2583 address))(((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
)) >= 3 ? (_su_llog(soa_log, 3, "soa.c", (const char *)__func__
, 2583, "%s: searching for %s from list \"%s\"\n", __func__, ip6
&& !ip4 ? "IP6 " : !ip6 && ip4 ? "IP4 " : ""
, address)) : (void)0)
;
2584
2585 for (; address[0]; address += n + strspn(address, ", ")) {
2586 n = strcspn(address, ", ");
2587 if (n == 0)
2588 continue;
2589
2590 for (li = res; li; li = li->li_next) {
2591 if (su_casenmatch(li->li_canonname, address, n) &&
2592 li->li_canonname[n] == '\0')
2593 break;
2594 }
2595
2596 if (li == NULL((void*)0))
2597 continue;
2598#if HAVE_SIN61
2599 else if (li->li_family == AF_INET610) {
2600 if (ip6 >= ip4)
2601 return li;
2602 else if (ip6 && !best)
2603 best = li; /* Best IP6 address */
2604 }
2605#endif
2606 else if (li->li_family == AF_INET2) {
2607 if (ip4 >= ip6)
2608 return li;
2609 else if (ip4 && !best)
2610 best = li; /* Best IP4 address */
2611 }
2612 }
2613
2614 return best;
2615}
2616
2617/* Search for first entry from SOATAG_ADDRESS() list in session */
2618static sdp_connection_t const *
2619best_listed_address_in_session(sdp_session_t const *sdp,
2620 char const *address0,
2621 int ip4,
2622 int ip6)
2623{
2624 sdp_connection_t *c = NULL((void*)0), *best = NULL((void*)0);
2625 sdp_media_t *m;
2626 char const *address;
2627 size_t n;
2628
2629 for (address = address0; address[0]; address += n + strspn(address, ", ")) {
2630 n = strcspn(address, ", ");
2631 if (n == 0)
2632 continue;
2633
2634 c = sdp->sdp_connection;
2635
2636 if (c && su_casenmatch(c->c_address, address, n) && c->c_address[n] == 0)
2637 ;
2638 else
2639 for (m = sdp->sdp_media; m; m = m->m_next) {
2640 if (m->m_connections && m->m_connections != sdp->sdp_connection) {
2641 c = sdp->sdp_connection;
2642 if (c && su_casenmatch(c->c_address, address, n) && c->c_address[n] == 0)
2643 break;
2644 c = NULL((void*)0);
2645 }
2646 }
2647
2648 if (c == NULL((void*)0) || c->c_nettype != sdp_net_in)
2649 continue;
2650#if HAVE_SIN61
2651 else if (c->c_addrtype == sdp_addr_ip6) {
2652 if (ip6 >= ip4)
2653 return c;
2654 else if (ip6 && !best)
2655 best = c; /* Best IP6 address */
2656 }
2657#endif
2658 else if (c->c_addrtype == sdp_addr_ip4) {
2659 if (ip4 >= ip6)
2660 return c;
2661 else if (ip4 && !best)
2662 best = c; /* Best IP4 address */
2663 }
2664 }
2665
2666 if (best || sdp->sdp_origin == NULL((void*)0))
2667 return best;
2668
2669 /* Check if address on list is already been used on o= line */
2670 for (address = address0; address[0]; address += n + strspn(address, ", ")) {
2671 n = strcspn(address, ", ");
2672 if (n == 0)
2673 continue;
2674 c = sdp->sdp_origin->o_address;
2675
2676 if (su_casenmatch(c->c_address, address, n) && c->c_address[n] != 0)
2677 continue;
2678#if HAVE_SIN61
2679 else if (c->c_addrtype == sdp_addr_ip6) {
2680 if (ip6 >= ip4)
2681 return c;
2682 else if (ip6 && !best)
2683 best = c; /* Best IP6 address */
2684 }
2685#endif
2686 else if (c->c_addrtype == sdp_addr_ip4) {
2687 if (ip4 >= ip6)
2688 return c;
2689 else if (ip4 && !best)
2690 best = c; /* Best IP4 address */
2691 }
2692 }
2693
2694 return best;
2695}
2696
2697static su_localinfo_t const *
2698best_listed_address(su_localinfo_t *li0,
2699 char const *address,
2700 int ip4,
2701 int ip6)
2702{
2703 size_t n, best = 0;
2704 char *buffer = (char *)li0->li_canonname;
2705
2706 for (; address[0]; address += n + strspn(address + n, " ,")) {
2707 if ((n = span_ip6_address(address))) {
2708#if SU_HAVE_IN61
2709 if (ip6 > ip4) {
2710 li0->li_family = AF_INET610;
2711 strncpy(buffer, address, n)[n] = '\0';
2712 return li0;
2713 }
2714 else if (ip6 && !best) {
2715 li0->li_family = AF_INET610;
2716 strncpy(buffer, address, best = n)[n] = '\0';
2717 }
2718#endif
2719 }
2720 else if ((n = span_ip4_address(address))) {
2721 if (ip4 > ip6) {
2722 li0->li_family = AF_INET2;
2723 strncpy(buffer, address, n)[n] = '\0';
2724 return li0;
2725 }
2726 else if (ip4 && !best) {
2727 li0->li_family = AF_INET2;
2728 strncpy(buffer, address, best = n)[n] = '\0';
2729 }
2730 }
2731 else {
2732 n = strcspn(address, " ,");
2733 }
2734 }
2735
2736 if (best)
2737 return li0;
2738 else
2739 return NULL((void*)0);
2740}