Commit d3d74da0 authored by Rafaël Carré's avatar Rafaël Carré
Browse files

* #6905 : simplify udp/stun/tls pjsip transport creation

parent 014cf030
......@@ -57,47 +57,29 @@ AudioRtpFactory::~AudioRtpFactory()
void AudioRtpFactory::initAudioRtpConfig ()
{
if (_rtpSession != NULL) {
_debug ("An audio rtp thread was already created but not" \
"destroyed. Forcing it before continuing.");
if (_rtpSession != NULL)
stop();
}
std::string accountId(Manager::instance().getAccountFromCall (ca_->getCallId()));
_debug ("AudioRtpFactory: Init rtp session for account %s", accountId.c_str());
// Manager::instance().getAccountLink (accountId);
Account *account = Manager::instance().getAccount (accountId);
if (!account)
_error ("AudioRtpFactory: Error no account found");
std::string accountId(Manager::instance().getAccountFromCall(ca_->getCallId()));
registerAccount(account, accountId);
}
void AudioRtpFactory::registerAccount(Account * /*account*/, const std::string & /* id */)
{
_srtpEnabled = false;
_keyExchangeProtocol = Symmetric;
_helloHashEnabled = false;
}
SIPAccount *account = dynamic_cast<SIPAccount *>(Manager::instance().getAccount (accountId));
if (account) {
_srtpEnabled = account->getSrtpEnabled();
std::string key(account->getSrtpKeyExchange());
if (key == "sdes")
_keyExchangeProtocol = Sdes;
else if (key == "zrtp")
_keyExchangeProtocol = Zrtp;
else
_keyExchangeProtocol = Symmetric;
void AudioRtpFactory::registerAccount(SIPAccount *sipaccount, const std::string& accountId)
{
_srtpEnabled = sipaccount->getSrtpEnabled();
std::string tempkey(sipaccount->getSrtpKeyExchange());
if (tempkey == "sdes")
_keyExchangeProtocol = Sdes;
else if (tempkey == "zrtp")
_keyExchangeProtocol = Zrtp;
else
_helloHashEnabled = account->getZrtpHelloHash();
} else {
_srtpEnabled = false;
_keyExchangeProtocol = Symmetric;
_debug ("AudioRtpFactory: Registered account %s profile selected with key exchange protocol number %d", accountId.c_str(), _keyExchangeProtocol);
_helloHashEnabled = sipaccount->getZrtpHelloHash();
_helloHashEnabled = false;
}
}
void AudioRtpFactory::initAudioSymmetricRtpSession ()
......@@ -113,24 +95,20 @@ void AudioRtpFactory::initAudioSymmetricRtpSession ()
case Zrtp:
_rtpSession = new AudioZrtpSession (ca_, zidFilename);
if (_helloHashEnabled) {
// TODO: be careful with that. The hello hash is computed asynchronously. Maybe it's
// not even available at that point.
ca_->getLocalSDP()->setZrtpHash (static_cast<AudioZrtpSession *> (_rtpSession)->getHelloHash());
_debug ("AudioRtpFactory: Zrtp hello hash fed to SDP");
}
break;
case Sdes:
_rtpSession = new AudioSrtpSession (ca_);
break;
default:
_debug ("AudioRtpFactory: Unsupported Rtp Session Exception Type!");
throw UnsupportedRtpSessionType();
throw UnsupportedRtpSessionType("Unsupported Rtp Session Exception Type!");
}
} else {
_rtpSession = new AudioSymmetricRtpSession (ca_);
......
......@@ -152,8 +152,6 @@ class AudioRtpFactory
void sendDtmfDigit (int digit);
private:
void registerAccount(Account *account, const std::string &id);
void registerAccount(SIPAccount *account, const std::string &id);
AudioRtpSession *_rtpSession;
ost::Mutex _audioRtpThreadMutex;
......
......@@ -165,10 +165,9 @@ IAXVoIPLink::terminateIAXCall()
void
IAXVoIPLink::getEvent()
{
iax_event* event = NULL;
{
ost::MutexLock m(mutexIAX_);
iax_event *event;
while ((event = iax_get_event (IAX_NONBLOCKING)) != NULL) {
// If we received an 'ACK', libiax2 tells apps to ignore them.
if (event->etype == IAX_EVENT_NULL)
......@@ -263,8 +262,6 @@ IAXVoIPLink::getIAXCall (const std::string& id)
void
IAXVoIPLink::sendRegister (Account *a)
{
_debug ("IAX: Sending registration");
IAXAccount *account = dynamic_cast<IAXAccount*>(a);
if (account->getHostname().empty())
......@@ -273,43 +270,28 @@ IAXVoIPLink::sendRegister (Account *a)
if (account->getUsername().empty())
throw VoipLinkException("Account username is empty");
// lock
ost::MutexLock m(mutexIAX_);
// Always use a brand new session
if (regSession_)
iax_destroy(regSession_);
regSession_ = iax_session_new();
if (!regSession_)
_debug ("IAX: Error when generating new session for register");
else {
_debug ("IAX: Sending registration to %s with user %s", account->getHostname().c_str() , account->getUsername().c_str());
int val = iax_register (regSession_, account->getHostname().data(), account->getUsername().data(), account->getPassword().data(), 120);
_debug ("IAX: Return value: %d", val);
// set the time-out to 15 seconds, after that, resend a registration request.
// until we unregister.
if (regSession_) {
iax_register (regSession_, account->getHostname().data(), account->getUsername().data(), account->getPassword().data(), 120);
nextRefreshStamp_ = time (NULL) + 10;
account->setRegistrationState (Trying);
account->setRegistrationState(Trying);
}
}
void
IAXVoIPLink::sendUnregister (Account *a)
{
_debug ("IAXVoipLink: Send unregister");
{
ost::MutexLock m(mutexIAX_);
if (regSession_) {
iax_destroy (regSession_);
regSession_ = NULL;
}
}
mutexIAX_.leaveMutex();
ost::MutexLock m(mutexIAX_);
if (regSession_) {
iax_destroy (regSession_);
regSession_ = NULL;
}
nextRefreshStamp_ = 0;
......
......@@ -2755,10 +2755,6 @@ void ManagerImpl::loadAccountMap(Conf::YamlParser *parser)
// IP to IP settings (most likely using port 5060)
link->createDefaultSipUdpTransport();
// Call this method to create TLS listener
link->createDefaultSipTlsListener();
// Force IP2IP settings to be loaded to be loaded
// No registration in the sense of the REGISTER method is performed.
ip2ip->registerVoIPLink();
......
......@@ -535,7 +535,7 @@ void SIPAccount::registerVoIPLink()
return;
try {
link_->sendRegister (this);
link_->sendRegister(this);
}
catch (const VoipLinkException &e) {
_error("SIPAccount: %s", e.what());
......
......@@ -57,7 +57,6 @@
#include "pjsip/sip_endpoint.h"
#include "pjsip/sip_transport_tls.h"
#include "pjsip/sip_transport_tls.h"
#include "pjsip/sip_uri.h"
#include <pjnath.h>
......@@ -80,9 +79,6 @@ namespace {
/** The default transport (5060) */
static pjsip_transport *_localUDPTransport = NULL;
/** The local tls listener */
static pjsip_tpfactory *_localTlsListener = NULL;
/** A map to retreive SFLphone internal call id
* Given a SIP call ID (usefull for transaction sucha as transfer)*/
static std::map<std::string, std::string> transferCallID;
......@@ -138,6 +134,33 @@ std::string loadSIPLocalIP()
return pj_inet_ntoa (ip_addr.ipv4.sin_addr);
return "";
}
pjsip_route_hdr *createRouteSet(const std::string &route, pj_pool_t *hdr_pool)
{
int port = 0;
std::string host;
size_t found = route.find(":");
if (found != std::string::npos) {
host = route.substr(0, found);
port = atoi(route.substr(found + 1, route.length()).c_str());
}
else {
host = route;
}
pjsip_route_hdr *route_set = pjsip_route_hdr_create (hdr_pool);
pjsip_route_hdr *routing = pjsip_route_hdr_create (hdr_pool);
pjsip_sip_uri *url = pjsip_sip_uri_create (hdr_pool, 0);
routing->name_addr.uri = (pjsip_uri*) url;
pj_strdup2(hdr_pool, &url->host, host.c_str());
url->port = port;
pj_list_push_back(route_set, pjsip_hdr_clone (hdr_pool, routing));
return route_set;
}
} // end anonymous namespace
/*************************************************************************************************/
......@@ -251,26 +274,34 @@ SIPVoIPLink::getEvent()
pj_time_val timeout = {0, 10};
pjsip_endpt_handle_events(_endpt, &timeout);
}
void SIPVoIPLink::sendRegister (Account *a)
{
SIPAccount *account = static_cast<SIPAccount*>(a);
acquireTransport(account);
if (account->transport)
pjsip_transport_dec_ref(account->transport);
ost::MutexLock m(mutexSIP_);
createSipTransport(account);
if (account->transport)
return;
pjsip_regc *regc = account->getRegistrationInfo();
account->setRegister(true);
// Could not create new transport, this transport may already exists
account->transport = transportMap_[account->getLocalPort()];
if (account->transport) {
pjsip_transport_add_ref(account->transport);
} else {
account->transport = _localUDPTransport;
account->setLocalPort(_localUDPTransport->local_name.port);
}
int expire_value = atoi(account->getRegistrationExpire().c_str());
if (!expire_value)
expire_value = PJSIP_REGC_EXPIRATION_NOT_SPECIFIED;
ost::MutexLock m(mutexSIP_);
account->setRegister(true);
account->setRegistrationState (Trying);
pjsip_regc *regc = account->getRegistrationInfo();
if (pjsip_regc_create(_endpt, (void *) account, &registration_cb, &regc) != PJ_SUCCESS)
throw VoipLinkException("UserAgent: Unable to create regc structure.");
......@@ -285,55 +316,49 @@ void SIPVoIPLink::sendRegister (Account *a)
pj_str_t pjContact = pj_str((char*)contact.c_str());
pj_str_t pjSrv = pj_str((char*)srvUri.c_str());
int expire_value = atoi(account->getRegistrationExpire().c_str());
if (!expire_value)
expire_value = PJSIP_REGC_EXPIRATION_NOT_SPECIFIED;
if (pjsip_regc_init (regc, &pjSrv, &pjFrom, &pjFrom, 1, &pjContact, expire_value) != PJ_SUCCESS)
throw VoipLinkException("Unable to initialize account registration structure");
if (!account->getServiceRoute().empty()) {
pjsip_route_hdr *route_set = createRouteSet(account, _pool);
pjsip_regc_set_route_set (regc, route_set);
}
if (!account->getServiceRoute().empty())
pjsip_regc_set_route_set (regc, createRouteSet(account->getServiceRoute(), _pool));
pjsip_regc_set_credentials (regc, account->getCredentialCount(), account->getCredInfo());
unsigned count = account->getCredentialCount();
pjsip_cred_info *info = account->getCredInfo();
pjsip_regc_set_credentials (regc, count, info);
// Add User-Agent Header
pjsip_hdr hdr_list;
pj_list_init (&hdr_list);
pj_str_t useragent = pj_str ((char*)account->getUserAgentName().c_str());
std::string useragent(account->getUserAgentName());
pj_str_t pJuseragent = pj_str ((char*)useragent.c_str());
const pj_str_t STR_USER_AGENT = { (char*) "User-Agent", 10 };
pjsip_generic_string_hdr *h = pjsip_generic_string_hdr_create (_pool, &STR_USER_AGENT, &useragent);
pjsip_generic_string_hdr *h = pjsip_generic_string_hdr_create(_pool, &STR_USER_AGENT, &pJuseragent);
pj_list_push_back (&hdr_list, (pjsip_hdr*) h);
pjsip_regc_add_headers (regc, &hdr_list);
pjsip_tx_data *tdata;
if (pjsip_regc_register (regc, PJ_TRUE, &tdata) != PJ_SUCCESS)
throw VoipLinkException("Unable to initialize transaction data for account registration");
pjsip_tpselector *tp = initTransportSelector (account->transport, _pool);
pj_status_t status = pjsip_regc_set_transport (regc, tp);
if (pjsip_regc_set_transport (regc, initTransportSelector (account->transport, _pool)) != PJ_SUCCESS)
throw VoipLinkException("Unable to set transport");
// decrease transport's ref count, counter incrementation is managed when acquiring transport
if (account->transport)
pjsip_transport_dec_ref(account->transport);
if (status != PJ_SUCCESS)
throw VoipLinkException("Unable to set transport");
pjsip_transport_dec_ref(account->transport);
// pjsip_regc_send increment the transport ref count by one,
status = pjsip_regc_send(regc, tdata);
if (pjsip_regc_send(regc, tdata) != PJ_SUCCESS)
throw VoipLinkException("Unable to send account registration request");
// Decrease transport's ref count, since coresponding reference counter decrementation
// is performed in pjsip_regc_destroy. This function is never called in SFLphone as the
// regc data structure is permanently associated to the account at first registration.
if (account->transport)
pjsip_transport_dec_ref (account->transport);
if (status != PJ_SUCCESS)
throw VoipLinkException("Unable to send account registration request");
pjsip_transport_dec_ref (account->transport);
account->setRegistrationInfo (regc);
}
......@@ -342,15 +367,6 @@ void SIPVoIPLink::sendUnregister (Account *a)
{
SIPAccount *account = dynamic_cast<SIPAccount *>(a);
// If an transport is attached to this account, detach it and decrease reference counter
if (account->transport) {
_debug ("Sent account unregistration using transport: %s %s (refcnt=%d)",
account->transport->obj_name,
account->transport->info,
(int) pj_atomic_get (account->transport->ref_cnt));
}
// This may occurs if account failed to register and is in state INVALID
if (!account->isRegister()) {
account->setRegistrationState (Unregistered);
......@@ -373,19 +389,11 @@ void SIPVoIPLink::sendUnregister (Account *a)
Call *SIPVoIPLink::newOutgoingCall (const std::string& id, const std::string& toUrl)
{
// Create a new SIP call
SIPCall* call = new SIPCall (id, Call::Outgoing, _cp);
// Find the account associated to this call
SIPAccount *account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount (Manager::instance().getAccountFromCall (id)));
if (account == NULL) {
_error ("UserAgent: Error: Could not retrieving account to make call with");
call->setConnectionState (Call::Disconnected);
call->setState (Call::Error);
delete call;
// TODO: We should investigate how we could get rid of this error and create a IP2IP call instead
if (account == NULL) // TODO: We should investigate how we could get rid of this error and create a IP2IP call instead
throw VoipLinkException("Could not get account for this call");
}
SIPCall* call = new SIPCall (id, Call::Outgoing, _cp);
// If toUri is not a well formated sip URI, use account information to process it
std::string toUri;
......@@ -393,13 +401,10 @@ Call *SIPVoIPLink::newOutgoingCall (const std::string& id, const std::string& to
toUrl.find("sips:") != std::string::npos)
toUri = toUrl;
else
toUri = account->getToUri (toUrl);
toUri = account->getToUri(toUrl);
call->setPeerNumber (toUri);
_debug ("UserAgent: New outgoing call %s to %s", id.c_str(), toUri.c_str());
std::string localAddr(getInterfaceAddrFromName (account->getLocalInterface ()));
_debug ("UserAgent: Local address for thi call: %s", localAddr.c_str());
if (localAddr == "0.0.0.0")
localAddr = loadSIPLocalIP();
......@@ -419,27 +424,22 @@ Call *SIPVoIPLink::newOutgoingCall (const std::string& id, const std::string& to
// the session initialization is completed
sfl::Codec* audiocodec = Manager::instance().audioCodecFactory.instantiateCodec (PAYLOAD_CODEC_ULAW);
if (audiocodec == NULL) {
_error ("UserAgent: Could not instantiate codec");
delete call;
throw VoipLinkException ("Could not instantiate codec for early media");
}
try {
_info ("UserAgent: Creating new rtp session");
call->getAudioRtp()->initAudioRtpConfig ();
call->getAudioRtp()->initAudioSymmetricRtpSession ();
call->getAudioRtp()->initLocalCryptoInfo ();
_info ("UserAgent: Start audio rtp session");
call->getAudioRtp()->start (static_cast<sfl::AudioCodec *>(audiocodec));
} catch (...) {
delete call;
throw VoipLinkException ("Could not start rtp session for early media");
}
// init file name according to peer phone number
call->initRecFileName (toUrl);
call->initRecFileName(toUrl);
// Building the local SDP offer
call->getLocalSDP()->setLocalIP (addrSdp);
call->getLocalSDP()->createOffer(account->getActiveCodecs());
......@@ -454,25 +454,19 @@ Call *SIPVoIPLink::newOutgoingCall (const std::string& id, const std::string& to
void
SIPVoIPLink::answer (Call *c)
{
pjsip_tx_data *tdata;
_debug ("UserAgent: Answering call");
SIPCall *call = dynamic_cast<SIPCall*>(c);
if (call != NULL) {
pjsip_inv_session *inv_session = call->inv;
if (!call)
return;
_debug ("UserAgent: SDP negotiation success! : call %s ", call->getCallId().c_str());
// Create and send a 200(OK) response
if (pjsip_inv_answer (inv_session, PJSIP_SC_OK, NULL, NULL, &tdata) != PJ_SUCCESS)
throw VoipLinkException("Could not init invite request answer (200 OK)");
if (pjsip_inv_send_msg (inv_session, tdata) != PJ_SUCCESS)
throw VoipLinkException("Could not send invite request answer (200 OK)");
pjsip_tx_data *tdata;
if (pjsip_inv_answer (call->inv, PJSIP_SC_OK, NULL, NULL, &tdata) != PJ_SUCCESS)
throw VoipLinkException("Could not init invite request answer (200 OK)");
call->setConnectionState (Call::Connected);
call->setState (Call::Active);
}
if (pjsip_inv_send_msg (call->inv, tdata) != PJ_SUCCESS)
throw VoipLinkException("Could not send invite request answer (200 OK)");
call->setConnectionState (Call::Connected);
call->setState (Call::Active);
}
void
......@@ -491,7 +485,7 @@ SIPVoIPLink::hangup (const std::string& id)
// Looks for sip routes
if (not (account->getServiceRoute().empty())) {
pjsip_route_hdr *route_set = createRouteSet(account, inv->pool);
pjsip_route_hdr *route_set = createRouteSet(account->getServiceRoute(), inv->pool);
pjsip_dlg_set_route_set (inv->dlg, route_set);
}
......@@ -562,18 +556,10 @@ SIPVoIPLink::offhold (const std::string& id)
throw VoipLinkException("Could not find sdp session");
try {
// Retreive previously selected codec
int pl;
int pl = PAYLOAD_CODEC_ULAW;
sfl::Codec *sessionMedia = sdpSession->getSessionMedia();
if (sessionMedia == NULL) {
_warn("UserAgent: Session media not yet initialized, using default (ULAW)");
pl = PAYLOAD_CODEC_ULAW;
}
else
pl = (int) sessionMedia->getPayloadType();
_debug ("UserAgent: Payload from session media %d", pl);
if (sessionMedia)
pl = sessionMedia->getPayloadType();
// Create a new instance for this codec
sfl::Codec* audiocodec = Manager::instance().audioCodecFactory.instantiateCodec (pl);
......@@ -740,14 +726,11 @@ bool
SIPVoIPLink::refuse (const std::string& id)
{
SIPCall *call = getSIPCall (id);
// can't refuse outgoing call or connected
if (!call->isIncoming() or call->getConnectionState() == Call::Connected)
return false;
call->getAudioRtp()->stop();
// User refuse current call. Notify peer
pjsip_tx_data *tdata;
if (pjsip_inv_end_session (call->inv, PJSIP_SC_DECLINE, NULL, &tdata) != PJ_SUCCESS)
return false;
......@@ -835,6 +818,9 @@ SIPVoIPLink::SIPStartCall(SIPCall *call)
pj_str_t pjContact = pj_str((char*)contact.c_str());
pj_str_t pjTo = pj_str((char*)toUri.c_str());
pjsip_dialog *dialog;
if (pjsip_dlg_create_uac (pjsip_ua_instance(), &pjFrom, &pjContact, &pjTo, NULL, &dialog) != PJ_SUCCESS)
return false;
......@@ -843,7 +829,7 @@ SIPVoIPLink::SIPStartCall(SIPCall *call)
return false;
if (not account->getServiceRoute().empty())
pjsip_dlg_set_route_set(dialog, createRouteSet(account, call->inv->pool));
pjsip_dlg_set_route_set(dialog, createRouteSet(account->getServiceRoute(), call->inv->pool));
pjsip_auth_clt_set_credentials (&dialog->auth_sess, account->getCredentialCount(), account->getCredInfo());
......@@ -902,7 +888,7 @@ SIPCall*
SIPVoIPLink::getSIPCall (const std::string& id)
{
SIPCall *result = dynamic_cast<SIPCall*> (getCall (id));
if (result == 0)
if (result == NULL)
throw VoipLinkException("Could not find SIPCall " + id);
return result;
}
......@@ -951,15 +937,13 @@ bool SIPVoIPLink::SIPNewIpToIpCall (const std::string& id, const std::string& to
return false;
}
if (createTlsTransport (account, remoteAddr) != PJ_SUCCESS) {
createTlsTransport(account, remoteAddr);
if (!account->transport) {
delete call;
return false;
}
}
if (account->transport == NULL)
account->transport = _localUDPTransport;
if (!SIPStartCall(call)) {
delete call;
return false;
......@@ -986,11 +970,10 @@ static pj_bool_t stun_sock_on_rx_data_cb (pj_stun_sock *stun_sock UNUSED, void *
pj_status_t SIPVoIPLink::stunServerResolve (SIPAccount *account)
{
// Initialize STUN configuration
pj_stun_config stunCfg;
pj_stun_config_init (&stunCfg, &_cp->factory, 0, pjsip_endpt_get_ioqueue (_endpt), pjsip_endpt_get_timer_heap (_endpt));
const pj_stun_sock_cb stun_sock_cb = {
static const pj_stun_sock_cb stun_sock_cb = {
stun_sock_on_rx_data_cb,
NULL,
stun_sock_on_status_cb
......@@ -1019,46 +1002,17 @@ pj_status_t SIPVoIPLink::stunServerResolve (SIPAccount *account)
return status;
}
void SIPVoIPLink::acquireTransport (SIPAccount *account)
{
if (account->transport)
pjsip_transport_dec_ref(account->transport);
if (createSipTransport(account))
return;
// Could not create new transport, this transport may already exists
account->transport = transportMap_[account->getLocalPort()];
if (account->transport) {
pjsip_transport_add_ref(account->transport);
} else {
account->transport = _localUDPTransport;
account->setLocalPort(_localUDPTransport->local_name.port);
}
}
void SIPVoIPLink::createDefaultSipUdpTransport()
{
SIPAccount *account = dynamic_cast<SIPAccount *>(Manager::instance().getAccount(IP2IP_PROFILE));
pjsip_transport *transport = createUdpTransport(account, true);
if (transport) {
transportMap_[account->getLocalPort()] = transport;
_localUDPTransport = transport;
account->transport = transport;