test_proxy.c 25.9 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 38 39
/*
 * 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;
struct proxy_transaction;
struct registration_entry;
40
struct binding;
41 42 43 44 45 46

#define SU_ROOT_MAGIC_T struct proxy
#define NTA_LEG_MAGIC_T struct proxy
#define NTA_OUTGOING_MAGIC_T struct proxy_transaction
#define NTA_INCOMING_MAGIC_T struct proxy_transaction

47 48 49 50 51 52 53 54
#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>
55 56 57

#include <stdlib.h>
#include <assert.h>
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84

#define LIST_PROTOS(STORAGE, PREFIX, T)			 \
STORAGE void PREFIX ##_insert(T **list, T *node),	 \
        PREFIX ##_remove(T *node)			 

#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

#include <test_proxy.h>

85 86
struct proxy {
  su_home_t    home[1];
87
  su_root_t   *parent;
88
  su_clone_r   clone;
89 90
  tagi_t      *tags;

91
  su_root_t   *root;
92 93
  auth_mod_t  *auth;
 
94 95 96 97 98
  nta_agent_t *agent;
  url_t const *uri;
  
  nta_leg_t *defleg;

99 100 101 102 103 104
  nta_leg_t *example_net;
  nta_leg_t *example_org;
  nta_leg_t *example_com;

  sip_contact_t *transport_contacts;

105 106 107
  struct proxy_transaction *stateless;
  struct proxy_transaction *transactions;
  struct registration_entry *entries;
108 109 110

  struct {
    sip_time_t min_expires, expires, max_expires;
111 112
    
    sip_time_t session_expires, min_se;
113 114
  } prefs;
}; 
115

116
LIST_PROTOS(static, registration_entry, struct registration_entry);
117 118
static struct registration_entry *registration_entry_new(struct proxy *,
							 url_t const *);
119 120
static void registration_entry_destroy(struct registration_entry *e);

121

122 123 124 125 126
struct registration_entry
{
  struct registration_entry *next, **prev;
  struct proxy *proxy;		/* backpointer */
  url_t *aor;			/* address-of-record */
127 128
  struct binding *bindings;	/* list of bindings */
  sip_contact_t *contacts;
129 130
};

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
struct binding
{
  struct binding *next, **prev;
  sip_contact_t *contact;	/* bindings */
  sip_time_t registered, expires; /* When registered and when expires */
  sip_call_id_t *call_id;	
  uint32_t cseq;
};

static struct binding *binding_new(su_home_t *home, 
				   sip_contact_t *contact,
				   sip_call_id_t *call_id,
				   uint32_t cseq,
				   sip_time_t registered, 
				   sip_time_t expires);
static void binding_destroy(su_home_t *home, struct binding *b);
static int binding_is_active(struct binding const *b)
{
  return b->expires > sip_now();
}

152 153 154 155 156 157 158 159 160 161 162 163 164 165
LIST_PROTOS(static, proxy_transaction, struct proxy_transaction);
struct proxy_transaction *proxy_transaction_new(struct proxy *);
static void proxy_transaction_destroy(struct proxy_transaction *t);

struct proxy_transaction
{
  struct proxy_transaction *next, **prev;

  struct proxy *proxy;		/* backpointer */
  sip_request_t *rq;		/* request line */
  nta_incoming_t *server;	/* server transaction */
  nta_outgoing_t *client;	/* client transaction */
};

166 167 168
static sip_contact_t *create_transport_contacts(struct proxy *p);

static int proxy_request(struct proxy *proxy,
169
			 nta_leg_t *leg,
170
			 nta_incoming_t *irq,
171 172 173
			 sip_t const *sip);

static int proxy_ack_cancel(struct proxy_transaction *t,
174
			    nta_incoming_t *irq,
175 176 177 178 179 180
			    sip_t const *sip);

static int proxy_response(struct proxy_transaction *t,
			  nta_outgoing_t *client,
			  sip_t const *sip);

181 182
static int process_register(struct proxy *proxy,
			    nta_incoming_t *irq,
183 184
			    sip_t const *sip);

185 186 187 188 189 190 191 192 193
static int domain_request(struct proxy *proxy,
			  nta_leg_t *leg,
			  nta_incoming_t *irq,
			  sip_t const *sip);

