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