test_proxy.c 37.7 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 29 30 31 32 33 34 35 36 37
/*
 * 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 test_proxy.c
 * @brief Extremely simple proxy and registrar for testing nua
 *
 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
 *
 * @date Created: Thu Nov  3 22:49:46 EET 2005
 */

#include "config.h"

#include <string.h>

struct proxy;
38 39 40 41
struct domain;
union proxy_or_domain;
struct proxy_tr;
struct client_tr;
42
struct registration_entry;
43
struct binding;
44 45

#define SU_ROOT_MAGIC_T struct proxy
46 47 48
#define NTA_LEG_MAGIC_T union proxy_or_domain
#define NTA_OUTGOING_MAGIC_T struct client_tr
#define NTA_INCOMING_MAGIC_T struct proxy_tr
49
#define SU_TIMER_ARG_T struct proxy_tr
50

51 52 53 54 55 56 57 58
#include <sofia-sip/su_wait.h>
#include <sofia-sip/nta.h>
#include <sofia-sip/sip_header.h>
#include <sofia-sip/sip_status.h>
#include <sofia-sip/sip_util.h>
#include <sofia-sip/auth_module.h>
#include <sofia-sip/su_tagarg.h>
#include <sofia-sip/msg_addr.h>
59
#include <sofia-sip/hostdomain.h>
60 61
#include <sofia-sip/tport.h>
#include <sofia-sip/nta_tport.h>
62 63 64

#include <stdlib.h>
#include <assert.h>
65 66 67

#define LIST_PROTOS(STORAGE, PREFIX, T)			 \
STORAGE void PREFIX ##_insert(T **list, T *node),	 \
68
  PREFIX ##_remove(T *node)
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

#define LIST_BODIES(STORAGE, PREFIX, T, NEXT, PREV)	  \
STORAGE void PREFIX ##_insert(T **list, T *node)   \
{							 \
  if ((node->NEXT = *list)) {				 \
    node->PREV = node->NEXT->PREV;			 \
    node->NEXT->PREV = &node->NEXT;			 \
  }							 \
  else							 \
    node->PREV = list;					 \
  *list = node;						 \
}							 \
STORAGE void PREFIX ##_remove(T *node)			 \
{							 \
  if (node->PREV)					 \
    if ((*node->PREV = node->NEXT))			 \
      node->NEXT->PREV = node->PREV;			 \
  node->PREV = NULL;					 \
}							 \
extern int LIST_DUMMY_VARIABLE

Pekka Pessi's avatar
Pekka Pessi committed
90
#include "test_proxy.h"
91
#include <sofia-sip/auth_module.h>
92

93 94
struct proxy {
  su_home_t    home[1];
95
  void        *magic;
96
  su_root_t   *parent;
97
  su_clone_r   clone;
98 99
  tagi_t      *tags;

100
  su_root_t   *root;
101

102 103
  nta_agent_t *agent;
  url_t const *uri;
104 105
  sip_route_t *lr;
  char const *lr_str;
106
  url_t const *rr_uri;
107

108
  nta_leg_t *defleg;
109 110 111

  sip_contact_t *transport_contacts;

112 113
  struct proxy_tr *stateless;
  struct proxy_tr *transactions;
114
  struct proxy_tr *invite_waiting;
115 116

  struct domain *domains;
117 118

  struct {
119
    unsigned t1x64;
120
    sip_time_t session_expires, min_se;
121
  } prefs;
122
};
123

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
struct domain {
  su_home_t home[1];
  void *magic;
  struct proxy *proxy;
  struct domain *next, **prev;

  url_t *uri;

  nta_leg_t *rleg, *uleg;

  auth_mod_t *auth;
  struct registration_entry *entries;

  struct {
    sip_time_t min_expires, expires, max_expires;
    int outbound_tcp;		/**< Use inbound TCP connection as outbound */
140
    char const *authorize;	/**< Authorization realm to use */
141
    int record_route;
142
  } prefs;
143 144 145 146 147 148 149 150 151 152 153

  tagi_t *tags;
};

LIST_PROTOS(static, domain, struct domain);
static int _domain_init(void *_d);
static int  domain_init(struct domain *domain);
static void domain_destroy(struct domain *domain);

LIST_BODIES(static, domain, struct domain, next, prev);

154
LIST_PROTOS(static, registration_entry, struct registration_entry);
155
static struct registration_entry *registration_entry_new(struct domain *,
156
							 url_t const *);
157 158 159 160 161
static void registration_entry_destroy(struct registration_entry *e);

struct registration_entry
{
  struct registration_entry *next, **prev;
162
  struct domain *domain;	/* backpointer */
163
  url_t *aor;			/* address-of-record */
164 165
  struct binding *bindings;	/* list of bindings */
  sip_contact_t *contacts;
166 167
};

168 169 170
struct binding
{
  struct binding *next, **prev;
171
  sip_contact_t *contact;	/* binding */
172
  sip_time_t registered, expires; /* When registered and when expires */
173
  sip_call_id_t *call_id;
174
  uint32_t cseq;
175
  tport_t *tport;		/**< Reference to tport */
176 177
};

178
static struct binding *binding_new(su_home_t *home,
179
				   sip_contact_t *contact,
180
				   tport_t *tport,
181
				   sip_call_id_t const *call_id,
182
				   uint32_t cseq,
183
				   sip_time_t registered,
184 185 186 187
				   sip_time_t expires);
static void binding_destroy(su_home_t *home, struct binding *b);
static int binding_is_active(struct binding const *b)
{
188
  return
189
    b->expires > sip_now() &&
190
    (b->tport == NULL || tport_is_clear_to_send(b->tport));
191 192
}

193 194
LIST_PROTOS(static, proxy_tr, struct proxy_tr);
struct proxy_tr *proxy_tr_new(struct proxy *);
195
static void proxy_tr_timeout(struct proxy_tr *t);
196
static void proxy_tr_destroy(struct proxy_tr *t);
197

198
struct proxy_tr
199
{
200
  struct proxy_tr *next, **prev;
201

202
  struct proxy *proxy;		/**< Backpointer to proxy */
203

204 205
  struct domain *origin;	/**< Originating domain */
  struct domain *domain;	/**< Destination domain */
206

207
  sip_time_t now;		/**< When received */
208

209 210 211
  nta_incoming_t *server;	/**< server transaction */
  msg_t *msg;			/**< request message */
  sip_t *sip;			/**< request headers */
212

213
  sip_method_t method;		/**< request method */
214
  char const *method_name;
215 216
  int status;			/**< best status */
  url_t *target;		/**< request-URI */
217

218
  struct client_tr *clients;	/**< Client transactions */
219 220

  struct registration_entry *entry;
221
				/**< Registration entry */
222

223 224 225 226 227 228
  auth_mod_t *am;		/**< Authentication module */
  auth_status_t *as;		/**< Authentication status */
  char const *realm;		/**< Authentication realm to use */
  unsigned use_auth;		/**< Authentication method (401/407) to use */

  su_timer_t *timer;		/**< Timer */
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244

  unsigned rr:1;
};

LIST_PROTOS(static, client_tr, struct client_tr);

struct client_tr
{
  struct client_tr *next, **prev;
  struct proxy_tr *t;

  int status;			/* response status */
  sip_request_t *rq;		/* request line */
  msg_t *msg;			/* request message */
  sip_t *sip;			/* request headers */
  nta_outgoing_t *client;	/* transaction */
245 246
};

247 248
LIST_BODIES(static, client_tr, struct client_tr, next, prev);

249 250
static sip_contact_t *create_transport_contacts(struct proxy *p);

251 252 253
union proxy_or_domain { struct proxy proxy[1]; struct domain domain[1]; };

static int proxy_request(union proxy_or_domain *proxy,
254
			 nta_leg_t *leg,
255
			 nta_incoming_t *irq,
256 257
			 sip_t const *sip);

258
static int domain_request(union proxy_or_domain *domain,
259 260 261 262
			  nta_leg_t *leg,
			  nta_incoming_t *irq,
			  sip_t const *sip);

263 264
static int proxy_response(struct client_tr *client,
			   nta_outgoing_t *orq,
265 266
			   sip_t const *sip);

267 268
static int close_tports(void *proxy);

269 270
static auth_challenger_t registrar_challenger[1];
static auth_challenger_t proxy_challenger[1];
271

272
/* Proxy entry point */
273
static int
274 275
test_proxy_init(su_root_t *root, struct proxy *proxy)
{
276 277
  struct proxy_tr *t;
  struct client_tr *c;
278

279 280
  auth_challenger_t _proxy_challenger[1] =
  {{
281 282 283 284 285
      SIP_407_PROXY_AUTH_REQUIRED,
      sip_proxy_authenticate_class,
      sip_proxy_authentication_info_class
    }};

286 287
  auth_challenger_t _registrar_challenger[1] =
  {{
288
      SIP_401_UNAUTHORIZED,
289 290 291
      sip_www_authenticate_class,
      sip_authentication_info_class
    }};
292 293

  *proxy_challenger = *_proxy_challenger;
294 295
  *registrar_challenger = *_registrar_challenger;

296 297 298
  proxy->root = root;

  proxy->agent = nta_agent_create(root,
299
				  URL_STRING_MAKE("sip:0.0.0.0:*"),
300 301
				  NULL, NULL,
				  NTATAG_UA(0),
302
				  NTATAG_CANCEL_487(0),
303 304
				  NTATAG_SERVER_RPORT(1),
				  NTATAG_CLIENT_RPORT(1),
305
				  TAG_NEXT(proxy->tags));
306

307 308 309
  if (!proxy->agent)
    return -1;

310 311 312
  proxy->transport_contacts = create_transport_contacts(proxy);

  proxy->defleg = nta_leg_tcreate(proxy->agent,
313
				  proxy_request,
314
				  (union proxy_or_domain *)proxy,
315 316 317
				  NTATAG_NO_DIALOG(1),
				  TAG_END());

318 319
  proxy->prefs.session_expires = 180;
  proxy->prefs.min_se = 90;
320 321 322 323 324
  proxy->prefs.t1x64 = 64 * 500;

  nta_agent_get_params(proxy->agent,
		       NTATAG_SIP_T1X64_REF(proxy->prefs.t1x64),
		       TAG_END());
325

326
  if (!proxy->defleg)
327
    return -1;
328 329
  /* if (!proxy->example_net || !proxy->example_org || !proxy->example_com)
     return -1; */
330

331 332
  /* Create stateless client */
  t = su_zalloc(proxy->home, sizeof *t);
333
  c = su_zalloc(proxy->home, sizeof *c);
334

335
  if (!t || !c)
336 337 338 339
    return -1;

  proxy->stateless = t;
  t->proxy = proxy;
340
  c->t = t, client_tr_insert(&t->clients, c);
341
  t->server = nta_incoming_default(proxy->agent);
342
  c->client = nta_outgoing_default(proxy->agent, proxy_response, c);
343

344
  if (!c->client || !t->server)
345 346
    return -1;

347
  proxy->uri = nta_agent_contact(proxy->agent)->m_url;
348 349 350 351 352
  proxy->lr_str = su_sprintf(proxy->home, "<" URL_PRINT_FORMAT ";lr>", URL_PRINT_ARGS(proxy->uri));
  proxy->lr = sip_route_make(proxy->home, proxy->lr_str);

  if (!proxy->lr)
    return -1;
353

354 355 356 357 358 359
  return 0;
}

static void
test_proxy_deinit(su_root_t *root, struct proxy *proxy)
{
360
  struct proxy_tr *t;
361

362 363 364
  while (proxy->transactions)
    proxy_tr_destroy(proxy->transactions);

365
  if ((t = proxy->stateless)) {
366 367
    proxy->stateless = NULL;
    proxy_tr_destroy(t);
368 369
  }

370 371
  while (proxy->domains)
    domain_destroy(proxy->domains);
372

373 374
  nta_agent_destroy(proxy->agent);

375
  free(proxy->tags);
376 377
}

378
/* Create test proxy object */
379
struct proxy *test_proxy_create(su_root_t *root,
380
				tag_type_t tag, tag_value_t value, ...)
381 382 383 384
{
  struct proxy *p = su_home_new(sizeof *p);

  if (p) {
385 386
    ta_list ta;

387 388
    p->magic = test_proxy_create;

389 390
    p->parent = root;

391 392 393
    ta_start(ta, tag, value);
    p->tags = tl_llist(ta_tags(ta));
    ta_end(ta);
394

395 396
    if (su_clone_start(root,
		       p->clone,
397
		       p,
398 399 400 401 402 403 404
		       test_proxy_init,
		       test_proxy_deinit) == -1)
      su_home_unref(p->home), p = NULL;
  }

  return p;
}
405 406

/* Destroy the proxy object */
407 408 409
void test_proxy_destroy(struct proxy *p)
{
  if (p) {
410
    su_clone_wait(p->parent, p->clone);
411 412 413 414
    su_home_unref(p->home);
  }
}

415 416 417 418 419 420
/* Return the proxy URI */
url_t const *test_proxy_uri(struct proxy const *p)
{
  return p ? p->uri : NULL;
}

421 422 423 424 425 426 427 428 429 430 431 432 433
/* Return the proxy route URI */
char const *test_proxy_route_uri(struct proxy const *p,
				 sip_route_t const **return_route)
{
  if (p == NULL)
    return NULL;

  if (return_route)
    *return_route = p->lr;

  return p->lr_str;
}

434 435 436 437
struct _set_logging {
  struct proxy *p;
  int logging;
};
438

439 440 441 442 443 444 445 446 447 448 449 450 451 452
static int _set_logging(void *_a)
{
  struct _set_logging *a = _a;
  return nta_agent_set_params(a->p->agent, TPTAG_LOG(a->logging), TAG_END());
}

void test_proxy_set_logging(struct proxy *p, int logging)
{
  if (p) {
    struct _set_logging a[1] = {{ p, logging }};
    su_task_execute(su_clone_task(p->clone), _set_logging, a, NULL);
  }
}

453
void test_proxy_domain_set_expiration(struct domain *d,
454 455
				      sip_time_t min_expires,
				      sip_time_t expires,
456
				      sip_time_t max_expires)
457
{
458 459 460 461
  if (d) {
    d->prefs.min_expires = min_expires;
    d->prefs.expires = expires;
    d->prefs.max_expires = max_expires;
462 463 464
  }
}

465 466 467 468
void test_proxy_domain_get_expiration(struct domain *d,
				      sip_time_t *return_min_expires,
				      sip_time_t *return_expires,
				      sip_time_t *return_max_expires)
469
{
470 471 472 473
  if (d) {
    if (return_min_expires) *return_min_expires = d->prefs.min_expires;
    if (return_expires) *return_expires = d->prefs.expires;
    if (return_max_expires) *return_max_expires = d->prefs.max_expires;
474 475 476
  }
}

477
void test_proxy_set_session_timer(struct proxy *p,
478
				  sip_time_t session_expires,
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
				  sip_time_t min_se)
{
  if (p) {
    p->prefs.session_expires = session_expires;
    p->prefs.min_se = min_se;
  }
}

void test_proxy_get_session_timer(struct proxy *p,
				  sip_time_t *return_session_expires,
				  sip_time_t *return_min_se)
{
  if (p) {
    if (return_session_expires)
      *return_session_expires = p->prefs.session_expires;
    if (return_min_se) *return_min_se = p->prefs.min_se;
  }
}

498 499
void test_proxy_domain_set_outbound(struct domain *d,
				    int use_outbound)
500
{
501 502
  if (d) {
    d->prefs.outbound_tcp = use_outbound;
503 504 505
  }
}

506 507
void test_proxy_domain_get_outbound(struct domain *d,
				    int *return_use_outbound)
508
{
509
  if (d) {
510
    if (return_use_outbound)
511 512 513 514
      *return_use_outbound = d->prefs.outbound_tcp;
  }
}

515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
void test_proxy_domain_set_record_route(struct domain *d,
					int use_record_route)
{
  if (d) {
    d->prefs.record_route = use_record_route;
  }
}

void test_proxy_domain_get_record_route(struct domain *d,
					int *return_use_record_route)
{
  if (d) {
    if (return_use_record_route)
      *return_use_record_route = d->prefs.record_route;
  }
}

