test_nua.c 141 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 36 37
 *
 * @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
38 39 40

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

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

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

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

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

54 55 56 57 58 59 60 61 62 63 64
#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
65
extern su_log_t nua_log[];
66
extern su_log_t soa_log[];
67
extern su_log_t nea_log[];
68 69
extern su_log_t nta_log[];
extern su_log_t tport_log[];
Pekka Pessi's avatar
Pekka Pessi committed
70 71
extern su_log_t su_log_default[];

72 73 74
extern void *memmem(const void *haystack, size_t haystacklen,
		    const void *needle, size_t needlelen);

Pekka Pessi's avatar
Pekka Pessi committed
75
char const name[] = "test_nua";
76 77

int print_headings = 1;
Pekka Pessi's avatar
Pekka Pessi committed
78 79 80 81 82 83 84 85 86 87 88 89 90 91
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)

92 93
#define TEST_E(a, b) TEST_S(nua_event_name(a), nua_event_name(b))

94 95 96
struct endpoint;

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

Pekka Pessi's avatar
Pekka Pessi committed
105 106 107 108 109 110 111 112 113 114
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
115 116 117
struct proxy_transaction;
struct registration_entry;

118
struct context
Pekka Pessi's avatar
Pekka Pessi committed
119 120 121 122
{
  su_home_t home[1];
  su_root_t *root;

Pekka Pessi's avatar
Pekka Pessi committed
123 124
  int threading;

125
  struct endpoint {
Pekka Pessi's avatar
Pekka Pessi committed
126
    char name[4];
Pekka Pessi's avatar
Pekka Pessi committed
127
    struct context *ctx;	/* Backpointer */
128 129 130

    int running;

131 132
    condition_function *next_condition;
    nua_event_t next_event, last_event;
Pekka Pessi's avatar
Pekka Pessi committed
133
    nua_t *nua;
134
    sip_contact_t *contact;
Pekka Pessi's avatar
Pekka Pessi committed
135
    sip_from_t *to;
Pekka Pessi's avatar
Pekka Pessi committed
136

Pekka Pessi's avatar
Pekka Pessi committed
137
    printer_function *printer;
Pekka Pessi's avatar
Pekka Pessi committed
138

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

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

158
  } a, b, c;
Pekka Pessi's avatar
Pekka Pessi committed
159 160

  struct proxy *p;
Pekka Pessi's avatar
Pekka Pessi committed
161 162
};

163
struct event
164 165 166
{
  struct event *next, **prev;
  nua_saved_event_t saved_event[1];
Pekka Pessi's avatar
Pekka Pessi committed
167
  nua_event_data_t const *data;
168 169
};

Pekka Pessi's avatar
Pekka Pessi committed
170 171 172 173 174 175
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 *);
176

177 178 179 180 181
#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
182
	   nua_handle_t *nh, struct call *call, \
183 184 185
	   sip_t const *sip,			\
	   tagi_t tags[])

186 187
CONDITION_FUNCTION(until_final_response){ return status >= 200; }
CONDITION_FUNCTION(save_until_final_response)
188
{
Pekka Pessi's avatar
Pekka Pessi committed
189 190
  save_event_in_list(ctx, event, ep, ep->call);
  return event >= nua_r_set_params && status >= 200;
191 192
}

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

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

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

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

  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)))
324
    ep->running = 0;
325

Pekka Pessi's avatar
Pekka Pessi committed
326
  ep->last_event = event;
327 328
}

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

339 340 341
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
342
		nua_handle_t *nh, struct call *call,
343 344 345 346 347
		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
348

349 350 351
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
352
		nua_handle_t *nh, struct call *call,
353 354 355 356
		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
357 358
}

359 360 361 362
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
363
{
364
  struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
365 366 367 368 369

  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
370
  a->flags.n = 0;
371 372 373 374 375

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

378 379 380 381
  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
382
  c->flags.n = 0;
383 384

  for (; a->running || b->running || c->running;) {
Pekka Pessi's avatar
Pekka Pessi committed
385 386
    su_root_step(ctx->root, 1000);
  }
387
}
Pekka Pessi's avatar
Pekka Pessi committed
388

389 390 391 392 393 394 395
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);
}

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

int run_b_until(struct context *ctx,
		nua_event_t b_event,
		condition_function *b_condition)
{
408
  run_abc_until(ctx, -1, NULL, b_event, b_condition, -1, NULL);
409
  return ctx->b.last_event;
Pekka Pessi's avatar
Pekka Pessi committed
410 411
}

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

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

  if (ep->printer)
