test_nua.c 131 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
/*
 * 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"

struct context;
#define NUA_MAGIC_T struct context
Pekka Pessi's avatar
Pekka Pessi committed
37 38 39

struct call;
#define NUA_HMAGIC_T struct call
Pekka Pessi's avatar
Pekka Pessi committed
40 41

#include "nua.h"
42
#include "sip_status.h"
Pekka Pessi's avatar
Pekka Pessi committed
43 44

#include <sdp.h>
45
#include <sip_header.h>
Pekka Pessi's avatar
Pekka Pessi committed
46 47

#include <su_log.h>
Pekka Pessi's avatar
Pekka Pessi committed
48
#include <su_tagarg.h>
Pekka Pessi's avatar
Pekka Pessi committed
49
#include <su_tag_io.h>
Pekka Pessi's avatar
Pekka Pessi committed
50

Pekka Pessi's avatar
Pekka Pessi committed
51 52
#include <test_proxy.h>

53 54 55 56 57 58 59 60 61 62 63
#include <stddef.h>
#include <stdlib.h>
#include <string.h>

#include <assert.h>

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

Pekka Pessi's avatar
Pekka Pessi committed
64
extern su_log_t nua_log[];
65 66 67
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
68 69 70
extern su_log_t su_log_default[];

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

int print_headings = 1;
Pekka Pessi's avatar
Pekka Pessi committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86
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)

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

89 90 91
struct endpoint;

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

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

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

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

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

    int running;

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

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

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

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

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

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

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

Pekka Pessi's avatar
Pekka Pessi committed
165 166 167 168 169 170
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 *);
171

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

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

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

Pekka Pessi's avatar
Pekka Pessi committed
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
/* 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
246 247 248 249 250 251 252 253 254
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
255 256 257
{
  if (event == nua_i_state) {
    fprintf(stderr, "%s.nua(%p): event %s %s\n",
258
	    ep->name, nh, nua_event_name(event),
Pekka Pessi's avatar
Pekka Pessi committed
259 260
	    nua_callstate_name(callstate(tags)));
  }
Pekka Pessi's avatar
Pekka Pessi committed
261
  else if ((int)event >= nua_r_set_params) {
Pekka Pessi's avatar
Pekka Pessi committed
262 263 264
    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
265 266 267 268
  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
269 270
  else if (status > 0) {
    fprintf(stderr, "%s.nua(%p): call %s() with status %u %s\n",
271
	    ep->name, nh, operation, status, phrase);
Pekka Pessi's avatar
Pekka Pessi committed
272 273
  }
  else {
Pekka Pessi's avatar
Pekka Pessi committed
274 275 276 277 278
    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
279
	      ep->name, nh, operation, subject);
Pekka Pessi's avatar
Pekka Pessi committed
280 281 282
    }
    else
      fprintf(stderr, "%s.nua(%p): call %s()\n",
Pekka Pessi's avatar
Pekka Pessi committed
283
	      ep->name, nh, operation);
Pekka Pessi's avatar
Pekka Pessi committed
284 285 286 287 288
  }

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

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

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

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

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

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

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

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

  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
365
  a->flags.n = 0;
366 367 368 369 370

  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
371
  b->flags.n = 0;
Pekka Pessi's avatar
Pekka Pessi committed
372

373 374 375 376
  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
377
  c->flags.n = 0;
378 379

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

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

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

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

Pekka Pessi's avatar
Pekka Pessi committed
407 408 409 410 411 412 413 414
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
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
#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);
435
OPERATION(ack);
Pekka Pessi's avatar
Pekka Pessi committed
436 437 438
OPERATION(bye);
OPERATION(cancel);
OPERATION(authenticate);
439
OPERATION(update);
440
OPERATION(info);
Pekka Pessi's avatar
Pekka Pessi committed
441 442 443 444
OPERATION(refer);
OPERATION(message);
OPERATION(options);
OPERATION(publish);
445 446
OPERATION(unpublish);
OPERATION(unregister);
Pekka Pessi's avatar
Pekka Pessi committed
447
OPERATION(subscribe);
Pekka Pessi's avatar
Pekka Pessi committed
448
OPERATION(unsubscribe);
449 450 451
OPERATION(notify);
OPERATION(notifier);
OPERATION(terminate);
452
OPERATION(authorize);
453

454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
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
472
/* Respond via endpoint and handle */
Pekka Pessi's avatar
Pekka Pessi committed
473 474 475
int respond(struct endpoint *ep,
	    struct call *call,
	    nua_handle_t *nh,
Pekka Pessi's avatar
Pekka Pessi committed
476 477 478 479 480 481 482
	    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
483 484

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

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

  return 0;
}

494

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

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

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

Pekka Pessi's avatar
Pekka Pessi committed
511

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

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

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

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

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

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

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

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

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

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

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

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

Pekka Pessi's avatar
Pekka Pessi committed
565 566 567 568 569
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
570 571 572 573
int test_api_errors(struct context *ctx)
{
  BEGIN();

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

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

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

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

Pekka Pessi's avatar
Pekka Pessi committed
583 584 585 586 587
  /* 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
588 589 590 591 592
  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
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

  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
634

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

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

    memset(event, 0, sizeof event);
644

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

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

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

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

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

  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));

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

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

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

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

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

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

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

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

691 692 693 694 695 696 697 698 699 700 701 702 703 704
  /* 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());

705
  run_a_until(ctx, nua_r_set_params, until_final_response);
706

707 708 709
  /* Modify everything from their default value */
  nua_set_params(ctx->a.nua,
		 SIPTAG_FROM(from),
710
		 NUTAG_RETRY_COUNT(9),
711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
		 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),
733
		 NUTAG_SUBSTATE(nua_substate_pending),
734

735 736 737
		 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")),
738

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

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

744 745
		 TAG_END());

746
  run_a_until(ctx, nua_r_set_params, until_final_response);
747

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

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

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

761 762 763 764 765
    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
766
    unsigned invite_timeout = -1;
767

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

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

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

    sip_allow_t const *allow = NONE;
784
    char const *allow_str = "NONE";
785 786 787 788 789 790 791 792 793 794
    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;
795
    struct event *e;
796

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

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

803
    n = tl_gets(e->data->e_tags,
804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829
	       	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),
830
	       	NUTAG_SUBSTATE_REF(substate),
831 832 833 834 835 836 837 838 839 840 841 842 843 844

	       	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());
845
    TEST(n, 30);
846 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

    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);
873
    TEST(substate, nua_substate_pending);
874 875 876 877 878 879 880

    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");
881
    TEST_S(sip_header_as_string(tmphome, (void *)organization),
882 883 884
	   "Pussy Galore's Flying Circus");
    TEST_S(organization_str, "Pussy Galore's Flying Circus");

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

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

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

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

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

900 901 902 903 904
    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
905
    unsigned invite_timeout = -1;
906

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

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

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

    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;
934
    struct event *e;
935

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

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

942
    n = tl_gets(e->data->e_tags,
943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968
	       	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),
969
	       	NUTAG_SUBSTATE_REF(substate),
970 971 972 973 974 975 976 977 978 979 980 981 982 983

	       	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());
984
    TEST(n, 3);
985 986 987

    TEST(invite_timeout, 90);

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

991
    /* Nothing else should be set */
992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
    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);
1014
    TEST(substate, -1);
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025

    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
1026

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

  nua_handle_destroy(nh);
1031

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

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

  su_home_deinit(