test_nua.c 164 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 43
#include "sofia-sip/nua.h"
#include "sofia-sip/sip_status.h"
Pekka Pessi's avatar
Pekka Pessi committed
44

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

48 49 50
#include <sofia-sip/su_log.h>
#include <sofia-sip/su_tagarg.h>
#include <sofia-sip/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 <test_nat.h>
54
#include <sofia-sip/auth_module.h>
Pekka Pessi's avatar
Pekka Pessi committed
55

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

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

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

67 68 69 70
#if defined(_WIN32)
#include <fcntl.h>
#endif

Pekka Pessi's avatar
Pekka Pessi committed
71
extern su_log_t nua_log[];
72
extern su_log_t soa_log[];
73
extern su_log_t nea_log[];
74 75
extern su_log_t nta_log[];
extern su_log_t tport_log[];
Pekka Pessi's avatar
Pekka Pessi committed
76 77
extern su_log_t su_log_default[];

78 79 80
extern void *memmem(const void *haystack, size_t haystacklen,
		    const void *needle, size_t needlelen);

Pekka Pessi's avatar
Pekka Pessi committed
81
char const name[] = "test_nua";
82 83

int print_headings = 1;
Pekka Pessi's avatar
Pekka Pessi committed
84 85 86
int tstflags = 0;
#define TSTFLAGS tstflags

87
#include <sofia-sip/tstdef.h>
Pekka Pessi's avatar
Pekka Pessi committed
88 89 90 91 92 93 94 95 96 97

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

#define NONE ((void*)-1)

98 99
#define TEST_E(a, b) TEST_S(nua_event_name(a), nua_event_name(b))

100 101 102
struct endpoint;

typedef
Pekka Pessi's avatar
Pekka Pessi committed
103 104 105
int condition_function(nua_event_t event,
		       int status, char const *phrase,
		       nua_t *nua, struct context *ctx,
106
		       struct endpoint *ep,
Pekka Pessi's avatar
Pekka Pessi committed
107
		       nua_handle_t *nh, struct call *call,
Pekka Pessi's avatar
Pekka Pessi committed
108 109 110
		       sip_t const *sip,
		       tagi_t tags[]);

Pekka Pessi's avatar
Pekka Pessi committed
111 112 113 114 115 116 117 118 119 120
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
121 122 123
struct proxy_transaction;
struct registration_entry;

124
struct context
Pekka Pessi's avatar
Pekka Pessi committed
125 126 127 128
{
  su_home_t home[1];
  su_root_t *root;

Pekka Pessi's avatar
Pekka Pessi committed
129 130
  int threading;

131
  struct endpoint {
Pekka Pessi's avatar
Pekka Pessi committed
132
    char name[4];
Pekka Pessi's avatar
Pekka Pessi committed
133
    struct context *ctx;	/* Backpointer */
134 135 136

    int running;

137 138
    condition_function *next_condition;
    nua_event_t next_event, last_event;
Pekka Pessi's avatar
Pekka Pessi committed
139
    nua_t *nua;
140
    sip_contact_t *contact;
Pekka Pessi's avatar
Pekka Pessi committed
141
    sip_from_t *to;
Pekka Pessi's avatar
Pekka Pessi committed
142

Pekka Pessi's avatar
Pekka Pessi committed
143
    printer_function *printer;
Pekka Pessi's avatar
Pekka Pessi committed
144

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

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

164
  } a, b, c;
Pekka Pessi's avatar
Pekka Pessi committed
165 166

  struct proxy *p;
Pekka Pessi's avatar
Pekka Pessi committed
167
  struct nat *nat;
Pekka Pessi's avatar
Pekka Pessi committed
168 169
};

170
struct event
171 172 173
{
  struct event *next, **prev;
  nua_saved_event_t saved_event[1];
Pekka Pessi's avatar
Pekka Pessi committed
174
  nua_event_data_t const *data;
175 176
};

Pekka Pessi's avatar
Pekka Pessi committed
177 178 179 180 181 182
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 *);
183