532
int test_proxy_domain_set_authorize(struct domain *d,
533
				     char const *realm)
534 535
{
  if (d) {
536 537 538 539 540 541 542 543 544
    if (realm) {
      realm = su_strdup(d->home, realm);
      if (!realm)
	return -1;
    }

    d->prefs.authorize = realm;

    return 0;
545
  }
546
  return -1;
547 548
}

549 550
int test_proxy_domain_get_authorize(struct domain *d,
				     char const **return_realm)
551 552
{
  if (d) {
553 554 555 556
    if (return_realm) {
      *return_realm = d->prefs.authorize;
      return 0;
    }
557
  }
558
  return -1;
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
}

int test_proxy_close_tports(struct proxy *p)
{
  if (p) {
    int retval = -EPROTO;

    su_task_execute(su_clone_task(p->clone), close_tports, p, &retval);

    if (retval < 0)
      return errno = -retval, -1;
    else
      return 0;
  }
  return errno = EFAULT, -1;
}

576 577
/* ---------------------------------------------------------------------- */

578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604
struct domain *test_proxy_add_domain(struct proxy *p,
				     url_t const *uri,
				     tag_type_t tag, tag_value_t value, ...)
{
  struct domain *d;

  if (p == NULL || uri == NULL)
    return NULL;

  d = su_home_clone(p->home, sizeof *d);

  if (d) {
    ta_list ta;
    int init = 0;

    ta_start(ta, tag, value);

    d->magic = domain_init;

    d->proxy = p;
    d->uri = url_hdup(d->home, uri);
    d->tags = tl_adup(d->home, ta_args(ta));

    d->prefs.min_expires = 300;
    d->prefs.expires = 3600;
    d->prefs.max_expires = 36000;
    d->prefs.outbound_tcp = 0;
605
    d->prefs.authorize = NULL;
606

607
    if (d->uri && d->tags &&
608 609 610 611 612 613
	!su_task_execute(su_clone_task(p->clone), _domain_init, d, &init)) {
      if (init == 0)
	/* OK */;
      else
	d = NULL;
    }
614
    else
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
      su_home_unref(d->home);
  }

  return d;
}

static int _domain_init(void *_d)
{
  return domain_init(_d);
}

static int domain_init(struct domain *d)
{
  struct proxy *p = d->proxy;
  url_t uri[1];

  *uri = *d->uri;

  d->auth = auth_mod_create(p->root, TAG_NEXT(d->tags));

  /* Leg for URIs without userpart */
  d->rleg = nta_leg_tcreate(d->proxy->agent,
			    domain_request,
			    (union proxy_or_domain *)d,
			    NTATAG_NO_DIALOG(1),
			    URLTAG_URL(uri),
			    TAG_END());

  /* Leg for URIs with wildcard userpart */
  uri->url_user = "%";
  d->uleg = nta_leg_tcreate(d->proxy->agent,
			    domain_request,
			    (union proxy_or_domain *)d,
			    NTATAG_NO_DIALOG(1),
			    URLTAG_URL(uri),
			    TAG_END());

  if (d->auth && d->rleg && d->uleg) {
    domain_insert(&p->domains, d);
    return 0;
  }

  domain_destroy(d);

  return -1;
}

static void domain_destroy(struct domain *d)
{
  while (d->entries)
    registration_entry_destroy(d->entries);

  nta_leg_destroy(d->rleg), d->rleg = NULL;
  nta_leg_destroy(d->uleg), d->uleg = NULL;
  auth_mod_destroy(d->auth), d->auth = NULL;

  domain_remove(d);

  su_home_unref(d->home);
}

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

678 679 680 681 682 683 684 685 686 687 688 689
static sip_contact_t *create_transport_contacts(struct proxy *p)
{
  su_home_t *home = p->home;
  sip_via_t *v;
  sip_contact_t *retval = NULL, **mm = &retval;

  if (!p->agent)
    return NULL;

  for (v = nta_agent_via(p->agent); v; v = v->v_next) {
    char const *proto = v->v_protocol;

690
    if (v->v_next &&
691
	su_casematch(v->v_host, v->v_next->v_host) &&
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
	str0cmp(v->v_port, v->v_next->v_port) == 0 &&
	((proto == sip_transport_udp &&
	  v->v_next->v_protocol == sip_transport_tcp) ||
	 (proto == sip_transport_tcp &&
	  v->v_next->v_protocol == sip_transport_udp)))
      /* We have udp/tcp pair, insert URL without tport parameter */
      *mm = sip_contact_create_from_via_with_transport(home, v, NULL, NULL);
    if (*mm) mm = &(*mm)->m_next;

    *mm = sip_contact_create_from_via_with_transport(home, v, NULL, proto);

    if (*mm) mm = &(*mm)->m_next;
  }

  return retval;
}

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

711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734
static int proxy_tr_with(struct proxy *proxy,
			 struct domain *domain,
			 nta_incoming_t *irq,
			 sip_t const *sip,
			 int (*process)(struct proxy_tr *));
static int proxy_transaction(struct proxy_tr *t);
static int respond_transaction(struct proxy_tr *t,
			       int status, char const *phrase,
			       tag_type_t tag, tag_value_t value,
			       ...);
static int validate_transaction(struct proxy_tr *t);
static int originating_transaction(struct proxy_tr *t);
static int challenge_transaction(struct proxy_tr *t);
static int session_timers(struct proxy_tr *t);
static int incoming_transaction(struct proxy_tr *t);
static int target_transaction(struct proxy_tr *t,
			      url_t const *target,
			      tport_t *tport);
