test_nua.c 174 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

162 163
    char const *instance;

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

Pekka Pessi's avatar
Pekka Pessi committed
172 173 174 175 176 177 178
    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
179 180 181 182 183 184 185 186 187
    /* 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;

188
  } a, b, c;
Pekka Pessi's avatar
Pekka Pessi committed
189 190

  struct proxy *p;
Pekka Pessi's avatar
Pekka Pessi committed
191
  struct nat *nat;
Pekka Pessi's avatar
Pekka Pessi committed
192 193
};

Pekka Pessi's avatar
Pekka Pessi committed
194 195 196 197 198
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
199
				struct eventlist *);
200

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

217 218
/** Save events.
 *
Pekka Pessi's avatar
Pekka Pessi committed
219 220
 * Terminate when a event is saved.
 */
221
int save_until_received(CONDITION_PARAMS)
222
{
223 224 225 226 227 228 229 230 231 232 233 234
  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;
235 236
}

Pekka Pessi's avatar
Pekka Pessi committed
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 284 285
/* 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
286 287 288 289 290 291 292 293 294
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
295 296 297
{
  if (event == nua_i_state) {
    fprintf(stderr, "%s.nua(%p): event %s %s\n",
298
	    ep->name, nh, nua_event_name(event),
Pekka Pessi's avatar
Pekka Pessi committed
299 300
	    nua_callstate_name(callstate(tags)));
  }
Pekka Pessi's avatar
Pekka Pessi committed
301
  else if ((int)event >= nua_r_set_params) {
Pekka Pessi's avatar
Pekka Pessi committed
302 303 304
    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
305 306 307 308
  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
309 310
  else if (status > 0) {
    fprintf(stderr, "%s.nua(%p): call %s() with status %u %s\n",
311
	    ep->name, nh, operation, status, phrase);
Pekka Pessi's avatar
Pekka Pessi committed
312 313
  }
  else {
Pekka Pessi's avatar
Pekka Pessi committed
314 315 316 317 318
    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
319
	      ep->name, nh, operation, subject);
Pekka Pessi's avatar
Pekka Pessi committed
320 321 322
    }
    else
      fprintf(stderr, "%s.nua(%p): call %s()\n",
Pekka Pessi's avatar
Pekka Pessi committed
323
	      ep->name, nh, operation);
Pekka Pessi's avatar
Pekka Pessi committed
324 325 326 327 328
  }

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

330 331 332 333
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
334
		 nua_handle_t *nh, struct call *call,
335 336
		 sip_t const *sip,
		 tagi_t tags[])
337
{
Pekka Pessi's avatar
Pekka Pessi committed
338
  if (ep->printer)
Pekka Pessi's avatar
Pekka Pessi committed
339 340
    ep->printer(event, "", status, phrase, nua, ctx, ep, nh, call, sip, tags);

341
  if (call == NULL && nh) {
Pekka Pessi's avatar
Pekka Pessi committed
342 343 344 345 346 347 348 349 350 351 352 353
    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
354 355 356 357 358

  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)))
359
    ep->running = 0;
360

Pekka Pessi's avatar
Pekka Pessi committed
361
  ep->last_event = event;
362 363 364

  if (call == NULL && nh)
    nua_handle_destroy(nh);
365 366
}

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

377 378 379
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
380
		nua_handle_t *nh, struct call *call,
381 382 383 384 385
		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
386

387 388 389
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
390
		nua_handle_t *nh, struct call *call,
391 392 393 394
		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
395 396
}

397 398 399 400
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
401
{
402
  struct endpoint *a = &ctx->a, *b = &ctx->b, *c = &ctx->c;
403 404 405 406 407

  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
408
  a->flags.n = 0;
409 410 411 412 413

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

416 417 418 419
  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
420
  c->flags.n = 0;
421 422

  for (; a->running || b->running || c->running;) {
Pekka Pessi's avatar
Pekka Pessi committed
423 424
    su_root_step(ctx->root, 1000);
  }
425
}
Pekka Pessi's avatar
Pekka Pessi committed
426

427 428 429 430 431 432 433
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);
}

434 435 436 437
int run_a_until(struct context *ctx,
		nua_event_t a_event,
		condition_function *a_condition)
{
438
  run_abc_until(ctx, a_event, a_condition, -1, NULL, -1, NULL);
439 440 441 442 443 444 445
  return ctx->a.last_event;
}

int run_b_until(struct context *ctx,
		nua_event_t b_event,
		condition_function *b_condition)
{
446
  run_abc_until(ctx, -1, NULL, b_event, b_condition, -1, NULL);
447
  return ctx->b.last_event;
Pekka Pessi's avatar
Pekka Pessi committed
448 449
}

Pekka Pessi's avatar
Pekka Pessi committed
450 451 452 453 454 455 456 457
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;
}

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

477 478 479 480 481 482 483
OPERATION(INVITE, invite);
OPERATION(ACK, ack);
OPERATION(BYE, bye);
OPERATION(CANCEL, cancel);
OPERATION(AUTHENTICATE, authenticate);
OPERATION(UPDATE, update);
OPERATION(INFO, info);
484
OPERATION(PRACK, prack);
485 486 487 488 489 490 491 492 493 494 495 496 497
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);
498

Pekka Pessi's avatar
Pekka Pessi committed
499
/* Respond via endpoint and handle */
500
int RESPOND(struct endpoint *ep,
Pekka Pessi's avatar
Pekka Pessi committed
501 502
	    struct call *call,
	    nua_handle_t *nh,
Pekka Pessi's avatar
Pekka Pessi committed
503 504 505 506 507 508 509
	    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
510 511

  if (ep->printer)
Pekka Pessi's avatar
Pekka Pessi committed
512 513
    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
514

Pekka Pessi's avatar
Pekka Pessi committed
515 516 517 518 519 520
  nua_respond(nh, status, phrase, ta_tags(ta));
  ta_end(ta);

  return 0;
}

