nta.c 312 KB
Newer Older
Pekka Pessi's avatar
Pekka Pessi committed
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) 2005 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 nta.c
Pekka Pessi's avatar
Pekka Pessi committed
26
 * @brief Sofia SIP Transaction API implementation
27
 *
Pekka Pessi's avatar
Pekka Pessi committed
28 29 30 31
 * This source file has been divided into sections as follows:
 * 1) agent
 * 2) tport handling
 * 3) dispatching messages received from network
32
 * 4) message creation and message utility functions
Pekka Pessi's avatar
Pekka Pessi committed
33 34 35 36 37 38
 * 5) stateless operation
 * 6) dialogs (legs)
 * 7) server transactions (incoming)
 * 8) client transactions (outgoing)
 * 9) resolving URLs for client transactions
 * 10) 100rel reliable responses (reliable)
Pekka Pessi's avatar
Pekka Pessi committed
39
 * 11) SigComp handling and public transport interface
40
 *
Pekka Pessi's avatar
Pekka Pessi committed
41
 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
42
 *
Pekka Pessi's avatar
Pekka Pessi committed
43
 * @date Created: Tue Jun 13 02:57:51 2000 ppessi
44 45 46
 *
 * @sa
 * @RFC3261, @RFC4320
Pekka Pessi's avatar
Pekka Pessi committed
47 48 49 50
 */

#include "config.h"

51
#include <sofia-sip/su_string.h>
Pekka Pessi's avatar
Pekka Pessi committed
52 53 54 55 56 57

/** @internal SU message argument structure type */
#define SU_MSG_ARG_T   union sm_arg_u
/** @internal SU timer argument pointer type */
#define SU_TIMER_ARG_T struct nta_agent_s

58 59 60
#include <sofia-sip/su_alloc.h>
#include <sofia-sip/su.h>
#include <sofia-sip/su_time.h>
61
#include <sofia-sip/su_wait.h>
62
#include <sofia-sip/su_tagarg.h>
Pekka Pessi's avatar
Pekka Pessi committed
63

64 65
#include <sofia-sip/base64.h>
#include <sofia-sip/su_uniqueid.h>
Pekka Pessi's avatar
Pekka Pessi committed
66

67 68 69 70
#include <sofia-sip/sip.h>
#include <sofia-sip/sip_header.h>
#include <sofia-sip/sip_util.h>
#include <sofia-sip/sip_status.h>
Pekka Pessi's avatar
Pekka Pessi committed
71

72
#include <sofia-sip/hostdomain.h>
73
#include <sofia-sip/url_tag.h>
74

75
#include <sofia-sip/msg_addr.h>
76
#include <sofia-sip/msg_parser.h>
Pekka Pessi's avatar
Pekka Pessi committed
77

78 79 80 81 82 83 84 85
/* Resolver context type */
#define SRES_CONTEXT_T    nta_outgoing_t

/* We are customer of tport_t */
#define TP_AGENT_T        nta_agent_t
#define TP_MAGIC_T        sip_via_t
#define TP_CLIENT_T       nta_outgoing_t

Pekka Pessi's avatar
Pekka Pessi committed
86 87
#include "nta_internal.h"

Pekka Pessi's avatar
Pekka Pessi committed
88 89 90 91 92 93 94 95
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <assert.h>
#include <limits.h>
#include <errno.h>

Pekka Pessi's avatar
Pekka Pessi committed
96 97 98
/* From AM_INIT/AC_INIT in our "config.h" */
char const nta_version[] = PACKAGE_VERSION;

Pekka Pessi's avatar
Pekka Pessi committed
99 100 101 102 103 104 105 106 107
#if HAVE_FUNC
#elif HAVE_FUNCTION
#define __func__ __FUNCTION__
#else
static char const __func__[] = "nta";
#endif

#define NONE ((void *)-1)

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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
/* ------------------------------------------------------------------------- */

/** Resolving order */
enum nta_res_order_e
{
  nta_res_ip6_ip4,
  nta_res_ip4_ip6,
  nta_res_ip6_only,
  nta_res_ip4_only
};

HTABLE_DECLARE_WITH(leg_htable, lht, nta_leg_t, size_t, hash_value_t);
HTABLE_DECLARE_WITH(outgoing_htable, oht, nta_outgoing_t, size_t, hash_value_t);
HTABLE_DECLARE_WITH(incoming_htable, iht, nta_incoming_t, size_t, hash_value_t);

typedef struct outgoing_queue_t {
  nta_outgoing_t **q_tail;
  nta_outgoing_t  *q_head;
  size_t           q_length;
  unsigned         q_timeout;
} outgoing_queue_t;

typedef struct incoming_queue_t {
  nta_incoming_t **q_tail;
  nta_incoming_t  *q_head;
  size_t           q_length;
  unsigned         q_timeout;
} incoming_queue_t;

struct nta_agent_s
{
  su_home_t             sa_home[1];
  su_root_t            *sa_root;
  su_timer_t           *sa_timer;
  nta_agent_magic_t    *sa_magic;
  nta_message_f        *sa_callback;

  nta_update_magic_t   *sa_update_magic;
  nta_update_tport_f   *sa_update_tport;

  su_time_t             sa_now;	 /**< Timestamp in microsecond resolution. */
  uint32_t              sa_next; /**< Timestamp for next agent_timer. */
  uint32_t              sa_millisec; /**< Timestamp in milliseconds. */

  msg_mclass_t const   *sa_mclass;
  uint32_t sa_flags;		/**< SIP message flags */
  unsigned sa_preload;		/**< Memory preload for SIP messages. */

  tport_t              *sa_tports;
  sip_contact_t        *sa_contact;
  sip_via_t            *sa_vias;   /**< @Via headers for all transports */
  sip_via_t            *sa_public_vias;   /**< @Vias for public transports */
  sip_contact_t        *sa_aliases;/**< List of aliases for agent */

  uint64_t              sa_branch; /**< Generator for branch parameters */
  uint64_t              sa_tags;   /**< Generator for tag parameters */

#if HAVE_SOFIA_SRESOLV
  sres_resolver_t      *sa_resolver; /**< DNS resolver */
  enum nta_res_order_e  sa_res_order;  /** Resolving order (AAAA/A) */
#endif

  url_t   *sa_default_proxy;	/**< Default outbound proxy */
  unsigned sa_bad_req_mask;     /**< Request error mask */
  unsigned sa_bad_resp_mask;	/**< Response error mask */
173 174
  usize_t  sa_maxsize;		/**< Maximum size of incoming messages */
  usize_t  sa_max_proceeding;	/**< Maximum size of proceeding queue */
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320

  unsigned sa_udp_mtu;		/**< Maximum size of outgoing UDP requests */

  unsigned sa_t1;  /**< SIP T1 - initial retransmit interval (500 ms) */
  unsigned sa_t2;  /**< SIP T2 - maximum retransmit interval (4000 ms) */
  unsigned sa_t4;  /**< SIP T4 - clear message time (5000 ms) */


  unsigned sa_t1x64; /**< SIP T1X64 - transaction lifetime (32 s) */

  unsigned sa_progress;		/**< Progress timer.
				   Interval between retransmitting
				   provisional responses. */

  unsigned sa_timer_c;		/**< SIP timer C.
				   Maximum interval between receiving
				   provisional responses. */

  unsigned sa_graylist;		/**< Graylisting period */
  unsigned sa_blacklist;	/**< Blacklisting period */

  unsigned sa_drop_prob : 10;	/**< NTA is used to test packet drop */
  unsigned sa_is_a_uas : 1;	/**< NTA is acting as an User Agent server */
  unsigned sa_is_stateless : 1;	/**< Process requests statelessly
				 *   unless they match existing dialog.
				 */
  unsigned sa_user_via:1;	/**< Let application provide @Via headers */
  unsigned sa_extra_100:1;	/**< Allow NTA to return "100 Trying" response
				 * even if application has not responded.
				 */
  unsigned sa_pass_100:1;	/**< Pass the "100 Trying"
				 * provisional responses to the application
				 */
  unsigned sa_timeout_408:1;	/**< A "408 Request Timeout" message
				 * is generated when outgoing request expires.
				 */
  unsigned sa_pass_408:1;	/**< A "408 Request Timeout" responses
				 * are passed to client.
				 */
  unsigned sa_merge_482 : 1;	/**< A "482 Request Merged" response is returned
				 * to merged requests.
				 */
  unsigned sa_cancel_2543 : 1;  /**< Send a CANCEL to an INVITE without
				 * waiting for an provisional response.
				 */
  unsigned sa_cancel_487 : 1;	/**< Return 487 response automatically when
				 * a CANCEL is received.
				 */

  unsigned sa_invite_100rel:1;	/**< Include 100rel in INVITE requests. */
  unsigned sa_timestamp : 1;	/**< Insert @Timestamp in requests. */

  unsigned sa_tport_ip4 : 1;	/**< Transports support IPv4. */
  unsigned sa_tport_ip6 : 1;	/**< Transports support IPv6. */
  unsigned sa_tport_udp : 1;	/**< Transports support UDP. */
  unsigned sa_tport_tcp : 1;	/**< Transports support TCP. */
  unsigned sa_tport_sctp : 1;	/**< Transports support SCTP. */
  unsigned sa_tport_tls : 1;	/**< Transports support TLS. */

  unsigned sa_use_naptr : 1;	/**< Use NAPTR lookup */
  unsigned sa_use_srv : 1;	/**< Use SRV lookup */

  unsigned sa_tport_threadpool:1; /**< Transports use threadpool */

  unsigned sa_rport:1;		/**< Use rport at client */
  unsigned sa_server_rport:2;	/**< Use rport at server */
  unsigned sa_tcp_rport:1;	/**< Use rport with tcp, too */
  unsigned sa_tls_rport:1;	/**< Use rport with tls, too */

  unsigned sa_auto_comp:1;	/**< Automatically create compartments */
  unsigned sa_in_timer:1;	/**< Set when executing timers */
  unsigned sa_use_timer_c:1;	/**< Application has set value for timer C */

  unsigned :0;

#if HAVE_SMIME
  sm_object_t          *sa_smime;
#else
  void                 *sa_smime;
#endif

  /** @MaxForwards */
  sip_max_forwards_t    sa_max_forwards[1];

  /** Name of SigComp algorithm */
  char const           *sa_algorithm;
  /** Options for SigComp. */
  char const           *sa_sigcomp_options;
  char const* const    *sa_sigcomp_option_list;
  char const           *sa_sigcomp_option_free;

  nta_compressor_t     *sa_compressor;

