test_nua.c 27.8 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 26 27 28
/*
 * 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_nua.c
 * @brief High-level tester for Sofia SIP User Agent Engine
 *
 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
Pekka Pessi's avatar
Pekka Pessi committed
29
 * @author Martti Mela <Martti Mela@nokia.com>
Pekka Pessi's avatar
Pekka Pessi committed
30 31 32 33 34 35
 *
 * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
 */

#include "config.h"

36
#include "test_nua.h"
37 38 39 40 41

#if HAVE_ALARM
#include <signal.h>
#endif

42 43 44 45
#if defined(_WIN32)
#include <fcntl.h>
#endif

46 47 48 49 50 51
SOFIAPUBVAR su_log_t nua_log[];
SOFIAPUBVAR su_log_t soa_log[];
SOFIAPUBVAR su_log_t nea_log[];
SOFIAPUBVAR su_log_t nta_log[];
SOFIAPUBVAR su_log_t tport_log[];
SOFIAPUBVAR su_log_t su_log_default[];
Pekka Pessi's avatar
Pekka Pessi committed
52

53 54 55
extern void *memmem(const void *haystack, size_t haystacklen,
		    const void *needle, size_t needlelen);

Pekka Pessi's avatar
Pekka Pessi committed
56
char const name[] = "test_nua";
57
int print_headings = 1;
Pekka Pessi's avatar
Pekka Pessi committed
58 59 60 61 62 63 64 65 66
int tstflags = 0;

#if HAVE_FUNC
#elif HAVE_FUNCTION
#define __func__ __FUNCTION__
#else
#define __func__ name
#endif

67
int save_events(CONDITION_PARAMS)
Pekka Pessi's avatar
Pekka Pessi committed
68
{
69 70
  return save_event_in_list(ctx, event, ep, ep->call) == event_is_normal;
}
Pekka Pessi's avatar
Pekka Pessi committed
71

72 73 74 75
int until_final_response(CONDITION_PARAMS)
{ 
  return status >= 200;
}
Pekka Pessi's avatar
Pekka Pessi committed
76

77
int save_until_final_response(CONDITION_PARAMS)
78
{
Pekka Pessi's avatar
Pekka Pessi committed
79 80
  save_event_in_list(ctx, event, ep, ep->call);
  return event >= nua_r_set_params && status >= 200;
81 82
}

83 84
/** Save events.
 *
Pekka Pessi's avatar
Pekka Pessi committed
85 86
 * Terminate when a event is saved.
 */
87
int save_until_received(CONDITION_PARAMS)
88
{
89 90 91 92 93 94 95
  return save_event_in_list(ctx, event, ep, ep->call) == event_is_normal;
}

/** Save events until nua_i_outbound is received.  */
int save_until_special(CONDITION_PARAMS)
{
  return save_event_in_list(ctx, event, ep, ep->call) == event_is_special;
96 97
}

Pekka Pessi's avatar
Pekka Pessi committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
/* Return call state from event tag list */
int callstate(tagi_t const *tags)
{
  tagi_t const *ti = tl_find(tags, nutag_callstate);
  return ti ? ti->t_value : -1;
}

/* Return true if offer is sent */
int is_offer_sent(tagi_t const *tags)
{
  tagi_t const *ti = tl_find(tags, nutag_offer_sent);
  return ti ? ti->t_value : 0;
}

/* Return true if answer is sent */
int is_answer_sent(tagi_t const *tags)
{
  tagi_t const *ti = tl_find(tags, nutag_answer_sent);
  return ti ? ti->t_value : 0;
}

/* Return true if offer is recv */
int is_offer_recv(tagi_t const *tags)
{
  tagi_t const *ti = tl_find(tags, nutag_offer_recv);
  return ti ? ti->t_value : 0;
}

/* Return true if answer is recv */
int is_answer_recv(tagi_t const *tags)
{
  tagi_t const *ti = tl_find(tags, nutag_answer_recv);
  return ti ? ti->t_value : 0;
}

133 134 135 136 137 138 139 140 141 142 143 144
/* Return true if offer/answer is sent/recv */
int is_offer_answer_done(tagi_t const *tags)
{
  tagi_t const *ti;

  return 
    ((ti = tl_find(tags, nutag_answer_recv)) && ti->t_value) ||
    ((ti = tl_find(tags, nutag_offer_sent)) && ti->t_value) ||
    ((ti = tl_find(tags, nutag_offer_recv)) && ti->t_value) ||
    ((ti = tl_find(tags, nutag_answer_sent)) && ti->t_value);
}

Pekka Pessi's avatar
Pekka Pessi committed
145 146 147 148 149 150 151 152 153 154 155 156 157 158
/* Return audio state from event tag list */
int audio_activity(tagi_t const *tags)
{
  tagi_t const *ti = tl_find(tags, soatag_active_audio);
  return ti ? ti->t_value : -1;
}

/* Return video state from event tag list */
int video_activity(tagi_t const *tags)
{
  tagi_t const *ti = tl_find(tags, soatag_active_video);
  return ti ? ti->t_value : -1;
}

Pekka Pessi's avatar
Pekka Pessi committed
159 160 161 162 163 164 165 166 167
static
void print_event(nua_event_t event,
		 char const *operation,
		 int status, char const *phrase,
		 nua_t *nua, struct context *ctx,
		 struct endpoint *ep,
		 nua_handle_t *nh, struct call *call,
		 sip_t const *sip,
		 tagi_t tags[])
