nua_register.c 60.1 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 26 27 28
/*
 * 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_register.c
 * @brief REGISTER and registrations
 *
 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
29
 * @author Martti Mela <Martti.Mela@nokia.com>
30
 * @author Kai Vehmanen <Kai.Vehmanen@nokia.com>
31 32 33 34 35 36
 *
 * @date Created: Wed Mar  8 11:48:49 EET 2006 ppessi
 */

#include "config.h"

37 38 39
/** @internal SU network changed detector argument pointer type */
#define SU_NETWORK_CHANGED_MAGIC_T struct nua_s

40 41
#define TP_CLIENT_T          struct register_usage

42
#include <sofia-sip/su_string.h>
43
#include <sofia-sip/su_strlst.h>
44 45 46
#include <sofia-sip/su_uniqueid.h>
#include <sofia-sip/su_tagarg.h>

47
#include <sofia-sip/sip_protos.h>
48
#include <sofia-sip/sip_util.h>
49
#include <sofia-sip/sip_status.h>
50

51
#define NTA_UPDATE_MAGIC_T   struct nua_s
52

53
#include "nua_stack.h"
54

55
#include <sofia-sip/hostdomain.h>
56
#include <sofia-sip/nta_tport.h>
57
#include <sofia-sip/tport.h>
58
#include <sofia-sip/tport_tag.h>
59

60 61 62 63
#define OUTBOUND_OWNER_T struct nua_handle_s

#include "outbound.h"

64 65 66 67
#if HAVE_SIGCOMP
#include <sigcomp.h>
#endif

68 69 70 71 72 73 74
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

#include <assert.h>

75 76
/* ======================================================================== */
/* Registrations and contacts */
77

78
int nua_registration_from_via(nua_registration_t **list,
79
			      nua_handle_t *nh,
80 81
			      sip_via_t const *via,
			      int public);
82

83
int nua_registration_add(nua_registration_t **list, nua_registration_t *nr);
84

85
void nua_registration_remove(nua_registration_t *nr);
86

87 88
int nua_registration_set_aor(su_home_t *, nua_registration_t *nr,
			     sip_from_t const *aor);
89

90
int nua_registration_set_contact(nua_handle_t *,
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
				 nua_registration_t *nr,
				 sip_contact_t const *m,
				 int terminating);

void nua_registration_set_ready(nua_registration_t *nr, int ready);

/* ====================================================================== */
/* REGISTER usage */

static char const *nua_register_usage_name(nua_dialog_usage_t const *du);

static int nua_register_usage_add(nua_handle_t *nh,
				  nua_dialog_state_t *ds,
				  nua_dialog_usage_t *du);
static void nua_register_usage_remove(nua_handle_t *nh,
				      nua_dialog_state_t *ds,
107 108 109
				      nua_dialog_usage_t *du,
				      nua_client_request_t *cr,
				      nua_server_request_t *sr);
110 111 112 113
static void nua_register_usage_update_params(nua_dialog_usage_t const *du,
					     nua_handle_preferences_t const *,
					     nua_handle_preferences_t const *,
					     nua_handle_preferences_t const *);
114 115 116
static void nua_register_usage_peer_info(nua_dialog_usage_t *du,
					 nua_dialog_state_t const *ds,
					 sip_t const *sip);
117 118 119
static void nua_register_usage_refresh(nua_handle_t *,
				       nua_dialog_state_t *,
				       nua_dialog_usage_t *,
120
				       sip_time_t);
121 122 123
static int nua_register_usage_shutdown(nua_handle_t *,
				       nua_dialog_state_t *,
				       nua_dialog_usage_t *);
124

Pekka Pessi's avatar
Pekka Pessi committed
125
/** @internal @brief REGISTER usage, aka nua_registration_t. */
126 127 128 129
struct register_usage {
  nua_registration_t *nr_next, **nr_prev, **nr_list; /* Doubly linked list and its head */
  sip_from_t *nr_aor;		/**< AoR for this registration, NULL if none */
  sip_contact_t *nr_contact;	/**< Our Contact */
130
  sip_contact_t nr_dcontact[1];	/**< Contact in dialog */
131
  sip_via_t *nr_via;		/**< Corresponding Via headers */
132

133 134
  unsigned long nr_min_expires;	/**< Value from 423 negotiation */

135 136
  /** Status of registration */
  unsigned nr_ready:1;
137

138 139 140 141 142 143 144 145 146
  /** Kind of registration.
   *
   * If nr_default is true, this is not a real registration but placeholder
   * for Contact header derived from a transport address.
   *
   * If nr_secure is true, this registration supports SIPS/TLS.
   *
   * If nr_public is true, transport should have public address.
   */
147
  unsigned nr_default:1, nr_secure:1, nr_public:1, nr_ip4:1, nr_ip6:1;
148

149
  /** Stack-generated contact */
150 151 152
  unsigned nr_by_stack:1;

  unsigned:0;
153

154
  int nr_error_report_id;	/**< ID used to ask for error reports from tport */
155

156 157
  sip_route_t *nr_route;	/**< Outgoing Service-Route */
  sip_path_t *nr_path;		/**< Incoming Path */
158

159 160
  tport_t *nr_tport;		/**< Transport to be used when registered */
  nua_dialog_state_t *nr_dialogs; /**< List of our dialogs */
161

162 163 164
#if HAVE_SIGCOMP
  struct sigcomp_compartment *nr_compartment;
#endif
165

166 167
  outbound_t *nr_ob;	/**< Outbound connection */
};
168

169 170 171 172 173 174 175
nua_usage_class const nua_register_usage[1] = {
  {
    sizeof (struct register_usage),
    (sizeof nua_register_usage),
    nua_register_usage_add,
    nua_register_usage_remove,
    nua_register_usage_name,
176
    nua_register_usage_update_params,
177
    nua_register_usage_peer_info,
178 179
    nua_register_usage_refresh,
    nua_register_usage_shutdown
180
  }};
181

182 183 184 185
static char const *nua_register_usage_name(nua_dialog_usage_t const *du)
{
  return "register";
}
186

187 188 189 190
static int nua_register_usage_add(nua_handle_t *nh,
				  nua_dialog_state_t *ds,
				  nua_dialog_usage_t *du)
{
191
  nua_registration_t *nr = NUA_DIALOG_USAGE_PRIVATE(du);
192

193 194
  if (ds->ds_has_register)
    return -1;			/* There can be only one usage */
195

196
  ds->ds_has_register = 1;
197

198
  nr->nr_public = 1;		/* */
199

200 201
  return 0;
}
202

203

204 205
static void nua_register_usage_remove(nua_handle_t *nh,
				      nua_dialog_state_t *ds,
206 207 208
				      nua_dialog_usage_t *du,
				      nua_client_request_t *cr,
				      nua_server_request_t *sr)
209
{
210
  nua_registration_t *nr = NUA_DIALOG_USAGE_PRIVATE(du);
211

212 213 214 215 216
  if (nr->nr_list)
    nua_registration_remove(nr);	/* Remove from list of registrations */

  if (nr->nr_ob)
    outbound_unref(nr->nr_ob);
217

218
#if HAVE_SIGCOMP
219 220 221
  if (nr->nr_compartment)
    sigcomp_compartment_unref(nr->nr_compartment);
  nr->nr_compartment = NULL;
222
#endif
223

224 225 226 227 228 229
  if (nr->nr_error_report_id)
    tport_release(nr->nr_tport, nr->nr_error_report_id, NULL, NULL, nr, 0);

  if (nr->nr_tport)
    tport_unref(nr->nr_tport), nr->nr_tport = NULL;

230 231 232 233 234 235 236 237 238
  ds->ds_has_register = 0;	/* There can be only one */
}


/** @internal Store information about registrar. */
static void nua_register_usage_peer_info(nua_dialog_usage_t *du,
					 nua_dialog_state_t const *ds,
					 sip_t const *sip)
{
239
  nua_registration_t *nr = NUA_DIALOG_USAGE_PRIVATE(du);
240 241 242
  if (nr->nr_ob)
    outbound_peer_info(nr->nr_ob, sip);
}
243

244 245 246
/* ======================================================================== */
/* REGISTER */

247 248 249 250 251 252
static void nua_register_connection_closed(tp_stack_t *sip_stack,
					   nua_registration_t *nr,
					   tport_t *tport,
					   msg_t *msg,
					   int error);

253
/* Interface towards outbound_t */
254 255
sip_contact_t *nua_handle_contact_by_via(nua_handle_t *nh,
					 su_home_t *home,
256
					 int in_dialog,
257 258 259 260 261
					 sip_via_t const *v,
					 char const *transport,
					 char const *m_param,
					 ...);

262 263
static int nua_stack_outbound_refresh(nua_handle_t *,
				      outbound_t *ob);
264

265 266
static int nua_stack_outbound_status(nua_handle_t *,
				     outbound_t *ob,
267 268 269
				     int status, char const *phrase,
				     tag_type_t tag, tag_value_t value, ...);

270 271
static int nua_stack_outbound_failed(nua_handle_t *,
				     outbound_t *ob,
272 273 274
				     int status, char const *phrase,
				     tag_type_t tag, tag_value_t value, ...);

275
static int nua_stack_outbound_credentials(nua_handle_t *, auth_client_t **auc);
276

277 278
outbound_owner_vtable nua_stack_outbound_callbacks = {
    sizeof nua_stack_outbound_callbacks,
279 280 281 282 283 284
    /* oo_contact */ nua_handle_contact_by_via,
    /* oo_refresh */ nua_stack_outbound_refresh,
    /* oo_status */  nua_stack_outbound_status,
    /* oo_probe_error */     nua_stack_outbound_failed,
    /* oo_keepalive_error */ nua_stack_outbound_failed,
    /* oo_credentials */     nua_stack_outbound_credentials
285 286
  };

287
/**@fn void nua_register(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
288 289
 *
 * Send SIP REGISTER request to the registrar.
290 291 292 293 294 295 296 297 298 299 300 301 302
 *
 * Request status will be delivered to the application using #nua_r_register
 * event. When successful the registration will be updated periodically.
 *
 * The handle used for registration cannot be used for any other purposes.
 *
 * @param nh              Pointer to operation handle
 * @param tag, value, ... List of tagged parameters
 *
 * @return
 *     nothing
 *
 * @par Related tags:
303
 *     NUTAG_REGISTRAR(), NUTAG_INSTANCE(), NUTAG_OUTBOUND(),
304
 *     NUTAG_KEEPALIVE(), NUTAG_KEEPALIVE_STREAM(), NUTAG_M_USERNAME(),
Pekka Pessi's avatar
Pekka Pessi committed
305
 *     NUTAG_M_DISPLAY(), NUTAG_M_PARAMS(), NUTAG_M_FEATURES()
306 307 308
 *
 * @par Events:
 *     #nua_r_register, #nua_i_outbound
309
 *
310 311 312 313 314 315 316
 * @par Generating Contact Header
 *
 * If the application did not specify the Contact header in the tags,
 * nua_register() will generate one. It will obtain the schema, IP address
 * for the host and port number for the Contact URI from the transport
 * socket. The diplay name is taken from NUTAG_M_DISPLAY(), URL username
 * part is taken from NUTAG_M_USERNAME(), URI parameters from
317
 * NUTAG_M_PARAMS(), and Contact header parameters from NUTAG_M_FEATURES().
318 319
 * If NUTAG_CALLEE_CAPS(1) is specified, additional Contact header
 * parameters are generated based on SDP capabilities and SIP @Allow header.
320
 *
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
 * Note that @b nua may append a identifier of its own to the @Contact URI
 * username. Such nua-generated identifier trailer always starts with "="
 * (equal sign), rest of the nua-generated identifier may contain any
 * url-unreserved characters except "=".
 *
 * Likewise, nua may add transport parameters (such as "transport=tcp" or
 * "maddr") to the @Contact URI. It can add addtional header parameters, like
 * "+sip.instance" or "reg-id", too.
 *
 * For instance, if application uses tags like
 * @code
 *   nua_register(nh,
 *                NUTAG_M_DISPLAY("1"),
 *                NUTAG_M_USERNAME("line-1"),
 *                NUTAG_M_PARAMS("user=phone"),
 *                NUTAG_M_FEATURES("audio"),
 *                NUTAG_CALLEE_CAPS(0),
 *                TAG_END())
 * @endcode
 * @b nua can generate a Contact header like
 * @code
 * Contact: 1 <sip:line-1=SSQAIbjv@192.168.1.200;transport=tcp;user=phone>
 *   ;audio;reg-id=1
 *   ;+sip.instance=urn:uuid:97701ad9-39df-1229-1083-dbc0a85f029c
 * @endcode
 *
 * The incoming request from the proxy should contain the registered contact
 * URI as the request URI. The application can use the username prefix set
 * by NUTAG_M_USERNAME() and the non-transport parameters of the request URI
 * set by NUTAG_M_PARAMS() when determining to which registration the
 * incoming request belongs.
352
 *
353 354 355 356 357 358 359 360
 * For example, a request line correspoding to the @Contact in above example
 * may look like:
 * @code
 * INVITE sip:line-1=SSQAIbjv@192.168.1.200;user=phone SIP/2.0
 * @endcode
 *
 * @sa NUTAG_M_DISPLAY(), NUTAG_M_USERNAME(), NUTAG_M_PARAMS(),
 * NUTAG_M_FEATURES(), NUTAG_CALLEE_CAPS().
361 362 363
 *
 * @par NAT, Firewall and Outbound Support
 *
364 365
 * Normally, @b nua will start start a protocol engine for outbound
 * connections used for NAT and firewall traversal and connectivity checks
366
 * when registering.
367
 *
368 369 370 371
 * @note If the application provides @b nua with a
 * @Contact header of its own (or includes a SIPTAG_CONTACT(NULL) tag in
 * nua_register() tags), the outbound protocol engine is not started. It is
 * assumed that the application knows better what it is doing when it sets
372
 * the @Contact, or it is using experimental CPL upload as specified in
373 374 375
 * <a href="http://www.ietf.org/internet-drafts/draft-lennox-sip-reg-payload-01.txt">
 * draft-lennox-sip-reg-payload-01.txt</a>.
 *
376
 * First, outbound engine will probe for NATs in between UA and registrar.
377 378 379 380 381 382
 * It will send a REGISTER request as usual. Upon receiving the response it
 * checks for the presence of "received" and "rport" parameters in the Via
 * header returned by registrar. The presence of NAT is determined from the
 * "received" parameter in a Via header. When a REGISTER request was sent,
 * the stack inserted the actual source IP address in the Via header: if
 * that is different from the source IP address seen by the registrar, the
383 384 385 386 387 388 389
 * registrar inserts the source IP address it sees into the "received"
 * parameter.
 *
 * Please note that an ALG (application-level gateway) modifying the Via
 * headers in outbound requests and again in incoming responses will make
 * the above-described NAT check to fail.
 *
390 391
 * The response to the initial REGISTER should also include option tags
 * indicating whether registrar supports various SIP extension options: @e
392 393 394 395 396 397 398 399 400 401 402 403 404 405
 * outbound, @e pref, @e path, @e gruu.
 *
 * Basically, @e outbound means that instead of registering its contact URI
 * with a particular address-of-record URI, the user-agent registers a
 * transport-level connection. Such a connection is identified on the
 * Contact header field with an instance identifier, application-provided
 * @ref NUTAG_INSTANCE() "unique string" identifying the user-agent instance
 * and a stack-generated numeric index identifying the transport-level
 * connection.
 *
 * If the @e outbound extension is supported, NUTAG_OUTBOUND() contains
 * option string "outbound" and the application has provided an instance
 * identifer to the stack with NUTAG_INSTANCE(), the nua_register() will try
 * to use outbound.
406 407 408 409 410 411 412 413 414
 *
 * If @e outbound is not supported, nua_register() has to generate a URI
 * that can be used to reach it from outside. It will check for public
 * transport addresses detected by underlying stack with, e.g., STUN, UPnP
 * or SOCKS. If there are public addresses, nua_register() will use them. If
 * there is no public address, it will try to generate a Contact URI from
 * the "received" and "rport" parameters found in the Via header of the
 * response message.
 *
415 416 417 418
 * @todo Actually generate public addresses.
 *
 * You can disable this kind of NAT traversal by setting "no-natify" into
 * NUTAG_OUTBOUND() options string.
419
 *
420 421 422 423 424 425
 * @par GRUU and Service-Route
 *
 * After a successful response to the REGISTER request has been received,
 * nua_register() will update the information about the registration based
 * on it. If there is a "gruu" parameter included in the response,
 * nua_register() will save it and use the gruu URI in the Contact header
426
 * fields of dialog-establishing messages, such as INVITE or SUBSCRIBE.
427 428 429 430 431 432 433 434 435 436 437 438 439 440
 * Also, if the registrar has included a Service-Route header in the
 * response, and the service route feature has not been disabled using
 * NUTAG_SERVICE_ROUTE_ENABLE(), the route URIs from the Service-Route
 * header will be used for initial non-REGISTER requests.
 *
 * The #nua_r_register message will include the contact header and route
 * used in with the registration.
 *
 * @par Registration Keep-Alive
 *
 * After the registration has successfully completed the nua_register() will
 * validate the registration and initiate the keepalive mechanism, too. The
 * user-agent validates the registration by sending a OPTIONS requests to
 * itself. If there is an error, nua_register() will indicate that to the
441
 * application using #nua_i_outbound event, and start unregistration
442 443
 * procedure (unless that has been explicitly disabled).
 *
444 445 446
 * You can disable validation by inserting "no-validate" into
 * NUTAG_OUTBOUND() string.
 *
447 448
 * The keepalive mechanism depends on the network features detected earlier.
 * If @a outbound extension is used, the STUN keepalives will be used.
449 450
 * Otherwise, NUA stack will repeatedly send OPTIONS requests to itself. In
 * order to save bandwidth, it will include Max-Forwards: 0 in the
451 452 453 454 455 456 457 458 459 460 461 462
 * keep-alive requests, however. The keepalive interval is determined by
 * NUTAG_KEEPALIVE() parameter. If the interval is 0, no keepalive messages
 * is sent.
 *
 * You can disable keepalive OPTIONS by inserting "no-options-keepalive"
 * into NUTAG_OUTBOUND() string. Currently there are no other keepalive
 * mechanisms available.
 *
 * The value of NUTAG_KEEPALIVE_STREAM(), if specified, is used to indicate
 * the desired transport-layer keepalive interval for stream-based
 * transports like TLS and TCP.
 *
463 464
 * As alternative to OPTIONS/STUN keepalives, the client can propose
 * a more frequent registration refresh interval with
465
 * NUTAG_M_FEATURES() (e.g. NUTAG_M_FEATURES("expires=120") given as
466
 * parameter to nua_register()).
467 468
 *
 * @sa #nua_r_register, nua_unregister(), #nua_r_unregister,
469 470 471 472 473
 * #nua_i_register,
 * @RFC3261 section 10,
 * @Expires, @Contact, @CallID, @CSeq,
 * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680,
 *     NUTAG_REGISTRAR(), NUTAG_INSTANCE(), NUTAG_OUTBOUND(),
474
 *     NUTAG_KEEPALIVE(), NUTAG_KEEPALIVE_STREAM(),
475
 *     SIPTAG_CONTACT(), SIPTAG_CONTACT_STR(), NUTAG_M_USERNAME(),
476
 *     NUTAG_M_DISPLAY(), NUTAG_M_PARAMS(), NUTAG_M_FEATURES(),
477 478
 */

479
/** @NUA_EVENT nua_r_register
480
 *
481
 * Response to an outgoing REGISTER.
482 483
 *
 * The REGISTER may be sent explicitly by nua_register() or implicitly by
484 485
 * NUA state machines.
 *
486 487
 * When REGISTER request has been restarted the @a status may be 100 even
 * while the real response status returned is different.
488
 *
489 490 491 492 493
 * @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
494
 * @param nh     operation handle associated with the registration
495
 * @param hmagic application context associated with the registration
496
 * @param sip    response message to REGISTER request or NULL upon an error
497
 *               (status code is in @a status and
498
 *                descriptive message in @a phrase parameters)
499
 * @param tags   empty
500 501 502 503
 *
 * @sa nua_register(), nua_unregister(), #nua_r_unregister,
 * @Contact, @CallID, @CSeq, @RFC3261 section 10,
 * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680
504
 *
505
 * @END_NUA_EVENT
506 507 508
 */

/**@fn void nua_unregister(nua_handle_t *nh, tag_type_t tag, tag_value_t value, ...);
509
 * Unregister.
510
 *
511 512 513
 * Send a REGISTER request with expiration time 0. This removes the
 * registration from the registrar. If the handle was earlier used
 * with nua_register() the periodic updates will be terminated.
514 515 516 517 518 519 520 521 522 523 524 525 526
 *
 * If a SIPTAG_CONTACT_STR() with argument "*" is used, all the
 * registrations will be removed from the registrar otherwise only the
 * contact address belonging to the NUA stack is removed.
 *
 * @param nh              Pointer to operation handle
 * @param tag, value, ... List of tagged parameters
 *
 * @return
 *     nothing
 *
 * @par Related tags:
 *     NUTAG_REGISTRAR() \n
527
 *     Header tags defined in <sofia-sip/sip_tag.h> except SIPTAG_EXPIRES() or SIPTAG_EXPIRES_STR()
528 529 530
 *
 * @par Events:
 *     #nua_r_unregister
531 532 533 534 535 536
 *
 * @sa nua_register(), #nua_r_register, nua_handle_destroy(), nua_shutdown(),
 * #nua_i_register,
 * @Expires, @Contact, @CallID, @CSeq, @RFC3261 section 10,
 * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680,
 *     NUTAG_REGISTRAR(), NUTAG_INSTANCE(), NUTAG_OUTBOUND(),
537
 *     NUTAG_KEEPALIVE(), NUTAG_KEEPALIVE_STREAM(),
538
 *     SIPTAG_CONTACT(), SIPTAG_CONTACT_STR(), NUTAG_M_USERNAME(),
539
 *     NUTAG_M_DISPLAY(), NUTAG_M_PARAMS(), NUTAG_M_FEATURES(),
540 541
 */

542
/** @NUA_EVENT nua_r_unregister
543 544 545
 *
 * Answer to outgoing un-REGISTER.
 *
546 547 548 549 550
 * @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
551
 * @param nh     operation handle associated with the registration
552
 * @param hmagic application context associated with the registration
553
 * @param sip    response message to REGISTER request or NULL upon an error
554
 *               (status code is in @a status and
555
 *                descriptive message in @a phrase parameters)
556
 * @param tags   empty
557 558 559 560
 *
 * @sa nua_unregister(), nua_register(), #nua_r_register,
 * @Contact, @CallID, @CSeq, @RFC3261 section 10,
 * @Path, @RFC3327, @ServiceRoute, @RFC3608, @RFC3680
561
 *
562
 * @END_NUA_EVENT
563 564
 */

565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
static int nua_register_client_template(nua_client_request_t *cr,
					msg_t **return_msg,
					tagi_t const *tags);
static int nua_register_client_init(nua_client_request_t *cr,
				    msg_t *, sip_t *,
				    tagi_t const *tags);
static int nua_register_client_request(nua_client_request_t *cr,
				       msg_t *, sip_t *,
				       tagi_t const *tags);
static int nua_register_client_check_restart(nua_client_request_t *cr,
					     int status, char const *phrase,
					     sip_t const *sip);
static int nua_register_client_response(nua_client_request_t *cr,
					int status, char const *phrase,
					sip_t const *sip);

581
static nua_client_methods_t const nua_register_client_methods = {
582 583 584
  SIP_METHOD_REGISTER,		/* crm_method, crm_method_name */
  0,				/* crm_extra */
  {				/* crm_flags */
585 586 587 588
    /* create_dialog */ 1,
    /* in_dialog */ 0,
    /* target refresh */ 0
  },
589 590 591 592 593 594 595 596
  nua_register_client_template,	/* crm_template */
  nua_register_client_init,	/* crm_init */
  nua_register_client_request,	/* crm_send */
  nua_register_client_check_restart, /* crm_check_restart */
  nua_register_client_response,	/* crm_recv */
  NULL,				/* crm_preliminary */
  NULL,				/* crm_report */
  NULL,				/* crm_complete */
597 598 599 600 601 602 603 604 605 606 607 608 609 610
};

/**@internal Send REGISTER. */
int nua_stack_register(nua_t *nua,
		       nua_handle_t *nh,
		       nua_event_t e,
		       tagi_t const *tags)
{
  return nua_client_create(nh, e, &nua_register_client_methods, tags);
}

static int nua_register_client_template(nua_client_request_t *cr,
					msg_t **return_msg,
					tagi_t const *tags)
611 612 613
{
  nua_dialog_usage_t *du;

614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
  if (cr->cr_event == nua_r_register)
    return 0;

  /* Use a copy of REGISTER message as the template for un-REGISTER */
  du = nua_dialog_usage_get(cr->cr_owner->nh_ds, nua_register_usage, NULL);
  if (du && du->du_cr) {
    if (nua_client_set_target(cr, du->du_cr->cr_target) < 0)
      return -1;
    *return_msg = msg_copy(du->du_cr->cr_msg);
    return 1;
  }

  return 0;
}

static int nua_register_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_registration_t *nr;
  sip_to_t const *aor = sip->sip_to;

  int unreg;
639

640 641 642 643 644 645 646 647
  /* Explicit empty (NULL) contact - used for CPL store/remove? */
  if (!sip->sip_contact && cr->cr_has_contact)
    /* Do not create any usage */
    return 0;

  unreg = cr->cr_event != nua_r_register ||
    (sip->sip_expires && sip->sip_expires->ex_delta == 0);
  if (unreg)
648
    nua_client_set_terminating(cr, 1);
649

650
  du = nua_dialog_usage_add(nh, nh->nh_ds, nua_register_usage, NULL);
651 652 653 654 655 656
  if (du == NULL)
    return -1;
  nr = nua_dialog_usage_private(du);

  if (nua_client_bind(cr, du) < 0)
    return -1;
657

658 659
  if (!nr->nr_list) {
    nua_registration_add(&nh->nh_nua->nua_registrations, nr);
660

661 662 663 664 665 666 667 668
    if (aor == NULL)
      aor = sip->sip_from;
    if (aor == NULL)
      aor = nh->nh_nua->nua_from;

    if (nua_registration_set_aor(nh->nh_home, nr, aor) < 0)
      return -1;
  }
669

670 671
  if (nua_registration_set_contact(nh, nr, sip->sip_contact, unreg) < 0)
    return -1;
672

673 674 675 676 677 678 679
  if (!nr->nr_ob && (NH_PGET(nh, outbound) || NH_PGET(nh, instance))) {
    nr->nr_ob = outbound_new(nh, &nua_stack_outbound_callbacks,
			     nh->nh_nua->nua_root,
			     nh->nh_nua->nua_nta,
			     NH_PGET(nh, instance));
    if (!nr->nr_ob)
      return nua_client_return(cr, 900, "Cannot create outbound", msg);
680 681 682 683 684

    nua_register_usage_update_params(du,
				     NULL,
				     nh->nh_prefs,
				     nh->nh_dprefs);
685
  }
686

687 688 689 690 691 692 693 694
  if (nr->nr_ob) {
    outbound_t *ob = nr->nr_ob;
    sip_contact_t *m;

    if (!unreg && sip->sip_contact) {
      for (m = sip->sip_contact; m; m = m->m_next)
	if (!m->m_expires || strtoul(m->m_expires, NULL, 10) != 0)
	  break;
695

696 697 698 699 700 701
      if (m == NULL)
	unreg = 1;	/* All contacts have expires=0 */
    }

    if (outbound_set_contact(ob, sip->sip_contact, nr->nr_via, unreg) < 0)
      return nua_client_return(cr, 900, "Cannot set outbound contact", msg);
702 703
  }

704
  return 0;
705 706
}

707 708 709 710
static
int nua_register_client_request(nua_client_request_t *cr,
				msg_t *msg, sip_t *sip,
				tagi_t const *tags)
711
{
712
  nua_handle_t *nh = cr->cr_owner;
713
  nua_dialog_usage_t *du = cr->cr_usage;
714
  nua_registration_t *nr;
715 716
  sip_contact_t *m, *contacts = sip->sip_contact;
  char const *min_expires = NULL;
717
  int unreg;
718
  tport_t *tport = NULL;
719 720 721 722 723 724 725 726 727

  (void)nh;

  /* Explicit empty (NULL) contact - used for CPL store/remove? */
  if (!contacts && cr->cr_has_contact)
    return nua_base_client_request(cr, msg, sip, tags);

  if ((du && du->du_shutdown) ||
      (sip->sip_expires && sip->sip_expires->ex_delta == 0))
728
    nua_client_set_terminating(cr, 1);
729 730 731 732 733 734 735 736

  if (contacts) {
    if (!cr->cr_terminating) {
      for (m = contacts; m; m = m->m_next)
	if (!m->m_expires || strtoul(m->m_expires, NULL, 10) != 0)
	  break;
      /* All contacts have expires=0 */
      if (m == NULL)
737
	nua_client_set_terminating(cr, 1);
738 739
    }
  }
740

741
  unreg = cr->cr_terminating;
742

743
  nr = nua_dialog_usage_private(du);
744

745
  if (nr) {
746 747 748 749
    if (nr->nr_ob) {
      outbound_stop_keepalive(nr->nr_ob);
      outbound_start_registering(nr->nr_ob);
    }
750

751
    if (nr->nr_by_stack) {
752 753
      sip_contact_t *m = nr->nr_contact, *previous = NULL;

754
      outbound_get_contacts(nr->nr_ob, &m, &previous);
755 756

      sip_add_dup(msg, sip, (sip_header_t *)m);
757
      /* previous is an outdated contact generated by stack
758 759 760 761
       * and it is now unregistered */
      if (previous)
	sip_add_dup(msg, sip, (sip_header_t *)previous);
    }
762 763

    tport = nr->nr_tport;
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
  }

  for (m = sip->sip_contact; m; m = m->m_next) {
    if (m->m_url->url_type == url_any) {
      /* If there is a '*' in contact list, remove everything else */
      while (m != sip->sip_contact)
	sip_header_remove(msg, sip, (sip_header_t *)sip->sip_contact);
      while (m->m_next)
	sip_header_remove(msg, sip, (sip_header_t *)m->m_next);
      contacts = m;
      break;
    }

    if (!m->m_expires)
      continue;
    if (unreg) {
      /* Remove the expire parameters from contacts */
      msg_header_remove_param(m->m_common, "expires");
    }
783 784 785 786 787 788 789 790
    else if (nr && nr->nr_min_expires) {
      unsigned long exp = strtoul(m->m_expires, 0, 10);
      if (exp != 0 && exp < nr->nr_min_expires) {
        if (min_expires == NULL)
          min_expires = su_sprintf(msg_home(msg), "expires=%lu",
                                   nr->nr_min_expires);
        msg_header_replace_param(msg_home(msg), m->m_common, min_expires);
      }
791 792
    }
  }
793

794 795 796 797 798 799
  return nua_base_client_trequest(cr, msg, sip,
				  TAG_IF(unreg, SIPTAG_EXPIRES_STR("0")),
#if 0
				  TAG_IF(unreg, NTATAG_SIGCOMP_CLOSE(1)),
				  TAG_IF(!unreg, NTATAG_COMP("sigcomp")),
#endif
800
				  NTATAG_TPORT(tport),
801
				  TAG_NEXT(tags));
802
}
803

804 805 806
static int nua_register_client_check_restart(nua_client_request_t *cr,
					     int status, char const *phrase,
					     sip_t const *sip)
807
{
808 809 810 811 812 813 814
  nua_registration_t *nr = nua_dialog_usage_private(cr->cr_usage);
  unsigned short retry_count = cr->cr_retry_count;
  int restart = 0, retry;

  if (nr && nr->nr_ob) {
    msg_t *_reqmsg = nta_outgoing_getrequest(cr->cr_orq);
    sip_t *req = sip_object(_reqmsg); msg_destroy(_reqmsg);
815

816 817
    retry = outbound_register_response(nr->nr_ob, cr->cr_terminating,
				       req, sip);
818

819
    restart = retry >= ob_reregister_now;
820

821 822 823 824 825
    if (retry == ob_reregister)
      /* outbound restarts REGISTER later */;

    if (retry < 0)
      /* XXX - report an error? */;
826
  }
827

828 829 830 831 832
  if (nr && status == 423) {
    if (sip->sip_min_expires)
      nr->nr_min_expires = sip->sip_min_expires->me_delta;
  }

833 834 835
  /* Check for status-specific reasons to retry */
  if (nua_base_client_check_restart(cr, status, phrase, sip))
    return 1;
836

837 838
  /* Restart only if nua_base_client_check_restart() did not try to restart */
  if (restart && retry_count == cr->cr_retry_count)
839
    return nua_client_restart(cr, 100, "Outbound NAT Detected");
840

841
  return 0;
842 843
}

844 845 846
static int nua_register_client_response(nua_client_request_t *cr,
					int status, char const *phrase,
					sip_t const *sip)
847
{
848 849
  nua_handle_t *nh = cr->cr_owner;
  nua_dialog_usage_t *du = cr->cr_usage;
850
  nua_registration_t *nr = nua_dialog_usage_private(du);
851
  int ready;
852

853
  ready = du && !cr->cr_terminated && status < 300;
854

855 856 857
  if (ready) {
    sip_time_t mindelta = 0;
    sip_time_t now = sip_now(), delta, reqdelta, mdelta;
858

859
    sip_contact_t const *m, *sent;
860

861 862 863
    msg_t *_reqmsg = nta_outgoing_getrequest(cr->cr_orq);
    sip_t *req = sip_object(_reqmsg);

864 865
    tport_t *tport;

866 867
    msg_destroy(_reqmsg);

868
    assert(nr); assert(sip); assert(req);
869

870 871 872 873 874 875 876 877
#if HAVE_SIGCOMP
    {
      struct sigcomp_compartment *cc;
      cc = nta_outgoing_compartment(cr->cr_orq);
      sigcomp_compartment_unref(nr->nr_compartment);
      nr->nr_compartment = cc;
    }
#endif
878

879
    /* XXX - if store/remove, remove
880 881 882 883
       Content-Disposition
       Content-Type
       body
    */
884

885 886
    /** Search for lowest delta of SIP contacts we tried to register */
    mindelta = SIP_TIME_MAX;
887

888
    reqdelta = req->sip_expires ? req->sip_expires->ex_delta : 0;
889

890
    for (m = sip->sip_contact; m; m = m->m_next) {
891
      if (m->m_url->url_type != url_sip &&
892 893
	  m->m_url->url_type != url_sips)
	continue;
894

895 896 897 898 899 900 901 902 903 904 905
      for (sent = req->sip_contact; sent; sent = sent->m_next) {
	if (url_cmp(m->m_url, sent->m_url))
	  continue;

	if (sent->m_expires)
	  mdelta = strtoul(sent->m_expires, NULL, 10);
	else
	  mdelta = reqdelta;

	if (mdelta == 0)
	  mdelta = 3600;
906

907 908 909 910 911 912 913
	delta = sip_contact_expires(m, sip->sip_expires, sip->sip_date,
				    mdelta, now);
	if (delta > 0 && delta < mindelta)
	  mindelta = delta;

	if (url_cmp_all(m->m_url, sent->m_url) == 0)
	  break;
914
      }
915
    }
916

917 918 919
    if (mindelta == SIP_TIME_MAX)
      mindelta = 3600;

920
    nua_dialog_usage_set_refresh(du, mindelta);
921

922
  /*  RFC 3608 Section 6.1 Procedures at the UA
923 924 925 926 927 928 929 930 931 932 933 934 935 936 937

   The UA performs a registration as usual.  The REGISTER response may
   contain a Service-Route header field.  If so, the UA MAY store the
   value of the Service-Route header field in an association with the
   address-of-record for which the REGISTER transaction had registered a
   contact.  If the UA supports multiple addresses-of-record, it may be
   able to store multiple service routes, one per address-of-record.  If
   the UA refreshes the registration, the stored value of the Service-
   Route is updated according to the Service-Route header field of the
   latest 200 class response.  If there is no Service-Route header field
   in the response, the UA clears any service route for that address-
   of-record previously stored by the UA.  If the re-registration
   request is refused or if an existing registration expires and the UA
   chooses not to re-register, the UA SHOULD discard any stored service
   route for that address-of-record.
938

939
  */
940 941
    su_free(nh->nh_home, nr->nr_route);
    nr->nr_route = sip_route_dup(nh->nh_home, sip->sip_service_route);
942

943 944 945 946
    {
      /* RFC 3327 */
      /* Store last URI in Path header */
      sip_path_t *path = sip->sip_path;
947

948 949
      while (path && path->r_next)
	path = path->r_next;
950

951 952 953 954 955
      if (!nr->nr_path || !path ||
	  url_cmp_all(nr->nr_path->r_url, path->r_url)) {
	su_free(nh->nh_home, nr->nr_path);
	nr->nr_path = sip_path_dup(nh->nh_home, path);
      }
956 957
    }

958
    if (sip->sip_to->a_url->url_type == url_sips)
959
      nr->nr_secure = 1;
960

961
    if (nr->nr_ob) {
962
      outbound_gruuize(nr->nr_ob, sip);
963
      outbound_start_keepalive(nr->nr_ob, cr->cr_orq);
964
    }
965

966 967 968 969 970 971 972 973 974 975 976 977 978 979
    tport = nta_outgoing_transport (cr->cr_orq);

    /* cache persistant connection for registration */
    if (tport && tport != nr->nr_tport) {
      if (nr->nr_error_report_id) {
	if (tport_release(nr->nr_tport, nr->nr_error_report_id, NULL, NULL, nr, 0) < 0)
	  SU_DEBUG_1(("nua_register: tport_release() failed\n"));
	nr->nr_error_report_id = 0;
      }
      tport_unref(nr->nr_tport);
      nr->nr_tport = tport;

      if (tport_is_secondary(tport)) {
	tport_set_params(tport, TPTAG_SDWN_ERROR(1), TAG_END());
980
	nr->nr_error_report_id =
981 982 983 984 985
	  tport_pend(tport, NULL, nua_register_connection_closed, nr);
      }
    }
    else
      tport_unref(tport);    /* note: nta_outgoing_transport() makes a ref */
986

987 988 989
    nua_registration_set_ready(nr, 1);
  }
  else if (du) {
990
    nua_dialog_usage_reset_refresh(du);
991 992 993 994 995 996

    su_free(nh->nh_home, nr->nr_route);
    nr->nr_route = NULL;

    outbound_stop_keepalive(nr->nr_ob);

997
    /* release the persistant transport for registration */
998 999 1000 1001 1002 1003
    if (nr->nr_tport) {
      if (nr->nr_error_report_id) {
	if (tport_release(nr->nr_tport, nr->nr_error_report_id, NULL, NULL, nr, 0) < 0)
	  SU_DEBUG_1(("nua_register: tport_release() failed\n"));
	nr->nr_error_report_id = 0;
      }
1004

1005 1006
      tport_unref(nr->nr_tport), nr->nr_tport = NULL;
    }
1007
    nua_registration_set_ready(nr, 0);
1008 1009 1010
  }


1011 1012 1013
  return nua_base_client_response(cr, status, phrase, sip, NULL);
}