Pekka Pessi's avatar
Pekka Pessi committed
490 491
    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
492

Pekka Pessi's avatar
Pekka Pessi committed
493 494 495 496 497 498
  nua_respond(nh, status, phrase, ta_tags(ta));
  ta_end(ta);

  return 0;
}

499

Pekka Pessi's avatar
Pekka Pessi committed
500 501 502 503 504
/* 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)
505
{
Pekka Pessi's avatar
Pekka Pessi committed
506 507
  if (call)
    return call;
508

Pekka Pessi's avatar
Pekka Pessi committed
509 510
  if (status)
    respond(ep, call, nh, status, phrase, TAG_END());
511

Pekka Pessi's avatar
Pekka Pessi committed
512 513
  nua_handle_destroy(nh);
  return NULL;
514 515
}

Pekka Pessi's avatar
Pekka Pessi committed
516

Pekka Pessi's avatar
Pekka Pessi committed
517 518
static void
call_init(struct call *call)
Pekka Pessi's avatar
Pekka Pessi committed
519
{
Pekka Pessi's avatar
Pekka Pessi committed
520
  call->events.tail = &call->events.head;
Pekka Pessi's avatar
Pekka Pessi committed
521 522
}

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

530
{
Pekka Pessi's avatar
Pekka Pessi committed
531 532 533 534 535 536
  struct event *e;

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

  e = su_zalloc(ctx->home, sizeof *e);
537 538

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

540 541
  if (!nua_save_event(ep->nua, e->saved_event)) {
    su_free(ctx->home, e);
Pekka Pessi's avatar
Pekka Pessi committed
542
    return -1;
543
  }
Pekka Pessi's avatar
Pekka Pessi committed
544

545 546
  *(e->prev = call->events.tail) = e;
  call->events.tail = &e->next;
Pekka Pessi's avatar
Pekka Pessi committed
547
  e->data = nua_event_data(e->saved_event);
548

Pekka Pessi's avatar
Pekka Pessi committed
549
  return 1;
550
}
Pekka Pessi's avatar
Pekka Pessi committed
551

Pekka Pessi's avatar
Pekka Pessi committed
552
/* Save nua event in endpoint list */
553
static
Pekka Pessi's avatar
Pekka Pessi committed
554 555
void free_events_in_list(struct context *ctx,
			 struct call *call)