static int process_options(struct proxy *proxy,
			   nta_incoming_t *irq,
			   sip_t const *sip);

194 195 196
static struct registration_entry *
registration_entry_find(struct proxy const *proxy, url_t const *uri);

197 198
static auth_challenger_t registrar_challenger[1];
static auth_challenger_t proxy_challenger[1];
199

200 201 202 203
/* Proxy entry point */
static int 
test_proxy_init(su_root_t *root, struct proxy *proxy)
{
204 205
  struct proxy_transaction *t;

206 207 208 209 210 211 212
  auth_challenger_t _proxy_challenger[1] = 
  {{ 
      SIP_407_PROXY_AUTH_REQUIRED,
      sip_proxy_authenticate_class,
      sip_proxy_authentication_info_class
    }};

213 214
  auth_challenger_t _registrar_challenger[1] = 
  {{ 
215
      SIP_401_UNAUTHORIZED,
216 217 218
      sip_www_authenticate_class,
      sip_authentication_info_class
    }};
219 220

  *proxy_challenger = *_proxy_challenger;
221 222
  *registrar_challenger = *_registrar_challenger;

223 224
  proxy->root = root;

225 226
  proxy->auth = auth_mod_create(root, TAG_NEXT(proxy->tags));

227
  proxy->agent = nta_agent_create(root,
228
				  URL_STRING_MAKE("sip:0.0.0.0:*"),
229 230
				  NULL, NULL,
				  NTATAG_UA(0),
231 232
				  NTATAG_SERVER_RPORT(1),
				  NTATAG_CLIENT_RPORT(1),
233
				  TAG_END());
234

235 236 237
  proxy->transport_contacts = create_transport_contacts(proxy);

  proxy->defleg = nta_leg_tcreate(proxy->agent,
238 239 240 241 242
				  proxy_request,
				  proxy,
				  NTATAG_NO_DIALOG(1),
				  TAG_END());

243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
  proxy->example_net = nta_leg_tcreate(proxy->agent,
				       domain_request,
				       proxy,
				       NTATAG_NO_DIALOG(1),
				       URLTAG_URL("sip:example.net"),
				       TAG_END());
  proxy->example_org = nta_leg_tcreate(proxy->agent,
				       domain_request,
				       proxy,
				       NTATAG_NO_DIALOG(1),
				       URLTAG_URL("sip:example.org"),
				       TAG_END());
  proxy->example_com = nta_leg_tcreate(proxy->agent,
				       domain_request,
				       proxy,
				       NTATAG_NO_DIALOG(1),
				       URLTAG_URL("sip:example.com"),
				       TAG_END());

262 263 264 265
  proxy->prefs.min_expires = 30;
  proxy->prefs.expires = 3600;
  proxy->prefs.max_expires = 3600;

266 267 268
  proxy->prefs.session_expires = 180;
  proxy->prefs.min_se = 90;

269 270
  if (!proxy->defleg || 
      !proxy->example_net || !proxy->example_org || !proxy->example_com)
271 272
    return -1;

273
  t = su_zalloc(proxy->home, sizeof *t); 
274 275 276 277 278 279 280 281 282 283 284 285

  if (!t)
    return -1;

  proxy->stateless = t;
  t->proxy = proxy;
  t->server = nta_incoming_default(proxy->agent);
  t->client = nta_outgoing_default(proxy->agent, proxy_response, t);

  if (!t->client || !t->server)
    return -1;

286 287 288 289 290 291 292 293
  proxy->uri = nta_agent_contact(proxy->agent)->m_url;
				  
  return 0;
}

static void
test_proxy_deinit(su_root_t *root, struct proxy *proxy)
{
294
  struct proxy_transaction *t;
295 296
  
  auth_mod_destroy(proxy->auth);
297 298 299 300 301 302

  if ((t = proxy->stateless)) {
    nta_incoming_destroy(t->server), t->server = NULL;
    nta_outgoing_destroy(t->client), t->client = NULL;
  }

303
  nta_agent_destroy(proxy->agent);
304

305 306 307
  while (proxy->entries)
    registration_entry_destroy(proxy->entries);

308
  free(proxy->tags);
309 310 311
}

/* Create tst proxy object */
312
struct proxy *test_proxy_create(su_root_t *root,
313
				tag_type_t tag, tag_value_t value, ...)