1014 1015 1016 1017 1018 1019 1020
static
void nua_register_connection_closed(tp_stack_t *sip_stack,
				    nua_registration_t *nr,
				    tport_t *tport,
				    msg_t *msg,
				    int error)
{
1021
  nua_dialog_usage_t *du;
1022
  tp_name_t const *tpn;
1023
  int pending;
1024

1025 1026
  assert(nr && tport == nr->nr_tport);
  if (nr == NULL || tport != nr->nr_tport)
1027 1028
    return;

1029 1030 1031 1032
  du = NUA_DIALOG_USAGE_PUBLIC(nr);
  pending = nr->nr_error_report_id;

  if (tport_release(tport, pending, NULL, NULL, nr, 0) < 0)
1033
    SU_DEBUG_1(("nua_register: tport_release() failed\n"));
1034
  nr->nr_error_report_id = 0;
1035 1036 1037

  tpn = tport_name(nr->nr_tport);

1038
  SU_DEBUG_5(("nua_register(%p): tport to %s/%s:%s%s%s closed %s\n",
1039
		  (void *)du->du_dialog->ds_owner,
1040 1041 1042 1043 1044
	      tpn->tpn_proto, tpn->tpn_host, tpn->tpn_port,
	      tpn->tpn_comp ? ";comp=" : "",
	      tpn->tpn_comp ? tpn->tpn_comp : "",
	      error != 0 ? su_strerror(error) : ""));

1045 1046 1047
  tport_unref(nr->nr_tport), nr->nr_tport = NULL;

  /* Schedule re-REGISTER immediately */
Pekka Pessi's avatar
Pekka Pessi committed
1048
  nua_dialog_usage_set_refresh_range(du, 0, 0);
1049 1050
}

1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
static void
nua_register_usage_update_params(nua_dialog_usage_t const *du,
				 nua_handle_preferences_t const *changed,
				 nua_handle_preferences_t const *nhp,
				 nua_handle_preferences_t const *dnhp)
{
  nua_registration_t *nr = nua_dialog_usage_private(du);
  outbound_t *ob = nr->nr_ob;

  if (!ob)
    return;

  if (!changed ||
      NHP_ISSET(changed, outbound) ||
      NHP_ISSET(changed, keepalive) ||
      NHP_ISSET(changed, keepalive_stream)) {
    char const *outbound =
      NHP_ISSET(nhp, outbound) ? nhp->nhp_outbound
      : dnhp->nhp_outbound;
    unsigned keepalive =
      NHP_ISSET(nhp, keepalive) ? nhp->nhp_keepalive
      : dnhp->nhp_keepalive;
    unsigned keepalive_stream =
      NHP_ISSET(nhp, keepalive_stream) ? nhp->nhp_keepalive_stream
      : NHP_ISSET(dnhp, keepalive_stream) ? nhp->nhp_keepalive_stream
      : keepalive;

    outbound_set_options(ob, outbound, keepalive, keepalive_stream);
  }

  if (!changed || NHP_ISSET(changed, proxy)) {
    if (NHP_ISSET(nhp, proxy))
      outbound_set_proxy(ob, nhp->nhp_proxy);
  }
}

1087

1088 1089 1090 1091 1092
static void nua_register_usage_refresh(nua_handle_t *nh,
				       nua_dialog_state_t *ds,
				       nua_dialog_usage_t *du,
				       sip_time_t now)
{
1093
  nua_t *nua = nh->nh_nua;
1094 1095 1096
  nua_client_request_t *cr = du->du_cr;

  if (cr) {
1097
    if (nua_client_resend_request(cr, 0) >= 0)
1098 1099 1100 1101
      return;
  }

  /* Report that we have de-registered */
1102
  nua_stack_event(nua, nh, NULL, nua_r_register, NUA_ERROR_AT(__FILE__, __LINE__), NULL);
1103
  nua_dialog_usage_remove(nh, ds, du, NULL, NULL);
1104 1105 1106 1107 1108 1109 1110 1111 1112
}

/** @interal Shut down REGISTER usage.
 *
 * @retval >0  shutdown done
 * @retval 0   shutdown in progress
 * @retval <0  try again later
 */
static int nua_register_usage_shutdown(nua_handle_t *nh,
1113 1114
				       nua_dialog_state_t *ds,
				       nua_dialog_usage_t *du)
1115 1116
{
  nua_client_request_t *cr = du->du_cr;
1117
  nua_registration_t *nr = NUA_DIALOG_USAGE_PRIVATE(du);
1118 1119 1120 1121 1122

  if (cr) {
    if (nua_client_is_queued(cr)) /* Already registering. */
      return -1;
    cr->cr_event = nua_r_unregister;
1123
    if (nua_client_resend_request(cr, 1) >= 0)
1124 1125 1126
      return 0;
  }

1127 1128 1129 1130
  /* release the persistant transport for registration */
  if (nr->nr_tport)
    tport_decref(&nr->nr_tport), nr->nr_tport = NULL;

1131
  nua_dialog_usage_remove(nh, ds, du, NULL, NULL);
1132
  return 200;
1133
}
1134

1135
/* ---------------------------------------------------------------------- */
1136
/* nua_registration_t interface */
1137

1138 1139 1140 1141
#if HAVE_SOFIA_STUN
#include <sofia-sip/stun.h>
#endif

1142
static void nua_stack_tport_update(nua_t *nua, nta_agent_t *nta);
1143 1144
static int nua_registration_add_contact_and_route(nua_handle_t *nh,
						  nua_registration_t *nr,
1145 1146 1147 1148
						  msg_t *msg,
						  sip_t *sip,
						  int add_contact,
						  int add_service_route);
1149

1150
int
1151 1152 1153 1154 1155 1156 1157
nua_stack_init_transport(nua_t *nua, tagi_t const *tags)
{
  url_string_t const *contact1 = NULL, *contact2 = NULL;
  char const *name1 = "sip", *name2 = "sip";
  char const *certificate_dir = NULL;

  tl_gets(tags,
1158 1159 1160 1161
          NUTAG_URL_REF(contact1),
          NUTAG_SIPS_URL_REF(contact2),
          NUTAG_CERTIFICATE_DIR_REF(certificate_dir),
          TAG_END());
1162

1163 1164 1165
  if (!contact1 && contact2)
    contact1 = contact2, contact2 = NULL;

1166
  if (contact1 &&
1167
      (url_is_string(contact1)
1168
       ? su_casenmatch(contact1->us_str, "sips:", 5)
1169 1170 1171
       : contact1->us_url->url_type == url_sips))
    name1 = "sips";

1172 1173
  if (contact2 &&
      (url_is_string(contact2)
1174
       ? su_casenmatch(contact2->us_str, "sips:", 5)
1175 1176 1177
       : contact2->us_url->url_type == url_sips))
    name2 = "sips";

1178
  if (!contact1 /* && !contact2 */) {
1179
    if (nta_agent_add_tport(nua->nua_nta, NULL,
1180 1181 1182
			    TPTAG_IDENT("sip"),
			    TPTAG_CERTIFICATE(certificate_dir),
			    TAG_NEXT(nua->nua_args)) < 0 &&
1183
        nta_agent_add_tport(nua->nua_nta, URL_STRING_MAKE("sip:*:*"),
1184 1185 1186
			    TPTAG_IDENT("sip"),
			    TPTAG_CERTIFICATE(certificate_dir),
			    TAG_NEXT(nua->nua_args)) < 0)
1187
      return -1;
1188
#if HAVE_SOFIA_STUN
1189 1190 1191 1192 1193 1194 1195 1196
    if (stun_is_requested(TAG_NEXT(nua->nua_args)) &&
	nta_agent_add_tport(nua->nua_nta, URL_STRING_MAKE("sip:0.0.0.0:*"),
			    TPTAG_IDENT("stun"),
			    TPTAG_PUBLIC(tport_type_stun), /* use stun */
			    TPTAG_CERTIFICATE(certificate_dir),
			    TAG_NEXT(nua->nua_args)) < 0) {
      SU_DEBUG_0(("nua: error initializing STUN transport\n"));
    }
1197
#endif
1198
  }
1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209
  else {
    if (nta_agent_add_tport(nua->nua_nta, contact1,
			    TPTAG_IDENT(name1),
			    TPTAG_CERTIFICATE(certificate_dir),
			    TAG_NEXT(nua->nua_args)) < 0)
      return -1;

    if (contact2 &&
	nta_agent_add_tport(nua->nua_nta, contact2,
			    TPTAG_IDENT(name2),
			    TPTAG_CERTIFICATE(certificate_dir),
1210
			    TAG_NEXT(nua->nua_args)) < 0)
1211
      return -1;
1212 1213
  }

1214

1215 1216 1217 1218 1219 1220
  if (nua_stack_init_registrations(nua) < 0)
    return -1;

  return 0;
}

