File: | libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c |
Location: | line 670, column 21 |
Description: | Access to field 'nh_nua' results in a dereference of a null pointer (loaded from variable 'nh') |
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 nua_stack.c | |||
26 | * @brief Sofia-SIP User Agent Engine implementation | |||
27 | * | |||
28 | * @author Pekka Pessi <Pekka.Pessi@nokia.com> | |||
29 | * @author Kai Vehmanen <Kai.Vehmanen@nokia.com> | |||
30 | * @author Martti Mela <Martti Mela@nokia.com> | |||
31 | * @author Remeres Jacobs <Remeres.Jacobs@nokia.com> | |||
32 | * @author Tat Chan <Tat.Chan@nokia.com> | |||
33 | * | |||
34 | * @date Created: Wed Feb 14 18:32:58 2001 ppessi | |||
35 | */ | |||
36 | ||||
37 | #include "config.h" | |||
38 | ||||
39 | #include <sofia-sip/su_tag_class.h> | |||
40 | #include <sofia-sip/su_tag_inline.h> | |||
41 | #include <sofia-sip/su_tagarg.h> | |||
42 | #include <sofia-sip/su_strlst.h> | |||
43 | #include <sofia-sip/su_uniqueid.h> | |||
44 | ||||
45 | #include <sofia-sip/su_tag_io.h> | |||
46 | ||||
47 | #define SU_ROOT_MAGIC_Tstruct nua_s struct nua_s | |||
48 | #define SU_MSG_ARG_Tstruct nua_ee_data struct nua_ee_data | |||
49 | ||||
50 | #define NUA_SAVED_EVENT_Tsu_msg_t * su_msg_t * | |||
51 | #define NUA_SAVED_SIGNAL_Tsu_msg_t * su_msg_t * | |||
52 | ||||
53 | #define NTA_AGENT_MAGIC_Tstruct nua_s struct nua_s | |||
54 | #define NTA_LEG_MAGIC_Tstruct nua_handle_s struct nua_handle_s | |||
55 | #define NTA_OUTGOING_MAGIC_Tstruct nua_client_request struct nua_client_request | |||
56 | ||||
57 | #include <sofia-sip/sip.h> | |||
58 | #include <sofia-sip/sip_header.h> | |||
59 | #include <sofia-sip/sip_status.h> | |||
60 | #include <sofia-sip/sip_util.h> | |||
61 | ||||
62 | #include <sofia-sip/tport_tag.h> | |||
63 | #include <sofia-sip/nta.h> | |||
64 | #include <sofia-sip/nta_tport.h> | |||
65 | #include <sofia-sip/auth_client.h> | |||
66 | ||||
67 | #include <sofia-sip/soa.h> | |||
68 | ||||
69 | #include "sofia-sip/nua.h" | |||
70 | #include "sofia-sip/nua_tag.h" | |||
71 | #include "nua_stack.h" | |||
72 | ||||
73 | #include <stddef.h> | |||
74 | #include <stdlib.h> | |||
75 | #include <string.h> | |||
76 | #include <limits.h> | |||
77 | #include <stdio.h> | |||
78 | ||||
79 | #include <assert.h> | |||
80 | ||||
81 | /* ======================================================================== | |||
82 | * | |||
83 | * Protocol stack side | |||
84 | * | |||
85 | * ======================================================================== */ | |||
86 | ||||
87 | /* ---------------------------------------------------------------------- */ | |||
88 | /* Internal types */ | |||
89 | ||||
90 | /** @internal Linked stack frames from nua event callback */ | |||
91 | struct nua_event_frame_s { | |||
92 | nua_event_frame_t *nf_next; | |||
93 | nua_saved_event_t nf_saved[1]; | |||
94 | }; | |||
95 | ||||
96 | ||||
97 | static void nua_event_deinit(nua_ee_data_t *ee); | |||
98 | static void nua_application_event(nua_t *, su_msg_r, nua_ee_data_t *ee); | |||
99 | static void nua_stack_signal(nua_t *nua, su_msg_r, nua_ee_data_t *ee); | |||
100 | ||||
101 | nua_handle_t *nh_create(nua_t *nua, tag_type_t t, tag_value_t v, ...); | |||
102 | static void nh_append(nua_t *nua, nua_handle_t *nh); | |||
103 | static void nh_remove(nua_t *nua, nua_handle_t *nh); | |||
104 | ||||
105 | static void nua_stack_timer(nua_t *nua, su_timer_t *t, su_timer_arg_t *a); | |||
106 | ||||
107 | /* ---------------------------------------------------------------------- */ | |||
108 | /* Constant data */ | |||
109 | ||||
110 | /**@internal Default internal error. */ | |||
111 | char const nua_internal_error[] = "Internal NUA Error"; | |||
112 | ||||
113 | char const nua_application_sdp[] = "application/sdp"; | |||
114 | ||||
115 | #define NUA_STACK_TIMER_INTERVAL(1000) (1000) | |||
116 | ||||
117 | /* ---------------------------------------------------------------------- | |||
118 | * Initialization & deinitialization | |||
119 | */ | |||
120 | ||||
121 | int nua_stack_init(su_root_t *root, nua_t *nua) | |||
122 | { | |||
123 | su_home_t *home; | |||
124 | nua_handle_t *dnh; | |||
125 | ||||
126 | static int initialized_logs = 0; | |||
127 | ||||
128 | enter(void)((((nua_log) != ((void*)0) && (nua_log)->log_init ) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 9 ? (_su_llog((nua_log), 9, "nua_stack.c", ( const char *)__func__, 128, "nua: %s: entering\n", __func__)) : (void)0); | |||
129 | ||||
130 | if (!initialized_logs) { | |||
131 | extern su_log_t tport_log[]; | |||
132 | extern su_log_t nta_log[]; | |||
133 | extern su_log_t nea_log[]; | |||
134 | extern su_log_t iptsec_log[]; | |||
135 | ||||
136 | su_log_init(tport_log); | |||
137 | su_log_init(nta_log); | |||
138 | su_log_init(nea_log); | |||
139 | su_log_init(iptsec_log); | |||
140 | ||||
141 | initialized_logs = 1; | |||
142 | } | |||
143 | ||||
144 | nua->nua_root = root; | |||
145 | nua->nua_timer = su_timer_create(su_root_task(root), | |||
146 | NUA_STACK_TIMER_INTERVAL(1000)); | |||
147 | if (!nua->nua_timer) | |||
148 | return -1; | |||
149 | ||||
150 | home = nua->nua_home; | |||
151 | nua->nua_handles_tail = &nua->nua_handles; | |||
152 | sip_from_init(nua->nua_from); | |||
153 | ||||
154 | dnh = su_home_clone(nua->nua_home, sizeof (*dnh) + sizeof(*dnh->nh_prefs)); | |||
155 | if (!dnh) | |||
156 | return -1; | |||
157 | ||||
158 | dnh->nh_prefs = (void *)(dnh + 1); | |||
159 | dnh->nh_valid = nua_valid_handle_cookie((void *)(intptr_t)nua_handle); | |||
160 | dnh->nh_nua = nua; | |||
161 | nua_handle_ref(dnh); dnh->nh_ref_by_stack = 1; | |||
162 | nua_handle_ref(dnh); dnh->nh_ref_by_user = 1; | |||
163 | nh_append(nua, dnh); | |||
164 | dnh->nh_identity = dnh; | |||
165 | dnh->nh_ds->ds_local = nua->nua_from; | |||
166 | dnh->nh_ds->ds_remote = nua->nua_from; | |||
167 | ||||
168 | if (nua_stack_set_defaults(dnh, dnh->nh_prefs) < 0) | |||
169 | return -1; | |||
170 | ||||
171 | if (nua_stack_set_params(nua, dnh, nua_i_none, nua->nua_args) < 0) | |||
172 | return -1; | |||
173 | ||||
174 | nua->nua_invite_accept = sip_accept_make(home, SDP_MIME_TYPEnua_application_sdp); | |||
175 | ||||
176 | nua->nua_nta = nta_agent_create(root, NONE((void *)-1), NULL((void*)0), NULL((void*)0), | |||
177 | NTATAG_MERGE_482(1)ntatag_merge_482, tag_bool_v((1)), | |||
178 | NTATAG_CLIENT_RPORT(1)ntatag_client_rport, tag_bool_v((1)), | |||
179 | NTATAG_UA(1)ntatag_ua, tag_bool_v((1)), | |||
180 | #if HAVE_SOFIA_SMIME0 | |||
181 | NTATAG_SMIME(nua->sm)ntatag_smime, tag_ptr_v((nua->sm)), | |||
182 | #endif | |||
183 | TPTAG_STUN_SERVER(1)tptag_stun_server, tag_bool_v((1)), | |||
184 | TAG_NEXT(nua->nua_args)tag_next, (tag_value_t)(nua->nua_args)); | |||
185 | ||||
186 | dnh->nh_ds->ds_leg = nta_leg_tcreate(nua->nua_nta, | |||
187 | nua_stack_process_request, dnh, | |||
188 | NTATAG_NO_DIALOG(1)ntatag_no_dialog, tag_bool_v((1)), | |||
189 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||
190 | ||||
191 | if (nua->nua_nta == NULL((void*)0) || | |||
192 | dnh->nh_ds->ds_leg == NULL((void*)0) || | |||
193 | nta_agent_set_params(nua->nua_nta, NTATAG_UA(1)ntatag_ua, tag_bool_v((1)), TAG_END()(tag_type_t)0, (tag_value_t)0) < 0 || | |||
194 | nua_stack_init_transport(nua, nua->nua_args) < 0) { | |||
195 | SU_DEBUG_1(("nua: initializing SIP stack failed\n" VA_NONE))((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 1 ? (_su_llog((nua_log), 1, "nua_stack.c", ( const char *)__func__, 195, "nua: initializing SIP stack failed\n" "%s", "")) : (void)0); | |||
196 | return -1; | |||
197 | } | |||
198 | ||||
199 | if (nua_stack_set_from(nua, 1, nua->nua_args) < 0) | |||
200 | return -1; | |||
201 | ||||
202 | if (nua->nua_prefs->ngp_detect_network_updates) | |||
203 | nua_stack_launch_network_change_detector(nua); | |||
204 | ||||
205 | nua_stack_timer(nua, nua->nua_timer, NULL((void*)0)); | |||
206 | ||||
207 | return 0; | |||
208 | } | |||
209 | ||||
210 | void nua_stack_deinit(su_root_t *root, nua_t *nua) | |||
211 | { | |||
212 | enter(void)((((nua_log) != ((void*)0) && (nua_log)->log_init ) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 9 ? (_su_llog((nua_log), 9, "nua_stack.c", ( const char *)__func__, 212, "nua: %s: entering\n", __func__)) : (void)0); | |||
213 | ||||
214 | su_timer_destroy(nua->nua_timer), nua->nua_timer = NULL((void*)0); | |||
215 | nta_agent_destroy(nua->nua_nta), nua->nua_nta = NULL((void*)0); | |||
216 | } | |||
217 | ||||
218 | /* ---------------------------------------------------------------------- | |||
219 | * Sending events to client application | |||
220 | */ | |||
221 | ||||
222 | static void nua_stack_shutdown(nua_t *); | |||
223 | ||||
224 | void | |||
225 | nua_stack_authenticate(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *), | |||
226 | nua_stack_respond(nua_t *, nua_handle_t *, int , char const *, tagi_t const *), | |||
227 | nua_stack_destroy_handle(nua_t *, nua_handle_t *, tagi_t const *); | |||
228 | ||||
229 | /* Notifier */ | |||
230 | void | |||
231 | nua_stack_authorize(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *), | |||
232 | nua_stack_notifier(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *), | |||
233 | nua_stack_terminate(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *); | |||
234 | ||||
235 | int nh_notifier_shutdown(nua_handle_t *nh, nea_event_t *ev, | |||
236 | tag_type_t t, tag_value_t v, ...); | |||
237 | ||||
238 | int nua_stack_tevent(nua_t *nua, nua_handle_t *nh, msg_t *msg, | |||
239 | nua_event_t event, int status, char const *phrase, | |||
240 | tag_type_t tag, tag_value_t value, ...) | |||
241 | { | |||
242 | ta_list ta; | |||
243 | int retval; | |||
244 | 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); | |||
245 | retval = nua_stack_event(nua, nh, msg, event, status, phrase, ta_args(ta)(ta).tl); | |||
246 | 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)); | |||
247 | return retval; | |||
248 | } | |||
249 | ||||
250 | /** @internal Send an event to the application. */ | |||
251 | int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg, | |||
252 | nua_event_t event, int status, char const *phrase, | |||
253 | tagi_t const *tags) | |||
254 | { | |||
255 | su_msg_r sumsg = SU_MSG_R_INIT{ ((void*)0) }; | |||
256 | size_t e_len, len, xtra, p_len; | |||
257 | ||||
258 | if (event == nua_r_ack || event == nua_i_none) | |||
259 | return event; | |||
260 | ||||
261 | if (nh == nua->nua_dhandlenua_handles) | |||
262 | nh = NULL((void*)0); | |||
263 | ||||
264 | if (nua_log->log_level >= 5) { | |||
265 | char const *name = nua_event_name(event) + 4; | |||
266 | char const *p = phrase ? phrase : ""; | |||
267 | ||||
268 | if (status == 0) | |||
269 | SU_DEBUG_5(("nua(%p): event %s %s\n", (void *)nh, name, p))((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_stack.c", ( const char *)__func__, 269, "nua(%p): event %s %s\n", (void * )nh, name, p)) : (void)0); | |||
270 | else | |||
271 | SU_DEBUG_5(("nua(%p): event %s %u %s\n", (void *)nh, name, status, p))((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_stack.c", ( const char *)__func__, 271, "nua(%p): event %s %u %s\n", (void *)nh, name, status, p)) : (void)0); | |||
272 | } | |||
273 | ||||
274 | if (event == nua_r_destroy) { | |||
275 | if (msg) | |||
276 | msg_destroy(msg); | |||
277 | if (status >= 200) { | |||
278 | nh_destroy(nua, nh); | |||
279 | } | |||
280 | return event; | |||
281 | } | |||
282 | ||||
283 | if ((event > nua_r_authenticate && event <= nua_r_ack) | |||
284 | || event < nua_i_error | |||
285 | || (nh && !nh->nh_valid) | |||
286 | || (nua->nua_shutdown && event != nua_r_shutdown && | |||
287 | !nua->nua_prefs->ngp_shutdown_events)) { | |||
288 | if (msg) | |||
289 | msg_destroy(msg); | |||
290 | return event; | |||
291 | } | |||
292 | ||||
293 | if (tags) { | |||
294 | e_len = offsetof(nua_ee_data_t, ee_data[0].e_tags)__builtin_offsetof(nua_ee_data_t, ee_data[0].e_tags); | |||
295 | len = tl_len(tags); | |||
296 | xtra = tl_xtra(tags, len); | |||
297 | } | |||
298 | else { | |||
299 | e_len = sizeof(nua_ee_data_t), len = 0, xtra = 0; | |||
300 | } | |||
301 | p_len = phrase ? strlen(phrase) + 1 : 1; | |||
302 | ||||
303 | if (su_msg_new(sumsg, e_len + len + xtra + p_len) == 0) { | |||
304 | nua_ee_data_t *ee = su_msg_data(sumsg); | |||
305 | nua_event_data_t *e = ee->ee_data; | |||
306 | void *p; | |||
307 | ||||
308 | if (tags) { | |||
309 | tagi_t *t = e->e_tags, *t_end = (tagi_t *)((char *)t + len); | |||
310 | void *b = t_end, *end = (char *)b + xtra; | |||
311 | ||||
312 | t = tl_dup(t, tags, &b); p = b; | |||
313 | assert(t == t_end)((t == t_end) ? (void) (0) : __assert_fail ("t == t_end", "nua_stack.c" , 313, __PRETTY_FUNCTION__)); assert(b == end)((b == end) ? (void) (0) : __assert_fail ("b == end", "nua_stack.c" , 313, __PRETTY_FUNCTION__)); (void)end; | |||
314 | } | |||
315 | else | |||
316 | p = e + 1; | |||
317 | ||||
318 | ee->ee_nua = nua_stack_ref(nua); | |||
319 | e->e_event = event; | |||
320 | e->e_nh = nh ? nua_handle_ref(nh) : NULL((void*)0); | |||
321 | e->e_status = status; | |||
322 | e->e_phrase = strcpy(p, phrase ? phrase : ""); | |||
323 | if (msg) | |||
324 | e->e_msg = msg, su_home_threadsafe(msg_home(msg)((su_home_t*)(msg))); | |||
325 | ||||
326 | su_msg_deinitializer(sumsg, nua_event_deinit); | |||
327 | ||||
328 | su_msg_send_to(sumsg, nua->nua_client, nua_application_event); | |||
329 | } | |||
330 | ||||
331 | return event; | |||
332 | } | |||
333 | ||||
334 | static | |||
335 | void nua_event_deinit(nua_ee_data_t *ee) | |||
336 | { | |||
337 | nua_t *nua = ee->ee_nua; | |||
338 | nua_event_data_t *e = ee->ee_data; | |||
339 | nua_handle_t *nh = e->e_nh; | |||
340 | ||||
341 | if (e->e_msg) | |||
342 | msg_destroy(e->e_msg), e->e_msg = NULL((void*)0); | |||
343 | ||||
344 | if (nh) | |||
345 | nua_handle_unref(nh), e->e_nh = NULL((void*)0); | |||
346 | ||||
347 | if (nua) | |||
348 | nua_stack_unref(nua), ee->ee_nua = NULL((void*)0); | |||
349 | } | |||
350 | ||||
351 | /*# Receive event from protocol machine and hand it over to application */ | |||
352 | static | |||
353 | void nua_application_event(nua_t *dummy, su_msg_r sumsg, nua_ee_data_t *ee) | |||
354 | { | |||
355 | nua_t *nua = ee->ee_nua; | |||
356 | nua_event_data_t *e = ee->ee_data; | |||
357 | nua_handle_t *nh = e->e_nh; | |||
358 | ||||
359 | enter(void)((((nua_log) != ((void*)0) && (nua_log)->log_init ) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 9 ? (_su_llog((nua_log), 9, "nua_stack.c", ( const char *)__func__, 359, "nua: %s: entering\n", __func__)) : (void)0); | |||
360 | ||||
361 | ee->ee_nua = NULL((void*)0); | |||
362 | e->e_nh = NULL((void*)0); | |||
363 | ||||
364 | if (nh == NULL((void*)0)) { | |||
365 | /* Xyzzy */ | |||
366 | } | |||
367 | else if (nh->nh_valid) { | |||
368 | if (!nh->nh_ref_by_user) { | |||
369 | /* Application must now call nua_handle_destroy() */ | |||
370 | nh->nh_ref_by_user = 1; | |||
371 | nua_handle_ref(nh); | |||
372 | } | |||
373 | } | |||
374 | else if (!nh->nh_valid) { /* Handle has been destroyed */ | |||
375 | if (nua_log->log_level >= 7) { | |||
376 | char const *name = nua_event_name((enum nua_event_e)e->e_event) + 4; | |||
377 | SU_DEBUG_7(("nua(%p): event %s dropped\n", (void *)nh, name))((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 7 ? (_su_llog((nua_log), 7, "nua_stack.c", ( const char *)__func__, 377, "nua(%p): event %s dropped\n", (void *)nh, name)) : (void)0); | |||
378 | } | |||
379 | nua_handle_unref(nh); | |||
380 | nua_stack_unref(nua); | |||
381 | return; | |||
382 | } | |||
383 | ||||
384 | if (e->e_event == nua_r_shutdown && e->e_status >= 200) | |||
385 | nua->nua_shutdown_final = 1; | |||
386 | ||||
387 | if (nua->nua_callback) { | |||
388 | nua_event_frame_t frame[1]; | |||
389 | ||||
390 | su_msg_save(frame->nf_saved, sumsg); | |||
391 | frame->nf_next = nua->nua_current, nua->nua_current = frame; | |||
392 | ||||
393 | nua->nua_callback((enum nua_event_e)e->e_event, e->e_status, e->e_phrase, | |||
394 | nua, nua->nua_magic, | |||
395 | nh, nh ? nh->nh_magic : NULL((void*)0), | |||
396 | e->e_msg ? sip_object(e->e_msg) : NULL((void*)0), | |||
397 | e->e_tags); | |||
398 | ||||
399 | if (su_msg_is_non_null(frame->nf_saved)) { | |||
400 | su_msg_destroy(frame->nf_saved); | |||
401 | } | |||
402 | nua->nua_current = frame->nf_next; | |||
403 | } | |||
404 | ||||
405 | nua_handle_unref(nh); | |||
406 | nua_stack_unref(nua); | |||
407 | } | |||
408 | ||||
409 | /** Get current request message. @NEW_1_12_4. | |||
410 | * | |||
411 | * @note A response message is returned when processing response message. | |||
412 | * | |||
413 | * @sa #nua_event_e, nua_respond(), NUTAG_WITH_CURRENT() | |||
414 | */ | |||
415 | msg_t *nua_current_request(nua_t const *nua) | |||
416 | { | |||
417 | if (nua && nua->nua_current && su_msg_is_non_null(nua->nua_current->nf_saved)) | |||
418 | return su_msg_data(nua->nua_current->nf_saved)->ee_data->e_msg; | |||
419 | return NULL((void*)0); | |||
420 | } | |||
421 | ||||
422 | ||||
423 | su_msg_t *nua_current_msg(nua_t const *nua, int clear) | |||
424 | { | |||
425 | if (nua && nua->nua_current && su_msg_is_non_null(nua->nua_current->nf_saved)) { | |||
426 | su_msg_t *r = nua->nua_current->nf_saved[0]; | |||
427 | if (clear) { | |||
428 | nua->nua_current->nf_saved[0] = NULL((void*)0); | |||
429 | } | |||
430 | return r; | |||
431 | //return su_msg_data(nua->nua_current->nf_saved)->ee_data->e_msg; | |||
432 | ||||
433 | } | |||
434 | ||||
435 | return NULL((void*)0); | |||
436 | } | |||
437 | ||||
438 | ||||
439 | /** Get request message from saved nua event. @NEW_1_12_4. | |||
440 | * | |||
441 | * @sa nua_save_event(), nua_respond(), NUTAG_WITH_SAVED(), | |||
442 | */ | |||
443 | msg_t *nua_saved_event_request(nua_saved_event_t const *saved) | |||
444 | { | |||
445 | return saved && saved[0] ? su_msg_data(saved)->ee_data->e_msg : NULL((void*)0); | |||
446 | } | |||
447 | ||||
448 | /** Save nua event and its arguments. | |||
449 | * | |||
450 | * @sa #nua_event_e, nua_event_data() nua_saved_event_request(), nua_destroy_event() | |||
451 | */ | |||
452 | int nua_save_event(nua_t *nua, nua_saved_event_t return_saved[1]) | |||
453 | { | |||
454 | if (return_saved) { | |||
455 | if (nua && nua->nua_current) { | |||
456 | su_msg_save(return_saved, nua->nua_current->nf_saved); | |||
457 | return su_msg_is_non_null(return_saved); | |||
458 | } | |||
459 | else | |||
460 | *return_saved = NULL((void*)0); | |||
461 | } | |||
462 | ||||
463 | return 0; | |||
464 | } | |||
465 | ||||
466 | /* ---------------------------------------------------------------------- */ | |||
467 | ||||
468 | /** @internal | |||
469 | * Post signal to stack itself | |||
470 | */ | |||
471 | void nua_stack_post_signal(nua_handle_t *nh, nua_event_t event, | |||
472 | tag_type_t tag, tag_value_t value, ...) | |||
473 | { | |||
474 | ta_list ta; | |||
475 | 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); | |||
476 | nua_signal((nh)->nh_nua, nh, NULL((void*)0), event, 0, NULL((void*)0), ta_tags(ta)(ta).tl[0].t_tag, (ta).tl[0].t_value, (ta).tl[1].t_tag, (ta). tl[1].t_value); | |||
477 | 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)); | |||
478 | } | |||
479 | ||||
480 | ||||
481 | /*# Send a request to the protocol thread */ | |||
482 | int nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg, | |||
483 | nua_event_t event, | |||
484 | int status, char const *phrase, | |||
485 | tag_type_t tag, tag_value_t value, ...) | |||
486 | { | |||
487 | su_msg_r sumsg = SU_MSG_R_INIT{ ((void*)0) }; | |||
488 | size_t len, xtra, ee_len, l_len = 0, l_xtra = 0; | |||
489 | ta_list ta; | |||
490 | int retval = -1; | |||
491 | ||||
492 | if (nua == NULL((void*)0)) | |||
493 | return -1; | |||
494 | ||||
495 | if (nua->nua_shutdown_started && event != nua_r_shutdown) | |||
496 | return -1; | |||
497 | ||||
498 | 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); | |||
499 | ||||
500 | ee_len = offsetof(nua_ee_data_t, ee_data[0].e_tags)__builtin_offsetof(nua_ee_data_t, ee_data[0].e_tags); | |||
501 | len = tl_len(ta_args(ta)(ta).tl); | |||
502 | xtra = tl_xtra(ta_args(ta)(ta).tl, len); | |||
503 | ||||
504 | if (su_msg_new(sumsg, ee_len + len + l_len + xtra + l_xtra) == 0) { | |||
505 | nua_ee_data_t *ee = su_msg_data(sumsg); | |||
506 | nua_event_data_t *e = ee->ee_data; | |||
507 | tagi_t *t = e->e_tags; | |||
508 | void *b = (char *)t + len + l_len; | |||
509 | ||||
510 | tagi_t *tend = (tagi_t *)b; | |||
511 | char *bend = (char *)b + xtra + l_xtra; | |||
512 | ||||
513 | t = tl_dup(t, ta_args(ta)(ta).tl, &b); | |||
514 | ||||
515 | assert(tend == t)((tend == t) ? (void) (0) : __assert_fail ("tend == t", "nua_stack.c" , 515, __PRETTY_FUNCTION__)); (void)tend; assert(b == bend)((b == bend) ? (void) (0) : __assert_fail ("b == bend", "nua_stack.c" , 515, __PRETTY_FUNCTION__)); (void)bend; | |||
516 | ||||
517 | e->e_always = event == nua_r_destroy || event == nua_r_shutdown; | |||
518 | e->e_event = event; | |||
519 | e->e_nh = nh ? nua_handle_ref(nh) : NULL((void*)0); | |||
520 | e->e_status = status; | |||
521 | e->e_phrase = phrase; | |||
522 | ||||
523 | su_msg_deinitializer(sumsg, nua_event_deinit); | |||
524 | ||||
525 | retval = su_msg_send_to(sumsg, nua->nua_server, nua_stack_signal); | |||
526 | ||||
527 | if (retval == 0){ | |||
528 | SU_DEBUG_7(("nua(%p): %s signal %s\n", (void *)nh,((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 7 ? (_su_llog((nua_log), 7, "nua_stack.c", ( const char *)__func__, 529, "nua(%p): %s signal %s\n", (void * )nh, "sent", nua_event_name(event) + 4)) : (void)0) | |||
529 | "sent", nua_event_name(event) + 4))((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 7 ? (_su_llog((nua_log), 7, "nua_stack.c", ( const char *)__func__, 529, "nua(%p): %s signal %s\n", (void * )nh, "sent", nua_event_name(event) + 4)) : (void)0); | |||
530 | } | |||
531 | else { | |||
532 | SU_DEBUG_0(("nua(%p): %s signal %s\n", (void *)nh,((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 0 ? (_su_llog((nua_log), 0, "nua_stack.c", ( const char *)__func__, 533, "nua(%p): %s signal %s\n", (void * )nh, "FAILED TO SEND", nua_event_name(event) + 4)) : (void)0) | |||
533 | "FAILED TO SEND", nua_event_name(event) + 4))((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 0 ? (_su_llog((nua_log), 0, "nua_stack.c", ( const char *)__func__, 533, "nua(%p): %s signal %s\n", (void * )nh, "FAILED TO SEND", nua_event_name(event) + 4)) : (void)0); | |||
534 | ||||
535 | } | |||
536 | } | |||
537 | ||||
538 | 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)); | |||
539 | ||||
540 | return retval; | |||
541 | } | |||
542 | ||||
543 | /* ---------------------------------------------------------------------- | |||
544 | * Receiving events from client | |||
545 | */ | |||
546 | static | |||
547 | void nua_stack_signal(nua_t *nua, su_msg_r msg, nua_ee_data_t *ee) | |||
548 | { | |||
549 | nua_event_data_t *e = ee->ee_data; | |||
550 | nua_handle_t *nh = e->e_nh; | |||
| ||||
551 | tagi_t *tags = e->e_tags; | |||
552 | nua_event_t event; | |||
553 | int error = 0; | |||
554 | ||||
555 | if (nh) { | |||
556 | if (!nh->nh_prev) | |||
557 | nh_append(nua, nh); | |||
558 | if (!nh->nh_ref_by_stack) { | |||
559 | /* Mark handle as used by stack */ | |||
560 | nh->nh_ref_by_stack = 1; | |||
561 | nua_handle_ref(nh); | |||
562 | } | |||
563 | } | |||
564 | ||||
565 | if (nua_log->log_level >= 5) { | |||
566 | char const *name = nua_event_name((enum nua_event_e)e->e_event); | |||
567 | ||||
568 | if (e->e_status == 0) | |||
569 | SU_DEBUG_5(("nua(%p): %s signal %s\n", (void *)nh, "recv", name + 4))((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_stack.c", ( const char *)__func__, 569, "nua(%p): %s signal %s\n", (void * )nh, "recv", name + 4)) : (void)0); | |||
570 | else | |||
571 | SU_DEBUG_5(("nua(%p): recv signal %s %u %s\n",((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_stack.c", ( const char *)__func__, 573, "nua(%p): recv signal %s %u %s\n" , (void *)nh, name + 4, e->e_status, e->e_phrase ? e-> e_phrase : "")) : (void)0) | |||
572 | (void *)nh, name + 4,((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_stack.c", ( const char *)__func__, 573, "nua(%p): recv signal %s %u %s\n" , (void *)nh, name + 4, e->e_status, e->e_phrase ? e-> e_phrase : "")) : (void)0) | |||
573 | e->e_status, e->e_phrase ? e->e_phrase : ""))((((nua_log) != ((void*)0) && (nua_log)->log_init) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 5 ? (_su_llog((nua_log), 5, "nua_stack.c", ( const char *)__func__, 573, "nua(%p): recv signal %s %u %s\n" , (void *)nh, name + 4, e->e_status, e->e_phrase ? e-> e_phrase : "")) : (void)0); | |||
574 | } | |||
575 | ||||
576 | su_msg_save(nua->nua_signal, msg); | |||
577 | ||||
578 | event = (enum nua_event_e)e->e_event; | |||
579 | ||||
580 | if (nua->nua_shutdown && !e->e_always) { | |||
581 | /* Shutting down */ | |||
582 | nua_stack_event(nua, nh, NULL((void*)0), event, | |||
583 | 901, "Stack is going down", | |||
584 | NULL((void*)0)); | |||
585 | } | |||
586 | else switch (event) { | |||
587 | case nua_r_get_params: | |||
588 | nua_stack_get_params(nua, nh ? nh : nua->nua_dhandlenua_handles, event, tags); | |||
589 | break; | |||
590 | case nua_r_set_params: | |||
591 | nua_stack_set_params(nua, nh ? nh : nua->nua_dhandlenua_handles, event, tags); | |||
592 | break; | |||
593 | case nua_r_shutdown: | |||
594 | nua_stack_shutdown(nua); | |||
595 | break; | |||
596 | case nua_r_register: | |||
597 | case nua_r_unregister: | |||
598 | nua_stack_register(nua, nh, event, tags); | |||
599 | break; | |||
600 | case nua_r_invite: | |||
601 | error = nua_stack_invite(nua, nh, event, tags); | |||
602 | break; | |||
603 | case nua_r_cancel: | |||
604 | error = nua_stack_cancel(nua, nh, event, tags); | |||
605 | break; | |||
606 | case nua_r_bye: | |||
607 | error = nua_stack_bye(nua, nh, event, tags); | |||
608 | break; | |||
609 | case nua_r_options: | |||
610 | error = nua_stack_options(nua, nh, event, tags); | |||
611 | break; | |||
612 | case nua_r_refer: | |||
613 | error = nua_stack_refer(nua, nh, event, tags); | |||
614 | break; | |||
615 | case nua_r_publish: | |||
616 | case nua_r_unpublish: | |||
617 | error = nua_stack_publish(nua, nh, event, tags); | |||
618 | break; | |||
619 | case nua_r_info: | |||
620 | error = nua_stack_info(nua, nh, event, tags); | |||
621 | break; | |||
622 | case nua_r_prack: | |||
623 | error = nua_stack_prack(nua, nh, event, tags); | |||
624 | break; | |||
625 | case nua_r_update: | |||
626 | error = nua_stack_update(nua, nh, event, tags); | |||
627 | break; | |||
628 | case nua_r_message: | |||
629 | error = nua_stack_message(nua, nh, event, tags); | |||
630 | break; | |||
631 | case nua_r_subscribe: | |||
632 | case nua_r_unsubscribe: | |||
633 | error = nua_stack_subscribe(nua, nh, event, tags); | |||
634 | break; | |||
635 | case nua_r_notify: | |||
636 | error = nua_stack_notify(nua, nh, event, tags); | |||
637 | break; | |||
638 | case nua_r_notifier: | |||
639 | nua_stack_notifier(nua, nh, event, tags); | |||
640 | break; | |||
641 | case nua_r_terminate: | |||
642 | nua_stack_terminate(nua, nh, event, tags); | |||
643 | break; | |||
644 | case nua_r_method: | |||
645 | error = nua_stack_method(nua, nh, event, tags); | |||
646 | break; | |||
647 | case nua_r_authenticate: | |||
648 | nua_stack_authenticate(nua, nh, event, tags); | |||
649 | break; | |||
650 | case nua_r_authorize: | |||
651 | nua_stack_authorize(nua, nh, event, tags); | |||
652 | break; | |||
653 | case nua_r_ack: | |||
654 | error = nua_stack_ack(nua, nh, event, tags); | |||
655 | break; | |||
656 | case nua_r_respond: | |||
657 | nua_stack_respond(nua, nh, e->e_status, e->e_phrase, tags); | |||
658 | break; | |||
659 | case nua_r_destroy: | |||
660 | if (!nh->nh_destroyed) { | |||
661 | nua_stack_destroy_handle(nua, nh, tags); | |||
662 | su_msg_destroy(nua->nua_signal); | |||
663 | } | |||
664 | return; | |||
665 | default: | |||
666 | break; | |||
667 | } | |||
668 | ||||
669 | if (error < 0) { | |||
670 | nua_stack_event(nh->nh_nua, nh, NULL((void*)0), event, | |||
| ||||
671 | NUA_ERROR_AT(__FILE__, __LINE__)900, "Internal error at " "nua_stack.c" ":" "671", NULL((void*)0)); | |||
672 | } | |||
673 | ||||
674 | su_msg_destroy(nua->nua_signal); | |||
675 | } | |||
676 | ||||
677 | /* ====================================================================== */ | |||
678 | /* Signal and event handling */ | |||
679 | ||||
680 | /** Get event data. | |||
681 | * | |||
682 | * @sa #nua_event_e, nua_event_save(), nua_saved_event_request(), nua_destroy_event(). | |||
683 | */ | |||
684 | nua_event_data_t const *nua_event_data(nua_saved_event_t const saved[1]) | |||
685 | { | |||
686 | return saved && saved[0] ? su_msg_data(saved)->ee_data : NULL((void*)0); | |||
687 | } | |||
688 | ||||
689 | /** Destroy saved event. | |||
690 | * | |||
691 | * @sa #nua_event_e, nua_event_save(), nua_event_data(), nua_saved_event_request(). | |||
692 | */ | |||
693 | void nua_destroy_event(nua_saved_event_t saved[1]) | |||
694 | { | |||
695 | if (saved && saved[0]) su_msg_destroy(saved); | |||
696 | } | |||
697 | ||||
698 | /** @internal Move signal. */ | |||
699 | void nua_move_signal(nua_saved_signal_t a[1], nua_saved_signal_t b[1]) | |||
700 | { | |||
701 | su_msg_save(a, b); | |||
702 | } | |||
703 | ||||
704 | void nua_destroy_signal(nua_saved_signal_t saved[1]) | |||
705 | { | |||
706 | if (saved) su_msg_destroy(saved); | |||
707 | } | |||
708 | ||||
709 | nua_signal_data_t const *nua_signal_data(nua_saved_signal_t const saved[1]) | |||
710 | { | |||
711 | return nua_event_data(saved); | |||
712 | } | |||
713 | ||||
714 | /* ====================================================================== */ | |||
715 | ||||
716 | static int nh_call_pending(nua_handle_t *nh, sip_time_t time); | |||
717 | ||||
718 | /**@internal | |||
719 | * Timer routine. | |||
720 | * | |||
721 | * Go through all active handles and execute pending tasks | |||
722 | */ | |||
723 | void nua_stack_timer(nua_t *nua, su_timer_t *t, su_timer_arg_t *a) | |||
724 | { | |||
725 | nua_handle_t *nh, *nh_next; | |||
726 | sip_time_t now = sip_now(); | |||
727 | su_root_t *root = su_timer_root(t); | |||
728 | ||||
729 | su_timer_set(t, nua_stack_timer, a); | |||
730 | ||||
731 | if (nua->nua_shutdown) { | |||
732 | nua_stack_shutdown(nua); | |||
733 | return; | |||
734 | } | |||
735 | ||||
736 | for (nh = nua->nua_handles; nh; nh = nh_next) { | |||
737 | nh_next = nh->nh_next; | |||
738 | nh_call_pending(nh, now); | |||
739 | su_root_yield(root); /* Handle received packets */ | |||
740 | } | |||
741 | } | |||
742 | ||||
743 | ||||
744 | static | |||
745 | int nh_call_pending(nua_handle_t *nh, sip_time_t now) | |||
746 | { | |||
747 | nua_dialog_state_t *ds = nh->nh_ds; | |||
748 | nua_dialog_usage_t *du; | |||
749 | sip_time_t next = now + NUA_STACK_TIMER_INTERVAL(1000) / 1000; | |||
750 | ||||
751 | for (du = ds->ds_usage; du; du = du->du_next) { | |||
752 | if (now == 0) | |||
753 | break; | |||
754 | if (du->du_refresh && du->du_refresh < next) | |||
755 | break; | |||
756 | } | |||
757 | ||||
758 | if (du == NULL((void*)0)) | |||
759 | return 0; | |||
760 | ||||
761 | nua_handle_ref(nh); | |||
762 | ||||
763 | while (du) { | |||
764 | nua_dialog_usage_t *du_next = du->du_next; | |||
765 | ||||
766 | nua_dialog_usage_refresh(nh, ds, du, now); | |||
767 | ||||
768 | if (du_next == NULL((void*)0)) | |||
769 | break; | |||
770 | ||||
771 | for (du = nh->nh_ds->ds_usage; du; du = du->du_next) | |||
772 | if (du == du_next) | |||
773 | break; | |||
774 | ||||
775 | for (; du; du = du->du_next) { | |||
776 | if (now == 0) | |||
777 | break; | |||
778 | if (du->du_refresh && du->du_refresh < next) | |||
779 | break; | |||
780 | } | |||
781 | } | |||
782 | ||||
783 | nua_handle_unref(nh); | |||
784 | ||||
785 | return 1; | |||
786 | } | |||
787 | ||||
788 | ||||
789 | ||||
790 | /* ====================================================================== */ | |||
791 | ||||
792 | /**Shutdown a @nua stack. | |||
793 | * | |||
794 | * When the @nua stack is shutdown, ongoing calls are released, | |||
795 | * registrations unregistered, publications un-PUBLISHed and subscriptions | |||
796 | * terminated. If the stack cannot terminate everything within 30 seconds, | |||
797 | * it sends the #nua_r_shutdown event with status 500. | |||
798 | * | |||
799 | * @param nua Pointer to @nua stack object | |||
800 | * | |||
801 | * @return | |||
802 | * nothing | |||
803 | * | |||
804 | * @par Related tags: | |||
805 | * none | |||
806 | * | |||
807 | * @par Events: | |||
808 | * #nua_r_shutdown | |||
809 | * | |||
810 | * @sa #nua_r_shutdown, nua_destroy(), nua_create(), nua_bye(), | |||
811 | * nua_unregister(), nua_unpublish(), nua_unsubscribe(), nua_notify(), | |||
812 | * nua_handle_destroy(), nua_handle_unref() | |||
813 | */ | |||
814 | ||||
815 | /** @NUA_EVENT nua_r_shutdown | |||
816 | * | |||
817 | * Answer to nua_shutdown(). | |||
818 | * | |||
819 | * Status codes | |||
820 | * - 100 shutdown started | |||
821 | * - 101 shutdown in progress (sent when shutdown has been progressed) | |||
822 | * - 200 shutdown was successful | |||
823 | * - 500 shutdown timeout after 30 sec | |||
824 | * | |||
825 | * @param status shutdown status code | |||
826 | * @param nh NULL | |||
827 | * @param hmagic NULL | |||
828 | * @param sip NULL | |||
829 | * @param tags empty | |||
830 | * | |||
831 | * @sa nua_shutdown(), nua_destroy() | |||
832 | * | |||
833 | * @END_NUA_EVENT | |||
834 | */ | |||
835 | ||||
836 | /** @internal Shut down stack. */ | |||
837 | void nua_stack_shutdown(nua_t *nua) | |||
838 | { | |||
839 | nua_handle_t *nh, *nh_next; | |||
840 | int busy = 0; | |||
841 | sip_time_t now = sip_now(); | |||
842 | int status; | |||
843 | char const *phrase; | |||
844 | ||||
845 | enter(void)((((nua_log) != ((void*)0) && (nua_log)->log_init ) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 9 ? (_su_llog((nua_log), 9, "nua_stack.c", ( const char *)__func__, 845, "nua: %s: entering\n", __func__)) : (void)0); | |||
846 | ||||
847 | if (!nua->nua_shutdown) | |||
848 | nua->nua_shutdown = now; | |||
849 | ||||
850 | for (nh = nua->nua_handles; nh; nh = nh_next) { | |||
851 | nua_dialog_state_t *ds = nh->nh_ds; | |||
852 | ||||
853 | nh_next = nh->nh_next; | |||
854 | ||||
855 | busy += nua_dialog_repeat_shutdown(nh, ds); | |||
856 | ||||
857 | if (nh->nh_soa) { | |||
858 | soa_destroy(nh->nh_soa), nh->nh_soa = NULL((void*)0); | |||
859 | } | |||
860 | ||||
861 | if (nua_client_request_pending(ds->ds_cr)) | |||
862 | busy++; | |||
863 | ||||
864 | if (nh_notifier_shutdown(nh, NULL((void*)0), NEATAG_REASON("noresource")neatag_reason, tag_str_v(("noresource")), TAG_END()(tag_type_t)0, (tag_value_t)0)) | |||
865 | busy++; | |||
866 | } | |||
867 | ||||
868 | if (!busy) | |||
869 | SET_STATUS(200, "Shutdown successful")status = 200, phrase = "Shutdown successful"; | |||
870 | else if (now == nua->nua_shutdown) | |||
871 | SET_STATUS(100, "Shutdown started")status = 100, phrase = "Shutdown started"; | |||
872 | else if (now - nua->nua_shutdown < 30) | |||
873 | SET_STATUS(101, "Shutdown in progress")status = 101, phrase = "Shutdown in progress"; | |||
874 | else | |||
875 | SET_STATUS(500, "Shutdown timeout")status = 500, phrase = "Shutdown timeout"; | |||
876 | ||||
877 | if (status >= 200) { | |||
878 | for (nh = nua->nua_handles; nh; nh = nh_next) { | |||
879 | nh_next = nh->nh_next; | |||
880 | while (nh->nh_ds && nh->nh_ds->ds_usage) { | |||
881 | nua_dialog_usage_remove(nh, nh->nh_ds, nh->nh_ds->ds_usage, NULL((void*)0), NULL((void*)0)); | |||
882 | } | |||
883 | } | |||
884 | su_timer_destroy(nua->nua_timer), nua->nua_timer = NULL((void*)0); | |||
885 | nta_agent_destroy(nua->nua_nta), nua->nua_nta = NULL((void*)0); | |||
886 | } | |||
887 | ||||
888 | nua_stack_event(nua, NULL((void*)0), NULL((void*)0), nua_r_shutdown, status, phrase, NULL((void*)0)); | |||
889 | } | |||
890 | ||||
891 | /* ---------------------------------------------------------------------- */ | |||
892 | ||||
893 | /** @internal Create a handle */ | |||
894 | nua_handle_t *nh_create(nua_t *nua, tag_type_t tag, tag_value_t value, ...) | |||
895 | { | |||
896 | ta_list ta; | |||
897 | nua_handle_t *nh; | |||
898 | ||||
899 | enter(void)((((nua_log) != ((void*)0) && (nua_log)->log_init ) == 0 ? 9 : (((nua_log) != ((void*)0) && (nua_log)-> log_init > 1) ? (nua_log)->log_level : su_log_default-> log_level)) >= 9 ? (_su_llog((nua_log), 9, "nua_stack.c", ( const char *)__func__, 899, "nua: %s: entering\n", __func__)) : (void)0); | |||
900 | ||||
901 | 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); | |||
902 | nh = nh_create_handle(nua, NULL((void*)0), ta_args(ta)(ta).tl); | |||
903 | 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)); | |||
904 | ||||
905 | if (nh) { | |||
906 | nh->nh_ref_by_stack = 1; | |||
907 | nh_append(nua, nh); | |||
908 | } | |||
909 | ||||
910 | return nh; | |||
911 | } | |||
912 | ||||
913 | /** @internal Append a handle to the list of handles */ | |||
914 | void nh_append(nua_t *nua, nua_handle_t *nh) | |||
915 | { | |||
916 | nh->nh_next = NULL((void*)0); | |||
917 | nh->nh_prev = nua->nua_handles_tail; | |||
918 | *nua->nua_handles_tail = nh; | |||
919 | nua->nua_handles_tail = &nh->nh_next; | |||
920 | } | |||
921 | ||||
922 | nua_handle_t *nh_validate(nua_t *nua, nua_handle_t *maybe) | |||
923 | { | |||
924 | nua_handle_t *nh; | |||
925 | ||||
926 | if (maybe) | |||
927 | for (nh = nua->nua_handles; nh; nh = nh->nh_next) | |||
928 | if (nh == maybe) | |||
929 | return nh; | |||
930 | ||||
931 | return NULL((void*)0); | |||
932 | } | |||
933 | ||||
934 | void nua_stack_destroy_handle(nua_t *nua, nua_handle_t *nh, tagi_t const *tags) | |||
935 | { | |||
936 | if (nh->nh_destroyed) { | |||
937 | return; | |||
938 | } | |||
939 | ||||
940 | if (nh->nh_notifier) | |||
941 | nua_stack_terminate(nua, nh, (enum nua_event_e)0, NULL((void*)0)); | |||
942 | ||||
943 | nua_dialog_shutdown(nh, nh->nh_ds); | |||
944 | ||||
945 | if (nh->nh_ref_by_user) { | |||
946 | nh->nh_ref_by_user = 0; | |||
947 | nua_handle_unref(nh); | |||
948 | } | |||
949 | ||||
950 | nh_destroy(nua, nh); | |||
951 | } | |||
952 | ||||
953 | #define nh_is_inserted(nh)((nh)->nh_prev != ((void*)0)) ((nh)->nh_prev != NULL((void*)0)) | |||
954 | ||||
955 | /** @internal Remove a handle from list of handles */ | |||
956 | static | |||
957 | void nh_remove(nua_t *nua, nua_handle_t *nh) | |||
958 | { | |||
959 | assert(nh_is_inserted(nh))((((nh)->nh_prev != ((void*)0))) ? (void) (0) : __assert_fail ("((nh)->nh_prev != ((void*)0))", "nua_stack.c", 959, __PRETTY_FUNCTION__ )); assert(*nh->nh_prev == nh)((*nh->nh_prev == nh) ? (void) (0) : __assert_fail ("*nh->nh_prev == nh" , "nua_stack.c", 959, __PRETTY_FUNCTION__)); | |||
960 | ||||
961 | if (nh->nh_next) | |||
962 | nh->nh_next->nh_prev = nh->nh_prev; | |||
963 | else | |||
964 | nua->nua_handles_tail = nh->nh_prev; | |||
965 | ||||
966 | *nh->nh_prev = nh->nh_next; | |||
967 | ||||
968 | nh->nh_prev = NULL((void*)0); | |||
969 | nh->nh_next = NULL((void*)0); | |||
970 | } | |||
971 | ||||
972 | ||||
973 | void nh_destroy(nua_t *nua, nua_handle_t *nh) | |||
974 | { | |||
975 | assert(nh)((nh) ? (void) (0) : __assert_fail ("nh", "nua_stack.c", 975, __PRETTY_FUNCTION__)); assert(nh != nua->nua_dhandle)((nh != nua->nua_handles) ? (void) (0) : __assert_fail ("nh != nua->nua_handles" , "nua_stack.c", 975, __PRETTY_FUNCTION__)); | |||
976 | ||||
977 | if (nh->nh_destroyed) { | |||
978 | return; | |||
979 | } | |||
980 | ||||
981 | nh->nh_destroyed = 1; | |||
982 | ||||
983 | if (nh->nh_notifier) | |||
984 | nea_server_destroy(nh->nh_notifier), nh->nh_notifier = NULL((void*)0); | |||
985 | ||||
986 | while (nh->nh_ds->ds_cr) | |||
987 | nua_client_request_complete(nh->nh_ds->ds_cr); | |||
988 | ||||
989 | while (nh->nh_ds->ds_sr) | |||
990 | nua_server_request_destroy(nh->nh_ds->ds_sr); | |||
991 | ||||
992 | nua_dialog_deinit(nh, nh->nh_ds); | |||
993 | ||||
994 | if (nh->nh_soa) | |||
995 | soa_destroy(nh->nh_soa), nh->nh_soa = NULL((void*)0); | |||
996 | ||||
997 | if (nh_is_inserted(nh)((nh)->nh_prev != ((void*)0))) | |||
998 | nh_remove(nua, nh); | |||
999 | ||||
1000 | nua_handle_unref(nh); /* Remove stack reference */ | |||
1001 | } | |||
1002 | ||||
1003 | /* ======================================================================== */ | |||
1004 | ||||
1005 | /** @internal Create a handle for processing incoming request */ | |||
1006 | nua_handle_t *nua_stack_incoming_handle(nua_t *nua, | |||
1007 | nta_incoming_t *irq, | |||
1008 | sip_t const *sip, | |||
1009 | int create_dialog) | |||
1010 | { | |||
1011 | nua_handle_t *nh; | |||
1012 | url_t const *url; | |||
1013 | sip_to_t to[1]; | |||
1014 | sip_from_t from[1]; | |||
1015 | ||||
1016 | assert(sip && sip->sip_from && sip->sip_to)((sip && sip->sip_from && sip->sip_to) ? (void) (0) : __assert_fail ("sip && sip->sip_from && sip->sip_to" , "nua_stack.c", 1016, __PRETTY_FUNCTION__)); | |||
1017 | ||||
1018 | if (sip->sip_contact) | |||
1019 | url = sip->sip_contact->m_url; | |||
1020 | else | |||
1021 | url = sip->sip_from->a_url; | |||
1022 | ||||
1023 | /* Strip away parameters */ | |||
1024 | sip_from_init(from)->a_display = sip->sip_to->a_display; | |||
1025 | *from->a_url = *sip->sip_to->a_url; | |||
1026 | ||||
1027 | sip_to_init(to)->a_display = sip->sip_from->a_display; | |||
1028 | *to->a_url = *sip->sip_from->a_url; | |||
1029 | ||||
1030 | nh = nh_create(nua, | |||
1031 | NUTAG_URL((url_string_t *)url)nutag_url, urltag_url_v((url_string_t *)url), /* Remote target */ | |||
1032 | SIPTAG_TO(to)siptag_to, siptag_to_v(to), /* Local AoR */ | |||
1033 | SIPTAG_FROM(from)siptag_from, siptag_from_v(from), /* Remote AoR */ | |||
1034 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||
1035 | ||||
1036 | if (nh && nua_stack_init_handle(nua, nh, NULL((void*)0)) < 0) | |||
1037 | nh_destroy(nua, nh), nh = NULL((void*)0); | |||
1038 | ||||
1039 | if (nh && create_dialog) { | |||
1040 | struct nua_dialog_state *ds = nh->nh_ds; | |||
1041 | ||||
1042 | nua_dialog_store_peer_info(nh, ds, sip); | |||
1043 | ||||
1044 | ds->ds_leg = nta_leg_tcreate(nua->nua_nta, nua_stack_process_request, nh, | |||
1045 | SIPTAG_CALL_ID(sip->sip_call_id)siptag_call_id, siptag_call_id_v(sip->sip_call_id), | |||
1046 | SIPTAG_FROM(sip->sip_to)siptag_from, siptag_from_v(sip->sip_to), | |||
1047 | SIPTAG_TO(sip->sip_from)siptag_to, siptag_to_v(sip->sip_from), | |||
1048 | NTATAG_REMOTE_CSEQ(sip->sip_cseq->cs_seq)ntatag_remote_cseq, tag_uint_v((sip->sip_cseq->cs_seq)), | |||
1049 | TAG_END()(tag_type_t)0, (tag_value_t)0); | |||
1050 | ||||
1051 | if (!ds->ds_leg || !nta_leg_tag(ds->ds_leg, nta_incoming_tag(irq, NULL((void*)0)))) | |||
1052 | nh_destroy(nua, nh), nh = NULL((void*)0); | |||
1053 | } | |||
1054 | ||||
1055 | if (nh) | |||
1056 | nua_dialog_uas_route(nh, nh->nh_ds, sip, 1); | |||
1057 | ||||
1058 | return nh; | |||
1059 | } | |||
1060 | ||||
1061 | ||||
1062 | /** Set flags and special event on handle. | |||
1063 | * | |||
1064 | * @retval 0 when successful | |||
1065 | * @retval -1 upon an error | |||
1066 | */ | |||
1067 | int nua_stack_set_handle_special(nua_handle_t *nh, | |||
1068 | enum nh_kind kind, | |||
1069 | nua_event_t special) | |||
1070 | { | |||
1071 | if (nh == NULL((void*)0)) | |||
1072 | return -1; | |||
1073 | ||||
1074 | if (special && nh->nh_special && nh->nh_special != special) | |||
1075 | return -1; | |||
1076 | ||||
1077 | if (!nh_is_special(nh) && !nh->nh_has_invite) { | |||
1078 | switch (kind) { | |||
1079 | case nh_has_invite: nh->nh_has_invite = 1; break; | |||
1080 | case nh_has_subscribe: nh->nh_has_subscribe = 1; break; | |||
1081 | case nh_has_notify: nh->nh_has_notify = 1; break; | |||
1082 | case nh_has_register: nh->nh_has_register = 1; break; | |||
1083 | case nh_has_nothing: | |||
1084 | default: | |||
1085 | break; | |||
1086 | } | |||
1087 | ||||
1088 | if (special) | |||
1089 | nh->nh_special = special; | |||
1090 | } | |||
1091 | ||||
1092 | return 0; | |||
1093 | } | |||
1094 | ||||
1095 | sip_replaces_t *nua_stack_handle_make_replaces(nua_handle_t *nh, | |||
1096 | su_home_t *home, | |||
1097 | int early_only) | |||
1098 | { | |||
1099 | if (nh && nh->nh_ds && nh->nh_ds->ds_leg) | |||
1100 | return nta_leg_make_replaces(nh->nh_ds->ds_leg, home, early_only); | |||
1101 | else | |||
1102 | return NULL((void*)0); | |||
1103 | } | |||
1104 | ||||
1105 | nua_handle_t *nua_stack_handle_by_replaces(nua_t *nua, | |||
1106 | sip_replaces_t const *r) | |||
1107 | { | |||
1108 | if (nua) { | |||
1109 | nta_leg_t *leg = nta_leg_by_replaces(nua->nua_nta, r); | |||
1110 | if (leg) | |||
1111 | return nta_leg_magic(leg, nua_stack_process_request); | |||
1112 | } | |||
1113 | return NULL((void*)0); | |||
1114 | } | |||
1115 | ||||
1116 | nua_handle_t *nua_stack_handle_by_call_id(nua_t *nua, const char *call_id) | |||
1117 | { | |||
1118 | if (nua) { | |||
1119 | nta_leg_t *leg = nta_leg_by_call_id(nua->nua_nta, call_id); | |||
1120 | if (leg) | |||
1121 | return nta_leg_magic(leg, nua_stack_process_request); | |||
1122 | } | |||
1123 | return NULL((void*)0); | |||
1124 | } |