Pekka Pessi's avatar
Pekka Pessi committed
556 557 558
{
  struct event *e;

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

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

Pekka Pessi's avatar
Pekka Pessi committed
570 571 572 573 574
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
575 576 577 578
int test_api_errors(struct context *ctx)
{
  BEGIN();

Pekka Pessi's avatar
Pekka Pessi committed
579
  /* Invoke every API function with invalid arguments */
Pekka Pessi's avatar
Pekka Pessi committed
580

Pekka Pessi's avatar
Pekka Pessi committed
581 582
  int level;

Pekka Pessi's avatar
Pekka Pessi committed
583 584
  int status; char const *phrase;

585 586 587
  if (print_headings)
    printf("TEST NUA-1.0: test API\n");

Pekka Pessi's avatar
Pekka Pessi committed
588 589 590 591 592
  /* 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
593 594 595 596 597
  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
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638

  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
639

Pekka Pessi's avatar
Pekka Pessi committed
640 641
  TEST_1(!nua_handle_home(NULL));
  TEST_1(!nua_save_event(NULL, NULL));
642
  TEST_1(!nua_event_data(NULL));
Pekka Pessi's avatar
Pekka Pessi committed
643
  TEST_VOID(nua_destroy_event(NULL));
644

Pekka Pessi's avatar
Pekka Pessi committed
645 646 647 648
  {
    nua_saved_event_t event[1];

    memset(event, 0, sizeof event);
649

Pekka Pessi's avatar
Pekka Pessi committed
650
    TEST_1(!nua_save_event(NULL, event));
651
    TEST_1(!nua_event_data(event));
Pekka Pessi's avatar
Pekka Pessi committed
652 653 654
    TEST_VOID(nua_destroy_event(event));
  }

Pekka Pessi's avatar
Pekka Pessi committed
655
  su_log_set_level(nua_log, level);
Pekka Pessi's avatar
Pekka Pessi committed
656

657 658 659
  if (print_headings)
    printf("TEST NUA-1.0: PASSED\n");

Pekka Pessi's avatar
Pekka Pessi committed
660 661 662 663 664 665
  END();
}

int test_params(struct context *ctx)
{
  BEGIN();
666 667 668 669 670 671 672 673

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

674
  if (print_headings)
675
    printf("TEST NUA-1.1: PARAMETERS\n");
676

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

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

682 683
  ctx->a.nua = nua_create(ctx->root, a_callback, ctx,
			  SIPTAG_FROM_STR("sip:alice@example.com"),
684
			  NUTAG_URL("sip:0.0.0.0:*;transport=udp"),
685
			  TAG_END());
686

687 688
  TEST_1(ctx->a.nua);

689
  from = sip_from_make(tmphome, Alice);
690 691 692

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

693
  nua_set_hparams(nh, NUTAG_INVITE_TIMER(90), TAG_END());
694
  run_a_until(ctx, nua_r_set_params, until_final_response);
695

696 697 698 699 700 701 702 703 704 705 706 707 708 709
  /* 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());

710
  run_a_until(ctx, nua_r_set_params, until_final_response);
711

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

740 741 742
		 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")),
743

744
		 SIPTAG_ORGANIZATION(sip_organization_make(tmphome, "Pussy Galore's Flying Circus")),
745 746

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

749 750
		 TAG_END());

751
  run_a_until(ctx, nua_r_set_params, until_final_response);
752

753 754 755 756
  /* Modify something... */
  nua_set_params(ctx->a.nua,
		 NUTAG_RETRY_COUNT(5),
		 TAG_END());
757
  run_a_until(ctx, nua_r_set_params, until_final_response);
758 759 760 761 762

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

Pekka Pessi's avatar
Pekka Pessi committed
763 764
    unsigned retry_count = -1;
    unsigned max_subscriptions = -1;
765

766 767 768 769 770
    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
771
    unsigned invite_timeout = -1;
772

Pekka Pessi's avatar
Pekka Pessi committed
773 774
    unsigned session_timer = -1;
    unsigned min_se = -1;
775 776
    int refresher = -1;
    int update_refresh = -1;
777

778 779 780
    int message_enable = -1;
    int win_messenger_enable = -1;
    int message_auto_respond = -1;
781

782 783 784 785
    int callee_caps = -1;
    int media_features = -1;
    int service_route_enable = -1;
    int path_enable = -1;
786
    int substate = -1;
787 788

    sip_allow_t const *allow = NONE;
789
    char const *allow_str = "NONE";
790 791 792 793 794 795 796 797 798 799
    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;
800
    struct event *e;
801

Pekka Pessi's avatar
Pekka Pessi committed
802
    nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
803
    run_a_until(ctx, nua_r_get_params, save_until_final_response);
804

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

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

	       	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());
850
    TEST(n, 30);
851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877

    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);
878
    TEST(substate, nua_substate_pending);
879 880 881 882 883 884 885

    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");
886
    TEST_S(sip_header_as_string(tmphome, (void *)organization),
887 888 889
	   "Pussy Galore's Flying Circus");
    TEST_S(organization_str, "Pussy Galore's Flying Circus");

890
    TEST_S(url_as_string(tmphome, registrar->us_url),
891
	   "sip:sip.wonderland.org");
892

Pekka Pessi's avatar
Pekka Pessi committed
893
    free_events_in_list(ctx, ctx->a.call);
894
  }
895

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

898 899 900 901
  {
    sip_from_t const *from = NONE;
    char const *from_str = "NONE";

Pekka Pessi's avatar
Pekka Pessi committed
902 903
    unsigned retry_count = -1;
    unsigned max_subscriptions = -1;
904

905 906 907 908 909
    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
910
    unsigned invite_timeout = -1;
911

Pekka Pessi's avatar
Pekka Pessi committed
912 913
    unsigned session_timer = -1;
    unsigned min_se = -1;
914 915
    int refresher = -1;
    int update_refresh = -1;
916

917 918 919
    int message_enable = -1;
    int win_messenger_enable = -1;
    int message_auto_respond = -1;
920

921 922 923 924
    int callee_caps = -1;
    int media_features = -1;
    int service_route_enable = -1;
    int path_enable = -1;
925
    int substate = -1;
926 927 928 929 930 931 932 933 934 935 936 937 938

    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;
939
    struct event *e;
940

941
    nua_get_hparams(nh, TAG_ANY(), TAG_END());
942
    run_a_until(ctx, nua_r_get_params, save_until_final_response);
943

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

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

	       	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());
989
    TEST(n, 3);
990 991 992

    TEST(invite_timeout, 90);

993 994
    TEST_1(from != NULL && from != NONE);
    TEST_1(strcmp(from_str, "NONE"));
995

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

    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
1031