static int process_register(struct proxy_tr *t);
static int process_options(struct proxy_tr *t);

static int proxy_ack_cancel(struct proxy_tr *t,
			    nta_incoming_t *irq,
			    sip_t const *sip);
735

736 737 738 739 740 741 742
static struct registration_entry *
registration_entry_find(struct domain const *domain, url_t const *uri);

static int proxy_request(union proxy_or_domain *pod,
			 nta_leg_t *leg,
			 nta_incoming_t *irq,
			 sip_t const *sip)
743
{
744 745 746 747 748 749 750 751 752 753 754
  assert(pod->proxy->magic = test_proxy_init);

  return proxy_tr_with(pod->proxy, NULL, irq, sip, proxy_transaction);
}

static int domain_request(union proxy_or_domain *pod,
			  nta_leg_t *leg,
			  nta_incoming_t *irq,
			  sip_t const *sip)
{
  int (*process)(struct proxy_tr *) = NULL;
755
  sip_method_t method = sip->sip_request->rq_method;
756

757 758 759 760 761 762
  assert(pod->domain->magic = domain_init);

  if (leg == pod->domain->uleg)
    process = proxy_transaction;
  else if (method == sip_method_register)
    process = process_register;
763
  else if (method == sip_method_options)
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
    process = process_options;

  if (process == NULL)
    return 501;			/* Not implemented */

  return proxy_tr_with(pod->domain->proxy, pod->domain, irq, sip, process);
}

static int proxy_tr_with(struct proxy *proxy,
			 struct domain *domain,
			 nta_incoming_t *irq,
			 sip_t const *sip,
			 int (*process)(struct proxy_tr *))
{
  struct proxy_tr *t = NULL;
  int status = 500;

  assert(proxy->magic = test_proxy_init);

  t = proxy_tr_new(proxy);
  if (t) {
    t->proxy = proxy, t->domain = domain, t->server = irq;
    t->msg = nta_incoming_getrequest(irq);
    t->sip = sip_object(t->msg);

    t->method = sip->sip_request->rq_method;
790
    t->method_name = sip->sip_request->rq_method_name;
791 792 793 794 795 796
    t->target = sip->sip_request->rq_url;
    t->now = nta_incoming_received(irq, NULL);

    if (t->method != sip_method_ack && t->method != sip_method_cancel)
      nta_incoming_bind(irq, proxy_ack_cancel, t);

797 798 799
    if (domain && domain->prefs.record_route)
      t->rr = 1;

800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828
    if (process(t) < 200)
      return 0;

    proxy_tr_destroy(t);
  }
  else {
    nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
  }

  return status;
}

/** Forward request */
static int proxy_transaction(struct proxy_tr *t)
{
  if (originating_transaction(t))
    return t->status;

  if (validate_transaction(t))
    return t->status;

  if (session_timers(t))
    return t->status;

  if (t->domain)
    return incoming_transaction(t);

  return target_transaction(t, t->target, NULL);
}
829

830 831 832 833 834 835 836 837 838 839 840 841
static int respond_transaction(struct proxy_tr *t,
			       int status, char const *phrase,
			       tag_type_t tag, tag_value_t value,
			       ...)
{
  ta_list ta;
  void *info = NULL, *response = NULL;

  ta_start(ta, tag, value);

  if (t->as)
    info = t->as->as_info, response = t->as->as_response;
842 843

  if (nta_incoming_treply(t->server, t->status = status, phrase,
844 845 846 847 848 849
			  SIPTAG_HEADER(info),
			  SIPTAG_HEADER(response),
			  ta_tags(ta)) < 0)
    t->status = status = 500;

  ta_end(ta);
850

851 852 853 854 855 856 857 858 859 860 861 862 863
  return status;
}

static int originating_transaction(struct proxy_tr *t)
{
  struct domain *o;
  char const *host;

  host = t->sip->sip_from->a_url->url_host;
  if (!host)
    return 0;

  for (o = t->proxy->domains; o; o = o->next)
864
    if (su_casematch(host, o->uri->url_host))
865
      break;
866

867 868 869 870
  t->origin = o;

  if (o && o->auth && o->prefs.authorize) {
    t->am = o->auth;
871
    t->realm = o->prefs.authorize;
872 873 874
    t->use_auth = 407;
  }

875 876 877
  if (o && o->prefs.record_route)
    t->rr = 1;

878 879 880 881 882 883 884 885
  return 0;
}

static int validate_transaction(struct proxy_tr *t)
{
  sip_max_forwards_t *mf;

  mf = t->sip->sip_max_forwards;
886 887

  if (mf && mf->mf_count <= 1) {
888 889 890 891
    if (t->method == sip_method_options)
      return process_options(t);

    return respond_transaction(t, SIP_483_TOO_MANY_HOPS, TAG_END());
892 893
  }

894
  /* Remove our routes */
895 896
  while (t->sip->sip_route &&
	 url_has_param(t->sip->sip_route->r_url, "lr") &&
897 898
	 (url_cmp(t->proxy->lr->r_url, t->sip->sip_route->r_url) == 0 ||
	  url_cmp(t->proxy->rr_uri, t->sip->sip_route->r_url) == 0)) {
899 900
    sip_route_remove(t->msg, t->sip);
    /* add record-route also to the forwarded request  */
901
  }
902

903 904
  if (t->use_auth)
    return challenge_transaction(t);
905

906 907 908 909 910 911 912 913 914 915 916 917
  return 0;
}