Pekka Pessi's avatar
Pekka Pessi committed
168 169 170
{
  if (event == nua_i_state) {
    fprintf(stderr, "%s.nua(%p): event %s %s\n",
171
	    ep->name, nh, nua_event_name(event),
Pekka Pessi's avatar
Pekka Pessi committed
172 173
	    nua_callstate_name(callstate(tags)));
  }
Pekka Pessi's avatar
Pekka Pessi committed
174
  else if ((int)event >= nua_r_set_params) {
Pekka Pessi's avatar
Pekka Pessi committed
175 176 177
    fprintf(stderr, "%s.nua(%p): event %s status %u %s\n",
	    ep->name, nh, nua_event_name(event), status, phrase);
  }
Pekka Pessi's avatar
Pekka Pessi committed
178 179 180 181
  else if ((int)event >= 0) {
    fprintf(stderr, "%s.nua(%p): event %s %s\n",
	    ep->name, nh, nua_event_name(event), phrase);
  }
Pekka Pessi's avatar
Pekka Pessi committed
182 183
  else if (status > 0) {
    fprintf(stderr, "%s.nua(%p): call %s() with status %u %s\n",
184
	    ep->name, nh, operation, status, phrase);
Pekka Pessi's avatar
Pekka Pessi committed
185 186
  }
  else {
Pekka Pessi's avatar
Pekka Pessi committed
187 188 189 190 191
    tagi_t const *t;
    t = tl_find(tags, siptag_subject_str);
    if (t && t->t_value) {
      char const *subject = (char const *)t->t_value;
      fprintf(stderr, "%s.nua(%p): call %s() \"%s\"\n",
Pekka Pessi's avatar
Pekka Pessi committed
192
	      ep->name, nh, operation, subject);
Pekka Pessi's avatar
Pekka Pessi committed
193 194 195
    }
    else
      fprintf(stderr, "%s.nua(%p): call %s()\n",
Pekka Pessi's avatar
Pekka Pessi committed
196
	      ep->name, nh, operation);
Pekka Pessi's avatar
Pekka Pessi committed
197 198 199 200 201
  }

  if ((tstflags & tst_verbatim) && tags)
    tl_print(stderr, "", tags);
}
202

203 204 205 206
void ep_callback(nua_event_t event,
		 int status, char const *phrase,
		 nua_t *nua, struct context *ctx,
		 struct endpoint *ep,
Pekka Pessi's avatar
Pekka Pessi committed
207
		 nua_handle_t *nh, struct call *call,
208 209
		 sip_t const *sip,
		 tagi_t tags[])
210
{
Pekka Pessi's avatar
Pekka Pessi committed
211
  if (ep->printer)
Pekka Pessi's avatar
Pekka Pessi committed
212 213
    ep->printer(event, "", status, phrase, nua, ctx, ep, nh, call, sip, tags);

214
  if (call == NULL && nh) {
Pekka Pessi's avatar
Pekka Pessi committed
215 216 217 218 219 220 221 222 223 224 225 226
    for (call = ep->call; call; call = call->next) {
      if (!call->nh)
	break;
      if (nh == call->nh)
	break;
    }

    if (call && call->nh == NULL) {
      call->nh = nh;
      nua_handle_bind(nh, call);
    }
  }
Pekka Pessi's avatar
Pekka Pessi committed
227 228 229 230 231

  if ((ep->next_event == -1 || ep->next_event == event) &&
      (ep->next_condition == NULL ||
       ep->next_condition(event, status, phrase,
			  nua, ctx, ep, nh, call, sip, tags)))
232
    ep->running = 0;
233

Pekka Pessi's avatar
Pekka Pessi committed
234
  ep->last_event = event;
235 236 237

  if (call == NULL && nh)
    nua_handle_destroy(nh);
238 239
}

240
void a_callback(nua_event_t event,
241 242
		int status, char const *phrase,
		nua_t *nua, struct context *ctx,
Pekka Pessi's avatar
Pekka Pessi committed
243
		nua_handle_t *nh, struct call *call,
244 245
		sip_t const *sip,
		tagi_t tags[])
Pekka Pessi's avatar
Pekka Pessi committed
246
{
247 248
  ep_callback(event, status, phrase, nua, ctx, &ctx->a, nh, call, sip, tags);
}
249

250 251 252
void b_callback(nua_event_t event,
		int status, char const *phrase,
		nua_t *nua, struct context *ctx,
Pekka Pessi's avatar
Pekka Pessi committed
253
		nua_handle_t *nh, struct call *call,
254 255 256 257 258
		sip_t const *sip,
		tagi_t tags[])
{
  ep_callback(event, status, phrase, nua, ctx, &ctx->b, nh, call, sip, tags);
}
Pekka Pessi's avatar
Pekka Pessi committed
259

260 261 262
void c_callback(nua_event_t event,
		int status, char const *phrase,
		nua_t *nua, struct context *ctx,
Pekka Pessi's avatar
Pekka Pessi committed
263
		nua_handle_t *nh, struct call *call,
264 265 266 267
		sip_t const *sip,
		tagi_t tags[])
{
  ep_callback(event, status, phrase, nua, ctx, &ctx->c, nh, call, sip, tags);
Pekka Pessi's avatar
Pekka Pessi committed
268 269
}

270 271 272 273
void run_abc_until(struct context *ctx,
		   nua_event_t a_event, condition_function *a_condition,
		   nua_event_t b_event, condition_function *b_condition,
		   nua_event_t c_event, condition_function *c_condition)