521

Pekka Pessi's avatar
Pekka Pessi committed
522 523 524 525 526
/* 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)
527
{
Pekka Pessi's avatar
Pekka Pessi committed
528 529
  if (call)
    return call;
530

Pekka Pessi's avatar
Pekka Pessi committed
531
  if (status)
532
    RESPOND(ep, call, nh, status, phrase, TAG_END());
533

Pekka Pessi's avatar
Pekka Pessi committed
534 535
  nua_handle_destroy(nh);
  return NULL;
536 537
}

Pekka Pessi's avatar
Pekka Pessi committed
538

Pekka Pessi's avatar
Pekka Pessi committed
539
/* Save nua event in call-specific list */
540
static
541
int save_event_in_list(struct context *ctx,
Pekka Pessi's avatar
Pekka Pessi committed
542 543 544 545
		       nua_event_t nevent,
		       struct endpoint *ep,
		       struct call *call)

546
{
Pekka Pessi's avatar
Pekka Pessi committed
547
  struct eventlist *list;
Pekka Pessi's avatar
Pekka Pessi committed
548
  struct event *e;
Pekka Pessi's avatar
Pekka Pessi committed
549
  int action = ep->is_special(nevent);
Pekka Pessi's avatar
Pekka Pessi committed
550

Pekka Pessi's avatar
Pekka Pessi committed
551
  if (action == event_is_extra)
Pekka Pessi's avatar
Pekka Pessi committed
552
    return 0;
Pekka Pessi's avatar
Pekka Pessi committed
553
  else if (action == event_is_special || call == NULL)
Pekka Pessi's avatar
Pekka Pessi committed
554 555 556 557 558
    list = ep->specials;
  else if (call->events)
    list = call->events;
  else
    list = ep->events;
Pekka Pessi's avatar
Pekka Pessi committed
559 560

  e = su_zalloc(ctx->home, sizeof *e);
561 562

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

564 565
  if (!nua_save_event(ep->nua, e->saved_event)) {
    su_free(ctx->home, e);
Pekka Pessi's avatar
Pekka Pessi committed
566
    return -1;
567
  }
Pekka Pessi's avatar
Pekka Pessi committed
568

Pekka Pessi's avatar
Pekka Pessi committed
569 570 571
  *(e->prev = list->tail) = e; list->tail = &e->next;

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

574
  return action;
575
}
Pekka Pessi's avatar
Pekka Pessi committed
576

