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') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
66 | typedef unsigned longlonglong long ull; | |||
67 | ||||
68 | #if HAVE_FUNC1 | |||
69 | #elif HAVE_FUNCTION1 | |||
70 | #define __func__ __FUNCTION__ | |||
71 | #else | |||
72 | static char const __func__[] = "soa"; | |||
73 | #endif | |||
74 | ||||
75 | /* ======================================================================== */ | |||
76 | ||||
77 | /* Internal prototypes */ | |||
78 | enum soa_sdp_kind { | |||
79 | soa_capability_sdp_kind, | |||
80 | soa_user_sdp_kind, | |||
81 | soa_remote_sdp_kind | |||
82 | }; | |||
83 | ||||
84 | static 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 | */ | |||
126 | extern 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 | */ | |||
137 | su_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 | ||||
146 | struct 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 | ||||
155 | static struct soa_namenode const soa_default_node = | |||
156 | { | |||
157 | NULL((void*)0), "default", &soa_default_actions | |||
158 | }; | |||
159 | ||||
160 | static struct soa_namenode const *soa_namelist = &soa_default_node; | |||
161 | ||||
162 | /** Add a named soa backend */ | |||
163 | int 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 */ | |||
194 | struct 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. */ | |||
219 | soa_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. */ | |||
271 | soa_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 */ | |||
305 | soa_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 */ | |||
313 | void 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 */ | |||
321 | int 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. */ | |||
353 | void 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 | ||||
367 | void 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 | */ | |||
397 | int 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 | */ | |||
442 | int 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 | */ | |||
609 | int 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 | */ | |||
657 | int 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. */ | |||
692 | tagi_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. */ | |||
713 | tagi_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. */ | |||
764 | int 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. */ | |||
782 | char 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. */ | |||
806 | int 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 | */ | |||
835 | int 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 | */ | |||
885 | int 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 */ | |||
896 | int | |||
897 | soa_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) | |||
| ||||
911 | *o = *sdp->sdp_origin; | |||
912 | else | |||
913 | o->o_address = c0; | |||
914 | ||||
915 | if (soa_init_sdp_origin(ss, o, c_address) < 0) | |||
916 | return -1; | |||
917 | ||||
918 | sdp->sdp_origin = o; | |||
919 | ||||
920 | if (!sdp->sdp_subject) | |||
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) | |||
927 | m->m_port = 0; | |||
928 | ||||
929 | if (sdp->sdp_connection == NULL((void*)0)) { | |||
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); | |||
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 | */ | |||
971 | int 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 | */ | |||
1012 | int 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 | */ | |||
1047 | int 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). */ | |||
1058 | int 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 | */ | |||
1088 | int 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 | */ | |||
1129 | int 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 | */ | |||
1166 | int 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). */ | |||
1177 | int 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 | */ | |||
1211 | int 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 | */ | |||
1229 | int 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 | */ | |||
1260 | int 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 | */ | |||
1297 | int 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. */ | |||
1321 | char **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 | ||||
1333 | char **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 | ||||
1338 | char 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 | ||||
1350 | char 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 | ||||
1356 | char 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 | ||||
1368 | char 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 | ||||
1374 | int 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 | ||||
1388 | int 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 | */ | |||
1421 | int 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 | ||||
1466 | int 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 | */ | |||
1511 | int 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. */ | |||
1545 | int 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 | */ | |||
1591 | int 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 | */ | |||
1627 | int 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 | */ | |||
1672 | int 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 | */ | |||
1704 | int 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 | */ | |||
1727 | int 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 | ||||
1742 | int 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 | */ | |||
1758 | int 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 | ||||
1773 | int 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. */ | |||
1781 | void 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 | ||||
1797 | void 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 | */ | |||
1812 | int 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. */ | |||
1818 | int 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. */ | |||
1826 | int 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. */ | |||
1834 | int 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. */ | |||
1842 | int 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). */ | |||
1850 | int 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). */ | |||
1858 | int 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). */ | |||
1866 | int 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). */ | |||
1874 | int 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 | ||||
1884 | int 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 | ||||
1893 | int 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 | ||||
1900 | void 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 | **/ | |||
1986 | static | |||
1987 | int 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. */ | |||
2082 | int 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) | |||
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) { | |||
2108 | tbf1 = ssd->ssd_sdp, tbf2 = ssd->ssd_printer; | |||
| ||||
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. */ | |||
2132 | int 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. */ | |||
2150 | void 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 */ | |||
2167 | int | |||
2168 | soa_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 | */ | |||
2176 | int | |||
2177 | soa_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. */ | |||
2188 | int | |||
2189 | soa_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 */ | |||
2219 | int | |||
2220 | soa_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 | ||||
2227 | static su_localinfo_t const *best_listed_address_in_localinfo( | |||
2228 | su_localinfo_t const *res, char const *address, int ip4, int ip6); | |||
2229 | static sdp_connection_t const *best_listed_address_in_session( | |||
2230 | sdp_session_t const *sdp, char const *address0, int ip4, int ip6); | |||
2231 | static 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 | */ | |||
2239 | int | |||
2240 | soa_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 */ | |||
2572 | static su_localinfo_t const * | |||
2573 | best_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 */ | |||
2618 | static sdp_connection_t const * | |||
2619 | best_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 | ||||
2697 | static su_localinfo_t const * | |||
2698 | best_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 | } |