nua.c 27.9 KB
Newer Older
Pekka Pessi's avatar
Pekka Pessi committed
1 2 3
/*
 * This file is part of the Sofia-SIP package
 *
4
 * Copyright (C) 2006 Nokia Corporation.
Pekka Pessi's avatar
Pekka Pessi committed
5 6 7
 *
 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
 *
8
 * This library is free software; you can redistribute it and/or
Pekka Pessi's avatar
Pekka Pessi committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

Pekka Pessi's avatar
Pekka Pessi committed
25
/**@internal @file nua.c High-Level User Agent Library - "nua" Implementation.
Pekka Pessi's avatar
Pekka Pessi committed
26 27
 *
 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
28 29
 * @author Kai Vehmanen <Kai.Vehmanen@nokia.com>
 * @author Pasi Rinne-Rahkola
Pekka Pessi's avatar
Pekka Pessi committed
30 31 32 33 34 35
 *
 * @date Created: Wed Feb 14 18:32:58 2001 ppessi
 */

#include "config.h"

36 37 38
#include <sofia-sip/su_tag.h>
#include <sofia-sip/su_tag_class.h>
#include <sofia-sip/su_tagarg.h>
Pekka Pessi's avatar
Pekka Pessi committed
39

40
#include <sofia-sip/su_tag_io.h>
Pekka Pessi's avatar
Pekka Pessi committed
41 42

#define SU_LOG (nua_log)
43
#include <sofia-sip/su_debug.h>
Pekka Pessi's avatar
Pekka Pessi committed
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>
Pekka Pessi's avatar
Pekka Pessi committed
50

51 52
#include "sofia-sip/nua.h"
#include "sofia-sip/nua_tag.h"
Pekka Pessi's avatar
Pekka Pessi committed
53 54
#include "nua_stack.h"

55 56 57 58 59
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
Pekka Pessi's avatar
Pekka Pessi committed
60

Pekka Pessi's avatar
Pekka Pessi committed
61 62 63
/* From AM_INIT/AC_INIT in our "config.h" */
char const nua_version[] = VERSION;

64
/**Environment variable determining the debug log level for @nua module.
Pekka Pessi's avatar
Pekka Pessi committed
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
Pekka Pessi's avatar
Pekka Pessi committed
70 71 72 73 74 75 76
 */
extern char const NUA_DEBUG[];

#ifndef SU_DEBUG
#define SU_DEBUG 3
#endif

77 78
/**Debug log for @nua module.
 *
79
 * The nua_log is the log object used by @nua module. The level of
Pekka Pessi's avatar
Pekka Pessi committed
80 81 82 83
 * #nua_log is set using #NUA_DEBUG environment variable.
 */
su_log_t nua_log[] = { SU_LOG_INIT("nua", "NUA_DEBUG", SU_DEBUG) };

84
/**Create a @nua agent.
Pekka Pessi's avatar
Pekka Pessi committed
85
 *
86
 * This function creates a Sofia-SIP User Agent stack object (@nua) and
Pekka Pessi's avatar
Pekka Pessi committed
87 88 89 90 91 92 93
 * initializes its parameters by given tagged values.
 *
 * @param root            Pointer to a root object
 * @param callback        Pointer to event callback function
 * @param magic           Pointer to callback context
 * @param tag,value,... List of tagged parameters
 *
Pekka Pessi's avatar
Pekka Pessi committed
94
 * @retval !=NULL a pointer to a @nua stack object
Pekka Pessi's avatar
Pekka Pessi committed
95 96 97
 * @retval NULL upon an error
 *
 * @par Related tags:
Pekka Pessi's avatar
Pekka Pessi committed
98 99 100 101
 * - NUTAG_PROXY(), giving the URI of the outbound proxy
 *   (but see also NUTAG_INITIAL_ROUTE()).
 * - NUTAG_URL() (and NUTAG_SIPS_URL(), listing URIs describing
 *   transports)
102
 * - NUTAG_CERTIFICATE_DIR(), specifying the location of the
Pekka Pessi's avatar
Pekka Pessi committed
103
 *   root and client/server certificate files
104
 * - NUTAG_SIP_PARSER(), providing customized parser used to
Pekka Pessi's avatar
Pekka Pessi committed
105 106 107
 *   parse received SIP messages
 * - All parameter tags, listed with nua_set_params()
 * - All NTATAG_* are passed to NTA documented in <sofia-sip/nta_tag.h>:
108 109
 *   see NTATAG_EXTRA_100(),
 * - All tport tags are passed to tport.
Pekka Pessi's avatar
Pekka Pessi committed
110 111 112 113 114 115
 *   They are documented in <sofia-sip/tport_tag.h>
 * - All SOATAG_* are passed to the default SOA (media session) object which
 *   is created by nua_create() unless NUTAG_MEDIA_ENABLE(0) is included in
 *   the tag list
 * - STUN tags STUNTAG_DOMAIN(), STUNTAG_SERVER().
 *   STUN is deprecated, however.
Pekka Pessi's avatar
Pekka Pessi committed
116
 *
Pekka Pessi's avatar
Pekka Pessi committed
117
 * @note
118
 * From the @VERSION_1_12_2 all the nua_set_params() tags are processed.
119 120 121 122 123
 * Previously all nutags except NUTAG_SOA_NAME() and NUTAG_MEDIA_ENABLE()
 * were ignored.
 *
 * @note
 * Both the NUTAG_URL() and NUTAG_SIPS_URL() are used to pass arguments to
124
 * nta_agent_add_tport().
Pekka Pessi's avatar
Pekka Pessi committed
125
 *
Pekka Pessi's avatar
Pekka Pessi committed
126 127
 * @par Events:
 *     none
128
 *
129
 * @sa nua_shutdown(), nua_destroy(), nua_handle(), nta_agent_create().
Pekka Pessi's avatar
Pekka Pessi committed
130 131 132 133 134 135 136 137 138 139
 */
nua_t *nua_create(su_root_t *root,
		  nua_callback_f callback,
		  nua_magic_t *magic,
		  tag_type_t tag, tag_value_t value, ...)
{
  nua_t *nua = NULL;

  enter;

140 141
  if (callback == NULL)
    return (void)(errno = EFAULT), NULL;
Pekka Pessi's avatar
Pekka Pessi committed
142

143 144 145
  if (root == NULL)
    return (void)(errno = EFAULT), NULL;

146
  if ((nua = su_home_new(sizeof(*nua)))) {
Pekka Pessi's avatar
Pekka Pessi committed
147 148 149 150 151 152 153
    ta_list ta;

    su_home_threadsafe(nua->nua_home);
    nua->nua_api_root = root;

    ta_start(ta, tag, value);

154
    nua->nua_args = tl_adup(nua->nua_home, ta_args(ta));
Pekka Pessi's avatar
Pekka Pessi committed
155 156 157 158 159 160 161 162 163 164 165 166

    su_task_copy(nua->nua_client, su_root_task(root));

    /* XXX: where to put this in the nua_server case? */
#if HAVE_SMIME		/* Start NRC Boston */
      nua->sm = sm_create();
#endif                  /* End NRC Boston */

#ifndef NUA_SERVER
    if (su_clone_start(root,
		       nua->nua_clone,
		       nua,
167 168
		       nua_stack_init,
		       nua_stack_deinit) == SU_SUCCESS) {
Pekka Pessi's avatar
Pekka Pessi committed
169 170 171 172 173
      su_task_copy(nua->nua_server, su_clone_task(nua->nua_clone));
      nua->nua_callback = callback;
      nua->nua_magic = magic;
    }
    else {
174
      su_home_unref(nua->nua_home);
Pekka Pessi's avatar
Pekka Pessi committed
175 176 177 178 179 180 181 182 183 184
      nua = NULL;
    }
#endif

    ta_end(ta);
  }

  return nua;
}

185 186
/* nua_shutdown() is documented with nua_stack_shutdown() */

Pekka Pessi's avatar
Pekka Pessi committed
187 188 189 190
void nua_shutdown(nua_t *nua)
{
  enter;

191 192
  if (nua)
    nua->nua_shutdown_started = 1;
193
  nua_signal(nua, NULL, NULL, nua_r_shutdown, 0, NULL, TAG_END());
Pekka Pessi's avatar
Pekka Pessi committed
194 195
}

196
/** Destroy the @nua stack.
Pekka Pessi's avatar
Pekka Pessi committed
197
 *
198
 * Before calling nua_destroy() the application
Pekka Pessi's avatar
Pekka Pessi committed
199
 * should call nua_shutdown and wait for successful #nua_r_shutdown event.
200
 * Shuts down and destroys the @nua stack. Ongoing calls, registrations,
Pekka Pessi's avatar
Pekka Pessi committed
201 202
 * and subscriptions are left as they are.
 *
203
 * @param nua         Pointer to @nua stack object
Pekka Pessi's avatar
Pekka Pessi committed
204 205 206 207 208 209 210 211 212
 *
 * @return
 *     nothing
 *
 * @par Related tags:
 *     none
 *
 * @par Events:
 *     none
213 214
 *
 * @sa nua_shutdown(), nua_create(), nua_handle_destroy(), nua_handle_unref()
Pekka Pessi's avatar
Pekka Pessi committed
215 216 217 218 219 220
 */
void nua_destroy(nua_t *nua)
{
  enter;

  if (nua) {
221
    if (!nua->nua_shutdown_final) {
222 223
      SU_DEBUG_0(("nua_destroy(%p): FATAL: nua_shutdown not completed\n",
		  (void *)nua));
224
      assert(nua->nua_shutdown);
225 226 227
      return;
    }

228 229
    nua->nua_callback = NULL;

230
    su_task_deinit(nua->nua_server);
231 232
    su_task_deinit(nua->nua_client);

Pekka Pessi's avatar
Pekka Pessi committed
233 234 235 236
    su_clone_wait(nua->nua_api_root, nua->nua_clone);
#if HAVE_SMIME		/* Start NRC Boston */
    sm_destroy(nua->sm);
#endif			/* End NRC Boston */
237
    su_home_unref(nua->nua_home);
Pekka Pessi's avatar
Pekka Pessi committed
238 239 240
  }
}