314 315 316 317
{
  struct proxy *p = su_home_new(sizeof *p);

  if (p) {
318 319
    ta_list ta;

320 321
    p->parent = root;

322 323 324 325
    ta_start(ta, tag, value);
    p->tags = tl_llist(ta_tags(ta));
    ta_end(ta);
    
326 327
    if (su_clone_start(root,
		       p->clone,
328
		       p,
329 330 331 332 333 334 335
		       test_proxy_init,
		       test_proxy_deinit) == -1)
      su_home_unref(p->home), p = NULL;
  }

  return p;
}
336 337

/* Destroy the proxy object */
338 339 340
void test_proxy_destroy(struct proxy *p)
{
  if (p) {
341
    su_clone_wait(p->parent, p->clone);
342 343 344 345
    su_home_unref(p->home);
  }
}

346 347 348 349 350 351
/* Return the proxy URI */
url_t const *test_proxy_uri(struct proxy const *p)
{
  return p ? p->uri : NULL;
}

352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
void test_proxy_set_expiration(struct proxy *p,
			       sip_time_t min_expires, 
			       sip_time_t expires, 
			       sip_time_t max_expires)
{
  if (p) {
    p->prefs.min_expires = min_expires;
    p->prefs.expires = expires;
    p->prefs.max_expires = max_expires;
  }
}

void test_proxy_get_expiration(struct proxy *p,
			       sip_time_t *return_min_expires,
			       sip_time_t *return_expires,
			       sip_time_t *return_max_expires)
{
  if (p) {
    if (return_min_expires) *return_min_expires = p->prefs.min_expires;
    if (return_expires) *return_expires = p->prefs.expires;
    if (return_max_expires) *return_max_expires = p->prefs.max_expires;
  }
}

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

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;

    if (v->v_next && 
	strcasecmp(v->v_host, v->v_next->v_host) == 0 &&
	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;
}

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

411 412
static int challenge_request(struct proxy *, nta_incoming_t *, sip_t const *);