184 185 186 187 188 189 190 191 192 193 194
#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)
195
{
Pekka Pessi's avatar
Pekka Pessi committed
196 197
  save_event_in_list(ctx, event, ep, ep->call);
  return event >= nua_r_set_params && status >= 200;
198 199
}

Pekka Pessi's avatar
Pekka Pessi committed
200 201 202
/** Save events (except nua_i_active or terminated).
 * Terminate when a event is saved.
 */
203
int save_until_received(CONDITION_PARAMS)
204
{
Pekka Pessi's avatar
Pekka Pessi committed
205
  save_event_in_list(ctx, event, ep, ep->call);
206 207 208
  return 1;
}

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

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

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

  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)))
331
    ep->running = 0;
332

Pekka Pessi's avatar
Pekka Pessi committed
333
  ep->last_event = event;
334 335
}

336
void a_callback(nua_event_t event,
337 338
		int status, char const *phrase,
		nua_t *nua, struct context *ctx,
Pekka Pessi's avatar
Pekka Pessi committed
339
		nua_handle_t *nh, struct call *call,
340 341
		sip_t const *sip,
		tagi_t tags[])
Pekka Pessi's avatar
Pekka Pessi committed
342
{
343 344
  ep_callback(event, status, phrase, nua, ctx, &ctx->a, nh, call, sip, tags);
}
345

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

356 357 358
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
359
		nua_handle_t *nh, struct call *call,
360 361 362 363
		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
364 365
}

366 367 368 369
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
370
{
371
  struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
372 373 374 375 376

  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
377
  a->flags.n = 0;
378 379 380 381 382

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

385 386 387 388
  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
389
  c->flags.n = 0;
390 391

  for (; a->running || b->running || c->running;) {
Pekka Pessi's avatar
Pekka Pessi committed
392 393
    su_root_step(ctx->root, 1000);
  }
394
}
Pekka Pessi's avatar
Pekka Pessi committed
395

396 397 398 399 400 401 402
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);
}

403 404 405 406
int run_a_until(struct context *ctx,
		nua_event_t a_event,
		condition_function *a_condition)
{
407
  run_abc_until(ctx, a_event, a_condition, -1, NULL, -1, NULL);
408 409 410 411 412 413 414
  return ctx->a.last_event;
}

int run_b_until(struct context *ctx,
		nua_event_t b_event,
		condition_function *b_condition)
{
415
  run_abc_until(ctx, -1, NULL, b_event, b_condition, -1, NULL);
416
  return ctx->b.last_event;
Pekka Pessi's avatar
Pekka Pessi committed
417 418
}

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

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

  if (ep->printer)
Pekka Pessi's avatar
Pekka Pessi committed
497 498
    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
499

Pekka Pessi's avatar
Pekka Pessi committed
500 501 502 503 504 505
  nua_respond(nh, status, phrase, ta_tags(ta));
  ta_end(ta);

  return 0;
}

506

Pekka Pessi's avatar
Pekka Pessi committed
507 508 509 510 511
/* 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)
512
{
Pekka Pessi's avatar
Pekka Pessi committed
513 514
  if (call)
    return call;
515

Pekka Pessi's avatar
Pekka Pessi committed
516 517
  if (status)
    respond(ep, call, nh, status, phrase, TAG_END());
518

Pekka Pessi's avatar
Pekka Pessi committed
519 520
  nua_handle_destroy(nh);
  return NULL;
521 522
}

Pekka Pessi's avatar
Pekka Pessi committed
523

Pekka Pessi's avatar
Pekka Pessi committed
524 525
static void
call_init(struct call *call)
Pekka Pessi's avatar
Pekka Pessi committed
526
{
Pekka Pessi's avatar
Pekka Pessi committed
527
  call->events.tail = &call->events.head;
Pekka Pessi's avatar
Pekka Pessi committed
528 529
}

Pekka Pessi's avatar
Pekka Pessi committed
530
/* Save nua event in call-specific list */
531
static
532
int save_event_in_list(struct context *ctx,
Pekka Pessi's avatar
Pekka Pessi committed
533 534 535 536
		       nua_event_t nevent,
		       struct endpoint *ep,
		       struct call *call)

