nua_session.c 128 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * This file is part of the Sofia-SIP package
 *
 * Copyright (C) 2006 Nokia Corporation.
 *
 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * 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
 *
 */

/**@CFILE nua_session.c
26
 * @brief SIP session handling
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
 *
 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
 *
 * @date Created: Wed Mar  8 16:17:27 EET 2006 ppessi
 */

#include "config.h"

#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

#include <assert.h>

#include <sofia-sip/string0.h>
#include <sofia-sip/sip_protos.h>
#include <sofia-sip/sip_status.h>
#include <sofia-sip/sip_util.h>
46
#include <sofia-sip/su_uniqueid.h>
47

48
#define NTA_INCOMING_MAGIC_T struct nua_server_request
49
#define NTA_OUTGOING_MAGIC_T struct nua_client_request
50
#define NTA_RELIABLE_MAGIC_T struct nua_server_request
51 52 53 54 55 56 57 58

#include "nua_stack.h"
#include <sofia-sip/soa.h>

#ifndef SDP_H
typedef struct sdp_session_s sdp_session_t;
#endif

59
/* ---------------------------------------------------------------------- */
60

61 62 63 64 65 66 67 68 69 70 71 72 73
/** @enum nua_callstate

The states for SIP session established with INVITE.

Initially the call states follow the state of the INVITE transaction. If the
initial INVITE transaction fails, the call is terminated. The status codes
401 and 407 are an exception: if the client (on the left side in the diagram
below) receives them, it enters in #nua_callstate_authenticating state.

If a re-INVITE transaction fails, the result depends on the status code in
failure. The call can return to the ready state, be terminated immediately,
or be terminated gracefully. The proper action to take is determined with
sip_response_terminates_dialog().			   
74 75

@sa @ref nua_call_model, #nua_i_state, nua_invite(), #nua_i_invite
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
							   
@par Session State Diagram				   
							   
@code							   
  			 +----------+			   
  			 |          |---------------------+
  			 |   Init   |                     |
  			 |          |----------+          |
  			 +----------+          |          |
  			  |        |           |          |
                 --/INVITE|        |INVITE/100 |          |
                          V        V           |          |
     		+----------+      +----------+ |          |
       +--------|          |      |          | |          |
       |  18X +-| Calling  |      | Received | |INVITE/   |
       |   /- | |          |      |          | |  /18X    |
       |      V +----------+      +----------+ V          |
       |   +----------+ |           |     |  +----------+ |
       |---|          | |2XX     -/ |  -/ |  |          | |
       |   | Proceed- | | /-     2XX|  18X|  |  Early   | |INVITE/
       |   |   ing    | |           |     +->|          | |  /200
       |   +----------+ V           V        +----------+ |
       |     |  +----------+      +----------+   | -/     |
       |  2XX|  |          |      |          |<--+ 2XX    |
       |   /-|  | Complet- |      | Complete |<-----------+
       |     +->|   ing    |      |          |------+
       |        +----------+      +----------+      |
       |                  |        |      |         |
       |401,407/     -/ACK|        |ACK/- |timeout/ |
       | /ACK             V        V      | /BYE    |
       |                 +----------+     |         |
       |                 |          |     |         |
       |              +--|  Ready   |     |         |
       |              |  |          |     |         |
       |              |  +----------+     |         |
       |              |       |           |         |
       |         BYE/ |       |-/BYE      |         |BYE/
       V         /200 |       V           |         |/200
  +----------+        |  +----------+     |         |
  |          |        |  |          |     |         |
  |Authentic-|        |  | Terminat-|<----+         |
  |  ating   |        |  |   ing    |               |
  +----------+        |  +----------+               |
                      |       |                     |
                      |       |[23456]XX/-          |
                      |       V                     |
                      |  +----------+               |
                      |  |          |               |
                      +->|Terminated|<--------------+
                         |          |
                         +----------+
                              | 
                              V
                         +----------+
        		 |          |
                         |   Init   |
			 |          |
133 134
          		 +----------+
@endcode			      
135 136
*/			      
			      
137 138 139
/* ---------------------------------------------------------------------- */
/* Session event usage */

Pekka Pessi's avatar
Pekka Pessi committed
140
/** @internal @brief Session-related state. */
141 142
typedef struct nua_session_usage
{
143
  enum nua_callstate ss_state;		/**< Session status (enum nua_callstate) */
144 145 146 147 148 149 150 151
  
  unsigned        ss_100rel:1;	        /**< Use 100rel, send 183 */
  unsigned        ss_alerting:1;	/**< 180 is sent/received */
  
  unsigned        ss_update_needed:2;	/**< Send an UPDATE (do O/A if > 1) */

  unsigned        ss_precondition:1;	/**< Precondition required */

152
  unsigned        ss_reporting:1;       /**< True if reporting state */
153
  unsigned        : 0;
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168

  struct session_timer {
    unsigned  interval;		/**< Negotiated expiration time */
    enum nua_session_refresher refresher; /**< Our Negotiated role */

    struct {
      unsigned expires, defaults; /**< Value of Session-Expires (delta) */
      unsigned min_se;	/**< Minimum session expires */
      /** none, local or remote */
      enum nua_session_refresher refresher;
      unsigned    supported:1, require:1, :0;
    } local, remote;

    unsigned      timer_set:1;  /**< We have active session timer. */
  } ss_timer[1];
169

170
  char const     *ss_reason;	        /**< Reason for termination. */
171 172 173

  /* Offer-Answer status */
  char const     *ss_oa_recv, *ss_oa_sent;
174
} nua_session_usage_t;
175

176 177
static char const Offer[] = "offer", Answer[] = "answer";

178
static char const *nua_session_usage_name(nua_dialog_usage_t const *du);
179
static int nua_session_usage_add(nua_handle_t *nh,
180 181
				 nua_dialog_state_t *ds,
				 nua_dialog_usage_t *du);
182
static void nua_session_usage_remove(nua_handle_t *nh,
183 184
				     nua_dialog_state_t *ds,
				     nua_dialog_usage_t *du);
185
static void nua_session_usage_refresh(nua_owner_t *,
186
				      nua_dialog_state_t *,
187 188 189
				      nua_dialog_usage_t *,
				      sip_time_t now);
static int nua_session_usage_shutdown(nua_owner_t *,
190 191
				      nua_dialog_state_t *,
				      nua_dialog_usage_t *);
192

193 194 195
static int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags);
static int nua_invite_client_deinit(nua_client_request_t *cr);

196 197
static nua_usage_class const nua_session_usage[1] = {
  {
198
    sizeof (nua_session_usage_t),
199 200 201 202
    sizeof nua_session_usage,
    nua_session_usage_add,
    nua_session_usage_remove,
    nua_session_usage_name,
203 204 205
    NULL,
    nua_session_usage_refresh,
    nua_session_usage_shutdown
206 207 208 209 210 211 212
  }};

static char const *nua_session_usage_name(nua_dialog_usage_t const *du)
{
  return "session";
}

213 214
static
int nua_session_usage_add(nua_handle_t *nh,
215 216 217
			   nua_dialog_state_t *ds,
			   nua_dialog_usage_t *du)
{
218 219
  nua_session_usage_t *ss = nua_dialog_usage_private(du);  

220 221 222
  if (ds->ds_has_session)
    return -1;
  ds->ds_has_session = 1;
223
  ds->ds_got_session = 1;
224

225 226 227
  ss->ss_timer->local.refresher = nua_any_refresher;
  ss->ss_timer->remote.refresher = nua_any_refresher;

228 229 230
  return 0;
}

231 232
static
void nua_session_usage_remove(nua_handle_t *nh,
233 234 235
			       nua_dialog_state_t *ds,
			       nua_dialog_usage_t *du)
{
236
  nua_session_usage_t *ss = nua_dialog_usage_private(du);
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
  nua_client_request_t *cr, *cr_next;

  cr = du->du_cr;

  if (cr && cr->cr_orq && cr->cr_status >= 200) {
    ss->ss_reporting = 1;
    nua_invite_client_ack(cr, NULL);
    ss->ss_reporting = 0;
  }

  /* Destroy queued INVITE transactions */
  for (cr = ds->ds_cr; cr; cr = cr_next) {
    cr_next = cr->cr_next;

    if (cr->cr_method != sip_method_invite)
      continue;
    if (cr == du->du_cr)
      continue;

    nua_stack_event(nh->nh_nua, nh, 
		    NULL,
		    cr->cr_event,
		    SIP_481_NO_TRANSACTION,
		    NULL);

    nua_client_request_destroy(cr);

    cr_next = ds->ds_cr;
  }
266

267
  
268 269 270 271 272 273 274
  ds->ds_has_session = 0;
  nh->nh_has_invite = 0;
  nh->nh_active_call = 0;
  nh->nh_hold_remote = 0;

  if (nh->nh_soa)
    soa_destroy(nh->nh_soa), nh->nh_soa = NULL;
275
}
276

277 278 279 280 281
static
nua_dialog_usage_t *nua_dialog_usage_for_session(nua_dialog_state_t const *ds)
{
  if (ds == ((nua_handle_t *)NULL)->nh_ds)
    return NULL;
282

283
  return nua_dialog_usage_get(ds, nua_session_usage, NULL);
284 285 286
}

static
287
nua_session_usage_t *nua_session_usage_for_dialog(nua_dialog_state_t const *ds)
288 289 290 291 292 293 294 295 296
{
  nua_dialog_usage_t *du;

  if (ds == ((nua_handle_t *)NULL)->nh_ds)
    return NULL;

  du = nua_dialog_usage_get(ds, nua_session_usage, NULL);

  return (nua_session_usage_t *)nua_dialog_usage_private(du);
297 298
}

299 300 301 302 303 304 305
/** Zap the session associated with the handle */
static
void nua_session_usage_destroy(nua_handle_t *nh,
			       nua_session_usage_t *ss)
{
  /* Remove usage */
  nua_dialog_usage_remove(nh, nh->nh_ds, nua_dialog_usage_public(ss));
306

307
  SU_DEBUG_5(("nua: terminated session %p\n", (void *)nh));
308
}
309

310 311
/* ======================================================================== */
/* INVITE and call (session) processing */
312 313 314 315

int nua_stack_prack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
		    tagi_t const *tags);

316 317 318 319 320 321 322 323
static int session_timer_is_supported(struct session_timer const *t);

static void session_timer_preferences(struct session_timer *t,
				      sip_t const *sip,
				      sip_supported_t const *supported,
				      unsigned expires, int isset,
				      enum nua_session_refresher refresher,
				      unsigned min_se);
324

325 326
static void session_timer_store(struct session_timer *t,
				sip_t const *sip);
327

328 329 330
static int session_timer_check_min_se(msg_t *msg, sip_t *sip,
				      sip_t const *request,
				      unsigned long min_se);
331

332 333 334 335 336 337 338
static int session_timer_add_headers(struct session_timer *t,
				     int initial,
				     msg_t *msg, sip_t *sip);

static void session_timer_negotiate(struct session_timer *t);

static void session_timer_set(nua_session_usage_t *ss);
339

340 341 342
static int session_timer_check_restart(nua_client_request_t *cr,
				       int status, char const *phrase,
				       sip_t const *sip);
343

344 345 346
static int nh_referral_check(nua_handle_t *nh, tagi_t const *tags);
static void nh_referral_respond(nua_handle_t *,
				int status, char const *phrase);
347

348
static void signal_call_state_change(nua_handle_t *nh,
349 350 351
				      nua_session_usage_t *ss,
				      int status, char const *phrase,
				      enum nua_callstate next_state);
352 353

static
354
int session_get_description(sip_t const *sip,
355
			    char const **return_sdp,
356 357 358
			    size_t *return_len);

static
359
int session_include_description(soa_session_t *soa,
360
				int session,
361
				msg_t *msg,
362 363 364
				sip_t *sip);

static
365 366
int session_make_description(su_home_t *home,
			     soa_session_t *soa,
367
			     int session,
368 369 370 371
			     sip_content_disposition_t **return_cd,
			     sip_content_type_t **return_ct,
			     sip_payload_t **return_pl);

372
static
373 374 375
int nua_server_retry_after(nua_server_request_t *sr,
			   int status, char const *phrase,
			   int min, int max);
376

377
/**@fn void nua_invite(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
378 379 380 381 382 383 384
 *
 * Place a call using SIP INVITE method. 
 *
 * Incomplete call can be hung-up with nua_cancel(). Complete or incomplete
 * calls can be hung-up with nua_bye().
 *
 * Optionally 
385
 * - uses early media if NUTAG_EARLY_MEDIA() tag is used with non zero-value
386 387 388 389 390 391 392 393 394 395 396 397
 * - media parameters can be set by SOA tags
 * - nua_invite() can be used to change status of an existing call: 
 *   - #SOATAG_HOLD tag can be used to list the media that will be put on hold,
 *     the value "*" sets all the media beloginging to the session on hold
 *
 * @param nh              Pointer to operation handle
 * @param tag, value, ... List of tagged parameters
 *
 * @return 
 *    nothing
 *
 * @par Related Tags:
398 399 400
 *    NUTAG_URL() \n
 *    Tags of nua_set_hparams() \n
 *    NUTAG_INCLUDE_EXTRA_SDP() \n
401 402 403
 *    SOATAG_HOLD(), SOATAG_AF(), SOATAG_ADDRESS(),
 *    SOATAG_RTP_SELECT(), SOATAG_RTP_SORT(), SOATAG_RTP_MISMATCH(), 
 *    SOATAG_AUDIO_AUX(), \n
404
 *    SOATAG_USER_SDP() or SOATAG_USER_SDP_STR() \n
405
 *    See use of tags in <sip_tag.h> below
406 407 408
 *
 * @par Events:
 *    #nua_r_invite \n
409
 *    #nua_i_state (#nua_i_active, #nua_i_terminated) \n
410 411 412 413 414 415 416 417
 *    #nua_i_media_error \n
 *    #nua_i_fork \n
 *
 * @par Populating SIP Request Message with Tagged Arguments
 * The tagged arguments can be used to pass values for any SIP headers to
 * the stack. When the INVITE message (or any other SIP message) is created,
 * the tagged values saved with nua_handle() are used first, next the tagged
 * values given with the operation (nua_invite()) are added.
418 419
 *
 * @par
420 421 422 423 424 425 426
 * When multiple tags for the same header are specified, the behaviour
 * depends on the header type. If only a single header field can be included
 * in a SIP message, the latest non-NULL value is used, e.g., @Subject. 
 * However, if the SIP header can consist of multiple lines or header fields
 * separated by comma, e.g., @Accept, all the tagged
 * values are concatenated.
 * 
427
 * @par
428 429 430
 * However, if a tag value is #SIP_NONE (-1 casted as a void pointer), the
 * values from previous tags are ignored.
 *
431
 * @par
432 433 434 435
 * Next, values previously set with nua_set_params() or nua_set_hparams()
 * are used: @Allow, @Supported, @Organization, and @UserAgent headers are
 * added to the request if they are not already set.
 *
436
 * @par
437 438
 * Now, the target URI for the request needs to be determined.
 *
439
 * @par
440 441 442 443 444 445 446 447 448 449
 * For initial INVITE requests, values from tags are used. If NUTAG_URL() is
 * given, it is used as target URI. Otherwise, if SIPTAG_TO() is given, it
 * is used as target URI. If neither is given, the complete request line
 * already specified using SIPTAG_REQUEST() or SIPTAG_REQUEST_STR() is used. 
 * If none of the tags above are given, an internal error is returned to the
 * application. At this point, the target URI is stored in the request line,
 * together with method name ("INVITE") and protocol version ("SIP/2.0"). 
 * The initial dialog information is also created: @CallID, @CSeq headers
 * are generated, if they do not exist, and tag is added to @From header.
 *
450
 * @par
451 452 453 454 455 456 457
 * For in-dialog INVITE (re-INVITE), the request URI is taken from the
 * @Contact header received from the remote party during the dialog
 * establishment. Also, the @CallID and @CSeq headers and @From and @To tags
 * are generated based on the dialog information and added to the request. 
 * If the dialog has a route (set by @RecordRoute headers), it is added to
 * the request, too.
 *
458
 * @par
459 460 461
 * @MaxForwards header (with default value set by NTATAG_MAX_FORWARDS()) is
 * also added now, if it does not exist.
 * 
462
 * @par
463 464 465 466 467 468 469 470
 * Next, the stack generates a @Contact header for the request (Unless the
 * application already gave a @Contact header or it does not want to use
 * @Contact and indicates that by including SIPTAG_CONTACT(NULL) or
 * SIPTAG_CONTACT(SIP_NONE) in the tagged parameters.) If the application
 * has registered the URI in @From header, the @Contact header used with
 * registration is used. Otherwise, the @Contact header is generated from the
 * local IP address and port number.
 *
471
 * @par
472 473 474
 * For the initial INVITE requests, @ServiceRoute set received from
 * the registrar is also added to the request message.
 *
475
 * @par
476 477
 * The INVITE request message created by nua_invite() operation is saved as
 * a template for automatic re-INVITE requests sent by the session timer
478 479 480 481 482
 * ("timer") feature (see NUTAG_SESSION_TIMER() for more details). Please
 * note that the template message is not used when ACK, PRACK, UPDATE or
 * INFO requests are created (however, these requests will include
 * dialog-specific headers like @To, @From, and @CallID as well as
 * preference headers @Allow, @Supported, @UserAgent, @Organization).
483 484 485 486 487 488 489
 *
 * @par SDP Handling
 * The initial nua_invite() creates a @ref soa_session_t "soa media session"
 * unless NUTAG_MEDIA_ENABLE(0) has been given. The SDP description of the
 * @ref soa_session_t "soa media session" is included in the INVITE request
 * as message body. 
 *
490
 * @par
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
 * The SDP in a 1XX or 2XX response message is interpreted as an answer,
 * given to the @ref soa_session_t "soa media session" object for
 * processing.
 *
 * @bug If the INVITE request already contains a message body, SDP is not
 * added. Also, if the response contains a multipart body, it is not parsed.
 *
 * @par Authentication
 * The INVITE request may need authentication. Each proxy or server
 * requiring authentication can respond with 401 or 407 response. The
 * nua_authenticate() operation stores authentication information (username
 * and password) to the handle, and stack tries to authenticate all the rest
 * of the requests (e.g., PRACK, ACK, UPDATE, re-INVITE, BYE) using same
 * username and password.
 *
506 507
 * @sa @ref nua_call_model, #nua_r_invite, #nua_i_state, \n
 *     nua_handle_has_active_call() \n
508 509 510 511 512 513 514 515
 *     nua_handle_has_call_on_hold()\n
 *     nua_handle_has_invite() \n
 *     nua_authenticate() \n
 *     nua_prack() \n
 *     nua_update() \n
 *     nua_info() \n 
 *     nua_cancel() \n
 *     nua_bye() \n
516
 *     #nua_i_invite, nua_respond()
517 518
 */

519 520 521
/* Tags not implemented
 *    NUTAG_REFER_PAUSE() \n
 */
522

523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
static int nua_invite_client_init(nua_client_request_t *cr, 
				  msg_t *msg, sip_t *sip,
				  tagi_t const *tags);
static int nua_invite_client_request(nua_client_request_t *cr,
				     msg_t *msg, sip_t *sip,
				     tagi_t const *tags);
static int nua_invite_client_preliminary(nua_client_request_t *cr,
					 int status, char const *phrase,
					 sip_t const *sip);
static int nua_invite_client_response(nua_client_request_t *cr,
				      int status, char const *phrase,
				      sip_t const *sip);
static int nua_session_client_response(nua_client_request_t *cr,
				       int status, char const *phrase,
				       sip_t const *sip);
static int nua_invite_client_report(nua_client_request_t *cr,
				    int status, char const *phrase,
				    sip_t const *sip,
				    nta_outgoing_t *orq,
				    tagi_t const *tags);

544
nua_client_methods_t const nua_invite_client_methods = {
545 546 547 548 549 550 551 552 553 554 555 556 557
  SIP_METHOD_INVITE,
  0,
  { 
    /* create_dialog */ 1,
    /* in_dialog */ 1,
    /* target refresh */ 1
  },
  NULL,
  nua_invite_client_init,
  nua_invite_client_request,
  session_timer_check_restart,
  nua_invite_client_response,
  nua_invite_client_preliminary,
558 559
  nua_invite_client_report,
  nua_invite_client_deinit
560 561
};

562 563 564 565 566
extern nua_client_methods_t const nua_bye_client_methods;
extern nua_client_methods_t const nua_cancel_client_methods;
extern nua_client_methods_t const nua_info_client_methods;
extern nua_client_methods_t const nua_update_client_methods;
extern nua_client_methods_t const nua_prack_client_methods;
567 568 569 570 571

int nua_stack_invite(nua_t *nua, nua_handle_t *nh, nua_event_t e,
		     tagi_t const *tags)
{
  return nua_client_create(nh, e, &nua_invite_client_methods, tags);
572 573
}

574 575 576
static int nua_invite_client_init(nua_client_request_t *cr, 
				  msg_t *msg, sip_t *sip,
				  tagi_t const *tags)
577
{
578
  nua_handle_t *nh = cr->cr_owner;
579
  nua_dialog_usage_t *du;
580
  nua_session_usage_t *ss;
581

582
  cr->cr_usage = du = nua_dialog_usage_for_session(nh->nh_ds);
583
  /* Errors returned by nua_invite_client_init() 
584
     do not change the session state */
585
  cr->cr_neutral = 1;	
586 587 588 589 590 591
  
  if (nh_is_special(nh) || 
      nua_stack_set_handle_special(nh, nh_has_invite, nua_i_error))
    return nua_client_return(cr, 900, "Invalid handle for INVITE", msg);
  else if (nh_referral_check(nh, tags) < 0)
    return nua_client_return(cr, 900, "Invalid referral", msg);
592

593 594 595 596 597 598 599 600 601
  if (du) {
    nua_server_request_t *sr;
    for (sr = nh->nh_ds->ds_sr; sr; sr = sr->sr_next)
      /* INVITE in progress? */
      if (sr->sr_usage == du && sr->sr_method == sip_method_invite &&
	  nua_server_request_is_pending(sr))
	return nua_client_return(cr, SIP_491_REQUEST_PENDING, msg);
  }
  else
602
    du = nua_dialog_usage_add(nh, nh->nh_ds, nua_session_usage, NULL);
603

604 605
  if (!du)
    return -1;
606

607 608
  if (nua_client_bind(cr, du) < 0)
    return nua_client_return(cr, 900, "INVITE already in progress", msg);
609

610 611 612 613 614
  ss = nua_dialog_usage_private(du);

  session_timer_preferences(ss->ss_timer,
			    sip,
			    NH_PGET(nh, supported),		     
615
			    NH_PGET(nh, session_timer),
616 617 618
			    NUA_PISSET(nh->nh_nua, nh, session_timer),
			    NH_PGET(nh, refresher),
			    NH_PGET(nh, min_se));
619

620 621
  cr->cr_neutral = 0;

622 623
  return 0;
}
624

625 626 627 628 629 630 631 632 633
static int nua_invite_client_request(nua_client_request_t *cr,
				     msg_t *msg, sip_t *sip,
				     tagi_t const *tags)
{
  nua_handle_t *nh = cr->cr_owner;
  nua_dialog_usage_t *du = cr->cr_usage;
  nua_session_usage_t *ss = nua_dialog_usage_private(du);
  int offer_sent = 0, retval;
  sip_time_t invite_timeout;
634

635 636
  if (du == NULL)		/* Call terminated */ 
    return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg);
637

638
  assert(ss);
639

640 641 642
  invite_timeout = NH_PGET(nh, invite_timeout);
  if (invite_timeout == 0)
    invite_timeout = UINT_MAX;
643
  /* Send CANCEL if we don't get response within timeout*/
644
  /* nua_dialog_usage_set_expires(du, invite_timeout); Xyzzy */
645
  nua_dialog_usage_reset_refresh(du);
646

647
  /* Add session timer headers */
648 649 650
  if (session_timer_is_supported(ss->ss_timer))
    session_timer_add_headers(ss->ss_timer, ss->ss_state == nua_callstate_init,
			      msg, sip);
651

652 653 654 655
  ss->ss_100rel = NH_PGET(nh, early_media);
  ss->ss_precondition = sip_has_feature(sip->sip_require, "precondition");
  if (ss->ss_precondition)
    ss->ss_update_needed = ss->ss_100rel = 1;
656 657

  if (nh->nh_soa) {
658 659 660
    soa_init_offer_answer(nh->nh_soa);

    if (sip->sip_payload)
661
      offer_sent = 0;		/* XXX - kludge */
662
    else if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0)
663
      return -1;
664 665 666
    else
      offer_sent = 1;

667 668 669
    if (offer_sent > 0 &&
	session_include_description(nh->nh_soa, 1, msg, sip) < 0)
      return nua_client_return(cr, 900, "Internal media error", msg);
670

671 672 673 674 675
    if (NH_PGET(nh, media_features) &&
	!nua_dialog_is_established(nh->nh_ds) &&
	!sip->sip_accept_contact && !sip->sip_reject_contact) {
      sip_accept_contact_t ac[1];
      sip_accept_contact_init(ac);
676

677 678
      ac->cp_params = (msg_param_t *)
	soa_media_features(nh->nh_soa, 1, msg_home(msg));
679

680 681 682 683
      if (ac->cp_params) {
	msg_header_replace_param(msg_home(msg), ac->cp_common, "explicit");
	sip_add_dup(msg, sip, (sip_header_t *)ac);
      }
684
    }
685
  }
686 687 688
  else {
    offer_sent = session_get_description(sip, NULL, NULL);
  }
689

690 691 692 693
  retval = nua_base_client_trequest(cr, msg, sip,
				    NTATAG_REL100(ss->ss_100rel),
				    TAG_NEXT(tags));
  if (retval == 0) {
694 695
    if ((cr->cr_offer_sent = offer_sent))
      ss->ss_oa_sent = Offer;
696

697
    if (!cr->cr_restarting) /* Restart logic calls nua_invite_client_report */
698 699 700
      signal_call_state_change(nh, ss, 0, "INVITE sent", 
			       nua_callstate_calling);
  }
701

702 703
  return retval;
}
704

705 706 707 708 709 710
static int nua_invite_client_response(nua_client_request_t *cr,
				      int status, char const *phrase,
				      sip_t const *sip)
{
  nua_dialog_usage_t *du = cr->cr_usage;
  nua_session_usage_t *ss = nua_dialog_usage_private(du);
711

712 713
  if (ss == NULL || sip == NULL) {
    /* Xyzzy */
714
  }
715 716
  else if (status < 300) {
    du->du_ready = 1;
717

718 719 720 721
    if (session_timer_is_supported(ss->ss_timer))
      session_timer_store(ss->ss_timer, sip);

    session_timer_set(ss);
722 723 724 725
  }
  
  return nua_session_client_response(cr, status, phrase, sip);
}
726

727 728 729 730 731 732 733
static int nua_invite_client_preliminary(nua_client_request_t *cr,
					 int status, char const *phrase,
					 sip_t const *sip)
{
  nua_handle_t *nh = cr->cr_owner;
  nua_dialog_usage_t *du = cr->cr_usage;
  nua_session_usage_t *ss = nua_dialog_usage_private(du);
734

735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
  assert(sip); assert(ss);

  if (ss && sip && sip->sip_rseq) {
    /* Handle 100rel responses */
    sip_rseq_t *rseq = sip->sip_rseq;

    /* Establish early dialog - we should fork here */
    if (!nua_dialog_is_established(nh->nh_ds)) {
      nta_outgoing_t *tagged;

      nua_dialog_uac_route(nh, nh->nh_ds, sip, 1);
      nua_dialog_store_peer_info(nh, nh->nh_ds, sip);
      
      /* Tag the INVITE request */
      tagged = nta_outgoing_tagged(cr->cr_orq,
				   nua_client_orq_response, cr,
				   sip->sip_to->a_tag, sip->sip_rseq);
      if (tagged) {
	nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = tagged;
      }
      else {
	cr->cr_graceful = 1;
	ss->ss_reason = "SIP;cause=500;text=\"Cannot Create Early Dialog\"";
      }
    }
  
    if (!rseq) {
762
      SU_DEBUG_5(("nua(%p): 100rel missing RSeq\n", (void *)nh));
763 764
    }
    else if (nta_outgoing_rseq(cr->cr_orq) > rseq->rs_response) {
765
      SU_DEBUG_5(("nua(%p): 100rel bad RSeq %u (got %u)\n", (void *)nh, 
766 767 768 769 770
		  (unsigned)rseq->rs_response,
		  nta_outgoing_rseq(cr->cr_orq)));
      return 1;    /* Do not send event */
    }
    else if (nta_outgoing_setrseq(cr->cr_orq, rseq->rs_response) < 0) {
771
      SU_DEBUG_1(("nua(%p): cannot set RSeq %u\n", (void *)nh, 
772 773 774 775 776
		  (unsigned)rseq->rs_response));
      cr->cr_graceful = 1;
      ss->ss_reason = "SIP;cause=400;text=\"Bad RSeq\"";
    }
  }
777

778
  return nua_session_client_response(cr, status, phrase, sip);
779 780
}

781 782 783 784
/** Process response to a session request (INVITE, PRACK, UPDATE) */
static int nua_session_client_response(nua_client_request_t *cr,
				       int status, char const *phrase,
				       sip_t const *sip)
785
{
786 787 788 789 790 791
  nua_handle_t *nh = cr->cr_owner;
  nua_dialog_usage_t *du = cr->cr_usage;
  nua_session_usage_t *ss = nua_dialog_usage_private(du);

  char const *sdp = NULL;
  size_t len;
792 793
  char const *received = NULL;

794 795
#define LOG3(m) \
  SU_DEBUG_3(("nua(%p): %s: %s %s in %u %s\n", \
796
	      (void *)nh, cr->cr_method_name, (m),		\
797 798 799
	      received ? received : "SDP", status, phrase))
#define LOG5(m) \
  SU_DEBUG_5(("nua(%p): %s: %s %s in %u %s\n", \
800
	      (void *)nh, cr->cr_method_name, (m), received, status, phrase))
801

802
  if (!ss || !sip || 300 <= status)
803 804 805 806 807 808 809
    /* Xyzzy */;
  else if (!session_get_description(sip, &sdp, &len))
    /* No SDP */;
  else if (cr->cr_answer_recv) {
    /* Ignore spurious answers after completing O/A */
    LOG3("ignoring duplicate");
    sdp = NULL;
810
  }
811
  else if (cr->cr_offer_sent) {
812
    /* case 1: answer to our offer */
813
    cr->cr_answer_recv = status;
814
    received = Answer;
815

816 817 818
    if (nh->nh_soa == NULL)
      LOG5("got SDP");
    else if (soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) {
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
      LOG3("error parsing SDP");
      sdp = NULL;
      cr->cr_graceful = 1;
      ss->ss_reason = "SIP;cause=400;text=\"Malformed Session Description\"";
    }
    else if (soa_process_answer(nh->nh_soa, NULL) < 0) {
      LOG5("error processing SDP");
      /* XXX */
      sdp = NULL;
    }
    else if (soa_activate(nh->nh_soa, NULL) < 0)
      /* XXX - what about errors? */
      LOG3("error activating media after");
    else
      LOG5("processed SDP");
  }
  else if (cr->cr_method != sip_method_invite) {
    /* If non-invite request did not have offer, ignore SDP in response */
    LOG3("ignoring extra");
    sdp = NULL;
  }
  else {
841
    /* case 2: new offer */
842
    cr->cr_offer_recv = 1, cr->cr_answer_sent = 0;
843
    received = Offer;
844

845
    if (nh->nh_soa && soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) {
846 847 848 849
      LOG3("error parsing SDP");
      sdp = NULL;
      cr->cr_graceful = 1;
      ss->ss_reason = "SIP;cause=400;text=\"Malformed Session Description\"";
850
    }
851 852
    else 
      LOG5("got SDP");
853
  }
854

855 856
  if (ss && received)
    ss->ss_oa_recv = received;
857

858
  if (sdp && nh->nh_soa)
859 860 861 862 863 864
    return nua_base_client_tresponse(cr, status, phrase, sip,
				     NH_REMOTE_MEDIA_TAGS(1, nh->nh_soa),
				     TAG_END());
  else
    return nua_base_client_response(cr, status, phrase, sip, NULL);
}
865

