test_nua.c 148 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
#include <test_proxy.h>
Pekka Pessi's avatar
Pekka Pessi committed
53
#include <auth_module.h>
Pekka Pessi's avatar
Pekka Pessi committed
54

55 56 57 58 59
#include <stddef.h>
#include <stdlib.h>
#include <string.h>

#include <assert.h>
60
#include <unistd.h>
61 62 63 64 65

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

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

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

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

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

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

95 96 97
struct endpoint;

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

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

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

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

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

    int running;

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

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

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

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

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

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

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

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

178 179 180 181 182 183 184 185 186 187 188
#define CONDITION_PARAMS			\
  nua_event_t event,				\
  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[]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  return 0;
}

500

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

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

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

Pekka Pessi's avatar
Pekka Pessi committed
517

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  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
640

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

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

    memset(event, 0, sizeof event);
650

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

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

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

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

664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
#include <su_tag_class.h>

int test_tag_filter(void)
{
  BEGIN();

#undef TAG_NAMESPACE
#define TAG_NAMESPACE "test"
  tag_typedef_t tag_a = STRTAG_TYPEDEF(a);
#define TAG_A(s)      tag_a, tag_str_v((s))
  tag_typedef_t tag_b = STRTAG_TYPEDEF(b);
#define TAG_B(s)      tag_b, tag_str_v((s))

  tagi_t filter[2] = {{ NUTAG_ANY() }, { TAG_END() }};

  tagi_t *lst, *result;

  lst = tl_list(TAG_A("X"),
		TAG_SKIP(2), 
		NUTAG_URL((void *)"urn:foo"),
		TAG_B("Y"),
		NUTAG_URL((void *)"urn:bar"),
		TAG_NULL());

  TEST_1(lst);

  result = tl_afilter(NULL, filter, lst);

  TEST_1(result);
  TEST(result[0].t_tag, nutag_url);
  TEST(result[1].t_tag, nutag_url);

  tl_vfree(lst);
  free(result);

  END();
}

Pekka Pessi's avatar
Pekka Pessi committed
702 703 704
int test_params(struct context *ctx)
{
  BEGIN();
705 706 707 708 709 710 711 712

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

713
  if (print_headings)
714
    printf("TEST NUA-1.1: PARAMETERS\n");
715

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

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

721 722
  ctx->a.nua = nua_create(ctx->root, a_callback, ctx,
			  SIPTAG_FROM_STR("sip:alice@example.com"),
723
			  NUTAG_URL("sip:0.0.0.0:*;transport=udp"),
724
			  TAG_END());
725

726 727
  TEST_1(ctx->a.nua);

728 729 730 731 732 733
  nh = nua_handle(ctx->a.nua, NULL, TAG_END()); TEST_1(nh);
  nua_handle_unref(nh);

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

734
  from = sip_from_make(tmphome, Alice);
735 736 737

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

738
  nua_set_hparams(nh, NUTAG_INVITE_TIMER(90), TAG_END());
739
  run_a_until(ctx, nua_r_set_params, until_final_response);
740

741 742 743 744 745 746 747 748 749 750 751 752 753 754
  /* 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());

755
  run_a_until(ctx, nua_r_set_params, until_final_response);
756

757 758 759
  /* Modify everything from their default value */
  nua_set_params(ctx->a.nua,
		 SIPTAG_FROM(from),
760
		 NUTAG_RETRY_COUNT(9),
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
		 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),
783
		 NUTAG_SUBSTATE(nua_substate_pending),
784

785 786 787
		 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")),
788

789
		 SIPTAG_ORGANIZATION(sip_organization_make(tmphome, "Pussy Galore's Flying Circus")),
790 791

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

794 795
		 TAG_END());

796
  run_a_until(ctx, nua_r_set_params, until_final_response);
797

798 799 800 801
  /* Modify something... */
  nua_set_params(ctx->a.nua,
		 NUTAG_RETRY_COUNT(5),
		 TAG_END());
802
  run_a_until(ctx, nua_r_set_params, until_final_response);
803 804 805 806 807

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

Pekka Pessi's avatar
Pekka Pessi committed
808 809
    unsigned retry_count = -1;
    unsigned max_subscriptions = -1;
810

811 812 813 814 815
    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
816
    unsigned invite_timeout = -1;
817

Pekka Pessi's avatar
Pekka Pessi committed
818 819
    unsigned session_timer = -1;
    unsigned min_se = -1;
820 821
    int refresher = -1;
    int update_refresh = -1;
822

823 824 825
    int message_enable = -1;
    int win_messenger_enable = -1;
    int message_auto_respond = -1;
826

827 828 829 830
    int callee_caps = -1;
    int media_features = -1;
    int service_route_enable = -1;
    int path_enable = -1;
831
    int substate = -1;
832 833

    sip_allow_t const *allow = NONE;
834
    char const *allow_str = "NONE";
835 836 837 838 839 840 841 842 843 844
    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;
845
    struct event *e;
846

Pekka Pessi's avatar
Pekka Pessi committed
847
    nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
848
    run_a_until(ctx, nua_r_get_params, save_until_final_response);
849

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

853
    n = tl_gets(e->data->e_tags,
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879
	       	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),
880
	       	NUTAG_SUBSTATE_REF(substate),
881 882 883 884 885 886 887 888 889 890 891 892 893 894

	       	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());
895
    TEST(n, 30);
896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922

    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);
923
    TEST(substate, nua_substate_pending);
924 925 926 927 928 929 930

    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");
931
    TEST_S(sip_header_as_string(tmphome, (void *)organization),
932 933 934
	   "Pussy Galore's Flying Circus");
    TEST_S(organization_str, "Pussy Galore's Flying Circus");

935
    TEST_S(url_as_string(tmphome, registrar->us_url),
936
	   "sip:sip.wonderland.org");
937

Pekka Pessi's avatar
Pekka Pessi committed
938
    free_events_in_list(ctx, ctx->a.call);
939
  }
940

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

943 944 945 946
  {
    sip_from_t const *from = NONE;
    char const *from_str = "NONE";

Pekka Pessi's avatar
Pekka Pessi committed
947 948
    unsigned retry_count = -1;
    unsigned max_subscriptions = -1;
949

950 951 952 953 954
    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
955
    unsigned invite_timeout = -1;
956

Pekka Pessi's avatar
Pekka Pessi committed
957 958
    unsigned session_timer = -1;
    unsigned min_se = -1;
959 960
    int refresher = -1;
    int update_refresh = -1;
961

962 963 964
    int message_enable = -1;
    int win_messenger_enable = -1;
    int message_auto_respond = -1;
965

966 967 968 969
    int callee_caps = -1;
    int media_features = -1;
    int service_route_enable = -1;
    int path_enable = -1;
970
    int substate = -1;
971 972 973 974 975 976 977 978 979 980 981 982 983

    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;
984
    struct event *e;
985

986
    nua_get_hparams(nh, TAG_ANY(), TAG_END());
987
    run_a_until(ctx, nua_r_get_params, save_until_final_response);
988

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

992
    n = tl_gets(e->data->e_tags,
993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
	       	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),
1019
	       	NUTAG_SUBSTATE_REF(substate),
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033

	       	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());
1034
    TEST(n, 3);
1035 1036 1037

    TEST(invite_timeout, 90);

1038