static int session_timers(struct proxy_tr *t)
{
  sip_t *sip = t->sip;
  sip_session_expires_t *x = NULL, x0[1];
  sip_min_se_t *min_se = NULL, min_se0[1];
  char const *require = NULL;

  if (t->method == sip_method_invite) {
    if (t->proxy->prefs.min_se) {
918
      if (!sip->sip_min_se ||
919
	  sip->sip_min_se->min_delta < t->proxy->prefs.min_se) {
920
	min_se = sip_min_se_init(min_se0);
921
	min_se->min_delta = t->proxy->prefs.min_se;
922 923 924
      }

      if (sip->sip_session_expires
925
	  && sip->sip_session_expires->x_delta < t->proxy->prefs.min_se
926 927 928
	  && sip_has_supported(sip->sip_supported, "timer")) {
	if (min_se == NULL)
	  min_se = sip->sip_min_se; assert(min_se);
929 930 931
	return respond_transaction(t, SIP_422_SESSION_TIMER_TOO_SMALL,
				   SIPTAG_MIN_SE(min_se),
				   TAG_END());
932
      }
933 934
    }

935
    if (t->proxy->prefs.session_expires) {
936
      if (!sip->sip_session_expires ||
937
	  sip->sip_session_expires->x_delta > t->proxy->prefs.session_expires) {
938
	x = sip_session_expires_init(x0);
939
	x->x_delta = t->proxy->prefs.session_expires;
940 941 942
	if (!sip_has_supported(sip->sip_supported, "timer"))
	  require = "timer";
      }
943
    }
944

945 946 947 948 949 950
    if (x || min_se || require)
      sip_add_tl(t->msg, t->sip,
		 SIPTAG_REQUIRE_STR(require),
		 SIPTAG_MIN_SE(min_se),
		 SIPTAG_SESSION_EXPIRES(x),
		 TAG_END());
951 952
  }

953 954
  return 0;
}
955

956 957 958 959
static int incoming_transaction(struct proxy_tr *t)
{
  struct registration_entry *e;
  struct binding *b;
960

961
#if 0
962
  if (sip->sip_request->rq_method == sip_method_register)
963 964
    return process_register(proxy, irq, sip);
#endif
965

966 967 968
  t->entry = e = registration_entry_find(t->domain, t->target);
  if (e == NULL)
    return respond_transaction(t, SIP_404_NOT_FOUND, TAG_END());
969

970
  for (b = e->bindings; b; b = b->next) {
971
    if (binding_is_active(b))
972
      target_transaction(t, b->contact->m_url, b->tport);
973

974 975
    if (t->clients)		/* XXX - enable forking */
      break;
976
  }
977 978 979 980 981 982 983 984 985 986 987 988

  if (t->clients != NULL)
    return 0;

  return respond_transaction(t, SIP_480_TEMPORARILY_UNAVAILABLE, TAG_END());
}

static int target_transaction(struct proxy_tr *t,
			      url_t const *target,
			      tport_t *tport)
{
  struct client_tr *c = su_zalloc(t->proxy->home, sizeof *c);
989
  int stateless = t->method == sip_method_ack;
990 991

  if (c == NULL)
992
    return 500;
993 994 995 996 997 998 999

  c->t = t;
  c->msg = msg_copy(t->msg);
  c->sip = sip_object(c->msg);

  if (c->msg)
    c->rq = sip_request_create(msg_home(c->msg),
1000
			       t->method, t->method_name,
1001 1002 1003 1004 1005
			       (url_string_t *)target,
			       NULL);

  msg_header_insert(c->msg, (msg_pub_t *)c->sip, (msg_header_t *)c->rq);

1006
  if (t->rr) {
1007 1008
    sip_record_route_t rr[1];

1009 1010 1011 1012 1013 1014 1015 1016
    if (t->proxy->rr_uri) {
      *sip_record_route_init(rr)->r_url = *t->proxy->rr_uri;
      msg_header_add_dup(c->msg, (msg_pub_t *)c->sip, (msg_header_t *)rr);
    }
    else if (t->proxy->lr) {
      *sip_record_route_init(rr)->r_url = *t->proxy->lr->r_url;
      msg_header_add_dup(c->msg, (msg_pub_t *)c->sip, (msg_header_t *)rr);
    }
1017 1018
  }

1019 1020 1021 1022 1023 1024 1025
  if (c->rq)
    /* Forward request */
    c->client = nta_outgoing_mcreate(t->proxy->agent,
				     proxy_response, c,
				     NULL,
				     msg_ref_create(c->msg),
				     NTATAG_TPORT(tport),
1026
				     NTATAG_STATELESS(stateless),
1027 1028
				     TAG_END());

1029 1030 1031 1032 1033
  if (!c->client) {
    msg_destroy(c->msg);
    su_free(t->proxy->home, c);
    return 500;
  }
1034

1035
  client_tr_insert(&t->clients, c);
1036

1037
  return stateless ? 200 : 0;
1038 1039
}