  /* Statistics */
  struct {
    usize_t as_recv_msg;
    usize_t as_recv_request;
    usize_t as_recv_response;
    usize_t as_bad_message;
    usize_t as_bad_request;
    usize_t as_bad_response;
    usize_t as_drop_request;
    usize_t as_drop_response;
    usize_t as_client_tr;
    usize_t as_server_tr;
    usize_t as_dialog_tr;
    usize_t as_acked_tr;
    usize_t as_canceled_tr;
    usize_t as_trless_request;
    usize_t as_trless_to_tr;
    usize_t as_trless_response;
    usize_t as_trless_200;
    usize_t as_merged_request;
    usize_t as_sent_msg;
    usize_t as_sent_request;
    usize_t as_sent_response;
    usize_t as_retry_request;
    usize_t as_retry_response;
    usize_t as_recv_retry;
    usize_t as_tout_request;
    usize_t as_tout_response;
  }                  sa_stats[1];

  /** Hash of dialogs. */
  leg_htable_t          sa_dialogs[1];
  /** Default leg */
  nta_leg_t            *sa_default_leg;
  /** Hash of legs without dialogs. */
  leg_htable_t          sa_defaults[1];
  /** Hash table for outgoing transactions */
  outgoing_htable_t     sa_outgoing[1];
  nta_outgoing_t       *sa_default_outgoing;
  /** Hash table for incoming transactions */
  incoming_htable_t     sa_incoming[1];
  nta_incoming_t       *sa_default_incoming;

  /* Queues (states) for outgoing client transactions */
  struct {
    /** Queue for retrying client transactions */
    nta_outgoing_t   *re_list;
    nta_outgoing_t  **re_t1;	        /**< Special place for T1 timer */
    size_t            re_length;	/**< Length of sa_out.re_list */

    outgoing_queue_t  delayed[1];
    outgoing_queue_t  resolving[1];

321
    outgoing_queue_t  trying[1];	/* Timer F / Timer E */
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 352 353 354 355 356 357 358 359 360 361 362 363 364 365
    outgoing_queue_t  completed[1];	/* Timer K */
    outgoing_queue_t  terminated[1];

    /* Special queues (states) for outgoing INVITE transactions */
    outgoing_queue_t  inv_calling[1];	/* Timer B/A */
    outgoing_queue_t  inv_proceeding[1]; /* Timer C */
    outgoing_queue_t  inv_completed[1];	/* Timer D */

    /* Temporary queue for transactions waiting to be freed */
    outgoing_queue_t *free;
  } sa_out;

  /* Queues (states) for incoming server transactions */
  struct {
    /** Queue for retransmitting response of server transactions */
    nta_incoming_t   *re_list;
    nta_incoming_t  **re_t1;	        /**< Special place for T1 timer */
    size_t            re_length;        /**< Length of sa_in.re_list */

    incoming_queue_t  proceeding[1];	/**< Request received */
    incoming_queue_t  preliminary[1];   /**< 100rel sent  */
    incoming_queue_t  completed[1];	/**< Final answer sent (non-invite). */
    incoming_queue_t  inv_completed[1];	/**< Final answer sent (INVITE). */
    incoming_queue_t  inv_confirmed[1];	/**< Final answer sent, ACK recvd. */
    incoming_queue_t  terminated[1];	/**< Terminated, ready to free. */
    incoming_queue_t  final_failed[1];
  } sa_in;

  /* Special task for freeing memory */
  su_clone_r          sa_terminator;
};

struct nta_leg_s
{
  su_home_t         leg_home[1];
  hash_value_t      leg_hash;

  unsigned leg_dialog : 1;
  unsigned leg_stateless : 1;   /**< Process requests statelessly */
#ifdef NTA_STRICT_ROUTING
  unsigned leg_contact_set : 1;
#else
  unsigned leg_loose_route : 1; /**< Topmost route in set is LR */
#endif
366
  unsigned leg_route_set : 1;	/**< Route set has been saved */
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
  unsigned leg_local_is_to : 1; /**< Backwards-compatibility. */
  unsigned leg_tagged : 1;	/**< Tagged after creation.
				 *
				 * Request missing @To tag matches
				 * a tagged leg even after tagging.
				 */
  unsigned:0;
  nta_request_f    *leg_callback;
  nta_leg_magic_t  *leg_magic;
  nta_agent_t      *leg_agent;

  url_t const      *leg_url;	/**< Match incoming requests. */
  char const       *leg_method;	/**< Match incoming requests. */

  uint32_t	    leg_seq;    /**< Sequence number for next transaction */
  uint32_t	    leg_rseq;   /**< Remote sequence number */
  sip_call_id_t	   *leg_id;	/**< Call ID */
  sip_from_t   	   *leg_remote;	/**< Remote address (@To/@From) */
  sip_to_t     	   *leg_local;	/**< Local address (@From/@To) */

  sip_route_t      *leg_route;  /**< @Route for outgoing requests. */
  sip_contact_t    *leg_target; /**< Remote destination (from @Contact). */
};

struct nta_incoming_s
{
  su_home_t            *irq_home;
  hash_value_t          irq_hash;
  nta_agent_t          *irq_agent;
  nta_ack_cancel_f     *irq_callback;
  nta_incoming_magic_t *irq_magic;

  /* Timeout/state queue */
  nta_incoming_t      **irq_prev;
  nta_incoming_t       *irq_next;
  incoming_queue_t     *irq_queue;

  /* Retry queue */
  nta_incoming_t      **irq_rprev;
  nta_incoming_t       *irq_rnext;

  sip_method_t        	irq_method;
  sip_request_t        *irq_rq;
  sip_from_t           *irq_from;
  sip_to_t             *irq_to;
  char const           *irq_tag;
  sip_cseq_t           *irq_cseq;
  sip_call_id_t        *irq_call_id;
  sip_via_t            *irq_via;
  sip_record_route_t   *irq_record_route;
  char const           *irq_branch;

  uint32_t              irq_rseq;

  sip_timestamp_t      *irq_timestamp;
  su_time_t             irq_received;

  uint32_t       	irq_timeout;    /**< Timer H, I, J */
  uint32_t       	irq_retry;      /**< Timer G */
  unsigned short      	irq_interval;	/**< Next timer  */

  short               	irq_status;

  unsigned irq_retries:8;
  unsigned irq_default:1;	/**< Default transaction */
  unsigned irq_canceled:1;	/**< Transaction is canceled */
  unsigned irq_completed:1;	/**< Transaction is completed */
  unsigned irq_confirmed:1;	/**< Response has been acked */
  unsigned irq_terminated:1;	/**< Transaction is terminated */
  unsigned irq_final_failed:1;	/**< Sending final response failed */
  unsigned irq_destroyed :1;	/**< Transaction is destroyed */
  unsigned irq_in_callback:1;	/**< Callback is being invoked */
  unsigned irq_reliable_tp:1;	/**< Transport is reliable */
  unsigned irq_sigcomp_zap:1;	/**< Reset SigComp */
  unsigned irq_must_100rel:1;	/**< 100rel is required */
  unsigned irq_tag_set:1;	/**< Tag is not from request */
  unsigned :0;

  tp_name_t             irq_tpn[1];
  tport_t              *irq_tport;
  struct sigcomp_compartment *irq_cc;
  msg_t		       *irq_request;
  msg_t		       *irq_request2;       /**< ACK/CANCEL */
  msg_t		       *irq_response;

  nta_reliable_t       *irq_reliable;       /**< List of reliable responses */
};

struct nta_reliable_s
{
  nta_reliable_t       *rel_next;
  nta_incoming_t       *rel_irq;
  nta_prack_f          *rel_callback;
  nta_reliable_magic_t *rel_magic;
  uint32_t              rel_rseq;
  unsigned short        rel_status;
  unsigned              rel_pracked:1;
  unsigned              rel_precious:1;
  msg_t                *rel_response;
  msg_t                *rel_unsent;
};

typedef struct sipdns_resolver sipdns_resolver_t;

struct nta_outgoing_s
{
  hash_value_t          orq_hash;    /**< Hash value */
  nta_agent_t          *orq_agent;
  nta_response_f       *orq_callback;
  nta_outgoing_magic_t *orq_magic;

  /* Timeout/state queue */
  nta_outgoing_t      **orq_prev;
  nta_outgoing_t       *orq_next;
  outgoing_queue_t     *orq_queue;

  /* Retry queue */
  nta_outgoing_t      **orq_rprev;
  nta_outgoing_t       *orq_rnext;

  sip_method_t        	orq_method;
  char const           *orq_method_name;
  url_t const          *orq_url;        /**< Original RequestURI */

  sip_from_t const     *orq_from;
  sip_to_t const       *orq_to;
  char const           *orq_tag;        /**< Tag from final response. */

  sip_cseq_t const     *orq_cseq;
  sip_call_id_t const  *orq_call_id;

  msg_t		       *orq_request;
  msg_t                *orq_response;

  su_time_t             orq_sent;       /**< When request was sent? */
  unsigned              orq_delay;      /**< RTT estimate */

  uint32_t		orq_retry;	/**< Timer A, E */
  uint32_t		orq_timeout;	/**< Timer B, D, F, K */

  unsigned short      	orq_interval;	/**< Next timer A/E */

  unsigned short      	orq_status;
  unsigned char         orq_retries;    /**< Number of tries this far */
  unsigned orq_default:1;	        /**< This is default transaction */
  unsigned orq_inserted:1;
  unsigned orq_resolved:1;
  unsigned orq_prepared:1; /**< outgoing_prepare() called */
  unsigned orq_canceled:1;
  unsigned orq_terminated:1;
  unsigned orq_destroyed:1;
  unsigned orq_completed:1;
  unsigned orq_delayed:1;
  unsigned orq_stripped_uri:1;
  unsigned orq_user_tport:1;	/**< Application provided tport - don't retry */
  unsigned orq_try_tcp_instead:1;
  unsigned orq_try_udp_instead:1;
  unsigned orq_reliable:1; /**< Transport is reliable */
  unsigned orq_ack_error:1; /**< ACK is sent by NTA */

  /* Attributes */
  unsigned orq_user_via:1;
  unsigned orq_stateless:1;
  unsigned orq_pass_100:1;
  unsigned orq_sigcomp_new:1;	/**< Create compartment if needed */
  unsigned orq_sigcomp_zap:1;	/**< Reset SigComp after completing */
  unsigned orq_must_100rel:1;
  unsigned orq_timestamp:1;	/**< Insert @Timestamp header. */
  unsigned orq_100rel:1;	/**< Support 100rel */
  unsigned:0;	/* pad */

#if HAVE_SOFIA_SRESOLV
  sipdns_resolver_t    *orq_resolver;
#endif
  enum nta_res_order_e  orq_res_order;  /**< AAAA/A first? */

  url_t                *orq_route;      /**< Route URL */
  tp_name_t             orq_tpn[1];     /**< Where to send request */
  char const           *orq_scheme;     /**< Transport URL type */

  tport_t              *orq_tport;
  struct sigcomp_compartment *orq_cc;
  tagi_t               *orq_tags;       /**< Tport tag items */
  int                   orq_pending;    /**< Request is pending in tport */

  char const           *orq_branch;	/**< Transaction branch */
  char const           *orq_via_branch;	/**< @Via branch */

  int                  *orq_status2b;   /**< Delayed response */

  nta_outgoing_t       *orq_cancel;     /**< CANCEL transaction */

  uint32_t              orq_rseq;       /**< Latest incoming rseq */
};

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

Pekka Pessi's avatar
Pekka Pessi committed
564 565
/* Internal tags */

566
/* Delay sending of request */
Pekka Pessi's avatar
Pekka Pessi committed
567 568 569 570 571 572 573
#define NTATAG_DELAY_SENDING(x) ntatag_delay_sending, tag_bool_v((x))
#define NTATAG_DELAY_SENDING_REF(x) \
ntatag_delay_sending_ref, tag_bool_vr(&(x))

extern tag_typedef_t ntatag_delay_sending;
extern tag_typedef_t ntatag_delay_sending_ref;

574
/* Allow sending incomplete responses */
Pekka Pessi's avatar
Pekka Pessi committed
575 576 577 578 579 580 581
#define NTATAG_INCOMPLETE(x) ntatag_incomplete, tag_bool_v((x))
#define NTATAG_INCOMPLETE_REF(x) \
ntatag_incomplete_ref, tag_bool_vr(&(x))

extern tag_typedef_t ntatag_incomplete;
extern tag_typedef_t ntatag_incomplete_ref;

582 583
nta_compressor_vtable_t *nta_compressor_vtable = NULL;

Pekka Pessi's avatar
Pekka Pessi committed
584 585 586 587 588 589 590
/* Agent */
static int agent_tag_init(nta_agent_t *self);
static int agent_timer_init(nta_agent_t *agent);
static void agent_timer(su_root_magic_t *rm, su_timer_t *, nta_agent_t *);
static int agent_launch_terminator(nta_agent_t *agent);
static void agent_kill_terminator(nta_agent_t *agent);
static int agent_set_params(nta_agent_t *agent, tagi_t *tags);
591
static void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu);
Pekka Pessi's avatar
Pekka Pessi committed
592 593 594 595
static int agent_get_params(nta_agent_t *agent, tagi_t *tags);

/* Transport interface */
static sip_via_t const *agent_tport_via(tport_t *tport);
Pekka Pessi's avatar
Pekka Pessi committed
596
static int outgoing_insert_via(nta_outgoing_t *orq, sip_via_t const *);
Pekka Pessi's avatar
Pekka Pessi committed
597 598 599
static int nta_tpn_by_via(tp_name_t *tpn, sip_via_t const *v, int *using_rport);

static msg_t *nta_msg_create_for_transport(nta_agent_t *agent, int flags,
600 601 602
					   char const data[], usize_t dlen,
					   tport_t const *tport,
					   tp_client_t *via);
Pekka Pessi's avatar
Pekka Pessi committed
603

604 605
static int complete_response(msg_t *response,
			     int status, char const *phrase,
Pekka Pessi's avatar
Pekka Pessi committed
606
			     msg_t *request);
607

608 609 610 611 612 613 614 615 616 617 618
static int mreply(nta_agent_t *agent,
		  msg_t *reply,
		  int status, char const *phrase,
		  msg_t *req_msg,
		  tport_t *tport,
		  int incomplete,
		  int sdwn_after,
		  char const *to_tag,
		  tag_type_t tag, tag_value_t value, ...);

#define IF_SIGCOMP_TPTAG_COMPARTMENT(cc)     TAG_IF(cc && cc != NONE, TPTAG_COMPARTMENT(cc)),
619
#define IF_SIGCOMP_TPTAG_COMPARTMENT_REF(cc) TPTAG_COMPARTMENT_REF(cc),
Pekka Pessi's avatar
Pekka Pessi committed
620

621
struct sigcomp_compartment;
622

Pekka Pessi's avatar
Pekka Pessi committed
623
struct sigcomp_compartment *
624
nta_compartment_ref(struct sigcomp_compartment *cc);
Pekka Pessi's avatar
Pekka Pessi committed
625 626 627

static
struct sigcomp_compartment *
628 629
agent_compression_compartment(nta_agent_t *sa, tport_t *tp, tp_name_t const *tpn,
			      int new_if_needed);
Pekka Pessi's avatar
Pekka Pessi committed
630 631

static
632 633
int agent_accept_compressed(nta_agent_t *sa, msg_t *msg,
			    struct sigcomp_compartment *cc);
Pekka Pessi's avatar
Pekka Pessi committed
634

635 636 637 638 639
static int agent_close_compressor(nta_agent_t *sa,
				  struct sigcomp_compartment *cc);

static int agent_zap_compressor(nta_agent_t *sa,
				struct sigcomp_compartment *cc);
Pekka Pessi's avatar
Pekka Pessi committed
640 641


Pekka Pessi's avatar
Pekka Pessi committed
642 643
static char const * stateful_branch(su_home_t *home, nta_agent_t *);
static char const * stateless_branch(nta_agent_t *, msg_t *, sip_t const *,
Pekka Pessi's avatar
Pekka Pessi committed
644 645 646 647 648
				    tp_name_t const *tp);

#define NTA_BRANCH_PRIME SU_U64_C(0xB9591D1C361C6521)
#define NTA_TAG_PRIME    SU_U64_C(0xB9591D1C361C6521)

Michael Jerris's avatar
Michael Jerris committed
649 650 651 652
#ifndef UINT32_MAX
#define UINT32_MAX (0xffffffffU)
#endif

653
HTABLE_PROTOS_WITH(leg_htable, lht, nta_leg_t, size_t, hash_value_t);
Pekka Pessi's avatar
Pekka Pessi committed
654 655 656 657 658
static nta_leg_t *leg_find(nta_agent_t const *sa,
			   char const *method_name,
			   url_t const *request_uri,
			   sip_call_id_t const *i,
			   char const *from_tag,
659
			   char const *to_tag);
Pekka Pessi's avatar
Pekka Pessi committed
660 661 662 663 664 665 666
static nta_leg_t *dst_find(nta_agent_t const *sa, url_t const *u0,
			   char const *method);
static void leg_recv(nta_leg_t *, msg_t *, sip_t *, tport_t *);
static void leg_free(nta_agent_t *sa, nta_leg_t *leg);

#define NTA_HASH(i, cs) ((i)->i_hash + 26839U * (uint32_t)(cs))

667
HTABLE_PROTOS_WITH(incoming_htable, iht, nta_incoming_t, size_t, hash_value_t);
Pekka Pessi's avatar
Pekka Pessi committed
668 669 670 671 672 673 674
static nta_incoming_t *incoming_create(nta_agent_t *agent,
				       msg_t *request,
				       sip_t *sip,
				       tport_t *tport,
				       char const *tag);
static int incoming_callback(nta_leg_t *leg, nta_incoming_t *irq, sip_t *sip);
static void incoming_free(nta_incoming_t *irq);
675 676
su_inline void incoming_cut_off(nta_incoming_t *irq);
su_inline void incoming_reclaim(nta_incoming_t *irq);
677
static void incoming_queue_init(incoming_queue_t *,
Pekka Pessi's avatar
Pekka Pessi committed
678
				unsigned timeout);
679 680
static void incoming_queue_adjust(nta_agent_t *sa,
				  incoming_queue_t *queue,
Pekka Pessi's avatar
Pekka Pessi committed
681 682
				  unsigned timeout);

683 684 685 686
static nta_incoming_t *incoming_find(nta_agent_t const *agent,
				     sip_t const *sip,
				     sip_via_t const *v,
				     nta_incoming_t **merge,
687 688
				     nta_incoming_t **ack,
				     nta_incoming_t **cancel);
Pekka Pessi's avatar
Pekka Pessi committed
689
static int incoming_reply(nta_incoming_t *irq, msg_t *msg, sip_t *sip);
690
su_inline int incoming_recv(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
Pekka Pessi's avatar
Pekka Pessi committed
691
				tport_t *tport);
692
su_inline int incoming_ack(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
Pekka Pessi's avatar
Pekka Pessi committed
693
			       tport_t *tport);
694
su_inline int incoming_cancel(nta_incoming_t *irq, msg_t *msg, sip_t *sip,
Pekka Pessi's avatar
Pekka Pessi committed
695
				  tport_t *tport);
696 697 698
static void request_merge(nta_agent_t *,
			  msg_t *msg, sip_t *sip, tport_t *tport,
			  char const *to_tag);
699
su_inline int incoming_timestamp(nta_incoming_t *, msg_t *, sip_t *);
700
static void incoming_timer(nta_agent_t *);
Pekka Pessi's avatar
Pekka Pessi committed
701 702 703 704 705 706 707

static nta_reliable_t *reliable_mreply(nta_incoming_t *,
				       nta_prack_f *, nta_reliable_magic_t *,
				       msg_t *, sip_t *);
static int reliable_send(nta_incoming_t *, nta_reliable_t *, msg_t *, sip_t *);
static int reliable_final(nta_incoming_t *irq, msg_t *msg, sip_t *sip);
static msg_t *reliable_response(nta_incoming_t *irq);
708 709
static nta_reliable_t *reliable_find(nta_agent_t const *, sip_t const *);
static int reliable_recv(nta_reliable_t *rel, msg_t *, sip_t *, tport_t *);
Pekka Pessi's avatar
Pekka Pessi committed
710 711 712
static void reliable_flush(nta_incoming_t *irq);
static void reliable_timeout(nta_incoming_t *irq, int timeout);

713
HTABLE_PROTOS_WITH(outgoing_htable, oht, nta_outgoing_t, size_t, hash_value_t);
Pekka Pessi's avatar
Pekka Pessi committed
714 715 716 717 718 719 720
static nta_outgoing_t *outgoing_create(nta_agent_t *agent,
				       nta_response_f *callback,
				       nta_outgoing_magic_t *magic,
				       url_string_t const *route_url,
				       tp_name_t const *tpn,
				       msg_t *msg,
				       tag_type_t tag, tag_value_t value, ...);
721
static void outgoing_queue_init(outgoing_queue_t *,
Pekka Pessi's avatar
Pekka Pessi committed
722
				unsigned timeout);
723 724
static void outgoing_queue_adjust(nta_agent_t *sa,
				  outgoing_queue_t *queue,
Pekka Pessi's avatar
Pekka Pessi committed
725 726
				  unsigned timeout);
static void outgoing_free(nta_outgoing_t *orq);
727 728
su_inline void outgoing_cut_off(nta_outgoing_t *orq);
su_inline void outgoing_reclaim(nta_outgoing_t *orq);
Pekka Pessi's avatar
Pekka Pessi committed
729 730 731 732 733
static nta_outgoing_t *outgoing_find(nta_agent_t const *sa,
				     msg_t const *msg,
				     sip_t const *sip,
				     sip_via_t const *v);
static int outgoing_recv(nta_outgoing_t *orq, int status, msg_t *, sip_t *);
734
static void outgoing_default_recv(nta_outgoing_t *, int, msg_t *, sip_t *);
735
static void outgoing_timer(nta_agent_t *);
Pekka Pessi's avatar
Pekka Pessi committed
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
static int outgoing_recv_reliable(nta_outgoing_t *orq, msg_t *msg, sip_t *sip);

/* Internal message passing */
union sm_arg_u {
  struct outgoing_recv_s {
    nta_outgoing_t *orq;
    msg_t          *msg;
    sip_t          *sip;
    int             status;
  } a_outgoing_recv[1];

  incoming_queue_t a_incoming_queue[1];
  outgoing_queue_t a_outgoing_queue[1];
};

/* Global module data */

753
/**@var char const NTA_DEBUG[];
Pekka Pessi's avatar
Pekka Pessi committed
754 755 756 757 758
 *
 * Environment variable determining the default debug log level.
 *
 * The NTA_DEBUG environment variable is used to determine the default
 * debug logging level. The normal level is 3.
759
 *
760
 * @sa <sofia-sip/su_debug.h>, #su_log_global, #SOFIA_DEBUG
Pekka Pessi's avatar
Pekka Pessi committed
761
 */
Michael Jerris's avatar
Michael Jerris committed
762 763 764
#ifdef DOXYGEN
extern char const NTA_DEBUG[]; /* dummy declaration for Doxygen */
#endif
Pekka Pessi's avatar
Pekka Pessi committed
765 766 767 768 769

#ifndef SU_DEBUG
#define SU_DEBUG 3
#endif

770 771
/**Debug log for @b nta module.
 *
Pekka Pessi's avatar
Pekka Pessi committed
772
 * The nta_log is the log object used by @b nta module. The level of
773
 * nta_log is set using #NTA_DEBUG environment variable.
Pekka Pessi's avatar
Pekka Pessi committed
774 775 776 777 778 779 780 781 782
 */
su_log_t nta_log[] = { SU_LOG_INIT("nta", "NTA_DEBUG", SU_DEBUG) };

/* ====================================================================== */
/* 1) Agent */

/**
 * Create an NTA agent object.
 *
783
 * Create an NTA agent object.  The agent
Pekka Pessi's avatar
Pekka Pessi committed
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
 * object creates and binds a server socket with address specified in @e url.
 * If the @e host portion of the @e url is @c "*", the agent listens to all
 * addresses available on the host.
 *
 * When a message is received, the agent object parses it.  If the result is
 * a valid SIP message, the agent object passes the message to the
 * application by invoking the nta_message_f @e callback function.
 *
 * @note
 * The @e url can be either parsed url (of type url_t ()), or a valid
 * SIP URL as a string.
 *
 * @note
 * If @e url is @c NULL, the default @e url @c "sip:*" is used.
 * @par
799 800
 * If @e url is @c NONE (iow, (void*)-1), no server sockets are bound.
 * @par
Pekka Pessi's avatar
Pekka Pessi committed
801 802 803 804 805
 * If @p transport parameters are specified in @a url, agent uses only
 * specified transport type.
 *
 * @par
 * If an @p maddr parameter is specified in @e url, agent binds to the
806 807 808
 * specified address, but uses @e host part of @e url when it generates
 * @Contact and @Via headers. The @p maddr parameter is also included,
 * unless it equals to @c INADDR_ANY (@p 0.0.0.0 or @p [::]).
Pekka Pessi's avatar
Pekka Pessi committed
809 810 811 812 813
 *
 * @param root          pointer to a su_root_t used for synchronization
 * @param contact_url   URL that agent uses to bind the server sockets
 * @param callback      pointer to callback function
 * @param magic         pointer to user data
814
 * @param tag,value,... tagged arguments
Pekka Pessi's avatar
Pekka Pessi committed
815
 *
816 817 818 819 820
 * @TAGS
 * NTATAG_ALIASES(),
 * NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(),
 * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(),
 * NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(),
821
 * NTATAG_EXTRA_100(), NTATAG_GRAYLIST(),
822
 * NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS()
823 824
 * NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(),
 * NTATAG_REL100(),
825 826 827 828 829
 * NTATAG_SERVER_RPORT(),
 * NTATAG_SIPFLAGS(),
 * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4(),
 * NTATAG_STATELESS(),
 * NTATAG_TAG_3261(), NTATAG_TCP_RPORT(), NTATAG_TIMEOUT_408(),
830
 * NTATAG_TLS_RPORT(),
Michael Jerris's avatar
Michael Jerris committed
831
 * NTATAG_TIMER_C(), NTATAG_MAX_PROCEEDING(),
832 833 834 835 836 837
 * NTATAG_UA(), NTATAG_UDP_MTU(), NTATAG_USER_VIA(),
 * NTATAG_USE_NAPTR(), NTATAG_USE_SRV() and NTATAG_USE_TIMESTAMP().
 *
 * @note The value from following tags are stored, but they currently do nothing:
 * NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_OPTIONS(), NTATAG_SMIME()
 *
838
 * @note It is possible to provide @c (url_string_t*)-1 as @a contact_url.
839
 * In that case, no server sockets are bound.
840
 *
Pekka Pessi's avatar
Pekka Pessi committed
841 842 843
 * @retval handle to the agent when successful,
 * @retval NULL upon an error.
 *
844
 * @sa NUTAG_
Pekka Pessi's avatar
Pekka Pessi committed
845 846 847 848 849 850 851 852 853 854 855 856 857 858 859
 */
nta_agent_t *nta_agent_create(su_root_t *root,
			      url_string_t const *contact_url,
			      nta_message_f *callback,
			      nta_agent_magic_t *magic,
			      tag_type_t tag, tag_value_t value, ...)
{
  nta_agent_t *agent;
  ta_list ta;

  if (root == NULL)
    return su_seterrno(EINVAL), NULL;

  ta_start(ta, tag, value);

860
  if ((agent = su_home_new(sizeof(*agent)))) {
861 862
    unsigned timer_c;

Pekka Pessi's avatar
Pekka Pessi committed
863 864 865 866 867
    agent->sa_root = root;
    agent->sa_callback = callback;
    agent->sa_magic = magic;
    agent->sa_flags = MSG_DO_CANONIC;

868
    agent->sa_maxsize         = 2 * 1024 * 1024; /* 2 MB */
869
    agent->sa_bad_req_mask    =
870
      /*
871 872
       * Bit-wise not of these - what is left is suitable for UAs with
       * 100rel, timer, events, publish
873
       */
874
      (unsigned) ~(sip_mask_response | sip_mask_proxy | sip_mask_registrar |
875
		   sip_mask_pref | sip_mask_privacy);
876 877
    agent->sa_bad_resp_mask   =
      (unsigned) ~(sip_mask_request | sip_mask_proxy | sip_mask_registrar |
878
		   sip_mask_pref | sip_mask_privacy);
Pekka Pessi's avatar
Pekka Pessi committed
879 880 881 882
    agent->sa_t1 	      = NTA_SIP_T1;
    agent->sa_t2 	      = NTA_SIP_T2;
    agent->sa_t4              = NTA_SIP_T4;
    agent->sa_t1x64 	      = 64 * NTA_SIP_T1;
883
    agent->sa_timer_c         = 185 * 1000;
884
    agent->sa_graylist        = 600;
Pekka Pessi's avatar
Pekka Pessi committed
885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903
    agent->sa_drop_prob       = 0;
    agent->sa_is_a_uas        = 0;
    agent->sa_progress        = 60 * 1000;
    agent->sa_user_via        = 0;
    agent->sa_extra_100       = 0;
    agent->sa_pass_100        = 0;
    agent->sa_timeout_408     = 1;
    agent->sa_pass_408        = 0;
    agent->sa_merge_482       = 0;
    agent->sa_cancel_2543     = 0;
    agent->sa_cancel_487      = 1;
    agent->sa_invite_100rel   = 0;
    agent->sa_timestamp       = 0;
    agent->sa_use_naptr       = 1;
    agent->sa_use_srv         = 1;
    agent->sa_auto_comp       = 0;
    agent->sa_server_rport    = 1;

    /* RFC 3261 section 8.1.1.6 */
904
    sip_max_forwards_init(agent->sa_max_forwards);
Pekka Pessi's avatar
Pekka Pessi committed
905 906 907 908 909 910 911 912 913 914

    if (getenv("SIPCOMPACT"))
      agent->sa_flags |= MSG_DO_COMPACT;

    agent_set_params(agent, ta_args(ta));

    if (agent->sa_mclass == NULL)
      agent->sa_mclass = sip_default_mclass();

    agent->sa_in.re_t1 = &agent->sa_in.re_list;
915

Pekka Pessi's avatar
Pekka Pessi committed
916 917 918 919 920 921
    incoming_queue_init(agent->sa_in.proceeding, 0);
    incoming_queue_init(agent->sa_in.preliminary, agent->sa_t1x64); /* P1 */
    incoming_queue_init(agent->sa_in.inv_completed, agent->sa_t1x64); /* H */
    incoming_queue_init(agent->sa_in.inv_confirmed, agent->sa_t4); /* I */
    incoming_queue_init(agent->sa_in.completed, agent->sa_t1x64); /* J */
    incoming_queue_init(agent->sa_in.terminated, 0);
922
    incoming_queue_init(agent->sa_in.final_failed, 0);
Pekka Pessi's avatar
Pekka Pessi committed
923 924 925 926 927 928 929

    agent->sa_out.re_t1 = &agent->sa_out.re_list;

    outgoing_queue_init(agent->sa_out.delayed, 0);
    outgoing_queue_init(agent->sa_out.resolving, 0);
    outgoing_queue_init(agent->sa_out.trying, agent->sa_t1x64); /* F */
    outgoing_queue_init(agent->sa_out.completed, agent->sa_t4); /* K */
930
    outgoing_queue_init(agent->sa_out.terminated, 0);
Pekka Pessi's avatar
Pekka Pessi committed
931 932
    /* Special queues (states) for outgoing INVITE transactions */
    outgoing_queue_init(agent->sa_out.inv_calling, agent->sa_t1x64); /* B */
933 934 935
    timer_c = (agent->sa_use_timer_c || !agent->sa_is_a_uas)
      ? agent->sa_timer_c : 0;
    outgoing_queue_init(agent->sa_out.inv_proceeding, timer_c); /* C */
Pekka Pessi's avatar
Pekka Pessi committed
936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
    outgoing_queue_init(agent->sa_out.inv_completed, 32000); /* Timer D */

    if (leg_htable_resize(agent->sa_home, agent->sa_dialogs, 0) < 0 ||
	leg_htable_resize(agent->sa_home, agent->sa_defaults, 0) < 0 ||
	outgoing_htable_resize(agent->sa_home, agent->sa_outgoing, 0) < 0 ||
	incoming_htable_resize(agent->sa_home, agent->sa_incoming, 0) < 0) {
      SU_DEBUG_0(("nta_agent_create: failure with %s\n", "hash tables"));
      goto deinit;
    }
    SU_DEBUG_9(("nta_agent_create: initialized %s\n", "hash tables"));

    if (contact_url != (url_string_t *)-1 &&
	nta_agent_add_tport(agent, contact_url, ta_tags(ta)) < 0) {
      SU_DEBUG_7(("nta_agent_create: failure with %s\n", "transport"));
      goto deinit;
    }
    SU_DEBUG_9(("nta_agent_create: initialized %s\n", "transports"));

    if (agent_tag_init(agent) < 0) {
      SU_DEBUG_3(("nta_agent_create: failure with %s\n", "random identifiers"));
      goto deinit;
    }
    SU_DEBUG_9(("nta_agent_create: initialized %s\n", "random identifiers"));

    if (agent_timer_init(agent) < 0) {
      SU_DEBUG_0(("nta_agent_create: failure with %s\n", "timer"));
      goto deinit;
    }
    SU_DEBUG_9(("nta_agent_create: initialized %s\n", "timer"));

    if (agent_launch_terminator(agent) == 0)
      SU_DEBUG_9(("nta_agent_create: initialized %s\n", "threads"));

#if HAVE_SOFIA_SRESOLV
    agent->sa_resolver = sres_resolver_create(root, NULL, ta_tags(ta));
    if (!agent->sa_resolver) {
      SU_DEBUG_0(("nta_agent_create: failure with %s\n", "resolver"));
    }
    SU_DEBUG_9(("nta_agent_create: initialized %s\n", "resolver"));
#endif

    ta_end(ta);

    return agent;

  deinit:
    nta_agent_destroy(agent);
  }

  ta_end(ta);

  return NULL;
}

