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') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * This file is part of the Sofia-SIP package | |||
3 | * | |||
4 | * Copyright (C) 2005 Nokia Corporation. | |||
5 | * | |||
6 | * Contact: Pekka Pessi <pekka.pessi@nokia.com> | |||
7 | * | |||
8 | * This library is free software; you can redistribute it and/or | |||
9 | * modify it under the terms of the GNU Lesser General Public License | |||
10 | * as published by the Free Software Foundation; either version 2.1 of | |||
11 | * the License, or (at your option) any later version. | |||
12 | * | |||
13 | * This library is distributed in the hope that it will be useful, but | |||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
16 | * Lesser General Public License for more details. | |||
17 | * | |||
18 | * You should have received a copy of the GNU Lesser General Public | |||
19 | * License along with this library; if not, write to the Free Software | |||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |||
21 | * 02110-1301 USA | |||
22 | * | |||
23 | */ | |||
24 | ||||
25 | /**@CFILE 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 | 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 | ||||
252 | static void nua_stack_shutdown(nua_t *); | |||
253 | ||||
254 | void | |||
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 */ | |||
260 | void | |||
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 | ||||
265 | int nh_notifier_shutdown(nua_handle_t *nh, nea_event_t *ev, | |||
266 | tag_type_t t, tag_value_t v, ...); | |||
267 | ||||
268 | int 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. */ | |||
281 | int 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 | ||||
364 | static | |||
365 | void 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 */ | |||
382 | static | |||
383 | void 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 | */ | |||
445 | msg_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 | ||||
453 | su_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 | */ | |||
473 | msg_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 | */ | |||
482 | int 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 | */ | |||
501 | void 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 */ | |||
512 | int 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 | */ | |||
576 | static | |||
577 | void 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; | |||
| ||||
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) { | |||
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) { | |||
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) { | |||
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) { | |||
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)); | |||
| ||||
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 | */ | |||
726 | nua_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 | */ | |||
735 | void 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. */ | |||
741 | void nua_move_signal(nua_saved_signal_t a[1], nua_saved_signal_t b[1]) | |||
742 | { | |||
743 | su_msg_save(a, b); | |||
744 | } | |||
745 | ||||
746 | void nua_destroy_signal(nua_saved_signal_t saved[1]) | |||
747 | { | |||
748 | if (saved) su_msg_destroy(saved); | |||
749 | } | |||
750 | ||||
751 | nua_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 | ||||
758 | static 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 | */ | |||
765 | void 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 | ||||
786 | static | |||
787 | int 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. */ | |||
879 | void 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 */ | |||
936 | nua_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 */ | |||
956 | void 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 | ||||
964 | nua_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 | ||||
976 | void 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 */ | |||
998 | static | |||
999 | void 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 | ||||
1015 | void 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 */ | |||
1048 | nua_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 | */ | |||
1109 | int 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 | ||||
1137 | sip_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 | ||||
1147 | nua_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 | ||||
1158 | nua_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 | } |