866 867 868 869 870 871 872
static int nua_invite_client_report(nua_client_request_t *cr,
				    int status, char const *phrase,
				    sip_t const *sip,
				    nta_outgoing_t *orq,
				    tagi_t const *tags)
{
  nua_handle_t *nh = cr->cr_owner;
873
  nua_dialog_state_t *ds = nh->nh_ds;
874 875 876 877
  nua_dialog_usage_t *du = cr->cr_usage;
  nua_session_usage_t *ss = nua_dialog_usage_private(du);
  unsigned next_state;
  int error;
878

879
  nh_referral_respond(nh, status, phrase); /* XXX - restarting after 401/407 */
880 881 882 883 884

  nua_stack_event(nh->nh_nua, nh, 
		  nta_outgoing_getresponse(orq),
		  cr->cr_event,
		  status, phrase,
885
		  tags);
886

887 888
  if (cr->cr_waiting)
    /* Do not report call state change if waiting for restart */
889
    return 1;
890

891 892 893 894 895
  if (ss == NULL) {
    signal_call_state_change(nh, ss, status, phrase, nua_callstate_terminated);
    return 1;
  }

896 897
  ss->ss_reporting = 1;

898 899 900 901
  if (cr->cr_neutral) {
    signal_call_state_change(nh, ss, status, phrase, ss->ss_state);
    ss->ss_reporting = 0;
    return 1;
902
  }
903

904 905 906 907
  if (orq != cr->cr_orq && cr->cr_orq) {	/* Being restarted */
    next_state = nua_callstate_calling;
  }
  else if (status == 100) {
908 909 910 911 912 913 914 915 916 917
    next_state = nua_callstate_calling;
  }
  else if (status < 300 && cr->cr_graceful) {
    next_state = nua_callstate_terminating;
    if (200 <= status) {
      nua_invite_client_ack(cr, NULL);
    }
  }
  else if (status < 200) {
    next_state = nua_callstate_proceeding;
918 919 920

    if (sip && sip->sip_rseq && 
	!SIP_IS_ALLOWED(NH_PGET(nh, appl_method), sip_method_prack)) {
921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945
      sip_rack_t rack[1];

      sip_rack_init(rack);
      rack->ra_response    = sip->sip_rseq->rs_response;
      rack->ra_cseq        = sip->sip_cseq->cs_seq;
      rack->ra_method      = sip->sip_cseq->cs_method;
      rack->ra_method_name = sip->sip_cseq->cs_method_name;

      error = nua_client_tcreate(nh, nua_r_prack, &nua_prack_client_methods, 
				 SIPTAG_RACK(rack),
				 TAG_END());
      if (error < 0) {
	cr->cr_graceful = 1;
	next_state = nua_callstate_terminating;
      }
    }
  }
  else if (status < 300) {
    next_state = nua_callstate_completing;
  }
  else if (cr->cr_terminated) {
    next_state = nua_callstate_terminated;
  }
  else if (cr->cr_graceful && ss->ss_state >= nua_callstate_completing) {
    next_state = nua_callstate_terminating;
946 947
  }
  else {
948
    next_state = nua_callstate_init;
949 950
  }

951
  if (next_state == nua_callstate_calling) {
952 953
    if (sip && sip->sip_status && sip->sip_status->st_status == 100) {
      ss->ss_reporting = 0;
954
      return 1;
955
    }
956
  }
957

958 959 960 961 962
  if (next_state == nua_callstate_completing) {
    if (NH_PGET(nh, auto_ack) ||
	/* Auto-ACK response to re-INVITE unless auto_ack is set to 0 */
	(ss->ss_state == nua_callstate_ready &&
	 !NH_PISSET(nh, auto_ack))) {
963
      nua_client_request_t *cru;
964

965 966 967 968 969 970 971 972
      for (cru = ds->ds_cr; cru; cru = cru->cr_next) {
	if (cr != cru && cru->cr_offer_sent && !cru->cr_answer_recv)
	  break;
      }

      if (cru)
	/* A final response to UPDATE or PRACK with answer on its way? */;
      else if (nua_invite_client_ack(cr, NULL) > 0)
973 974 975 976 977
	next_state = nua_callstate_ready;
      else
	next_state = nua_callstate_terminating;
    }
  }
978

979
  if (next_state == nua_callstate_terminating) {
980 981 982 983 984 985 986 987 988
    /* Send BYE or CANCEL */
    /* XXX - Forking - send BYE to early dialog?? */
    if (ss->ss_state > nua_callstate_proceeding || status >= 200)
      error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL);
    else
      error = nua_client_create(nh, nua_r_cancel, 
				&nua_cancel_client_methods, tags);

    if (error) {
989 990 991
      next_state = nua_callstate_terminated;
      cr->cr_terminated = 1;
    }
992
    cr->cr_graceful = 0;
993 994
  }

995 996
  ss->ss_reporting = 0;

997 998 999
  signal_call_state_change(nh, ss, status, phrase, next_state);

  return 1;
1000 1001
}

1002 1003 1004 1005 1006
/**@fn void nua_ack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
 *
 * Acknowledge a succesful response to INVITE request.
 *
 * Acknowledge a successful response (200..299) to INVITE request with the
1007
 * SIP ACK request message. This function is needed only if NUTAG_AUTOACK()
1008 1009 1010 1011 1012 1013 1014 1015 1016
 * parameter has been cleared.
 *
 * @param nh              Pointer to operation handle
 * @param tag, value, ... List of tagged parameters
 *
 * @return 
 *    nothing
 *
 * @par Related Tags:
1017
 *    Header tags defined in <sofia-sip/sip_tag.h>
1018 1019 1020
 *
 * @par Events:
 *    #nua_i_media_error \n
1021
 *    #nua_i_state  (#nua_i_active, #nua_i_terminated) 
1022 1023
 *
 * @sa NUTAG_AUTOACK(), @ref nua_call_model, #nua_i_state
1024 1025
 */

1026 1027
int nua_stack_ack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
		  tagi_t const *tags)
1028
{
1029 1030
  nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds);
  nua_session_usage_t *ss = nua_dialog_usage_private(du);
1031 1032
  nua_client_request_t *cr = du ? du->du_cr : NULL;
  int error;
1033

1034
  if (!cr || cr->cr_orq == NULL || cr->cr_status < 200) {
1035 1036 1037
    UA_EVENT2(nua_i_error, 900, "No response to ACK");
    return 1;
  }
1038

1039 1040 1041 1042 1043
  if (tags) {
    nua_stack_set_params(nua, nh, nua_i_error, tags);
    if (nh->nh_soa)
      soa_set_params(nh->nh_soa, TAG_NEXT(tags));
  }
1044

1045 1046 1047
  error = nua_invite_client_ack(cr, tags);

  if (error < 0) {
1048 1049
    if (ss->ss_reason == NULL)
      ss->ss_reason = "SIP;cause=500;text=\"Internal Error\"";
1050 1051 1052 1053 1054 1055 1056
    ss->ss_reporting = 1;	/* We report state here if BYE fails */
    error = nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL);
    ss->ss_reporting = 0;
    signal_call_state_change(nh, ss, 500, "Internal Error", 
			     error 
			     ? nua_callstate_terminated
			     : nua_callstate_terminating);
1057
  }
1058 1059
  else if (ss)
    signal_call_state_change(nh, ss, 200, "ACK sent", nua_callstate_ready);
1060

1061 1062
  if (!nua_client_is_queued(cr) && !nua_client_is_bound(cr))
    nua_client_request_destroy(cr);
1063 1064

  nua_client_next_request(nh->nh_ds->ds_cr, 1);
1065

1066 1067
  return 0;
}
1068

1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
/** Send ACK, destroy INVITE transaction.
 *
 *  @retval 1 if successful
 *  @retval < 0 if an error occurred
 */
static
int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags)
{
  nua_handle_t *nh = cr->cr_owner;
  nua_dialog_state_t *ds = nh->nh_ds;
1079
  nua_session_usage_t *ss = nua_dialog_usage_private(cr->cr_usage);
1080

1081 1082 1083 1084 1085 1086
  msg_t *msg;
  sip_t *sip;
  int error = -1;
  sip_authorization_t *wa;
  sip_proxy_authorization_t *pa;
  sip_cseq_t *cseq;
1087 1088 1089
  nta_outgoing_t *ack;
  int status = 200;
  char const *phrase = "OK", *reason = NULL;
1090
  char const *invite_branch;
1091

1092 1093
  assert(ds->ds_leg);
  assert(cr->cr_orq);
1094

1095
  msg = nta_outgoing_getrequest(cr->cr_orq);
1096
  sip = sip_object(msg);
1097 1098
  if (!msg)
    return -1;
1099 1100
  invite_branch = nta_outgoing_branch(cr->cr_orq);

1101 1102 1103
  wa = sip_authorization(sip);
  pa = sip_proxy_authorization(sip);
  
1104 1105
  msg_destroy(msg);

1106 1107 1108 1109
  msg = nta_msg_create(nh->nh_nua->nua_nta, 0);
  sip = sip_object(msg);  
  if (!msg)
    return -1;
1110

1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
  cseq = sip_cseq_create(msg_home(msg), cr->cr_seq, SIP_METHOD_ACK);

  if (!cseq)
    ;
  else if (nh->nh_tags && sip_add_tl(msg, sip, TAG_NEXT(nh->nh_tags)) < 0)
    ;
  else if (tags && sip_add_tl(msg, sip, TAG_NEXT(tags)) < 0)
    ;
  else if (wa && sip_add_dup(msg, sip, (sip_header_t *)wa) < 0)
    ;
  else if (pa && sip_add_dup(msg, sip, (sip_header_t *)pa) < 0)
    ;
  else if (sip_header_insert(msg, sip, (sip_header_t *)cseq) < 0)
    ;
  else if (nta_msg_request_complete(msg, ds->ds_leg, SIP_METHOD_ACK, NULL) < 0)
    ;
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
  else {
    /* Remove extra headers */
    while (sip->sip_allow)
      sip_header_remove(msg, sip, (sip_header_t*)sip->sip_allow);
    while (sip->sip_priority)
      sip_header_remove(msg, sip, (sip_header_t*)sip->sip_priority);
    while (sip->sip_proxy_require)
      sip_header_remove(msg, sip, (sip_header_t*)sip->sip_proxy_require);
    while (sip->sip_require)
      sip_header_remove(msg, sip, (sip_header_t*)sip->sip_require);
    while (sip->sip_subject)
      sip_header_remove(msg, sip, (sip_header_t*)sip->sip_subject);
    while (sip->sip_supported)
      sip_header_remove(msg, sip, (sip_header_t*)sip->sip_supported);

1142 1143 1144 1145
    if (ss == NULL || ss->ss_state >= nua_callstate_ready)
      ;
    else if (cr->cr_offer_recv && !cr->cr_answer_sent) {
      if (nh->nh_soa == NULL) {
1146
	if (session_get_description(sip, NULL, NULL))
1147
	  cr->cr_answer_sent = 1, ss->ss_oa_sent = Answer;
1148 1149
      }
      else if (soa_generate_answer(nh->nh_soa, NULL) < 0 ||
1150 1151 1152 1153 1154 1155
	  session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
	status = 900, phrase = "Internal media error";
	reason = "SIP;cause=500;text=\"Internal media error\"";
	/* reason = soa_error_as_sip_reason(nh->nh_soa); */
      }
      else {
1156
	cr->cr_answer_sent = 1, ss->ss_oa_sent = Answer;
1157
      }
1158
    }
1159

1160
    if (ss == NULL || ss->ss_state >= nua_callstate_ready || reason)
1161
      ;
1162 1163
    else if (nh->nh_soa && soa_is_complete(nh->nh_soa)) {
      /* signal SOA that O/A round(s) is (are) complete */
1164 1165
	soa_activate(nh->nh_soa, NULL);
    }
1166 1167 1168
    else if (nh->nh_soa == NULL && !(cr->cr_offer_sent && !cr->cr_answer_recv)) {
      ;
    }
1169
    else {
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182
      nua_client_request_t *cru;

      /* Final response to UPDATE or PRACK may be on its way ... */
      for (cru = ds->ds_cr; cru; cru = cru->cr_next) {
	if (cr != cru && cru->cr_offer_sent && !cru->cr_answer_recv)
	  break;
      }

      if (cru == NULL) {
	/* No SDP answer -> terminate call */
	status = 988, phrase = "Incomplete offer/answer";
	reason = "SIP;cause=488;text=\"Incomplete offer/answer\"";
      }
1183
    }
1184 1185 1186
    
    if ((ack = nta_outgoing_mcreate(nh->nh_nua->nua_nta, NULL, NULL, NULL,
				    msg,
1187
				    NTATAG_ACK_BRANCH(invite_branch),
1188 1189
				    SIPTAG_END(),
				    TAG_NEXT(tags)))) {
1190 1191
      /* TR engine keeps this around for T2 so it catches all 2XX retransmissions  */
      nta_outgoing_destroy(ack);
1192

1193
      if (nh->nh_soa && reason && ss && ss->ss_state <= nua_callstate_ready)
1194 1195 1196
	nua_stack_event(nh->nh_nua, nh, NULL,
			nua_i_media_error, status, phrase,
			NULL);
1197
    }
1198 1199 1200
    else if (!reason) {
      status = 900, phrase = "Cannot send ACK";
      reason = "SIP;cause=500;text=\"Internal Error\"";
1201 1202
    }

1203 1204 1205 1206 1207 1208 1209
    if (ss && reason)
      ss->ss_reason = reason;

    if (status < 300)
      error = 1;
    else
      error = -2;
1210 1211
  }

1212 1213 1214
  if (error == -1)
    msg_destroy(msg);

1215 1216
  nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL;
  nua_client_request_remove(cr);
1217
  
1218
  return error;
1219 1220
}

1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233
/** Deinitialize client request */
static int nua_invite_client_deinit(nua_client_request_t *cr)
{
  if (cr->cr_orq == NULL)
    /* Xyzzy */;
  else if (cr->cr_status < 200)
    nta_outgoing_cancel(cr->cr_orq);
  else
    nua_invite_client_ack(cr, NULL);

  return 0;
}

1234
/**@fn void nua_cancel(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
1235
 *
1236
 * Cancel an INVITE operation 
1237 1238 1239 1240 1241 1242 1243 1244
 *
 * @param nh              Pointer to operation handle
 * @param tag, value, ... List of tagged parameters
 *
 * @return 
 *    nothing
 *
 * @par Related Tags:
1245
 *    Header tags defined in <sofia-sip/sip_tag.h>
1246 1247
 *
 * @par Events:
1248
 *    #nua_r_cancel, #nua_i_state  (#nua_i_active, #nua_i_terminated)
1249
 *
1250
 * @sa @ref nua_call_model, nua_invite(), #nua_i_cancel
1251 1252
 */

