Commit 452a735e authored by Pekka Pessi's avatar Pekka Pessi
Browse files

Refactored test_nua.c.

The test structure now allows for multiple active handles per endpoint.

darcs-hash:20051028122603-65a35-a9794f7b621b7ed2e1ae72c94861240668715ee4.gz
parent d75d3b6b
......@@ -45,7 +45,9 @@
struct context;
#define NUA_MAGIC_T struct context
#define NUA_HMAGIC_T void
struct call;
#define NUA_HMAGIC_T struct call
#include "nua.h"
#include "nua_tag.h"
......@@ -90,10 +92,20 @@ int condition_function(nua_event_t event,
int status, char const *phrase,
nua_t *nua, struct context *ctx,
struct endpoint *ep,
nua_handle_t *nh, void *call,
nua_handle_t *nh, struct call *call,
sip_t const *sip,
tagi_t tags[]);
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[]);
struct context
{
su_home_t home[1];
......@@ -111,16 +123,18 @@ struct context
nua_event_t next_event, last_event;
nua_t *nua;
sip_contact_t *contact;
sip_from_t *address;
sip_from_t *to;
condition_function *printer;
printer_function *printer;
/* Per-call stuff */
nua_handle_t *nh;
struct {
struct event *head, **tail;
} events;
struct call {
struct call *next;
nua_handle_t *nh;
struct {
struct event *head, **tail;
} events;
} call[1];
} a, b, c;
};
......@@ -131,28 +145,35 @@ struct event
nua_event_data_t const *data;
};
static int save_event_in_list(struct context *ctx, struct endpoint *ep);
static void free_events_in_list(struct context *ctx, struct endpoint *ep);
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 *);
#define CONDITION_FUNCTION(name) \
int name(nua_event_t event, \
int status, char const *phrase, \
nua_t *nua, struct context *ctx, \
struct endpoint *ep, \
nua_handle_t *nh, void *call, \
nua_handle_t *nh, struct call *call, \
sip_t const *sip, \
tagi_t tags[])
CONDITION_FUNCTION(until_final_response){ return status >= 200; }
CONDITION_FUNCTION(save_until_final_response)
{
save_event_in_list(ctx, ep);
return status >= 200;
save_event_in_list(ctx, event, ep, ep->call);
return event >= nua_r_set_params && status >= 200;
}
/** Save events (except nua_i_active or terminated).
* Terminate when a event is saved.
*/
CONDITION_FUNCTION(save_until_received)
{
save_event_in_list(ctx, ep);
save_event_in_list(ctx, event, ep, ep->call);
return 1;
}
......@@ -205,18 +226,29 @@ int video_activity(tagi_t const *tags)
return ti ? ti->t_value : -1;
}
CONDITION_FUNCTION(print_event)
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[])
{
if (event == nua_i_state) {
fprintf(stderr, "%s.nua(%p): event %s %s\n",
ep->name, nh, nua_event_name(event),
nua_callstate_name(callstate(tags)));
}
else if ((int)event >= 0) {
else if ((int)event >= nua_r_set_params) {
fprintf(stderr, "%s.nua(%p): event %s status %u %s\n",
ep->name, nh, nua_event_name(event), status, phrase);
}
else if ((int)event >= 0) {
fprintf(stderr, "%s.nua(%p): event %s %s\n",
ep->name, nh, nua_event_name(event), phrase);
}
else if (status > 0) {
fprintf(stderr, "%s.nua(%p): call %s() with status %u %s\n",
ep->name, nh, (char const *)call, status, phrase);
......@@ -227,29 +259,41 @@ CONDITION_FUNCTION(print_event)
if (t && t->t_value) {
char const *subject = (char const *)t->t_value;
fprintf(stderr, "%s.nua(%p): call %s() \"%s\"\n",
ep->name, nh, (char const *)call, subject);
ep->name, nh, operation, subject);
}
else
fprintf(stderr, "%s.nua(%p): call %s()\n",
ep->name, nh, (char const *)call);
ep->name, nh, operation);
}
if ((tstflags & tst_verbatim) && tags)
tl_print(stderr, "", tags);
return 0;
}
void ep_callback(nua_event_t event,
int status, char const *phrase,
nua_t *nua, struct context *ctx,
struct endpoint *ep,
nua_handle_t *nh, void *call,
nua_handle_t *nh, struct call *call,
sip_t const *sip,
tagi_t tags[])
{
if (ep->printer)
ep->printer(event, status, phrase, nua, ctx, ep, nh, call, sip, tags);
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);
}
}
if ((ep->next_event == -1 || ep->next_event == event) &&
(ep->next_condition == NULL ||
......@@ -263,7 +307,7 @@ void ep_callback(nua_event_t event,
void a_callback(nua_event_t event,
int status, char const *phrase,
nua_t *nua, struct context *ctx,
nua_handle_t *nh, void *call,
nua_handle_t *nh, struct call *call,
sip_t const *sip,
tagi_t tags[])
{
......@@ -273,7 +317,7 @@ void a_callback(nua_event_t event,
void b_callback(nua_event_t event,
int status, char const *phrase,
nua_t *nua, struct context *ctx,
nua_handle_t *nh, void *call,
nua_handle_t *nh, struct call *call,
sip_t const *sip,
tagi_t tags[])
{
......@@ -283,7 +327,7 @@ void b_callback(nua_event_t event,
void c_callback(nua_event_t event,
int status, char const *phrase,
nua_t *nua, struct context *ctx,
nua_handle_t *nh, void *call,
nua_handle_t *nh, struct call *call,
sip_t const *sip,
tagi_t tags[])
{
......@@ -348,77 +392,39 @@ int run_c_until(struct context *ctx,
return ctx->c.last_event;
}
/* Invite via endpoint and handle */
int invite(struct endpoint *ep, 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, 0, "", ep->nua, ep->ctx, ep,
nh, "nua_invite", NULL, ta_args(ta));
nua_invite(nh, ta_tags(ta));
ta_end(ta);
return 0;
}
/* cancel via endpoint and handle */
int cancel(struct endpoint *ep, 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, 0, "", ep->nua, ep->ctx, ep,
nh, "nua_cancel", NULL, ta_args(ta));
nua_cancel(nh, ta_tags(ta));
ta_end(ta);
return 0;
}
/* bye via endpoint and handle */
int bye(struct endpoint *ep, 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, 0, "", ep->nua, ep->ctx, ep,
nh, "nua_bye", NULL, ta_args(ta));
nua_bye(nh, ta_tags(ta));
ta_end(ta);
return 0;
}
/* authenticate via endpoint and handle */
int authenticate(struct endpoint *ep, 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, 0, "", ep->nua, ep->ctx, ep,
nh, "nua_authenticate", NULL, ta_args(ta));
nua_authenticate(nh, ta_tags(ta));
ta_end(ta);
return 0;
}
#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);
OPERATION(bye);
OPERATION(cancel);
OPERATION(authenticate);
OPERATION(refer);
OPERATION(message);
OPERATION(options);
OPERATION(publish);
OPERATION(subscribe);
/* Respond via endpoint and handle */
int respond(struct endpoint *ep, nua_handle_t *nh,
int respond(struct endpoint *ep,
struct call *call,
nua_handle_t *nh,
int status, char const *phrase,
tag_type_t tag, tag_value_t value,
...)
......@@ -428,8 +434,8 @@ int respond(struct endpoint *ep, nua_handle_t *nh,
ta_start(ta, tag, value);
if (ep->printer)
ep->printer(-1, status, phrase, ep->nua, ep->ctx, ep,
nh, "nua_respond", NULL, ta_args(ta));
ep->printer(-1, "nua_respond", status, phrase, ep->nua, ep->ctx, ep,
nh, call, NULL, ta_args(ta));
nua_respond(nh, status, phrase, ta_tags(ta));
ta_end(ta);
......@@ -437,110 +443,72 @@ int respond(struct endpoint *ep, nua_handle_t *nh,
return 0;
}
/* message via endpoint and handle */
int message(struct endpoint *ep, 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, 0, "", ep->nua, ep->ctx, ep,
nh, "nua_message", NULL, ta_args(ta));
nua_message(nh, ta_tags(ta));
ta_end(ta);
return 0;
}
/* options via endpoint and handle */
int options(struct endpoint *ep, nua_handle_t *nh,
tag_type_t tag, tag_value_t value,
...)
/* 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)
{
ta_list ta;
ta_start(ta, tag, value);
if (ep->printer)
ep->printer(-1, 0, "", ep->nua, ep->ctx, ep,
nh, "nua_options", NULL, ta_args(ta));
nua_options(nh, ta_tags(ta));
ta_end(ta);
return 0;
}
/* publish via endpoint and handle */
int publish(struct endpoint *ep, 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, 0, "", ep->nua, ep->ctx, ep,
nh, "nua_publish", NULL, ta_args(ta));
if (call)
return call;
nua_publish(nh, ta_tags(ta));
if (status)
respond(ep, call, nh, status, phrase, TAG_END());
ta_end(ta);
return 0;
nua_handle_destroy(nh);
return NULL;
}
/* Reject all but currently used handle */
int check_handle(struct endpoint *ep, nua_handle_t *nh,
int status, char const *phrase)
static void
call_init(struct call *call)
{
if (ep->nh && ep->nh != nh) {
if (status) {
respond(ep, nh, status, phrase, TAG_END());
}
nua_handle_destroy(nh);
return 0;
}
ep->nh = nh;
return 1;
call->events.tail = &call->events.head;
}
/* Save nua event in endpoint list */
/* Save nua event in call-specific list */
static
int save_event_in_list(struct context *ctx,
struct endpoint *ep)
nua_event_t nevent,
struct endpoint *ep,
struct call *call)
{
struct event *e = su_zalloc(ctx->home, sizeof *e);
struct event *e;
if (nevent == nua_i_active || nevent == nua_i_terminated)
return 0;
e = su_zalloc(ctx->home, sizeof *e);
if (!e) { perror("su_zalloc"), abort(); }
*(e->prev = ep->events.tail) = e;
ep->events.tail = &e->next;
*(e->prev = call->events.tail) = e;
call->events.tail = &e->next;
if (!nua_save_event(ep->nua, e->saved_event))
return -1;
e->data = nua_event_data(e->saved_event);
return 0;
return 1;
}
/* Save nua event in endpoint list */
static
void free_events_in_list(struct context *ctx, struct endpoint *ep)
void free_events_in_list(struct context *ctx,
struct call *call)
{
struct event *e;
while ((e = ep->events.head)) {
while ((e = call->events.head)) {
if ((*e->prev = e->next))
e->next->prev = e->prev;
nua_destroy_event(e->saved_event);
su_free(ctx->home, e);
}
ep->events.tail = &ep->events.head;
call->events.tail = &call->events.head;
}
void nolog(void *stream, char const *fmt, va_list ap) {}
......@@ -766,7 +734,7 @@ int test_params(struct context *ctx)
nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
run_a_until(ctx, nua_r_get_params, save_until_final_response);
TEST_1(e = ctx->a.events.head);
TEST_1(e = ctx->a.call->events.head);
TEST_E(e->data->e_event, nua_r_get_params);
n = tl_gets(e->data->e_tags,
......@@ -852,7 +820,7 @@ int test_params(struct context *ctx)
TEST_S(url_as_string(tmphome, registrar->us_url),
"sip:sip.wonderland.org");
free_events_in_list(ctx, &ctx->a);
free_events_in_list(ctx, ctx->a.call);
}
{
......@@ -900,7 +868,7 @@ int test_params(struct context *ctx)
nua_get_hparams(nh, TAG_ANY(), TAG_END());
run_a_until(ctx, nua_r_get_params, save_until_final_response);
TEST_1(e = ctx->a.events.head);
TEST_1(e = ctx->a.call->events.head);
TEST_E(e->data->e_event, nua_r_get_params);
n = tl_gets(e->data->e_tags,
......@@ -986,7 +954,7 @@ int test_params(struct context *ctx)
TEST(registrar->us_url, NONE);
free_events_in_list(ctx, &ctx->a);
free_events_in_list(ctx, ctx->a.call);
}
nua_handle_destroy(nh);
......@@ -1029,15 +997,15 @@ int test_init(struct context *ctx, char *argv[])
nua_get_params(ctx->a.nua, TAG_ANY(), TAG_END());
run_a_until(ctx, nua_r_get_params, save_until_final_response);
TEST_1(e = ctx->a.events.head);
TEST_1(e = ctx->a.call->events.head);
TEST(tl_gets(e->data->e_tags,
NTATAG_CONTACT_REF(m),
SIPTAG_FROM_REF(sipaddress),
TAG_END()), 2); TEST_1(m);
TEST_1(ctx->a.contact = sip_contact_dup(ctx->home, m));
TEST_1(ctx->a.address = sip_to_dup(ctx->home, sipaddress));
TEST_1(ctx->a.to = sip_to_dup(ctx->home, sipaddress));
free_events_in_list(ctx, &ctx->a);
free_events_in_list(ctx, ctx->a.call);
if (print_headings)
printf("TEST NUA-3.0.1: PASSED\n");
......@@ -1054,14 +1022,14 @@ int test_init(struct context *ctx, char *argv[])
nua_get_params(ctx->b.nua, TAG_ANY(), TAG_END());
run_b_until(ctx, nua_r_get_params, save_until_final_response);
TEST_1(e = ctx->b.events.head);
TEST_1(e = ctx->b.call->events.head);
TEST(tl_gets(e->data->e_tags,
NTATAG_CONTACT_REF(m),
SIPTAG_FROM_REF(sipaddress),
TAG_END()), 2); TEST_1(m);
TEST_1(ctx->b.contact = sip_contact_dup(ctx->home, m));
TEST_1(ctx->b.address = sip_to_dup(ctx->home, sipaddress));
free_events_in_list(ctx, &ctx->b);
TEST_1(ctx->b.to = sip_to_dup(ctx->home, sipaddress));
free_events_in_list(ctx, ctx->b.call);
if (print_headings)
printf("TEST NUA-3.0.2: PASSED\n");
......@@ -1078,14 +1046,14 @@ int test_init(struct context *ctx, char *argv[])
nua_get_params(ctx->c.nua, TAG_ANY(), TAG_END());
run_c_until(ctx, nua_r_get_params, save_until_final_response);
TEST_1(e = ctx->c.events.head);
TEST_1(e = ctx->c.call->events.head);
TEST(tl_gets(e->data->e_tags,
NTATAG_CONTACT_REF(m),
SIPTAG_FROM_REF(sipaddress),
TAG_END()), 2); TEST_1(m);
TEST_1(ctx->c.contact = sip_contact_dup(ctx->home, m));
TEST_1(ctx->c.address = sip_to_dup(ctx->home, sipaddress));
free_events_in_list(ctx, &ctx->c);
TEST_1(ctx->c.to = sip_to_dup(ctx->home, sipaddress));
free_events_in_list(ctx, ctx->c.call);
if (print_headings)
printf("TEST NUA-3.0.3: PASSED\n");
......@@ -1095,18 +1063,15 @@ int test_init(struct context *ctx, char *argv[])
CONDITION_FUNCTION(save_events)
{
if (event != nua_i_active && event != nua_i_terminated)
save_event_in_list(ctx, ep);
return 0;
return save_event_in_list(ctx, event, ep, ep->call) > 0;
}
CONDITION_FUNCTION(until_terminated)
{
if (!check_handle(ep, nh, SIP_500_INTERNAL_SERVER_ERROR))
if (!check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR))
return 0;
if (event != nua_i_active && event != nua_i_terminated)
save_event_in_list(ctx, ep);
save_event_in_list(ctx, event, ep, call);
return event == nua_i_state && callstate(tags) == nua_callstate_terminated;
}
......@@ -1125,7 +1090,7 @@ CONDITION_FUNCTION(until_terminated)
|--------ACK-------->|
| |
|<-------BYE---------|
|-------200 OK-------|
|-------200 OK------>|
| |
Client transitions:
......@@ -1142,23 +1107,23 @@ CONDITION_FUNCTION(until_terminated)
CONDITION_FUNCTION(receive_basic_call)
{
if (!check_handle(ep, nh, SIP_486_BUSY_HERE))
if (!(check_handle(ep, call, nh, SIP_486_BUSY_HERE)))
return 0;
if (event != nua_i_active && event != nua_i_terminated)
save_event_in_list(ctx, ep);
save_event_in_list(ctx, event, ep, call);
switch (callstate(tags)) {
case nua_callstate_received:
respond(ep, nh, SIP_180_RINGING, TAG_END());
respond(ep, call, nh, SIP_180_RINGING, TAG_END());
return 0;
case nua_callstate_early: