test_nua.c 130 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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
/*
 * 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>
 *
 * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
 */

#include "config.h"

#include <stddef.h>
#include <stdlib.h>
#include <string.h>

#include <assert.h>

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

struct context;
#define NUA_MAGIC_T struct context
Pekka Pessi's avatar
Pekka Pessi committed
48 49 50

struct call;
#define NUA_HMAGIC_T struct call
Pekka Pessi's avatar
Pekka Pessi committed
51 52 53

#include "nua.h"
#include "nua_tag.h"
54
#include "sip_status.h"
Pekka Pessi's avatar
Pekka Pessi committed
55 56

#include <sdp.h>
57
#include <sip_header.h>
Pekka Pessi's avatar
Pekka Pessi committed
58 59

#include <su_log.h>
Pekka Pessi's avatar
Pekka Pessi committed
60
#include <su_tagarg.h>
Pekka Pessi's avatar
Pekka Pessi committed
61
#include <su_tag_io.h>
Pekka Pessi's avatar
Pekka Pessi committed
62

Pekka Pessi's avatar
Pekka Pessi committed
63 64
#include <test_proxy.h>

Pekka Pessi's avatar
Pekka Pessi committed
65
extern su_log_t nua_log[];
66 67 68
extern su_log_t soa_log[];
extern su_log_t nta_log[];
extern su_log_t tport_log[];
Pekka Pessi's avatar
Pekka Pessi committed
69 70 71
extern su_log_t su_log_default[];

char const name[] = "test_nua";
72 73

int print_headings = 1;
Pekka Pessi's avatar
Pekka Pessi committed
74 75 76 77 78 79 80 81 82 83 84 85 86 87
int tstflags = 0;
#define TSTFLAGS tstflags

#include <tstdef.h>

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

#define NONE ((void*)-1)

88 89
#define TEST_E(a, b) TEST_S(nua_event_name(a), nua_event_name(b))

90 91 92
struct endpoint;

typedef
Pekka Pessi's avatar
Pekka Pessi committed
93 94 95
int condition_function(nua_event_t event,
		       int status, char const *phrase,
		       nua_t *nua, struct context *ctx,
96
		       struct endpoint *ep,
Pekka Pessi's avatar
Pekka Pessi committed
97
		       nua_handle_t *nh, struct call *call,
Pekka Pessi's avatar
Pekka Pessi committed
98 99 100
		       sip_t const *sip,
		       tagi_t tags[]);

