Commit 468b2690 authored by Pekka Pessi's avatar Pekka Pessi

nua: save Contact from target refresh request or response.

Save the Contact header which the application has added to the target
refresh requests or responses and use the saved contact in subsequent target
refresh requests or responses.

Previously the application had no way of specifying the Contact included in
the automatic responses to target refresh requests.

Thanks for Anthony Minessale for reporting this problem.

darcs-hash:20070910162753-65a35-5d7e4b1312164aa849546b360079b74c5b58cb87.gz
parent 34bb6a58
...@@ -190,6 +190,7 @@ int nua_dialog_remove(nua_owner_t *own, ...@@ -190,6 +190,7 @@ int nua_dialog_remove(nua_owner_t *own,
{ {
if (ds->ds_usage == usage && (usage == NULL || usage->du_next == NULL)) { if (ds->ds_usage == usage && (usage == NULL || usage->du_next == NULL)) {
nua_dialog_store_peer_info(own, ds, NULL); /* zap peer info */ nua_dialog_store_peer_info(own, ds, NULL); /* zap peer info */
msg_header_free(own, (msg_header_t *)ds->ds_ltarget), ds->ds_ltarget = NULL;
nta_leg_destroy(ds->ds_leg), ds->ds_leg = NULL; nta_leg_destroy(ds->ds_leg), ds->ds_leg = NULL;
su_free(own, (void *)ds->ds_remote_tag), ds->ds_remote_tag = NULL; su_free(own, (void *)ds->ds_remote_tag), ds->ds_remote_tag = NULL;
ds->ds_route = 0; ds->ds_route = 0;
......
...@@ -352,11 +352,12 @@ struct nua_dialog_state ...@@ -352,11 +352,12 @@ struct nua_dialog_state
sip_from_t const *ds_local; /**< Local address */ sip_from_t const *ds_local; /**< Local address */
sip_to_t const *ds_remote; /**< Remote address */ sip_to_t const *ds_remote; /**< Remote address */
nta_leg_t *ds_leg; nta_leg_t *ds_leg;
sip_contact_t *ds_ltarget; /**< Local target */
char const *ds_remote_tag; /**< Remote tag (if any). char const *ds_remote_tag; /**< Remote tag (if any).
* Should be non-NULL * Should be non-NULL
* if dialog is established. * if dialog is established.
*/ */
struct nua_dialog_peer_info { struct nua_dialog_peer_info {
sip_allow_t *nr_allow; sip_allow_t *nr_allow;
sip_accept_t *nr_accept; sip_accept_t *nr_accept;
......
...@@ -1428,9 +1428,10 @@ int nua_server_trespond(nua_server_request_t *sr, ...@@ -1428,9 +1428,10 @@ int nua_server_trespond(nua_server_request_t *sr,
int nua_server_respond(nua_server_request_t *sr, tagi_t const *tags) int nua_server_respond(nua_server_request_t *sr, tagi_t const *tags)
{ {
nua_handle_t *nh = sr->sr_owner; nua_handle_t *nh = sr->sr_owner;
nua_dialog_state_t *ds = nh->nh_ds;
sip_method_t method = sr->sr_method; sip_method_t method = sr->sr_method;
struct { msg_t *msg; sip_t *sip; } next = { NULL, NULL }; struct { msg_t *msg; sip_t *sip; } next = { NULL, NULL };
int retval; int retval, user_contact = 1;
#if HAVE_OPEN_C #if HAVE_OPEN_C
/* Nice. And old arm symbian compiler; see below. */ /* Nice. And old arm symbian compiler; see below. */
tagi_t next_tags[2]; tagi_t next_tags[2];
...@@ -1485,15 +1486,26 @@ int nua_server_respond(nua_server_request_t *sr, tagi_t const *tags) ...@@ -1485,15 +1486,26 @@ int nua_server_respond(nua_server_request_t *sr, tagi_t const *tags)
sip_add_dup(msg, sip, (void *)NH_PGET(nh, allow_events)) < 0) sip_add_dup(msg, sip, (void *)NH_PGET(nh, allow_events)) < 0)
; ;
else if (!sip->sip_contact && sr->sr_status < 300 && sr->sr_add_contact && else if (!sip->sip_contact && sr->sr_status < 300 && sr->sr_add_contact &&
nua_registration_add_contact_to_response(nh, msg, sip, NULL, m) < 0) (user_contact = 0,
ds->ds_ltarget
? sip_add_dup(msg, sip, (sip_header_t *)ds->ds_ltarget)
: nua_registration_add_contact_to_response(nh, msg, sip, NULL, m))
< 0)
; ;
else { else {
int term; int term;
sip_contact_t *ltarget = NULL;
term = sip_response_terminates_dialog(sr->sr_status, sr->sr_method, NULL); term = sip_response_terminates_dialog(sr->sr_status, sr->sr_method, NULL);
sr->sr_terminating = (term < 0) ? -1 : (term > 0 || sr->sr_terminating); sr->sr_terminating = (term < 0) ? -1 : (term > 0 || sr->sr_terminating);
if (sr->sr_target_refresh && sr->sr_status < 300 && !sr->sr_terminating &&
user_contact && sip->sip_contact) {
/* Save Contact given by application */
ltarget = sip_contact_dup(nh->nh_home, sip->sip_contact);
}
retval = sr->sr_methods->sm_respond(sr, next_tags); retval = sr->sr_methods->sm_respond(sr, next_tags);
if (sr->sr_status < 200) if (sr->sr_status < 200)
...@@ -1503,6 +1515,16 @@ int nua_server_respond(nua_server_request_t *sr, tagi_t const *tags) ...@@ -1503,6 +1515,16 @@ int nua_server_respond(nua_server_request_t *sr, tagi_t const *tags)
assert(sr->sr_status >= 200 || sr->sr_response.msg); assert(sr->sr_status >= 200 || sr->sr_response.msg);
if (ltarget) {
if (sr->sr_status < 300) {
nua_dialog_state_t *ds = nh->nh_ds;
msg_header_free(nh->nh_home, (msg_header_t *)ds->ds_ltarget);
ds->ds_ltarget = ltarget;
}
else
msg_header_free(nh->nh_home, (msg_header_t *)ltarget);
}
return retval; return retval;
} }
...@@ -2250,9 +2272,20 @@ int nua_client_request_sendmsg(nua_client_request_t *cr, msg_t *msg, sip_t *sip) ...@@ -2250,9 +2272,20 @@ int nua_client_request_sendmsg(nua_client_request_t *cr, msg_t *msg, sip_t *sip)
* registrar is also added to the request message. * registrar is also added to the request message.
*/ */
if (cr->cr_method != sip_method_register) { if (cr->cr_method != sip_method_register) {
if (cr->cr_contactize && cr->cr_has_contact) {
sip_contact_t *ltarget = sip_contact_dup(nh->nh_home, sip->sip_contact);
if (ds->ds_ltarget)
msg_header_free(nh->nh_home, (msg_header_t *)ds->ds_ltarget);
ds->ds_ltarget = ltarget;
}
if (ds->ds_ltarget && !cr->cr_has_contact)
sip_add_dup(msg, sip, (sip_header_t *)ds->ds_ltarget);
if (nua_registration_add_contact_to_request(nh, msg, sip, if (nua_registration_add_contact_to_request(nh, msg, sip,
cr->cr_contactize && cr->cr_contactize &&
!cr->cr_has_contact, !cr->cr_has_contact &&
!ds->ds_ltarget,
!ds->ds_route) < 0) !ds->ds_route) < 0)
return -1; return -1;
} }
......
...@@ -1356,14 +1356,262 @@ int accept_upgrade(CONDITION_PARAMS) ...@@ -1356,14 +1356,262 @@ int accept_upgrade(CONDITION_PARAMS)
} }
} }
/* Basic call and re-INVITE with user-specified Contact:
A B
|-------INVITE------>|
|<----100 Trying-----|
| |
|<----180 Ringing----|
| |
|<------200 OK-------|
|--------ACK-------->|
| |
|-----re-INVITE----->|
|<------200 OK-------|
|--------ACK-------->|
| |
|<-------BYE---------|
|-------200 OK------>|
| |
Client transitions:
INIT -(C1)-> CALLING -(C2a)-> PROCEEDING -(C3+C4)-> READY
Server transitions:
INIT -(S1)-> RECEIVED -(S2a)-> EARLY -(S3b)-> COMPLETED -(S4)-> READY
Both client and server save Contact from nua_invite() and nua_respond(),
respectively.
INIT -(C1)-> CALLING -(C3a+C4)-> READY
INIT -(S3c)-> COMPLETED -(S4)-> READY
Both client and server use saved Contact.
B sends BYE:
READY -(T2)-> TERMINATING -(T3)-> TERMINATED
A receives BYE:
READY -(T1)-> TERMINATED
See @page nua_call_model in nua.docs for more information
*/
static sip_contact_t *contact_for_b;
int accept_call_with_contact(CONDITION_PARAMS)
{
if (!(check_handle(ep, call, nh, SIP_500_INTERNAL_SERVER_ERROR)))
return 0;
save_event_in_list(ctx, event, ep, call);
switch (callstate(tags)) {
case nua_callstate_received:
RESPOND(ep, call, nh, SIP_180_RINGING,
TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
SIPTAG_CONTACT(contact_for_b),
TAG_END());
return 0;
case nua_callstate_early:
RESPOND(ep, call, nh, SIP_200_OK,
TAG_IF(call->sdp, SOATAG_USER_SDP_STR(call->sdp)),
SIPTAG_CONTACT(contact_for_b),
TAG_END());
return 0;
case nua_callstate_ready:
return 1;
case nua_callstate_terminated:
if (call)
nua_handle_destroy(call->nh), call->nh = NULL;
return 1;
default:
return 0;
}
}
int test_basic_call_6(struct context *ctx)
{
BEGIN();
struct endpoint *a = &ctx->a, *b = &ctx->b;
struct call *a_call = a->call, *b_call = b->call;
struct event *e;
sip_t *sip;
sip_contact_t ma[1], mb[1];
if (print_headings)
printf("TEST NUA-3.1: Basic call\n");
a_call->sdp = "m=audio 5008 RTP/AVP 8";
b_call->sdp = "m=audio 5010 RTP/AVP 0 8";
TEST_1(a_call->nh = nua_handle(a->nua, a_call, SIPTAG_TO(b->to), TAG_END()));
TEST_1(!nua_handle_has_active_call(a_call->nh));
TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
*ma = *a->contact;
ma->m_display = "Alice B.";
ma->m_url->url_user = "a++a";
*mb = *b->contact;
mb->m_display = "Bob A.";
mb->m_url->url_user = "b++b";
contact_for_b = mb;
INVITE(a, a_call, a_call->nh,
TAG_IF(!ctx->proxy_tests, NUTAG_URL(b->contact->m_url)),
SOATAG_USER_SDP_STR(a_call->sdp),
SIPTAG_CONTACT(ma),
TAG_END());
run_ab_until(ctx, -1, until_ready, -1, accept_call_with_contact);
TEST_1(nua_handle_has_active_call(a_call->nh));
TEST_1(!nua_handle_has_call_on_hold(a_call->nh));
TEST_1(nua_handle_has_active_call(b_call->nh));
TEST_1(!nua_handle_has_call_on_hold(b_call->nh));
/* Client transitions:
INIT -(C1)-> CALLING: nua_invite(), nua_i_state
CALLING -(C2)-> PROCEEDING: nua_r_invite, nua_i_state
PROCEEDING -(C3+C4)-> READY: nua_r_invite, nua_i_state
*/
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
TEST_1(is_offer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 180);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_payload);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_proceeding); /* PROCEEDING */
TEST_1(is_answer_recv(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_payload);
TEST_1(sip->sip_contact);
TEST_S(sip->sip_contact->m_display, "Bob A.");
TEST_S(sip->sip_contact->m_url->url_user, "b++b");
/* Test that B uses application-specific contact */
TEST_1(sip->sip_contact->m_url->url_user);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
/*
Server transitions:
INIT -(S1)-> RECEIVED: nua_i_invite, nua_i_state
RECEIVED -(S2a)-> EARLY: nua_respond(), nua_i_state
EARLY -(S3b)-> COMPLETED: nua_respond(), nua_i_state
COMPLETED -(S4)-> READY: nua_i_ack, nua_i_state
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
TEST(e->data->e_status, 100);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_contact);
TEST_S(sip->sip_contact->m_display, "Alice B.");
TEST_S(sip->sip_contact->m_url->url_user, "a++a");
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_received); /* RECEIVED */
TEST_1(is_offer_recv(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_early); /* EARLY */
TEST_1(is_answer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
TEST_1(is_answer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
TEST_1(!e->next);
free_events_in_list(ctx, b->events);
/* re-INVITE */
INVITE(a, a_call, a_call->nh, TAG_END());
run_ab_until(ctx, -1, until_ready, -1, until_ready);
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_calling); /* CALLING */
TEST_1(is_offer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_r_invite);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_contact);
TEST_S(sip->sip_contact->m_display, "Bob A.");
TEST_S(sip->sip_contact->m_url->url_user, "b++b");
/* Test that B uses application-specific contact */
TEST_1(sip->sip_contact->m_url->url_user);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_i_invite);
TEST(e->data->e_status, 200);
TEST_1(sip = sip_object(e->data->e_msg));
TEST_1(sip->sip_contact);
TEST_S(sip->sip_contact->m_display, "Alice B.");
TEST_S(sip->sip_contact->m_url->url_user, "a++a");
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_completed); /* COMPLETED */
TEST_1(is_answer_sent(e->data->e_tags));
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_ack);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_ready); /* READY */
TEST_1(!e->next);
free_events_in_list(ctx, b->events);
BYE(b, b_call, b_call->nh, TAG_END());
run_ab_until(ctx, -1, until_terminated, -1, until_terminated);
/* B transitions:
READY --(T2)--> TERMINATING: nua_bye()
TERMINATING --(T3)--> TERMINATED: nua_r_bye, nua_i_state
*/
TEST_1(e = b->events->head); TEST_E(e->data->e_event, nua_r_bye);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
TEST_1(!e->next);
free_events_in_list(ctx, b->events);
TEST_1(!nua_handle_has_active_call(b_call->nh));
/* A transitions:
READY -(T1)-> TERMINATED: nua_i_bye, nua_i_state
*/
TEST_1(e = a->events->head); TEST_E(e->data->e_event, nua_i_bye);
TEST(e->data->e_status, 200);
TEST_1(e = e->next); TEST_E(e->data->e_event, nua_i_state);
TEST(callstate(e->data->e_tags), nua_callstate_terminated); /* TERMINATED */
TEST_1(!e->next);
free_events_in_list(ctx, a->events);
TEST_1(!nua_handle_has_active_call(a_call->nh));
nua_handle_destroy(a_call->nh), a_call->nh = NULL;
nua_handle_destroy(b_call->nh), b_call->nh = NULL;
if (print_headings)
printf("TEST NUA-3.1: PASSED\n");
END();
}
int test_basic_call(struct context *ctx) int test_basic_call(struct context *ctx)
{ {
return return 0
test_basic_call_1(ctx) || test_basic_call_1(ctx)
|| test_basic_call_2(ctx) || test_basic_call_2(ctx)
|| test_basic_call_3(ctx) || test_basic_call_3(ctx)
|| test_basic_call_4(ctx) || test_basic_call_4(ctx)
|| test_basic_call_5(ctx) || test_basic_call_5(ctx)
|| test_basic_call_6(ctx)
|| test_video_call_1(ctx) || test_video_call_1(ctx)
; ;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment