nua_session.c 116 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 51 52 53 54 55 56 57 58
#define NTA_RELIABLE_MAGIC_T struct nua_handle_s

#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 */

140 141 142
/** Session-related state */
typedef struct nua_session_usage
{
143
  enum nua_callstate ss_state;		/**< Session status (enum nua_callstate) */
144 145 146 147 148 149 150 151 152
  
  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 */

  unsigned        ss_timer_set:1;       /**< We have active session timer. */
153 154

  unsigned        ss_reporting:1;       /**< True if reporting state */
155 156 157 158 159 160
  unsigned        : 0;
  
  unsigned        ss_session_timer;	/**< Value of Session-Expires (delta) */
  unsigned        ss_min_se;		/**< Minimum session expires */
  enum nua_session_refresher ss_refresher; /**< none, local or remote */

161 162
  char const     *ss_oa_recv, *ss_oa_sent;
  char const     *ss_reason;	        /**< Reason for termination. */
163
} nua_session_usage_t;
164 165

static char const *nua_session_usage_name(nua_dialog_usage_t const *du);
166
static int nua_session_usage_add(nua_handle_t *nh,
167 168
				 nua_dialog_state_t *ds,
				 nua_dialog_usage_t *du);
169
static void nua_session_usage_remove(nua_handle_t *nh,
170 171
				     nua_dialog_state_t *ds,
				     nua_dialog_usage_t *du);
172
static void nua_session_usage_refresh(nua_owner_t *,
173
				      nua_dialog_state_t *,
174 175 176
				      nua_dialog_usage_t *,
				      sip_time_t now);
static int nua_session_usage_shutdown(nua_owner_t *,
177 178
				      nua_dialog_state_t *,
				      nua_dialog_usage_t *);
179 180 181

static nua_usage_class const nua_session_usage[1] = {
  {
182
    sizeof (nua_session_usage_t),
183 184 185 186
    sizeof nua_session_usage,
    nua_session_usage_add,
    nua_session_usage_remove,
    nua_session_usage_name,
187 188 189
    NULL,
    nua_session_usage_refresh,
    nua_session_usage_shutdown
190 191 192 193 194 195 196
  }};

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

197 198
static
int nua_session_usage_add(nua_handle_t *nh,
199 200 201 202 203 204
			   nua_dialog_state_t *ds,
			   nua_dialog_usage_t *du)
{
  if (ds->ds_has_session)
    return -1;
  ds->ds_has_session = 1;
205

206 207 208
  return 0;
}

209 210
static
void nua_session_usage_remove(nua_handle_t *nh,
211 212 213
			       nua_dialog_state_t *ds,
			       nua_dialog_usage_t *du)
{
214 215
  nua_session_usage_t *ss = nua_dialog_usage_private(du);

216
  ds->ds_has_session = 0;
217 218 219
  
  (void)ss;
}
220

221 222 223 224 225
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;
226

227
  return nua_dialog_usage_get(ds, nua_session_usage, NULL);
228 229 230 231 232 233 234 235 236 237 238 239 240
}

static
nua_session_usage_t *nua_session_usage_get(nua_dialog_state_t const *ds)
{
  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);
241 242
}

243 244 245 246 247 248 249 250
/** Zap the session associated with the handle */
static
void nua_session_usage_destroy(nua_handle_t *nh,
			       nua_session_usage_t *ss)
{
  nh->nh_has_invite = 0;
  nh->nh_active_call = 0;
  nh->nh_hold_remote = 0;
251

252 253 254 255 256
  if (nh->nh_soa)
    soa_destroy(nh->nh_soa), nh->nh_soa = NULL;

  /* Remove usage */
  nua_dialog_usage_remove(nh, nh->nh_ds, nua_dialog_usage_public(ss));
257

258 259
  SU_DEBUG_5(("nua: terminated session %p\n", nh));
}
260

261 262
/* ======================================================================== */
/* INVITE and call (session) processing */
263 264 265 266

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

267 268 269 270
static void session_timer_preferences(nua_session_usage_t *ss,
				      unsigned expires,
				      unsigned min_se,
				      enum nua_session_refresher refresher);
271

272
static int session_timer_is_supported(nua_handle_t const *nh);
273

274 275 276 277
static int prefer_session_timer(nua_handle_t const *nh);

static int use_session_timer(nua_session_usage_t *ss, int uas, int always,
			     msg_t *msg, sip_t *);
278
static int init_session_timer(nua_session_usage_t *ss, sip_t const *, int refresher);
279 280
static void set_session_timer(nua_session_usage_t *ss);

281 282 283
static int session_timer_check_restart(nua_client_request_t *cr,
				       int status, char const *phrase,
				       sip_t const *sip);
284

285 286 287
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);
288

