1 /*
2  * This file is part of the Sofia-SIP package
3  *
4  * Copyright (C) 2006 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 /**@internal @file nua.c High-Level User Agent Library - "nua" Implementation.
26  *
27  * @author Pekka Pessi <Pekka.Pessi@nokia.com>
28  * @author Kai Vehmanen <Kai.Vehmanen@nokia.com>
29  * @author Pasi Rinne-Rahkola
30  *
31  * @date Created: Wed Feb 14 18:32:58 2001 ppessi
32  */
33 
34 #include "config.h"
35 
36 #include <sofia-sip/su_tag.h>
37 #include <sofia-sip/su_tag_class.h>
38 #include <sofia-sip/su_tagarg.h>
39 
40 #include <sofia-sip/su_tag_io.h>
41 
42 #define SU_LOG (nua_log)
43 #include <sofia-sip/su_debug.h>
44 
45 #define SU_ROOT_MAGIC_T   struct nua_s
46 
47 #include <sofia-sip/sip_status.h>
48 #include <sofia-sip/sip_header.h>
49 #include <sofia-sip/nta.h>
50 
51 #include "sofia-sip/nua.h"
52 #include "sofia-sip/nua_tag.h"
53 #include "nua_stack.h"
54 
55 #include <stddef.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <stdio.h>
59 #include <assert.h>
60 
61 /* From AM_INIT/AC_INIT in our "config.h" */
62 char const nua_version[] = VERSION;
63 
64 /**Environment variable determining the debug log level for @nua module.
65  *
66  * The NUA_DEBUG environment variable is used to determine the debug logging
67  * level for @nua module. The default level is 3.
68  *
69  * @sa <sofia-sip/su_debug.h>, nua_log, SOFIA_DEBUG
70  */
71 extern char const NUA_DEBUG[];
72 
73 #ifndef SU_DEBUG
74 #define SU_DEBUG 3
75 #endif
76 
77 /**Debug log for @nua module.
78  *
79  * The nua_log is the log object used by @nua module. The level of
80  * #nua_log is set using #NUA_DEBUG environment variable.
81  */
82 su_log_t nua_log[] = { SU_LOG_INIT("nua", "NUA_DEBUG", SU_DEBUG) };
83 
84 /**Create a @nua agent.
85  *
86  * This function creates a Sofia-SIP User Agent stack object (@nua) and
87  * initializes its parameters by given tagged values.
88  *
89  * @param root            Pointer to a root object
90  * @param callback        Pointer to event callback function
91  * @param magic           Pointer to callback context
92  * @param tag,�value, ... List of tagged parameters
93  *
94  * @retval !=NULL a pointer to a @nua stack object
95  * @retval NULL upon an error
96  *
97  * @par Related tags:
98  * - NUTAG_PROXY(), giving the URI of the outbound proxy
99  *   (but see also NUTAG_INITIAL_ROUTE()).
100  * - NUTAG_URL() (and NUTAG_SIPS_URL(), listing URIs describing
101  *   transports)
102  * - NUTAG_CERTIFICATE_DIR(), specifying the location of the
103  *   root and client/server certificate files
104  * - NUTAG_SIP_PARSER(), providing customized parser used to
105  *   parse received SIP messages
106  * - All parameter tags, listed with nua_set_params()
107  * - All NTATAG_* are passed to NTA documented in <sofia-sip/nta_tag.h>:
108  *   see NTATAG_EXTRA_100(),
109  * - All tport tags are passed to tport.
110  *   They are documented in <sofia-sip/tport_tag.h>
111  * - All SOATAG_* are passed to the default SOA (media session) object which
112  *   is created by nua_create() unless NUTAG_MEDIA_ENABLE(0) is included in
113  *   the tag list
114  * - STUN tags STUNTAG_DOMAIN(), STUNTAG_SERVER().
115  *   STUN is deprecated, however.
116  *
117  * @note
118  * From the @VERSION_1_12_2 all the nua_set_params() tags are processed.
119  * Previously all nutags except NUTAG_SOA_NAME() and NUTAG_MEDIA_ENABLE()
120  * were ignored.
121  *
122  * @note
123  * Both the NUTAG_URL() and NUTAG_SIPS_URL() are used to pass arguments to
124  * nta_agent_add_tport().
125  *
126  * @par Events:
127  *     none
128  *
129  * @sa nua_shutdown(), nua_destroy(), nua_handle(), nta_agent_create().
130  */
nua_create(su_root_t * root,nua_callback_f callback,nua_magic_t * magic,tag_type_t tag,tag_value_t value,...)131 nua_t *nua_create(su_root_t *root,
132 		  nua_callback_f callback,
133 		  nua_magic_t *magic,
134 		  tag_type_t tag, tag_value_t value, ...)
135 {
136   nua_t *nua = NULL;
137 
138   enter;
139 
140   if (callback == NULL)
141     return (void)(errno = EFAULT), NULL;
142 
143   if (root == NULL)
144     return (void)(errno = EFAULT), NULL;
145 
146   if ((nua = su_home_new(sizeof(*nua)))) {
147     ta_list ta;
148 
149     su_home_threadsafe(nua->nua_home);
150     nua->nua_api_root = root;
151 
152     ta_start(ta, tag, value);
153 
154     nua->nua_args = tl_adup(nua->nua_home, ta_args(ta));
155 
156     su_task_copy(nua->nua_client, su_root_task(root));
157 
158     /* XXX: where to put this in the nua_server case? */
159 #if HAVE_SMIME		/* Start NRC Boston */
160       nua->sm = sm_create();
161 #endif                  /* End NRC Boston */
162 
163 #ifndef NUA_SERVER
164     if (su_clone_start(root,
165 		       nua->nua_clone,
166 		       nua,
167 		       nua_stack_init,
168 		       nua_stack_deinit) == SU_SUCCESS) {
169       su_task_copy(nua->nua_server, su_clone_task(nua->nua_clone));
170       nua->nua_callback = callback;
171       nua->nua_magic = magic;
172     }
173     else {
174       su_home_unref(nua->nua_home);
175       nua = NULL;
176     }
177 #endif
178 
179     ta_end(ta);
180   }
181 
182   return nua;
183 }
184 
185 /* nua_shutdown() is documented with nua_stack_shutdown() */
186 
nua_shutdown(nua_t * nua)187 void nua_shutdown(nua_t *nua)
188 {
189   enter;
190 
191   if (nua)
192     nua->nua_shutdown_started = 1;
193   nua_signal(nua, NULL, NULL, nua_r_shutdown, 0, NULL, TAG_END());
194 }
195 
196 /** Destroy the @nua stack.
197  *
198  * Before calling nua_destroy() the application
199  * should call nua_shutdown and wait for successful #nua_r_shutdown event.
200  * Shuts down and destroys the @nua stack. Ongoing calls, registrations,
201  * and subscriptions are left as they are.
202  *
203  * @param nua         Pointer to @nua stack object
204  *
205  * @return
206  *     nothing
207  *
208  * @par Related tags:
209  *     none
210  *
211  * @par Events:
212  *     none
213  *
214  * @sa nua_shutdown(), nua_create(), nua_handle_destroy(), nua_handle_unref()
215  */
nua_destroy(nua_t * nua)216 void nua_destroy(nua_t *nua)
217 {
218   nua_handle_t *nh, *nh_next;
219   enter;
220 
221   if (nua) {
222     if (!nua->nua_shutdown_final) {
223       SU_DEBUG_0(("nua_destroy(%p): FATAL: nua_shutdown not completed\n",
224 		  (void *)nua));
225       assert(nua->nua_shutdown);
226       return;
227     }
228 
229     nua->nua_callback = NULL;
230 
231     su_task_deinit(nua->nua_server);
232     su_task_deinit(nua->nua_client);
233 
234     su_clone_wait(nua->nua_api_root, nua->nua_clone);
235 #if HAVE_SMIME		/* Start NRC Boston */
236     sm_destroy(nua->sm);
237 #endif			/* End NRC Boston */
238 
239     /* Cleanup remaining nua handles as they are su_home_new'ed and not su_home_cloned (do not belong to the nua's home)
240        See nh_create_handle().
241     */
242     for (nh = nua->nua_handles; nh; nh = nh_next) {
243       su_home_t *nh_home = (su_home_t *)nh;
244       nh_next = nh->nh_next;
245 
246       /* at least one handle will be found here and it is nua default handle
247          which is su_home_cloned (see nua_stack_init()) and therefore does not actually require to be unrefed
248          but it is safe to do that anyways just for sure
249       */
250       SU_DEBUG_9(("nua(%p): found handle with refcount = "MOD_ZU". Destroying.\n", (void *)nh, su_home_refcount(nh_home)));
251 
252       /* nua is about to die so we don't remove nh from nua, just unref nh */
253       while(!su_home_unref(nh_home));
254     }
255 
256 	nua_unref(nua);
257   }
258 }
259 
nua_unref(nua_t * nua)260 void nua_unref(nua_t *nua) {
261 	if (nua) su_home_unref(nua->nua_home);
262 }
263 
264 /** Fetch callback context from nua.
265  *
266  * @param nua         Pointer to @nua stack object
267  *
268  * @return Callback context pointer.
269  *
270  * @NEW_1_12_4.
271  */
nua_magic(nua_t * nua)272 nua_magic_t *nua_magic(nua_t *nua)
273 {
274   return nua ? nua->nua_magic : NULL;
275 }
276 
277 /** Obtain default operation handle of the @nua stack object.
278  *
279  * A default operation can be used for operations where the
280  * ultimate result is not important or can be discarded.
281  *
282  * @param nua         Pointer to @nua stack object
283  *
284  * @retval !=NULL Pointer to @nua operation handle
285  * @retval NULL   No default operation exists
286  *
287  * @par Related tags:
288  *    none
289  *
290  * @par Events:
291  *    none
292  *
293  */
nua_default(nua_t * nua)294 nua_handle_t *nua_default(nua_t *nua)
295 {
296   return nua ? nua->nua_handles : NULL;
297 }
298 
299 /** Create an operation handle
300  *
301  * Allocates a new operation handle and associated storage.
302  *
303  * @param nua         Pointer to @nua stack object
304  * @param hmagic      Pointer to callback context
305  * @param tag, value, ... List of tagged parameters
306  *
307  * @retval !=NULL  Pointer to operation handle
308  * @retval NULL    Creation failed
309  *
310  * @par Related tags:
311  *     Duplicates the provided tags for use with every operation. Note that
312  *     NUTAG_URL() is converted to SIPTAG_TO() if there is no SIPTAG_TO().
313  *     And also vice versa, request-URI is taken from SIPTAG_TO() if there
314  *     is no NUTAG_URL(). Note that certain SIP headers cannot be saved with
315  *     the handle. They include @ContentLength, @CSeq, @RSeq, @RAck, and
316  *     @Timestamp.
317  *
318  * @par
319  *     nua_handle() accepts all the tags accepted by nua_set_hparams(), too.
320  *
321  *
322  * @par Events:
323  *     none
324  *
325  * @sa nua_handle_bind(), nua_handle_destroy(), nua_handle_ref(),
326  * nua_handle_unref().
327  */
nua_handle(nua_t * nua,nua_hmagic_t * hmagic,tag_type_t tag,tag_value_t value,...)328 nua_handle_t *nua_handle(nua_t *nua, nua_hmagic_t *hmagic,
329 			 tag_type_t tag, tag_value_t value, ...)
330 {
331   nua_handle_t *nh = NULL;
332 
333   if (nua) {
334     ta_list ta;
335 
336     ta_start(ta, tag, value);
337 
338     nh = nh_create_handle(nua, hmagic, ta_args(ta));
339 
340     if (nh)
341       nh->nh_ref_by_user = 1;
342 
343     ta_end(ta);
344   }
345 
346   return nh;
347 }
348 
349 /** Bind a callback context to an operation handle.
350  *
351  * @param nh          Pointer to operation handle
352  * @param hmagic      Pointer to callback context
353  *
354  * @return
355  *     nothing
356  *
357  * @par Related tags:
358  *     none
359  *
360  * @par Events:
361  *     none
362  */
nua_handle_bind(nua_handle_t * nh,nua_hmagic_t * hmagic)363 void nua_handle_bind(nua_handle_t *nh, nua_hmagic_t *hmagic)
364 {
365   enter;
366 
367   if (NH_IS_VALID(nh))
368     nh->nh_magic = hmagic;
369 }
370 
371 /** Fetch a callback context from an operation handle.
372  *
373  * @param nh          Pointer to operation handle
374  *
375  * @return
376  *     Pointer to callback context
377  *
378  * @par Related tags:
379  *     none
380  *
381  * @par Events:
382  *     none
383  *
384  * @NEW_1_12_4.
385  */
nua_handle_magic(nua_handle_t * nh)386 nua_hmagic_t *nua_handle_magic(nua_handle_t *nh)
387 {
388   nua_hmagic_t *magic = NULL;
389   enter;
390 
391   if (NH_IS_VALID(nh))
392     magic = nh->nh_magic;
393 
394   return magic;
395 }
396 
397 /* ---------------------------------------------------------------------- */
398 
399 /** Check if operation handle is used for INVITE
400  *
401  * Check if operation handle has been used with either outgoing or incoming
402  * INVITE request.
403  *
404  * @param nh          Pointer to operation handle
405  *
406  * @retval 0 no invite in operation or operation handle is invalid
407  * @retval 1 operation has invite
408  *
409  * @par Related tags:
410  *     none
411  *
412  * @par Events:
413  *     none
414  */
nua_handle_has_invite(nua_handle_t const * nh)415 int nua_handle_has_invite(nua_handle_t const *nh)
416 {
417   return nh ? nh->nh_has_invite : 0;
418 }
419 
420 /**Check if operation handle has active event subscriptions.
421  *
422  * Active subscription can be established either by nua_subscribe() or
423  * nua_refer() calls.
424  *
425  * @param nh          Pointer to operation handle
426  *
427  * @retval 0    no event subscriptions in operation or
428  *              operation handle is invalid
429  * @retval !=0  operation has event subscriptions
430  *
431  * @par Related tags:
432  *     none
433  *
434  * @par Events:
435  *     none
436  */
nua_handle_has_events(nua_handle_t const * nh)437 int nua_handle_has_events(nua_handle_t const *nh)
438 {
439   return nh ? nh->nh_ds->ds_has_events : 0;
440 }
441 
442 /** Check if operation handle has active registrations
443  *
444  * A registration is active when either when a REGISTER operation is going
445  * on or when it has successfully completed so that @nua stack is expected to
446  * refresh the registration in the future. Normally, a handle has active
447  * registration after nua_register() until nua_unregister() completes,
448  * unless the initial nua_register() had either expiration time of 0 or it
449  * had SIPTAG_CONTACT(NULL) as an argument.
450  *
451  * @param nh          Pointer to operation handle
452  *
453  * @retval 0 no active registration in operation or
454  *           operation handle is invalid
455  * @retval 1 operation has registration
456  *
457  * @par Related tags:
458  *     none
459  *
460  * @par Events:
461  *     none
462  *
463  * @sa nua_register(), nua_unregister(), #nua_r_register, #nua_r_unregister
464  */
nua_handle_has_registrations(nua_handle_t const * nh)465 int nua_handle_has_registrations(nua_handle_t const *nh)
466 {
467   return nh && nh->nh_ds->ds_has_register;
468 }
469 
470 /** Check if operation handle has been used with outgoing SUBSCRIBE of REFER request.
471  *
472  * @param nh          Pointer to operation handle
473  *
474  * @retval 0 no active subscription in operation or
475  *           operation handle is invalid
476  * @retval 1 operation has subscription.
477  *
478  * @par Related tags:
479  *     none
480  *
481  * @par Events:
482  *     none
483  */
nua_handle_has_subscribe(nua_handle_t const * nh)484 int nua_handle_has_subscribe(nua_handle_t const *nh)
485 {
486   return nh ? nh->nh_has_subscribe : 0;
487 }
488 
489 /** Check if operation handle has been used with nua_register() or nua_unregister().
490  *
491  * @param nh          Pointer to operation handle
492  *
493  * @retval 0 no active register in operation or operation handle is invalid
494  * @retval 1 operation has been used with nua_register() or nua-unregister()
495  *
496  * @par Related tags:
497  *     none
498  *
499  * @par Events:
500  *     none
501  */
nua_handle_has_register(nua_handle_t const * nh)502 int nua_handle_has_register(nua_handle_t const *nh)
503 {
504   return nh ? nh->nh_has_register : 0;
505 }
506 
507 /** Check if operation handle has an active call
508  *
509  * @param nh          Pointer to operation handle
510  *
511  * @retval 0 no active call in operation or operation handle is invalid
512  * @retval 1 operation has established call or pending call request.
513  *
514  * @par Related tags:
515  *     none
516  *
517  * @par Events:
518  *     none
519  */
nua_handle_has_active_call(nua_handle_t const * nh)520 int nua_handle_has_active_call(nua_handle_t const *nh)
521 {
522   return nh ? nh->nh_active_call : 0;
523 }
524 
525 /** Check if operation handle has a call on hold
526  *
527  * Please note that this status is not affected by remote end putting
528  * this end on hold. Remote end can put each media separately on hold
529  * and status is reflected on SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO()
530  * and SOATAG_ACTIVE_CHAT() tag values in #nua_i_state event.
531  *
532  * @param nh          Pointer to operation handle
533  *
534  * @retval 0  if no call on hold in operation or operation handle is invalid
535  * @retval 1  if operation has call on hold, for example nua_invite() or
536  *            nua_update() has been called with SOATAG_HOLD() with non-NULL
537  *            argument.
538  *
539  * @par Related tags:
540  *     none
541  *
542  * @par Events:
543  *     none
544  */
nua_handle_has_call_on_hold(nua_handle_t const * nh)545 int nua_handle_has_call_on_hold(nua_handle_t const *nh)
546 {
547   return nh ? nh->nh_hold_remote : 0;
548 }
549 
550 /** Get the remote address (From/To header) of operation handle
551  *
552  * Remote address is used as To header in outgoing operations and
553  * derived from From: header in incoming operations.
554  *
555  * @param nh          Pointer to operation handle
556  *
557  * @retval NULL   no remote address for operation or operation handle invalid
558  * @retval !=NULL pointer to remote address for operation
559  *
560  * @par Related tags:
561  *     none
562  *
563  * @par Events:
564  *     none
565  */
nua_handle_remote(nua_handle_t const * nh)566 sip_to_t const *nua_handle_remote(nua_handle_t const *nh)
567 {
568   return nh ? nh->nh_ds->ds_remote : NULL;
569 }
570 
571 /** Get the local address (From/To header) of operation handle
572  *
573  * Local address is used as From header in outgoing operations and
574  * derived from To: header in incoming operations.
575  *
576  * @param nh          Pointer to operation handle
577  *
578  * @retval NULL   no local address for operation or operation handle invalid
579  * @retval !=NULL pointer to local address for operation
580  *
581  * @par Related tags:
582  *     none
583  *
584  * @par Events:
585  *     none
586  */
nua_handle_local(nua_handle_t const * nh)587 sip_to_t const *nua_handle_local(nua_handle_t const *nh)
588 {
589   return nh ? nh->nh_ds->ds_local : NULL;
590 }
591 
592 /* Documented with nua_stack_set_params() */
nua_set_params(nua_t * nua,tag_type_t tag,tag_value_t value,...)593 void nua_set_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
594 {
595   ta_list ta;
596   ta_start(ta, tag, value);
597 
598   enter;
599 
600   nua_signal(nua, NULL, NULL, nua_r_set_params, 0, NULL, ta_tags(ta));
601 
602   ta_end(ta);
603 }
604 
605 /* Documented with nua_stack_get_params() */
nua_get_params(nua_t * nua,tag_type_t tag,tag_value_t value,...)606 void nua_get_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
607 {
608   ta_list ta;
609   ta_start(ta, tag, value);
610 
611   enter;
612 
613   nua_signal(nua, NULL, NULL, nua_r_get_params, 0, NULL, ta_tags(ta));
614 
615   ta_end(ta);
616 }
617 
618 #define NUA_SIGNAL(nh, event, tag, value) \
619   enter; \
620   if (NH_IS_VALID((nh))) { \
621     ta_list ta; \
622     ta_start(ta, tag, value); \
623     nua_signal((nh)->nh_nua, nh, NULL, event, 0, NULL, ta_tags(ta));	\
624     ta_end(ta); \
625   } \
626   else { \
627     SU_DEBUG_1(("nua: " #event " with invalid handle %p\n", (void *)nh)); \
628   }
629 
630 /* Documented with nua_stack_set_params() */
nua_set_hparams(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)631 void nua_set_hparams(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
632 {
633   NUA_SIGNAL(nh, nua_r_set_params, tag, value);
634 }
635 
636 /* Documented with nua_stack_get_params() */
nua_get_hparams(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)637 void nua_get_hparams(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
638 {
639   NUA_SIGNAL(nh, nua_r_get_params, tag, value);
640 }
641 
642 /* Documented with nua_stack_register() */
nua_register(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)643 void nua_register(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
644 {
645   NUA_SIGNAL(nh, nua_r_register, tag, value);
646 }
647 
nua_unregister(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)648 void nua_unregister(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
649 {
650   NUA_SIGNAL(nh, nua_r_unregister, tag, value);
651 }
652 
653 /* Documented with nua_stack_invite() */
nua_invite(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)654 void nua_invite(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
655 {
656   NUA_SIGNAL(nh, nua_r_invite, tag, value);
657 }
658 
659 /* Documented with nua_stack_ack() */
nua_ack(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)660 void nua_ack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
661 {
662   NUA_SIGNAL(nh, nua_r_ack, tag, value);
663 }
664 
665 /* Documented with nua_stack_bye() */
nua_bye(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)666 void nua_bye(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
667 {
668   NUA_SIGNAL(nh, nua_r_bye, tag, value);
669 }
670 
671 /* Documented with nua_stack_cancel() */
nua_cancel(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)672 void nua_cancel(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
673 {
674   NUA_SIGNAL(nh, nua_r_cancel, tag, value);
675 }
676 
677 /* Documented with nua_stack_options() */
nua_options(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)678 void nua_options(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
679 {
680   NUA_SIGNAL(nh, nua_r_options, tag, value);
681 }
682 
683 /* Documented with nua_stack_message() */
nua_message(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)684 void nua_message(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
685 {
686   NUA_SIGNAL(nh, nua_r_message, tag, value);
687 }
688 
689 /* Documented with nua_stack_method() */
nua_method(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)690 void nua_method(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
691 {
692   NUA_SIGNAL(nh, nua_r_method, tag, value);
693 }
694 
695 /** Send a chat message.
696  *
697  * A chat channel can be established during call setup using "message" media.
698  * An active chat channel is indicated using #nua_i_state event containing
699  * SOATAG_ACTIVE_CHAT() tag. Chat messages can be sent using this channel with
700  * nua_chat() function. Currently this is implemented using SIP MESSAGE
701  * requests but in future MSRP (message session protocol) will replace it.
702 *
703  * @param nh              Pointer to operation handle
704  * @param tag, value, ... List of tagged parameters
705  *
706  * @return
707  *    nothing
708  *
709  * @par Related Tags:
710  *    SIPTAG_CONTENT_TYPE() \n
711  *    SIPTAG_PAYLOAD()      \n
712  *    SIPTAG_FROM()         \n
713  *    SIPTAG_TO()           \n
714  *    Use of other SIP tags is deprecated
715  *
716  * @par Events:
717  *    #nua_r_chat
718  */
nua_chat(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)719 void nua_chat(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
720 {
721   NUA_SIGNAL(nh, nua_r_chat, tag, value);
722 }
723 
724 /* Documented with nua_stack_subscribe() */
nua_subscribe(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)725 void nua_subscribe(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
726 {
727   NUA_SIGNAL(nh, nua_r_subscribe, tag, value);
728 }
729 
730 /* Documented with nua_stack_subscribe() */
nua_unsubscribe(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)731 void nua_unsubscribe(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
732 {
733   NUA_SIGNAL(nh, nua_r_unsubscribe, tag, value);
734 }
735 
736 /* Documented with nua_stack_notify() */
nua_notify(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)737 void nua_notify(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
738 {
739   NUA_SIGNAL(nh, nua_r_notify, tag, value);
740 }
741 
742 /* nua_r_notify is documented with process_response_to_notify() */
743 
744 /** Create an event server.
745  *
746  * This function create an event server taking care of sending NOTIFY
747  * requests and responding to further SUBSCRIBE requests. The event
748  * server can accept multiple subscriptions from several sources and
749  * takes care for distributing the notifications. Unlike other functions
750  * this call only accepts the SIP tags listed below.
751  *
752  * @param nh              Pointer to operation handle
753  * @param tag, value, ... List of tagged parameters
754  *
755  * @return
756  *    nothing
757  *
758  * @par Related Tags:
759  *    NUTAG_URL() \n
760  *    SIPTAG_EVENT() or SIPTAG_EVENT_STR() \n
761  *    SIPTAG_CONTENT_TYPE() or SIPTAG_CONTENT_TYPE_STR() \n
762  *    SIPTAG_PAYLOAD() or SIPTAG_PAYLOAD_STR() \n
763  *    SIPTAG_ACCEPT() or SIPTAG_ACCEPT_STR() \n
764  *
765  * @par Events:
766  *    #nua_r_notify
767  */
nua_notifier(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)768 void nua_notifier(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
769 {
770   NUA_SIGNAL(nh, nua_r_notifier, tag, value);
771 }
772 
773 /** Terminate an event server.
774  *
775  * Terminate an event server with matching event and content type. The event
776  * server was created earlier with nua_notifier() function.
777  *
778  * @param nh              Pointer to operation handle
779  * @param tag, value, ... List of tagged parameters
780  *
781  * @return
782  *    nothing
783  *
784  * @par Related Tags:
785  *    SIPTAG_EVENT() \n
786  *    SIPTAG_CONTENT_TYPE() \n
787  *    SIPTAG_PAYLOAD() \n
788  *    NEATAG_REASON()
789  *
790  * @par Events:
791  *    #nua_r_terminate
792  *
793  * @sa nua_notifier(), nua_authorize().
794  */
nua_terminate(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)795 void nua_terminate(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
796 {
797   NUA_SIGNAL(nh, nua_r_terminate, tag, value);
798 }
799 
800 /* Documented with nua_stack_refer() */
nua_refer(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)801 void nua_refer(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
802 {
803   NUA_SIGNAL(nh, nua_r_refer, tag, value);
804 }
805 
806 /* Documented with nua_stack_publish() */
nua_publish(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)807 void nua_publish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
808 {
809   NUA_SIGNAL(nh, nua_r_publish, tag, value);
810 }
811 
812 /* Documented with nua_stack_publish() */
nua_unpublish(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)813 void nua_unpublish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
814 {
815   NUA_SIGNAL(nh, nua_r_unpublish, tag, value);
816 }
817 
818 /* Documented with nua_stack_info() */
nua_info(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)819 void nua_info(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
820 {
821   NUA_SIGNAL(nh, nua_r_info, tag, value);
822 }
823 
824 /* Documented with nua_stack_prack() */
nua_prack(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)825 void nua_prack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
826 {
827   NUA_SIGNAL(nh, nua_r_prack, tag, value);
828 }
829 
830 /* Documented with nua_stack_update() */
nua_update(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)831 void nua_update(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
832 {
833   NUA_SIGNAL(nh, nua_r_update, tag, value);
834 }
835 
836 /** Authenticate an operation.
837  *
838  * - 401 / 407 response with www-authenticate header/ proxy-authenticate header
839  * - application should provide stack with username&password for each realm
840  *   with NUTAG_AUTH() tag
841  * - restarts operation
842  *
843  * @param nh              Pointer to operation handle
844  * @param tag, value, ... List of tagged parameters
845  *
846  * @return
847  *    nothing
848  *
849  * @par Related Tags:
850  *    NUTAG_AUTH()
851  *
852  * @par Events:
853  *    (any operation events)
854  */
nua_authenticate(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)855 void nua_authenticate(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
856 {
857   NUA_SIGNAL(nh, nua_r_authenticate, tag, value);
858 }
859 
860 /** Authorize a subscriber.
861  *
862  * After creating a local presence server by nua_notifier(), an incoming
863  * SUBSCRIBE request causes #nua_i_subscription event. Each subscriber is
864  * identified with NEATAG_SUB() tag in the #nua_i_subscription event.
865  * Application can either authorize the subscriber with
866  * NUTAG_SUBSTATE(#nua_substate_active) or terminate the subscription with
867  * NUTAG_SUBSTATE(#nua_substate_terminated).
868  *
869  * @param nh              Pointer to operation handle
870  * @param tag, value, ... List of tagged parameters
871  *
872  * @return
873  *    nothing
874  *
875  * @par Related Tags:
876  *    NEATAG_SUB() \n
877  *    NUTAG_SUBSTATE()
878  *
879  * @par Events:
880  *    #nua_i_subscription
881  *
882  * @sa nua_notifier(), nua_terminate()
883  */
nua_authorize(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)884 void nua_authorize(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
885 {
886   NUA_SIGNAL(nh, nua_r_authorize, tag, value);
887 }
888 
889 /*# Redirect an operation. */
nua_redirect(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)890 void nua_redirect(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
891 {
892   NUA_SIGNAL(nh, nua_r_redirect, tag, value);
893 }
894 
895 /* Documented with nua_stack_respond() */
896 
nua_respond(nua_handle_t * nh,int status,char const * phrase,tag_type_t tag,tag_value_t value,...)897 void nua_respond(nua_handle_t *nh,
898 		 int status, char const *phrase,
899 		 tag_type_t tag, tag_value_t value,
900 		 ...)
901 {
902   enter;
903 
904   if (NH_IS_VALID(nh)) {
905     ta_list ta;
906     ta_start(ta, tag, value);
907     nua_signal(nh->nh_nua, nh, NULL, nua_r_respond,
908 	       status, phrase, ta_tags(ta));
909     ta_end(ta);
910   }
911   else {
912     SU_DEBUG_1(("nua: respond with invalid handle %p\n", (void *)nh));
913   }
914 }
915 
916 /** Destroy a handle
917  *
918  * Terminate the protocol state associated with an operation handle. The
919  * stack discards resources and terminates the ongoing dialog usage,
920  * sessions and transactions associated with this handle. For example, calls
921  * are terminated with BYE request. Also, the reference count for the handle
922  * is also decremented.
923  *
924  * The handles use reference counting for memory management. In order to
925  * make it more convenient for programmer, nua_handle_destroy() decreases
926  * the reference count, too.
927  *
928  * @param nh              Pointer to operation handle
929  *
930  * @return
931  *    nothing
932  *
933  * @par Related Tags:
934  *    none
935  *
936  * @par Events:
937  *    none
938  *
939  * @sa nua_handle(), nua_handle_bind(), nua_handle_ref(), nua_handle_unref(),
940  * nua_unregister(), nua_unpublish(), nua_unsubscribe(), nua_bye().
941  */
nua_handle_destroy(nua_handle_t * nh)942 void nua_handle_destroy(nua_handle_t *nh)
943 {
944   enter;
945 
946   if (NH_IS_VALID(nh) && !NH_IS_DEFAULT(nh)) {
947     nh->nh_valid = NULL;	/* Events are no more delivered to appl. */
948     nua_signal(nh->nh_nua, nh, NULL, nua_r_destroy, 0, NULL, TAG_END());
949   }
950 }
951 
952 /* ---------------------------------------------------------------------- */
953 
954 struct nua_stack_handle_make_replaces_args {
955   sip_replaces_t *retval;
956   nua_handle_t *nh;
957   su_home_t *home;
958   int early_only;
959 };
960 
nua_stack_handle_make_replaces_call(void * arg)961 static int nua_stack_handle_make_replaces_call(void *arg)
962 {
963   struct nua_stack_handle_make_replaces_args *a = arg;
964 
965   a->retval = nua_stack_handle_make_replaces(a->nh, a->home, a->early_only);
966 
967   return 0;
968 }
969 
970 
971 /**Generate a @Replaces header for handle.
972  *
973  * A @Replaces header contains the @CallID value, @From and @To tags
974  * corresponding to SIP dialog associated with handle @a nh. Note that the
975  * @Replaces matches with dialog of the remote peer,
976  * nua_handle_by_replaces() does not return same handle (unless you swap
977  * rp_from_tag and rp_to_tag in @Replaces header).
978  *
979  * A @Replaces header is used in attended transfer, among other things.
980  *
981  * @param nh pointer to operation handle
982  * @param home memory home used to allocate the header
983  * @param early_only if true, include "early-only" parameter in @Replaces, too
984  *
985  * @return A newly created @Replaces header.
986  *
987  * @since New in @VERSION_1_12_4.
988  *
989  * @sa nua_handle_by_replaces(), @Replaces, @RFC3891, @RFC3515, nua_refer(),
990  * #nua_i_refer(), @ReferTo, nta_leg_make_replaces(),
991  * sip_headers_as_url_query()
992  */
nua_handle_make_replaces(nua_handle_t * nh,su_home_t * home,int early_only)993 sip_replaces_t *nua_handle_make_replaces(nua_handle_t *nh,
994 					 su_home_t *home,
995 					 int early_only)
996 {
997   if (nh && nh->nh_valid && nh->nh_nua) {
998 #if HAVE_OPEN_C
999     struct nua_stack_handle_make_replaces_args a = { NULL, NULL, NULL, 0 };
1000     a.nh = nh;
1001     a.home = home;
1002     a.early_only = early_only;
1003 #else
1004     struct nua_stack_handle_make_replaces_args a = { NULL, nh, home, early_only };
1005 #endif
1006 
1007     if (su_task_execute(nh->nh_nua->nua_server,
1008 			nua_stack_handle_make_replaces_call, (void *)&a,
1009 			NULL) == 0) {
1010       return a.retval;
1011     }
1012   }
1013   return NULL;
1014 }
1015 
1016 struct nua_stack_handle_by_replaces_args {
1017   nua_handle_t *retval;
1018   nua_t *nua;
1019   sip_replaces_t const *r;
1020 };
1021 
nua_stack_handle_by_replaces_call(void * arg)1022 static int nua_stack_handle_by_replaces_call(void *arg)
1023 {
1024   struct nua_stack_handle_by_replaces_args *a = arg;
1025 
1026   a->retval = nua_stack_handle_by_replaces(a->nua, a->r);
1027   if (!NH_IS_VALID(a->retval) || NH_IS_DEFAULT(a->retval)) {
1028     a->retval = NULL;
1029     return 1;
1030   }
1031 
1032   nua_handle_ref(a->retval);
1033 
1034   return 0;
1035 }
1036 
1037 struct nua_stack_handle_by_call_id_args {
1038   nua_handle_t *retval;
1039   nua_t *nua;
1040   const char *call_id;
1041 };
1042 
nua_stack_handle_by_call_id_call(void * arg)1043 static int nua_stack_handle_by_call_id_call(void *arg)
1044 {
1045   struct nua_stack_handle_by_call_id_args *a = arg;
1046 
1047   a->retval = nua_stack_handle_by_call_id(a->nua, a->call_id);
1048   if (!NH_IS_VALID(a->retval) || NH_IS_DEFAULT(a->retval)) {
1049     a->retval = NULL;
1050     return 1;
1051   }
1052 
1053   nua_handle_ref(a->retval);
1054 
1055   return 0;
1056 }
1057 
1058 /** Obtain a new reference to an existing handle based on @Replaces header.
1059  *
1060  * @since New in @VERSION_1_12_4.
1061  *
1062  * @note
1063  * You should release the reference with nua_handle_unref() when you are
1064  * done with the handle.
1065  *
1066  * @sa nua_handle_make_replaces(), @Replaces, @RFC3891, nua_refer(),
1067  * #nua_i_refer, @ReferTo, nta_leg_by_replaces()
1068  */
nua_handle_by_replaces(nua_t * nua,sip_replaces_t const * r)1069 nua_handle_t *nua_handle_by_replaces(nua_t *nua, sip_replaces_t const *r)
1070 {
1071   if (nua) {
1072 #if HAVE_OPEN_C
1073     struct nua_stack_handle_by_replaces_args a;
1074     a.retval = NULL;
1075     a.nua = nua;
1076     a.r = r;
1077 #else
1078     struct nua_stack_handle_by_replaces_args a = { NULL, nua, r };
1079 #endif
1080 
1081     if (su_task_execute(nua->nua_server,
1082 			nua_stack_handle_by_replaces_call, (void *)&a,
1083 			NULL) == 0) {
1084        return a.retval;
1085     }
1086   }
1087   return NULL;
1088 }
1089 
1090 /** Obtain a new reference to an existing handle based on @CallID.
1091  *
1092  * @since New in @VERSION_1_12_9.
1093  *
1094  * @note
1095  * You should release the reference with nua_handle_unref() when you are
1096  * done with the handle.
1097  *
1098  * @sa nua_handle_make_replaces(), @Replaces, @RFC3891, nua_refer(),
1099  * #nua_i_refer, @ReferTo, nta_leg_by_replaces()
1100  */
nua_handle_by_call_id(nua_t * nua,const char * call_id)1101 nua_handle_t *nua_handle_by_call_id(nua_t *nua, const char *call_id)
1102 {
1103   if (nua) {
1104 #if HAVE_OPEN_C
1105     struct nua_stack_handle_by_call_id_args a;
1106 	a.retval = NULL;
1107     a.nua = nua;
1108     a.call_id = call_id;
1109 #else
1110     struct nua_stack_handle_by_call_id_args a = { NULL, nua, call_id };
1111 #endif
1112 
1113     if (su_task_execute(nua->nua_server,
1114 			nua_stack_handle_by_call_id_call, (void *)&a,
1115 			NULL) == 0) {
1116        return a.retval;
1117     }
1118   }
1119   return NULL;
1120 }
1121 
1122 /** Get leg from dialog. */
nua_get_dialog_state_leg(nua_handle_t * nh)1123 const nta_leg_t *nua_get_dialog_state_leg(nua_handle_t *nh)
1124 {
1125 	if (nh && nh->nh_ds)
1126 		return nh->nh_ds->ds_leg;
1127 	else
1128 		return NULL;
1129 }
1130 
1131 /** Get su_home_t from nua handle. */
nua_handle_get_home(nua_handle_t * nh)1132 su_home_t *nua_handle_get_home(nua_handle_t *nh)
1133 {
1134 	if (nh && nh->nh_home)
1135 		return nh->nh_home;
1136 	else
1137 		return NULL;
1138 }
1139 
1140 /** Get su_home_t from nua. */
nua_get_home(nua_t * nua)1141 su_home_t *nua_get_home(nua_t *nua)
1142 {
1143 	if (nua && nua->nua_home)
1144 		return nua->nua_home;
1145 	else
1146 		return NULL;
1147 }
1148 
1149 /** Get nta_agent_t from nua. */
nua_get_agent(nua_t * nua)1150 nta_agent_t *nua_get_agent(nua_t *nua)
1151 {
1152 	if (nua && nua->nua_nta)
1153 		return nua->nua_nta;
1154 	else
1155 		return NULL;
1156 }
1157 
1158 /** Set has invite of a nua handle */
nua_handle_set_has_invite(nua_handle_t * nh,unsigned val)1159 void nua_handle_set_has_invite(nua_handle_t *nh, unsigned val)
1160 {
1161 	if (nh)
1162 		nh->nh_has_invite = val;
1163 }
1164 
1165 /** Check if nua handle is destroyed */
nua_handle_is_destroyed(nua_handle_t * nh)1166 unsigned nua_handle_is_destroyed(nua_handle_t *nh)
1167 {
1168 	assert(nh);
1169 	return nh->nh_destroyed;
1170 }
1171 
nua_handle_dialog_usage_set_refresh_range(nua_handle_t * nh,unsigned min,unsigned max)1172 void nua_handle_dialog_usage_set_refresh_range(nua_handle_t *nh,
1173 	unsigned min, unsigned max) {
1174 	if (nh && nh->nh_ds && nh->nh_ds->ds_usage) {
1175 		nua_dialog_usage_set_refresh_range(nh->nh_ds->ds_usage, min, max);
1176 	}
1177 }
1178 
nua_unref_user(nua_t * nua)1179 void nua_unref_user(nua_t *nua)
1180 {
1181 	enter;
1182 	nua_signal(nua, NULL, NULL, nua_r_unref, 0, NULL, TAG_NULL());
1183 }
1184 
nua_handle_unref_user(nua_handle_t * nh)1185 void nua_handle_unref_user(nua_handle_t *nh)
1186 {
1187 	assert(nh);
1188 	nh_enter;
1189 	nua_signal(nh->nh_nua, nh, NULL, nua_r_handle_unref, 0, NULL, TAG_NULL());
1190 }
1191