Bug Summary

File:nua_stack.c
Warning:line 694, column 21
Access to field 'nh_nua' results in a dereference of a null pointer (loaded from variable 'nh')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name nua_stack.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-11/lib/clang/11.0.1 -D HAVE_CONFIG_H -I . -I ../.. -I ../../libsofia-sip-ua/su/sofia-sip -I ../../libsofia-sip-ua/features -I ../../libsofia-sip-ua/features -I ../../libsofia-sip-ua/ipt -I ../../libsofia-sip-ua/ipt -I ../../libsofia-sip-ua/iptsec -I ../../libsofia-sip-ua/iptsec -I ../../libsofia-sip-ua/bnf -I ../../libsofia-sip-ua/bnf -I ../../libsofia-sip-ua/http -I ../../libsofia-sip-ua/http -I ../../libsofia-sip-ua/msg -I ../../libsofia-sip-ua/msg -I ../../libsofia-sip-ua/nth -I ../../libsofia-sip-ua/nth -I ../../libsofia-sip-ua/nta -I ../../libsofia-sip-ua/nta -I ../../libsofia-sip-ua/nea -I ../../libsofia-sip-ua/nea -I ../../libsofia-sip-ua/nua -I ../../libsofia-sip-ua/nua -I ../../libsofia-sip-ua/soa -I ../../libsofia-sip-ua/soa -I ../../libsofia-sip-ua/sdp -I ../../libsofia-sip-ua/sdp -I ../../libsofia-sip-ua/sip -I ../../libsofia-sip-ua/sip -I ../../libsofia-sip-ua/soa -I ../../libsofia-sip-ua/soa -I ../../libsofia-sip-ua/sresolv -I ../../libsofia-sip-ua/sresolv -I ../../libsofia-sip-ua/tport -I ../../libsofia-sip-ua/tport -I ../../libsofia-sip-ua/stun -I ../../libsofia-sip-ua/stun -I ../../libsofia-sip-ua/url -I ../../libsofia-sip-ua/url -I ../../libsofia-sip-ua/su -I ../../libsofia-sip-ua/su -I ../../s2check -D SU_DEBUG=0 -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-11/lib/clang/11.0.1/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /drone/src/libsofia-sip-ua/nua -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -faddrsig -o /drone/src/scan-build/2023-09-14-191556-13-1 -x c nua_stack.c
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 */
91struct nua_event_frame_s {
92 nua_event_frame_t *nf_next;
93 nua_saved_event_t nf_saved[1];
94};
95
96
97static void nua_event_deinit(nua_ee_data_t *ee);
98static void nua_application_event(nua_t *, su_msg_r, nua_ee_data_t *ee);
99static void nua_stack_signal(nua_t *nua, su_msg_r, nua_ee_data_t *ee);
100
101nua_handle_t *nh_create(nua_t *nua, tag_type_t t, tag_value_t v, ...);
102static void nh_append(nua_t *nua, nua_handle_t *nh);
103static void nh_remove(nua_t *nua, nua_handle_t *nh);
104
105static 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. */
111char const nua_internal_error[] = "Internal NUA Error";
112
113char const nua_application_sdp[] = "application/sdp";
114
115#define NUA_STACK_TIMER_INTERVAL(1000) (1000)
116
117/* ----------------------------------------------------------------------
118 * Initialization & deinitialization
119 */
120
121int 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
210void nua_stack_deinit(su_root_t *root, nua_t *nua)
211{
212 nua_handle_t *nh, *nh_next;
213
214 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__, 214, "nua: %s: entering\n", __func__))
: (void)0)
;
215
216 su_task_deinit(nua->nua_server);
217 su_task_deinit(nua->nua_client);
218
219 su_timer_destroy(nua->nua_timer), nua->nua_timer = NULL((void*)0);
220 nta_agent_destroy(nua->nua_nta), nua->nua_nta = NULL((void*)0);
221
222 for (nh = nua->nua_handles; nh; nh = nh_next) {
223 nh_next = nh->nh_next;
224
225 if (nh->nh_soa) {
226 soa_destroy(nh->nh_soa), nh->nh_soa = NULL((void*)0);
227 }
228
229 /* Cleanup remaining nua handles as they are su_home_new'ed and not su_home_cloned (do not belong to the nua's home)
230 See nh_create_handle().
231 At least one handle will be found here and it is nua default handle
232 which is su_home_cloned (see nua_stack_init()) and therefore does not actually require to be unrefed.
233 Nua is about to die so we don't remove nh from nua, just unref nh */
234 if (nh != nua->nua_handles) {
235 su_home_t *nh_home = (su_home_t *)nh;
236
237 SU_DEBUG_9(("nua(%p): found handle with refcount = "MOD_ZU". Destroying.\n", (void *)nh, su_home_refcount(nh_home)))((((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__, 237, "nua(%p): found handle with refcount = "
"%zu"". Destroying.\n", (void *)nh, su_home_refcount(nh_home)
)) : (void)0)
;
238 while(!su_home_unref(nh_home));
239 }
240 }
241
242#if HAVE_SMIME /* Start NRC Boston */
243 sm_destroy(nua->sm);
244#endif /* End NRC Boston */
245
246}
247
248/* ----------------------------------------------------------------------
249 * Sending events to client application
250 */
251
252static void nua_stack_shutdown(nua_t *);
253
254void
255 nua_stack_authenticate(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *),
256 nua_stack_respond(nua_t *, nua_handle_t *, int , char const *, tagi_t const *),
257 nua_stack_destroy_handle(nua_t *, nua_handle_t *, tagi_t const *);
258
259/* Notifier */
260void
261 nua_stack_authorize(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *),
262 nua_stack_notifier(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *),
263 nua_stack_terminate(nua_t *, nua_handle_t *, nua_event_t, tagi_t const *);
264
265int nh_notifier_shutdown(nua_handle_t *nh, nea_event_t *ev,
266 tag_type_t t, tag_value_t v, ...);
267
268int nua_stack_tevent(nua_t *nua, nua_handle_t *nh, msg_t *msg,
269 nua_event_t event, int status, char const *phrase,
270 tag_type_t tag, tag_value_t value, ...)
271{
272 ta_list ta;
273 int retval;
274 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)
;
275 retval = nua_stack_event(nua, nh, msg, event, status, phrase, ta_args(ta)(ta).tl);
276 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))
;
277 return retval;
278}
279
280/** @internal Send an event to the application. */
281int nua_stack_event(nua_t *nua, nua_handle_t *nh, msg_t *msg,
282 nua_event_t event, int status, char const *phrase,
283 tagi_t const *tags)
284{
285 su_msg_r sumsg = SU_MSG_R_INIT{ ((void*)0) };
286 size_t e_len, len, xtra, p_len;
287
288 if (event == nua_r_ack || event == nua_i_none)
289 return event;
290
291 if (nh == nua->nua_dhandlenua_handles)
292 nh = NULL((void*)0);
293
294 if (nua_log->log_level >= 5) {
295 char const *name = nua_event_name(event) + 4;
296 char const *p = phrase ? phrase : "";
297
298 if (status == 0)
299 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__, 299, "nua(%p): event %s %s\n", (void *
)nh, name, p)) : (void)0)
;
300 else
301 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__, 301, "nua(%p): event %s %u %s\n", (void
*)nh, name, status, p)) : (void)0)
;
302 }
303
304 if (event == nua_r_destroy) {
305 if (msg)
306 msg_destroy(msg);
307 if (status >= 200) {
308 nh_destroy(nua, nh);
309 }
310 return event;
311 }
312
313 if ((event > nua_r_authenticate && event <= nua_r_ack)
314 || event < nua_i_error
315 || (nh && !nh->nh_valid)
316 || (nua->nua_shutdown && event != nua_r_shutdown &&
317 !nua->nua_prefs->ngp_shutdown_events)) {
318 if (msg)
319 msg_destroy(msg);
320 return event;
321 }
322
323 if (tags) {
324 e_len = offsetof(nua_ee_data_t, ee_data[0].e_tags)__builtin_offsetof(nua_ee_data_t, ee_data[0].e_tags);
325 len = tl_len(tags);
326 xtra = tl_xtra(tags, len);
327 }
328 else {
329 e_len = sizeof(nua_ee_data_t), len = 0, xtra = 0;
330 }
331 p_len = phrase ? strlen(phrase) + 1 : 1;
332
333 if (su_msg_new(sumsg, e_len + len + xtra + p_len) == 0) {
334 nua_ee_data_t *ee = su_msg_data(sumsg);
335 nua_event_data_t *e = ee->ee_data;
336 void *p;
337
338 if (tags) {
339 tagi_t *t = e->e_tags, *t_end = (tagi_t *)((char *)t + len);
340 void *b = t_end, *end = (char *)b + xtra;
341
342 t = tl_dup(t, tags, &b); p = b;
343 assert(t == t_end)((void) sizeof ((t == t_end) ? 1 : 0), __extension__ ({ if (t
== t_end) ; else __assert_fail ("t == t_end", "nua_stack.c",
343, __extension__ __PRETTY_FUNCTION__); }))
; assert(b == end)((void) sizeof ((b == end) ? 1 : 0), __extension__ ({ if (b ==
end) ; else __assert_fail ("b == end", "nua_stack.c", 343, __extension__
__PRETTY_FUNCTION__); }))
; (void)end;
344 }
345 else
346 p = ee + 1;
347
348 ee->ee_nua = nua_stack_ref(nua);
349 e->e_event = event;
350 e->e_nh = nh ? nua_handle_ref(nh) : NULL((void*)0);
351 e->e_status = status;
352 e->e_phrase = strcpy(p, phrase ? phrase : "");
353 if (msg)
354 e->e_msg = msg, su_home_threadsafe(msg_home(msg)((su_home_t*)(msg)));
355
356 su_msg_deinitializer(sumsg, nua_event_deinit);
357
358 su_msg_send_to(sumsg, nua->nua_client, nua_application_event);
359 }
360
361 return event;
362}
363
364static
365void nua_event_deinit(nua_ee_data_t *ee)
366{
367 nua_t *nua = ee->ee_nua;
368 nua_event_data_t *e = ee->ee_data;
369 nua_handle_t *nh = e->e_nh;
370
371 if (e->e_msg)
372 msg_destroy(e->e_msg), e->e_msg = NULL((void*)0);
373
374 if (nh)
375 nua_handle_unref(nh), e->e_nh = NULL((void*)0);
376
377 if (nua)
378 nua_stack_unref(nua), ee->ee_nua = NULL((void*)0);
379}
380
381/*# Receive event from protocol machine and hand it over to application */
382static
383void nua_application_event(nua_t *dummy, su_msg_r sumsg, nua_ee_data_t *ee)
384{
385 nua_t *nua = ee->ee_nua;
386 nua_event_data_t *e = ee->ee_data;
387 nua_handle_t *nh = e->e_nh;
388
389 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__, 389, "nua: %s: entering\n", __func__))
: (void)0)
;
390
391 ee->ee_nua = NULL((void*)0);
392 e->e_nh = NULL((void*)0);
393
394 if (nh == NULL((void*)0)) {
395 /* Xyzzy */
396 }
397 else if (nh->nh_valid) {
398 if (!nh->nh_ref_by_user) {
399 /* Application must now call nua_handle_destroy() */
400 nh->nh_ref_by_user = 1;
401 nua_handle_ref(nh);
402 }
403 }
404 else if (!nh->nh_valid) { /* Handle has been destroyed */
405 if (nua_log->log_level >= 7) {
406 char const *name = nua_event_name((enum nua_event_e)e->e_event) + 4;
407 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__, 407, "nua(%p): event %s dropped\n", (void
*)nh, name)) : (void)0)
;
408 }
409 if (nh) nua_handle_unref_user(nh);
410 if (nua) nua_unref_user(nua);
411 return;
412 }
413
414 if (e->e_event == nua_r_shutdown && e->e_status >= 200)
415 nua->nua_shutdown_final = 1;
416
417 if (nua->nua_callback) {
418 nua_event_frame_t frame[1];
419
420 su_msg_save(frame->nf_saved, sumsg);
421 frame->nf_next = nua->nua_current, nua->nua_current = frame;
422
423 nua->nua_callback((enum nua_event_e)e->e_event, e->e_status, e->e_phrase,
424 nua, nua->nua_magic,
425 nh, nh ? nh->nh_magic : NULL((void*)0),
426 e->e_msg ? sip_object(e->e_msg) : NULL((void*)0),
427 e->e_tags);
428
429 if (su_msg_is_non_null(frame->nf_saved)) {
430 su_msg_destroy(frame->nf_saved);
431 }
432 nua->nua_current = frame->nf_next;
433 }
434
435 if (nh) nua_handle_unref_user(nh);
436 if (nua) nua_unref_user(nua);
437}
438
439/** Get current request message. @NEW_1_12_4.
440 *
441 * @note A response message is returned when processing response message.
442 *
443 * @sa #nua_event_e, nua_respond(), NUTAG_WITH_CURRENT()
444 */
445msg_t *nua_current_request(nua_t const *nua)
446{
447 if (nua && nua->nua_current && su_msg_is_non_null(nua->nua_current->nf_saved))
448 return su_msg_data(nua->nua_current->nf_saved)->ee_data->e_msg;
449 return NULL((void*)0);
450}
451
452
453su_msg_t *nua_current_msg(nua_t const *nua, int clear)
454{
455 if (nua && nua->nua_current && su_msg_is_non_null(nua->nua_current->nf_saved)) {
456 su_msg_t *r = nua->nua_current->nf_saved[0];
457 if (clear) {
458 nua->nua_current->nf_saved[0] = NULL((void*)0);
459 }
460 return r;
461 //return su_msg_data(nua->nua_current->nf_saved)->ee_data->e_msg;
462
463 }
464
465 return NULL((void*)0);
466}
467
468
469/** Get request message from saved nua event. @NEW_1_12_4.
470 *
471 * @sa nua_save_event(), nua_respond(), NUTAG_WITH_SAVED(),
472 */
473msg_t *nua_saved_event_request(nua_saved_event_t const *saved)
474{
475 return saved && saved[0] ? su_msg_data(saved)->ee_data->e_msg : NULL((void*)0);
476}
477
478/** Save nua event and its arguments.
479 *
480 * @sa #nua_event_e, nua_event_data() nua_saved_event_request(), nua_destroy_event()
481 */
482int nua_save_event(nua_t *nua, nua_saved_event_t return_saved[1])
483{
484 if (return_saved) {
485 if (nua && nua->nua_current) {
486 su_msg_save(return_saved, nua->nua_current->nf_saved);
487 return su_msg_is_non_null(return_saved);
488 }
489 else
490 *return_saved = NULL((void*)0);
491 }
492
493 return 0;
494}
495
496/* ---------------------------------------------------------------------- */
497
498/** @internal
499 * Post signal to stack itself
500 */
501void nua_stack_post_signal(nua_handle_t *nh, nua_event_t event,
502 tag_type_t tag, tag_value_t value, ...)
503{
504 ta_list ta;
505 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)
;
506 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
);
507 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))
;
508}
509
510
511/*# Send a request to the protocol thread */
512int nua_signal(nua_t *nua, nua_handle_t *nh, msg_t *msg,
513 nua_event_t event,
514 int status, char const *phrase,
515 tag_type_t tag, tag_value_t value, ...)
516{
517 su_msg_r sumsg = SU_MSG_R_INIT{ ((void*)0) };
518 size_t len, xtra, ee_len, l_len = 0, l_xtra = 0;
519 ta_list ta;
520 int retval = -1;
521
522 if (nua == NULL((void*)0))
523 return -1;
524
525 if (nua->nua_shutdown_started && event != nua_r_shutdown && event != nua_r_destroy && event != nua_r_handle_unref && event != nua_r_unref)
526 return -1;
527
528 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)
;
529
530 ee_len = offsetof(nua_ee_data_t, ee_data[0].e_tags)__builtin_offsetof(nua_ee_data_t, ee_data[0].e_tags);
531 len = tl_len(ta_args(ta)(ta).tl);
532 xtra = tl_xtra(ta_args(ta)(ta).tl, len);
533
534 if (su_msg_new(sumsg, ee_len + len + l_len + xtra + l_xtra) == 0) {
535 nua_ee_data_t *ee = su_msg_data(sumsg);
536 nua_event_data_t *e = ee->ee_data;
537 tagi_t *t = e->e_tags;
538 void *b = (char *)t + len + l_len;
539
540 tagi_t *tend = (tagi_t *)b;
541 char *bend = (char *)b + xtra + l_xtra;
542
543 t = tl_dup(t, ta_args(ta)(ta).tl, &b);
544
545 assert(tend == t)((void) sizeof ((tend == t) ? 1 : 0), __extension__ ({ if (tend
== t) ; else __assert_fail ("tend == t", "nua_stack.c", 545,
__extension__ __PRETTY_FUNCTION__); }))
; (void)tend; assert(b == bend)((void) sizeof ((b == bend) ? 1 : 0), __extension__ ({ if (b ==
bend) ; else __assert_fail ("b == bend", "nua_stack.c", 545,
__extension__ __PRETTY_FUNCTION__); }))
; (void)bend;
546
547 e->e_always = event == nua_r_destroy || event == nua_r_shutdown || event == nua_r_handle_unref || event == nua_r_unref;
548 e->e_event = event;
549 e->e_nh = nh ? nua_handle_ref(nh) : NULL((void*)0);
550 e->e_status = status;
551 e->e_phrase = phrase;
552
553 su_msg_deinitializer(sumsg, nua_event_deinit);
554
555 retval = su_msg_send_to(sumsg, nua->nua_server, nua_stack_signal);
556
557 if (retval == 0){
558 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__, 559, "nua(%p): %s signal %s\n", (void *
)nh, "sent", nua_event_name(event) + 4)) : (void)0)
559 "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__, 559, "nua(%p): %s signal %s\n", (void *
)nh, "sent", nua_event_name(event) + 4)) : (void)0)
;
560 }
561 else {
562 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__, 563, "nua(%p): %s signal %s\n", (void *
)nh, "FAILED TO SEND", nua_event_name(event) + 4)) : (void)0)
563 "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__, 563, "nua(%p): %s signal %s\n", (void *
)nh, "FAILED TO SEND", nua_event_name(event) + 4)) : (void)0)
;
564
565 }
566 }
567
568 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))
;
569
570 return retval;
571}
572
573/* ----------------------------------------------------------------------
574 * Receiving events from client
575 */
576static
577void nua_stack_signal(nua_t *nua, su_msg_r msg, nua_ee_data_t *ee)
578{
579 nua_event_data_t *e = ee->ee_data;
580 nua_handle_t *nh = e->e_nh;
1
'nh' initialized here
581 tagi_t *tags = e->e_tags;
582 nua_event_t event = (enum nua_event_e)e->e_event;
583 int error = 0;
584
585 if (nh && !nh->nh_destroyed && event != nua_r_handle_unref) {
2
Assuming 'nh' is null
586 if (!nh->nh_prev)
587 nh_append(nua, nh);
588 if (!nh->nh_ref_by_stack) {
589 /* Mark handle as used by stack */
590 nh->nh_ref_by_stack = 1;
591 nua_handle_ref(nh);
592 }
593 }
594
595 if (nua_log->log_level >= 5) {
3
Assuming field 'log_level' is < 5
4
Taking false branch
596 char const *name = nua_event_name((enum nua_event_e)e->e_event);
597
598 if (e->e_status == 0)
599 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__, 599, "nua(%p): %s signal %s\n", (void *
)nh, "recv", name + 4)) : (void)0)
;
600 else
601 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__, 603, "nua(%p): recv signal %s %u %s\n"
, (void *)nh, name + 4, e->e_status, e->e_phrase ? e->
e_phrase : "")) : (void)0)
602 (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__, 603, "nua(%p): recv signal %s %u %s\n"
, (void *)nh, name + 4, e->e_status, e->e_phrase ? e->
e_phrase : "")) : (void)0)
603 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__, 603, "nua(%p): recv signal %s %u %s\n"
, (void *)nh, name + 4, e->e_status, e->e_phrase ? e->
e_phrase : "")) : (void)0)
;
604 }
605
606 su_msg_save(nua->nua_signal, msg);
607
608 if (nua->nua_shutdown && !e->e_always) {
5
Assuming field 'nua_shutdown' is 0
609 /* Shutting down */
610 nua_stack_event(nua, nh, NULL((void*)0), event,
611 901, "Stack is going down",
612 NULL((void*)0));
613 }
614 else switch (event) {
6
Control jumps to 'case nua_r_destroy_user:' at line 693
615 case nua_r_get_params:
616 nua_stack_get_params(nua, nh ? nh : nua->nua_dhandlenua_handles, event, tags);
617 break;
618 case nua_r_set_params:
619 nua_stack_set_params(nua, nh ? nh : nua->nua_dhandlenua_handles, event, tags);
620 break;
621 case nua_r_shutdown:
622 nua_stack_shutdown(nua);
623 break;
624 case nua_r_register:
625 case nua_r_unregister:
626 nua_stack_register(nua, nh, event, tags);
627 break;
628 case nua_r_invite:
629 error = nua_stack_invite(nua, nh, event, tags);
630 break;
631 case nua_r_cancel:
632 error = nua_stack_cancel(nua, nh, event, tags);
633 break;
634 case nua_r_bye:
635 error = nua_stack_bye(nua, nh, event, tags);
636 break;
637 case nua_r_options:
638 error = nua_stack_options(nua, nh, event, tags);
639 break;
640 case nua_r_refer:
641 error = nua_stack_refer(nua, nh, event, tags);
642 break;
643 case nua_r_publish:
644 case nua_r_unpublish:
645 error = nua_stack_publish(nua, nh, event, tags);
646 break;
647 case nua_r_info:
648 error = nua_stack_info(nua, nh, event, tags);
649 break;
650 case nua_r_prack:
651 error = nua_stack_prack(nua, nh, event, tags);
652 break;
653 case nua_r_update:
654 error = nua_stack_update(nua, nh, event, tags);
655 break;
656 case nua_r_message:
657 error = nua_stack_message(nua, nh, event, tags);
658 break;
659 case nua_r_subscribe:
660 case nua_r_unsubscribe:
661 error = nua_stack_subscribe(nua, nh, event, tags);
662 break;
663 case nua_r_notify:
664 error = nua_stack_notify(nua, nh, event, tags);
665 break;
666 case nua_r_notifier:
667 nua_stack_notifier(nua, nh, event, tags);
668 break;
669 case nua_r_terminate:
670 nua_stack_terminate(nua, nh, event, tags);
671 break;
672 case nua_r_method:
673 error = nua_stack_method(nua, nh, event, tags);
674 break;
675 case nua_r_authenticate:
676 nua_stack_authenticate(nua, nh, event, tags);
677 break;
678 case nua_r_authorize:
679 nua_stack_authorize(nua, nh, event, tags);
680 break;
681 case nua_r_ack:
682 error = nua_stack_ack(nua, nh, event, tags);
683 break;
684 case nua_r_respond:
685 nua_stack_respond(nua, nh, e->e_status, e->e_phrase, tags);
686 break;
687 case nua_r_destroy:
688 if (nh && !nh->nh_destroyed) {
689 nua_stack_destroy_handle(nua, nh, tags);
690 su_msg_destroy(nua->nua_signal);
691 }
692 return;
693 case nua_r_destroy_user:
694 nua_stack_event(nh->nh_nua, nh, NULL((void*)0), nua_r_destroy_user, 0, NULL((void*)0), NULL((void*)0));
7
Access to field 'nh_nua' results in a dereference of a null pointer (loaded from variable 'nh')
695 break;
696 case nua_r_unref:
697 nua_unref(nua);
698 break;
699 case nua_r_handle_unref:
700 nua_handle_unref(nh);
701 break;
702 case nua_r_nta_agent_resolver_clean_dns_cache:
703 nta_agent_resolver_clean_cache(nua->nua_nta);
704 break;
705 default:
706 break;
707 }
708
709 if (error < 0) {
710 if (nh) {
711 nua_stack_event(nh->nh_nua, nh, NULL((void*)0), event,
712 NUA_ERROR_AT(__FILE__, __LINE__)900, "Internal error at " "nua_stack.c" ":" "712", NULL((void*)0));
713 }
714 }
715
716 su_msg_destroy(nua->nua_signal);
717}
718
719/* ====================================================================== */
720/* Signal and event handling */
721
722/** Get event data.
723 *
724 * @sa #nua_event_e, nua_event_save(), nua_saved_event_request(), nua_destroy_event().
725 */
726nua_event_data_t const *nua_event_data(nua_saved_event_t const saved[1])
727{
728 return saved && saved[0] ? su_msg_data(saved)->ee_data : NULL((void*)0);
729}
730
731/** Destroy saved event.
732 *
733 * @sa #nua_event_e, nua_event_save(), nua_event_data(), nua_saved_event_request().
734 */
735void nua_destroy_event(nua_saved_event_t saved[1])
736{
737 if (saved && saved[0]) su_msg_destroy(saved);
738}
739
740/** @internal Move signal. */
741void nua_move_signal(nua_saved_signal_t a[1], nua_saved_signal_t b[1])
742{
743 su_msg_save(a, b);
744}
745
746void nua_destroy_signal(nua_saved_signal_t saved[1])
747{
748 if (saved) su_msg_destroy(saved);
749}
750
751nua_signal_data_t const *nua_signal_data(nua_saved_signal_t const saved[1])
752{
753 return nua_event_data(saved);
754}
755
756/* ====================================================================== */
757
758static int nh_call_pending(nua_handle_t *nh, sip_time_t time);
759
760/**@internal
761 * Timer routine.
762 *
763 * Go through all active handles and execute pending tasks
764 */
765void nua_stack_timer(nua_t *nua, su_timer_t *t, su_timer_arg_t *a)
766{
767 nua_handle_t *nh, *nh_next;
768 sip_time_t now = sip_now();
769 su_root_t *root = su_timer_root(t);
770
771 su_timer_set(t, nua_stack_timer, a);
772
773 if (nua->nua_shutdown) {
774 nua_stack_shutdown(nua);
775 return;
776 }
777
778 for (nh = nua->nua_handles; nh; nh = nh_next) {
779 nh_next = nh->nh_next;
780 nh_call_pending(nh, now);
781 su_root_yield(root); /* Handle received packets */
782 }
783}
784
785
786static
787int nh_call_pending(nua_handle_t *nh, sip_time_t now)
788{
789 nua_dialog_state_t *ds = nh->nh_ds;
790 nua_dialog_usage_t *du;
791 sip_time_t next = now + NUA_STACK_TIMER_INTERVAL(1000) / 1000;
792
793 for (du = ds->ds_usage; du; du = du->du_next) {
794 if (now == 0)
795 break;
796 if (du->du_refresh && du->du_refresh < next)
797 break;
798 }
799
800 if (du == NULL((void*)0))
801 return 0;
802
803 nua_handle_ref(nh);
804
805 while (du) {
806 nua_dialog_usage_t *du_next = du->du_next;
807
808 nua_dialog_usage_refresh(nh, ds, du, now);
809
810 if (du_next == NULL((void*)0))
811 break;
812
813 for (du = nh->nh_ds->ds_usage; du; du = du->du_next)
814 if (du == du_next)
815 break;
816
817 for (; du; du = du->du_next) {
818 if (now == 0)
819 break;
820 if (du->du_refresh && du->du_refresh < next)
821 break;
822 }
823 }
824
825 nua_handle_unref(nh);
826
827 return 1;
828}
829
830
831
832/* ====================================================================== */
833
834/**Shutdown a @nua stack.
835 *
836 * When the @nua stack is shutdown, ongoing calls are released,
837 * registrations unregistered, publications un-PUBLISHed and subscriptions
838 * terminated. If the stack cannot terminate everything within 30 seconds,
839 * it sends the #nua_r_shutdown event with status 500.
840 *
841 * @param nua Pointer to @nua stack object
842 *
843 * @return
844 * nothing
845 *
846 * @par Related tags:
847 * none
848 *
849 * @par Events:
850 * #nua_r_shutdown
851 *
852 * @sa #nua_r_shutdown, nua_destroy(), nua_create(), nua_bye(),
853 * nua_unregister(), nua_unpublish(), nua_unsubscribe(), nua_notify(),
854 * nua_handle_destroy(), nua_handle_unref()
855 */
856
857/** @NUA_EVENT nua_r_shutdown
858 *
859 * Answer to nua_shutdown().
860 *
861 * Status codes
862 * - 100 shutdown started
863 * - 101 shutdown in progress (sent when shutdown has been progressed)
864 * - 200 shutdown was successful
865 * - 500 shutdown timeout after 30 sec
866 *
867 * @param status shutdown status code
868 * @param nh NULL
869 * @param hmagic NULL
870 * @param sip NULL
871 * @param tags empty
872 *
873 * @sa nua_shutdown(), nua_destroy()
874 *
875 * @END_NUA_EVENT
876 */
877
878/** @internal Shut down stack. */
879void nua_stack_shutdown(nua_t *nua)
880{
881 nua_handle_t *nh, *nh_next;
882 int busy = 0;
883 sip_time_t now = sip_now();
884 int status;
885 char const *phrase;
886
887 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__, 887, "nua: %s: entering\n", __func__))
: (void)0)
;
888
889 if (!nua->nua_shutdown)
890 nua->nua_shutdown = now;
891
892 for (nh = nua->nua_handles; nh; nh = nh_next) {
893 nua_dialog_state_t *ds = nh->nh_ds;
894
895 nh_next = nh->nh_next;
896
897 busy += nua_dialog_repeat_shutdown(nh, ds);
898
899 if (nh->nh_soa) {
900 soa_destroy(nh->nh_soa), nh->nh_soa = NULL((void*)0);
901 }
902
903 if (nua_client_request_pending(ds->ds_cr))
904 busy++;
905
906 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))
907 busy++;
908 }
909
910 if (!busy)
911 SET_STATUS(200, "Shutdown successful")status = 200, phrase = "Shutdown successful";
912 else if (now == nua->nua_shutdown)
913 SET_STATUS(100, "Shutdown started")status = 100, phrase = "Shutdown started";
914 else if (now - nua->nua_shutdown < 30)
915 SET_STATUS(101, "Shutdown in progress")status = 101, phrase = "Shutdown in progress";
916 else
917 SET_STATUS(500, "Shutdown timeout")status = 500, phrase = "Shutdown timeout";
918
919 if (status >= 200) {
920 for (nh = nua->nua_handles; nh; nh = nh_next) {
921 nh_next = nh->nh_next;
922 while (nh->nh_ds->ds_usage) {
923 nua_dialog_usage_remove(nh, nh->nh_ds, nh->nh_ds->ds_usage, NULL((void*)0), NULL((void*)0));
924 }
925 }
926 su_timer_destroy(nua->nua_timer), nua->nua_timer = NULL((void*)0);
927 nta_agent_destroy(nua->nua_nta), nua->nua_nta = NULL((void*)0);
928 }
929
930 nua_stack_event(nua, NULL((void*)0), NULL((void*)0), nua_r_shutdown, status, phrase, NULL((void*)0));
931}
932
933/* ---------------------------------------------------------------------- */
934
935/** @internal Create a handle */
936nua_handle_t *nh_create(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
937{
938 ta_list ta;
939 nua_handle_t *nh;
940
941 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__, 941, "nua: %s: entering\n", __func__))
: (void)0)
;
942
943 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)
;
944 nh = nh_create_handle(nua, NULL((void*)0), ta_args(ta)(ta).tl);
945 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))
;
946
947 if (nh) {
948 nh->nh_ref_by_stack = 1;
949 nh_append(nua, nh);
950 }
951
952 return nh;
953}
954
955/** @internal Append a handle to the list of handles */
956void nh_append(nua_t *nua, nua_handle_t *nh)
957{
958 nh->nh_next = NULL((void*)0);
959 nh->nh_prev = nua->nua_handles_tail;
960 *nua->nua_handles_tail = nh;
961 nua->nua_handles_tail = &nh->nh_next;
962}
963
964nua_handle_t *nh_validate(nua_t *nua, nua_handle_t *maybe)
965{
966 nua_handle_t *nh;
967
968 if (maybe)
969 for (nh = nua->nua_handles; nh; nh = nh->nh_next)
970 if (nh == maybe)
971 return nh;
972
973 return NULL((void*)0);
974}
975
976void nua_stack_destroy_handle(nua_t *nua, nua_handle_t *nh, tagi_t const *tags)
977{
978 if (nh->nh_destroyed) {
979 return;
980 }
981
982 if (nh->nh_notifier)
983 nua_stack_terminate(nua, nh, (enum nua_event_e)0, NULL((void*)0));
984
985 nua_dialog_shutdown(nh, nh->nh_ds);
986
987 if (nh->nh_ref_by_user) {
988 nh->nh_ref_by_user = 0;
989 nua_handle_unref(nh);
990 }
991
992 nh_destroy(nua, nh);
993}
994
995#define nh_is_inserted(nh)((nh)->nh_prev != ((void*)0)) ((nh)->nh_prev != NULL((void*)0))
996
997/** @internal Remove a handle from list of handles */
998static
999void nh_remove(nua_t *nua, nua_handle_t *nh)
1000{
1001 assert(nh_is_inserted(nh))((void) sizeof ((((nh)->nh_prev != ((void*)0))) ? 1 : 0), __extension__
({ if (((nh)->nh_prev != ((void*)0))) ; else __assert_fail
("nh_is_inserted(nh)", "nua_stack.c", 1001, __extension__ __PRETTY_FUNCTION__
); }))
; assert(*nh->nh_prev == nh)((void) sizeof ((*nh->nh_prev == nh) ? 1 : 0), __extension__
({ if (*nh->nh_prev == nh) ; else __assert_fail ("*nh->nh_prev == nh"
, "nua_stack.c", 1001, __extension__ __PRETTY_FUNCTION__); })
)
;
1002
1003 if (nh->nh_next)
1004 nh->nh_next->nh_prev = nh->nh_prev;
1005 else
1006 nua->nua_handles_tail = nh->nh_prev;
1007
1008 *nh->nh_prev = nh->nh_next;
1009
1010 nh->nh_prev = NULL((void*)0);
1011 nh->nh_next = NULL((void*)0);
1012}
1013
1014
1015void nh_destroy(nua_t *nua, nua_handle_t *nh)
1016{
1017 assert(nh)((void) sizeof ((nh) ? 1 : 0), __extension__ ({ if (nh) ; else
__assert_fail ("nh", "nua_stack.c", 1017, __extension__ __PRETTY_FUNCTION__
); }))
; assert(nh != nua->nua_dhandle)((void) sizeof ((nh != nua->nua_handles) ? 1 : 0), __extension__
({ if (nh != nua->nua_handles) ; else __assert_fail ("nh != nua->nua_dhandle"
, "nua_stack.c", 1017, __extension__ __PRETTY_FUNCTION__); })
)
;
1018
1019 if (nh->nh_destroyed) {
1020 return;
1021 }
1022
1023 nh->nh_destroyed = 1;
1024
1025 if (nh->nh_notifier)
1026 nea_server_destroy(nh->nh_notifier), nh->nh_notifier = NULL((void*)0);
1027
1028 while (nh->nh_ds->ds_cr)
1029 nua_client_request_complete(nh->nh_ds->ds_cr);
1030
1031 while (nh->nh_ds->ds_sr)
1032 nua_server_request_destroy(nh->nh_ds->ds_sr);
1033
1034 nua_dialog_deinit(nh, nh->nh_ds);
1035
1036 if (nh->nh_soa)
1037 soa_destroy(nh->nh_soa), nh->nh_soa = NULL((void*)0);
1038
1039 if (nh_is_inserted(nh)((nh)->nh_prev != ((void*)0)))
1040 nh_remove(nua, nh);
1041
1042 nua_handle_unref(nh); /* Remove stack reference */
1043}
1044
1045/* ======================================================================== */
1046
1047/** @internal Create a handle for processing incoming request */
1048nua_handle_t *nua_stack_incoming_handle(nua_t *nua,
1049 nta_incoming_t *irq,
1050 sip_t const *sip,
1051 int create_dialog)
1052{
1053 nua_handle_t *nh;
1054 url_t const *url;
1055 sip_to_t to[1];
1056 sip_from_t from[1];
1057
1058 assert(sip && sip->sip_from && sip->sip_to)((void) sizeof ((sip && sip->sip_from && sip
->sip_to) ? 1 : 0), __extension__ ({ if (sip && sip
->sip_from && sip->sip_to) ; else __assert_fail
("sip && sip->sip_from && sip->sip_to"
, "nua_stack.c", 1058, __extension__ __PRETTY_FUNCTION__); })
)
;
1059
1060 if (sip->sip_contact)
1061 url = sip->sip_contact->m_url;
1062 else
1063 url = sip->sip_from->a_url;
1064
1065 /* Strip away parameters */
1066 sip_from_init(from)->a_display = sip->sip_to->a_display;
1067 *from->a_url = *sip->sip_to->a_url;
1068
1069 sip_to_init(to)->a_display = sip->sip_from->a_display;
1070 *to->a_url = *sip->sip_from->a_url;
1071
1072 nh = nh_create(nua,
1073 NUTAG_URL((url_string_t *)url)nutag_url, urltag_url_v((url_string_t *)url), /* Remote target */
1074 SIPTAG_TO(to)siptag_to, siptag_to_v(to), /* Local AoR */
1075 SIPTAG_FROM(from)siptag_from, siptag_from_v(from), /* Remote AoR */
1076 TAG_END()(tag_type_t)0, (tag_value_t)0);
1077
1078 if (nh && nua_stack_init_handle(nua, nh, NULL((void*)0)) < 0)
1079 nh_destroy(nua, nh), nh = NULL((void*)0);
1080
1081 if (nh && create_dialog) {
1082 struct nua_dialog_state *ds = nh->nh_ds;
1083
1084 nua_dialog_store_peer_info(nh, ds, sip);
1085
1086 ds->ds_leg = nta_leg_tcreate(nua->nua_nta, nua_stack_process_request, nh,
1087 SIPTAG_CALL_ID(sip->sip_call_id)siptag_call_id, siptag_call_id_v(sip->sip_call_id),
1088 SIPTAG_FROM(sip->sip_to)siptag_from, siptag_from_v(sip->sip_to),
1089 SIPTAG_TO(sip->sip_from)siptag_to, siptag_to_v(sip->sip_from),
1090 NTATAG_REMOTE_CSEQ(sip->sip_cseq->cs_seq)ntatag_remote_cseq, tag_uint_v((sip->sip_cseq->cs_seq)),
1091 TAG_END()(tag_type_t)0, (tag_value_t)0);
1092
1093 if (!ds->ds_leg || !nta_leg_tag(ds->ds_leg, nta_incoming_tag(irq, NULL((void*)0))))
1094 nh_destroy(nua, nh), nh = NULL((void*)0);
1095 }
1096
1097 if (nh)
1098 nua_dialog_uas_route(nh, nh->nh_ds, sip, 1);
1099
1100 return nh;
1101}
1102
1103
1104/** Set flags and special event on handle.
1105 *
1106 * @retval 0 when successful
1107 * @retval -1 upon an error
1108 */
1109int nua_stack_set_handle_special(nua_handle_t *nh,
1110 enum nh_kind kind,
1111 nua_event_t special)
1112{
1113 if (nh == NULL((void*)0))
1114 return -1;
1115
1116 if (special && nh->nh_special && nh->nh_special != special)
1117 return -1;
1118
1119 if (!nh_is_special(nh) && !nh->nh_has_invite) {
1120 switch (kind) {
1121 case nh_has_invite: nh->nh_has_invite = 1; break;
1122 case nh_has_subscribe: nh->nh_has_subscribe = 1; break;
1123 case nh_has_notify: nh->nh_has_notify = 1; break;
1124 case nh_has_register: nh->nh_has_register = 1; break;
1125 case nh_has_nothing:
1126 default:
1127 break;
1128 }
1129
1130 if (special)
1131 nh->nh_special = special;
1132 }
1133
1134 return 0;
1135}
1136
1137sip_replaces_t *nua_stack_handle_make_replaces(nua_handle_t *nh,
1138 su_home_t *home,
1139 int early_only)
1140{
1141 if (nh && nh->nh_ds->ds_leg)
1142 return nta_leg_make_replaces(nh->nh_ds->ds_leg, home, early_only);
1143 else
1144 return NULL((void*)0);
1145}
1146
1147nua_handle_t *nua_stack_handle_by_replaces(nua_t *nua,
1148 sip_replaces_t const *r)
1149{
1150 if (nua) {
1151 nta_leg_t *leg = nta_leg_by_replaces(nua->nua_nta, r);
1152 if (leg)
1153 return nta_leg_magic(leg, nua_stack_process_request);
1154 }
1155 return NULL((void*)0);
1156}
1157
1158nua_handle_t *nua_stack_handle_by_call_id(nua_t *nua, const char *call_id)
1159{
1160 if (nua) {
1161 nta_leg_t *leg = nta_leg_by_call_id(nua->nua_nta, call_id);
1162 if (leg)
1163 return nta_leg_magic(leg, nua_stack_process_request);
1164 }
1165 return NULL((void*)0);
1166}