1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236
#if 0
  /* Store network detector param value */
  if (agent->sa_nw_updates == 0)
    agent->sa_nw_updates = nw_updates;
 	      NTATAG_DETECT_NETWORK_UPDATES_REF(nw_updates),
  unsigned nw_updates = 0;
  unsigned nw_updates = 0;

  su_network_changed_t *sa_nw_changed;

#endif

static
void nua_network_changed_cb(nua_t *nua, su_root_t *root)
{

1237 1238 1239
  uint32_t nw_updates;

  nw_updates = nua->nua_prefs->ngp_detect_network_updates;
1240 1241 1242

  switch (nw_updates) {
  case NUA_NW_DETECT_ONLY_INFO:
1243
    nua_stack_event(nua, NULL, NULL, nua_i_network_changed, SIP_200_OK, NULL);
1244
    break;
1245

1246 1247 1248 1249 1250
  case NUA_NW_DETECT_TRY_FULL:

    /* 1) Shutdown all tports */
    nta_agent_close_tports(nua->nua_nta);

1251
    /* 2) Create new tports */
1252 1253 1254
    if (nua_stack_init_transport(nua, nua->nua_args) < 0)
      /* We are hosed */
      nua_stack_event(nua, NULL, NULL, nua_i_network_changed,
1255
		      900, "Internal Error", NULL);
1256 1257
    else
      nua_stack_event(nua, NULL, NULL, nua_i_network_changed,
1258
		      SIP_200_OK, NULL);
1259 1260

    break;
1261

1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
  default:
    break;
  }

  return;
}

int nua_stack_launch_network_change_detector(nua_t *nua)
{
  su_network_changed_t *snc = NULL;

  snc = su_root_add_network_changed(nua->nua_home,
1274
				    nua->nua_root,
1275 1276
				    nua_network_changed_cb,
				    nua);
1277

1278 1279 1280 1281 1282 1283 1284 1285 1286
  if (!snc)
    return -1;

  nua->nua_nw_changed = snc;

  return 0;
}


1287 1288
int
nua_stack_init_registrations(nua_t *nua)
1289 1290
{
  /* Create initial identities: peer-to-peer, public, sips */
1291 1292
  nua_registration_t **nr_list = &nua->nua_registrations, **nr_next;
  nua_handle_t **nh_list;
1293
  nua_handle_t *dnh = nua->nua_dhandle;
1294
  sip_via_t const *v;
1295

1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308
  /* Remove existing, local address based registrations and count the
     rest */
  while (nr_list && *nr_list) {
    nr_next = &(*nr_list)->nr_next;
    if ((*nr_list)->nr_default == 1) {
      nua_registration_remove(*nr_list);
      /* memset(*nr_list, 170, sizeof(**nr_list)); */
      /* XXX - free, too */
    }
    nr_list = nr_next;
  }
  nr_list = &nua->nua_registrations;

1309 1310
  v = nta_agent_public_via(nua->nua_nta);
  if (v) {
1311
    nua_registration_from_via(nr_list, dnh, v, 1);
1312
  }
1313

1314 1315
  v = nta_agent_via(nua->nua_nta);
  if (v) {
1316
    nua_registration_from_via(nr_list, dnh, v, 0);
1317
  }
1318 1319
  else {
    sip_via_t v[2];
1320

1321 1322 1323 1324 1325 1326
    sip_via_init(v)->v_next = v + 1;
    v[0].v_protocol = sip_transport_udp;
    v[0].v_host = "addr.is.invalid.";
    sip_via_init(v + 1);
    v[1].v_protocol = sip_transport_tcp;
    v[1].v_host = "addr.is.invalid.";
1327

1328
    nua_registration_from_via(nr_list, dnh, v, 0);
1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341
  }

  /* Go through all the registrations and set to refresh almost
     immediately */
  nh_list = &nua->nua_handles;
  for (; *nh_list; nh_list = &(*nh_list)->nh_next) {
    nua_dialog_state_t *ds;
    nua_dialog_usage_t *du;

    ds = (*nh_list)->nh_ds;
    du = ds->ds_usage;

    if (ds->ds_has_register == 1 && du->du_class->usage_refresh) {
1342
      nua_dialog_usage_refresh(*nh_list, ds, du, 1);
1343
    }
1344 1345
  }

Michael Jerris's avatar
Michael Jerris committed
1346
  nta_agent_bind_tport_update(nua->nua_nta, (nta_update_magic_t *)nua, nua_stack_tport_update);
1347

1348 1349 1350
  return 0;
}

1351
int nua_registration_from_via(nua_registration_t **list,
1352
			      nua_handle_t *nh,
1353 1354
			      sip_via_t const *via,
			      int public)
1355
{
1356
  su_home_t *home = nh->nh_home;
1357 1358 1359
  sip_via_t *v, *pair, /* v2[2], */ *vias, **vv, **prev;
  nua_registration_t *nr = NULL, **next;
  su_home_t autohome[SU_HOME_AUTO_SIZE(1024)];
1360
  int nr_items = 0;
1361

1362
  vias = sip_via_copy(su_home_auto(autohome, sizeof autohome), via);
1363

1364
  for (; *list; list = &(*list)->nr_next)
1365
    ++nr_items;
1366

1367
  next = list;
1368

1369 1370