Pekka Pessi's avatar
Pekka Pessi committed
577
/* Save nua event in endpoint list */
578
static
Pekka Pessi's avatar
Pekka Pessi committed
579
void free_events_in_list(struct context *ctx,
Pekka Pessi's avatar
Pekka Pessi committed
580
			 struct eventlist *list)
Pekka Pessi's avatar
Pekka Pessi committed
581 582 583
{
  struct event *e;

Pekka Pessi's avatar
Pekka Pessi committed
584
  while ((e = list->head)) {
Pekka Pessi's avatar
Pekka Pessi committed
585 586 587 588 589
    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
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 623 624 625 626 627

  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
628 629
}

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

Pekka Pessi's avatar
Pekka Pessi committed
632 633 634 635 636
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
637
int test_nua_api_errors(struct context *ctx)
Pekka Pessi's avatar
Pekka Pessi committed
638 639 640
{
  BEGIN();

Pekka Pessi's avatar
Pekka Pessi committed
641
  /* Invoke every API function with invalid arguments */
Pekka Pessi's avatar
Pekka Pessi committed
642

Pekka Pessi's avatar
Pekka Pessi committed
643 644
  int level;

Pekka Pessi's avatar
Pekka Pessi committed
645 646
  int status; char const *phrase;

647 648 649
  if (print_headings)
    printf("TEST NUA-1.0: test API\n");

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

  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()));
684
  TEST_VOID(nua_prack(NULL, TAG_END()));
Pekka Pessi's avatar
Pekka Pessi committed
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
  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
702

Pekka Pessi's avatar
Pekka Pessi committed
703 704
  TEST_1(!nua_handle_home(NULL));
  TEST_1(!nua_save_event(NULL, NULL));
705
  TEST_1(!nua_event_data(NULL));
Pekka Pessi's avatar
Pekka Pessi committed
706
  TEST_VOID(nua_destroy_event(NULL));
707

Pekka Pessi's avatar
Pekka Pessi committed
708 709 710 711
  {
    nua_saved_event_t event[1];

    memset(event, 0, sizeof event);
712

Pekka Pessi's avatar
Pekka Pessi committed
713
    TEST_1(!nua_save_event(NULL, event));
714
    TEST_1(!nua_event_data(event));
Pekka Pessi's avatar
Pekka Pessi committed
715 716 717
    TEST_VOID(nua_destroy_event(event));
  }

Pekka Pessi's avatar
Pekka Pessi committed
718
  su_log_set_level(nua_log, level);
Pekka Pessi's avatar
Pekka Pessi committed
719

720 721 722
  if (print_headings)
    printf("TEST NUA-1.0: PASSED\n");

Pekka Pessi's avatar
Pekka Pessi committed
723 724 725
  END();
}

726
#include <sofia-sip/su_tag_class.h>
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743

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

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

775
  if (print_headings)
776
    printf("TEST NUA-1.1: PARAMETERS\n");
777

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

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

783 784
  ctx->a.nua = nua_create(ctx->root, a_callback, ctx,
			  SIPTAG_FROM_STR("sip:alice@example.com"),
785
			  NUTAG_URL("sip:0.0.0.0:*;transport=udp"),
786
			  TAG_END());
787

788 789
  TEST_1(ctx->a.nua);

790 791 792 793 794 795
  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);

796
  from = sip_from_make(tmphome, Alice);
797 798 799

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

800
  nua_set_hparams(nh, NUTAG_INVITE_TIMER(90), TAG_END());
801
  run_a_until(ctx, nua_r_set_params, until_final_response);
802

803 804 805 806 807 808 809 810 811 812 813 814 815 816
  /* 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());

817
  run_a_until(ctx, nua_r_set_params, until_final_response);
818

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

847 848 849 850 851 852
		 NUTAG_KEEPALIVE(66),
		 NUTAG_KEEPALIVE_STREAM(33),

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

853 854 855
		 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")),
856

857
		 SIPTAG_ORGANIZATION(sip_organization_make(tmphome, "Pussy Galore's Flying Circus")),
858 859

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

862 863
		 TAG_END());

864
  run_a_until(ctx, nua_r_set_params, until_final_response);
865

866 867 868 869
  /* Modify something... */
  nua_set_params(ctx->a.nua,
		 NUTAG_RETRY_COUNT(5),
		 TAG_END());
870
  run_a_until(ctx, nua_r_set_params, until_final_response);
871 872 873 874 875

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

Pekka Pessi's avatar
Pekka Pessi committed
876 877
    unsigned retry_count = -1;
    unsigned max_subscriptions = -1;
878

879 880 881 882 883
    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
884
    unsigned invite_timeout = -1;
885

Pekka Pessi's avatar
Pekka Pessi committed
886 887
    unsigned session_timer = -1;
    unsigned min_se = -1;
888 889
    int refresher = -1;
    int update_refresh = -1;
890

891 892 893
    int message_enable = -1;
    int win_messenger_enable = -1;
    int message_auto_respond = -1;
894

895 896 897 898
    int callee_caps = -1;
    int media_features = -1;
    int service_route_enable = -1;
    int path_enable = -1;
899
    int substate = -1;
900 901

    sip_allow_t const *allow = NONE;
902
    char const *allow_str = "NONE";
903 904 905 906 907 908 909
    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";

910 911 912 913 914
    char const *outbound = "NONE";
    char const *instance = "NONE";
    
    unsigned keepalive = -1, keepalive_stream = -1;

915 916 917
    url_string_t const *registrar = NONE;

    int n;
918
    struct event *e;
919

Pekka Pessi's avatar
Pekka Pessi committed
920
    nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
921
    run_a_until(ctx, nua_r_get_params, save_until_final_response);
922

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

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

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

965 966 967 968 969 970
		NUTAG_OUTBOUND_REF(outbound),
		NUTAG_INSTANCE_REF(instance),

		NUTAG_KEEPALIVE_REF(keepalive),
		NUTAG_KEEPALIVE_STREAM_REF(keepalive_stream),

971 972 973
	       	NUTAG_REGISTRAR_REF(registrar),

		TAG_END());
974
    TEST(n, 34);
975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001

    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);
1002
    TEST(substate, nua_substate_pending);
1003 1004 1005 1006 1007 1008 1009

    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");
1010
    TEST_S(sip_header_as_string(tmphome, (void *)organization),
1011 1012 1013
	   "Pussy Galore's Flying Circus");
    TEST_S(organization_str, "Pussy Galore's Flying Circus");

1014 1015 1016 1017 1018 1019
    TEST(keepalive, 66);
    TEST(keepalive_stream, 33);

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

1020
    TEST_S(url_as_string(tmphome, registrar->us_url),
1021
	   "sip:sip.wonderland.org");
1022

Pekka Pessi's avatar
Pekka Pessi committed
1023
    free_events_in_list(ctx, ctx->a.events);
1024
  }
1025

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

1028 1029 1030 1031
  {
    sip_from_t const *from = NONE;
    char const *from_str = "NONE";

Pekka Pessi's avatar
Pekka Pessi committed
1032 1033
    unsigned retry_count = -1;
    unsigned max_subscriptions = -1;
1034

1035 1036 1037 1038 1039
    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
1040
    unsigned invite_timeout = -1;
1041

Pekka Pessi's avatar
Pekka Pessi committed
1042 1043
    unsigned session_timer = -1;
    unsigned min_se = -1;
1044 1045
    int refresher = -1;
    int update_refresh = -1;
1046

1047 1048 1049
    int message_enable = -1;
    int win_messenger_enable = -1;
    int message_auto_respond = -1;
1050

1051 1052 1053 1054
    int callee_caps = -1;
    int media_features = -1;
    int service_route_enable = -1;
    int path_enable = -1;
1055
    int substate = -1;
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068

    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;
1069
    struct event *e;
1070

1071
    nua_get_hparams(nh, TAG_ANY(), TAG_END());
1072
    run_a_until(ctx, nua_r_get_params, save_until_final_response);
1073

Pekka Pessi's avatar
Pekka Pessi committed
1074
    TEST_1(e = ctx->a.events->head);
1075
    TEST_E(e->data