241 242 243 244 245
/** Fetch callback context from nua.
 *
 * @param nua         Pointer to @nua stack object
 *
 * @return Callback context pointer.
246 247
 *
 * @NEW_1_12_4.
248 249 250
 */
nua_magic_t *nua_magic(nua_t *nua)
{
251
  return nua ? nua->nua_magic : NULL;
252 253
}

254
/** Obtain default operation handle of the @nua stack object.
Pekka Pessi's avatar
Pekka Pessi committed
255
 *
256
 * A default operation can be used for operations where the
Pekka Pessi's avatar
Pekka Pessi committed
257 258
 * ultimate result is not important or can be discarded.
 *
259
 * @param nua         Pointer to @nua stack object
Pekka Pessi's avatar
Pekka Pessi committed
260
 *
261
 * @retval !=NULL Pointer to @nua operation handle
Pekka Pessi's avatar
Pekka Pessi committed
262 263 264 265 266 267 268 269
 * @retval NULL   No default operation exists
 *
 * @par Related tags:
 *    none
 *
 * @par Events:
 *    none
 *
Pekka Pessi's avatar
Pekka Pessi committed
270
 */
Pekka Pessi's avatar
Pekka Pessi committed
271 272
nua_handle_t *nua_default(nua_t *nua)
{
Pekka Pessi's avatar
Pekka Pessi committed
273
  return nua ? nua->nua_handles : NULL;
Pekka Pessi's avatar
Pekka Pessi committed
274 275
}

276
/** Create an operation handle
Pekka Pessi's avatar
Pekka Pessi committed
277 278 279
 *
 * Allocates a new operation handle and associated storage.
 *
280
 * @param nua         Pointer to @nua stack object
Pekka Pessi's avatar
Pekka Pessi committed
281 282 283 284 285 286 287
 * @param hmagic      Pointer to callback context
 * @param tag, value, ... List of tagged parameters
 *
 * @retval !=NULL  Pointer to operation handle
 * @retval NULL    Creation failed
 *
 * @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 291 292 293
 *     And also vice versa, request-URI is taken from SIPTAG_TO() if there
 *     is no NUTAG_URL(). Note that certain SIP headers cannot be saved with
 *     the handle. They include @ContentLength, @CSeq, @RSeq, @RAck, and
 *     @Timestamp.
Pekka Pessi's avatar
Pekka Pessi committed
294
 *
295 296 297 298
 * @par
 *     nua_handle() accepts all the tags accepted by nua_set_hparams(), too.
 *
 *
Pekka Pessi's avatar
Pekka Pessi committed
299 300 301
 * @par Events:
 *     none
 *
302 303
 * @sa nua_handle_bind(), nua_handle_destroy(), nua_handle_ref(),
 * nua_handle_unref().
Pekka Pessi's avatar
Pekka Pessi committed
304 305 306 307 308 309 310 311 312 313 314 315
 */
nua_handle_t *nua_handle(nua_t *nua, nua_hmagic_t *hmagic,
			 tag_type_t tag, tag_value_t value, ...)
{
  nua_handle_t *nh = NULL;

  if (nua) {
    ta_list ta;

    ta_start(ta, tag, value);

    nh = nh_create_handle(nua, hmagic, ta_args(ta));
316

Pekka Pessi's avatar
Pekka Pessi committed
317 318 319 320 321 322 323 324 325
    if (nh)
      nh->nh_ref_by_user = 1;

    ta_end(ta);
  }

  return nh;
}

326
/** Bind a callback context to an operation handle.
Pekka Pessi's avatar
Pekka Pessi committed
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
 *
 * @param nh          Pointer to operation handle
 * @param hmagic      Pointer to callback context
 *
 * @return
 *     nothing
 *
 * @par Related tags:
 *     none
 *
 * @par Events:
 *     none
 */
void nua_handle_bind(nua_handle_t *nh, nua_hmagic_t *hmagic)
{
  enter;

  if (NH_IS_VALID(nh))
    nh->nh_magic = hmagic;
}

348
/** Fetch a callback context from an operation handle.
349 350 351 352 353 354 355 356 357 358 359
 *
 * @param nh          Pointer to operation handle
 *
 * @return
 *     Pointer to callback context
 *
 * @par Related tags:
 *     none
 *
 * @par Events:
 *     none
360 361
 *
 * @NEW_1_12_4.
362
 */
363
nua_hmagic_t *nua_handle_magic(nua_handle_t *nh)
364 365 366 367 368 369
{
  nua_hmagic_t *magic = NULL;
  enter;

  if (NH_IS_VALID(nh))
    magic = nh->nh_magic;
370

371 372 373
  return magic;
}

Pekka Pessi's avatar
Pekka Pessi committed
374 375 376 377
/* ---------------------------------------------------------------------- */

/** Check if operation handle is used for INVITE
 *
378 379
 * Check if operation handle has been used with either outgoing or incoming
 * INVITE request.
Pekka Pessi's avatar
Pekka Pessi committed
380 381 382
 *
 * @param nh          Pointer to operation handle
 *
383 384
 * @retval 0 no invite in operation or operation handle is invalid
 * @retval 1 operation has invite
Pekka Pessi's avatar
Pekka Pessi committed
385 386 387 388 389 390 391 392 393 394 395 396
 *
 * @par Related tags:
 *     none
 *
 * @par Events:
 *     none
 */
int nua_handle_has_invite(nua_handle_t const *nh)
{
  return nh ? nh->nh_has_invite : 0;
}

397
/**Check if operation handle has active event subscriptions.
Pekka Pessi's avatar
Pekka Pessi committed
398
 *
399 400
 * Active subscription can be established either by nua_subscribe() or
 * nua_refer() calls.
Pekka Pessi's avatar
Pekka Pessi committed
401 402 403
 *
 * @param nh          Pointer to operation handle
 *
404 405
 * @retval 0    no event subscriptions in operation or
 *              operation handle is invalid
Pekka Pessi's avatar
Pekka Pessi committed
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
 * @retval !=0  operation has event subscriptions
 *
 * @par Related tags:
 *     none
 *
 * @par Events:
 *     none
 */
int nua_handle_has_events(nua_handle_t const *nh)
{
  return nh ? nh->nh_ds->ds_has_events : 0;
}

/** Check if operation handle has active registrations
 *
421 422
 * A registration is active when either when a REGISTER operation is going
 * on or when it has successfully completed so that @nua stack is expected to
423 424 425 426
 * refresh the registration in the future. Normally, a handle has active
 * registration after nua_register() until nua_unregister() completes,
 * unless the initial nua_register() had either expiration time of 0 or it
 * had SIPTAG_CONTACT(NULL) as an argument.
Pekka Pessi's avatar
Pekka Pessi committed
427 428 429
 *
 * @param nh          Pointer to operation handle
 *
430
 * @retval 0 no active registration in operation or
Pekka Pessi's avatar
Pekka Pessi committed
431 432 433 434 435 436 437 438
 *           operation handle is invalid
 * @retval 1 operation has registration
 *
 * @par Related tags:
 *     none
 *
 * @par Events:
 *     none
439 440
 *
 * @sa nua_register(), nua_unregister(), #nua_r_register, #nua_r_unregister
Pekka Pessi's avatar
Pekka Pessi committed
441 442 443 444 445 446
 */
int nua_handle_has_registrations(nua_handle_t const *nh)
{
  return nh && nh->nh_ds->ds_has_register;
}

447
/** Check if operation handle has been used with outgoing SUBSCRIBE of REFER request.
Pekka Pessi's avatar
Pekka Pessi committed
448 449 450
 *
 * @param nh          Pointer to operation handle
 *
451 452
 * @retval 0 no active subscription in operation or
 *           operation handle is invalid
Pekka Pessi's avatar
Pekka Pessi committed
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
 * @retval 1 operation has subscription.
 *
 * @par Related tags:
 *     none
 *
 * @par Events:
 *     none
 */
int nua_handle_has_subscribe(nua_handle_t const *nh)
{
  return nh ? nh->nh_has_subscribe : 0;
}

/** Check if operation handle has been used with nua_register() or nua_unregister().
 *
 * @param nh          Pointer to operation handle
 *
 * @retval 0 no active register in operation or operation handle is invalid
 * @retval 1 operation has been used with nua_register() or nua-unregister()
 *
 * @par Related tags:
 *     none
 *
 * @par Events:
 *     none
 */
int nua_handle_has_register(nua_handle_t const *nh)
{
  return nh ? nh->nh_has_register : 0;
}

484
/** Check if operation handle has an active call
Pekka Pessi's avatar
Pekka Pessi committed
485 486 487 488 489 490 491 492 493 494 495 496 497 498
 *
 * @param nh          Pointer to operation handle
 *
 * @retval 0 no active call in operation or operation handle is invalid
 * @retval 1 operation has established call or pending call request.
 *
 * @par Related tags:
 *     none
 *
 * @par Events:
 *     none
 */
int nua_handle_has_active_call(nua_handle_t const *nh)
{
499
  return nh ? nh->nh_active_call : 0;
Pekka Pessi's avatar
Pekka Pessi committed
500 501
}

502
/** Check if operation handle has a call on hold
Pekka Pessi's avatar
Pekka Pessi committed
503
 *
504 505 506
 * Please note that this status is not affected by remote end putting
 * this end on hold. Remote end can put each media separately on hold
 * and status is reflected on SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO()
507
 * and SOATAG_ACTIVE_CHAT() tag values in #nua_i_state event.
Pekka Pessi's avatar
Pekka Pessi committed
508 509 510
 *
 * @param nh          Pointer to operation handle
 *
511 512
 * @retval 0  if no call on hold in operation or operation handle is invalid
 * @retval 1  if operation has call on hold, for example nua_invite() or
513 514
 *            nua_update() has been called with SOATAG_HOLD() with non-NULL
 *            argument.
Pekka Pessi's avatar
Pekka Pessi committed
515 516 517 518 519 520 521 522 523
 *
 * @par Related tags:
 *     none
 *
 * @par Events:
 *     none
 */
int nua_handle_has_call_on_hold(nua_handle_t const *nh)
{
524
  return nh ? nh->nh_hold_remote : 0;
Pekka Pessi's avatar
Pekka Pessi committed
525 526 527 528
}

/** Get the remote address (From/To header) of operation handle
 *
529
 * Remote address is used as To header in outgoing operations and
Pekka Pessi's avatar
Pekka Pessi committed
530 531 532 533 534 535
 * derived from From: header in incoming operations.
 *
 * @param nh          Pointer to operation handle
 *
 * @retval NULL   no remote address for operation or operation handle invalid
 * @retval !=NULL pointer to remote address for operation
536
 *
Pekka Pessi's avatar
Pekka Pessi committed
537 538 539 540 541 542 543 544 545 546 547 548 549
 * @par Related tags:
 *     none
 *
 * @par Events:
 *     none
 */
sip_to_t const *nua_handle_remote(nua_handle_t const *nh)
{
  return nh ? nh->nh_ds->ds_remote : NULL;
}

/** Get the local address (From/To header) of operation handle
 *
550
 * Local address is used as From header in outgoing operations and
Pekka Pessi's avatar
Pekka Pessi committed
551 552 553 554 555 556
 * derived from To: header in incoming operations.
 *
 * @param nh          Pointer to operation handle
 *
 * @retval NULL   no local address for operation or operation handle invalid
 * @retval !=NULL pointer to local address for operation
557
 *
Pekka Pessi's avatar
Pekka Pessi committed
558 559 560 561 562 563 564 565 566 567 568
 * @par Related tags:
 *     none
 *
 * @par Events:
 *     none
 */
sip_to_t const *nua_handle_local(nua_handle_t const *nh)
{
  return nh ? nh->nh_ds->ds_local : NULL;
}

569
/* Documented with nua_stack_set_params() */
Pekka Pessi's avatar
Pekka Pessi committed
570 571 572 573 574 575 576
void nua_set_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
{
  ta_list ta;
  ta_start(ta, tag, value);

  enter;

577
  nua_signal(nua, NULL, NULL, nua_r_set_params, 0, NULL, ta_tags(ta));
Pekka Pessi's avatar
Pekka Pessi committed
578 579 580 581

  ta_end(ta);
}

582
/* Documented with nua_stack_get_params() */
Pekka Pessi's avatar
Pekka Pessi committed
583 584 585 586 587 588 589
void nua_get_params(nua_t *nua, tag_type_t tag, tag_value_t value, ...)
{
  ta_list ta;
  ta_start(ta, tag, value);

  enter;

590
  nua_signal(nua, NULL, NULL, nua_r_get_params, 0, NULL, ta_tags(ta));
Pekka Pessi's avatar
Pekka Pessi committed
591 592 593 594 595 596 597 598 599

  ta_end(ta);
}

#define NUA_SIGNAL(nh, event, tag, value) \
  enter; \
  if (NH_IS_VALID((nh))) { \
    ta_list ta; \
    ta_start(ta, tag, value); \
600
    nua_signal((nh)->nh_nua, nh, NULL, event, 0, NULL, ta_tags(ta));	\
Pekka Pessi's avatar
Pekka Pessi committed
601
    ta_end(ta); \
602 603
  } \
  else { \
604
    SU_DEBUG_1(("nua: " #event " with invalid handle %p\n", (void *)nh)); \
Pekka Pessi's avatar
Pekka Pessi committed
605 606
  }

607
/* Documented with nua_stack_set_params() */
608
void nua_set_hparams(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
609 610 611 612
{
  NUA_SIGNAL(nh, nua_r_set_params, tag, value);
}

613
/* Documented with nua_stack_get_params() */
614
void nua_get_hparams(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
615 616 617
{
  NUA_SIGNAL(nh, nua_r_get_params, tag, value);
}
Pekka Pessi's avatar
Pekka Pessi committed
618

619
/* Documented with nua_stack_register() */
Pekka Pessi's avatar
Pekka Pessi committed
620 621 622 623 624 625 626 627 628 629
void nua_register(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_register, tag, value);
}

void nua_unregister(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_unregister, tag, value);
}

630
/* Documented with nua_stack_invite() */
Pekka Pessi's avatar
Pekka Pessi committed
631 632 633 634 635
void nua_invite(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_invite, tag, value);
}

636
/* Documented with nua_stack_ack() */
Pekka Pessi's avatar
Pekka Pessi committed
637 638 639 640 641
void nua_ack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_ack, tag, value);
}

642
/* Documented with nua_stack_bye() */
Pekka Pessi's avatar
Pekka Pessi committed
643 644 645 646 647
void nua_bye(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_bye, tag, value);
}

648
/* Documented with nua_stack_cancel() */
Pekka Pessi's avatar
Pekka Pessi committed
649 650 651 652 653
void nua_cancel(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_cancel, tag, value);
}

654
/* Documented with nua_stack_options() */
Pekka Pessi's avatar
Pekka Pessi committed
655 656 657 658 659
void nua_options(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_options, tag, value);
}

660
/* Documented with nua_stack_message() */
Pekka Pessi's avatar
Pekka Pessi committed
661 662 663 664 665
void nua_message(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_message, tag, value);
}

666 667 668 669 670 671
/* Documented with nua_stack_method() */
void nua_method(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_method, tag, value);
}

672
/** Send a chat message.
Pekka Pessi's avatar
Pekka Pessi committed
673
 *
674 675 676 677
 * A chat channel can be established during call setup using "message" media.
 * An active chat channel is indicated using #nua_i_state event containing
 * SOATAG_ACTIVE_CHAT() tag. Chat messages can be sent using this channel with
 * nua_chat() function. Currently this is implemented using SIP MESSAGE
Pekka Pessi's avatar
Pekka Pessi committed
678 679 680 681 682
 * requests but in future MSRP (message session protocol) will replace it.
*
 * @param nh              Pointer to operation handle
 * @param tag, value, ... List of tagged parameters
 *
683
 * @return
Pekka Pessi's avatar
Pekka Pessi committed
684 685 686
 *    nothing
 *
 * @par Related Tags:
687 688 689 690 691
 *    SIPTAG_CONTENT_TYPE() \n
 *    SIPTAG_PAYLOAD()      \n
 *    SIPTAG_FROM()         \n
 *    SIPTAG_TO()           \n
 *    Use of other SIP tags is deprecated
Pekka Pessi's avatar
Pekka Pessi committed
692 693 694 695 696 697 698 699 700
 *
 * @par Events:
 *    #nua_r_chat
 */
void nua_chat(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_chat, tag, value);
}

701
/* Documented with nua_stack_subscribe() */
Pekka Pessi's avatar
Pekka Pessi committed
702 703 704 705 706
void nua_subscribe(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_subscribe, tag, value);
}

707
/* Documented with nua_stack_subscribe() */
Pekka Pessi's avatar
Pekka Pessi committed
708 709 710 711 712
void nua_unsubscribe(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_unsubscribe, tag, value);
}

713
/* Documented with nua_stack_notify() */
Pekka Pessi's avatar
Pekka Pessi committed
714 715 716 717 718
void nua_notify(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_notify, tag, value);
}

719 720
/* nua_r_notify is documented with process_response_to_notify() */

721
/** Create an event server.
Pekka Pessi's avatar
Pekka Pessi committed
722
 *
723 724 725 726
 * This function create an event server taking care of sending NOTIFY
 * requests and responding to further SUBSCRIBE requests. The event
 * server can accept multiple subscriptions from several sources and
 * takes care for distributing the notifications. Unlike other functions
Pekka Pessi's avatar
Pekka Pessi committed
727 728 729 730 731
 * this call only accepts the SIP tags listed below.
 *
 * @param nh              Pointer to operation handle
 * @param tag, value, ... List of tagged parameters
 *
732
 * @return
Pekka Pessi's avatar
Pekka Pessi committed
733 734 735
 *    nothing
 *
 * @par Related Tags:
736
 *    NUTAG_URL() \n
737 738 739 740
 *    SIPTAG_EVENT() or SIPTAG_EVENT_STR() \n
 *    SIPTAG_CONTENT_TYPE() or SIPTAG_CONTENT_TYPE_STR() \n
 *    SIPTAG_PAYLOAD() or SIPTAG_PAYLOAD_STR() \n
 *    SIPTAG_ACCEPT() or SIPTAG_ACCEPT_STR() \n
Pekka Pessi's avatar
Pekka Pessi committed
741 742 743 744 745 746 747 748 749
 *
 * @par Events:
 *    #nua_r_notify
 */
void nua_notifier(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_notifier, tag, value);
}

750
/** Terminate an event server.
Pekka Pessi's avatar
Pekka Pessi committed
751
 *
752 753
 * Terminate an event server with matching event and content type. The event
 * server was created earlier with nua_notifier() function.
Pekka Pessi's avatar
Pekka Pessi committed
754 755 756 757
 *
 * @param nh              Pointer to operation handle
 * @param tag, value, ... List of tagged parameters
 *
758
 * @return
Pekka Pessi's avatar
Pekka Pessi committed
759 760 761
 *    nothing
 *
 * @par Related Tags:
762 763 764 765
 *    SIPTAG_EVENT() \n
 *    SIPTAG_CONTENT_TYPE() \n
 *    SIPTAG_PAYLOAD() \n
 *    NEATAG_REASON()
Pekka Pessi's avatar
Pekka Pessi committed
766 767 768
 *
 * @par Events:
 *    #nua_r_terminate
769 770
 *
 * @sa nua_notifier(), nua_authorize().
Pekka Pessi's avatar
Pekka Pessi committed
771 772 773 774 775 776
 */
void nua_terminate(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_terminate, tag, value);
}

777
/* Documented with nua_stack_refer() */
Pekka Pessi's avatar
Pekka Pessi committed
778 779 780 781 782
void nua_refer(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_refer, tag, value);
}

783
/* Documented with nua_stack_publish() */
Pekka Pessi's avatar
Pekka Pessi committed
784 785 786 787 788
void nua_publish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_publish, tag, value);
}

789
/* Documented with nua_stack_publish() */
Pekka Pessi's avatar
Pekka Pessi committed
790 791 792 793 794
void nua_unpublish(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_unpublish, tag, value);
}

795
/* Documented with nua_stack_info() */
Pekka Pessi's avatar
Pekka Pessi committed
796 797 798 799 800
void nua_info(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_info, tag, value);
}

801
/* Documented with nua_stack_prack() */
Pekka Pessi's avatar
Pekka Pessi committed
802 803 804 805 806
void nua_prack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_prack, tag, value);
}

807
/* Documented with nua_stack_update() */
Pekka Pessi's avatar
Pekka Pessi committed
808 809 810 811 812 813 814 815 816
void nua_update(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_update, tag, value);
}

/** Authenticate an operation.
 *
 * - 401 / 407 response with www-authenticate header/ proxy-authenticate header
 * - application should provide stack with username&password for each realm
817
 *   with NUTAG_AUTH() tag
Pekka Pessi's avatar
Pekka Pessi committed
818 819 820 821 822
 * - restarts operation
 *
 * @param nh              Pointer to operation handle
 * @param tag, value, ... List of tagged parameters
 *
823
 * @return
Pekka Pessi's avatar
Pekka Pessi committed
824 825 826
 *    nothing
 *
 * @par Related Tags:
827
 *    NUTAG_AUTH()
Pekka Pessi's avatar
Pekka Pessi committed
828 829
 *
 * @par Events:
Pekka Pessi's avatar
Pekka Pessi committed
830
 *    (any operation events)
Pekka Pessi's avatar
Pekka Pessi committed
831 832 833 834 835 836
 */
void nua_authenticate(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_authenticate, tag, value);
}

837 838
/** Authorize a subscriber.
 *
839 840
 * After creating a local presence server by nua_notifier(), an incoming
 * SUBSCRIBE request causes #nua_i_subscription event. Each subscriber is
841
 * identified with NEATAG_SUB() tag in the #nua_i_subscription event.
842 843 844
 * Application can either authorize the subscriber with
 * NUTAG_SUBSTATE(#nua_substate_active) or terminate the subscription with
 * NUTAG_SUBSTATE(#nua_substate_terminated).
845 846 847 848
 *
 * @param nh              Pointer to operation handle
 * @param tag, value, ... List of tagged parameters
 *
849
 * @return
850 851 852
 *    nothing
 *
 * @par Related Tags:
853
 *    NEATAG_SUB() \n
854
 *    NUTAG_SUBSTATE()
855 856
 *
 * @par Events:
857 858 859
 *    #nua_i_subscription
 *
 * @sa nua_notifier(), nua_terminate()
860 861 862 863 864 865
 */
void nua_authorize(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_authorize, tag, value);
}

Pekka Pessi's avatar
Pekka Pessi committed
866 867 868 869 870 871
/*# Redirect an operation. */
void nua_redirect(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...)
{
  NUA_SIGNAL(nh, nua_r_redirect, tag, value);
}

872 873
/* Documented with nua_stack_respond() */

Pekka Pessi's avatar
Pekka Pessi committed
874 875 876 877 878 879 880 881 882 883
void nua_respond(nua_handle_t *nh,
		 int status, char const *phrase,
		 tag_type_t tag, tag_value_t value,
		 ...)
{
  enter;

  if (NH_IS_VALID(nh)) {
    ta_list ta;
    ta_start(ta, tag, value);
884
    nua_signal(nh->nh_nua, nh, NULL, nua_r_respond,
Pekka Pessi's avatar
Pekka Pessi committed
885 886 887
	       status, phrase, ta_tags(ta));
    ta_end(ta);
  }
888
  else {
889
    SU_DEBUG_1(("nua: respond with invalid handle %p\n", (void *)nh));
890
  }
Pekka Pessi's avatar
Pekka Pessi committed
891 892
}

893
/** Destroy a handle
Pekka Pessi's avatar
Pekka Pessi committed
894
 *
895 896 897 898 899 900 901 902 903
 * Terminate the protocol state associated with an operation handle. The
 * stack discards resources and terminates the ongoing dialog usage,
 * sessions and transactions associated with this handle. For example, calls
 * are terminated with BYE request. Also, the reference count for the handle
 * is also decremented.
 *
 * The handles use reference counting for memory management. In order to
 * make it more convenient for programmer, nua_handle_destroy() decreases
 * the reference count, too.
Pekka Pessi's avatar
Pekka Pessi committed
904 905 906
 *
 * @param nh              Pointer to operation handle
 *
907
 * @return
Pekka Pessi's avatar
Pekka Pessi committed
908 909 910 911 912 913 914
 *    nothing
 *
 * @par Related Tags:
 *    none
 *
 * @par Events:
 *    none
915
 *
916 917
 * @sa nua_handle(), nua_handle_bind(), nua_handle_ref(), nua_handle_unref(),
 * nua_unregister(), nua_unpublish(), nua_unsubscribe(), nua_bye().
Pekka Pessi's avatar
Pekka Pessi committed
918 919 920 921 922
 */
void nua_handle_destroy(nua_handle_t *nh)
{
  enter;

923
  if (NH_IS_VALID(nh) && !NH_IS_DEFAULT(nh)) {
Pekka Pessi's avatar
Pekka Pessi committed
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
  }
Pekka Pessi's avatar
Pekka Pessi committed
927
}
928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948

/* ---------------------------------------------------------------------- */

struct nua_stack_handle_make_replaces_args {
  sip_replaces_t *retval;
  nua_handle_t *nh;
  su_home_t *home;
  int early_only;
};

static int nua_stack_handle_make_replaces_call(void *arg)
{
  struct nua_stack_handle_make_replaces_args *a = arg;

  a->retval = nua_stack_handle_make_replaces(a->nh, a->home, a->early_only);

  return 0;
}


/**Generate a @Replaces header for handle.
949 950 951 952 953 954 955 956 957 958 959 960 961 962
 *
 * A @Replaces header contains the @CallID value, @From and @To tags
 * corresponding to SIP dialog associated with handle @a nh. Note that the
 * @Replaces matches with dialog of the remote peer,
 * nua_handle_by_replaces() does not return same handle (unless you swap
 * rp_from_tag and rp_to_tag in @Replaces header).
 *
 * A @Replaces header is used in attended transfer, among other things.
 *
 * @param nh pointer to operation handle
 * @param home memory home used to allocate the header
 * @param early_only if true, include "early-only" parameter in @Replaces, too
 *
 * @return A newly created @Replaces header.
963 964 965
 *
 * @since New in @VERSION_1_12_4.
 *
966 967 968
 * @sa nua_handle_by_replaces(), @Replaces, @RFC3891, @RFC3515, nua_refer(),
 * #nua_i_refer(), @ReferTo, nta_leg_make_replaces(),
 * sip_headers_as_url_query()
969
 */
970
sip_replaces_t *nua_handle_make_replaces(nua_handle_t *nh,
971 972 973 974
					 su_home_t *home,
					 int early_only)
{
  if (nh && nh->nh_valid && nh->nh_nua) {
975 976 977 978 979 980
#if HAVE_OPEN_C
    struct nua_stack_handle_make_replaces_args a = { NULL, NULL, NULL, 0 };
    a.nh = nh;
    a.home = home;
    a.early_only = early_only;
#else
981
    struct nua_stack_handle_make_replaces_args a = { NULL, nh, home, early_only };
982
#endif
983

984 985
    if (su_task_execute(nh->nh_nua->nua_server,
			nua_stack_handle_make_replaces_call, (void *)&a,
986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
			NULL) == 0) {
      return a.retval;
    }
  }
  return NULL;
}

struct nua_stack_handle_by_replaces_args {
  nua_handle_t *retval;
  nua_t *nua;
  sip_replaces_t const *r;
};

static int nua_stack_handle_by_replaces_call(void *arg)
{
  struct nua_stack_handle_by_replaces_args *a = arg;

  a->retval = nua_stack_handle_by_replaces(a->nua, a->r);

  return 0;
}

Michael Jerris's avatar
Michael Jerris committed
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
struct nua_stack_handle_by_call_id_args {
  nua_handle_t *retval;
  nua_t *nua;
  const char *call_id;
};

static int nua_stack_handle_by_call_id_call(void *arg)
{
  struct nua_stack_handle_by_call_id_args *a = arg;

  a->retval = nua_stack_handle_by_call_id(a->nua, a->call_id);

  return 0;
}

1023 1024 1025 1026
/** Obtain a new reference to an existing handle based on @Replaces header.
 *
 * @since New in @VERSION_1_12_4.
 *
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 1034 1035 1036
 */
nua_handle_t *nua_handle_by_replaces(nua_t *nua, sip_replaces_t const *r)
{
  if (nua) {
1037 1038
#if HAVE_OPEN_C
    struct nua_stack_handle_by_replaces_args a;
Pekka Pessi's avatar
Pekka Pessi committed
1039
    a.retval = NULL;
1040 1041 1042
    a.nua = nua;
    a.r = r;
#else
1043
    struct nua_stack_handle_by_replaces_args a = { NULL, nua, r };
1044
#endif
1045

1046 1047
    if (su_task_execute(nua->nua_server,
			nua_stack_handle_by_replaces_call, (void *)&a,
1048 1049 1050 1051 1052 1053 1054 1055 1056
			NULL) == 0) {
      nua_handle_t *nh = a.retval;

      if (nh && !NH_IS_DEFAULT(nh) && nh->nh_valid)
	return nua_handle_ref(nh);
    }
  }
  return NULL;
}
Michael Jerris's avatar
Michael Jerris committed
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091

/** Obtain a new reference to an existing handle based on @CallID.
 *
 * @since New in @VERSION_1_12_9.
 *
 * @note
 * You should release the reference with nua_handle_unref() when you are
 * done with the handle.
 *
 * @sa nua_handle_make_replaces(), @Replaces, @RFC3891, nua_refer(),
 * #nua_i_refer, @ReferTo, nta_leg_by_replaces()
 */
nua_handle_t *nua_handle_by_call_id(nua_t *nua, const char *call_id)
{
  if (nua) {
#if HAVE_OPEN_C
    struct nua_stack_handle_by_call_id_args a;
	a.retval = NULL;
    a.nua = nua;
    a.call_id = call_id;
#else
    struct nua_stack_handle_by_call_id_args a = { NULL, nua, call_id };
#endif

    if (su_task_execute(nua->nua_server,
			nua_stack_handle_by_call_id_call, (void *)&a,
			NULL) == 0) {
      nua_handle_t *nh = a.retval;

      if (nh && !NH_IS_DEFAULT(nh) && nh->nh_valid)
	return nua_handle_ref(nh);
    }
  }
  return NULL;
}