test_nua.c 169 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
enum { event_is_extra, event_is_normal, event_is_special };
Pekka Pessi's avatar
Pekka Pessi committed
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139

struct eventlist {
  nua_event_t kind;
  struct event *head, **tail;
};

struct event
{
  struct event *next, **prev;
  struct call *call;
  nua_saved_event_t saved_event[1];
  nua_event_data_t const *data;
};


140
struct context
Pekka Pessi's avatar
Pekka Pessi committed
141 142 143 144
{
  su_home_t home[1];
  su_root_t *root;

145 146
  int threading, proxy_tests;
  char const *external_proxy;
Pekka Pessi's avatar
Pekka Pessi committed
147

148
  struct endpoint {
Pekka Pessi's avatar
Pekka Pessi committed
149
    char name[4];
Pekka Pessi's avatar
Pekka Pessi committed
150
    struct context *ctx;	/* Backpointer */
151 152 153

    int running;

154 155
    condition_function *next_condition;
    nua_event_t next_event, last_event;
Pekka Pessi's avatar
Pekka Pessi committed
156
    nua_t *nua;
157
    sip_contact_t *contact;
Pekka Pessi's avatar
Pekka Pessi committed
158
    sip_from_t *to;
Pekka Pessi's avatar
Pekka Pessi committed
159

Pekka Pessi's avatar
Pekka Pessi committed
160
    printer_function *printer;
Pekka Pessi's avatar
Pekka Pessi committed
161

Pekka Pessi's avatar
Pekka Pessi committed
162
    /* Per-call stuff */
Pekka Pessi's avatar
Pekka Pessi committed
163 164 165
    struct call {
      struct call *next;
      nua_handle_t *nh;
166
      char const *sdp;
Pekka Pessi's avatar
Pekka Pessi committed
167
      struct eventlist *events;
Pekka Pessi's avatar
Pekka Pessi committed
168
    } call[1], reg[1];
Pekka Pessi's avatar
Pekka Pessi committed
169

Pekka Pessi's avatar
Pekka Pessi committed
170 171 172 173 174 175 176
    int (*is_special)(nua_event_t e);

    /* Normal events are saved here */
    struct eventlist events[1];
    /* Special events are saved here */
    struct eventlist specials[1];

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

186
  } a, b, c;
Pekka Pessi's avatar
Pekka Pessi committed
187 188

  struct proxy *p;
Pekka Pessi's avatar
Pekka Pessi committed
189
  struct nat *nat;
Pekka Pessi's avatar
Pekka Pessi committed
190 191
};

Pekka Pessi's avatar
Pekka Pessi committed
192 193 194 195 196
static int save_event_in_list(struct context *,
			      nua_event_t nevent,
			      struct endpoint *,
			      struct call *);
static void free_events_in_list(struct context *,
Pekka Pessi's avatar
Pekka Pessi committed
197
				struct eventlist *);
198

199 200 201 202 203 204 205 206 207 208 209
#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)
210
{
Pekka Pessi's avatar
Pekka Pessi committed
211 212
  save_event_in_list(ctx, event, ep, ep->call);
  return event >= nua_r_set_params && status >= 200;
213 214
}

215 216
/** Save events.
 *
Pekka Pessi's avatar
Pekka Pessi committed
217 218
 * Terminate when a event is saved.
 */
219
int save_until_received(CONDITION_PARAMS)
220
{
221 222 223 224 225 226 227 228 229 230 231 232
  return save_event_in_list(ctx, event, ep, ep->call) == event_is_normal;
}

int save_events(CONDITION_PARAMS)
{
  return save_event_in_list(ctx, event, ep, ep->call) == event_is_normal;
}

/** Save events until nua_i_outbound is received.  */
int save_until_special(CONDITION_PARAMS)
{
  return save_event_in_list(ctx, event, ep, ep->call) == event_is_special;
233 234
}