289
static void signal_call_state_change(nua_handle_t *nh,
290 291 292
				      nua_session_usage_t *ss,
				      int status, char const *phrase,
				      enum nua_callstate next_state);
293 294

static
295
int session_get_description(sip_t const *sip,
296
			    char const **return_sdp,
297 298 299
			    size_t *return_len);

static
300
int session_include_description(soa_session_t *soa,
301
				int session,
302
				msg_t *msg,
303 304 305
				sip_t *sip);

static
306 307
int session_make_description(su_home_t *home,
			     soa_session_t *soa,
308
			     int session,
309 310 311 312
			     sip_content_disposition_t **return_cd,
			     sip_content_type_t **return_ct,
			     sip_payload_t **return_pl);

313
static
314 315 316
int nua_server_retry_after(nua_server_request_t *sr,
			   int status, char const *phrase,
			   int min, int max);
317

318
/**@fn void nua_invite(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
319 320 321 322 323 324 325
 *
 * 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 
326
 * - uses early media if NUTAG_EARLY_MEDIA() tag is used with non zero-value
327 328 329 330 331 332 333 334 335 336 337 338
 * - 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:
339 340 341
 *    NUTAG_URL() \n
 *    Tags of nua_set_hparams() \n
 *    NUTAG_INCLUDE_EXTRA_SDP() \n
342 343 344
 *    SOATAG_HOLD(), SOATAG_AF(), SOATAG_ADDRESS(),
 *    SOATAG_RTP_SELECT(), SOATAG_RTP_SORT(), SOATAG_RTP_MISMATCH(), 
 *    SOATAG_AUDIO_AUX(), \n
345
 *    SOATAG_USER_SDP() or SOATAG_USER_SDP_STR() \n
346
 *    See use of tags in <sip_tag.h> below
347 348 349
 *
 * @par Events:
 *    #nua_r_invite \n
350
 *    #nua_i_state (#nua_i_active, #nua_i_terminated) \n
351 352 353 354 355 356 357 358
 *    #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.
359 360
 *
 * @par
361 362 363 364 365 366 367
 * 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.
 * 
368
 * @par
369 370 371
 * However, if a tag value is #SIP_NONE (-1 casted as a void pointer), the
 * values from previous tags are ignored.
 *
372
 * @par
373 374 375 376
 * 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.
 *
377
 * @par
378 379
 * Now, the target URI for the request needs to be determined.
 *
380
 * @par
381 382 383 384 385 386 387 388 389 390
 * 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.
 *
391
 * @par
392 393 394 395 396 397 398
 * 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.
 *
399
 * @par
400 401 402
 * @MaxForwards header (with default value set by NTATAG_MAX_FORWARDS()) is
 * also added now, if it does not exist.
 * 
403
 * @par
404 405 406 407 408 409 410 411
 * 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.
 *
412
 * @par
413 414 415
 * For the initial INVITE requests, @ServiceRoute set received from
 * the registrar is also added to the request message.
 *
416
 * @par
417 418
 * The INVITE request message created by nua_invite() operation is saved as
 * a template for automatic re-INVITE requests sent by the session timer
419 420 421 422 423
 * ("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).
424 425 426 427 428 429 430
 *
 * @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. 
 *
431
 * @par
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
 * 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.
 *
447 448
 * @sa @ref nua_call_model, #nua_r_invite, #nua_i_state, \n
 *     nua_handle_has_active_call() \n
449 450 451 452 453 454 455 456
 *     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
457
 *     #nua_i_invite, nua_respond()
458 459
 */

460 461 462
/* Tags not implemented
 *    NUTAG_REFER_PAUSE() \n
 */
463

464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
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);

static int nua_invite_client_ack(nua_client_request_t *cr, tagi_t const *tags);
static int nua_invite_client_ack_msg(nua_client_request_t *cr, 
				     msg_t *msg, sip_t *sip,
				     tagi_t const *tags);

490 491
static int nua_invite_client_deinit(nua_client_request_t *cr);

492
nua_client_methods_t const nua_invite_client_methods = {
493 494 495 496 497 498 499 500 501 502 503 504 505
  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,
506 507
  nua_invite_client_report,
  nua_invite_client_deinit
508 509
};

510 511 512 513 514
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;
515 516 517 518 519

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);
520 521
}

522 523 524
static int nua_invite_client_init(nua_client_request_t *cr, 
				  msg_t *msg, sip_t *sip,
				  tagi_t const *tags)
525
{
526
  nua_handle_t *nh = cr->cr_owner;
527 528
  nua_dialog_usage_t *du;

529 530 531 532 533 534 535
  cr->cr_usage = du = nua_dialog_usage_for_session(nh->nh_ds);
  
  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);
536

537 538 539 540
  if (!du)
    du = nua_dialog_usage_add(nh, nh->nh_ds, nua_session_usage, NULL);
  if (!du)
    return -1;
541

542 543
  if (nua_client_bind(cr, du) < 0)
    return nua_client_return(cr, 900, "INVITE already in progress", msg);
544

545 546 547 548
  session_timer_preferences(nua_dialog_usage_private(du), 
			    NH_PGET(nh, session_timer),
			    NH_PGET(nh, min_se),
			    NH_PGET(nh, refresher));
549

550 551
  return 0;
}
552

553 554 555 556 557 558 559 560 561
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;
562

563 564
  if (du == NULL)		/* Call terminated */ 
    return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg);
565

566
  assert(ss);
567

568 569 570 571 572 573
  invite_timeout = NH_PGET(nh, invite_timeout);
  if (invite_timeout == 0)
    invite_timeout = UINT_MAX;
  /* Cancel if we don't get response within timeout*/
  nua_dialog_usage_set_expires(du, invite_timeout);
  nua_dialog_usage_set_refresh(du, 0);
574

575 576 577
  /* Add session timer headers */
  if (session_timer_is_supported(nh))
    use_session_timer(ss, 0, prefer_session_timer(nh), msg, sip);
578

579 580 581 582
  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;
583 584

  if (nh->nh_soa) {
585 586 587
    soa_init_offer_answer(nh->nh_soa);

    if (sip->sip_payload)
588
      offer_sent = 0;		/* XXX - kludge */
589
    else if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0)
590
      return -1;
591 592 593 594
    else
      offer_sent = 1;
  }

595 596 597
  if (offer_sent > 0 &&
      session_include_description(nh->nh_soa, 1, msg, sip) < 0)
    return nua_client_return(cr, 900, "Internal media error", msg);
598

599 600 601 602 603 604
  if (nh->nh_soa &&
      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);
605

606 607
    ac->cp_params = (msg_param_t *)
      soa_media_features(nh->nh_soa, 1, msg_home(msg));
608

609 610 611
    if (ac->cp_params) {
      msg_header_replace_param(msg_home(msg), ac->cp_common, "explicit");
      sip_add_dup(msg, sip, (sip_header_t *)ac);
612
    }
613
  }
614

615 616 617 618 619 620
  retval = nua_base_client_trequest(cr, msg, sip,
				    NTATAG_REL100(ss->ss_100rel),
				    TAG_NEXT(tags));
  if (retval == 0) {
    cr->cr_offer_sent = offer_sent;
    ss->ss_oa_sent = offer_sent ? "offer" : NULL;
621

622 623 624 625
    if (!cr->cr_restarting)
      signal_call_state_change(nh, ss, 0, "INVITE sent", 
			       nua_callstate_calling);
  }
626

627 628
  return retval;
}
629

630 631 632 633 634 635 636
static int nua_invite_client_response(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);
637

638 639
  if (ss == NULL || sip == NULL) {
    /* Xyzzy */
640
  }
641 642
  else if (status < 300) {
    du->du_ready = 1;
643

644 645 646 647 648 649
    init_session_timer(ss, sip, NH_PGET(nh, refresher));
    set_session_timer(ss);
  }
  
  return nua_session_client_response(cr, status, phrase, sip);
}
650

651 652 653 654 655 656 657
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);
658

659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
  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) {
      SU_DEBUG_5(("nua(%p): 100rel missing RSeq\n", nh));
    }
    else if (nta_outgoing_rseq(cr->cr_orq) > rseq->rs_response) {
      SU_DEBUG_5(("nua(%p): 100rel bad RSeq %u (got %u)\n", nh, 
		  (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) {
      SU_DEBUG_1(("nua(%p): cannot set RSeq %u\n", nh, 
		  (unsigned)rseq->rs_response));
      cr->cr_graceful = 1;
      ss->ss_reason = "SIP;cause=400;text=\"Bad RSeq\"";
    }
  }
701

702
  return nua_session_client_response(cr, status, phrase, sip);
703 704
}

705 706 707 708
/** 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)
709
{
710 711 712 713 714 715
  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;
716 717
  char const *received = NULL;

718 719 720 721 722 723 724
#define LOG3(m) \
  SU_DEBUG_3(("nua(%p): %s: %s %s in %u %s\n", \
	      nh, cr->cr_method_name, (m), \
	      received ? received : "SDP", status, phrase))
#define LOG5(m) \
  SU_DEBUG_5(("nua(%p): %s: %s %s in %u %s\n", \
	      nh, cr->cr_method_name, (m), received, status, phrase))
725

726 727 728 729 730 731 732 733
  if (nh->nh_soa == NULL || !ss || !sip || 300 <= status)
    /* 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;
734
  }
735 736 737 738
  else if (cr->cr_offer_sent) {
    /* case 1: incoming answer */
    cr->cr_answer_recv = status;
    received = "answer";
739

740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765
    if (soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) {
      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 {
    /* case 2: answer to our offer */
    cr->cr_offer_recv = 1, cr->cr_answer_sent = 0;
    received = "offer";
766

767 768 769 770 771
    if (soa_set_remote_sdp(nh->nh_soa, NULL, sdp, len) < 0) {
      LOG3("error parsing SDP");
      sdp = NULL;
      cr->cr_graceful = 1;
      ss->ss_reason = "SIP;cause=400;text=\"Malformed Session Description\"";
772
    }
773 774
    else 
      LOG5("got SDP");
775
  }
776

777 778
  if (ss && received)
    ss->ss_oa_recv = received;
779

780 781 782 783 784 785 786
  if (sdp)
    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);
}
787