1040
static int challenge_transaction(struct proxy_tr *t)
1041 1042
{
  auth_status_t *as;
1043 1044 1045
  sip_t *sip = t->sip;

  assert(t->am);
1046

1047
  t->as = as = auth_status_new(t->proxy->home);
1048
  if (!as)
1049
    return respond_transaction(t, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
1050 1051

  as->as_method = sip->sip_request->rq_method_name;
1052
  as->as_source = msg_addrinfo(t->msg);
1053
  as->as_realm = t->realm;
1054 1055 1056 1057 1058 1059 1060 1061

  as->as_user_uri = sip->sip_from->a_url;
  as->as_display = sip->sip_from->a_display;

  if (sip->sip_payload)
    as->as_body = sip->sip_payload->pl_data,
      as->as_bodylen = sip->sip_payload->pl_len;

1062 1063 1064 1065 1066 1067
  if (t->use_auth == 401)
    auth_mod_check_client(t->am, as, sip->sip_authorization,
			  registrar_challenger);
  else
    auth_mod_check_client(t->am, as, sip->sip_proxy_authorization,
			  proxy_challenger);
1068

1069 1070
  if (as->as_status)
    return respond_transaction(t, as->as_status, as->as_phrase, TAG_END());
1071

1072 1073
  if (as->as_match)
    msg_header_remove(t->msg, (msg_pub_t *)sip, as->as_match);
1074

1075
  return 0;
1076
}
1077

1078
int proxy_ack_cancel(struct proxy_tr *t,
1079
		     nta_incoming_t *irq,
1080 1081
		     sip_t const *sip)
{
1082 1083 1084 1085
  struct client_tr *c;
  int status;

  if (sip == NULL) {		/* timeout */
1086
    proxy_tr_destroy(t);
1087 1088 1089
    return 0;
  }

1090
  if (sip->sip_request->rq_method != sip_method_cancel)
1091
    return 500;
1092 1093 1094 1095 1096 1097 1098

  status = 200;

  for (c = t->clients; c; c = c->next) {
    if (c->client && c->status < 200)
      /*
       * We don't care about response to CANCEL (or ACK)
1099
       * so we give NULL as callback pointer (and nta immediately
1100 1101 1102 1103
       * destroys transaction object or marks it disposable)
       */
      if (nta_outgoing_tcancel(c->client, NULL, NULL, TAG_END()) == NULL)
	status = 500;
1104
  }
1105 1106

  return status;
1107 1108
}

1109
int proxy_response(struct client_tr *c,
1110 1111 1112
		   nta_outgoing_t *client,
		   sip_t const *sip)
{
1113
  int final, timeout = 0;
1114

1115 1116
  assert(c->t);

1117 1118
  if (sip) {
    msg_t *response = nta_outgoing_getresponse(client);
1119
    if (c->t->method == sip_method_invite)
1120
      final = sip->sip_status->st_status >= 300,
1121 1122 1123
	timeout = sip->sip_status->st_status >= 200;
    else
      final = sip->sip_status->st_status >= 200;
1124
    sip_via_remove(response, sip_object(response));
1125
    nta_incoming_mreply(c->t->server, response);
1126 1127
  }
  else {
1128 1129 1130 1131 1132 1133 1134
    int status = nta_outgoing_status(c->client);
    char const *phrase;

    if (status < 300 || status > 699)
      status = 500;
    phrase = sip_status_phrase(status);
    respond_transaction(c->t, status, phrase, TAG_END());
1135 1136 1137 1138
    final = 1;
  }

  if (final)
1139
    proxy_tr_destroy(c->t);
1140 1141
  else if (timeout)
    proxy_tr_timeout(c->t);
1142 1143 1144 1145

  return 0;
}

1146 1147 1148 1149 1150 1151 1152
int proxy_late_response(struct client_tr *c,
			nta_outgoing_t *client,
			sip_t const *sip)
{
  assert(c->t);

  if (sip &&
1153
      sip->sip_status->st_status >= 200 &&
1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
      sip->sip_status->st_status < 300) {
    msg_t *response = nta_outgoing_getresponse(client);
    sip_via_remove(response, sip_object(response));
    nta_incoming_mreply(c->t->server, response);
  }

  return 0;
}

static void proxy_tr_remove_late(su_root_magic_t *magic,
				 su_timer_t *timer,
				 struct proxy_tr *t)
{
  proxy_tr_destroy(t);
}


1171
/** Proxy only late responses
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
 *
 * Keeping the invite transactions live
 */
static void proxy_tr_timeout(struct proxy_tr *t)
{
  struct client_tr *c;

  if (t == t->proxy->stateless)
    return;

  for (c = t->clients; c; c = c->next) {
    if (c->client && c->status < 300) {
      nta_outgoing_bind(c->client, proxy_late_response, c);
      if (c->status < 200) {
	nta_outgoing_tcancel(c->client, NULL, NULL, TAG_END());
      }
    }
  }

  t->timer = su_timer_create(su_root_task(t->proxy->root), t->proxy->prefs.t1x64);
  if (su_timer_set(t->timer, proxy_tr_remove_late, t) < 0) {
    proxy_tr_destroy(t);
  }
}

1197 1198
struct proxy_tr *
proxy_tr_new(struct proxy *proxy)
1199
{
1200
  struct proxy_tr *t;
1201 1202 1203 1204

  t = su_zalloc(proxy->home, sizeof *t);
  if (t) {
    t->proxy = proxy;
1205
    proxy_tr_insert(&proxy->transactions, t);
1206 1207 1208 1209 1210
  }
  return t;
}

static
1211
void proxy_tr_destroy(struct proxy_tr *t)
1212
{
1213 1214
  struct client_tr *c;

1215 1216
  if (t == t->proxy->stateless)
    return;
1217

1218
  proxy_tr_remove(t);
1219

1220 1221
  if (t->as)
    su_home_unref(t->as->as_home), t->as = NULL;
1222

1223 1224 1225 1226 1227 1228
  while (t->clients) {
    client_tr_remove(c = t->clients);
    nta_outgoing_destroy(c->client), c->client = NULL;
    msg_destroy(c->msg), c->msg = NULL;
    su_free(t->proxy->home, c);
  }
1229

1230 1231
  su_timer_destroy(t->timer), t->timer = NULL;

1232 1233
  msg_destroy(t->msg);

1234
  nta_incoming_destroy(t->server);
1235

1236 1237
  su_free(t->proxy->home, t);
}
1238

1239
LIST_BODIES(static, proxy_tr, struct proxy_tr, next, prev);
1240

1241
/* ---------------------------------------------------------------------- */
1242

1243
static int process_options(struct proxy_tr *t)
1244
{
1245 1246 1247
  return respond_transaction(t, SIP_200_OK,
			     SIPTAG_CONTACT(t->proxy->transport_contacts),
			     TAG_END());
1248 1249 1250 1251
}

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

1252 1253 1254 1255
static int check_received_contact(struct proxy_tr *t);
static int validate_contacts(struct proxy_tr *t);
static int check_out_of_order(struct proxy_tr *t);
static int update_bindings(struct proxy_tr *t);
1256

1257
int process_register(struct proxy_tr *t)
1258
{
1259 1260 1261 1262 1263 1264
  /* This is before authentication because we want to be bug-compatible */
  if (check_received_contact(t))
    return t->status;

  if (t->domain->auth) {
    t->am = t->domain->auth, t->use_auth = 401;
1265 1266
    if (t->domain->prefs.authorize)
      t->realm = t->domain->prefs.authorize;
1267 1268 1269
    if (challenge_transaction(t))
      return t->status;
  }
1270

1271 1272
  if (validate_contacts(t))
    return t->status;
1273

1274
  t->entry = registration_entry_find(t->domain, t->sip->sip_to->a_url);
1275

1276 1277
  if (check_out_of_order(t))
    return t->status;
1278

1279
  return update_bindings(t);
1280 1281
}

1282
static int check_received_contact(struct proxy_tr *t)
1283
{
1284
  sip_t *sip = t->sip;
1285 1286 1287 1288
  sip_contact_t *m = sip->sip_contact;
  sip_via_t *v = sip->sip_via;

  if (m && v && v->v_received && m->m_url->url_host
1289
      && !su_casematch(v->v_received, m->m_url->url_host)
1290
      && host_is_ip_address(m->m_url->url_host))
1291
    return respond_transaction(t, 406, "Unacceptable Contact", TAG_END());
1292

1293
  return 0;
1294 1295
}

1296 1297
/* Validate expiration times */
static int validate_contacts(struct proxy_tr *t)
1298
{
1299 1300 1301
  sip_contact_t const *m = t->sip->sip_contact;
  sip_expires_t const *ex = t->sip->sip_expires;
  sip_date_t const *date = t->sip->sip_date;
1302 1303
  sip_time_t expires;

1304 1305 1306 1307 1308 1309 1310 1311
  if (m && m->m_url->url_type == url_any) {
    if (!ex || ex->ex_delta || ex->ex_time || m->m_next)
      return respond_transaction(t, SIP_400_BAD_REQUEST, TAG_END());
    return 0;
  }

  for (; m; m = m->m_next) {
    expires = sip_contact_expires(m, ex, date, t->domain->prefs.expires, t->now);
1312

1313 1314 1315 1316 1317 1318 1319 1320
    if (expires > 0 && expires < t->domain->prefs.min_expires) {
      sip_min_expires_t me[1];

      sip_min_expires_init(me)->me_delta = t->domain->prefs.min_expires;

      return respond_transaction(t, SIP_423_INTERVAL_TOO_BRIEF,
				 SIPTAG_MIN_EXPIRES(me),
				 TAG_END());
1321 1322
    }
  }
1323 1324 1325 1326

  return 0;
}

1327
/** Check for out-of-order register request */
1328
static int check_out_of_order(struct proxy_tr *t)
1329 1330
{
  struct binding const *b;
1331 1332
  sip_call_id_t const *id = t->sip->sip_call_id;
  uint32_t cseq = t->sip->sip_cseq->cs_seq;
1333
  sip_contact_t *m;
1334

1335
  if (t->entry == NULL || !t->sip->sip_contact)
1336 1337
    return 0;

1338 1339
  /* RFC 3261 subsection 10.3 step 6 and step 7 (p. 66): */
  /* Check for reordered register requests */
1340
  for (b = t->entry->bindings; b; b = b->next) {
1341
    if (binding_is_active(b) &&
1342 1343 1344
	strcmp(id->i_id, b->call_id->i_id) == 0 &&
	cseq <= b->cseq) {
      for (m = t->sip->sip_contact; m; m = m->m_next) {
1345 1346
	if (m->m_url->url_type == url_any ||
	    url_cmp_all(m->m_url, b->contact->m_url) == 0)
1347 1348
	  return respond_transaction(t, SIP_500_INTERNAL_SERVER_ERROR,
				     TAG_END());
1349
      }
1350 1351 1352 1353
    }
  }

  return 0;
1354 1355 1356
}

static struct registration_entry *
1357
registration_entry_find(struct domain const *d, url_t const *uri)
1358 1359 1360 1361
{
  struct registration_entry *e;

  /* Our routing table */
1362
  for (e = d->entries; e; e = e->next) {
1363 1364 1365
    if (url_cmp(uri, e->aor) == 0)
      return e;
  }
1366

1367 1368 1369 1370
  return NULL;
}

static struct registration_entry *
1371
registration_entry_new(struct domain *d, url_t const *aor)
1372 1373 1374
{
  struct registration_entry *e;

1375 1376 1377
  if (d == NULL)
    return NULL;