Pekka Pessi's avatar
Pekka Pessi committed
274
{
275
  struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
276 277 278 279

  a->next_event = a_event;
  a->next_condition = a_condition;
  a->last_event = -1;
280 281
  a->running = a_condition != NULL && a_condition != save_events;
  a->running |= a_event != -1;
Pekka Pessi's avatar
Pekka Pessi committed
282
  a->flags.n = 0;
283 284 285 286

  b->next_event = b_event;
  b->next_condition = b_condition;
  b->last_event = -1;
287 288
  b->running = b_condition != NULL && b_condition != save_events;
  b->running |= b_event != -1;
Pekka Pessi's avatar
Pekka Pessi committed
289
  b->flags.n = 0;
Pekka Pessi's avatar
Pekka Pessi committed
290

291 292 293
  c->next_event = c_event;
  c->next_condition = c_condition;
  c->last_event = -1;
294 295
  c->running = c_condition != NULL && c_condition != save_events;
  c->running |= c_event != -1;
Pekka Pessi's avatar
Pekka Pessi committed
296
  c->flags.n = 0;
297 298

  for (; a->running || b->running || c->running;) {
Pekka Pessi's avatar
Pekka Pessi committed
299 300
    su_root_step(ctx->root, 1000);
  }
301
}
Pekka Pessi's avatar
Pekka Pessi committed
302

303 304 305 306 307 308 309
void run_ab_until(struct context *ctx,
		  nua_event_t a_event, condition_function *a_condition,
		  nua_event_t b_event, condition_function *b_condition)
{
  run_abc_until(ctx, a_event, a_condition, b_event, b_condition, -1, NULL);
}

310 311 312 313 314 315 316
void run_bc_until(struct context *ctx,
		  nua_event_t b_event, condition_function *b_condition,
		  nua_event_t c_event, condition_function *c_condition)
{
  run_abc_until(ctx, -1, NULL, b_event, b_condition, c_event, c_condition);
}

317 318 319 320
int run_a_until(struct context *ctx,
		nua_event_t a_event,
		condition_function *a_condition)
{
321
  run_abc_until(ctx, a_event, a_condition, -1, NULL, -1, NULL);
322 323 324 325 326 327 328
  return ctx->a.last_event;
}

int run_b_until(struct context *ctx,
		nua_event_t b_event,
		condition_function *b_condition)
{
329
  run_abc_until(ctx, -1, NULL, b_event, b_condition, -1, NULL);
330
  return ctx->b.last_event;
Pekka Pessi's avatar
Pekka Pessi committed
331 332
}

Pekka Pessi's avatar
Pekka Pessi committed
333 334 335 336 337 338 339 340
int run_c_until(struct context *ctx,
		nua_event_t event,
		condition_function *condition)
{
  run_abc_until(ctx, -1, NULL, -1, NULL, event, condition);
  return ctx->c.last_event;
}

341 342
#define OPERATION(X, x)	   \
int X(struct endpoint *ep, \
Pekka Pessi's avatar
Pekka Pessi committed
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
      struct call *call, nua_handle_t *nh, \
      tag_type_t tag, tag_value_t value, \
      ...) \
{ \
  ta_list ta; \
  ta_start(ta, tag, value); \
\
  if (ep->printer) \
    ep->printer(-1, "nua_" #x, 0, "", ep->nua, ep->ctx, ep, \
		nh, call, NULL, ta_args(ta)); \
\
  nua_##x(nh, ta_tags(ta)); \
\
  ta_end(ta); \
  return 0; \
} extern int dummy

360 361 362 363 364 365 366
OPERATION(INVITE, invite);
OPERATION(ACK, ack);
OPERATION(BYE, bye);
OPERATION(CANCEL, cancel);
OPERATION(AUTHENTICATE, authenticate);
OPERATION(UPDATE, update);
OPERATION(INFO, info);
367
OPERATION(PRACK, prack);
368 369 370 371 372 373 374 375 376 377 378 379 380
OPERATION(REFER, refer);
OPERATION(MESSAGE, message);
OPERATION(OPTIONS, options);
OPERATION(PUBLISH, publish);
OPERATION(UNPUBLISH, unpublish);
OPERATION(REGISTER, register);
OPERATION(UNREGISTER, unregister);
OPERATION(SUBSCRIBE, subscribe);
OPERATION(UNSUBSCRIBE, unsubscribe);
OPERATION(NOTIFY, notify);
OPERATION(NOTIFIER, notifier);
OPERATION(TERMINATE, terminate);
OPERATION(AUTHORIZE, authorize);
381

Pekka Pessi's avatar
Pekka Pessi committed
382
/* Respond via endpoint and handle */
383
int RESPOND(struct endpoint *ep,
Pekka Pessi's avatar
Pekka Pessi committed
384 385
	    struct call *call,
	    nua_handle_t *nh,
Pekka Pessi's avatar
Pekka Pessi committed
386 387 388 389 390 391 392
	    int status, char const *phrase,
	    tag_type_t tag, tag_value_t value,
	    ...)
{
  ta_list ta;

  ta_start(ta, tag, value);
Pekka Pessi's avatar
Pekka Pessi committed
393 394

  if (ep->printer)
Pekka Pessi's avatar
Pekka Pessi committed
395 396
    ep->printer(-1, "nua_respond", status, phrase, ep->nua, ep->ctx, ep,
		nh, call, NULL, ta_args(ta));
Pekka Pessi's avatar
Pekka Pessi committed
397

Pekka Pessi's avatar
Pekka Pessi committed
398 399 400 401 402 403
  nua_respond(nh, status, phrase, ta_tags(ta));
  ta_end(ta);

  return 0;
}

404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
/* Destroy an handle */
int DESTROY(struct endpoint *ep,
	    struct call *call,
	    nua_handle_t *nh)
{
  if (ep->printer)
    ep->printer(-1, "nua_handle_destroy", 0, "", ep->nua, ep->ctx, ep,
		nh, call, NULL, NULL);

  nua_handle_destroy(nh);

  if (call->nh == nh)
    call->nh = NULL;

  return 0;
}

421

Pekka Pessi's avatar
Pekka Pessi committed
422 423 424 425 426
/* Reject all but currently used handles */
struct call *check_handle(struct endpoint *ep,
			  struct call *call,
			  nua_handle_t *nh,
			  int status, char const *phrase)
427
{
Pekka Pessi's avatar
Pekka Pessi committed
428 429
  if (call)
    return call;
430

Pekka Pessi's avatar
Pekka Pessi committed
431
  if (status)
432
    RESPOND(ep, call, nh, status, phrase, TAG_END());
433

Pekka Pessi's avatar
Pekka Pessi committed
434 435
  nua_handle_destroy(nh);
  return NULL;
436 437
}

Pekka Pessi's avatar
Pekka Pessi committed
438
/* Save nua event in call-specific list */
439
int save_event_in_list(struct context *ctx,
Pekka Pessi's avatar
Pekka Pessi committed
440 441 442 443
		       nua_event_t nevent,
		       struct endpoint *ep,
		       struct call *call)

444
{
Pekka Pessi's avatar
Pekka Pessi committed
445
  struct eventlist *list;
Pekka Pessi's avatar
Pekka Pessi committed
446
  struct event *e;
Pekka Pessi's avatar
Pekka Pessi committed
447
  int action = ep->is_special(nevent);
Pekka Pessi's avatar
Pekka Pessi committed
448

Pekka Pessi's avatar
Pekka Pessi committed
449
  if (action == event_is_extra)
Pekka Pessi's avatar
Pekka Pessi committed
450
    return 0;
Pekka Pessi's avatar
Pekka Pessi committed
451
  else if (action == event_is_special || call == NULL)
Pekka Pessi's avatar
Pekka Pessi committed
452 453 454 455 456
    list = ep->specials;
  else if (call->events)
    list = call->events;
  else
    list = ep->events;
Pekka Pessi's avatar
Pekka Pessi committed
457 458

  e = su_zalloc(ctx->home, sizeof *e);
459 460

  if (!e) { perror("su_zalloc"), abort(); }
461

462 463
  if (!nua_save_event(ep->nua, e->saved_event)) {
    su_free(ctx->home, e);
Pekka Pessi's avatar
Pekka Pessi committed
464
    return -1;
465
  }
Pekka Pessi's avatar
Pekka Pessi committed
466

Pekka Pessi's avatar
Pekka Pessi committed
467 468 469
  *(e->prev = list->tail) = e; list->tail = &e->next;

  e->call = call;
Pekka Pessi's avatar
Pekka Pessi committed
470
  e->data = nua_event_data(e->saved_event);
471

472
  return action;
473
}
Pekka Pessi's avatar
Pekka Pessi committed
474

Pekka Pessi's avatar
Pekka Pessi committed
475
/* Save nua event in endpoint list */
Pekka Pessi's avatar
Pekka Pessi committed
476
void free_events_in_list(struct context *ctx,
Pekka Pessi's avatar
Pekka Pessi committed
477
			 struct eventlist *list)
Pekka Pessi's avatar
Pekka Pessi committed
478 479 480
{
  struct event *e;

Pekka Pessi's avatar
Pekka Pessi committed
481
  while ((e = list->head)) {
Pekka Pessi's avatar
Pekka Pessi committed
482 483 484 485 486
    if ((*e->prev = e->next))
      e->next->prev = e->prev;
    nua_destroy_event(e->saved_event);
    su_free(ctx->home, e);
  }
Pekka Pessi's avatar
Pekka Pessi committed
487 488 489 490 491 492 493 494 495 496 497 498 499 500

  list->tail = &list->head;
}

int is_special(nua_event_t e)
{
  if (e == nua_i_active || e == nua_i_terminated)
    return event_is_extra;
  if (e == nua_i_outbound)
    return event_is_special;

  return event_is_normal;
}

501
void
Pekka Pessi's avatar
Pekka Pessi committed
502 503 504 505 506 507 508 509 510 511 512
endpoint_init(struct context *ctx, struct endpoint *e, char id)
{
  e->name[0] = id;
  e->ctx = ctx;

  e->is_special = is_special;

  call_init(e->call);
  call_init(e->reg);
  eventlist_init(e->events);
  eventlist_init(e->specials);
Pekka Pessi's avatar
Pekka Pessi committed
513 514
}

Pekka Pessi's avatar
Pekka Pessi committed
515 516
void nolog(void *stream, char const *fmt, va_list ap) {}

517 518
/* ======================================================================== */

Pekka Pessi's avatar
Pekka Pessi committed
519 520
static char passwd_name[] = "tmp_sippasswd.XXXXXX";

521
static void remove_tmp(void)
Pekka Pessi's avatar
Pekka Pessi committed
522 523 524 525 526 527 528 529 530 531
{
  if (passwd_name[0])
    unlink(passwd_name);
}

