Bug Summary

File:libs/sofia-sip/libsofia-sip-ua/nua/nua_stack.c
Location:line 322, column 19
Description:String copy function overflows destination buffer

Annotated Source Code

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