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