static char const passwd[] =
  "alice:secret:\n"
  "bob:secret:\n"
  "charlie:secret:\n";

Pekka Pessi's avatar
Pekka Pessi committed
532 533 534 535 536
int test_nua_init(struct context *ctx,
		  int start_proxy,
		  url_t const *o_proxy,
		  int start_nat,
		  tag_type_t tag, tag_value_t value, ...)
Pekka Pessi's avatar
Pekka Pessi committed
537 538
{
  BEGIN();
539
  struct event *e;
540
  sip_contact_t const *m = NULL;
Pekka Pessi's avatar
Pekka Pessi committed
541
  sip_from_t const *sipaddress = NULL;
Pekka Pessi's avatar
Pekka Pessi committed
542
  url_t const *p_uri, *a_uri;		/* Proxy URI */
543 544 545
  char const *a_bind, *a_bind2;

  a_bind = a_bind2 = "sip:0.0.0.0:*";
546

Pekka Pessi's avatar
Pekka Pessi committed
547
  ctx->root = su_root_create(NULL); TEST_1(ctx->root);
548 549

  /* Disable threading by command line switch? */
Pekka Pessi's avatar
Pekka Pessi committed
550
  su_root_threading(ctx->root, ctx->threading);
551

552
  if (start_proxy && !o_proxy) {
Pekka Pessi's avatar
Pekka Pessi committed
553 554
    int temp;

555
    if (print_headings)
Pekka Pessi's avatar
Pekka Pessi committed
556
      printf("TEST NUA-2.1.1: init proxy P\n");
Pekka Pessi's avatar
Pekka Pessi committed
557

558
#ifndef _WIN32
559
    temp = mkstemp(passwd_name);
560
#else
561
    temp = open(passwd_name, O_WRONLY|O_CREAT|O_TRUNC, 666);
562
#endif
563
    TEST_1(temp != -1);
564
    atexit(remove_tmp);		/* Make sure temp file is unlinked */
Pekka Pessi's avatar
Pekka Pessi committed
565

Pekka Pessi's avatar
Pekka Pessi committed
566 567 568 569
    TEST(write(temp, passwd, strlen(passwd)), strlen(passwd));

    TEST_1(close(temp) == 0);

Pekka Pessi's avatar
Pekka Pessi committed
570
    ctx->p = test_proxy_create(ctx->root,
Pekka Pessi's avatar
Pekka Pessi committed
571 572 573 574 575 576 577
			       AUTHTAG_METHOD("Digest"),
			       AUTHTAG_REALM("test-proxy"),
			       AUTHTAG_OPAQUE("kuik"),
			       AUTHTAG_DB(passwd_name),
			       AUTHTAG_QOP("auth-int"),
			       AUTHTAG_ALGORITHM("md5-sess"),
			       TAG_END());
Pekka Pessi's avatar
Pekka Pessi committed
578

579 580
    ctx->proxy_tests = ctx->p != NULL;

581
    if (print_headings)
Pekka Pessi's avatar
Pekka Pessi committed
582 583 584 585 586 587 588 589 590 591 592 593 594 595
      printf("TEST NUA-2.1.1: PASSED\n");
  }

  p_uri = a_uri = test_proxy_uri(ctx->p);

  if (start_nat && p_uri == NULL)
    p_uri = url_hdup(ctx->home, (void *)o_proxy);

  if (start_nat && p_uri != NULL) {
    int family = 0;
    su_sockaddr_t su[1];
    socklen_t sulen = sizeof su;
    char b[64];
    int len;
Pekka Pessi's avatar
Pekka Pessi committed
596
    ta_list ta;
Pekka Pessi's avatar
Pekka Pessi committed
597 598 599 600 601 602 603

    if (print_headings)
      printf("TEST NUA-2.1.2: creating test NAT\n");

    /* Try to use different family than proxy. */
    if (p_uri->url_host[0] == '[')
      family = AF_INET;
604
#if defined(SU_HAVE_IN6)
Pekka Pessi's avatar
Pekka Pessi committed
605 606
    else
      family = AF_INET6;
607
#endif
Pekka Pessi's avatar
Pekka Pessi committed
608

Pekka Pessi's avatar
Pekka Pessi committed
609 610 611
    ta_start(ta, tag, value);
    ctx->nat = test_nat_create(ctx->root, family, ta_tags(ta));
    ta_end(ta);
Pekka Pessi's avatar
Pekka Pessi committed
612

613 614 615 616 617 618 619 620
    /*
     * NAT thingy works so that we set the outgoing proxy URI to point
     * towards its "private" address and give the real address of the proxy
     * as its "public" address. If we use different IP families here, we may
     * even manage to test real connectivity problems as proxy and endpoint
     * can not talk to each other.
     */

Pekka Pessi's avatar
Pekka Pessi committed
621 622 623 624
    if (test_nat_private(ctx->nat, su, &sulen) < 0) {
      printf("%s:%u: NUA-2.1.2: failed to get private NAT address\n",
	     __FILE__, __LINE__);
    }
625 626

#if defined(SU_HAVE_IN6)
Pekka Pessi's avatar
Pekka Pessi committed
627 628 629 630 631 632 633
    else if (su->su_family == AF_INET6) {
      a_uri = (void *)
	su_sprintf(ctx->home, "sip:[%s]:%u",
		   inet_ntop(su->su_family, SU_ADDR(su), b, sizeof b),
		   ntohs(su->su_port));
      a_bind = "sip:[::]:*";
    }
634
#endif
Pekka Pessi's avatar
Pekka Pessi committed
635 636 637 638 639 640 641
    else if (su->su_family == AF_INET) {
      a_uri = (void *)
	su_sprintf(ctx->home, "sip:%s:%u",
		   inet_ntop(su->su_family, SU_ADDR(su), b, sizeof b),
		   ntohs(su->su_port));
    }

642
#if defined(SU_HAVE_IN6)
Pekka Pessi's avatar
Pekka Pessi committed
643 644 645 646 647 648 649 650 651 652
    if (p_uri->url_host[0] == '[') {
      su->su_len = sulen = (sizeof su->su_sin6), su->su_family = AF_INET6;
      len = strcspn(p_uri->url_host + 1, "]"); assert(len < sizeof b);
      memcpy(b, p_uri->url_host + 1, len); b[len] = '\0';
      inet_pton(su->su_family, b, SU_ADDR(su));
    }
    else {
      su->su_len = sulen = (sizeof su->su_sin), su->su_family = AF_INET;
      inet_pton(su->su_family, p_uri->url_host, SU_ADDR(su));
    }
653 654 655 656
#else
    su->su_len = sulen = (sizeof su->su_sin), su->su_family = AF_INET;
    inet_pton(su->su_family, p_uri->url_host, SU_ADDR(su));
#endif
Pekka Pessi's avatar
Pekka Pessi committed
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672

    su->su_port = htons(strtoul(url_port(p_uri), NULL, 10));

    if (test_nat_public(ctx->nat, su, sulen) < 0) {
      printf("%s:%u: NUA-2.1.2: failed to set public address\n",
	     __FILE__, __LINE__);
      a_uri = NULL;
    }

    if (print_headings) {
      if (ctx->nat && a_uri) {
	printf("TEST NUA-2.1.2: PASSED\n");
      } else {
	printf("TEST NUA-2.1.2: FAILED\n");
      }
    }
673
  }
Pekka Pessi's avatar
Pekka Pessi committed
674

675
  if (print_headings)
Pekka Pessi's avatar
Pekka Pessi committed
676
    printf("TEST NUA-2.2.1: init endpoint A\n");
677

Pekka Pessi's avatar
Pekka Pessi committed
678 679
  if (a_uri == NULL)
    a_uri = p_uri;
680

681 682
  ctx->a.instance = nua_generate_instance_identifier(ctx->home);

683
  ctx->a.nua = nua_create(ctx->root, a_callback, ctx,
Pekka Pessi's avatar
Pekka Pessi committed
684
			  NUTAG_PROXY(a_uri ? a_uri : o_proxy),
685
			  SIPTAG_FROM_STR("sip:alice@example.com"),
Pekka Pessi's avatar
Pekka Pessi committed
686
			  NUTAG_URL(a_bind),
687
			  TAG_IF(a_bind != a_bind2, NUTAG_SIPS_URL(a_bind2)),
Pekka Pessi's avatar
Pekka Pessi committed
688
			  SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"),
689
			  NTATAG_SIP_T1X64(4000),
690
			  NUTAG_INSTANCE(ctx->a.instance),
691 692 693 694
			  TAG_END());
  TEST_1(ctx->a.nua);

  nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
695
  run_a_until(ctx, nua_r_get_params, save_until_final_response);
Pekka Pessi's avatar
Pekka Pessi committed
696
  TEST_1(e = ctx->a.events->head);
697
  TEST(tl_gets(e->data->e_tags,
Pekka Pessi's avatar
Pekka Pessi committed
698
	       NTATAG_CONTACT_REF(m),
Pekka Pessi's avatar
Pekka Pessi committed
699
	       SIPTAG_FROM_REF(sipaddress),
Pekka Pessi's avatar
Pekka Pessi committed
700
	       TAG_END()), 2); TEST_1(m);
701
  TEST_1(ctx->a.contact = sip_contact_dup(ctx->home, m));
Pekka Pessi's avatar
Pekka Pessi committed
702
  TEST_1(ctx->a.to = sip_to_dup(ctx->home, sipaddress));
703

Pekka Pessi's avatar
Pekka Pessi committed
704
  free_events_in_list(ctx, ctx->a.events);
705

706
  if (print_headings)
Pekka Pessi's avatar
Pekka Pessi committed
707
    printf("TEST NUA-2.2.1: PASSED\n");
708 709

  if (print_headings)
Pekka Pessi's avatar
Pekka Pessi committed
710
    printf("TEST NUA-2.2.2: init endpoint B\n");
711

712 713
  ctx->b.instance = nua_generate_instance_identifier(ctx->home);

714
  ctx->b.nua = nua_create(ctx->root, b_callback, ctx,
715
			  NUTAG_PROXY(p_uri ? p_uri : o_proxy),
716
			  SIPTAG_FROM_STR("sip:bob@example.org"),
717
			  NUTAG_URL("sip:0.0.0.0:*"),
Pekka Pessi's avatar
Pekka Pessi committed
718
			  SOATAG_USER_SDP_STR("m=audio 5006 RTP/AVP 8 0"),
719
			  NUTAG_INSTANCE(ctx->b.instance),
720 721 722 723
			  TAG_END());
  TEST_1(ctx->b.nua);

  nua_get_params(ctx->b.nua, TAG_ANY(), TAG_END());
724
  run_b_until(ctx, nua_r_get_params, save_until_final_response);
Pekka Pessi's avatar
Pekka Pessi committed
725
  TEST_1(e = ctx->b.events->head);
726
  TEST(tl_gets(e->data->e_tags,
Pekka Pessi's avatar
Pekka Pessi committed
727
	       NTATAG_CONTACT_REF(m),
Pekka Pessi's avatar
Pekka Pessi committed
728
	       SIPTAG_FROM_REF(sipaddress),
Pekka Pessi's avatar
Pekka Pessi committed
729 730
	       TAG_END()), 2); TEST_1(m);
  TEST_1(ctx->b.contact = sip_contact_dup(ctx->home, m));
Pekka Pessi's avatar
Pekka Pessi committed
731
  TEST_1(ctx->b.to = sip_to_dup(ctx->home, sipaddress));
Pekka Pessi's avatar
Pekka Pessi committed
732
  free_events_in_list(ctx, ctx->b.events);
733

734
  if (print_headings)
Pekka Pessi's avatar
Pekka Pessi committed
735
    printf("TEST NUA-2.2.2: PASSED\n");
736

Pekka Pessi's avatar
Pekka Pessi committed
737
  if (print_headings)
Pekka Pessi's avatar
Pekka Pessi committed
738
    printf("TEST NUA-2.2.3: init endpoint C\n");
Pekka Pessi's avatar
Pekka Pessi committed
739

Pekka Pessi's avatar
Pekka Pessi committed
740
  /* ctx->c.instance = nua_generate_instance_identifier(ctx->home); */
741

Pekka Pessi's avatar
Pekka Pessi committed
742
  ctx->c.nua = nua_create(ctx->root, c_callback, ctx,
743
			  NUTAG_PROXY(p_uri ? p_uri : o_proxy),
Pekka Pessi's avatar
Pekka Pessi committed
744
			  SIPTAG_FROM_STR("sip:charlie@example.net"),
745
			  NUTAG_URL("sip:0.0.0.0:*"),
Pekka Pessi's avatar
Pekka Pessi committed
746
			  SOATAG_USER_SDP_STR("m=audio 5400 RTP/AVP 8 0"),
747
			  NUTAG_INSTANCE(ctx->c.instance),
Pekka Pessi's avatar
Pekka Pessi committed
748 749 750 751 752
			  TAG_END());
  TEST_1(ctx->c.nua);

  nua_get_params(ctx->c.nua, TAG_ANY(), TAG_END());
  run_c_until(ctx, nua_r_get_params, save_until_final_response);
Pekka Pessi's avatar
Pekka Pessi committed
753
  TEST_1(e = ctx->c.events->head);
Pekka Pessi's avatar
Pekka Pessi committed
754 755 756 757 758
  TEST(tl_gets(e->data->e_tags,
	       NTATAG_CONTACT_REF(m),
	       SIPTAG_FROM_REF(sipaddress),
	       TAG_END()), 2); TEST_1(m);
  TEST_1(ctx->c.contact = sip_contact_dup(ctx->home, m));
Pekka Pessi's avatar
Pekka Pessi committed
759
  TEST_1(ctx->c.to = sip_to_dup(ctx->home, sipaddress));
Pekka Pessi's avatar
Pekka Pessi committed
760 761
  free_events_in_list(ctx, ctx->c.events);

Pekka Pessi's avatar
Pekka Pessi committed
762
  if (print_headings)
Pekka Pessi's avatar
Pekka Pessi committed
763
    printf("TEST NUA-2.2.3: PASSED\n");
Pekka Pessi's avatar
Pekka Pessi committed
764

Pekka Pessi's avatar
Pekka Pessi committed
765 766 767
  END();
}

Pekka Pessi's avatar
Pekka Pessi committed
768

769 770
/* ====================================================================== */

Pekka Pessi's avatar
Pekka Pessi committed
771 772 773 774
int test_deinit(struct context *ctx)
{
  BEGIN();

Pekka Pessi's avatar
Pekka Pessi committed
775 776
  struct call *call;

777 778 779
  if (!ctx->threading)
    su_root_step(ctx->root, 100);

780 781 782
  if (ctx->a.nua) {
    for (call = ctx->a.call; call; call = call->next)
      nua_handle_destroy(call->nh), call->nh = NULL;
783

784 785 786 787
    nua_shutdown(ctx->a.nua);
    run_a_until(ctx, nua_r_shutdown, until_final_response);
    nua_destroy(ctx->a.nua), ctx->a.nua = NULL;
  }
Pekka Pessi's avatar
Pekka Pessi committed
788

789 790 791
  if (ctx->b.nua) {
    for (call = ctx->b.call; call; call = call->next)
      nua_handle_destroy(call->nh), call->nh = NULL;
792

793 794 795 796
    nua_shutdown(ctx->b.nua);
    run_b_until(ctx, nua_r_shutdown, until_final_response);
    nua_destroy(ctx->b.nua), ctx->b.nua = NULL;
  }
Pekka Pessi's avatar
Pekka Pessi committed
797

798 799 800
  if (ctx->c.nua) {
    for (call = ctx->c.call; call; call = call->next)
      nua_handle_destroy(call->nh), call->nh = NULL;
Pekka Pessi's avatar
Pekka Pessi committed
801

802 803 804 805
    nua_shutdown(ctx->c.nua);
    run_c_until(ctx, nua_r_shutdown, until_final_response);
    nua_destroy(ctx->c.nua), ctx->c.nua = NULL;
  }
Pekka Pessi's avatar
Pekka Pessi committed
806

Pekka Pessi's avatar
Pekka Pessi committed
807
  test_proxy_destroy(ctx->p), ctx->p = NULL;
Pekka Pessi's avatar
Pekka Pessi committed
808 809

  test_nat_destroy(ctx->nat), ctx->nat = NULL;
Pekka Pessi's avatar
Pekka Pessi committed
810

Pekka Pessi's avatar
Pekka Pessi committed
811
  su_root_destroy(ctx->root);
812

Pekka Pessi's avatar
Pekka Pessi committed
813 814 815 816 817 818 819 820 821 822 823
  END();
}