788 789 790 791 792 793 794 795 796 797 798
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;
  nua_dialog_usage_t *du = cr->cr_usage;
  nua_session_usage_t *ss = nua_dialog_usage_private(du);
  unsigned next_state;
  int error;
799

800 801 802 803 804 805
  nh_referral_respond(nh, status, phrase);

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

808 809
  if (orq != cr->cr_orq && status != 100)
    return 1;
810

811 812
  ss->ss_reporting = 1;

813 814
  if (ss == NULL) {
    next_state = nua_callstate_terminated;
815
  }
816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
  else if (status == 100) {
    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;
    if (sip && sip->sip_rseq) {
      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;
853 854
  }
  else {
855
    next_state = nua_callstate_init;
856 857
  }

858
  if (next_state == nua_callstate_calling) {
859 860
    if (sip && sip->sip_status && sip->sip_status->st_status == 100) {
      ss->ss_reporting = 0;
861
      return 1;
862
    }
863
  }
864

865 866 867 868 869
  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))) {
870

871 872 873 874 875 876
      if (nua_invite_client_ack(cr, NULL) > 0)
	next_state = nua_callstate_ready;
      else
	next_state = nua_callstate_terminating;
    }
  }
877

878
  if (next_state == nua_callstate_terminating) {
879 880 881 882 883 884 885 886 887
    /* 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) {
888 889 890
      next_state = nua_callstate_terminated;
      cr->cr_terminated = 1;
    }
891
    cr->cr_graceful = 0;
892 893
  }

894 895
  ss->ss_reporting = 0;

896 897 898
  signal_call_state_change(nh, ss, status, phrase, next_state);

  return 1;
899 900
}

901 902 903 904 905
/**@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
906
 * SIP ACK request message. This function is needed only if NUTAG_AUTOACK()
907 908 909 910 911 912 913 914 915 916 917 918 919
 * parameter has been cleared.
 *
 * @param nh              Pointer to operation handle
 * @param tag, value, ... List of tagged parameters
 *
 * @return 
 *    nothing
 *
 * @par Related Tags:
 *    Tags in <sip_tag.h>
 *
 * @par Events:
 *    #nua_i_media_error \n
920
 *    #nua_i_state  (#nua_i_active, #nua_i_terminating, #nua_i_terminated) 
921 922
 *
 * @sa NUTAG_AUTOACK(), @ref nua_call_model, #nua_i_state
923 924
 */

925 926
int nua_stack_ack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
		  tagi_t const *tags)
927
{
928 929
  nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds);
  nua_session_usage_t *ss = nua_dialog_usage_private(du);
930

931 932 933 934 935 936 937
  if (!du || 
      !du->du_cr || 
      du->du_cr->cr_orq == NULL || 
      du->du_cr->cr_status < 200) {
    UA_EVENT2(nua_i_error, 900, "No response to ACK");
    return 1;
  }
938

939 940 941 942 943
  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));
  }
944

945
  if (nua_invite_client_ack(du->du_cr, tags) < 0) {
946
    int error;
947
    ss->ss_reason = "SIP;cause=500;text=\"Internal Error\"";
948 949 950 951 952 953 954
    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);
955
  }
956

957 958
  return 0;
}
959

960 961 962 963 964 965 966 967 968 969
/** 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;
970

971 972 973 974 975 976
  msg_t *msg;
  sip_t *sip;
  int error = -1;
  sip_authorization_t *wa;
  sip_proxy_authorization_t *pa;
  sip_cseq_t *cseq;
977

978 979
  assert(ds->ds_leg);
  assert(cr->cr_orq);
980

981 982 983 984 985 986 987 988
  msg = nta_outgoing_getrequest(cr->cr_orq);
  sip = sip_object(msg);  
  if (!msg)
    return -1;
  
  wa = sip_authorization(sip);
  pa = sip_proxy_authorization(sip);
  
989 990
  msg_destroy(msg);

991 992 993 994
  msg = nta_msg_create(nh->nh_nua->nua_nta, 0);
  sip = sip_object(msg);  
  if (!msg)
    return -1;
995

996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
  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)
    ;
  else
    error = nua_invite_client_ack_msg(cr, msg, sip, tags);
1014

1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
  nta_outgoing_destroy(cr->cr_orq), cr->cr_orq = NULL;
  
  if (error == -1)
    msg_destroy(msg);

  return error;
}

/** Send ACK, destroy INVITE transaction.
 *
 *  @retval 1 if successful
 *  @retval -2 if an error occurred
 */