/**
 * Destroy an NTA agent object.
 *
 * @param agent the NTA agent object to be destroyed.
 *
 */
void nta_agent_destroy(nta_agent_t *agent)
{
  if (agent) {
    size_t i;
    outgoing_htable_t *oht = agent->sa_outgoing;
    incoming_htable_t *iht = agent->sa_incoming;
    /* Currently, this is pretty pointless, as legs don't keep any resources */
    leg_htable_t *lht;
    nta_leg_t *leg;

    for (i = 0, lht = agent->sa_dialogs; i < lht->lht_size; i++) {
      if ((leg = lht->lht_table[i])) {
	SU_DEBUG_3(("nta_agent_destroy: destroying dialog with <"
		    URL_PRINT_FORMAT ">\n",
		    URL_PRINT_ARGS(leg->leg_remote->a_url)));
	leg_free(agent, leg);
      }
    }

    for (i = 0, lht = agent->sa_defaults; i < lht->lht_size; i++) {
      if ((leg = lht->lht_table[i])) {
1017
	SU_DEBUG_3(("%s: destroying leg for <"
Pekka Pessi's avatar
Pekka Pessi committed
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 1062
		    URL_PRINT_FORMAT ">\n",
		    __func__, URL_PRINT_ARGS(leg->leg_url)));
	leg_free(agent, leg);
      }
    }

    if (agent->sa_default_leg)
      leg_free(agent, agent->sa_default_leg);

    for (i = iht->iht_size; i-- > 0; )
      while (iht->iht_table[i]) {
	nta_incoming_t *irq = iht->iht_table[i];

	if (!irq->irq_destroyed)
	  SU_DEBUG_3(("%s: destroying %s server transaction from <"
		      URL_PRINT_FORMAT ">\n",
		      __func__, irq->irq_rq->rq_method_name,
		      URL_PRINT_ARGS(irq->irq_from->a_url)));

	incoming_free(irq);
      }

    for (i = oht->oht_size; i-- > 0;)
      while (oht->oht_table[i]) {
	nta_outgoing_t *orq = oht->oht_table[i];

	if (!orq->orq_destroyed)
	  SU_DEBUG_3(("%s: destroying %s client transaction to <"
		      URL_PRINT_FORMAT ">\n",
		      __func__, orq->orq_method_name,
		      URL_PRINT_ARGS(orq->orq_to->a_url)));

	outgoing_free(orq);
      }

    su_timer_destroy(agent->sa_timer), agent->sa_timer = NULL;

#   if HAVE_SOFIA_SRESOLV
    sres_resolver_destroy(agent->sa_resolver), agent->sa_resolver = NULL;
#   endif

    tport_destroy(agent->sa_tports), agent->sa_tports = NULL;

    agent_kill_terminator(agent);

1063
    su_home_unref(agent->sa_home);
Pekka Pessi's avatar
Pekka Pessi committed
1064 1065 1066 1067 1068 1069 1070 1071 1072
  }
}

/** Return agent context. */
nta_agent_magic_t *nta_agent_magic(nta_agent_t const *agent)
{
  return agent ? agent->sa_magic : NULL;
}

1073
/** Return @Contact header.
Pekka Pessi's avatar
Pekka Pessi committed
1074
 *
1075
 * Get a @Contact header, which can be used to reach @a agent.
Pekka Pessi's avatar
Pekka Pessi committed
1076 1077 1078
 *
 * @param agent NTA agent object
 *
1079
 * User agents can insert the @Contact header in the outgoing REGISTER,
Pekka Pessi's avatar
Pekka Pessi committed
1080 1081 1082
 * INVITE, and ACK requests and replies to incoming INVITE and OPTIONS
 * transactions.
 *
1083
 * Proxies can use the @Contact header to create appropriate @RecordRoute
Pekka Pessi's avatar
Pekka Pessi committed
1084 1085 1086 1087 1088 1089
 * headers:
 * @code
 * r_r = sip_record_route_create(msg_home(msg),
 *	 			 sip->sip_request->rq_url,
 *				 contact->m_url);
 * @endcode
1090 1091
 *
 * @return A sip_contact_t object corresponding to the @a agent.
Pekka Pessi's avatar
Pekka Pessi committed
1092 1093 1094 1095 1096 1097
 */
sip_contact_t *nta_agent_contact(nta_agent_t const *agent)
{
  return agent ? agent->sa_contact : NULL;
}

1098
/** Return a list of @Via headers.
Pekka Pessi's avatar
Pekka Pessi committed
1099
 *
1100
 * Get @Via headers for all activated transport.
Pekka Pessi's avatar
Pekka Pessi committed
1101 1102 1103
 *
 * @param agent NTA agent object
 *
1104
 * @return A list of #sip_via_t objects used by the @a agent.
Pekka Pessi's avatar
Pekka Pessi committed
1105 1106 1107 1108 1109 1110
 */
sip_via_t *nta_agent_via(nta_agent_t const *agent)
{
  return agent ? agent->sa_vias : NULL;
}

1111
/** Return a list of public (UPnP, STUN) @Via headers.
1112
 *
1113
 * Get public @Via headers for all activated transports.
1114 1115
 *
 * @param agent NTA agent object
1116
 *
1117
 * @return A list of #sip_via_t objects used by the @a agent.
1118 1119 1120 1121 1122 1123
 */
sip_via_t *nta_agent_public_via(nta_agent_t const *agent)
{
  return agent ? agent->sa_public_vias : NULL;
}

1124 1125 1126 1127 1128 1129 1130 1131 1132
/** Match a @Via header @a v with @Via headers in @a agent.
 *
 */
static
sip_via_t *agent_has_via(nta_agent_t const *agent, sip_via_t const *via)
{
  sip_via_t const *v;

  for (v = agent->sa_public_vias; v; v = v->v_next) {
1133
    if (!su_casematch(via->v_host, v->v_host))
1134
      continue;
1135
    if (!su_strmatch(via->v_port, v->v_port))
1136
      continue;
1137
    if (!su_casematch(via->v_protocol, v->v_protocol))
1138 1139 1140 1141 1142
      continue;
    return (sip_via_t *)v;
  }

  for (v = agent->sa_vias; v; v = v->v_next) {
1143
    if (!su_casematch(via->v_host, v->v_host))
1144
      continue;
1145
    if (!su_strmatch(via->v_port, v->v_port))
1146
      continue;
1147
    if (!su_casematch(via->v_protocol, v->v_protocol))
1148 1149 1150 1151 1152 1153 1154
      continue;
    return (sip_via_t *)v;
  }

  return NULL;
}

1155
/** Return @UserAgent header.
Pekka Pessi's avatar
Pekka Pessi committed
1156
 *
1157
 * Get @UserAgent information with NTA version.
Pekka Pessi's avatar
Pekka Pessi committed
1158
 *
1159
 * @param agent NTA agent object (may be NULL)
Pekka Pessi's avatar
Pekka Pessi committed
1160
 *
1161
 * @return A string containing the @a agent version.
Pekka Pessi's avatar
Pekka Pessi committed
1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200
 */
char const *nta_agent_version(nta_agent_t const *agent)
{
  return "nta" "/" VERSION;
}