537
{
Pekka Pessi's avatar
Pekka Pessi committed
538 539 540 541 542 543
  struct event *e;

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

  e = su_zalloc(ctx->home, sizeof *e);
544 545

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

547 548
  if (!nua_save_event(ep->nua, e->saved_event)) {
    su_free(ctx->home, e);
Pekka Pessi's avatar
Pekka Pessi committed
549
    return -1;
550
  }
Pekka Pessi's avatar
Pekka Pessi committed
551

552 553
  *(e->prev = call->events.tail) = e;
  call->events.tail = &e->next;
Pekka Pessi's avatar
Pekka Pessi committed
554
  e->data = nua_event_data(e->saved_event);
555

Pekka Pessi's avatar
Pekka Pessi committed
556
  return 1;
557
}
Pekka Pessi's avatar
Pekka Pessi committed
558

Pekka Pessi's avatar
Pekka Pessi committed
559
/* Save nua event in endpoint list */
560
static
Pekka Pessi's avatar
Pekka Pessi committed
561 562
void free_events_in_list(struct context *ctx,
			 struct call *call)
Pekka Pessi's avatar
Pekka Pessi committed
563 564 565
{
  struct event *e;

Pekka Pessi's avatar
Pekka Pessi committed
566
  while ((e = call->events.head)) {
Pekka Pessi's avatar
Pekka Pessi committed
567 568 569 570 571
    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
572
  call->events.tail = &call->events.head;
Pekka Pessi's avatar
Pekka Pessi committed
573 574
}

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

Pekka Pessi's avatar
Pekka Pessi committed
577 578 579 580 581
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
582 583 584 585
int test_api_errors(struct context *ctx)
{
  BEGIN();

Pekka Pessi's avatar
Pekka Pessi committed
586
  /* Invoke every API function with invalid arguments */
Pekka Pessi's avatar
Pekka Pessi committed
587

Pekka Pessi's avatar
Pekka Pessi committed
588 589
  int level;

Pekka Pessi's avatar
Pekka Pessi committed
590 591
  int status; char const *phrase;

592 593 594
  if (print_headings)
    printf("TEST NUA-1.0: test API\n");

Pekka Pessi's avatar
Pekka Pessi committed
595 596 597 598 599
  /* 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
600 601 602 603 604
  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
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 640 641 642 643 644 645

  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
646

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

Pekka Pessi's avatar
Pekka Pessi committed
652 653 654 655
  {
    nua_saved_event_t event[1];

    memset(event, 0, sizeof event);
656

Pekka Pessi's avatar
Pekka Pessi committed
657
    TEST_1(!nua_save_event(NULL, event));
658
    TEST_1(!nua_event_data(event));
Pekka Pessi's avatar
Pekka Pessi committed
659 660 661
    TEST_VOID(nua_destroy_event(event));
  }

Pekka Pessi's avatar
Pekka Pessi committed
662
  su_log_set_level(nua_log, level);
Pekka Pessi's avatar
Pekka Pessi committed
663

664 665 666
  if (print_headings)
    printf("TEST NUA-1.0: PASSED\n");

Pekka Pessi's avatar
Pekka Pessi committed
667 668 669
  END();
}

670
#include <sofia-sip/su_tag_class.h>
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 702 703 704 705 706 707

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
708 709 710
int test_params(struct context *ctx)
{
  BEGIN();
711 712 713 714 715 716 717 718

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

719
  if (print_headings)
720
    printf("TEST NUA-1.1: PARAMETERS\n");
721

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

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

727 728
  ctx->a.nua = nua_create(ctx->root, a_callback, ctx,
			  SIPTAG_FROM_STR("sip:alice@example.com"),
729
			  NUTAG_URL("sip:0.0.0.0:*;transport=udp"),
730
			  TAG_END());
731

732 733
  TEST_1(ctx->a.nua);

734 735 736 737 738 739
  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);

740
  from = sip_from_make(tmphome, Alice);
741 742 743

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

744
  nua_set_hparams(nh, NUTAG_INVITE_TIMER(90), TAG_END());
745
  run_a_until(ctx, nua_r_set_params, until_final_response);
746

747 748 749 750 751 752 753 754 755 756 757 758 759 760
  /* 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());

761
  run_a_until(ctx, nua_r_set_params, until_final_response);
762

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

791 792 793
		 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")),
794

795
		 SIPTAG_ORGANIZATION(sip_organization_make(tmphome, "Pussy Galore's Flying Circus")),
796 797

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

800 801
		 TAG_END());

802
  run_a_until(ctx, nua_r_set_params, until_final_response);
803

804 805 806 807
  /* Modify something... */
  nua_set_params(ctx->a.nua,
		 NUTAG_RETRY_COUNT(5),
		 TAG_END());
808
  run_a_until(ctx, nua_r_set_params, until_final_response);
809 810 811 812 813

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

Pekka Pessi's avatar
Pekka Pessi committed
814 815
    unsigned retry_count = -1;
    unsigned max_subscriptions = -1;
816

817 818 819 820 821
    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
822
    unsigned invite_timeout = -1;
823

Pekka Pessi's avatar
Pekka Pessi committed
824 825
    unsigned session_timer = -1;
    unsigned min_se = -1;
826 827
    int refresher = -1;
    int update_refresh = -1;
828

829 830 831
    int message_enable = -1;
    int win_messenger_enable = -1;
    int message_auto_respond = -1;
832

833 834 835 836
    int callee_caps = -1;
    int media_features = -1;
    int service_route_enable = -1;
    int path_enable = -1;
837
    int substate = -1;
838 839

    sip_allow_t const *allow = NONE;
840
    char const *allow_str = "NONE";
841 842 843 844 845 846 847 848 849 850
    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;
851
    struct event *e;
852

Pekka Pessi's avatar
Pekka Pessi committed
853
    nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
854
    run_a_until(ctx, nua_r_get_params, save_until_final_response);
855

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

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

	       	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());
901
    TEST(n, 30);
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928

    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);