#if HAVE_ALARM
static RETSIGTYPE sig_alarm(int s)
{
  fprintf(stderr, "%s: FAIL! test timeout!\n", name);
  exit(1);
}
#endif

824
static char const options_usage[] =
825 826
  "   -v | --verbose    be verbose\n"
  "   -q | --quiet      be quiet\n"
Pekka Pessi's avatar
Pekka Pessi committed
827
  "   -s                use only single thread\n"
828 829 830 831
  "   -l level          set logging level (0 by default)\n"
  "   -e | --events     print nua events\n"
  "   -A                print nua events for A\n"
  "   -B                print nua events for B\n"
832
  "   -C                print nua events for C\n"
833
  "   --attach          print pid, wait for a debugger to be attached\n"
834
  "   --no-proxy        do not use internal proxy\n"
Pekka Pessi's avatar
Pekka Pessi committed
835
  "   --no-nat          do not use internal \"nat\"\n"
Pekka Pessi's avatar
Pekka Pessi committed
836 837
  "   --symmetric       run internal \"nat\" in symmetric mode\n"
  "   -N                print events from internal \"nat\"\n"
838
  "   --no-alarm        don't ask for guard ALARM\n"
839
  "   -p uri            specify uri of outbound proxy (implies --no-proxy)\n"
