Commit 6f3bffff authored by Alexandre Savard's avatar Alexandre Savard

#9547: Extract all the transport layer from SIPVoIPLink to new SipTransport Class

parent 7a58f609
......@@ -37,6 +37,7 @@
#include "config.h"
#include "../manager.h"
#include "sip/sipvoiplink.h"
#include "sip/siptransport.h"
#include "account.h"
#include "sip/sipaccount.h"
......@@ -411,17 +412,17 @@ std::vector<std::map<std::string, std::string> > ConfigurationManager::getHistor
std::string
ConfigurationManager::getAddrFromInterfaceName(const std::string& interface)
{
return SIPVoIPLink::getInterfaceAddrFromName(interface);
return SipTransport::getInterfaceAddrFromName(interface);
}
std::vector<std::string> ConfigurationManager::getAllIpInterface()
{
return SIPVoIPLink::getAllIpInterface();
return SipTransport::getAllIpInterface();
}
std::vector<std::string> ConfigurationManager::getAllIpInterfaceByName()
{
return SIPVoIPLink::getAllIpInterfaceByName();
return SipTransport::getAllIpInterfaceByName();
}
std::map<std::string, std::string> ConfigurationManager::getShortcuts()
......
......@@ -2563,7 +2563,7 @@ void ManagerImpl::loadDefaultAccountMap()
{
// build a default IP2IP account with default parameters
accountMap_[SIPAccount::IP2IP_PROFILE] = new SIPAccount(SIPAccount::IP2IP_PROFILE);
SIPVoIPLink::instance()->createDefaultSipUdpTransport();
SIPVoIPLink::instance()->sipTransport.createDefaultSipUdpTransport();
accountMap_[SIPAccount::IP2IP_PROFILE]->registerVoIPLink();
}
......@@ -2627,7 +2627,7 @@ void ManagerImpl::loadAccountMap(Conf::YamlParser &parser)
// Initialize default UDP transport according to
// IP to IP settings (most likely using port 5060)
SIPVoIPLink::instance()->createDefaultSipUdpTransport();
SIPVoIPLink::instance()->sipTransport.createDefaultSipUdpTransport();
// Force IP2IP settings to be loaded to be loaded
// No registration in the sense of the REGISTER method is performed.
......
......@@ -9,12 +9,14 @@ libsiplink_la_SOURCES = \
sipaccount.cpp \
sipcall.cpp \
sipvoiplink.cpp \
siptransport.cpp \
pattern.h \
sdes_negotiator.h \
sdp.h \
sipaccount.h \
sipcall.h \
sipvoiplink.h \
siptransport.h \
sip_utils.cpp \
sip_utils.h
......
......@@ -407,7 +407,7 @@ void SIPAccount::setAccountDetails(std::map<std::string, std::string> details)
publishedPort_ = atoi(details[CONFIG_PUBLISHED_PORT].c_str());
if(stunServer_ != details[CONFIG_STUN_SERVER]) {
DEBUG("Stun server changed!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
link_->destroyStunResolver(stunServer_);
link_->sipTransport.destroyStunResolver(stunServer_);
// pj_stun_sock_destroy(pj_stun_sock *stun_sock);
}
stunServer_ = details[CONFIG_STUN_SERVER];
......@@ -816,7 +816,7 @@ std::string SIPAccount::getContactHeader() const
// Else we determine this infor based on transport information
std::string address, port;
link_->findLocalAddressFromTransport(transport_, transportType, address, port);
link_->sipTransport.findLocalAddressFromTransport(transport_, transportType, address, port);
// UDP does not require the transport specification
std::string scheme;
......
......@@ -76,8 +76,6 @@ using namespace sfl;
namespace {
static pjsip_transport *localUDPTransport_ = NULL; /** The default transport (5060) */
/** 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;
......@@ -121,18 +119,6 @@ int SIPSessionReinvite(SIPCall *);
*/
void onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata);
std::string getSIPLocalIP()
{
pj_sockaddr ip_addr;
if (pj_gethostip(pj_AF_INET(), &ip_addr) == PJ_SUCCESS)
return pj_inet_ntoa(ip_addr.ipv4.sin_addr);
else {
ERROR("SIPVoIPLink: Could not get local IP");
return "";
}
}
pjsip_route_hdr *createRouteSet(const std::string &route, pj_pool_t *hdr_pool)
{
int port = 0;
......@@ -309,15 +295,15 @@ pj_bool_t transaction_request_cb(pjsip_rx_data *rdata)
Manager::instance().associateCallToAccount(call->getCallId(), account_id);
// May use the published address as well
std::string addrToUse = SIPVoIPLink::instance()->getInterfaceAddrFromName(account->getLocalInterface());
std::string addrToUse = SipTransport::getInterfaceAddrFromName(account->getLocalInterface());
std::string addrSdp = account->isStunEnabled()
? account->getPublishedAddress()
: addrToUse;
pjsip_tpselector *tp = SIPVoIPLink::instance()->initTransportSelector(account->transport_, call->getMemoryPool());
pjsip_tpselector *tp = SIPVoIPLink::instance()->sipTransport.initTransportSelector(account->transport_, call->getMemoryPool());
if (addrToUse == "0.0.0.0")
addrToUse = getSIPLocalIP();
addrToUse = SipTransport::getSIPLocalIP();
if (addrSdp == "0.0.0.0")
addrSdp = addrToUse;
......@@ -427,7 +413,7 @@ pj_bool_t transaction_request_cb(pjsip_rx_data *rdata)
/*************************************************************************************************/
SIPVoIPLink::SIPVoIPLink() : transportMap_(), stunSocketMap_(), evThread_(new EventThread(this))
SIPVoIPLink::SIPVoIPLink() : sipTransport(endpt_, cp_, pool_), evThread_(new EventThread(this))
{
#define TRY(ret) do { \
if (ret != PJ_SUCCESS) \
......@@ -450,7 +436,11 @@ SIPVoIPLink::SIPVoIPLink() : transportMap_(), stunSocketMap_(), evThread_(new Ev
TRY(pjsip_endpt_create(&cp_->factory, pj_gethostname()->ptr, &endpt_));
if (getSIPLocalIP().empty())
sipTransport.setEndpoint(endpt_);
sipTransport.setCachingPool(cp_);
sipTransport.setPool(pool_);
if (SipTransport::getSIPLocalIP().empty())
throw VoipLinkException("UserAgent: Unable to determine network capabilities");
TRY(pjsip_tsx_layer_init_module(endpt_));
......@@ -540,7 +530,7 @@ SIPVoIPLink::getEvent()
void SIPVoIPLink::sendRegister(Account *a)
{
SIPAccount *account = dynamic_cast<SIPAccount*>(a);
createSipTransport(account);
sipTransport.createSipTransport(account);
account->setRegister(true);
account->setRegistrationState(Trying);
......@@ -588,7 +578,7 @@ void SIPVoIPLink::sendRegister(Account *a)
if (pjsip_regc_register(regc, PJ_TRUE, &tdata) != PJ_SUCCESS)
throw VoipLinkException("Unable to initialize transaction data for account registration");
if (pjsip_regc_set_transport(regc, initTransportSelector(account->transport_, pool_)) != PJ_SUCCESS)
if (pjsip_regc_set_transport(regc, sipTransport.initTransportSelector(account->transport_, pool_)) != PJ_SUCCESS)
throw VoipLinkException("Unable to set transport");
// decrease transport's ref count, counter incrementation is managed when acquiring transport
......@@ -683,20 +673,20 @@ Call *SIPVoIPLink::newOutgoingCall(const std::string& id, const std::string& toU
toUri = account->getToUri(toUrl);
call->setPeerNumber(toUri);
std::string localAddr(getInterfaceAddrFromName(account->getLocalInterface()));
std::string localAddr(SipTransport::getInterfaceAddrFromName(account->getLocalInterface()));
if (localAddr == "0.0.0.0")
localAddr = getSIPLocalIP();
localAddr = SipTransport::getSIPLocalIP();
setCallMediaLocal(call, localAddr);
// May use the published address as well
std::string addrSdp = account->isStunEnabled() ?
account->getPublishedAddress() :
getInterfaceAddrFromName(account->getLocalInterface());
SipTransport::getInterfaceAddrFromName(account->getLocalInterface());
if (addrSdp == "0.0.0.0")
addrSdp = getSIPLocalIP();
addrSdp = SipTransport::getSIPLocalIP();
// Initialize the session using ULAW as default codec in case of early media
// The session should be ready to receive media once the first INVITE is sent, before
......@@ -1094,7 +1084,7 @@ SIPVoIPLink::SIPStartCall(SIPCall *call)
if (pjsip_inv_invite(call->inv, &tdata) != PJ_SUCCESS)
return false;
pjsip_tpselector *tp = initTransportSelector(account->transport_, call->inv->pool);
pjsip_tpselector *tp = sipTransport.initTransportSelector(account->transport_, call->inv->pool);
if (pjsip_dlg_set_transport(dialog, tp) != PJ_SUCCESS)
return false;
......@@ -1164,10 +1154,10 @@ bool SIPVoIPLink::SIPNewIpToIpCall(const std::string& id, const std::string& to)
call->setIPToIP(true);
call->initRecFilename(to);
std::string localAddress(getInterfaceAddrFromName(account->getLocalInterface()));
std::string localAddress(SipTransport::getInterfaceAddrFromName(account->getLocalInterface()));
if (localAddress == "0.0.0.0")
localAddress = getSIPLocalIP();
localAddress = SipTransport::getSIPLocalIP();
setCallMediaLocal(call, localAddress);
......@@ -1205,8 +1195,8 @@ bool SIPVoIPLink::SIPNewIpToIpCall(const std::string& id, const std::string& to)
return false;
}
shutdownSipTransport(account);
pjsip_transport *transport = createTlsTransport(remoteAddr, account->getTlsListenerPort(),
sipTransport.shutdownSipTransport(account);
pjsip_transport *transport = sipTransport.createTlsTransport(remoteAddr, account->getTlsListenerPort(),
account->getTlsSetting());
if (transport == NULL) {
......@@ -1231,410 +1221,6 @@ bool SIPVoIPLink::SIPNewIpToIpCall(const std::string& id, const std::string& to)
// Private functions
///////////////////////////////////////////////////////////////////////////////
pj_bool_t
stun_sock_on_status_cb(pj_stun_sock * /*stun_sock*/, pj_stun_sock_op op,
pj_status_t status)
{
switch (op) {
case PJ_STUN_SOCK_DNS_OP:
DEBUG("UserAgent: Stun operation dns resolution");
break;
case PJ_STUN_SOCK_BINDING_OP:
DEBUG("UserAgent: Stun operation binding");
break;
case PJ_STUN_SOCK_KEEP_ALIVE_OP:
DEBUG("UserAgent: Stun operation keep alive");
break;
case PJ_STUN_SOCK_MAPPED_ADDR_CHANGE:
DEBUG("UserAgent: Stun operation address mapping change");
break;
default:
DEBUG("UserAgent: Stun unknown operation");
break;
}
if (status == PJ_SUCCESS) {
DEBUG("UserAgent: Stun operation success");
} else {
ERROR("UserAgent: Stun operation failure");
}
// Always return true so the stun transport registration retry even on failure
return true;
}
static pj_bool_t
stun_sock_on_rx_data_cb(pj_stun_sock * /*stun_sock*/, void * /*pkt*/,
unsigned /*pkt_len*/,
const pj_sockaddr_t * /*src_addr*/,
unsigned /*addr_len*/)
{
return PJ_TRUE;
}
pj_status_t SIPVoIPLink::createStunResolver(pj_str_t serverName, pj_uint16_t port)
{
pj_stun_config stunCfg;
pj_stun_config_init(&stunCfg, &cp_->factory, 0, pjsip_endpt_get_ioqueue(endpt_), pjsip_endpt_get_timer_heap(endpt_));
DEBUG("***************** Create Stun Resolver *********************");
static const pj_stun_sock_cb stun_sock_cb = {
stun_sock_on_rx_data_cb,
NULL,
stun_sock_on_status_cb
};
pj_stun_sock *stun_sock;
std::string stunResolverName(serverName.ptr, serverName.slen);
pj_status_t status = pj_stun_sock_create(&stunCfg, stunResolverName.c_str(), pj_AF_INET(), &stun_sock_cb, NULL, NULL, &stun_sock);
// store socket inside list
DEBUG(" insert %s resolver in map", stunResolverName.c_str());
stunSocketMap_.insert(std::pair<std::string, pj_stun_sock *>(stunResolverName, stun_sock));
if (status != PJ_SUCCESS) {
char errmsg[PJ_ERR_MSG_SIZE];
pj_strerror(status, errmsg, sizeof(errmsg));
ERROR("UserAgent: Error creating STUN socket for %.*s: %s", (int) serverName.slen, serverName.ptr, errmsg);
return status;
}
status = pj_stun_sock_start(stun_sock, &serverName, port, NULL);
if (status != PJ_SUCCESS) {
char errmsg[PJ_ERR_MSG_SIZE];
pj_strerror(status, errmsg, sizeof(errmsg));
DEBUG("UserAgent: Error starting STUN socket for %.*s: %s", (int) serverName.slen, serverName.ptr, errmsg);
pj_stun_sock_destroy(stun_sock);
}
return status;
}
pj_status_t SIPVoIPLink::destroyStunResolver(const std::string serverName)
{
std::map<std::string, pj_stun_sock *>::iterator it;
it = stunSocketMap_.find(serverName);
DEBUG("***************** Destroy Stun Resolver *********************");
if (it != stunSocketMap_.end()) {
DEBUG("UserAgent: Deleting stun resolver %s", it->first.c_str());
pj_stun_sock_destroy(it->second);
stunSocketMap_.erase(it);
}
return PJ_SUCCESS;
}
void SIPVoIPLink::createDefaultSipUdpTransport()
{
pj_uint16_t port = 0;
int counter = 0;
SIPAccount *account = Manager::instance().getIP2IPAccount();
pjsip_transport *transport = NULL;
static const int DEFAULT_TRANSPORT_ATTEMPTS = 5;
for (; transport == NULL and counter < DEFAULT_TRANSPORT_ATTEMPTS; ++counter) {
// if default udp transport fails to init on 5060, try other ports
// with 2 step size increment (i.e. 5062, 5064, ...)
port = account->getLocalPort() + (counter * 2);
transport = createUdpTransport(account->getLocalInterface(), port);
}
if (transport == NULL) {
ERROR("UserAgent: Create UDP transport");
return;
}
DEBUG("UserAgent: Created default sip transport on %d", port);
// set transport for this account
account->transport_ = transport;
// set local udp transport
localUDPTransport_ = account->transport_;
}
void SIPVoIPLink::createTlsListener(pj_uint16_t tlsListenerPort, pjsip_tls_setting *tlsSetting, pjsip_tpfactory **listener)
{
pj_sockaddr_in local_addr;
pj_sockaddr_in_init(&local_addr, 0, 0);
local_addr.sin_port = pj_htons(tlsListenerPort);
if (tlsSetting == NULL) {
ERROR("Error TLS settings not specified");
return;
}
if (listener == NULL) {
ERROR("Error no pointer to store new TLS listener");
return;
}
pj_str_t pjAddress;
pj_cstr(&pjAddress, PJ_INADDR_ANY);
pj_sockaddr_in_set_str_addr(&local_addr, &pjAddress);
std::string localIP(getSIPLocalIP());
pjsip_host_port a_name = {
pj_str((char*) localIP.c_str()),
local_addr.sin_port
};
pjsip_tls_transport_start(endpt_, tlsSetting, &local_addr, &a_name, 1, listener);
}
pjsip_transport *
SIPVoIPLink::createTlsTransport(const std::string &remoteAddr,
pj_uint16_t tlsListenerPort,
pjsip_tls_setting *tlsSettings)
{
pjsip_transport *transport = NULL;
pj_str_t remote;
pj_cstr(&remote, remoteAddr.c_str());
pj_sockaddr_in rem_addr;
pj_sockaddr_in_init(&rem_addr, &remote, (pj_uint16_t) DEFAULT_SIP_TLS_PORT);
// The local tls listener
static pjsip_tpfactory *localTlsListener = NULL;
if (localTlsListener == NULL)
createTlsListener(tlsListenerPort, tlsSettings, &localTlsListener);
pjsip_endpt_acquire_transport(endpt_, PJSIP_TRANSPORT_TLS, &rem_addr,
sizeof rem_addr, NULL, &transport);
if (transport == NULL)
ERROR("Error: Could not create new TLS transport\n");
return transport;
}
void SIPVoIPLink::createSipTransport(SIPAccount *account)
{
if (account == NULL) {
ERROR("UserAgent: Account is NULL while creating sip transport");
return;
}
shutdownSipTransport(account);
if (account->isTlsEnabled()) {
std::string remoteSipUri(account->getServerUri());
static const char SIPS_PREFIX[] = "<sips:";
size_t sips = remoteSipUri.find(SIPS_PREFIX) + (sizeof SIPS_PREFIX) - 1;
size_t trns = remoteSipUri.find(";transport");
std::string remoteAddr(remoteSipUri.substr(sips, trns-sips));
pjsip_transport *transport = createTlsTransport(remoteAddr, account->getTlsListenerPort(), account->getTlsSetting());
account->transport_ = transport;
} else if (account->isStunEnabled()) {
pjsip_transport *transport = createStunTransport(account->getStunServerName(), account->getStunPort());
account->transport_ = transport;
}
else {
pjsip_transport *transport = createUdpTransport(account->getLocalInterface(), account->getLocalPort());
account->transport_ = transport;
}
if (!account->transport_) {
// 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);
}
}
}
pjsip_transport *SIPVoIPLink::createUdpTransport(std::string interface, unsigned int port)
{
// init socket to bind this transport to
pj_sockaddr_in bound_addr;
pj_bzero(&bound_addr, sizeof(bound_addr));
pj_uint16_t listeningPort = (pj_uint16_t) port;
bound_addr.sin_port = pj_htons(listeningPort);
bound_addr.sin_family = PJ_AF_INET;
// determine the ip address for this transport
static const char * const DEFAULT_INTERFACE = "default";
std::string listeningAddress;
if (interface == DEFAULT_INTERFACE) {
listeningAddress = getSIPLocalIP();
bound_addr.sin_addr.s_addr = pj_htonl(PJ_INADDR_ANY);
} else {
listeningAddress = getInterfaceAddrFromName(interface);
bound_addr.sin_addr = pj_inet_addr2(listeningAddress.c_str());
}
if (listeningAddress.empty()) {
ERROR("SIP: Could not determine ip address for this transport");
return NULL;
}
if (listeningPort == 0) {
ERROR("SIP: Could not determine port for this transport");
return NULL;
}
// The published address for this transport
const pjsip_host_port a_name = {
pj_str((char*) listeningAddress.c_str()),
listeningPort
};
pjsip_transport *transport = NULL;
pj_status_t status = pjsip_udp_transport_start(endpt_, &bound_addr, &a_name, 1, &transport);
if (status != PJ_SUCCESS) {
ERROR("SIP: Could not create UDP transport for port %u", port);
return NULL;
}
// dump debug information to stdout
pjsip_tpmgr_dump_transports(pjsip_endpt_get_tpmgr(endpt_));
transportMap_[listeningPort] = transport;
return transport;
}
pjsip_tpselector *SIPVoIPLink::initTransportSelector(pjsip_transport *transport, pj_pool_t *tp_pool) const
{
assert(transport);
pjsip_tpselector *tp = (pjsip_tpselector *) pj_pool_zalloc(tp_pool, sizeof(pjsip_tpselector));
tp->type = PJSIP_TPSELECTOR_TRANSPORT;
tp->u.transport = transport;
return tp;
}
pjsip_transport *SIPVoIPLink::createStunTransport(pj_str_t serverName, pj_uint16_t port)
{
pjsip_transport *transport;
DEBUG("UserAgent: Create stun transport server name: %s, port: %d", serverName, port);// account->getStunPort());
if (createStunResolver(serverName, port) != PJ_SUCCESS) {
ERROR("UserAgent: Can't resolve STUN server");
Manager::instance().getDbusManager()->getConfigurationManager()->stunStatusFailure("");
return NULL;
}
pj_sock_t sock = PJ_INVALID_SOCKET;
pj_sockaddr_in boundAddr;
if (pj_sockaddr_in_init(&boundAddr, &serverName, 0) != PJ_SUCCESS) {
ERROR("UserAgent: Can't initialize IPv4 socket on %*s:%i", serverName.slen, serverName.ptr, port);
Manager::instance().getDbusManager()->getConfigurationManager()->stunStatusFailure("");
return NULL;
}
if (pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &sock) != PJ_SUCCESS) {
ERROR("UserAgent: Can't create or bind socket");
Manager::instance().getDbusManager()->getConfigurationManager()->stunStatusFailure("");
return NULL;
}
// Query the mapped IP address and port on the 'outside' of the NAT
pj_sockaddr_in pub_addr;
if (pjstun_get_mapped_addr(&cp_->factory, 1, &sock, &serverName, port, &serverName, port, &pub_addr) != PJ_SUCCESS) {
ERROR("UserAgent: Can't contact STUN server");
pj_sock_close(sock);
Manager::instance().getDbusManager()->getConfigurationManager()->stunStatusFailure("");
return NULL;
}
pjsip_host_port a_name = {
pj_str(pj_inet_ntoa(pub_addr.sin_addr)),
pj_ntohs(pub_addr.sin_port)
};
pjsip_udp_transport_attach2(endpt_, PJSIP_TRANSPORT_UDP, sock, &a_name, 1,
&transport);
pjsip_tpmgr_dump_transports(pjsip_endpt_get_tpmgr(endpt_));
return transport;
}
void SIPVoIPLink::shutdownSipTransport(SIPAccount *account)
{
if (account->isStunEnabled()) {
pj_str_t stunServerName = account->getStunServerName();
std::string server(stunServerName.ptr, stunServerName.slen);
destroyStunResolver(server);
}
if (account->transport_) {
pjsip_transport_dec_ref(account->transport_);
account->transport_ = NULL;
}
}
void SIPVoIPLink::findLocalAddressFromTransport(pjsip_transport *transport, pjsip_transport_type_e transportType, std::string &addr, std::string &port) const
{
// Initialize the sip port with the default SIP port
std::stringstream ss;
ss << DEFAULT_SIP_PORT;
port = ss.str();
// Initialize the sip address with the hostname
const pj_str_t *pjMachineName = pj_gethostname();
addr = std::string(pjMachineName->ptr, pjMachineName->slen);
// Update address and port with active transport
if (!transport) {
ERROR("SIPVoIPLink: Transport is NULL in findLocalAddress, using local address %s:%s", addr.c_str(), port.c_str());
return;
}
// get the transport manager associated with the SIP enpoint
pjsip_tpmgr *tpmgr = pjsip_endpt_get_tpmgr(endpt_);
if (!tpmgr) {
ERROR("SIPVoIPLink: Transport manager is NULL in findLocalAddress, using local address %s:%s", addr.c_str(), port.c_str());
return;
}
// initialize a transport selector
// TODO Need to determine why we exclude TLS here...
// if (transportType == PJSIP_TRANSPORT_UDP and transport_)
pjsip_tpselector *tp_sel = initTransportSelector(transport, pool_);
if (!tp_sel) {
ERROR("SIPVoIPLink: Could not initialize transport selector, using local address %s:%s", addr.c_str(), port.c_str());
return;
}