Pekka Pessi's avatar
Pekka Pessi committed
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
/* 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
284 285 286 287 288 289 290 291 292
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
293 294 295
{
  if (event == nua_i_state) {
    fprintf(stderr, "%s.nua(%p): event %s %s\n",
296
	    ep->name, nh, nua_event_name(event),
Pekka Pessi's avatar
Pekka Pessi committed
297 298
	    nua_callstate_name(callstate(tags)));
  }
Pekka Pessi's avatar
Pekka Pessi committed
299
  else if ((int)event >= nua_r_set_params) {
Pekka Pessi's avatar
Pekka Pessi committed
300 301 302
    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
303 304 305 306
  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
307 308
  else if (status > 0) {
    fprintf(stderr, "%s.nua(%p): call %s() with status %u %s\n",
309
	    ep->name, nh, operation, status, phrase);
Pekka Pessi's avatar
Pekka Pessi committed
310 311
  }
  else {
Pekka Pessi's avatar
Pekka Pessi committed
312 313 314 315 316
    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
317
	      ep->name, nh, operation, subject);
Pekka Pessi's avatar
Pekka Pessi committed
318 319 320
    }
    else
      fprintf(stderr, "%s.nua(%p): call %s()\n",
Pekka Pessi's avatar
Pekka Pessi committed
321
	      ep->name, nh, operation);
Pekka Pessi's avatar
Pekka Pessi committed
322 323 324 325 326
  }

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

328 329 330 331
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
332
		 nua_handle_t *nh, struct call *call,
333 334
		 sip_t const *sip,
		 tagi_t tags[])
335
{
Pekka Pessi's avatar
Pekka Pessi committed
336
  if (ep->printer)
Pekka Pessi's avatar
Pekka Pessi committed
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
    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
352 353 354 355 356

  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)))
357
    ep->running = 0;
358

Pekka Pessi's avatar
Pekka Pessi committed
359
  ep->last_event = event;
360 361
}

362
void a_callback(nua_event_t event,
363 364
		int status, char const *phrase,
		nua_t *nua, struct context *ctx,
Pekka Pessi's avatar
Pekka Pessi committed
365
		nua_handle_t *nh, struct call *call,
366 367
		sip_t const *sip,
		tagi_t tags[])
Pekka Pessi's avatar
Pekka Pessi committed
368
{
369 370
  ep_callback(event, status, phrase, nua, ctx, &ctx->a, nh, call, sip, tags);
}
371

372 373 374
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
375
		nua_handle_t *nh, struct call *call,
376 377 378 379 380
		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
381

382 383 384
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
385
		nua_handle_t *nh, struct call *call,
386 387 388 389
		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
390 391
}

392 393 394 395
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
396
{
397
  struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
398 399 400 401 402

  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
403
  a->flags.n = 0;
404 405 406 407 408

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

411 412 413 414
  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
415
  c->flags.n = 0;
416 417

  for (; a->running || b->running || c->running;) {
Pekka Pessi's avatar
Pekka Pessi committed
418 419
    su_root_step(ctx->root, 1000);
  }
420
}
Pekka Pessi's avatar
Pekka Pessi committed
421

422 423 424 425 426 427 428
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);
}

429 430 431 432
int run_a_until(struct context *ctx,
		nua_event_t a_event,
		condition_function *a_condition)
{
433
  run_abc_until(ctx, a_event, a_condition, -1, NULL, -1, NULL);
434 435 436 437 438 439 440
  return ctx->a.last_event;
}

int run_b_until(struct context *ctx,
		nua_event_t b_event,
		condition_function *b_condition)
{
441
  run_abc_until(ctx, -1, NULL, b_event, b_condition, -1, NULL);
442
  return ctx->b.last_event;
Pekka Pessi's avatar
Pekka Pessi committed
443 444
}

Pekka Pessi's avatar
Pekka Pessi committed
445 446 447 448 449 450 451 452
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;
}

453 454
#define OPERATION(X, x)	   \
int X(struct endpoint *ep, \
Pekka Pessi's avatar
Pekka Pessi committed
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
      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

472 473 474 475 476 477 478
OPERATION(INVITE, invite);
OPERATION(ACK, ack);
OPERATION(BYE, bye);
OPERATION(CANCEL, cancel);
OPERATION(AUTHENTICATE, authenticate);
OPERATION(UPDATE, update);
OPERATION(INFO, info);
479
OPERATION(PRACK, prack);
480 481 482 483 484 485 486 487 488 489 490 491 492
OPERATION(REFER, refer);
OPERATION(MESSAGE, message);
OPERATION(OPTIONS, options);
OPERATION(PUBLISH, publish);
OPERATION(UNPUBLISH, unpublish);
OPERATION(REGISTER, register);
OPERATION(UNREGISTER, unregister);
OPERATION(SUBSCRIBE, subscribe);
OPERATION(UNSUBSCRIBE, unsubscribe);
OPERATION(NOTIFY, notify);
OPERATION(NOTIFIER, notifier);
OPERATION(TERMINATE, terminate);
OPERATION(AUTHORIZE, authorize);
493

Pekka Pessi's avatar
Pekka Pessi committed
494
/* Respond via endpoint and handle */
495
int RESPOND(struct endpoint *ep,
Pekka Pessi's avatar
Pekka Pessi committed
496 497
	    struct call *call,
	    nua_handle_t *nh,
Pekka Pessi's avatar
Pekka Pessi committed
498 499 500 501 502 503 504
	    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
505 506

  if (ep->printer)
Pekka Pessi's avatar
Pekka Pessi committed
507 508
    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
509

Pekka Pessi's avatar
Pekka Pessi committed
510 511 512 513 514 515
  nua_respond(nh, status, phrase, ta_tags(ta));
  ta_end(ta);

  return 0;
}