/** Initialize default tag */
static int agent_tag_init(nta_agent_t *self)
{
  sip_contact_t *m = self->sa_contact;
  uint32_t hash = 1;

  if (m) {

    if (m->m_url->url_user)
      hash = 914715421U * hash + msg_hash_string(m->m_url->url_user);
    if (m->m_url->url_host)
      hash = 914715421U * hash + msg_hash_string(m->m_url->url_host);
    if (m->m_url->url_port)
      hash = 914715421U * hash + msg_hash_string(m->m_url->url_port);
    if (m->m_url->url_params)
      hash = 914715421U * hash + msg_hash_string(m->m_url->url_params);
  }

  if (hash == 0)
    hash = 914715421U;

  self->sa_branch = NTA_BRANCH_PRIME * su_ntp_now();
  self->sa_branch *= hash;

  self->sa_tags = NTA_TAG_PRIME * self->sa_branch;

  return 0;
}

/** Initialize agent timer. */
static
int agent_timer_init(nta_agent_t *agent)
{
1201 1202 1203 1204
  agent->sa_timer = su_timer_create(su_root_task(agent->sa_root),
				    NTA_SIP_T1 / 8);
#if 0
  return su_timer_set(agent->sa_timer,
Pekka Pessi's avatar
Pekka Pessi committed
1205 1206
		      agent_timer,
		      agent);
1207 1208
#endif
  return -(agent->sa_timer == NULL);
Pekka Pessi's avatar
Pekka Pessi committed
1209 1210 1211 1212 1213 1214 1215 1216
}

/**
 * Agent timer routine.
 */
static
void agent_timer(su_root_magic_t *rm, su_timer_t *timer, nta_agent_t *agent)
{
1217
  su_time_t stamp = su_now();
1218
  uint32_t now = su_time_ms(stamp), next, latest;
Pekka Pessi's avatar
Pekka Pessi committed
1219 1220 1221

  now += now == 0;

1222 1223
  agent->sa_next = 0;

1224
  agent->sa_now = stamp;
Pekka Pessi's avatar
Pekka Pessi committed
1225
  agent->sa_millisec = now;
1226
  agent->sa_in_timer = 1;
Pekka Pessi's avatar
Pekka Pessi committed
1227

1228 1229
  outgoing_timer(agent);
  incoming_timer(agent);
Pekka Pessi's avatar
Pekka Pessi committed
1230

1231
  /* agent->sa_now is used only if sa_millisec != 0 */
Pekka Pessi's avatar
Pekka Pessi committed
1232
  agent->sa_millisec = 0;
1233 1234
  agent->sa_in_timer = 0;

1235
  /* Calculate next timeout */
1236
  next = latest = now + NTA_TIME_MAX + 1;
1237 1238

#define NEXT_TIMEOUT(next, p, f, now) \
1239 1240
  (void)(p && (int32_t)(p->f - (next)) < 0 && \
	 ((next) = ((int32_t)(p->f - (now)) > 0 ? p->f : (now))))
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255

  NEXT_TIMEOUT(next, agent->sa_out.re_list, orq_retry, now);
  NEXT_TIMEOUT(next, agent->sa_out.inv_completed->q_head, orq_timeout, now);
  NEXT_TIMEOUT(next, agent->sa_out.completed->q_head, orq_timeout, now);
  NEXT_TIMEOUT(next, agent->sa_out.inv_calling->q_head, orq_timeout, now);
  if (agent->sa_out.inv_proceeding->q_timeout)
    NEXT_TIMEOUT(next, agent->sa_out.inv_proceeding->q_head, orq_timeout, now);
  NEXT_TIMEOUT(next, agent->sa_out.trying->q_head, orq_timeout, now);

  NEXT_TIMEOUT(next, agent->sa_in.preliminary->q_head, irq_timeout, now);
  NEXT_TIMEOUT(next, agent->sa_in.inv_completed->q_head, irq_timeout, now);
  NEXT_TIMEOUT(next, agent->sa_in.inv_confirmed->q_head, irq_timeout, now);
  NEXT_TIMEOUT(next, agent->sa_in.completed->q_head, irq_timeout, now);
  NEXT_TIMEOUT(next, agent->sa_in.re_list, irq_retry, now);

1256
  if (agent->sa_next)
1257 1258 1259
    NEXT_TIMEOUT(next, agent, sa_next, now);

#undef NEXT_TIMEOUT
1260

1261 1262
  if (next == latest) {
    /* Do not set timer? */
1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274
    SU_DEBUG_9(("nta: timer not set\n"));
    assert(!agent->sa_out.completed->q_head);
    assert(!agent->sa_out.trying->q_head);
    assert(!agent->sa_out.inv_calling->q_head);
    assert(!agent->sa_out.re_list);
    assert(!agent->sa_in.inv_confirmed->q_head);
    assert(!agent->sa_in.preliminary->q_head);
    assert(!agent->sa_in.completed->q_head);
    assert(!agent->sa_in.inv_completed->q_head);
    assert(!agent->sa_in.re_list);
    return;
  }
Pekka Pessi's avatar
Pekka Pessi committed
1275

1276 1277 1278 1279 1280 1281 1282
  if (next == now) if (++next == 0) ++next;

  SU_DEBUG_9(("nta: timer %s to %ld ms\n", "set next", (long)(next - now)));

  agent->sa_next = next;

  su_timer_set_at(timer, agent_timer, agent, su_time_add(stamp, next - now));
Pekka Pessi's avatar
Pekka Pessi committed
1283 1284
}

1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300
/** Add uin32_t milliseconds to the time. */
static su_time_t add_milliseconds(su_time_t t0, uint32_t ms)
{
  unsigned long sec = ms / 1000, usec = (ms % 1000) * 1000;

  t0.tv_usec += usec;
  t0.tv_sec += sec;

  if (t0.tv_usec >= 1000000) {
    t0.tv_sec += 1;
    t0.tv_usec -= 1000000;
  }

  return t0;
}

1301 1302 1303 1304 1305 1306 1307 1308
/** Calculate nonzero value for timeout.
 *
 * Sets or adjusts agent timer when needed.
 *
 * @retval 0 if offset is 0
 * @retval timeout (millisecond counter) otherwise
 */
static
1309
uint32_t set_timeout(nta_agent_t *agent, uint32_t offset)
Pekka Pessi's avatar
Pekka Pessi committed
1310
{
1311
  su_time_t now;
1312
  uint32_t next, ms;
Pekka Pessi's avatar
Pekka Pessi committed
1313

1314 1315 1316
  if (offset == 0)
    return 0;

1317
  if (agent->sa_millisec) /* Avoid expensive call to su_now() */
1318
    now = agent->sa_now, ms = agent->sa_millisec;
Pekka Pessi's avatar
Pekka Pessi committed
1319
  else
1320
    now = su_now(), ms = su_time_ms(now);
1321

1322
  next = ms + offset; if (next == 0) next = 1;
Pekka Pessi's avatar
Pekka Pessi committed
1323

1324
  if (agent->sa_in_timer)	/* Currently executing timer */
1325 1326
    return next;

1327
  if (agent->sa_next == 0 || (int32_t)(agent->sa_next - next - 5L) > 0) {
1328 1329 1330 1331 1332
    /* Set timer */
    if (agent->sa_next)
      SU_DEBUG_9(("nta: timer %s to %ld ms\n", "shortened", (long)offset));
    else
      SU_DEBUG_9(("nta: timer %s to %ld ms\n", "set", (long)offset));
1333 1334

    su_timer_set_at(agent->sa_timer, agent_timer, agent,
1335
		    add_milliseconds(now, offset));
1336 1337
    agent->sa_next = next;
  }
Pekka Pessi's avatar
Pekka Pessi committed
1338

1339
  return next;
Pekka Pessi's avatar
Pekka Pessi committed
1340 1341 1342 1343
}


/** Return current timeval. */
1344
static
Pekka Pessi's avatar
Pekka Pessi committed
1345 1346
su_time_t agent_now(nta_agent_t const *agent)
{
Pekka Pessi's avatar
Pekka Pessi committed
1347 1348
  if (agent && agent->sa_millisec != 0)
    return agent->sa_now;
1349
  else
Pekka Pessi's avatar
Pekka Pessi committed
1350
    return su_now();
Pekka Pessi's avatar
Pekka Pessi committed
1351 1352 1353 1354 1355 1356 1357 1358 1359 1360
}


/** Launch transaction terminator task */
static
int agent_launch_terminator(nta_agent_t *agent)
{
#ifdef TPTAG_THRPSIZE
  if (agent->sa_tport_threadpool) {
    su_home_threadsafe(agent->sa_home);
1361
    return su_clone_start(agent->sa_root,
Pekka Pessi's avatar
Pekka Pessi committed
1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383
			  agent->sa_terminator,
			  NULL,
			  NULL,
			  NULL);
  }
#endif
  return -1;
}

/** Kill transaction terminator task */
static
void agent_kill_terminator(nta_agent_t *agent)
{
  su_clone_wait(agent->sa_root, agent->sa_terminator);
}


/**Set NTA Parameters.
 *
 * The nta_agent_set_params() function sets the stack parameters. The
 * parameters determine the way NTA handles the retransmissions, how long
 * NTA keeps transactions alive, does NTA apply proxy or user-agent logic to
1384
 * INVITE transactions, or how the @Via headers are generated.
Pekka Pessi's avatar
Pekka Pessi committed
1385
 *
1386
 * @note
Michael Jerris's avatar
Michael Jerris committed
1387
 * Setting the parameters NTATAG_MAXSIZE(), NTATAG_UDP_MTU(), NTATAG_MAX_PROCEEDING(),
Pekka Pessi's avatar
Pekka Pessi committed
1388 1389 1390 1391
 * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4() to
 * 0 selects the default value.
 *
 * @TAGS
1392 1393 1394 1395
 * NTATAG_ALIASES(),
 * NTATAG_BAD_REQ_MASK(), NTATAG_BAD_RESP_MASK(), NTATAG_BLACKLIST(),
 * NTATAG_CANCEL_2543(), NTATAG_CANCEL_487(), NTATAG_CLIENT_RPORT(),
 * NTATAG_DEBUG_DROP_PROB(), NTATAG_DEFAULT_PROXY(),
1396
 * NTATAG_EXTRA_100(), NTATAG_GRAYLIST(),
1397
 * NTATAG_MAXSIZE(), NTATAG_MAX_FORWARDS(), NTATAG_MERGE_482(), NTATAG_MCLASS()
1398 1399
 * NTATAG_PASS_100(), NTATAG_PASS_408(), NTATAG_PRELOAD(), NTATAG_PROGRESS(),
 * NTATAG_REL100(),
1400 1401 1402 1403 1404
 * NTATAG_SERVER_RPORT(),
 * NTATAG_SIPFLAGS(),
 * NTATAG_SIP_T1X64(), NTATAG_SIP_T1(), NTATAG_SIP_T2(), NTATAG_SIP_T4(),
 * NTATAG_STATELESS(),
 * NTATAG_TAG_3261(), NTATAG_TCP_RPORT(), NTATAG_TIMEOUT_408(),
1405
 * NTATAG_TLS_RPORT(),
Michael Jerris's avatar
Michael Jerris committed
1406
 * NTATAG_TIMER_C(), NTATAG_MAX_PROCEEDING(),
1407 1408 1409 1410 1411
 * NTATAG_UA(), NTATAG_UDP_MTU(), NTATAG_USER_VIA(),
 * NTATAG_USE_NAPTR(), NTATAG_USE_SRV() and NTATAG_USE_TIMESTAMP().
 *
 * @note The value from following tags are stored, but they currently do nothing:
 * NTATAG_SIGCOMP_ALGORITHM(), NTATAG_SIGCOMP_OPTIONS(), NTATAG_SMIME()
Pekka Pessi's avatar
Pekka Pessi committed
1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434
 */