413 414
/** Forward request */
static
415
int proxy_request(struct proxy *proxy,
416
		  nta_leg_t *leg,
417
		  nta_incoming_t *irq,
418 419 420 421 422
		  sip_t const *sip)
{
  url_t const *request_uri, *target;
  struct proxy_transaction *t = NULL;
  sip_request_t *rq = NULL;
423
  sip_max_forwards_t *mf;
424 425
  sip_method_t method = sip->sip_request->rq_method;

426 427 428
  sip_session_expires_t *x = NULL, x0[1];
  sip_min_se_t *min_se = NULL, min_se0[1];

429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
  mf = sip->sip_max_forwards;

  if (mf && mf->mf_count <= 1) {
    if (sip->sip_request->rq_method == sip_method_options) {
      return process_options(proxy, irq, sip);
    }
    nta_incoming_treply(irq, SIP_483_TOO_MANY_HOPS, TAG_END());
    return 483;
  }

  if (method != sip_method_ack && method != sip_method_cancel && 
      str0casecmp(sip->sip_from->a_url->url_host, "example.net") == 0) {
    /* Challenge everything but CANCEL and ACK coming from Mr. C */
    int status = challenge_request(proxy, irq, sip);
    if (status)
      return status;
  }
446

447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
  if (method == sip_method_invite) {
    if (!sip->sip_min_se || 
	sip->sip_min_se->min_delta < proxy->prefs.min_se) {
      min_se = sip_min_se_init(min_se0);
      min_se->min_delta = proxy->prefs.min_se;
    }

    if (!sip->sip_session_expires) {
      x = sip_session_expires_init(x0);
      x->x_delta = proxy->prefs.session_expires;
    }
    else if (sip->sip_session_expires->x_delta < proxy->prefs.min_se
	     && sip_has_supported(sip->sip_supported, "timer")) {
      if (min_se == NULL)
	min_se = sip->sip_min_se; assert(min_se);
      nta_incoming_treply(irq, SIP_422_SESSION_TIMER_TOO_SMALL,
			  SIPTAG_MIN_SE(min_se),
			  TAG_END());
      return 422;
    }
  }

469 470 471 472 473 474 475 476 477 478 479
  /* We don't do any route processing */
  request_uri = sip->sip_request->rq_url;

  if (!request_uri->url_host || 
      (strcasecmp(request_uri->url_host, "example.org") &&
       strcasecmp(request_uri->url_host, "example.net") &&
       strcasecmp(request_uri->url_host, "example.com"))) {
    target = request_uri;
  }
  else {
    struct registration_entry *e;
480
    struct binding *b;
481 482 483 484 485 486 487 488 489

    if (sip->sip_request->rq_method == sip_method_register) 
      return process_register(proxy, irq, sip);

    e = registration_entry_find(proxy, request_uri);
    if (e == NULL) {
      nta_incoming_treply(irq, SIP_404_NOT_FOUND, TAG_END());
      return 404;
    }
490 491 492 493 494 495 496 497 498 499 500

    for (b = e->bindings; b; b = b->next)
      if (binding_is_active(b))
	break;

    if (b == NULL) {
      nta_incoming_treply(irq, SIP_480_TEMPORARILY_UNAVAILABLE, TAG_END());
      return 480;
    }
    
    target = b->contact->m_url;
501 502 503 504 505 506 507 508 509
  }

  t = proxy_transaction_new(proxy);
  if (t == NULL) {
    nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
    return 500;
  }
  nta_incoming_bind(t->server = irq, proxy_ack_cancel, t);
  
510
  rq = sip_request_create(proxy->home,
511 512
			  sip->sip_request->rq_method,
			  sip->sip_request->rq_method_name,
513
			  (url_string_t *)target,
514 515 516 517 518 519 520 521 522 523 524 525 526
			  NULL);
  if (rq == NULL) {
    nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
    proxy_transaction_destroy(t);
    return 500;
  }
  t->rq = rq;

  /* Forward request */
  t->client = nta_outgoing_mcreate(proxy->agent, proxy_response, t, NULL,
				   nta_incoming_getrequest(irq),
				   /* rewrite request */
				   SIPTAG_REQUEST(rq),
527 528
				   SIPTAG_SESSION_EXPIRES(x),
				   SIPTAG_MIN_SE(min_se),
529 530 531 532 533 534
				   TAG_END());
  if (t->client == NULL) {
    proxy_transaction_destroy(t);
    nta_incoming_treply(irq, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
    return 500;
  }
535 536
  else if (sip->sip_request->rq_method == sip_method_ack)
    proxy_transaction_destroy(t);
537 538 539 540

  return 0;
}

541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
static
int challenge_request(struct proxy *p,
		     nta_incoming_t *irq,
		     sip_t const *sip)
{
  int status;
  auth_status_t *as;
  msg_t *msg;

  as = auth_status_new(p->home);
  if (!as)
    return 500;

  as->as_method = sip->sip_request->rq_method_name;
  msg = nta_incoming_getrequest(irq);
  as->as_source = msg_addrinfo(msg);

  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;

  auth_mod_check_client(p->auth, as, sip->sip_proxy_authorization,
			proxy_challenger);

  if ((status = as->as_status)) {
    nta_incoming_treply(irq,
			as->as_status, as->as_phrase,
			SIPTAG_HEADER((void *)as->as_info),
			SIPTAG_HEADER((void *)as->as_response),
			TAG_END());
  }
  else if (as->as_match) {
    msg_header_remove(msg, NULL, as->as_match);
  }

  msg_destroy(msg);
  su_home_unref(as->as_home);

  return status;
}		      

585
int proxy_ack_cancel(struct proxy_transaction *t,
586
		     nta_incoming_t *irq,
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647
		     sip_t const *sip)
{
  if (sip == NULL) {
    proxy_transaction_destroy(t);
    return 0;
  }

  if (sip->sip_request->rq_method == sip_method_cancel) {
    /* We don't care about response to CANCEL (or ACK)
     * so we give NULL as callback pointer (and nta immediately 
     * destroys transaction object or marks it disposable)
     */
    if (nta_outgoing_tcancel(t->client, NULL, NULL, TAG_END()))
      return 200;
    else
      return 500;
  }
  else {
    return 500;
  }
}

int proxy_response(struct proxy_transaction *t,
		   nta_outgoing_t *client,
		   sip_t const *sip)
{
  int final;

  if (sip) {
    msg_t *response = nta_outgoing_getresponse(client);
    final = sip->sip_status->st_status >= 200;
    sip_via_remove(response, sip_object(response));
    nta_incoming_mreply(t->server, response);
  }
  else {
    final = 1;
    nta_incoming_treply(t->server, SIP_408_REQUEST_TIMEOUT, TAG_END());
  }

  if (final)
    proxy_transaction_destroy(t);

  return 0;
}

struct proxy_transaction *
proxy_transaction_new(struct proxy *proxy)
{
  struct proxy_transaction *t;

  t = su_zalloc(proxy->home, sizeof *t);
  if (t) {
    t->proxy = proxy;
    proxy_transaction_insert(&proxy->transactions, t);
  }
  return t;
}

static
void proxy_transaction_destroy(struct proxy_transaction *t)
{
648 649
  if (t == t->proxy->stateless)
    return;
650 651 652 653 654 655 656 657 658 659 660
  proxy_transaction_remove(t);
  nta_incoming_destroy(t->server);
  nta_outgoing_destroy(t->client);
  su_free(t->proxy->home, t->rq);
  su_free(t->proxy->home, t);
}

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

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

661

662
static
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
int domain_request(struct proxy *proxy,
		   nta_leg_t *leg,
		   nta_incoming_t *irq,
		   sip_t const *sip)
{
  sip_method_t method = sip->sip_request->rq_method;

  if (method == sip_method_register)
    return process_register(proxy, irq, sip);

  if (method == sip_method_options) 
    return process_options(proxy, irq, sip);

  return 501;
}

static
int process_options(struct proxy *proxy,
		    nta_incoming_t *irq,
		    sip_t const *sip)
{
  nta_incoming_treply(irq, SIP_200_OK,
		      SIPTAG_CONTACT(proxy->transport_contacts),
		      TAG_END());
  return 200;
}

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

692

693 694 695 696 697 698 699 700 701
static int process_register2(struct proxy *p, auth_status_t *as,
			      nta_incoming_t *irq, sip_t const *sip);

static int set_status(auth_status_t *as, int status, char const *phrase);

static int validate_contacts(struct proxy *p, auth_status_t *as,
			     sip_t const *sip);
static int check_out_of_order(struct proxy *p, auth_status_t *as,
			      struct registration_entry *e, sip_t const *);
702
static int binding_update(struct proxy *p,
703 704 705
       		   auth_status_t *as,
       		   struct registration_entry *e,
       		   sip_t const *sip);
706 707

sip_contact_t *binding_contacts(su_home_t *home, struct binding *bindings);
708

709
int process_register(struct proxy *proxy,
710 711
       	      nta_incoming_t *irq,
       	      sip_t const *sip)
712
{
713
  auth_status_t *as;
714
  msg_t *msg;
715
  int status;
716

717 718 719
  as = auth_status_new(proxy->home);
  if (!as)
    return 500;
720 721

  as->as_method = sip->sip_request->rq_method_name;
722 723 724
  msg = nta_incoming_getrequest(irq);
  as->as_source = msg_addrinfo(msg);
  msg_destroy(msg);
725 726 727 728 729

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

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

733 734
  process_register2(proxy, as, irq, sip);
  assert(as->as_status >= 200);
735

736 737 738 739 740 741
  nta_incoming_treply(irq,
       	       as->as_status, as->as_phrase,
       	       SIPTAG_HEADER((void *)as->as_info),
       	       SIPTAG_HEADER((void *)as->as_response),
       	       TAG_END());
  status = as->as_status;
742

743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759
  su_home_unref(as->as_home);

  return status;
}

static int process_register2(struct proxy *p,
			     auth_status_t *as,
			     nta_incoming_t *irq,
			     sip_t const *sip)
{
  struct registration_entry *e = NULL;

  auth_mod_check_client(p->auth, as, sip->sip_authorization,
			registrar_challenger);
  if (as->as_status)
    return as->as_status;
  assert(as->as_response == NULL);
760

761 762
  if (validate_contacts(p, as, sip))
    return as->as_status;
763

764
  e = registration_entry_find(p, sip->sip_to->a_url);
765
  if (!sip->sip_contact) {
766 767
    as->as_response = (msg_header_t *)e->contacts;
    return set_status(as, SIP_200_OK);
768 769
  }

770 771 772
  if (e && check_out_of_order(p, as, e, sip))
    return as->as_status;
  
773
  if (!e) 
774 775 776
    e = registration_entry_new(p, sip->sip_to->a_url);
  if (!e)
    return set_status(as, SIP_500_INTERNAL_SERVER_ERROR);
777

778 779
  if (binding_update(p, as, e, sip))
    return as->as_status;
780

781 782
  msg_header_free(p->home, (void *)e->contacts);
  e->contacts = binding_contacts(p->home, e->bindings);
783

784
  as->as_response = (msg_header_t *)e->contacts;
785

786
  return set_status(as, SIP_200_OK);
787 788
}

789 790 791 792 793 794 795 796
static int set_status(auth_status_t *as, int status, char const *phrase)
{
  return as->as_phrase = phrase, as->as_status = status;
}

static int validate_contacts(struct proxy *p,
			     auth_status_t *as,
			     sip_t const *sip)
797 798
{
  sip_contact_t const *m;
799 800
  sip_time_t expires;
  sip_time_t now = sip_now();
801 802 803

  for (m = sip->sip_contact; m; m = m->m_next) {
    if (m->m_url->url_type == url_any) {
804 805 806 807
      if (!sip->sip_expires ||
	  sip->sip_expires->ex_delta || 
	  sip->sip_expires->ex_time ||
	  sip->sip_contact->m_next)
808
	return set_status(as, SIP_400_BAD_REQUEST);
809
      else
810 811 812 813 814 815 816 817 818 819 820
	return 0;
    }

    expires = sip_contact_expires(m, sip->sip_expires, sip->sip_date,
				  p->prefs.expires, now);
    
    if (expires > 0 && expires < p->prefs.min_expires) {
      as->as_response = (msg_header_t *)
	sip_min_expires_format(as->as_home, "%u", 
			       (unsigned)p->prefs.min_expires);
      return set_status(as, SIP_423_INTERVAL_TOO_BRIEF);
821 822
    }
  }
823 824 825 826

  return 0;
}

827
/** Check for out-of-order register request */
828
static
829 830 831 832
int check_out_of_order(struct proxy *p,
		       auth_status_t *as,
		       struct registration_entry *e,
		       sip_t const *sip)
833 834 835
{
  struct binding const *b;
  sip_call_id_t const *id;
836
  sip_contact_t *m;
837

838
  if (e == NULL || !sip->sip_contact)
839 840
    return 0;

841
  id = sip->sip_call_id;
842
  
843 844
  /* RFC 3261 subsection 10.3 step 6 and step 7 (p. 66): */
  /* Check for reordered register requests */
845 846 847
  for (b = e->bindings; b; b = b->next) {
    if (binding_is_active(b) &&
	strcmp(sip->sip_call_id->i_id, b->call_id->i_id) == 0 &&
848 849 850 851 852 853
	sip->sip_cseq->cs_seq <= b->cseq) {
      for (m = sip->sip_contact; m; m = m->m_next) {
	if (m->m_url->url_type == url_any ||
	    url_cmp_all(m->m_url, b->contact->m_url) == 0)
	  return set_status(as, SIP_500_INTERNAL_SERVER_ERROR);
      }
854 855 856 857
    }
  }

  return 0;
858 859
}

860

861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900
static struct registration_entry *
registration_entry_find(struct proxy const *proxy, url_t const *uri)
{
  struct registration_entry *e;

  /* Our routing table */
  for (e = proxy->entries; e; e = e->next) {
    if (url_cmp(uri, e->aor) == 0)
      return e;
  }
  return NULL;
}

static struct registration_entry *
registration_entry_new(struct proxy *proxy, url_t const *aor)
{
  struct registration_entry *e;

  e = su_zalloc(proxy->home, sizeof *e); 
  if (!e) 
    return NULL;

  e->proxy = proxy;
  e->aor = url_hdup(proxy->home, aor);
  if (!e->aor) {
    su_free(proxy->home, e);
    return NULL;
  }

  registration_entry_insert(&proxy->entries, e);

  return e;
}

static void
registration_entry_destroy(struct registration_entry *e)
{
  if (e) {
    registration_entry_remove(e);
    su_free(e->proxy->home, e->aor);
901 902 903
    while (e->bindings)
      binding_destroy(e->proxy->home, e->bindings);
    msg_header_free(e->proxy->home, (void *)e->contacts);
904 905 906 907 908
    su_free(e->proxy->home, e);
  }
}

LIST_BODIES(static, registration_entry, struct registration_entry, next, prev);
909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958

/* ---------------------------------------------------------------------- */
/* Bindings */

static
struct binding *binding_new(su_home_t *home, 
			    sip_contact_t *contact,
			    sip_call_id_t *call_id,
			    uint32_t cseq,
			    sip_time_t registered, 
			    sip_time_t expires)
{
  struct binding *b;
  
  b = su_zalloc(home, sizeof *b);

  if (b) {
    sip_contact_t m[1];
    *m = *contact; m->m_next = NULL;

    b->contact = sip_contact_dup(home, m);
    b->call_id = sip_call_id_dup(home, call_id);
    b->cseq = cseq;
    b->registered = registered;
    b->expires = expires;

    if (!b->contact || !b->call_id)
      binding_destroy(home, b), b = NULL;

    if (b)
      msg_header_remove_param(b->contact->m_common, "expires");
  }
  
  return b;
}

static
void binding_destroy(su_home_t *home, struct binding *b)
{
  if (b->prev) {
    if ((*b->prev = b->next))
      b->next->prev = b->prev;
  }
  msg_header_free(home, (void *)b->contact);
  msg_header_free(home, (void *)b->call_id);
  su_free(home, b);
}

static
int binding_update(struct proxy *p,
959
		   auth_status_t *as,
960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976
		   struct registration_entry *e,
		   sip_t const *sip)
{
  struct binding *b, *old, *next, *last, *bindings = NULL, **bb = &bindings;
  sip_contact_t *m;
  sip_time_t expires;

  sip_time_t now = sip_now();

  assert(sip->sip_contact);

  /* Create new bindings */
  for (m = sip->sip_contact; m; m = m->m_next) {
    if (m->m_url->url_type == url_any)
      break;
    
    expires = sip_contact_expires(m, sip->sip_expires, sip->sip_date,
977 978 979 980
				  p->prefs.expires, now);

    if (expires > p->prefs.max_expires)
      expires = p->prefs.max_expires;
981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999

    msg_header_remove_param(m->m_common, "expires");

    b = binding_new(p->home, m, sip->sip_call_id, sip->sip_cseq->cs_seq, 
		    now, now + expires);
    if (!b)
      break;

    *bb = b, b->prev = bb, bb = &b->next;
  }

  last = NULL;

  if (m == NULL) {
    /* Merge new bindings with old ones */
    for (old = e->bindings; old; old = next) {
      next = old->next;

      for (b = bindings; b != last; b = b->next) {
1000
	if (url_cmp_all(old->contact->m_url, b->contact->m_url) != 0) 
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
	  continue;

	if (strcmp(old->call_id->i_id, b->call_id->i_id) == 0) {
	  b->registered = old->registered;
	}
	binding_destroy(p->home, old);
	break;
      }
    }

    for (bb = &e->bindings; *bb; bb = &(*bb)->next)
      ;

    if ((*bb = bindings))
      bindings->prev = bb;
  }
  else if (m->m_url->url_type == url_any) {
    /* Unregister all */
    for (b = e->bindings; b; b = b->next) {
      b->expires = now;
    }
  }
  else {
    /* Infernal error */
1025

1026 1027 1028 1029
    for (old = bindings; old; old = next) {
      next = old->next;
      binding_destroy(p->home, old);
    }
1030 1031

    return set_status(as, SIP_500_INTERNAL_SERVER_ERROR);
1032 1033
  }

1034
  return 0;
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
}

sip_contact_t *binding_contacts(su_home_t *home, struct binding *bindings)
{
  sip_contact_t *retval = NULL, **mm = &retval; 
  struct binding *b;
  sip_time_t now = sip_now();

  for (b = bindings; b; b = b->next) {
    char const *expires;
    if (b->expires <= now)
      continue;
    *mm = sip_contact_copy(home, b->contact);
Pekka Pessi's avatar
Pekka Pessi committed
1048 1049 1050 1051 1052
    if (*mm) {
      expires = su_sprintf(home, "expires=%u", (unsigned)(b->expires - now));
      msg_header_add_param(home, (*mm)->m_common, expires);
      mm = &(*mm)->m_next;
    }
1053 1054 1055 1056
  }

  return retval;
}