static
int nua_invite_client_ack_msg(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);

  nta_outgoing_t *ack;
  int status = 200;
  char const *phrase = "OK", *reason = NULL;

  /* 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);

  if (!nh->nh_soa)
    ;
  else if (cr->cr_offer_recv && !cr->cr_answer_sent) {
    if (soa_generate_answer(nh->nh_soa, NULL) < 0 ||
	session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
      status = 900, phrase = "Internal media error";
      reason = "SIP;cause=500;text=\"Internal media error\"";
1062
      /* reason = soa_error_as_sip_reason(nh->nh_soa); */
1063 1064 1065 1066 1067 1068
    }
    else {
      cr->cr_answer_sent = 1;
      soa_activate(nh->nh_soa, NULL);
      /* signal that O/A round is complete */
      ss->ss_oa_sent = "answer";
1069 1070
    }

1071
    if (!reason &&
1072 1073 1074
	/* ss->ss_offer_sent && !ss->ss_answer_recv */
	!soa_is_complete(nh->nh_soa)) {
      /* No SDP answer in 2XX response -> terminate call */
1075 1076
      status = 988, phrase = "Incomplete offer/answer";
      reason = "SIP;cause=488;text=\"Incomplete offer/answer\"";
1077 1078 1079
    }
  }

1080 1081 1082 1083 1084
  if ((ack = nta_outgoing_mcreate(nh->nh_nua->nua_nta, NULL, NULL, NULL,
				  msg,
				  SIPTAG_END(),
				  TAG_NEXT(tags)))) {
    nta_outgoing_destroy(ack);	/* TR engine keeps this around for T2 */
1085
  }
1086 1087 1088
  else if (!reason) {
    status = 900, phrase = "Cannot send ACK";
    reason = "SIP;cause=500;text=\"Internal Error\"";
1089 1090
  }

1091 1092 1093 1094
  if (ss) {
    if (reason)
      ss->ss_reason = reason;

1095 1096
    if (!ss->ss_reporting && status < 300)
      signal_call_state_change(nh, ss, status, phrase, nua_callstate_ready);
1097
  }
1098
  
1099
  return status < 300 ? 1 : -2;
1100 1101
}

1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
/** 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;
}

1115
/**@fn void nua_cancel(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
1116
 *
1117
 * Cancel an INVITE operation 
1118 1119 1120 1121 1122 1123 1124 1125
 *
 * @param nh              Pointer to operation handle
 * @param tag, value, ... List of tagged parameters
 *
 * @return 
 *    nothing
 *
 * @par Related Tags:
1126
 *    Tags in <sip_tag.h>
1127 1128
 *
 * @par Events:
1129
 *    #nua_r_cancel, #nua_i_state  (#nua_i_active, #nua_i_terminated)
1130
 *
1131
 * @sa @ref nua_call_model, nua_invite(), #nua_i_cancel
1132 1133
 */

1134 1135 1136 1137
static int nua_cancel_client_request(nua_client_request_t *cr,
				     msg_t *msg, sip_t *sip,
				     tagi_t const *tags);

1138
nua_client_methods_t const nua_cancel_client_methods = {
1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154
  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)
1155
{
1156
  return nua_client_create(nh, e, &nua_cancel_client_methods, tags);
1157 1158
}

1159 1160 1161
static int nua_cancel_client_request(nua_client_request_t *cr,
				     msg_t *msg, sip_t *sip,
				     tagi_t const *tags)
1162
{
1163 1164
  nua_handle_t *nh = cr->cr_owner;
  nua_dialog_usage_t *du = nua_dialog_usage_for_session(nh->nh_ds);
1165

1166 1167 1168
  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);
1169 1170
  }

1171 1172 1173
  cr->cr_orq = nta_outgoing_tcancel(du->du_cr->cr_orq,
				    nua_client_orq_response, cr,
				    TAG_NEXT(tags));
1174

1175
  return cr->cr_orq ? 0 : -1;
1176 1177
}

1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
/** @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
 */

1200
static void nua_session_usage_refresh(nua_handle_t *nh,
1201
				      nua_dialog_state_t *ds,
1202 1203
				      nua_dialog_usage_t *du,
				      sip_time_t now)