1253 1254 1255 1256
static int nua_cancel_client_request(nua_client_request_t *cr,
				     msg_t *msg, sip_t *sip,
				     tagi_t const *tags);

1257
nua_client_methods_t const nua_cancel_client_methods = {
1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
  SIP_METHOD_CANCEL,
  0,
  { 
    /* create_dialog */ 0,
    /* in_dialog */ 1,
    /* target refresh */ 0
  },
  NULL,
  NULL,
  nua_cancel_client_request,
  /* nua_cancel_client_check_restart */ NULL,
  /* nua_cancel_client_response */ NULL
};

int nua_stack_cancel(nua_t *nua, nua_handle_t *nh, nua_event_t e,
		     tagi_t const *tags)
1274
{
1275
  return nua_client_create(nh, e, &nua_cancel_client_methods, tags);
1276 1277
}

1278 1279 1280
static int nua_cancel_client_request(nua_client_request_t *cr,
				     msg_t *msg, sip_t *sip,
				     tagi_t const *tags)
1281
{
1282 1283
  nua_handle_t *nh = cr->cr_owner;
  nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds);
1284

1285 1286 1287
  if (!du || !du->du_cr || !du->du_cr->cr_orq || 
      nta_outgoing_status(du->du_cr->cr_orq) >= 200) {
    return nua_client_return(cr, 481, "No transaction to CANCEL", msg);
1288 1289
  }

1290 1291 1292
  cr->cr_orq = nta_outgoing_tcancel(du->du_cr->cr_orq,
				    nua_client_orq_response, cr,
				    TAG_NEXT(tags));
1293

1294
  return cr->cr_orq ? 0 : -1;
1295 1296
}

1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318
/** @NUA_EVENT nua_r_cancel
 *
 * Answer to outgoing CANCEL.
 *
 * The CANCEL may be sent explicitly by nua_cancel() or implicitly by NUA
 * state machine.
 *
 * @param status response status code 
 * @param phrase a short textual description of @a status code
 * @param nh     operation handle associated with the call
 * @param hmagic application context associated with the call
 * @param sip    response to CANCEL request or NULL upon an error
 *               (status code is in @a status and 
 *                descriptive message in @a phrase parameters)
 * @param tags   empty
 *
 * @sa nua_cancel(), @ref nua_uac_call_model, #nua_r_invite, nua_invite(),
 * #nua_i_state
 *
 * @END_NUA_EVENT
 */

1319
static void nua_session_usage_refresh(nua_handle_t *nh,
1320
				      nua_dialog_state_t *ds,
1321 1322
				      nua_dialog_usage_t *du,
				      sip_time_t now)
1323
{
1324 1325
  nua_session_usage_t *ss = nua_dialog_usage_private(du);
  nua_client_request_t const *cr = du->du_cr;
1326
  nua_server_request_t const *sr;
1327

1328 1329
  if (ss->ss_state >= nua_callstate_terminating || 
      /* INVITE is in progress or being authenticated */
1330
      (cr && (cr->cr_orq || cr->cr_wait_for_cred)))
1331 1332
    return;

1333
  /* UPDATE has been queued */
1334 1335 1336 1337
  for (cr = ds->ds_cr; cr; cr = cr->cr_next) 
    if (cr->cr_method == sip_method_update)
      return;

1338
  /* INVITE or UPDATE in progress on server side */
1339
  for (sr = ds->ds_sr; sr; sr = sr->sr_next)
1340
    if (sr->sr_usage == du && 
1341 1342
	(sr->sr_method == sip_method_invite || 
	 sr->sr_method == sip_method_update))
1343
      return;
1344

1345 1346 1347 1348
  if (ss->ss_timer->refresher == nua_remote_refresher) {
    ss->ss_reason = "SIP;cause=408;text=\"Session timeout\""; 
    nua_stack_bye(nh->nh_nua, nh, nua_r_bye, NULL);
    return;
1349 1350
  }
  else if (NH_PGET(nh, update_refresh)) {
1351
    nua_stack_update(nh->nh_nua, nh, nua_r_update, NULL);
1352
  }
1353
  else if (du->du_cr) {
1354
    nua_client_resend_request(du->du_cr, 0);
1355
  }
1356 1357 1358
  else {
    nua_stack_invite(nh->nh_nua, nh, nua_r_invite, NULL);
  }
1359 1360
}

1361 1362 1363 1364 1365 1366
/** @interal Shut down session usage. 
 *
 * @retval >0  shutdown done
 * @retval 0   shutdown in progress
 * @retval <0  try again later
 */
1367
static int nua_session_usage_shutdown(nua_handle_t *nh,
1368
				      nua_dialog_state_t *ds,
1369
				      nua_dialog_usage_t *du)
1370
{
1371 1372
  nua_session_usage_t *ss = nua_dialog_usage_private(du);
  nua_server_request_t *sr, *sr_next;
1373
  nua_client_request_t *cri;
1374

1375
  assert(ss == nua_session_usage_for_dialog(nh->nh_ds));
1376

1377 1378
  /* Zap server-side transactions */
  for (sr = ds->ds_sr; sr; sr = sr_next) {
1379 1380 1381 1382
    sr_next = sr->sr_next;
    if (sr->sr_usage == du) {
      assert(sr->sr_usage == du);
      sr->sr_usage = NULL;
1383 1384 1385 1386 1387 1388 1389

      if (nua_server_request_is_pending(sr)) {
	SR_STATUS1(sr, SIP_480_TEMPORARILY_UNAVAILABLE);
	nua_server_respond(sr, NULL);
	if (nua_server_report(sr) >= 2)
	  return 480;
      }
1390 1391 1392
      else
	nua_server_request_destroy(sr);
    }
1393 1394
  }

1395 1396
  cri = du->du_cr;

1397
  switch (ss->ss_state) {
1398 1399 1400 1401
  case nua_callstate_calling:
  case nua_callstate_proceeding:
    return nua_client_create(nh, nua_r_cancel, &nua_cancel_client_methods, NULL);

1402 1403
  case nua_callstate_completing:
  case nua_callstate_completed:
1404
  case nua_callstate_ready:
1405 1406 1407 1408 1409
    if (cri && cri->cr_orq) {
      if (cri->cr_status < 200)
	nua_client_create(nh, nua_r_cancel, &nua_cancel_client_methods, NULL);
      else if (cri->cr_status < 300)
	nua_invite_client_ack(cri, NULL);
1410
    }
1411 1412
    if (nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL) != 0)
      break;
1413 1414 1415

    signal_call_state_change(nh, ss, 487, "BYE sent",
			     nua_callstate_terminating);
1416
    return 0;
1417

1418
  case nua_callstate_terminating:
Pekka Pessi's avatar