int nta_agent_set_params(nta_agent_t *agent,
			 tag_type_t tag, tag_value_t value, ...)
{
  int retval;

  if (agent) {
    ta_list ta;
    ta_start(ta, tag, value);
    retval = agent_set_params(agent, ta_args(ta));
    ta_end(ta);
  } else {
    su_seterrno(EINVAL);
    retval = -1;
  }

  return retval;
}

/** Internal function for setting tags */
static
int agent_set_params(nta_agent_t *agent, tagi_t *tags)
{
1435
  int n, nC, m;
Pekka Pessi's avatar
Pekka Pessi committed
1436 1437
  unsigned bad_req_mask = agent->sa_bad_req_mask;
  unsigned bad_resp_mask = agent->sa_bad_resp_mask;
1438
  usize_t  maxsize    = agent->sa_maxsize;
Michael Jerris's avatar
Michael Jerris committed
1439
  usize_t  max_proceeding = agent->sa_max_proceeding;
1440
  unsigned max_forwards = agent->sa_max_forwards->mf_count;
1441
  unsigned udp_mtu    = agent->sa_udp_mtu;
Pekka Pessi's avatar
Pekka Pessi committed
1442 1443 1444 1445
  unsigned sip_t1     = agent->sa_t1;
  unsigned sip_t2     = agent->sa_t2;
  unsigned sip_t4     = agent->sa_t4;
  unsigned sip_t1x64  = agent->sa_t1x64;
1446
  unsigned timer_c    = agent->sa_timer_c;
1447
  unsigned graylist   = agent->sa_graylist;
Pekka Pessi's avatar
Pekka Pessi committed
1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467
  unsigned blacklist  = agent->sa_blacklist;
  int ua              = agent->sa_is_a_uas;
  unsigned progress   = agent->sa_progress;
  int stateless       = agent->sa_is_stateless;
  unsigned drop_prob  = agent->sa_drop_prob;
  int user_via        = agent->sa_user_via;
  int extra_100       = agent->sa_extra_100;
  int pass_100        = agent->sa_pass_100;
  int timeout_408     = agent->sa_timeout_408;
  int pass_408        = agent->sa_pass_408;
  int merge_482       = agent->sa_merge_482;
  int cancel_2543     = agent->sa_cancel_2543;
  int cancel_487      = agent->sa_cancel_487;
  int invite_100rel   = agent->sa_invite_100rel;
  int use_timestamp   = agent->sa_timestamp;
  int use_naptr       = agent->sa_use_naptr;
  int use_srv         = agent->sa_use_srv;
  void *smime         = agent->sa_smime;
  uint32_t flags      = agent->sa_flags;
  int rport           = agent->sa_rport;
1468
  int server_rport    = agent->sa_server_rport;
Pekka Pessi's avatar
Pekka Pessi committed
1469
  int tcp_rport       = agent->sa_tcp_rport;
1470
  int tls_rport       = agent->sa_tls_rport;
Pekka Pessi's avatar
Pekka Pessi committed
1471 1472 1473 1474
  unsigned preload         = agent->sa_preload;
  unsigned threadpool      = agent->sa_tport_threadpool;
  char const *sigcomp = agent->sa_sigcomp_options;
  char const *algorithm = NONE;
1475
  msg_mclass_t const *mclass = NONE;
Pekka Pessi's avatar
Pekka Pessi committed
1476 1477 1478 1479 1480 1481 1482
  sip_contact_t const *aliases = NONE;
  url_string_t const *proxy = NONE;
  tport_t *tport;

  su_home_t *home = agent->sa_home;

  n = tl_gets(tags,
1483
	      NTATAG_ALIASES_REF(aliases),
Pekka Pessi's avatar
Pekka Pessi committed
1484 1485 1486
	      NTATAG_BAD_REQ_MASK_REF(bad_req_mask),
	      NTATAG_BAD_RESP_MASK_REF(bad_resp_mask),
	      NTATAG_BLACKLIST_REF(blacklist),
1487 1488
	      NTATAG_CANCEL_2543_REF(cancel_2543),
	      NTATAG_CANCEL_487_REF(cancel_487),
Pekka Pessi's avatar
Pekka Pessi committed
1489
	      NTATAG_DEBUG_DROP_PROB_REF(drop_prob),
1490
	      NTATAG_DEFAULT_PROXY_REF(proxy),
Pekka Pessi's avatar
Pekka Pessi committed
1491
	      NTATAG_EXTRA_100_REF(extra_100),
1492
	      NTATAG_GRAYLIST_REF(graylist),
1493
	      NTATAG_MAXSIZE_REF(maxsize),
Michael Jerris's avatar
Michael Jerris committed
1494
	      NTATAG_MAX_PROCEEDING_REF(max_proceeding),
1495 1496 1497
	      NTATAG_MAX_FORWARDS_REF(max_forwards),
	      NTATAG_MCLASS_REF(mclass),
	      NTATAG_MERGE_482_REF(merge_482),
Pekka Pessi's avatar
Pekka Pessi committed
1498 1499
	      NTATAG_PASS_100_REF(pass_100),
	      NTATAG_PASS_408_REF(pass_408),
1500 1501
	      NTATAG_PRELOAD_REF(preload),
	      NTATAG_PROGRESS_REF(progress),
Pekka Pessi's avatar
Pekka Pessi committed
1502
	      NTATAG_REL100_REF(invite_100rel),
1503 1504 1505 1506 1507 1508 1509 1510 1511
	      NTATAG_RPORT_REF(rport),
	      NTATAG_SERVER_RPORT_REF(server_rport),
	      NTATAG_SIGCOMP_ALGORITHM_REF(algorithm),
	      NTATAG_SIGCOMP_OPTIONS_REF(sigcomp),
	      NTATAG_SIPFLAGS_REF(flags),
	      NTATAG_SIP_T1X64_REF(sip_t1x64),
	      NTATAG_SIP_T1_REF(sip_t1),
	      NTATAG_SIP_T2_REF(sip_t2),
	      NTATAG_SIP_T4_REF(sip_t4),
Pekka Pessi's avatar
Pekka Pessi committed
1512 1513 1514
#if HAVE_SOFIA_SMIME
	      NTATAG_SMIME_REF(smime),
#endif
1515
	      NTATAG_STATELESS_REF(stateless),
Pekka Pessi's avatar
Pekka Pessi committed
1516
	      NTATAG_TCP_RPORT_REF(tcp_rport),
1517
	      NTATAG_TLS_RPORT_REF(tls_rport),
1518 1519 1520 1521 1522 1523 1524
	      NTATAG_TIMEOUT_408_REF(timeout_408),
	      NTATAG_UA_REF(ua),
	      NTATAG_UDP_MTU_REF(udp_mtu),
	      NTATAG_USER_VIA_REF(user_via),
	      NTATAG_USE_NAPTR_REF(use_naptr),
	      NTATAG_USE_SRV_REF(use_srv),
	      NTATAG_USE_TIMESTAMP_REF(use_timestamp),
Pekka Pessi's avatar
Pekka Pessi committed
1525 1526 1527 1528 1529
#ifdef TPTAG_THRPSIZE
	      /* If threadpool is enabled, start a separate "reaper thread" */
	      TPTAG_THRPSIZE_REF(threadpool),
#endif
	      TAG_END());
1530 1531 1532 1533
  nC = tl_gets(tags,
	       NTATAG_TIMER_C_REF(timer_c),
	       TAG_END());
  n += nC;
Pekka Pessi's avatar
Pekka Pessi committed
1534 1535 1536 1537 1538 1539 1540 1541 1542

  if (mclass != NONE)
    agent->sa_mclass = mclass ? mclass : sip_default_mclass();

  m = 0;
  for (tport = agent->sa_tports; tport; tport = tport_next(tport)) {
    m = tport_set_params(tport, TAG_NEXT(tags));
  }

1543
  if (m == -1)
Pekka Pessi's avatar
Pekka Pessi committed
1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570
    return m;

  n += m;

  if (aliases != NONE) {
    sip_contact_t const *m, *m_next;

    m = agent->sa_aliases;
    agent->sa_aliases = sip_contact_dup(home, aliases);

    for (; m; m = m_next) {	/* Free old aliases */
      m_next = m->m_next;
      su_free(home, (void *)m);
    }
  }

  if (proxy != NONE) {
    url_t *dp = url_hdup(home, proxy->us_url);

    url_sanitize(dp);

    if (dp == NULL || dp->url_type == url_sip || dp->url_type == url_sips) {
      if (agent->sa_default_proxy)
	su_free(home, agent->sa_default_proxy);
      agent->sa_default_proxy = dp;
    }
    else
Pekka Pessi's avatar
Pekka Pessi committed
1571
      n = -1;
Pekka Pessi's avatar
Pekka Pessi committed
1572 1573 1574
  }

  if (algorithm != NONE)
1575
    agent->sa_algorithm = su_strdup(home, algorithm);
Pekka Pessi's avatar
Pekka Pessi committed
1576

1577
  if (!su_strmatch(sigcomp, agent->sa_sigcomp_options)) {
Pekka Pessi's avatar
Pekka Pessi committed
1578
    msg_param_t const *l = NULL;
Pekka Pessi's avatar
Pekka Pessi committed
1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596
    char *s = su_strdup(home, sigcomp);
    char *s1 = su_strdup(home, s), *s2 = s1;

    if (s && s2 && msg_avlist_d(home, &s2, &l) == 0 && *s2 == '\0') {
      su_free(home, (void *)agent->sa_sigcomp_options);
      su_free(home, (void *)agent->sa_sigcomp_option_list);
      agent->sa_sigcomp_options = s;
      agent->sa_sigcomp_option_free = s1;
      agent->sa_sigcomp_option_list = l;
    } else {
      su_free(home, s);
      su_free(home, s1);
      su_free(home, (void *)l);
      n = -1;
    }
  }

  if (maxsize == 0) maxsize = 2 * 1024 * 1024;
1597
  if (maxsize > UINT32_MAX) maxsize = UINT32_MAX;
Pekka Pessi's avatar
Pekka Pessi committed
1598 1599
  agent->sa_maxsize = maxsize;

1600
  if (max_proceeding == 0) max_proceeding = USIZE_MAX;
Michael Jerris's avatar
Michael Jerris committed
1601 1602
  agent->sa_max_proceeding = max_proceeding;

1603 1604 1605
  if (max_forwards == 0) max_forwards = 70; /* Default value */
  agent->sa_max_forwards->mf_count = max_forwards;

Pekka Pessi's avatar
Pekka Pessi committed
1606 1607
  if (udp_mtu == 0) udp_mtu = 1300;
  if (udp_mtu > 65535) udp_mtu = 65535;
1608 1609
  if (agent->sa_udp_mtu != udp_mtu) {
    agent->sa_udp_mtu = udp_mtu;
Pekka Pessi's avatar
Pekka Pessi committed
1610
    agent_set_udp_params(agent, udp_mtu);
1611
  }
Pekka Pessi's avatar
Pekka Pessi committed
1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638

  if (sip_t1 == 0) sip_t1 = NTA_SIP_T1;
  if (sip_t1 > NTA_TIME_MAX) sip_t1 = NTA_TIME_MAX;
  agent->sa_t1 = sip_t1;

  if (sip_t2 == 0) sip_t2 = NTA_SIP_T2;
  if (sip_t2 > NTA_TIME_MAX) sip_t2 = NTA_TIME_MAX;
  agent->sa_t2 = sip_t2;

  if (sip_t4 == 0) sip_t4 = NTA_SIP_T4;
  if (sip_t4 > NTA_TIME_MAX) sip_t4 = NTA_TIME_MAX;
  if (agent->sa_t4 != sip_t4) {
    incoming_queue_adjust(agent, agent->sa_in.inv_confirmed, sip_t4);
    outgoing_queue_adjust(agent, agent->sa_out.completed, sip_t4);
  }
  agent->sa_t4 = sip_t4;

  if (sip_t1x64 == 0) sip_t1x64 = NTA_SIP_T1 * 64;
  if (sip_t1x64 > NTA_TIME_MAX) sip_t1x64 = NTA_TIME_MAX;
  if (agent->sa_t1x64 != sip_t1x64) {
    incoming_queue_adjust(agent, agent->sa_in.preliminary, sip_t1x64);
    incoming_queue_adjust(agent, agent->sa_in.completed, sip_t1x64);
    incoming_queue_adjust(agent, agent->sa_in.inv_completed, sip_t1x64);
    outgoing_queue_adjust(agent, agent->sa_out.trying, sip_t1x64);
    outgoing_queue_adjust(agent, agent->sa_out.inv_calling, sip_t1x64);
  }
  agent->sa_t1x64 = sip_t1x64;
1639 1640 1641 1642 1643 1644 1645 1646
  if (nC == 1) {
    agent->sa_use_timer_c = 1;
    if (timer_c == 0)
      timer_c = 185 * 1000;
    agent->sa_timer_c = timer_c;
    outgoing_queue_adjust(agent, agent->sa_out.inv_proceeding, timer_c);
  }

1647 1648 1649 1650 1651 1652
  if (graylist > 24 * 60 * 60)
    graylist = 24 * 60 * 60;
  agent->sa_graylist = graylist;

  if (blacklist > 24 * 60 * 60)
    blacklist = 24 * 60 * 60;
Pekka Pessi's avatar
Pekka Pessi committed
1653 1654 1655 1656 1657 1658
  agent->sa_blacklist = blacklist;

  if (progress == 0)
    progress = 60 * 1000;
  agent->sa_progress = progress;

1659 1660
  if (server_rport > 2)
    server_rport = 1;
1661 1662
  else if (server_rport < 0)
    server_rport = 1;
1663 1664
  agent->sa_server_rport = server_rport;

Pekka Pessi's avatar
Pekka Pessi committed
1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685
  agent->sa_bad_req_mask = bad_req_mask;
  agent->sa_bad_resp_mask = bad_resp_mask;

  agent->sa_is_a_uas = ua != 0;
  agent->sa_is_stateless = stateless != 0;
  agent->sa_drop_prob = drop_prob < 1000 ? drop_prob : 1000;
  agent->sa_user_via = user_via != 0;
  agent->sa_extra_100 = extra_100 != 0;
  agent->sa_pass_100 = pass_100 != 0;
  agent->sa_timeout_408 = timeout_408 != 0;
  agent->sa_pass_408 = pass_408 != 0;
  agent->sa_merge_482 = merge_482 != 0;
  agent->sa_cancel_2543 = cancel_2543 != 0;
  agent->sa_cancel_487 = cancel_487 != 0;
  agent->sa_invite_100rel = invite_100rel != 0;
  agent->sa_timestamp = use_timestamp != 0;
  agent->sa_use_naptr = use_naptr != 0;
  agent->sa_use_srv = use_srv != 0;
  agent->sa_smime = smime;
  agent->sa_flags = flags & MSG_FLG_USERMASK;
  agent->sa_rport = rport != 0;
Pekka Pessi's avatar
Pekka Pessi committed
1686
  agent->sa_tcp_rport = tcp_rport != 0;
1687
  agent->sa_tls_rport = tls_rport != 0;
Pekka Pessi's avatar
Pekka Pessi committed
1688 1689 1690 1691 1692 1693
  agent->sa_preload = preload;
  agent->sa_tport_threadpool = threadpool;

  return n;
}