1204
{
1205 1206
  nua_session_usage_t *ss = nua_dialog_usage_private(du);
  nua_client_request_t const *cr = du->du_cr;
1207
  nua_server_request_t const *sr;
1208

1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
  assert(cr);

  if (ss->ss_state >= nua_callstate_terminating || 
      /* No INVITE template */
      cr == NULL || 
      /* INVITE is in progress or being authenticated */
      cr->cr_orq || cr->cr_challenged)
    return;

  /* UPDATE in progress or being authenticated */
  for (cr = ds->ds_cr; cr; cr = cr->cr_next) 
    if (cr->cr_method == sip_method_update)
      return;

  /* INVITE or UPDATE in progress or being authenticated */
1224
  for (sr = ds->ds_sr; sr; sr = sr->sr_next)
1225
    if (sr->sr_usage == du && 
1226 1227
	(sr->sr_method == sip_method_invite || 
	 sr->sr_method == sip_method_update))
1228
      return;
1229

1230
  if (!ss->ss_refresher) {
1231 1232 1233 1234 1235 1236 1237
    if (du->du_expires == 0 || now < du->du_expires)
      /* Refresh contact & route set using re-INVITE */
      nua_client_resend_request(du->du_cr, 0, NULL);
    else {
      ss->ss_reason = "SIP;cause=408;text=\"Session timeout\""; 
      nua_stack_bye(nh->nh_nua, nh, nua_r_bye, NULL);
    }
1238 1239
  }
  else if (NH_PGET(nh, update_refresh)) {
1240
    nua_stack_update(nh->nh_nua, nh, nua_r_update, NULL);
1241 1242
  }
  else {
1243
    nua_client_resend_request(du->du_cr, 0, NULL);
1244 1245 1246
  }
}

1247 1248 1249 1250 1251 1252
/** @interal Shut down session usage. 
 *
 * @retval >0  shutdown done
 * @retval 0   shutdown in progress
 * @retval <0  try again later
 */
1253
static int nua_session_usage_shutdown(nua_handle_t *nh,
1254
				      nua_dialog_state_t *ds,
1255
				      nua_dialog_usage_t *du)
1256
{
1257 1258
  nua_session_usage_t *ss = nua_dialog_usage_private(du);
  nua_server_request_t *sr, *sr_next;
1259
  nua_client_request_t *cri;
1260

1261 1262
  assert(ss == nua_session_usage_get(nh->nh_ds));

1263 1264
  /* Zap server-side transactions */
  for (sr = ds->ds_sr; sr; sr = sr_next) {
1265 1266 1267 1268
    sr_next = sr->sr_next;
    if (sr->sr_usage == du) {
      assert(sr->sr_usage == du);
      sr->sr_usage = NULL;
1269 1270 1271 1272 1273 1274 1275

      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;
      }
1276 1277 1278
      else
	nua_server_request_destroy(sr);
    }
1279 1280
  }

1281 1282
  cri = du->du_cr;

1283
  switch (ss->ss_state) {
1284 1285 1286 1287
  case nua_callstate_calling:
  case nua_callstate_proceeding:
    return nua_client_create(nh, nua_r_cancel, &nua_cancel_client_methods, NULL);

1288 1289 1290
  case nua_callstate_completing:
  case nua_callstate_ready:
  case nua_callstate_completed:
1291 1292 1293 1294 1295
    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);
1296
    }
1297 1298 1299
    if (nua_client_create(nh, nua_r_bye, &nua_bye_client_methods, NULL) != 0)
      break;
    return 0;
1300

1301
  case nua_callstate_terminating:
1302
  case nua_callstate_terminated: /* XXX */
1303
    return 0;
1304 1305 1306

  default:
    break;
1307 1308
  }
  
1309
  nua_dialog_usage_remove(nh, ds, du);
1310

1311
  return 200;
1312 1313
}

1314 1315
/**@fn void nua_prack(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
 * Send a PRACK request. 
1316
 *
1317
 * PRACK is used to acknowledge receipt of 100rel responses. See @RFC3262.
1318 1319 1320 1321 1322 1323 1324 1325
 *
 * @param nh              Pointer to operation handle
 * @param tag, value, ... List of tagged parameters
 *
 * @return 
 *    nothing
 *
 * @par Related Tags:
1326
 *    Tags in <sofia-sip/soa_tag.h>, <sofia-sip/sip_tag.h>.
1327 1328
 *
 * @par Events:
1329 1330 1331 1332
 *    #nua_r_prack
 */

/** @NUA_EVENT nua_r_prack
1333
 *
1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
 * Response to an outgoing @b PRACK request. PRACK request is used to
 * acknowledge reliable preliminary responses and it is usually sent
 * automatically by the nua stack.
 *
 * @param status response status code
 *               (if the request is retried, @a status is 100, the @a
 *               sip->sip_status->st_status contain the real status code
 *               from the response message, e.g., 302, 401, or 407)
 * @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 @b PRACK or NULL upon an error
 *               (status code is in @a status and 
 *                descriptive message in @a phrase parameters)
 * @param tags   empty
 *
 * @sa nua_prack(), #nua_i_prack, @RFC3262
 *
 * @END_NUA_EVENT
1353 1354
 */