516

Pekka Pessi's avatar
Pekka Pessi committed
517 518 519 520 521
/* 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)
522
{
Pekka Pessi's avatar
Pekka Pessi committed
523 524
  if (call)
    return call;
525

Pekka Pessi's avatar
Pekka Pessi committed
526
  if (status)
527
    RESPOND(ep, call, nh, status, phrase, TAG_END());
528

Pekka Pessi's avatar
Pekka Pessi committed
529 530
  nua_handle_destroy(nh);
  return NULL;
531 532
}

Pekka Pessi's avatar
Pekka Pessi committed
533

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

541
{
Pekka Pessi's avatar
Pekka Pessi committed
542
  struct eventlist *list;
Pekka Pessi's avatar
Pekka Pessi committed
543
  struct event *e;
Pekka Pessi's avatar
Pekka Pessi committed
544
  int action = ep->is_special(nevent);
Pekka Pessi's avatar
Pekka Pessi committed
545

Pekka Pessi's avatar
Pekka Pessi committed
546
  if (action == event_is_extra)
Pekka Pessi's avatar
Pekka Pessi committed
547
    return 0;
Pekka Pessi's avatar
Pekka Pessi committed
548 549 550 551 552 553
  else if (action == event_is_special)
    list = ep->specials;
  else if (call->events)
    list = call->events;
  else
    list = ep->events;
Pekka Pessi's avatar
Pekka Pessi committed
554 555

  e = su_zalloc(ctx->home, sizeof *e);
556 557

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

559 560
  if (!nua_save_event(ep->nua, e->saved_event)) {
    su_free(ctx->home, e);
Pekka Pessi's avatar
Pekka Pessi committed
561
    return -1;
562
  }
Pekka Pessi's avatar
Pekka Pessi committed
563

Pekka Pessi's avatar
Pekka Pessi committed
564 565 566
  *(e->prev = list->tail) = e; list->tail = &e->next;

  e->call = call;
Pekka Pessi's avatar
Pekka Pessi committed
567
  e->data = nua_event_data(e->saved_event);
568

569
  return action;
570
}
Pekka Pessi's avatar
Pekka Pessi committed
571

Pekka Pessi's avatar
Pekka Pessi committed
572
/* Save nua event in endpoint list */
573
static
Pekka Pessi's avatar
Pekka Pessi committed
574
void free_events_in_list(struct context *ctx,
Pekka Pessi's avatar
Pekka Pessi committed
575
			 struct eventlist *list)