840
  "   --proxy-tests     run tests involving proxy, too\n"
841
  "   -k                do not exit after first error\n"
842 843 844
  ;

void usage(int exitcode)
Pekka Pessi's avatar
Pekka Pessi committed
845
{
846
  fprintf(stderr, "usage: %s OPTIONS\n   where OPTIONS are\n%s",
847
	    name, options_usage);
848
  exit(exitcode);
Pekka Pessi's avatar
Pekka Pessi committed
849 850 851 852
}

int main(int argc, char *argv[])
{
853
  int retval = 0;
854
  int i, o_quiet = 0, o_attach = 0, o_alarm = 1;
855 856
  int o_events_init = 0, o_events_a = 0, o_events_b = 0, o_events_c = 0;
  int o_iproxy = 1, o_inat = 1;
857
  int o_inat_symmetric = 0, o_inat_logging = 0, o_expensive = 0;
Pekka Pessi's avatar
Pekka Pessi committed
858
  url_t const *o_proxy = NULL;
859
  int level = 0;
Pekka Pessi's avatar
Pekka Pessi committed
860 861 862

  struct context ctx[1] = {{{ SU_HOME_INIT(ctx) }}};

863 864 865
  if (getenv("EXPENSIVE_CHECKS"))
    o_expensive = 1;

Pekka Pessi's avatar
Pekka Pessi committed
866
  ctx->threading = 1;
867
  ctx->quit_on_single_failure = 1;
Pekka Pessi's avatar
Pekka Pessi committed
868

Pekka Pessi's avatar
Pekka Pessi committed
869 870 871
  endpoint_init(ctx, &ctx->a, 'a');
  endpoint_init(ctx, &ctx->b, 'b');
  endpoint_init(ctx, &ctx->c, 'c');
Pekka Pessi's avatar
Pekka Pessi committed
872

Pekka Pessi's avatar
Pekka Pessi committed
873
  for (i = 1; argv[i]; i++) {
874
    if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0)
Pekka Pessi's avatar
Pekka Pessi committed
875
      tstflags |= tst_verbatim;
876 877
    else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0)
      tstflags &= ~tst_verbatim, o_quiet = 1;
878
    else if (strcmp(argv[i], "-k") == 0)
879
      ctx->quit_on_single_failure = 0;
Pekka Pessi's avatar
Pekka Pessi committed
880 881 882 883 884 885 886 887 888 889 890
    else if (strncmp(argv[i], "-l", 2) == 0) {
      char *rest = NULL;

      if (argv[i][2])
	level = strtol(argv[i] + 2, &rest, 10);
      else if (argv[i + 1])
	level = strtol(argv[i + 1], &rest, 10), i++;
      else
	level = 3, rest = "";

      if (rest == NULL || *rest)
891
	usage(1);
892

Pekka Pessi's avatar
Pekka Pessi committed
893
      su_log_set_level(nua_log, level);
894
      su_log_soft_set_level(soa_log, level);
895
      su_log_soft_set_level(nea_log, level);
896 897 898 899
      su_log_soft_set_level(nta_log, level);
      su_log_soft_set_level(tport_log, level);
    }
    else if (strcmp(argv[i], "-e") == 0 || strcmp(argv[i], "--events") == 0) {
900 901 902 903
      o_events_init = o_events_a = o_events_b = o_events_c = 1;
    }
    else if (strcmp(argv[i], "-I") == 0) {
      o_events_init = 1;
904 905 906 907 908 909 910