363 lines
9.7 KiB
C
363 lines
9.7 KiB
C
/*
|
|
* This file is part of the Sofia-SIP package
|
|
*
|
|
* Copyright (C) 2008 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 check_etsi.c
|
|
*
|
|
* @brief ETSI test cases
|
|
*
|
|
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
|
|
* @author Paulo Pizarro
|
|
*
|
|
* @copyright (C) 2008 Nokia Corporation.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#undef NDEBUG
|
|
|
|
#include "check_nua.h"
|
|
|
|
#include <sofia-sip/sip_status.h>
|
|
#include <sofia-sip/sip_header.h>
|
|
#include <sofia-sip/soa.h>
|
|
#include <sofia-sip/su_tagarg.h>
|
|
#include <sofia-sip/su_string.h>
|
|
#include <sofia-sip/su_tag_io.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
/* ====================================================================== */
|
|
|
|
/* define XXX as 1 in order to see all failing test cases */
|
|
#ifndef XXX
|
|
#define XXX (0)
|
|
#endif
|
|
|
|
/* ====================================================================== */
|
|
|
|
static nua_t *nua;
|
|
static soa_session_t *soa = NULL;
|
|
static struct dialog *d1 = NULL;
|
|
static struct dialog *d2 = NULL;
|
|
|
|
#define CRLF "\r\n"
|
|
|
|
static void etsi_setup(void)
|
|
{
|
|
nua = s2_nua_setup("ETSI",
|
|
NUTAG_OUTBOUND("no-options-keepalive, no-validate"),
|
|
TAG_END());
|
|
|
|
soa = soa_create(NULL, s2base->root, NULL);
|
|
|
|
fail_if(!soa);
|
|
|
|
soa_set_params(soa,
|
|
SOATAG_USER_SDP_STR("m=audio 5008 RTP/AVP 8 0" CRLF
|
|
"m=video 5010 RTP/AVP 34" CRLF),
|
|
TAG_END());
|
|
|
|
d1 = su_home_new(sizeof *d1); fail_if(!d1);
|
|
d2 = su_home_new(sizeof *d2); fail_if(!d2);
|
|
}
|
|
|
|
static void etsi_thread_setup(void)
|
|
{
|
|
s2_nua_thread = 1;
|
|
etsi_setup();
|
|
}
|
|
|
|
static void etsi_threadless_setup(void)
|
|
{
|
|
s2_nua_thread = 0;
|
|
etsi_setup();
|
|
}
|
|
|
|
static void etsi_teardown(void)
|
|
{
|
|
s2_teardown_started("ETSI");
|
|
|
|
mark_point();
|
|
|
|
nua_shutdown(nua);
|
|
fail_unless_event(nua_r_shutdown, 200);
|
|
|
|
s2_nua_teardown();
|
|
}
|
|
|
|
static void save_sdp_to_soa(struct message *message)
|
|
{
|
|
sip_payload_t *pl;
|
|
char const *body;
|
|
isize_t bodylen;
|
|
|
|
fail_if(!message);
|
|
|
|
fail_if(!message->sip->sip_content_length);
|
|
fail_if(!message->sip->sip_content_type);
|
|
fail_if(strcmp(message->sip->sip_content_type->c_type,
|
|
"application/sdp"));
|
|
|
|
fail_if(!message->sip->sip_payload);
|
|
pl = message->sip->sip_payload;
|
|
body = pl->pl_data, bodylen = pl->pl_len;
|
|
|
|
fail_if(soa_set_remote_sdp(soa, NULL, body, (issize_t)bodylen) < 0);
|
|
}
|
|
|
|
static void process_offer(struct message *message)
|
|
{
|
|
save_sdp_to_soa(message);
|
|
fail_if(soa_generate_answer(soa, NULL) < 0);
|
|
}
|
|
|
|
static void
|
|
respond_with_sdp(struct message *request,
|
|
struct dialog *dialog,
|
|
int status, char const *phrase,
|
|
tag_type_t tag, tag_value_t value, ...)
|
|
{
|
|
ta_list ta;
|
|
|
|
char const *body;
|
|
isize_t bodylen;
|
|
|
|
fail_if(soa_get_local_sdp(soa, NULL, &body, &bodylen) != 1);
|
|
|
|
ta_start(ta, tag, value);
|
|
s2_sip_respond_to(request, dialog, status, phrase,
|
|
SIPTAG_CONTENT_TYPE_STR("application/sdp"),
|
|
SIPTAG_PAYLOAD_STR(body),
|
|
SIPTAG_CONTENT_DISPOSITION_STR("session"),
|
|
ta_tags(ta));
|
|
ta_end(ta);
|
|
}
|
|
|
|
static struct message *
|
|
invite_sent_by_nua(nua_handle_t *nh,
|
|
tag_type_t tag, tag_value_t value, ...)
|
|
{
|
|
ta_list ta;
|
|
ta_start(ta, tag, value);
|
|
nua_invite(nh, SOATAG_USER_SDP_STR("m=audio 5004 RTP/AVP 0 8"),
|
|
ta_tags(ta));
|
|
ta_end(ta);
|
|
|
|
fail_unless(s2_check_callstate(nua_callstate_calling));
|
|
|
|
return s2_sip_wait_for_request(SIP_METHOD_INVITE);
|
|
}
|
|
|
|
static void
|
|
bye_by_nua(struct dialog *dialog, nua_handle_t *nh,
|
|
tag_type_t tag, tag_value_t value, ...)
|
|
{
|
|
ta_list ta;
|
|
struct message *bye;
|
|
|
|
ta_start(ta, tag, value);
|
|
nua_bye(nh, ta_tags(ta));
|
|
ta_end(ta);
|
|
|
|
bye = s2_sip_wait_for_request(SIP_METHOD_BYE);
|
|
fail_if(!bye);
|
|
s2_sip_respond_to(bye, dialog, SIP_200_OK, TAG_END());
|
|
s2_sip_free_message(bye);
|
|
fail_unless_event(nua_r_bye, 200);
|
|
fail_unless(s2_check_callstate(nua_callstate_terminated));
|
|
}
|
|
|
|
/* ====================================================================== */
|
|
/* 6 - ETSI cases */
|
|
|
|
/* 6.1 Call Control - Originating Endpoint - Call Establishment */
|
|
|
|
START_TEST(SIP_CC_OE_CE_V_019)
|
|
{
|
|
nua_handle_t *nh;
|
|
struct message *invite;
|
|
struct message *bye;
|
|
|
|
S2_CASE("6.1.1", "SIP_CC_OE_CE_V_019",
|
|
"Ensure that the IUT when an INVITE client transaction "
|
|
"is in the Calling state, on receipt of Success (200 OK) "
|
|
"responses differing only on the tag in the To header, "
|
|
"sends an ACK request with a To header identical to the "
|
|
"received one for each received Success (200 OK) responses.");
|
|
|
|
nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END());
|
|
|
|
invite = invite_sent_by_nua(nh, TAG_END());
|
|
|
|
process_offer(invite);
|
|
|
|
respond_with_sdp(invite, d1, SIP_200_OK, TAG_END());
|
|
|
|
fail_unless_event(nua_r_invite, 200);
|
|
fail_unless(s2_check_callstate(nua_callstate_ready));
|
|
fail_unless(s2_sip_check_request(SIP_METHOD_ACK));
|
|
|
|
respond_with_sdp(invite, d2, SIP_200_OK, TAG_END());
|
|
s2_sip_free_message(invite);
|
|
|
|
fail_unless(s2_sip_check_request(SIP_METHOD_ACK));
|
|
|
|
bye = s2_sip_wait_for_request(SIP_METHOD_BYE);
|
|
fail_if(!bye);
|
|
s2_sip_respond_to(bye, d2, SIP_200_OK, TAG_END());
|
|
s2_sip_free_message(bye);
|
|
|
|
bye_by_nua(d1, nh, TAG_END());
|
|
|
|
nua_handle_destroy(nh);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(SIP_CC_OE_CE_TI_008)
|
|
{
|
|
nua_handle_t *nh;
|
|
struct message *invite;
|
|
|
|
S2_CASE("6.1.2", "SIP_CC_OE_CE_TI_008",
|
|
"If an unreliable transport is used, ensure that "
|
|
"the IUT, when an INVITE client transaction is in "
|
|
"the Completed state, on receipt of final responses "
|
|
"that matches the transaction, still answer with an "
|
|
"ACK request until timer D set to at least 32 second expires.");
|
|
|
|
nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END());
|
|
|
|
invite = invite_sent_by_nua(nh, TAG_END());
|
|
|
|
s2_sip_respond_to(invite, d1, 404, "First not found", TAG_END());
|
|
fail_unless_event(nua_r_invite, 404);
|
|
fail_unless(s2_check_callstate(nua_callstate_terminated));
|
|
fail_unless(s2_sip_check_request(SIP_METHOD_ACK));
|
|
|
|
s2_nua_fast_forward(5, s2base->root);
|
|
|
|
s2_sip_respond_to(invite, d1, 404, "Not found after 5 seconds", TAG_END());
|
|
fail_unless(s2_sip_check_request(SIP_METHOD_ACK));
|
|
|
|
s2_nua_fast_forward(5, s2base->root);
|
|
|
|
s2_sip_respond_to(invite, d1, 404, "Not found after 10 seconds", TAG_END());
|
|
fail_unless(s2_sip_check_request(SIP_METHOD_ACK));
|
|
|
|
s2_nua_fast_forward(21, s2base->root);
|
|
|
|
s2_sip_respond_to(invite, d1, 404, "Not found after 31 seconds", TAG_END());
|
|
fail_unless(s2_sip_check_request(SIP_METHOD_ACK));
|
|
|
|
s2_nua_fast_forward(5, s2base->root);
|
|
|
|
/* Wake up nua thread and let it time out INVITE transaction */
|
|
nua_set_params(s2->nua, TAG_END());
|
|
fail_unless_event(nua_r_set_params, 0);
|
|
|
|
s2_sip_respond_to(invite, d1, 404, "Not found after 32 seconds", TAG_END());
|
|
s2_sip_free_message(invite);
|
|
fail_if(s2_sip_check_request_timeout(SIP_METHOD_ACK, 3));
|
|
|
|
nua_handle_destroy(nh);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(SIP_CC_OE_CE_TI_011_012)
|
|
{
|
|
nua_handle_t *nh;
|
|
struct message *invite;
|
|
|
|
S2_CASE("6.1.2", "SIP_CC_OE_CE_TI_011_012",
|
|
"Ensure that the IUT, when an INVITE client transaction "
|
|
"has been in the Terminated state, on receipt of a "
|
|
"retransmitted Success (200 OK) responses sends an ACK "
|
|
"request until 64*T1 duration expires, after this, "
|
|
"on receipt of a retransmitted Success (200 OK) "
|
|
"responses does not send an ACK request.");
|
|
|
|
nh = nua_handle(nua, NULL, SIPTAG_TO(s2sip->aor), TAG_END());
|
|
|
|
invite = invite_sent_by_nua(nh, TAG_END());
|
|
|
|
process_offer(invite);
|
|
|
|
respond_with_sdp(invite, d1, SIP_200_OK, TAG_END());
|
|
|
|
fail_unless_event(nua_r_invite, 200);
|
|
fail_unless(s2_check_callstate(nua_callstate_ready));
|
|
fail_unless(s2_sip_check_request(SIP_METHOD_ACK));
|
|
|
|
s2_nua_fast_forward(5, s2base->root);
|
|
respond_with_sdp(invite, d1, SIP_200_OK, TAG_END());
|
|
fail_unless(s2_sip_check_request(SIP_METHOD_ACK));
|
|
|
|
s2_nua_fast_forward(5, s2base->root);
|
|
respond_with_sdp(invite, d1, SIP_200_OK, TAG_END());
|
|
fail_unless(s2_sip_check_request(SIP_METHOD_ACK));
|
|
|
|
s2_nua_fast_forward(20, s2base->root);
|
|
respond_with_sdp(invite, d1, SIP_200_OK, TAG_END());
|
|
fail_unless(s2_sip_check_request(SIP_METHOD_ACK));
|
|
|
|
/* Stack times out the INVITE transaction */
|
|
s2_nua_fast_forward(5, s2base->root);
|
|
|
|
respond_with_sdp(invite, d1, SIP_200_OK,
|
|
SIPTAG_SUBJECT_STR("Stray 200 OK"),
|
|
TAG_END());
|
|
s2_sip_free_message(invite);
|
|
mark_point();
|
|
fail_if(s2_sip_check_request_timeout(SIP_METHOD_ACK, 3));
|
|
|
|
bye_by_nua(d1, nh, TAG_END());
|
|
|
|
nua_handle_destroy(nh);
|
|
}
|
|
END_TEST
|
|
|
|
TCase *sip_cc_oe_ce_tcase(int threading)
|
|
{
|
|
TCase *tc = tcase_create("6.1 - ETSI CC OE - Call Establishment");
|
|
|
|
void (*setup)(void) = threading ? etsi_thread_setup : etsi_threadless_setup;
|
|
|
|
tcase_add_checked_fixture(tc, setup, etsi_teardown);
|
|
{
|
|
tcase_add_test(tc, SIP_CC_OE_CE_V_019);
|
|
tcase_add_test(tc, SIP_CC_OE_CE_TI_008);
|
|
tcase_add_test(tc, SIP_CC_OE_CE_TI_011_012);
|
|
}
|
|
return tc;
|
|
}
|
|
|
|
/* ====================================================================== */
|
|
|
|
void check_etsi_cases(Suite *suite, int threading)
|
|
{
|
|
suite_add_tcase(suite, sip_cc_oe_ce_tcase(threading));
|
|
}
|