Pekka Pessi's avatar
Pekka Pessi committed
576 577 578
{
  struct event *e;

Pekka Pessi's avatar
Pekka Pessi committed
579
  while ((e = list->head)) {
Pekka Pessi's avatar
Pekka Pessi committed
580 581 582 583 584
    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
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622

  list->tail = &list->head;
}

static
int is_special(nua_event_t e)
{
  if (e == nua_i_active || e == nua_i_terminated)
    return event_is_extra;
  if (e == nua_i_outbound)
    return event_is_special;

  return event_is_normal;
}

static void
eventlist_init(struct eventlist *list)
{
  list->tail = &list->head;
}

static void
call_init(struct call *call)
{
}

static void
endpoint_init(struct context *ctx, struct endpoint *e, char id)
{
  e->name[0] = id;
  e->ctx = ctx;

  e->is_special = is_special;

  call_init(e->call);
  call_init(e->reg);
  eventlist_init(e->events);
  eventlist_init(e->specials);
Pekka Pessi's avatar
Pekka Pessi committed
623 624
}

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

Pekka Pessi's avatar
Pekka Pessi committed
627 628 629 630 631
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
632 633 634 635
int test_api_errors(struct context *ctx)
{
  BEGIN();

Pekka Pessi's avatar
Pekka Pessi committed
636
  /* Invoke every API function with invalid arguments */
Pekka Pessi's avatar
Pekka Pessi committed
637

Pekka Pessi's avatar
Pekka Pessi committed
638 639
  int level;

Pekka Pessi's avatar
Pekka Pessi committed
640 641
  int status; char const *phrase;

642 643 644
  if (print_headings)
    printf("TEST NUA-1.0: test API\n");

Pekka Pessi's avatar
Pekka Pessi committed
645 646 647 648 649
  /* 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
650 651 652 653 654
  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
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678

  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()));
679
  TEST_VOID(nua_prack(NULL, TAG_END()));
Pekka Pessi's avatar
Pekka Pessi committed
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
  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
697

Pekka Pessi's avatar
Pekka Pessi committed
698 699
  TEST_1(!nua_handle_home(NULL));
  TEST_1(!nua_save_event(NULL, NULL));
700
  TEST_1(!nua_event_data(NULL));
Pekka Pessi's avatar
Pekka Pessi committed
701
  TEST_VOID(nua_destroy_event(NULL));
702

Pekka Pessi's avatar
Pekka Pessi committed
703 704 705 706
  {
    nua_saved_event_t event[1];

    memset(event, 0, sizeof event);
707

Pekka Pessi's avatar
Pekka Pessi committed
708
    TEST_1(!nua_save_event(NULL, event));
709
    TEST_1(!nua_event_data(event));
Pekka Pessi's avatar
Pekka Pessi committed
710 711 712
    TEST_VOID(nua_destroy_event(event));
  }

Pekka Pessi's avatar
Pekka Pessi committed
713
  su_log_set_level(nua_log, level);
Pekka Pessi's avatar
Pekka Pessi committed
714

715 716 717
  if (print_headings)
    printf("TEST NUA-1.0: PASSED\n");

Pekka Pessi's avatar
Pekka Pessi committed
718 719 720
  END();
}

721
#include <sofia-sip/su_tag_class.h>
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738

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"),
Pekka Pessi's avatar
Pekka Pessi committed
739
		TAG_SKIP(2),
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758
		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
759 760 761
int test_params(struct context *ctx)
{
  BEGIN();
762 763 764 765 766 767 768 769

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

770
  if (print_headings)
771
    printf("TEST NUA-1.1: PARAMETERS\n");
772

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

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

778 779
  ctx->a.nua = nua_create(ctx->root, a_callback, ctx,
			  SIPTAG_FROM_STR("sip:alice@example.com"),
780
			  NUTAG_URL("sip:0.0.0.0:*;transport=udp"),
781
			  TAG_END());
782

783 784
  TEST_1(ctx->a.nua);

785 786 787 788 789 790
  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);

791
  from = sip_from_make(tmphome, Alice);
792 793 794

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

795
  nua_set_hparams(nh, NUTAG_INVITE_TIMER(90), TAG_END());
796
  run_a_until(ctx, nua_r_set_params, until_final_response);
797

798 799 800 801 802 803 804 805 806 807 808 809 810 811
  /* 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());

812
  run_a_until(ctx, nua_r_set_params, until_final_response);
813

814 815 816
  /* Modify everything from their default value */
  nua_set_params(ctx->a.nua,
		 SIPTAG_FROM(from),
817
		 NUTAG_RETRY_COUNT(9),
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
		 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),
840
		 NUTAG_SUBSTATE(nua_substate_pending),
841

842 843 844 845 846 847
		 NUTAG_KEEPALIVE(66),
		 NUTAG_KEEPALIVE_STREAM(33),

		 NUTAG_OUTBOUND("foo"),
		 NUTAG_INSTANCE("urn:uuid:97701ad9-39df-1229-1083-dbc0a85f029c"),

848 849 850
		 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")),
851

852
		 SIPTAG_ORGANIZATION(sip_organization_make(tmphome, "Pussy Galore's Flying Circus")),
853 854

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

857 858
		 TAG_END());

859
  run_a_until(ctx, nua_r_set_params, until_final_response);
860

861 862 863 864
  /* Modify something... */
  nua_set_params(ctx->a.nua,
		 NUTAG_RETRY_COUNT(5),
		 TAG_END());
865
  run_a_until(ctx, nua_r_set_params, until_final_response);
866 867 868 869 870

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

Pekka Pessi's avatar
Pekka Pessi committed
871 872
    unsigned retry_count = -1;
    unsigned max_subscriptions = -1;
873

874 875 876 877 878
    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
879
    unsigned invite_timeout = -1;
880

Pekka Pessi's avatar
Pekka Pessi committed
881 882
    unsigned session_timer = -1;
    unsigned min_se = -1;
883 884
    int refresher = -1;
    int update_refresh = -1;
885

886 887 888
    int message_enable = -1;
    int win_messenger_enable = -1;
    int message_auto_respond = -1;
889

890 891 892 893
    int callee_caps = -1;
    int media_features = -1;
    int service_route_enable = -1;
    int path_enable = -1;
894
    int substate = -1;
895 896

    sip_allow_t const *allow = NONE;
897
    char const *allow_str = "NONE";
898 899 900 901 902 903 904
    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";

905 906 907 908 909
    char const *outbound = "NONE";
    char const *instance = "NONE";
    
    unsigned keepalive = -1, keepalive_stream = -1;

910 911 912
    url_string_t const *registrar = NONE;

    int n;
913
    struct event *e;
914

Pekka Pessi's avatar
Pekka Pessi committed
915
    nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
916
    run_a_until(ctx, nua_r_get_params, save_until_final_response);
917

Pekka Pessi's avatar
Pekka Pessi committed
918
    TEST_1(e = ctx->a.events->head);
919
    TEST_E(e->data->e_event, nua_r_get_params);
920

921
    n = tl_gets(e->data->e_tags,
922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947
	       	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),
948
	       	NUTAG_SUBSTATE_REF(substate),
949 950 951 952 953 954 955 956 957 958 959

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

960 961 962 963 964 965
		NUTAG_OUTBOUND_REF(outbound),
		NUTAG_INSTANCE_REF(instance),

		NUTAG_KEEPALIVE_REF(keepalive),
		NUTAG_KEEPALIVE_STREAM_REF(keepalive_stream),

966 967 968
	       	NUTAG_REGISTRAR_REF(registrar),

		TAG_END());
969
    TEST(n, 34);
970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996

    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);
997
    TEST(substate, nua_substate_pending);
998 999 1000 1001 1002 1003 1004

    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");
1005
    TEST_S(sip_header_as_string(tmphome, (void *)organization),
1006 1007 1008
	   "Pussy Galore's Flying Circus");
    TEST_S(organization_str, "Pussy Galore's Flying Circus");

1009 1010 1011 1012 1013 1014
    TEST(keepalive, 66);
    TEST(keepalive_stream, 33);

    TEST_S(outbound, "foo");
    TEST_S(instance, "urn:uuid:97701ad9-39df-1229-1083-dbc0a85f029c");

1015
    TEST_S(url_as_string(tmphome, registrar->us_url),
1016
	   "sip:sip.wonderland.org");
1017

Pekka Pessi's avatar
Pekka Pessi committed
1018
    free_events_in_list(ctx, ctx->a.events);
1019
  }
1020

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

1023 1024 1025 1026
  {
    sip_from_t const *from = NONE;
    char const *from_str = "NONE";

Pekka Pessi's avatar
Pekka Pessi committed
1027 1028
    unsigned retry_count = -1;
    unsigned max_subscriptions = -1;
1029

1030 1031 1032 1033 1034
    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
1035
    unsigned invite_timeout = -1;
1036

Pekka Pessi's avatar
Pekka Pessi committed
1037 1038
    unsigned session_timer = -1;
    unsigned min_se = -1;
1039 1040
    int refresher = -1;
    int update_refresh = -1;
1041

1042 1043 1044
    int message_enable = -1;
    int win_messenger_enable = -1;
    int message_auto_respond = -1;
1045

1046 1047 1048 1049
    int callee_caps = -1;
    int media_features = -1;
    int service_route_enable = -1;
    int path_enable = -1;
1050
    int substate = -1;
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063

    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;
1064
    struct event *e;
1065

1066
    nua_get_hparams(nh, TAG_ANY(), TAG_END());
1067
    run_a_until(ctx, nua_r_get_params, save_until_final_response);
1068

Pekka Pessi's avatar
Pekka Pessi committed
1069
    TEST_1(e = ctx->a.events->head);
1070
    TEST_E(e->data->e_event, nua_r_get_params);
1071

1072
    n = tl_gets(e->data->e_tags,
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
	       	SIPTAG_FROM_REF(from),
	       	SIPTAG_FROM_STR_REF(from_str),

	       	NUTAG_RETRY_COUNT_REF(retry_count),