1694
static
1695
void agent_set_udp_params(nta_agent_t *self, usize_t udp_mtu)
Pekka Pessi's avatar
Pekka Pessi committed
1696 1697 1698 1699 1700
{
  tport_t *tp;

  /* Set via fields for the tports */
  for (tp = tport_primaries(self->sa_tports); tp; tp = tport_next(tp)) {
Pekka Pessi's avatar
Pekka Pessi committed
1701
    if (tport_is_udp(tp))
Pekka Pessi's avatar
Pekka Pessi committed
1702 1703
      tport_set_params(tp,
		       TPTAG_TIMEOUT(2 * self->sa_t1x64),
1704
		       TPTAG_MTU(udp_mtu),
Pekka Pessi's avatar
Pekka Pessi committed
1705 1706 1707 1708 1709 1710 1711 1712 1713
		       TAG_END());
  }
}

/**Get NTA Parameters.
 *
 * The nta_agent_get_params() function retrieves the stack parameters. The
 * parameters determine the way NTA handles the retransmissions, how long
 * NTA keeps transactions alive, does NTA apply proxy or user-agent logic to
1714
 * INVITE transactions, or how the @Via headers are generated.
Pekka Pessi's avatar
Pekka Pessi committed
1715 1716
 *
 * @TAGS
1717
 * NTATAG_ALIASES_REF(), NTATAG_BLACKLIST_REF(),
1718
 * NTATAG_CANCEL_2543_REF(), NTATAG_CANCEL_487_REF(),
1719
 * NTATAG_CLIENT_RPORT_REF(), NTATAG_CONTACT_REF(),
1720
 * NTATAG_DEBUG_DROP_PROB_REF(), NTATAG_DEFAULT_PROXY_REF(),
1721
 * NTATAG_EXTRA_100_REF(), NTATAG_GRAYLIST_REF(),
1722
 * NTATAG_MAXSIZE_REF(), NTATAG_MAX_FORWARDS_REF(), NTATAG_MCLASS_REF(),
Michael Jerris's avatar
Michael Jerris committed
1723
 * NTATAG_MERGE_482_REF(), NTATAG_MAX_PROCEEDING_REF(),
1724 1725
 * NTATAG_PASS_100_REF(), NTATAG_PASS_408_REF(), NTATAG_PRELOAD_REF(),
 * NTATAG_PROGRESS_REF(),
1726 1727
 * NTATAG_REL100_REF(),
 * NTATAG_SERVER_RPORT_REF(),
1728 1729 1730
 * NTATAG_SIGCOMP_ALGORITHM_REF(), NTATAG_SIGCOMP_OPTIONS_REF(),
 * NTATAG_SIPFLAGS_REF(),
 * NTATAG_SIP_T1_REF(), NTATAG_SIP_T1X64_REF(), NTATAG_SIP_T2_REF(),
Pekka Pessi's avatar
Pekka Pessi committed
1731
 * NTATAG_SIP_T4_REF(), NTATAG_SMIME_REF(), NTATAG_STATELESS_REF(),
1732
 * NTATAG_TAG_3261_REF(), NTATAG_TIMEOUT_408_REF(), NTATAG_TIMER_C_REF(),
1733
 * NTATAG_UA_REF(), NTATAG_UDP_MTU_REF(), NTATAG_USER_VIA_REF(),
1734 1735
 * NTATAG_USE_NAPTR_REF(), NTATAG_USE_SRV_REF(),
 * and NTATAG_USE_TIMESTAMP_REF().
Pekka Pessi's avatar
Pekka Pessi committed
1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747
 *
 */
int nta_agent_get_params(nta_agent_t *agent,
			 tag_type_t tag, tag_value_t value, ...)
{
  int n;
  ta_list ta;

  if (agent) {
    ta_start(ta, tag, value);
    n = agent_get_params(agent, ta_args(ta));
    ta_end(ta);
1748
    return n;
Pekka Pessi's avatar
Pekka Pessi committed
1749 1750
  }

1751 1752
  su_seterrno(EINVAL);
  return -1;
Pekka Pessi's avatar
Pekka Pessi committed
1753 1754 1755 1756 1757 1758 1759 1760 1761 1762
}

/** Get NTA parameters */
static
int agent_get_params(nta_agent_t *agent, tagi_t *tags)
{
  return
    tl_tgets(tags,
	     NTATAG_ALIASES(agent->sa_aliases),
	     NTATAG_BLACKLIST(agent->sa_blacklist),
1763 1764 1765 1766
	     NTATAG_CANCEL_2543(agent->sa_cancel_2543),
	     NTATAG_CANCEL_487(agent->sa_cancel_487),
	     NTATAG_CLIENT_RPORT(agent->sa_rport),
	     NTATAG_CONTACT(agent->sa_contact),