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 enter;
219
220 if (nua) {
221 if (!nua->nua_shutdown_final) {
222 SU_DEBUG_0(("nua_destroy(%p): FATAL: nua_shutdown not completed\n",
223 (void *)nua));
224 assert(nua->nua_shutdown);
225 return;
226 }
227
228 nua->nua_callback = NULL;
229
230 su_task_deinit(nua->nua_server);
231 su_task_deinit(nua->nua_client);
232
233 su_clone_wait(nua->nua_api_root, nua->nua_clone);
234 #if HAVE_SMIME /* Start NRC Boston */
235 sm_destroy(nua->sm);
236 #endif /* End NRC Boston */
237 su_home_unref(nua->nua_home);
238 }
239 }
240
241 /** Fetch callback context from nua.
242 *
243 * @param nua Pointer to @nua stack object
244 *
245 * @return Callback context pointer.
246 *
247 * @NEW_1_12_4.
248 */
nua_magic(nua_t * nua)249 nua_magic_t *nua_magic(nua_t *nua)
250 {
251 return nua ? nua->nua_magic : NULL;
252 }
253
254 /** Obtain default operation handle of the @nua stack object.
255 *
256 * A default operation can be used for operations where the
257 * ultimate result is not important or can be discarded.
258 *
259 * @param nua Pointer to @nua stack object
260 *
261 * @retval !=NULL Pointer to @nua operation handle
262 * @retval NULL No default operation exists
263 *
264 * @par Related tags:
265 * none
266 *
267 * @par Events:
268 * none
269 *
270 */
nua_default(nua_t * nua)271 nua_handle_t *nua_default(nua_t *nua)
272 {
273 return nua ? nua->nua_handles : NULL;
274 }
275
276 /** Create an operation handle
277 *
278 * Allocates a new operation handle and associated storage.
279 *
280 * @param nua Pointer to @nua stack object
281 * @param hmagic Pointer to callback context
282 * @param tag, value, ... List of tagged parameters
283 *
284 * @retval !=NULL Pointer to operation handle
285 * @retval NULL Creation failed
286 *
287 * @par Related tags:
288 * Duplicates the provided tags for use with every operation. Note that
289 * NUTAG_URL() is converted to SIPTAG_TO() if there is no SIPTAG_TO().
290 * And also vice versa, request-URI is taken from SIPTAG_TO() if there
291 * is no NUTAG_URL(). Note that certain SIP headers cannot be saved with
292 * the handle. They include @ContentLength, @CSeq, @RSeq, @RAck, and
293 * @Timestamp.
294 *
295 * @par
296 * nua_handle() accepts all the tags accepted by nua_set_hparams(), too.
297 *
298 *
299 * @par Events:
300 * none
301 *
302 * @sa nua_handle_bind(), nua_handle_destroy(), nua_handle_ref(),
303 * nua_handle_unref().
304 */
nua_handle(nua_t * nua,nua_hmagic_t * hmagic,tag_type_t tag,tag_value_t value,...)305 nua_handle_t *nua_handle(nua_t *nua, nua_hmagic_t *hmagic,
306 tag_type_t tag, tag_value_t value, ...)
307 {
308 nua_handle_t *nh = NULL;
309
310 if (nua) {
311 ta_list ta;
312
313 ta_start(ta, tag, value);
314
315 nh = nh_create_handle(nua, hmagic, ta_args(ta));
316
317 if (nh)
318 nh->nh_ref_by_user = 1;
319
320 ta_end(ta);
321 }
322
323 return nh;
324 }
325
326 /** Bind a callback context to an operation handle.
327 *
328 * @param nh Pointer to operation handle
329 * @param hmagic Pointer to callback context
330 *
331 * @return
332 * nothing
333 *
334 * @par Related tags:
335 * none
336 *
337 * @par Events:
338 * none
339 */
nua_handle_bind(nua_handle_t * nh,nua_hmagic_t * hmagic)340 void nua_handle_bind(nua_handle_t *nh, nua_hmagic_t *hmagic)
341 {
342 enter;
343
344 if (NH_IS_VALID(nh))
345 nh->nh_magic = hmagic;
346 }
347
348 /** Fetch a callback context from an operation handle.
349 *
350 * @param nh Pointer to operation handle
351 *
352 * @return
353 * Pointer to callback context
354 *
355 * @par Related tags:
356 * none
357 *
358 * @par Events:
359 * none
360 *
361 * @NEW_1_12_4.
362 */
nua_handle_magic(nua_handle_t * nh)363 nua_hmagic_t *nua_handle_magic(nua_handle_t *nh)
364 {
365 nua_hmagic_t *magic = NULL;
366 enter;
367
368 if (NH_IS_VALID(nh))
369 magic = nh->nh_magic;
370
371 return magic;
372 }
373
374 /* ---------------------------------------------------------------------- */
375
376 /** Check if operation handle is used for INVITE
377 *
378 * Check if operation handle has been used with either outgoing or incoming
379 * INVITE request.
380 *
381 * @param nh Pointer to operation handle
382 *
383 * @retval 0 no invite in operation or operation handle is invalid
384 * @retval 1 operation has invite
385 *
386 * @par Related tags:
387 * none
388 *
389 * @par Events:
390 * none
391 */
nua_handle_has_invite(nua_handle_t const * nh)392 int nua_handle_has_invite(nua_handle_t const *nh)
393 {
394 return nh ? nh->nh_has_invite : 0;
395 }
396
397 /**Check if operation handle has active event subscriptions.
398 *
399 * Active subscription can be established either by nua_subscribe() or
400 * nua_refer() calls.
401 *
402 * @param nh Pointer to operation handle
403 *
404 * @retval 0 no event subscriptions in operation or
405 * operation handle is invalid
406 * @retval !=0 operation has event subscriptions
407 *
408 * @par Related tags:
409 * none
410 *
411 * @par Events:
412 * none
413 */
nua_handle_has_events(nua_handle_t const * nh)414 int nua_handle_has_events(nua_handle_t const *nh)
415 {
416 return nh ? nh->nh_ds->ds_has_events : 0;
417 }
418
419 /** Check if operation handle has active registrations
420 *
421 * A registration is active when either when a REGISTER operation is going
422 * on or when it has successfully completed so that @nua stack is expected to
423 * refresh the registration in the future. Normally, a handle has active
424 * registration after nua_register() until nua_unregister() completes,
425 * unless the initial nua_register() had either expiration time of 0 or it
426 * had SIPTAG_CONTACT(NULL) as an argument.
427 *
428 * @param nh Pointer to operation handle
429 *
430 * @retval 0 no active registration in operation or
431 * operation handle is invalid
432 * @retval 1 operation has registration
433 *
434 * @par Related tags:
435 * none
436 *
437 * @par Events:
438 * none
439 *
440 * @sa nua_register(), nua_unregister(), #nua_r_register, #nua_r_unregister
441 */
nua_handle_has_registrations(nua_handle_t const * nh)442 int nua_handle_has_registrations(nua_handle_t const *nh)
443 {
444 return nh && nh->nh_ds->ds_has_register;
445 }
446
447 /** Check if operation handle has been used with outgoing SUBSCRIBE of REFER request.
448 *
449 * @param nh Pointer to operation handle
450 *
451 * @retval 0 no active subscription in operation or
452 * operation handle is invalid
453 * @retval 1 operation has subscription.
454 *
455 * @par Related tags:
456 * none
457 *
458 * @par Events:
459 * none
460 */
nua_handle_has_subscribe(nua_handle_t const * nh)461 int nua_handle_has_subscribe(nua_handle_t const *nh)
462 {
463 return nh ? nh->nh_has_subscribe : 0;
464 }
465
466 /** Check if operation handle has been used with nua_register() or nua_unregister().
467 *
468 * @param nh Pointer to operation handle
469 *
470 * @retval 0 no active register in operation or operation handle is invalid
471 * @retval 1 operation has been used with nua_register() or nua-unregister()
472 *
473 * @par Related tags:
474 * none
475 *
476 * @par Events:
477 * none
478 */
nua_handle_has_register(nua_handle_t const * nh)479 int nua_handle_has_register(nua_handle_t const *nh)
480 {
481 return nh ? nh->nh_has_register : 0;
482 }
483
484 /** Check if operation handle has an active call
485 *
486 * @param nh Pointer to operation handle
487 *
488 * @retval 0 no active call in operation or operation handle is invalid
489 * @retval 1 operation has established call or pending call request.
490 *
491 * @par Related tags:
492 * none
493 *
494 * @par Events:
495 * none
496 */
nua_handle_has_active_call(nua_handle_t const * nh)497 int nua_handle_has_active_call(nua_handle_t const *nh)
498 {
499 return nh ? nh->nh_active_call : 0;
500 }
501
502 /** Check if operation handle has a call on hold
503 *
504 * Please note that this status is not affected by remote end putting
505 * this end on hold. Remote end can put each media separately on hold
506 * and status is reflected on SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO()
507 * and SOATAG_ACTIVE_CHAT() tag values in #nua_i_state event.
508 *
509 * @param nh Pointer to operation handle
510 *
511 * @retval 0 if no call on hold in operation or operation handle is invalid
512 * @retval 1 if operation has call on hold, for example nua_invite() or
513 * nua_update() has been called with SOATAG_HOLD() with non-NULL
514 * argument.
515 *
516 * @par Related tags:
517 * none
518 *
519 * @par Events:
520 * none
521 */
nua_handle_has_call_on_hold(nua_handle_t const * nh)522 int nua_handle_has_call_on_hold(nua_handle_t const *nh)
523 {
524 return nh ? nh->nh_hold_remote : 0;
525 }
526
527 /** Get the remote address (From/To header) of operation handle
528 *
529 * Remote address is used as To header in outgoing operations and
530 * derived from From: header in incoming operations.
531 *
532 * @param nh Pointer to operation handle
533 *
534 * @retval NULL no remote address for operation or operation handle invalid
535 * @retval !=NULL pointer to remote address for operation
536 *
537 * @par Related tags:
538 * none
539 *
540 * @par Events:
541 * none
542 */
nua_handle_remote(nua_handle_t const * nh)543 sip_to_t const *nua_handle_remote(nua_handle_t const *nh)
544 {
545 return nh ? nh->nh_ds->ds_remote : NULL;
546 }
547
548 /** Get the local address (From/To header) of operation handle
549 *
550 * Local address is used as From header in outgoing operations and
551 * derived from To: header in incoming operations.
552 *
553 * @param nh Pointer to operation handle
554 *
555 * @retval NULL no local address for operation or operation handle invalid
556 * @retval !=NULL pointer to local address for operation
557 *
558 * @par Related tags:
559 * none
560 *
561 * @par Events:
562 * none
563 */
nua_handle_local(nua_handle_t const * nh)564 sip_to_t const *nua_handle_local(nua_handle_t const *nh)
565 {
566 return nh ? nh->nh_ds->ds_local : NULL;
567 }
568
569 /* Documented with nua_stack_set_params() */
nua_set_params(nua_t * nua,tag_type_t tag,tag_value_t value,...)570 void nua_set_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
571 {
572 ta_list ta;
573 ta_start(ta, tag, value);
574
575 enter;
576
577 nua_signal(nua, NULL, NULL, nua_r_set_params, 0, NULL, ta_tags(ta));
578
579 ta_end(ta);
580 }
581
582 /* Documented with nua_stack_get_params() */
nua_get_params(nua_t * nua,tag_type_t tag,tag_value_t value,...)583 void nua_get_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
584 {
585 ta_list ta;
586 ta_start(ta, tag, value);
587
588 enter;
589
590 nua_signal(nua, NULL, NULL, nua_r_get_params, 0, NULL, ta_tags(ta));
591
592 ta_end(ta);
593 }
594
595 #define NUA_SIGNAL(nh, event, tag, value) \
596 enter; \
597 if (NH_IS_VALID((nh))) { \
598 ta_list ta; \
599 ta_start(ta, tag, value); \
600 nua_signal((nh)->nh_nua, nh, NULL, event, 0, NULL, ta_tags(ta)); \
601 ta_end(ta); \
602 } \
603 else { \
604 SU_DEBUG_1(("nua: " #event " with invalid handle %p\n", (void *)nh)); \
605 }
606
607 /* Documented with nua_stack_set_params() */
nua_set_hparams(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)608 void nua_set_hparams(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
609 {
610 NUA_SIGNAL(nh, nua_r_set_params, tag, value);
611 }
612
613 /* Documented with nua_stack_get_params() */
nua_get_hparams(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)614 void nua_get_hparams(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
615 {
616 NUA_SIGNAL(nh, nua_r_get_params, tag, value);
617 }
618
619 /* Documented with nua_stack_register() */
nua_register(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)620 void nua_register(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
621 {
622 NUA_SIGNAL(nh, nua_r_register, tag, value);
623 }
624
nua_unregister(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)625 void nua_unregister(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
626 {
627 NUA_SIGNAL(nh, nua_r_unregister, tag, value);
628 }
629
630 /* Documented with nua_stack_invite() */
nua_invite(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)631 void nua_invite(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
632 {
633 NUA_SIGNAL(nh, nua_r_invite, tag, value);
634 }
635
636 /* Documented with nua_stack_ack() */
nua_ack(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)637 void nua_ack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
638 {
639 NUA_SIGNAL(nh, nua_r_ack, tag, value);
640 }
641
642 /* Documented with nua_stack_bye() */
nua_bye(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)643 void nua_bye(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
644 {
645 NUA_SIGNAL(nh, nua_r_bye, tag, value);
646 }
647
648 /* Documented with nua_stack_cancel() */
nua_cancel(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)649 void nua_cancel(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
650 {
651 NUA_SIGNAL(nh, nua_r_cancel, tag, value);
652 }
653
654 /* Documented with nua_stack_options() */
nua_options(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)655 void nua_options(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
656 {
657 NUA_SIGNAL(nh, nua_r_options, tag, value);
658 }
659
660 /* Documented with nua_stack_message() */
nua_message(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)661 void nua_message(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
662 {
663 NUA_SIGNAL(nh, nua_r_message, tag, value);
664 }
665
666 /* Documented with nua_stack_method() */
nua_method(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)667 void nua_method(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
668 {
669 NUA_SIGNAL(nh, nua_r_method, tag, value);
670 }
671
672 /** Send a chat message.
673 *
674 * A chat channel can be established during call setup using "message" media.
675 * An active chat channel is indicated using #nua_i_state event containing
676 * SOATAG_ACTIVE_CHAT() tag. Chat messages can be sent using this channel with
677 * nua_chat() function. Currently this is implemented using SIP MESSAGE
678 * requests but in future MSRP (message session protocol) will replace it.
679 *
680 * @param nh Pointer to operation handle
681 * @param tag, value, ... List of tagged parameters
682 *
683 * @return
684 * nothing
685 *
686 * @par Related Tags:
687 * SIPTAG_CONTENT_TYPE() \n
688 * SIPTAG_PAYLOAD() \n
689 * SIPTAG_FROM() \n
690 * SIPTAG_TO() \n
691 * Use of other SIP tags is deprecated
692 *
693 * @par Events:
694 * #nua_r_chat
695 */
nua_chat(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)696 void nua_chat(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
697 {
698 NUA_SIGNAL(nh, nua_r_chat, tag, value);
699 }
700
701 /* Documented with nua_stack_subscribe() */
nua_subscribe(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)702 void nua_subscribe(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
703 {
704 NUA_SIGNAL(nh, nua_r_subscribe, tag, value);
705 }
706
707 /* Documented with nua_stack_subscribe() */
nua_unsubscribe(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)708 void nua_unsubscribe(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
709 {
710 NUA_SIGNAL(nh, nua_r_unsubscribe, tag, value);
711 }
712
713 /* Documented with nua_stack_notify() */
nua_notify(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)714 void nua_notify(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
715 {
716 NUA_SIGNAL(nh, nua_r_notify, tag, value);
717 }
718
719 /* nua_r_notify is documented with process_response_to_notify() */
720
721 /** Create an event server.
722 *
723 * This function create an event server taking care of sending NOTIFY
724 * requests and responding to further SUBSCRIBE requests. The event
725 * server can accept multiple subscriptions from several sources and
726 * takes care for distributing the notifications. Unlike other functions
727 * this call only accepts the SIP tags listed below.
728 *
729 * @param nh Pointer to operation handle
730 * @param tag, value, ... List of tagged parameters
731 *
732 * @return
733 * nothing
734 *
735 * @par Related Tags:
736 * NUTAG_URL() \n
737 * SIPTAG_EVENT() or SIPTAG_EVENT_STR() \n
738 * SIPTAG_CONTENT_TYPE() or SIPTAG_CONTENT_TYPE_STR() \n
739 * SIPTAG_PAYLOAD() or SIPTAG_PAYLOAD_STR() \n
740 * SIPTAG_ACCEPT() or SIPTAG_ACCEPT_STR() \n
741 *
742 * @par Events:
743 * #nua_r_notify
744 */
nua_notifier(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)745 void nua_notifier(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
746 {
747 NUA_SIGNAL(nh, nua_r_notifier, tag, value);
748 }
749
750 /** Terminate an event server.
751 *
752 * Terminate an event server with matching event and content type. The event
753 * server was created earlier with nua_notifier() function.
754 *
755 * @param nh Pointer to operation handle
756 * @param tag, value, ... List of tagged parameters
757 *
758 * @return
759 * nothing
760 *
761 * @par Related Tags:
762 * SIPTAG_EVENT() \n
763 * SIPTAG_CONTENT_TYPE() \n
764 * SIPTAG_PAYLOAD() \n
765 * NEATAG_REASON()
766 *
767 * @par Events:
768 * #nua_r_terminate
769 *
770 * @sa nua_notifier(), nua_authorize().
771 */
nua_terminate(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)772 void nua_terminate(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
773 {
774 NUA_SIGNAL(nh, nua_r_terminate, tag, value);
775 }
776
777 /* Documented with nua_stack_refer() */
nua_refer(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)778 void nua_refer(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
779 {
780 NUA_SIGNAL(nh, nua_r_refer, tag, value);
781 }
782
783 /* Documented with nua_stack_publish() */
nua_publish(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)784 void nua_publish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
785 {
786 NUA_SIGNAL(nh, nua_r_publish, tag, value);
787 }
788
789 /* Documented with nua_stack_publish() */
nua_unpublish(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)790 void nua_unpublish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
791 {
792 NUA_SIGNAL(nh, nua_r_unpublish, tag, value);
793 }
794
795 /* Documented with nua_stack_info() */
nua_info(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)796 void nua_info(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
797 {
798 NUA_SIGNAL(nh, nua_r_info, tag, value);
799 }
800
801 /* Documented with nua_stack_prack() */
nua_prack(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)802 void nua_prack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
803 {
804 NUA_SIGNAL(nh, nua_r_prack, tag, value);
805 }
806
807 /* Documented with nua_stack_update() */
nua_update(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)808 void nua_update(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
809 {
810 NUA_SIGNAL(nh, nua_r_update, tag, value);
811 }
812
813 /** Authenticate an operation.
814 *
815 * - 401 / 407 response with www-authenticate header/ proxy-authenticate header
816 * - application should provide stack with username&password for each realm
817 * with NUTAG_AUTH() tag
818 * - restarts operation
819 *
820 * @param nh Pointer to operation handle
821 * @param tag, value, ... List of tagged parameters
822 *
823 * @return
824 * nothing
825 *
826 * @par Related Tags:
827 * NUTAG_AUTH()
828 *
829 * @par Events:
830 * (any operation events)
831 */
nua_authenticate(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)832 void nua_authenticate(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
833 {
834 NUA_SIGNAL(nh, nua_r_authenticate, tag, value);
835 }
836
837 /** Authorize a subscriber.
838 *
839 * After creating a local presence server by nua_notifier(), an incoming
840 * SUBSCRIBE request causes #nua_i_subscription event. Each subscriber is
841 * identified with NEATAG_SUB() tag in the #nua_i_subscription event.
842 * Application can either authorize the subscriber with
843 * NUTAG_SUBSTATE(#nua_substate_active) or terminate the subscription with
844 * NUTAG_SUBSTATE(#nua_substate_terminated).
845 *
846 * @param nh Pointer to operation handle
847 * @param tag, value, ... List of tagged parameters
848 *
849 * @return
850 * nothing
851 *
852 * @par Related Tags:
853 * NEATAG_SUB() \n
854 * NUTAG_SUBSTATE()
855 *
856 * @par Events:
857 * #nua_i_subscription
858 *
859 * @sa nua_notifier(), nua_terminate()
860 */
nua_authorize(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)861 void nua_authorize(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
862 {
863 NUA_SIGNAL(nh, nua_r_authorize, tag, value);
864 }
865
866 /*# Redirect an operation. */
nua_redirect(nua_handle_t * nh,tag_type_t tag,tag_value_t value,...)867 void nua_redirect(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
868 {
869 NUA_SIGNAL(nh, nua_r_redirect, tag, value);
870 }
871
872 /* Documented with nua_stack_respond() */
873
nua_respond(nua_handle_t * nh,int status,char const * phrase,tag_type_t tag,tag_value_t value,...)874 void nua_respond(nua_handle_t *nh,
875 int status, char const *phrase,
876 tag_type_t tag, tag_value_t value,
877 ...)
878 {
879 enter;
880
881 if (NH_IS_VALID(nh)) {
882 ta_list ta;
883 ta_start(ta, tag, value);
884 nua_signal(nh->nh_nua, nh, NULL, nua_r_respond,
885 status, phrase, ta_tags(ta));
886 ta_end(ta);
887 }
888 else {
889 SU_DEBUG_1(("nua: respond with invalid handle %p\n", (void *)nh));
890 }
891 }
892
893 /** Destroy a handle
894 *
895 * Terminate the protocol state associated with an operation handle. The
896 * stack discards resources and terminates the ongoing dialog usage,
897 * sessions and transactions associated with this handle. For example, calls
898 * are terminated with BYE request. Also, the reference count for the handle
899 * is also decremented.
900 *
901 * The handles use reference counting for memory management. In order to
902 * make it more convenient for programmer, nua_handle_destroy() decreases
903 * the reference count, too.
904 *
905 * @param nh Pointer to operation handle
906 *
907 * @return
908 * nothing
909 *
910 * @par Related Tags:
911 * none
912 *
913 * @par Events:
914 * none
915 *
916 * @sa nua_handle(), nua_handle_bind(), nua_handle_ref(), nua_handle_unref(),
917 * nua_unregister(), nua_unpublish(), nua_unsubscribe(), nua_bye().
918 */
nua_handle_destroy(nua_handle_t * nh)919 void nua_handle_destroy(nua_handle_t *nh)
920 {
921 enter;
922
923 if (NH_IS_VALID(nh) && !NH_IS_DEFAULT(nh)) {
924 nh->nh_valid = NULL; /* Events are no more delivered to appl. */
925 nua_signal(nh->nh_nua, nh, NULL, nua_r_destroy, 0, NULL, TAG_END());
926 }
927 }
928
929 /* ---------------------------------------------------------------------- */
930
931 struct nua_stack_handle_make_replaces_args {
932 sip_replaces_t *retval;
933 nua_handle_t *nh;
934 su_home_t *home;
935 int early_only;
936 };
937
nua_stack_handle_make_replaces_call(void * arg)938 static int nua_stack_handle_make_replaces_call(void *arg)
939 {
940 struct nua_stack_handle_make_replaces_args *a = arg;
941
942 a->retval = nua_stack_handle_make_replaces(a->nh, a->home, a->early_only);
943
944 return 0;
945 }
946
947
948 /**Generate a @Replaces header for handle.
949 *
950 * A @Replaces header contains the @CallID value, @From and @To tags
951 * corresponding to SIP dialog associated with handle @a nh. Note that the
952 * @Replaces matches with dialog of the remote peer,
953 * nua_handle_by_replaces() does not return same handle (unless you swap
954 * rp_from_tag and rp_to_tag in @Replaces header).
955 *
956 * A @Replaces header is used in attended transfer, among other things.
957 *
958 * @param nh pointer to operation handle
959 * @param home memory home used to allocate the header
960 * @param early_only if true, include "early-only" parameter in @Replaces, too
961 *
962 * @return A newly created @Replaces header.
963 *
964 * @since New in @VERSION_1_12_4.
965 *
966 * @sa nua_handle_by_replaces(), @Replaces, @RFC3891, @RFC3515, nua_refer(),
967 * #nua_i_refer(), @ReferTo, nta_leg_make_replaces(),
968 * sip_headers_as_url_query()
969 */
nua_handle_make_replaces(nua_handle_t * nh,su_home_t * home,int early_only)970 sip_replaces_t *nua_handle_make_replaces(nua_handle_t *nh,
971 su_home_t *home,
972 int early_only)
973 {
974 if (nh && nh->nh_valid && nh->nh_nua) {
975 #if HAVE_OPEN_C
976 struct nua_stack_handle_make_replaces_args a = { NULL, NULL, NULL, 0 };
977 a.nh = nh;
978 a.home = home;
979 a.early_only = early_only;
980 #else
981 struct nua_stack_handle_make_replaces_args a = { NULL, nh, home, early_only };
982 #endif
983
984 if (su_task_execute(nh->nh_nua->nua_server,
985 nua_stack_handle_make_replaces_call, (void *)&a,
986 NULL) == 0) {
987 return a.retval;
988 }
989 }
990 return NULL;
991 }
992
993 struct nua_stack_handle_by_replaces_args {
994 nua_handle_t *retval;
995 nua_t *nua;
996 sip_replaces_t const *r;
997 };
998
nua_stack_handle_by_replaces_call(void * arg)999 static int nua_stack_handle_by_replaces_call(void *arg)
1000 {
1001 struct nua_stack_handle_by_replaces_args *a = arg;
1002
1003 a->retval = nua_stack_handle_by_replaces(a->nua, a->r);
1004
1005 return 0;
1006 }
1007
1008 struct nua_stack_handle_by_call_id_args {
1009 nua_handle_t *retval;
1010 nua_t *nua;
1011 const char *call_id;
1012 };
1013
nua_stack_handle_by_call_id_call(void * arg)1014 static int nua_stack_handle_by_call_id_call(void *arg)
1015 {
1016 struct nua_stack_handle_by_call_id_args *a = arg;
1017
1018 a->retval = nua_stack_handle_by_call_id(a->nua, a->call_id);
1019
1020 return 0;
1021 }
1022
1023 /** Obtain a new reference to an existing handle based on @Replaces header.
1024 *
1025 * @since New in @VERSION_1_12_4.
1026 *
1027 * @note
1028 * You should release the reference with nua_handle_unref() when you are
1029 * done with the handle.
1030 *
1031 * @sa nua_handle_make_replaces(), @Replaces, @RFC3891, nua_refer(),
1032 * #nua_i_refer, @ReferTo, nta_leg_by_replaces()
1033 */
nua_handle_by_replaces(nua_t * nua,sip_replaces_t const * r)1034 nua_handle_t *nua_handle_by_replaces(nua_t *nua, sip_replaces_t const *r)
1035 {
1036 if (nua) {
1037 #if HAVE_OPEN_C
1038 struct nua_stack_handle_by_replaces_args a;
1039 a.retval = NULL;
1040 a.nua = nua;
1041 a.r = r;
1042 #else
1043 struct nua_stack_handle_by_replaces_args a = { NULL, nua, r };
1044 #endif
1045
1046 if (su_task_execute(nua->nua_server,
1047 nua_stack_handle_by_replaces_call, (void *)&a,
1048 NULL) == 0) {
1049 nua_handle_t *nh = a.retval;
1050
1051 if (nh && !NH_IS_DEFAULT(nh) && nh->nh_valid)
1052 return nua_handle_ref(nh);
1053 }
1054 }
1055 return NULL;
1056 }
1057
1058 /** Obtain a new reference to an existing handle based on @CallID.
1059 *
1060 * @since New in @VERSION_1_12_9.
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_call_id(nua_t * nua,const char * call_id)1069 nua_handle_t *nua_handle_by_call_id(nua_t *nua, const char *call_id)
1070 {
1071 if (nua) {
1072 #if HAVE_OPEN_C
1073 struct nua_stack_handle_by_call_id_args a;
1074 a.retval = NULL;
1075 a.nua = nua;
1076 a.call_id = call_id;
1077 #else
1078 struct nua_stack_handle_by_call_id_args a = { NULL, nua, call_id };
1079 #endif
1080
1081 if (su_task_execute(nua->nua_server,
1082 nua_stack_handle_by_call_id_call, (void *)&a,
1083 NULL) == 0) {
1084 nua_handle_t *nh = a.retval;
1085
1086 if (nh && !NH_IS_DEFAULT(nh) && nh->nh_valid)
1087 return nua_handle_ref(nh);
1088 }
1089 }
1090 return NULL;
1091 }
1092