Pekka Pessi's avatar
Pekka Pessi committed
101 102 103 104 105 106 107 108 109 110
typedef
void printer_function(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
111 112 113
struct proxy_transaction;
struct registration_entry;

114
struct context
Pekka Pessi's avatar
Pekka Pessi committed
115 116 117 118
{
  su_home_t home[1];
  su_root_t *root;

Pekka Pessi's avatar
Pekka Pessi committed
119 120
  int threading;

121
  struct endpoint {
Pekka Pessi's avatar
Pekka Pessi committed
122
    char name[4];
Pekka Pessi's avatar
Pekka Pessi committed
123
    struct context *ctx;	/* Backpointer */
124 125 126

    int running;

127 128
    condition_function *next_condition;
    nua_event_t next_event, last_event;
Pekka Pessi's avatar
Pekka Pessi committed
129
    nua_t *nua;
130
    sip_contact_t *contact;
Pekka Pessi's avatar
Pekka Pessi committed
131
    sip_from_t *to;
Pekka Pessi's avatar
Pekka Pessi committed
132

Pekka Pessi's avatar
Pekka Pessi committed
133
    printer_function *printer;
Pekka Pessi's avatar
Pekka Pessi committed
134

Pekka Pessi's avatar
Pekka Pessi committed
135
    /* Per-call stuff */
Pekka Pessi's avatar
Pekka Pessi committed
136 137 138 139 140 141
    struct call {
      struct call *next;
      nua_handle_t *nh;
      struct {
	struct event *head, **tail;
      } events;
142
      char const *sdp;
Pekka Pessi's avatar
Pekka Pessi committed
143
    } call[1], reg[1];
Pekka Pessi's avatar
Pekka Pessi committed
144 145 146 147 148 149 150 151 152 153

    /* State flags for complex scenarios */
    union {
      struct {
	unsigned bit0:1, bit1:1, bit2:1, bit3:1;
	unsigned bit4:1, bit5:1, bit6:1, bit7:1;
      } b;
      unsigned n;
    } flags;

154
  } a, b, c;
Pekka Pessi's avatar
Pekka Pessi committed
155 156

  struct proxy *p;
Pekka Pessi's avatar
Pekka Pessi committed
157 158
};

159
struct event
160 161 162
{
  struct event *next, **prev;
  nua_saved_event_t saved_event[1];
Pekka Pessi's avatar
Pekka Pessi committed
163
  nua_event_data_t const *data;
164 165
};

Pekka Pessi's avatar
Pekka Pessi committed
166 167 168 169 170 171
static int save_event_in_list(struct context *,
			      nua_event_t nevent,
			      struct endpoint *,
			      struct call *);
static void free_events_in_list(struct context *,
				struct call *);
172

173 174 175 176 177
#define CONDITION_FUNCTION(name)		\
  int name(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
178
	   nua_handle_t *nh, struct call *call, \
179 180 181
	   sip_t const *sip,			\
	   tagi_t tags[])

182 183
CONDITION_FUNCTION(until_final_response){ return status >= 200; }
CONDITION_FUNCTION(save_until_final_response)
184
{
Pekka Pessi's avatar
Pekka Pessi committed
185 186
  save_event_in_list(ctx, event, ep, ep->call);
  return event >= nua_r_set_params && status >= 200;
187 188
}

Pekka Pessi's avatar
Pekka Pessi committed
189 190 191
/** Save events (except nua_i_active or terminated).
 * Terminate when a event is saved.
 */
192 193
CONDITION_FUNCTION(save_until_received)
{
Pekka Pessi's avatar
Pekka Pessi committed
194
  save_event_in_list(ctx, event, ep, ep->call);
195 196 197
  return 1;
}

Pekka Pessi's avatar
Pekka Pessi committed
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
/* 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;
}

/* 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
247 248 249 250 251 252 253 254 255
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
256 257 258
{
  if (event == nua_i_state) {
    fprintf(stderr, "%s.nua(%p): event %s %s\n",
259
	    ep->name, nh, nua_event_name(event),
Pekka Pessi's avatar
Pekka Pessi committed
260 261
	    nua_callstate_name(callstate(tags)));
  }
Pekka Pessi's avatar
Pekka Pessi committed
262
  else if ((int)event >= nua_r_set_params) {
Pekka Pessi's avatar
Pekka Pessi committed
263 264 265
    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
266 267 268 269
  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
270 271
  else if (status > 0) {
    fprintf(stderr, "%s.nua(%p): call %s() with status %u %s\n",
272
	    ep->name, nh, operation, status, phrase);
Pekka Pessi's avatar
Pekka Pessi committed
273 274
  }
  else {
Pekka Pessi's avatar
Pekka Pessi committed
275 276 277 278 279
    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
280
	      ep->name, nh, operation, subject);
Pekka Pessi's avatar
Pekka Pessi committed
281 282 283
    }
    else
      fprintf(stderr, "%s.nua(%p): call %s()\n",
Pekka Pessi's avatar
Pekka Pessi committed
284
	      ep->name, nh, operation);
Pekka Pessi's avatar
Pekka Pessi committed
285 286 287 288 289
  }

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

291 292 293 294
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
295
		 nua_handle_t *nh, struct call *call,
296 297
		 sip_t const *sip,
		 tagi_t tags[])
298
{
Pekka Pessi's avatar
Pekka Pessi committed
299
  if (ep->printer)
Pekka Pessi's avatar
Pekka Pessi committed
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
    ep->printer(event, "", status, phrase, nua, ctx, ep, nh, call, sip, tags);

  if (call == NULL) {
    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
315 316 317 318 319

  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)))
320
    ep->running = 0;
321

Pekka Pessi's avatar
Pekka Pessi committed
322
  ep->last_event = event;
323 324
}

325
void a_callback(nua_event_t event,
326 327
		int status, char const *phrase,
		nua_t *nua, struct context *ctx,
Pekka Pessi's avatar
Pekka Pessi committed
328
		nua_handle_t *nh, struct call *call,
329 330
		sip_t const *sip,
		tagi_t tags[])
Pekka Pessi's avatar
Pekka Pessi committed
331
{
332 333
  ep_callback(event, status, phrase, nua, ctx, &ctx->a, nh, call, sip, tags);
}
334

335 336 337
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
338
		nua_handle_t *nh, struct call *call,
339 340 341 342 343
		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
344

345 346 347
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
348
		nua_handle_t *nh, struct call *call,
349 350 351 352
		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
353 354
}

355 356 357 358
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
359
{
360
  struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
361 362 363 364 365

  a->next_event = a_event;
  a->next_condition = a_condition;
  a->last_event = -1;
  a->running = a_condition != NULL || a_event != -1;
Pekka Pessi's avatar
Pekka Pessi committed
366
  a->flags.n = 0;
367 368 369 370 371

  b->next_event = b_event;
  b->next_condition = b_condition;
  b->last_event = -1;
  b->running = b_condition != NULL || b_event != -1;
Pekka Pessi's avatar
Pekka Pessi committed
372
  b->flags.n = 0;
Pekka Pessi's avatar
Pekka Pessi committed
373

374 375 376 377
  c->next_event = c_event;
  c->next_condition = c_condition;
  c->last_event = -1;
  c->running = c_condition != NULL || c_event != -1;
Pekka Pessi's avatar
Pekka Pessi committed
378
  c->flags.n = 0;
379 380

  for (; a->running || b->running || c->running;) {
Pekka Pessi's avatar
Pekka Pessi committed
381 382
    su_root_step(ctx->root, 1000);
  }
383
}
Pekka Pessi's avatar
Pekka Pessi committed
384

385 386 387 388 389 390 391
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);
}

392 393 394 395
int run_a_until(struct context *ctx,
		nua_event_t a_event,
		condition_function *a_condition)
{
396
  run_abc_until(ctx, a_event, a_condition, -1, NULL, -1, NULL);
397 398 399 400 401 402 403
  return ctx->a.last_event;
}

int run_b_until(struct context *ctx,
		nua_event_t b_event,
		condition_function *b_condition)
{
404
  run_abc_until(ctx, -1, NULL, b_event, b_condition, -1, NULL);
405
  return ctx->b.last_event;
Pekka Pessi's avatar
Pekka Pessi committed
406 407
}

Pekka Pessi's avatar
Pekka Pessi committed
408 409 410 411 412 413 414 415
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;
}

Pekka Pessi's avatar
Pekka Pessi committed
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
#define OPERATION(x) \
int x(struct endpoint *ep, \
      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

OPERATION(invite);
436
OPERATION(ack);
Pekka Pessi's avatar
Pekka Pessi committed
437 438 439
OPERATION(bye);
OPERATION(cancel);
OPERATION(authenticate);
440
OPERATION(update);
441
OPERATION(info);
Pekka Pessi's avatar
Pekka Pessi committed
442 443 444 445
OPERATION(refer);
OPERATION(message);
OPERATION(options);
OPERATION(publish);
446 447
OPERATION(unpublish);
OPERATION(unregister);
Pekka Pessi's avatar
Pekka Pessi committed
448
OPERATION(subscribe);
Pekka Pessi's avatar
Pekka Pessi committed
449
OPERATION(unsubscribe);
450 451 452
OPERATION(notify);
OPERATION(notifier);
OPERATION(terminate);
453
OPERATION(authorize);
454

455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
int do_register(struct endpoint *ep,
		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_" "register", 0, "", ep->nua, ep->ctx, ep,
		nh, call, NULL, ta_args(ta));

  nua_register(nh, ta_tags(ta));

  ta_end(ta);
  return 0;
}

Pekka Pessi's avatar
Pekka Pessi committed
473
/* Respond via endpoint and handle */
Pekka Pessi's avatar
Pekka Pessi committed
474 475 476
int respond(struct endpoint *ep,
	    struct call *call,
	    nua_handle_t *nh,
Pekka Pessi's avatar
Pekka Pessi committed
477 478 479 480 481 482 483
	    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
484 485

  if (ep->printer)
Pekka Pessi's avatar
Pekka Pessi committed
486 487
    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
488

Pekka Pessi's avatar
Pekka Pessi committed
489 490 491 492 493 494
  nua_respond(nh, status, phrase, ta_tags(ta));
  ta_end(ta);

  return 0;
}

495

Pekka Pessi's avatar
Pekka Pessi committed
496 497 498 499 500
/* 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)
501
{
Pekka Pessi's avatar
Pekka Pessi committed
502 503
  if (call)
    return call;
504

Pekka Pessi's avatar
Pekka Pessi committed
505 506
  if (status)
    respond(ep, call, nh, status, phrase, TAG_END());
507

Pekka Pessi's avatar
Pekka Pessi committed
508 509
  nua_handle_destroy(nh);
  return NULL;
510 511
}

Pekka Pessi's avatar
Pekka Pessi committed
512

Pekka Pessi's avatar
Pekka Pessi committed
513 514
static void
call_init(struct call *call)
Pekka Pessi's avatar
Pekka Pessi committed
515
{
Pekka Pessi's avatar
Pekka Pessi committed
516
  call->events.tail = &call->events.head;
Pekka Pessi's avatar
Pekka Pessi committed
517 518
}

Pekka Pessi's avatar
Pekka Pessi committed
519
/* Save nua event in call-specific list */
520
static
521
int save_event_in_list(struct context *ctx,
Pekka Pessi's avatar
Pekka Pessi committed
522 523 524 525
		       nua_event_t nevent,
		       struct endpoint *ep,
		       struct call *call)

526
{
Pekka Pessi's avatar
Pekka Pessi committed
527 528 529 530 531 532
  struct event *e;

  if (nevent == nua_i_active || nevent == nua_i_terminated)
    return 0;

  e = su_zalloc(ctx->home, sizeof *e);
533 534

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

536 537
  if (!nua_save_event(ep->nua, e->saved_event)) {
    su_free(ctx->home, e);
Pekka Pessi's avatar
Pekka Pessi committed
538
    return -1;
539
  }
Pekka Pessi's avatar
Pekka Pessi committed
540

541 542
  *(e->prev = call->events.tail) = e;
  call->events.tail = &e->next;
Pekka Pessi's avatar
Pekka Pessi committed
543
  e->data = nua_event_data(e->saved_event);
544

Pekka Pessi's avatar
Pekka Pessi committed
545
  return 1;
546
}
Pekka Pessi's avatar
Pekka Pessi committed
547

Pekka Pessi's avatar
Pekka Pessi committed
548
/* Save nua event in endpoint list */
549
static
Pekka Pessi's avatar
Pekka Pessi committed
550 551
void free_events_in_list(struct context *ctx,
			 struct call *call)
Pekka Pessi's avatar
Pekka Pessi committed
552 553 554
{
  struct event *e;

Pekka Pessi's avatar
Pekka Pessi committed
555
  while ((e = call->events.head)) {
Pekka Pessi's avatar
Pekka Pessi committed
556 557 558 559 560
    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
561
  call->events.tail = &call->events.head;
Pekka Pessi's avatar
Pekka Pessi committed
562 563
}

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

Pekka Pessi's avatar
Pekka Pessi committed
566 567 568 569 570
int check_set_status(int status, char const *phrase)
{
  return status == 200 && strcmp(phrase, sip_200_OK) == 0;
}

Pekka Pessi's avatar
Pekka Pessi committed
571 572 573 574
int test_api_errors(struct context *ctx)
{
  BEGIN();

Pekka Pessi's avatar
Pekka Pessi committed
575
  /* Invoke every API function with invalid arguments */
Pekka Pessi's avatar
Pekka Pessi committed
576

Pekka Pessi's avatar
Pekka Pessi committed
577 578
  int level;

Pekka Pessi's avatar
Pekka Pessi committed
579 580
  int status; char const *phrase;

581 582 583
  if (print_headings)
    printf("TEST NUA-1.0: test API\n");

Pekka Pessi's avatar
Pekka Pessi committed
584 585 586 587 588
  /* This is a nasty macro. Test it. */
#define SET_STATUS1(x) ((status = x), status), (phrase = ((void)x))
  TEST_1(check_set_status(SET_STATUS1(SIP_200_OK)));
  TEST(status, 200); TEST_S(phrase, sip_200_OK);

Pekka Pessi's avatar
Pekka Pessi committed
589 590 591 592 593
  su_log_init(nua_log);

  level = nua_log->log_level;
  if (!(tstflags & tst_verbatim))
    su_log_set_level(nua_log, 0);
Pekka Pessi's avatar
Pekka Pessi committed
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

  TEST_1(!nua_create(NULL, NULL, NULL, TAG_END()));
  TEST_VOID(nua_shutdown(NULL));
  TEST_VOID(nua_destroy(NULL));
  TEST_VOID(nua_set_params(NULL, TAG_END()));
  TEST_VOID(nua_get_params(NULL, TAG_END()));
  TEST_1(!nua_default(NULL));
  TEST_1(!nua_handle(NULL, NULL, TAG_END()));
  TEST_VOID(nua_handle_destroy(NULL));
  TEST_VOID(nua_handle_bind(NULL, NULL));
  TEST_1(!nua_handle_has_invite(NULL));
  TEST_1(!nua_handle_has_subscribe(NULL));
  TEST_1(!nua_handle_has_register(NULL));
  TEST_1(!nua_handle_has_active_call(NULL));
  TEST_1(!nua_handle_has_call_on_hold(NULL));
  TEST_1(!nua_handle_has_events(NULL));
  TEST_1(!nua_handle_has_registrations(NULL));
  TEST_1(!nua_handle_remote(NULL));
  TEST_1(!nua_handle_local(NULL));
  TEST_S(nua_event_name(-1), "NUA_UNKNOWN");
  TEST_VOID(nua_register(NULL, TAG_END()));
  TEST_VOID(nua_unregister(NULL, TAG_END()));
  TEST_VOID(nua_invite(NULL, TAG_END()));
  TEST_VOID(nua_ack(NULL, TAG_END()));
  TEST_VOID(nua_options(NULL, TAG_END()));
  TEST_VOID(nua_publish(NULL, TAG_END()));
  TEST_VOID(nua_message(NULL, TAG_END()));
  TEST_VOID(nua_chat(NULL, TAG_END()));
  TEST_VOID(nua_info(NULL, TAG_END()));
  TEST_VOID(nua_subscribe(NULL, TAG_END()));
  TEST_VOID(nua_unsubscribe(NULL, TAG_END()));
  TEST_VOID(nua_notify(NULL, TAG_END()));
  TEST_VOID(nua_notifier(NULL, TAG_END()));
  TEST_VOID(nua_terminate(NULL, TAG_END()));
  TEST_VOID(nua_refer(NULL, TAG_END()));
  TEST_VOID(nua_update(NULL, TAG_END()));
  TEST_VOID(nua_bye(NULL, TAG_END()));
  TEST_VOID(nua_cancel(NULL, TAG_END()));
  TEST_VOID(nua_authenticate(NULL, TAG_END()));
  TEST_VOID(nua_redirect(NULL, TAG_END()));
  TEST_VOID(nua_respond(NULL, 0, "", TAG_END()));
Pekka Pessi's avatar
Pekka Pessi committed
635

Pekka Pessi's avatar
Pekka Pessi committed
636 637
  TEST_1(!nua_handle_home(NULL));
  TEST_1(!nua_save_event(NULL, NULL));
638
  TEST_1(!nua_event_data(NULL));
Pekka Pessi's avatar
Pekka Pessi committed
639
  TEST_VOID(nua_destroy_event(NULL));
640

Pekka Pessi's avatar
Pekka Pessi committed
641 642 643 644
  {
    nua_saved_event_t event[1];

    memset(event, 0, sizeof event);
645

Pekka Pessi's avatar
Pekka Pessi committed
646
    TEST_1(!nua_save_event(NULL, event));
647
    TEST_1(!nua_event_data(event));
Pekka Pessi's avatar
Pekka Pessi committed
648 649 650
    TEST_VOID(nua_destroy_event(event));
  }

Pekka Pessi's avatar
Pekka Pessi committed
651
  su_log_set_level(nua_log, level);
Pekka Pessi's avatar
Pekka Pessi committed
652

653 654 655
  if (print_headings)
    printf("TEST NUA-1.0: PASSED\n");

Pekka Pessi's avatar
Pekka Pessi committed
656 657 658 659 660 661
  END();
}

int test_params(struct context *ctx)
{
  BEGIN();
662 663 664 665 666 667 668 669

  char const Alice[] = "Alice <sip:a@wonderland.org>";
  sip_from_t const *from;
  su_home_t tmphome[SU_HOME_AUTO_SIZE(16384)];
  nua_handle_t *nh;

  su_home_auto(tmphome, sizeof(tmphome));

670 671 672
  if (print_headings)
    printf("TEST NUA-2.0: PARAMETERS\n");

Pekka Pessi's avatar
Pekka Pessi committed
673
  ctx->root = su_root_create(NULL); TEST_1(ctx->root);
674

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

678 679
  ctx->a.nua = nua_create(ctx->root, a_callback, ctx,
			  SIPTAG_FROM_STR("sip:alice@example.com"),
680
			  NUTAG_URL("sip:0.0.0.0:*;transport=udp"),
681
			  TAG_END());
682

683 684
  TEST_1(ctx->a.nua);

685
  from = sip_from_make(tmphome, Alice);
686 687 688

  nh = nua_handle(ctx->a.nua, NULL, TAG_END());

689
  nua_set_hparams(nh, NUTAG_INVITE_TIMER(90), TAG_END());
690
  run_a_until(ctx, nua_r_set_params, until_final_response);
691

692 693 694 695 696 697 698 699 700 701 702 703 704 705
  /* Modify all pointer values */
  nua_set_params(ctx->a.nua,
		 SIPTAG_FROM_STR(Alice),

		 SIPTAG_SUPPORTED_STR("test"),
		 SIPTAG_ALLOW_STR("DWIM, OPTIONS, INFO"),
		 SIPTAG_USER_AGENT_STR("test_nua/1.0"),

		 SIPTAG_ORGANIZATION_STR("Te-Ras y.r."),

		 NUTAG_REGISTRAR("sip:openlaboratory.net"),

		 TAG_END());

706
  run_a_until(ctx, nua_r_set_params, until_final_response);
707

708 709 710
  /* Modify everything from their default value */
  nua_set_params(ctx->a.nua,
		 SIPTAG_FROM(from),
711
		 NUTAG_RETRY_COUNT(9),
712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
		 NUTAG_MAX_SUBSCRIPTIONS(6),

		 NUTAG_ENABLEINVITE(0),
		 NUTAG_AUTOALERT(1),
		 NUTAG_EARLY_MEDIA(1),
		 NUTAG_AUTOANSWER(1),
		 NUTAG_AUTOACK(0),
		 NUTAG_INVITE_TIMER(60),

		 NUTAG_SESSION_TIMER(600),
		 NUTAG_MIN_SE(35),
		 NUTAG_SESSION_REFRESHER(nua_remote_refresher),
		 NUTAG_UPDATE_REFRESH(1),

		 NUTAG_ENABLEMESSAGE(0),
		 NUTAG_ENABLEMESSENGER(1),
		 /* NUTAG_MESSAGE_AUTOANSWER(0), */

		 NUTAG_CALLEE_CAPS(1),
		 NUTAG_MEDIA_FEATURES(1),
		 NUTAG_SERVICE_ROUTE_ENABLE(0),
		 NUTAG_PATH_ENABLE(0),
734
		 NUTAG_SUBSTATE(nua_substate_pending),
735

736 737 738
		 SIPTAG_SUPPORTED(sip_supported_make(tmphome, "humppaa,kuole")),
		 SIPTAG_ALLOW(sip_allow_make(tmphome, "OPTIONS, INFO")),
		 SIPTAG_USER_AGENT(sip_user_agent_make(tmphome, "test_nua")),
739

740
		 SIPTAG_ORGANIZATION(sip_organization_make(tmphome, "Pussy Galore's Flying Circus")),
741 742

		 NUTAG_MEDIA_ENABLE(0),
743
		 NUTAG_REGISTRAR(url_hdup(tmphome, (url_t *)"sip:sip.wonderland.org")),
744

745 746
		 TAG_END());

747
  run_a_until(ctx, nua_r_set_params, until_final_response);
748

749 750 751 752
  /* Modify something... */
  nua_set_params(ctx->a.nua,
		 NUTAG_RETRY_COUNT(5),
		 TAG_END());
753
  run_a_until(ctx, nua_r_set_params, until_final_response);
754 755 756 757 758

  {
    sip_from_t const *from = NONE;
    char const *from_str = "NONE";

Pekka Pessi's avatar
Pekka Pessi committed
759 760
    unsigned retry_count = -1;
    unsigned max_subscriptions = -1;
761

762 763 764 765 766
    int invite_enable = -1;
    int auto_alert = -1;
    int early_media = -1;
    int auto_answer = -1;
    int auto_ack = -1;
Pekka Pessi's avatar
Pekka Pessi committed
767
    unsigned invite_timeout = -1;
768

Pekka Pessi's avatar
Pekka Pessi committed
769 770
    unsigned session_timer = -1;
    unsigned min_se = -1;
771 772
    int refresher = -1;
    int update_refresh = -1;
773

774 775 776
    int message_enable = -1;
    int win_messenger_enable = -1;
    int message_auto_respond = -1;
777

778 779 780 781
    int callee_caps = -1;
    int media_features = -1;
    int service_route_enable = -1;
    int path_enable = -1;
782
    int substate = -1;
783 784

    sip_allow_t const *allow = NONE;
785
    char const *allow_str = "NONE";
786 787 788 789 790 791 792 793 794 795
    sip_supported_t const *supported = NONE;
    char const *supported_str = "NONE";
    sip_user_agent_t const *user_agent = NONE;
    char const *user_agent_str = "NONE";
    sip_organization_t const *organization = NONE;
    char const *organization_str = "NONE";

    url_string_t const *registrar = NONE;

    int n;
796
    struct event *e;
797

Pekka Pessi's avatar
Pekka Pessi committed
798
    nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
799
    run_a_until(ctx, nua_r_get_params, save_until_final_response);
800

Pekka Pessi's avatar
Pekka Pessi committed
801
    TEST_1(e = ctx->a.call->events.head);
802
    TEST_E(e->data->e_event, nua_r_get_params);
803

804
    n = tl_gets(e->data->e_tags,
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
	       	SIPTAG_FROM_REF(from),
	       	SIPTAG_FROM_STR_REF(from_str),

	       	NUTAG_RETRY_COUNT_REF(retry_count),
	       	NUTAG_MAX_SUBSCRIPTIONS_REF(max_subscriptions),

	       	NUTAG_ENABLEINVITE_REF(invite_enable),
	       	NUTAG_AUTOALERT_REF(auto_alert),
	       	NUTAG_EARLY_MEDIA_REF(early_media),
	       	NUTAG_AUTOANSWER_REF(auto_answer),
	       	NUTAG_AUTOACK_REF(auto_ack),
	       	NUTAG_INVITE_TIMER_REF(invite_timeout),

	       	NUTAG_SESSION_TIMER_REF(session_timer),
	       	NUTAG_MIN_SE_REF(min_se),
	       	NUTAG_SESSION_REFRESHER_REF(refresher),
	       	NUTAG_UPDATE_REFRESH_REF(update_refresh),

	       	NUTAG_ENABLEMESSAGE_REF(message_enable),
	       	NUTAG_ENABLEMESSENGER_REF(win_messenger_enable),
	       	/* NUTAG_MESSAGE_AUTOANSWER(message_auto_respond), */

	       	NUTAG_CALLEE_CAPS_REF(callee_caps),
	       	NUTAG_MEDIA_FEATURES_REF(media_features),
	       	NUTAG_SERVICE_ROUTE_ENABLE_REF(service_route_enable),
	       	NUTAG_PATH_ENABLE_REF(path_enable),
831
	       	NUTAG_SUBSTATE_REF(substate),
832 833 834 835 836 837 838 839 840 841 842 843 844 845

	       	SIPTAG_SUPPORTED_REF(supported),
	       	SIPTAG_SUPPORTED_STR_REF(supported_str),
	       	SIPTAG_ALLOW_REF(allow),
	       	SIPTAG_ALLOW_STR_REF(allow_str),
	       	SIPTAG_USER_AGENT_REF(user_agent),
	       	SIPTAG_USER_AGENT_STR_REF(user_agent_str),

	       	SIPTAG_ORGANIZATION_REF(organization),
	       	SIPTAG_ORGANIZATION_STR_REF(organization_str),

	       	NUTAG_REGISTRAR_REF(registrar),

		TAG_END());
846
    TEST(n, 30);
847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873

    TEST_S(sip_header_as_string(tmphome, (void *)from), Alice);
    TEST_S(from_str, Alice);

    TEST(retry_count, 5);
    TEST(max_subscriptions, 6);

    TEST(invite_enable, 0);
    TEST(auto_alert, 1);
    TEST(early_media, 1);
    TEST(auto_answer, 1);
    TEST(auto_ack, 0);
    TEST(invite_timeout, 60);

    TEST(session_timer, 600);
    TEST(min_se, 35);
    TEST(refresher, nua_remote_refresher);
    TEST(update_refresh, 1);

    TEST(message_enable, 0);
    TEST(win_messenger_enable, 1);
    TEST(message_auto_respond, -1); /* XXX */

    TEST(callee_caps, 1);
    TEST(media_features, 1);
    TEST(service_route_enable, 0);
    TEST(path_enable, 0);
874
    TEST(substate, nua_substate_pending);
875 876 877 878 879 880 881

    TEST_S(sip_header_as_string(tmphome, (void *)allow), "OPTIONS, INFO");
    TEST_S(allow_str, "OPTIONS, INFO");
    TEST_S(sip_header_as_string(tmphome, (void *)supported), "humppaa, kuole");
    TEST_S(supported_str, "humppaa, kuole");
    TEST_S(sip_header_as_string(tmphome, (void *)user_agent), "test_nua");
    TEST_S(user_agent_str, "test_nua");
882
    TEST_S(sip_header_as_string(tmphome, (void *)organization),
883 884 885
	   "Pussy Galore's Flying Circus");
    TEST_S(organization_str, "Pussy Galore's Flying Circus");

886
    TEST_S(url_as_string(tmphome, registrar->us_url),
887
	   "sip:sip.wonderland.org");
888

Pekka Pessi's avatar
Pekka Pessi committed
889
    free_events_in_list(ctx, ctx->a.call);
890
  }
891

892 893
  /* Test that only those tags that have been set per handle are returned by nua_get_hparams() */

894 895 896 897
  {
    sip_from_t const *from = NONE;
    char const *from_str = "NONE";

Pekka Pessi's avatar
Pekka Pessi committed
898 899
    unsigned retry_count = -1;
    unsigned max_subscriptions = -1;
900

901 902 903 904 905
    int invite_enable = -1;
    int auto_alert = -1;
    int early_media = -1;
    int auto_answer = -1;
    int auto_ack = -1;
Pekka Pessi's avatar
Pekka Pessi committed
906
    unsigned invite_timeout = -1;
907

Pekka Pessi's avatar
Pekka Pessi committed
908 909
    unsigned session_timer = -1;
    unsigned min_se = -1;
910 911
    int refresher = -1;
    int update_refresh = -1;
912

913 914 915
    int message_enable = -1;
    int win_messenger_enable = -1;
    int message_auto_respond = -1;
916

917 918 919 920
    int callee_caps = -1;
    int media_features = -1;
    int service_route_enable = -1;
    int path_enable = -1;
921
    int substate = -1;
922 923 924 925 926 927 928 929 930 931 932 933 934

    sip_allow_t const *allow = NONE;
    char const   *allow_str = "NONE";
    sip_supported_t const *supported = NONE;
    char const *supported_str = "NONE";
    sip_user_agent_t const *user_agent = NONE;
    char const *user_agent_str = "NONE";
    sip_organization_t const *organization = NONE;
    char const *organization_str = "NONE";

    url_string_t const *registrar = NONE;

    int n;
935
    struct event *e;
936

937
    nua_get_hparams(nh, TAG_ANY(), TAG_END());
938
    run_a_until(ctx, nua_r_get_params, save_until_final_response);
939

Pekka Pessi's avatar
Pekka Pessi committed
940
    TEST_1(e = ctx->a.call->events.head);
941
    TEST_E(e->data->e_event, nua_r_get_params);
942

943
    n = tl_gets(e->data->e_tags,
944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
	       	SIPTAG_FROM_REF(from),
	       	SIPTAG_FROM_STR_REF(from_str),

	       	NUTAG_RETRY_COUNT_REF(retry_count),
	       	NUTAG_MAX_SUBSCRIPTIONS_REF(max_subscriptions),

	       	NUTAG_ENABLEINVITE_REF(invite_enable),
	       	NUTAG_AUTOALERT_REF(auto_alert),
	       	NUTAG_EARLY_MEDIA_REF(early_media),
	       	NUTAG_AUTOANSWER_REF(auto_answer),
	       	NUTAG_AUTOACK_REF(auto_ack),
	       	NUTAG_INVITE_TIMER_REF(invite_timeout),

	       	NUTAG_SESSION_TIMER_REF(session_timer),
	       	NUTAG_MIN_SE_REF(min_se),
	       	NUTAG_SESSION_REFRESHER_REF(refresher),
	       	NUTAG_UPDATE_REFRESH_REF(update_refresh),

	       	NUTAG_ENABLEMESSAGE_REF(message_enable),
	       	NUTAG_ENABLEMESSENGER_REF(win_messenger_enable),
	       	/* NUTAG_MESSAGE_AUTOANSWER(message_auto_respond), */

	       	NUTAG_CALLEE_CAPS_REF(callee_caps),
	       	NUTAG_MEDIA_FEATURES_REF(media_features),
	       	NUTAG_SERVICE_ROUTE_ENABLE_REF(service_route_enable),
	       	NUTAG_PATH_ENABLE_REF(path_enable),
970
	       	NUTAG_SUBSTATE_REF(substate),
971 972 973 974 975 976 977 978 979 980 981 982 983 984

	       	SIPTAG_SUPPORTED_REF(supported),
	       	SIPTAG_SUPPORTED_STR_REF(supported_str),
	       	SIPTAG_ALLOW_REF(allow),
	       	SIPTAG_ALLOW_STR_REF(allow_str),
	       	SIPTAG_USER_AGENT_REF(user_agent),
	       	SIPTAG_USER_AGENT_STR_REF(user_agent_str),

	       	SIPTAG_ORGANIZATION_REF(organization),
	       	SIPTAG_ORGANIZATION_STR_REF(organization_str),

	       	NUTAG_REGISTRAR_REF(registrar),

		TAG_END());
985
    TEST(n, 3);
986 987 988

    TEST(invite_timeout, 90);

989 990
    TEST_1(from != NULL && from != NONE);
    TEST_1(strcmp(from_str, "NONE"));
991

992
    /* Nothing else should be set */
993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
    TEST(retry_count, -1);
    TEST(max_subscriptions, -1);

    TEST(invite_enable, -1);
    TEST(auto_alert, -1);
    TEST(early_media, -1);
    TEST(auto_answer, -1);
    TEST(auto_ack, -1);

    TEST(session_timer, -1);
    TEST(min_se, -1);
    TEST(refresher, -1);
    TEST(update_refresh, -1);

    TEST(message_enable, -1);
    TEST(win_messenger_enable, -1);
    TEST(message_auto_respond, -1); /* XXX */

    TEST(callee_caps, -1);
    TEST(media_features, -1);
    TEST(service_route_enable, -1);
    TEST(path_enable, -1);
1015
    TEST(substate, -1);
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026

    TEST(allow, NONE);
    TEST_S(allow_str, "NONE");
    TEST(supported, NONE);
    TEST_S(supported_str, "NONE");
    TEST(user_agent, NONE);
    TEST_S(user_agent_str, "NONE");
    TEST(organization, NONE);
    TEST_S(organization_str, "NONE");

    TEST(registrar->us_url, NONE);
Pekka Pessi's avatar
Pekka Pessi committed
1027

Pekka Pessi's avatar
Pekka Pessi committed
1028
    free_events_in_list(ctx, ctx->a.call);
1029 1030 1031
  }

  nua_handle_destroy(nh);
1032

1033
  nua_shutdown(ctx->a.nua);
1034
  run_a_until(ctx, nua_r_shutdown, until_final_response);
1035 1036 1037 1038 1039
  nua_destroy(ctx->a.nua), ctx->a.nua = NULL;

  su_root_destroy(ctx->root), ctx->root = NULL;

  su_home_deinit(tmphome);