929
    TEST(substate, nua_substate_pending);
930 931 932 933 934 935 936

    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");
937
    TEST_S(sip_header_as_string(tmphome, (void *)organization),
938 939 940
	   "Pussy Galore's Flying Circus");
    TEST_S(organization_str, "Pussy Galore's Flying Circus");

941
    TEST_S(url_as_string(tmphome, registrar->us_url),
942
	   "sip:sip.wonderland.org");
943

Pekka Pessi's avatar
Pekka Pessi committed
944
    free_events_in_list(ctx, ctx->a.call);
945
  }
946

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

949 950 951 952
  {
    sip_from_t const *from = NONE;
    char const *from_str = "NONE";

Pekka Pessi's avatar
Pekka Pessi committed
953 954
    unsigned retry_count = -1;
    unsigned max_subscriptions = -1;
955

956 957 958 959 960
    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
961
    unsigned invite_timeout = -1;
962

Pekka Pessi's avatar
Pekka Pessi committed
963 964
    unsigned session_timer = -1;
    unsigned min_se = -1;
965 966
    int refresher = -1;
    int update_refresh = -1;
967

968 969 970
    int message_enable = -1;
    int win_messenger_enable = -1;
    int message_auto_respond = -1;
971

972 973 974 975
    int callee_caps = -1;
    int media_features = -1;
    int service_route_enable = -1;
    int path_enable = -1;
976
    int substate = -1;
977 978 979 980 981 982 983 984 985 986 987 988 989

    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;
990
    struct event *e;
991

992
    nua_get_hparams(nh, TAG_ANY(), TAG_END());
993
    run_a_until(ctx, nua_r_get_params, save_until_final_response);
994

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

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