-
Guillaume Roguez authored
* refactor the code in modern C++11 * make a better call test by ensuring that the call is in correct state at each step. Change-Id: I3e17ee59acbf4a5a61783b2bf87eb4914faef65e Reviewed-by:
Anthony Léonard <anthony.leonard@savoirfairelinux.com>
Guillaume Roguez authored* refactor the code in modern C++11 * make a better call test by ensuring that the call is in correct state at each step. Change-Id: I3e17ee59acbf4a5a61783b2bf87eb4914faef65e Reviewed-by:
Anthony Léonard <anthony.leonard@savoirfairelinux.com>
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
test_SIP.cpp 12.95 KiB
/*
* Copyright (C) 2004-2017 Savoir-Faire Linux Inc.
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
* Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <fstream>
#include <pthread.h>
#include <string>
#include <thread>
#include "test_SIP.h"
#include "call_const.h"
using namespace ring;
static pthread_mutex_t count_mutex;
static pthread_cond_t count_nb_thread;
static int counter = 0;
CPPUNIT_TEST_SUITE_REGISTRATION( test_SIP );
/*
return an error if all call are not successful
*/
void*
sippThreadWithCount(void* str)
{
// number of time we use the mutex. Lock the utilisation of counter
pthread_mutex_lock(&count_mutex);
counter++;
pthread_mutex_unlock(&count_mutex);
// display what is send on the parameter of the method
std::string *command = (std::string *)(str);
std::cout << "test_SIP: " << command << std::endl;
// Set up the sipp instance in this thread in order to catch return value
// 0: All calls were successful
// 1: At least one call failed
// 97: exit on internal command. Calls may have been processed
// 99: Normal exit without calls processed
// -1: Fatal error
// -2: Fatal error binding a socket
int i = system(command->c_str()); //c_str() retrieve the *char of the string
CPPUNIT_ASSERT(i);
pthread_mutex_lock(&count_mutex);
counter--;
// ???
if (counter == 0)
pthread_cond_signal(&count_nb_thread);
pthread_mutex_unlock(&count_mutex);
pthread_exit(NULL);
}
RAIIThread
sippThread(const std::string& command)
{
return std::thread([command] {
std::cout << "test_SIP: " << command << std::endl;
// Set up the sipp instance in this thread in order to catch return value
// 0: All calls were successful
// 1: At least one call failed
// 97: exit on internal command. Calls may have been processed
// 99: Normal exit without calls processed
// -1: Fatal error
// -2: Fatal error binding a socket
auto ret = system(command.c_str());
std::cout << "test_SIP: Command executed by system returned: " << ret << std::endl;
});
}
void
test_SIP::setUp()
{
std::cout << "setup test SIP" << std::endl;
pthread_mutex_lock(&count_mutex);
counter = 0;
pthread_mutex_unlock(&count_mutex);
running_ = true;
eventLoop_ = RAIIThread(std::thread([this]{
while (running_) {
Manager::instance().pollEvents();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}));
}
void
test_SIP::tearDown()
{
running_ = false;
eventLoop_.join();
// in order to stop any currently running threads
std::cout << "test_SIP: Clean all remaining sipp instances" << std::endl;
int ret = system("killall sipp");
if (ret)
std::cout << "test_SIP: Error from system call, killall sipp"
<< ", ret=" << ret
<< '\n';
}
void
test_SIP::testSimpleOutgoingIpCall()
{
// start a user agent server waiting for a call
auto t = sippThread("sipp -sn uas -i 127.0.0.1 -p 5068 -m 1 -bg");
std::string testaccount("IP2IP");
std::string testcallnumber("sip:test@127.0.0.1:5068");
std::string testcallid; // returned by outgoingCall()
CPPUNIT_ASSERT(!Manager::instance().hasCurrentCall());
// start a new call sending INVITE message to sipp instance
testcallid = Manager::instance().outgoingCall(testaccount, testcallnumber);
// wait for receiving 180 and 200 message from peer
std::this_thread::sleep_for(std::chrono::seconds(2)); // should be enough
auto call = Manager::instance().getCallFromCallID(testcallid);
CPPUNIT_ASSERT(call);
// check call state
auto state = call->getStateStr();
std::cout << ">>>> call state is now " << state << '\n';
CPPUNIT_ASSERT(state == DRing::Call::StateEvent::CURRENT);
Manager::instance().hangupCall(testcallid);
// check call state
state = call->getStateStr();
std::cout << ">>>> call state is now " << state << '\n';
CPPUNIT_ASSERT(state == DRing::Call::StateEvent::OVER);
// Call must not not be available (except for thus how already own a pointer like us)
CPPUNIT_ASSERT(not Manager::instance().getCallFromCallID(testcallid));
}
#if 0
void test_SIP::testSimpleIncomingIpCall()
{
pthread_t thethread;
// command to be executed by the thread, user agent client which initiate a call and hangup
std::string command("sipp -sn uac 127.0.0.1 -i 127.0.0.1 -p 5062 -m 1i -bg");
int rc = pthread_create(&thethread, NULL, sippThread, &command);
if (rc)
std::cout << "test_SIP: ERROR; return code from pthread_create()" << std::endl;
// sleep a while to make sure that sipp insdtance is initialized and sflphoned received
// the incoming invite.
sleep(2);
// gtrab call id from sipvoiplink
SIPVoIPLink& siplink = SIPVoIPLink::instance();
CPPUNIT_ASSERT(siplink.sipCallMap_.size() == 1);
SipCallMap::iterator iterCallId = siplink.sipCallMap_.begin();
std::string testcallid = iterCallId->first;
// Answer this call
CPPUNIT_ASSERT(Manager::instance().answerCall(testcallid));
sleep(1);
rc = pthread_join(thethread, NULL);
if (rc)
std::cout << "test_SIP: ERROR; return code from pthread_join(): " << rc << std::endl;
else
std::cout << "test_SIP: completed join with thread" << std::endl;
}
#endif
void
test_SIP::testTwoOutgoingIpCall()
{
// This scenario expect to be put on hold before hangup
auto firstCallThread = sippThread("sipp -sf tools/sippxml/test_1.xml -i 127.0.0.1 -p 5062 -m 1");
// The second call uses the default user agent scenario
auto secondCallThread = sippThread("sipp -sn uas -i 127.0.0.1 -p 5064 -m 1");
sleep(1);
auto testAccount = "IP2IP";
auto firstCallNumber = "sip:test@127.0.0.1:5062";
auto secondCallNumber = "sip:test@127.0.0.1:5064";
CPPUNIT_ASSERT(!Manager::instance().hasCurrentCall());
// start a new call sending INVITE message to sipp instance
// this call should be put on hold when making the second call
auto firstCallId = Manager::instance().outgoingCall(testAccount, firstCallNumber);
// must sleep here until receiving 180 and 200 message from peer
sleep(1);
auto secondCallId = Manager::instance().outgoingCall(testAccount, secondCallNumber);
sleep(1);
Manager::instance().hangupCall(firstCallId);
Manager::instance().hangupCall(secondCallId);
}
#if 0
void test_SIP::testTwoIncomingIpCall()
{
pthread_mutex_init(&count_mutex, NULL);
pthread_cond_init(&count_nb_thread, NULL);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
// the first call is supposed to be put on hold when answering teh second incoming call
std::string firstCallCommand("sipp -sf tools/sippxml/test_2.xml 127.0.0.1 -i 127.0.0.1 -p 5064 -m 1 > testfile1.txt -bg");
// command to be executed by the thread, user agent client which initiate a call and hangup
std::string secondCallCommand("sipp -sn uac 127.0.0.1 -i 127.0.0.1 -p 5062 -m 1 -d 250 > testfile2.txt -bg");
pthread_t firstCallThread;
int rc = pthread_create(&firstCallThread, &attr, sippThreadWithCount, &firstCallCommand);
if (rc)
std::cout << "test_SIP: ERROR; return code from pthread_create()" << std::endl;
// sleep a while to make sure that sipp insdtance is initialized and sflphoned received
// the incoming invite.
sleep(1);
// gtrab call id from sipvoiplink
SIPVoIPLink& sipLink = SIPVoIPLink::instance();
CPPUNIT_ASSERT(sipLink.sipCallMap_.size() == 1);
SipCallMap::iterator iterCallId = sipLink.sipCallMap_.begin();
std::string firstCallID = iterCallId->first;
// Answer this call
CPPUNIT_ASSERT(Manager::instance().answerCall(firstCallID));
sleep(1);
pthread_t secondCallThread;
rc = pthread_create(&secondCallThread, &attr, sippThread, &secondCallCommand);
if (rc)
std::cout << "test_SIP: Error; return code from pthread_create()" << std::endl;
sleep(1);
CPPUNIT_ASSERT(sipLink.sipCallMap_.size() == 2);
iterCallId = sipLink.sipCallMap_.begin();
if (iterCallId->first == firstCallID)
++iterCallId;
std::string secondCallID(iterCallId->first);
CPPUNIT_ASSERT(Manager::instance().answerCall(secondCallID));
sleep(2);
pthread_mutex_lock(&count_mutex);
while (counter > 0)
pthread_cond_wait(&count_nb_thread, &count_mutex);
pthread_mutex_unlock(&count_mutex);
pthread_mutex_destroy(&count_mutex);
pthread_cond_destroy(&count_nb_thread);
}
#endif
void
test_SIP::testHoldIpCall()
{
auto testAccount = "IP2IP";
auto testCallNumber = "sip:test@127.0.0.1:5062";
auto callThread = sippThread("sipp -sf tools/sippxml/test_3.xml -i 127.0.0.1 -p 5062 -m 1 -bg");
auto testCallId = Manager::instance().outgoingCall(testAccount, testCallNumber);
sleep(1);
Manager::instance().onHoldCall(testCallId);
sleep(1);
Manager::instance().offHoldCall(testCallId);
sleep(1);
Manager::instance().hangupCall(testCallId);
}
#if 0
void test_SIP::testSIPURI()
{
std::string foo("<sip:17771234567@callcentric.com>");
sip_utils::stripSipUriPrefix(foo);
CPPUNIT_ASSERT(foo == "17771234567");
}
#endif
#if 0
void test_SIP::testParseDisplayName()
{
// 1st element is input, 2nd is expected output
const char *test_set[][2] = {
{"\nFrom: \"A. G. Bell\" <sip:agb@bell-telephone.com> ;tag=a48s", "A. G. Bell"},
{"\nFrom: \"A. G. Bell2\" <sip:agb@bell-telephone.com> ;tag=a48s\r\nOtherLine: \"bla\"\r\n", "A. G. Bell2"},
{"\nf: Anonymous <sip:c8oqz84zk7z@privacy.org>;tag=hyh8", "Anonymous"},
{"\nFrom: \"Alejandro Perez\" <sip:1111@10.0.0.1>;tag=3a7516a63bdbo0", "Alejandro Perez"},
{"\nFrom: \"Malformed <sip:1111@10.0.0.1>;tag=3a6a63bdbo0", ""},
{"\nTo: <sip:1955@10.0.0.1>;tag=as6fbade41", ""},
{"\nFrom: \"1000\" <sip:1000@sip.example.es>;tag=as775338f3", "1000"},
{"\nFrom: 1111_9532323 <sip:1111_9532323@sip.example.es>;tag=caa3a61", "1111_9532323"},
{"\nFrom: \"4444_953111111\" <sip:4444_111111@sip.example.es>;tag=2b00632co0", "4444_953111111"},
{"\nFrom: <sip:6926666@4.4.4.4>;tag=4421-D9700", ""},
{"\nFrom: <sip:pinger@sipwise.local>;tag=01f516a4", ""},
{"\nFrom: sip:pinger@sipwise.local;tag=01f516a4", ""},
{"\nFrom: ", ""},
{"\nFrom: \"\xb1""Alejandro P\xc3\xa9rez\" <sip:1111@10.0.0.1>;tag=3a7516a63bdbo0", "\xef\xbf\xbd""Alejandro P\xc3\xa9rez"},
{"\nFrom: \"Alejandro P\xc3\xa9rez\" <sip:1111@10.0.0.1>;tag=3a7516a63bdbo0", "Alejandro P\xc3\xa9rez"},
{"\nFrom: sip:+1212555@server.example.com;tag=887s", ""}};
for (const auto &t : test_set) {
const std::string str(sip_utils::parseDisplayName(t[0]));
CPPUNIT_ASSERT_MESSAGE(std::string("\"") + str + "\" should be \"" +
t[1] + "\", input on next line: " + t[0],
str == t[1]);
}
}
#endif
#if 0
void test_SIP::testIncomingIpCallSdp()
{
// command to be executed by the thread, user agent client which initiate a call and hangup
std::string command("sipp -sf tools/sippxml/test_4.xml 127.0.0.1 -i 127.0.0.1 -p 5062 -m 1i -bg");
pthread_t thethread;
int rc = pthread_create(&thethread, NULL, sippThread, (void *)(&command));
if (rc)
std::cout << "test_SIP: ERROR; return code from pthread_create()" << std::endl;
// sleep a while to make sure that sipp insdtance is initialized and sflphoned received
// the incoming invite.
sleep(2);
// gtrab call id from sipvoiplink
SIPVoIPLink& siplink = SIPVoIPLink::instance();
CPPUNIT_ASSERT(siplink.sipCallMap_.size() == 1);
SipCallMap::iterator iterCallId = siplink.sipCallMap_.begin();
std::string testcallid = iterCallId->first;
// TODO: hmmm, should IP2IP call be stored in call list....
CPPUNIT_ASSERT(Manager::instance().getCallList().empty());
// Answer this call
CPPUNIT_ASSERT(Manager::instance().answerCall(testcallid));
sleep(1);
rc = pthread_join(thethread, NULL);
if (rc)
std::cout << "test_SIP: ERROR; return code from pthread_join(): " << rc << std::endl;
else
std::cout << "test_SIP: completed join with thread" << std::endl;
}
#endif