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