1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369
static int nua_prack_client_init(nua_client_request_t *cr, 
				 msg_t *msg, sip_t *sip,
				 tagi_t const *tags);
static int nua_prack_client_request(nua_client_request_t *cr,
				    msg_t *msg, sip_t *sip,
				    tagi_t const *tags);
static int nua_prack_client_response(nua_client_request_t *cr,
				     int status, char const *phrase,
				     sip_t const *sip);
static int nua_prack_client_report(nua_client_request_t *cr,
				   int status, char const *phrase,
				   sip_t const *sip,
				   nta_outgoing_t *orq,
				   tagi_t const *tags);

1370
nua_client_methods_t const nua_prack_client_methods = {
1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388
  SIP_METHOD_PRACK,
  0,
  { 
    /* create_dialog */ 0,
    /* in_dialog */ 1,
    /* target refresh */ 0
  },
  NULL,
  nua_prack_client_init,
  nua_prack_client_request,
  /* nua_prack_client_check_restart */ NULL,
  nua_prack_client_response,
  NULL,
  nua_prack_client_report
};

int nua_stack_prack(nua_t *nua, nua_handle_t *nh, nua_event_t e,
		     tagi_t const *tags)
1389
{
1390 1391
  return nua_client_create(nh, e, &nua_prack_client_methods, tags);
}
1392

1393 1394 1395 1396 1397 1398
static int nua_prack_client_init(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 = nua_dialog_usage_for_session(nh->nh_ds);
1399

1400
  cr->cr_usage = du;
1401

1402 1403
  return 0;
}
1404

1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415
static int nua_prack_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);
  nua_client_request_t *cri;
  int offer_sent = 0, answer_sent = 0, retval;
  int status = 0; char const *phrase = "PRACK Sent";
  uint32_t rseq = 0;
1416

1417 1418 1419
  if (du == NULL)		/* Call terminated */
    return nua_client_return(cr, SIP_481_NO_TRANSACTION, msg);
  assert(ss);
1420

1421
  cri = du->du_cr;
1422

1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437
  if (sip->sip_rack)
    rseq = sip->sip_rack->ra_response;

  if (nh->nh_soa == NULL)
    /* It is up to application to handle SDP */;
  else if (sip->sip_payload)
    /* XXX - we should just do MIME in session_include_description() */;
  else if (cri->cr_offer_recv && !cri->cr_answer_sent) {
    if (soa_generate_answer(nh->nh_soa, NULL) < 0 ||
	session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
      status = soa_error_as_sip_response(nh->nh_soa, &phrase);
      SU_DEBUG_3(("nua(%p): local response to PRACK: %d %s\n",
		  nh, status, phrase));
      nua_stack_event(nh->nh_nua, nh, NULL,
		      nua_i_media_error, status, phrase,
1438
		      NULL);
1439 1440 1441 1442 1443 1444 1445 1446
      return nua_client_return(cr, status, phrase, msg);
    }
    else {
      answer_sent = 1;
      soa_activate(nh->nh_soa, NULL);
    }
  }
  /* When 100rel response status was 183 fake support for preconditions */
1447
  else if (cr->cr_auto && cri->cr_status == 183 && ss->ss_precondition) {
1448 1449 1450 1451 1452
    if (soa_generate_offer(nh->nh_soa, 0, NULL) < 0 ||
	session_include_description(nh->nh_soa, 1, msg, sip) < 0) {
      status = soa_error_as_sip_response(nh->nh_soa, &phrase);
      SU_DEBUG_3(("nua(%p): PRACK offer: %d %s\n", nh, status, phrase));
      nua_stack_event(nh->nh_nua, nh, NULL,
1453
		      nua_i_media_error, status, phrase, NULL);
1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465
      return nua_client_return(cr, status, phrase, msg);
    }
    else {
      offer_sent = 1;
    }
  }

  retval = nua_base_client_request(cr, msg, sip, NULL);

  if (retval == 0) {
    cr->cr_offer_sent = offer_sent;
    cr->cr_answer_sent = answer_sent;
1466

1467 1468 1469 1470 1471
    if (!cr->cr_restarting) {
      if (offer_sent) 
	ss->ss_oa_sent = "offer";
      else if (answer_sent)
	ss->ss_oa_sent = "answer";
1472

1473 1474 1475
      if (!ss->ss_reporting)
	signal_call_state_change(nh, ss, status, phrase, ss->ss_state);
    }
1476 1477
  }

1478
  return retval;
1479 1480
}

1481 1482 1483 1484 1485
static int nua_prack_client_response(nua_client_request_t *cr,
				     int status, char const *phrase,
				     sip_t const *sip)
{
  /* XXX - fatal error cases? */
1486

1487 1488
  return nua_session_client_response(cr, status, phrase, sip);
}
1489

1490 1491 1492 1493 1494
static int nua_prack_client_report(nua_client_request_t *cr,
				   int status, char const *phrase,
				   sip_t const *sip,
				   nta_outgoing_t *orq,
				   tagi_t const *tags)
1495
{
1496 1497 1498 1499 1500 1501 1502
  nua_handle_t *nh = cr->cr_owner;
  nua_session_usage_t *ss = nua_dialog_usage_private(cr->cr_usage);

  nua_stack_event(nh->nh_nua, nh, 
		  nta_outgoing_getresponse(orq),
		  cr->cr_event,
		  status, phrase,
1503
		  tags);
1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514

  if (!ss || orq != cr->cr_orq || cr->cr_terminated || cr->cr_graceful)
    return 1;

  if (cr->cr_offer_sent)
    signal_call_state_change(nh, ss, status, phrase, ss->ss_state);

  if (ss->ss_update_needed && 200 <= status && status < 300)
    nua_client_create(nh, nua_r_update, &nua_update_client_methods, NULL);
  
  return 1;
1515 1516
}

1517 1518 1519
/* ---------------------------------------------------------------------- */
/* UAS side of INVITE */

1520
/** @NUA_EVENT nua_i_invite
1521
 *
1522
 * Indication of incoming call or re-INVITE request. 
1523
 *
1524 1525
 * @param status statuscode of response sent automatically by stack
 * @param phrase a short textual description of @a status code
1526 1527
 * @param nh     operation handle associated with this call
 *               (maybe created for this call)
1528
 * @param hmagic application context associated with this call
1529 1530 1531
 *               (maybe NULL if call handle was created for this call)
 * @param sip    incoming INVITE request
 * @param tags   SOATAG_ACTIVE_AUDIO(), SOATAG_ACTIVE_VIDEO()
1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564
 * 
 * @par Responding to INVITE with nua_respond()
 *
 * If @a status in #nua_i_invite event is below 200, the application should
 * accept or reject the call with nua_respond(). See the @ref nua_call_model
 * for the detailed explanation of various options in call processing at
 * server end.
 *
 * The @b INVITE request takes care of session setup using SDP Offer-Answer
 * negotiation as specified in @RFC3264 (updated in @RFC3262 section 5,
 * @RFC3311, and @RFC3312). The Offer-Answer can be taken care by
 * application (if NUTAG_MEDIA_ENABLE(0) parameter has been set) or by the
 * built-in SDP Offer/Answer engine @soa (by default and when
 * NUTAG_MEDIA_ENABLE(1) parameter has been set). When @soa is enabled, it
 * will take care of parsing the SDP, negotiating the media and codecs, and
 * including the SDP in the SIP message bodies as required by the
 * Offer-Answer model.
 *
 * When @soa is enabled, the SDP in the incoming INVITE is parsed and feed
 * to a #soa_session_t object. The #nua_i_state event sent to the
 * application immediately after #nua_i_invite will contain the parsing
 * results in SOATAG_REMOTE_SDP() and SOATAG_REMOTE_SDP_STR() tags.
 * 
 * Note that currently the parser within @nua does not handle MIME
 * multipart. The SDP Offer/Answer engine can get confused if the SDP offer
 * is included in a MIME multipart, therefore such an @b INVITE is rejected
 * with <i>415 Unsupported Media Type</i> error response: the client is
 * expected to retry the INVITE without MIME multipart content.
 *
 * If the call is to be accepted, the application should include the SDP in
 * the 2XX response. If @soa is not disabled with NUTAG_MEDIA_ENABLE(0), the
 * SDP should be included in the SOATAG_USER_SDP() or SOATAG_USER_SDP_STR()
 * parameter given to nua_respond(). If it is disabled, the SDP should be
1565 1566 1567
 * included in the response message using SIPTAG_PAYLOAD() or
 * SIPTAG_PAYLOAD_STR(). Also, the @ContentType should be set using
 * SIPTAG_CONTENT_TYPE() or SIPTAG_CONTENT_TYPE_STR().
1568 1569 1570 1571 1572 1573
 *
 * @par Preliminary Responses and 100rel
 *
 * Call progress can be signaled with preliminary responses (with status
 * code in the range 101..199). It is possible to conclude the SDP
 * Offer-Answer negotiation using preliminary responses, too. If
1574 1575 1576
 * NUTAG_EARLY_ANSWER(1), SOATAG_USER_SDP() or SOATAG_USER_SDP_STR()