- initial import

This commit is contained in:
2018-06-05 11:05:37 +03:00
commit e1a4931375
4673 changed files with 1383093 additions and 0 deletions

View File

@@ -0,0 +1,747 @@
/* Copyright(C) 2007-2017 VoIPobjects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "EP_Engine.h"
#include "../helper/HL_Log.h"
#include "../helper/HL_Exception.h"
#include <resip/stack/ExtensionHeader.hxx>
#include <resip/stack/Pidf.hxx>
#include <resip/stack/PlainContents.hxx>
#define LOG_SUBSYSTEM "Account"
#define CONFIG(X) mConfig->at(X)
#define CONFIG_EXISTS(X) mConfig->exists(X)
//#define MODIFY_VIA_BEHIND_NAT
// NAT decorator
class NATDecorator: public resip::MessageDecorator
{
protected:
UserAgent& mUserAgent;
resip::SipMessage mMessage;
resip::Data mViaHost;
unsigned short mViaPort;
resip::Data mContactsHost;
resip::Data mContactsScheme;
unsigned short mContactsPort;
public:
NATDecorator(UserAgent& endpoint);
virtual ~NATDecorator();
virtual void decorateMessage(resip::SipMessage &msg, const resip::Tuple &source, const resip::Tuple &destination, const resip::Data& sigcompId);
virtual void rollbackMessage(resip::SipMessage& msg);
virtual MessageDecorator* clone() const;
};
NATDecorator::NATDecorator(UserAgent& ua)
:mUserAgent(ua), mViaPort(0), mContactsPort(0)
{
}
NATDecorator::~NATDecorator()
{
}
void NATDecorator::decorateMessage(resip::SipMessage &msg, const resip::Tuple &source, const resip::Tuple &destination, const resip::Data& sigcompId)
{
// Make a copy to allow rollback
mMessage = msg;
std::stringstream dump;
mMessage.encode(dump);
//ICELogDebug(<< "Decorating message: \n" << dump.str());
// Check From: header and find the account
resip::NameAddr from;
if (msg.isRequest())
from = msg.header(resip::h_From);
else
from = msg.header(resip::h_To);
PAccount account = mUserAgent.getAccount(from);
if (!account)
{
ICELogDebug(<< "Bad from header " << from.uri().getAor().c_str() << ". Will skip it");
return;
}
if (!account->mConfig->at(CONFIG_EXTERNALIP).asBool())
return;
if (!account->mExternalAddress.isEmpty())
{
#ifdef MODIFY_VIA_BEHIND_NAT
if (msg.header(resip::h_Vias).size() > 0)
{
resip::Via& via = msg.header(resip::h_Vias).front();
mViaHost = via.sentHost();
mViaPort = via.sentPort();
via.sentHost() = resip::Data(account->mExternalAddress.ip());
via.sentPort() = account->mExternalAddress.port();
}
#endif
if (msg.header(resip::h_Contacts).size() > 0)
{
resip::Uri& uri = msg.header(resip::h_Contacts).front().uri();
mContactsHost = uri.host();
mContactsPort = uri.port();
mContactsScheme = uri.scheme();
uri.host() = resip::Data(account->mExternalAddress.ip());
uri.port() = account->mExternalAddress.port();
if (account->mConfig->at(CONFIG_SIPS).asBool())
{
//uri.scheme() = "sips";
//uri.param(resip::p_transport) = "tls";
}
//uri.scheme() = account->mConfig->at(CONFIG_SIPS).asBool() ? "sips" : "sip";
}
}
}
void NATDecorator::rollbackMessage(resip::SipMessage& msg)
{
// Check From: header and find the account
resip::NameAddr from = msg.header(resip::h_From);
PAccount account = mUserAgent.getAccount(from);
if (!account)
return;
if (!account->mExternalAddress.isEmpty())
{
#ifdef MODIFY_VIA_BEHIND_NAT
if (msg.header(resip::h_Vias).size() > 0)
{
resip::Via& via = msg.header(resip::h_Vias).front();
if ((via.sentHost() == resip::Data(account->mExternalAddress.ip())) &&
(via.sentPort() == account->mExternalAddress.port()))
{
via.sentHost() = mViaHost;
via.sentPort() = mViaPort;
}
}
#endif
if (msg.header(resip::h_Contacts).size() > 0)
{
resip::Uri& uri = msg.header(resip::h_Contacts).front().uri();
if ((uri.host() == resip::Data(account->mExternalAddress.ip())) &&
(uri.port() == account->mExternalAddress.port()))
{
uri.host() = mContactsHost;
uri.port() = mContactsPort;
//uri.scheme() = mContactsScheme;
}
}
}
}
resip::MessageDecorator* NATDecorator::clone() const
{
return new NATDecorator(mUserAgent);
}
Account::Account(PVariantMap config, UserAgent& agent)
:mAgent(agent), mId(0), mConfig(config), mRegistrationState(RegistrationState::None),
mRegistration(NULL)
{
mProfile = resip::SharedPtr<resip::UserProfile>(new resip::UserProfile(agent.mProfile));
mId = Account::generateId();
setup(*config);
}
Account::~Account()
{
}
void Account::setup(VariantMap &config)
{
// Credentials
if (!config.exists(CONFIG_USERNAME) || !config.exists(CONFIG_PASSWORD) || !config.exists(CONFIG_DOMAIN))
throw Exception(ERR_NO_CREDENTIALS);
mProfile->clearDigestCredentials();
mProfile->setDigestCredential(resip::Data(config[CONFIG_DOMAIN].asStdString()),
resip::Data(config[CONFIG_USERNAME].asStdString()),
resip::Data(config[CONFIG_PASSWORD].asStdString()));
ICELogInfo( << "Credentials are set to domain " << config[CONFIG_DOMAIN].asStdString() <<
", username to " << config[CONFIG_USERNAME].asStdString());
// Proxy
mProfile->unsetOutboundProxy();
if (config.exists(CONFIG_PROXY))
{
if (!config[CONFIG_PROXY].asStdString().empty())
{
resip::Uri proxyAddr;
proxyAddr.host() = resip::Data(config[CONFIG_PROXY].asStdString());
proxyAddr.port() = 5060;
if (config.exists(CONFIG_PROXYPORT))
{
if (config[CONFIG_PROXYPORT].asInt())
proxyAddr.port() = config[CONFIG_PROXYPORT].asInt();
}
if (config[CONFIG_SIPS].asBool())
proxyAddr.param(resip::p_transport) = "tls";
mProfile->setOutboundProxy(proxyAddr);
}
}
// NAT decorator
mProfile->setOutboundDecorator(resip::SharedPtr<resip::MessageDecorator>(new NATDecorator(mAgent)));
// Rinstance
if (config.exists(CONFIG_INSTANCE_ID))
{
if (!config[CONFIG_INSTANCE_ID].asStdString().empty())
mProfile->setInstanceId(config[CONFIG_INSTANCE_ID].asStdString().c_str());
}
else
mProfile->setInstanceId(resip::Data::Empty);
if (config.exists(CONFIG_REGID))
mProfile->setRegId(config[CONFIG_REGID].asInt());
if (config.exists(CONFIG_RINSTANCE))
mProfile->setRinstanceEnabled(config[CONFIG_RINSTANCE].asBool());
else
mProfile->setRinstanceEnabled(true);
if (config.exists(CONFIG_RPORT))
mProfile->setRportEnabled(config[CONFIG_RPORT].asBool());
else
mProfile->setRportEnabled(true);
// From header
resip::NameAddr from;
if (config.exists(CONFIG_DISPLAYNAME))
from.displayName() = resip::Data(config[CONFIG_DISPLAYNAME].asStdString().c_str());
from.uri().scheme() = config[CONFIG_SIPS].asBool() ? "sips" : "sip";
if (config[CONFIG_DOMAINPORT].asInt() != 0)
from.uri().port() = config[CONFIG_DOMAINPORT].asInt();
else
from.uri().port();// = 5060;
from.uri().user() = resip::Data(config[CONFIG_USERNAME].asStdString());
from.uri().host() = resip::Data(config[CONFIG_DOMAIN].asStdString());
mProfile->setDefaultFrom(from);
if (!CONFIG_EXISTS(CONFIG_REGISTERDURATION))
CONFIG(CONFIG_REGISTERDURATION) = UA_REGISTRATION_TIME;
}
int Account::id() const
{
return mId;
}
void Account::start()
{
ICELogInfo(<< "Starting account " << this->name());
if (mRegistrationState != RegistrationState::None)
{
ICELogInfo(<< "Registration is active or in progress already.");
return;
}
if (!mAgent.mDum)
{
ICELogInfo(<< "DUM is not started yet.");
return;
}
// Create registration
mRegistration = new ResipSession(*mAgent.mDum);
resip::SharedPtr<resip::SipMessage> regmessage = mAgent.mDum->makeRegistration(mProfile->getDefaultFrom(), mProfile, mConfig->at(CONFIG_REGISTERDURATION).asInt(), mRegistration);
for (UserInfo::const_iterator iter = mUserInfo.begin(); iter != mUserInfo.end(); iter++)
regmessage->header(resip::ExtensionHeader(iter->first.c_str())).push_back(resip::StringCategory(iter->second.c_str()));
mRegistrationState = RegistrationState::Registering;
// Send packet here
mAgent.mDum->send(regmessage);
// Check if STUN IP is required
bool noStunServerIp = !CONFIG_EXISTS(CONFIG_STUNSERVER_IP);
//bool hasStunServerName = !CONFIG(CONFIG_STUNSERVER_NAME).asStdString().empty();
if (noStunServerIp)
{
ICELogInfo(<<"No STUN server name or IP is not specified. Has to resolve/discover STUN server IP.");
mRefreshStunServerIpTimer.start(CONFIG(CONFIG_DNS_CACHE_TIME).asInt() * 1000);
mRefreshStunServerIpTimer.isTimeToSend();
queryStunServerIp();
}
}
void Account::stop()
{
// Close presence publication
if (mPublication.isValid())
{
mPublication->end();
mPublication = resip::ClientPublicationHandle();
}
// Close client subscriptions
// Close registration
if (mRegistrationHandle.isValid())
{
mRegistrationHandle->removeAll();
mRegistrationHandle = resip::ClientRegistrationHandle();
}
else
if (mRegistration)
{
mRegistration->end();
}
mRegistration = NULL;
mRegistrationState = RegistrationState::None;
}
void Account::refresh()
{
if (mRegistrationHandle.isValid())
{
mRegistrationState = RegistrationState::Registering;
mRegistrationHandle->requestRefresh();
}
if (mPublication.isValid())
{
mPublication->refresh();
}
}
bool Account::active()
{
return mRegistrationState == RegistrationState::Registered ||
mRegistrationState == RegistrationState::Registering ||
mRegistrationState == RegistrationState::Reregistering;
}
std::string Account::name()
{
return contact(SecureScheme::Nothing).uri().toString().c_str();
}
Account::RegistrationState Account::registrationState()
{
return mRegistrationState;
}
void Account::publishPresence(bool online, const std::string& content, int seconds)
{
if (online == mPresenceOnline && content == mPresenceContent)
return;
mPresenceOnline = online;
mPresenceContent = content;
resip::Pidf p;
p.setEntity(contact(SecureScheme::Nothing).uri());
p.setSimpleId(resip::Data(CONFIG(CONFIG_PRESENCE_ID).asStdString()));
p.setSimpleStatus(online, resip::Data(content));
if (mPublication.isValid())
mPublication->update(&p);
else
mAgent.mDum->send(mAgent.mDum->makePublication(contact(SecureScheme::TlsOnly), mProfile, p, resip::Symbols::Presence, seconds));
}
void Account::stopPublish()
{
if (mPublication.isValid())
mPublication->end();
}
PClientObserver Account::observe(const std::string& target, const std::string& package, void* tag)
{
// Add subscription functionality
PClientObserver observer(new ClientObserver());
observer->mSession = new ResipSession(*mAgent.mDum);
observer->mSession->setRemoteAddress(target);
observer->mSession->setTag(tag);
observer->mSessionId = observer->mSession->sessionId();
observer->mPeer = target;
resip::SharedPtr<resip::SipMessage> msg;
int expires = DEFAULT_SUBSCRIPTION_TIME, refresh = DEFAULT_SUBSCRIPTION_REFRESHTIME;
if (mConfig->exists(CONFIG_SUBSCRIPTION_TIME))
expires = CONFIG(CONFIG_SUBSCRIPTION_TIME).asInt();
if (mConfig->exists(CONFIG_SUBSCRIPTION_REFRESHTIME))
refresh = CONFIG(CONFIG_SUBSCRIPTION_REFRESHTIME).asInt();
msg = mAgent.mDum->makeSubscription(resip::NameAddr(resip::Data(target)), mProfile,
resip::Data(package), expires, refresh, observer->mSession);
msg->header(resip::h_Accepts) = mAgent.mDum->getMasterProfile()->getSupportedMimeTypes(resip::NOTIFY);
mAgent.mClientObserverMap[observer->mSessionId] = observer;
mAgent.mDum->send(msg);
return observer;
}
/* Queues message to peer with specified mime type. Returns ID of message. */
int Account::sendMsg(const std::string& peer, const void* ptr, unsigned length, const std::string& mime, void* tag)
{
ResipSession* s = new ResipSession(*mAgent.mDum);
s->setUa(&mAgent);
s->setTag(tag);
s->setRemoteAddress(peer);
// Find MIME type
resip::Mime type;
std::string::size_type p = mime.find('/');
if (p != std::string::npos)
type = resip::Mime(resip::Data(mime.substr(0, p)), resip::Data(mime.substr(p+1)));
else
type = resip::Mime(resip::Data(mime), resip::Data());
resip::ClientPagerMessageHandle msgHandle = mAgent.mDum->makePagerMessage(resip::NameAddr(resip::Data(peer)), mProfile, s);
auto_ptr<resip::Contents> contentPtr(new resip::PlainContents(resip::Data(std::string((const char*)ptr, length)),type));
int result = s->sessionId();
msgHandle->page(contentPtr);
return result;
}
resip::NameAddr Account::contact(SecureScheme ss)
{
resip::NameAddr result;
switch (ss)
{
case SecureScheme::Nothing:
break;
case SecureScheme::SipsOnly:
result.uri().scheme() = mConfig->at(CONFIG_SIPS).asBool() ? "sips" : "sip";
break;
case SecureScheme::SipsAndTls:
result.uri().scheme() = mConfig->at(CONFIG_SIPS).asBool() ? "sips" : "sip";
if (mConfig->at(CONFIG_SIPS).asBool())
result.uri().param(resip::p_transport) = "tls";
break;
case SecureScheme::TlsOnly:
if (mConfig->at(CONFIG_SIPS).asBool())
result.uri().param(resip::p_transport) = "tls";
break;
}
result.uri().user() = resip::Data(mConfig->at(CONFIG_USERNAME).asStdString());
result.uri().host() = resip::Data(mConfig->at(CONFIG_DOMAIN).asStdString());
result.uri().port() = mConfig->at(CONFIG_DOMAINPORT).asInt();
return result;
}
void Account::queryStunServerIp()
{
ICELogInfo(<<"Looking for STUN/TURN server IP");
if (!mConfig->exists(CONFIG_STUNSERVER_NAME))
{
// Send request to find STUN or TURN service
std::string target = std::string(mConfig->at(CONFIG_RELAY).asBool() ? "_turn" : "_stun") + "._udp." + mConfig->at(CONFIG_DOMAIN).asStdString();
// Start lookup
mAgent.mStack->getDnsStub().lookup<resip::RR_SRV>(resip::Data(target), this);
}
else
{
// Check if host name is ip already
std::string server = mConfig->at(CONFIG_STUNSERVER_NAME).asStdString();
if (ice::NetworkAddress::isIp(server))
{
mConfig->at(CONFIG_STUNSERVER_IP) = server;
mRefreshStunServerIpTimer.stop();
}
else
mAgent.mStack->getDnsStub().lookup<resip::RR_A>(resip::Data(server), this);
}
}
void Account::prepareIceStack(Session *session, ice::AgentRole icerole)
{
ice::ServerConfig config;
ice::NetworkAddress addr;
addr.setIp(mConfig->at(CONFIG_STUNSERVER_IP).asStdString());
if (mConfig->at(CONFIG_STUNSERVER_PORT).asInt())
addr.setPort(mConfig->at(CONFIG_STUNSERVER_PORT).asInt());
else
addr.setPort(3478);
config.mServerList4.push_back(addr);
config.mRelay = mConfig->at(CONFIG_RELAY).asBool();
if (mConfig->exists(CONFIG_ICETIMEOUT))
config.mTimeout = mConfig->at(CONFIG_ICETIMEOUT).asInt();
config.mUsername = mConfig->at(CONFIG_ICEUSERNAME).asStdString();
config.mPassword = mConfig->at(CONFIG_ICEPASSWORD).asStdString();
config.mUseIPv4 = mAgent.config()[CONFIG_IPV4].asBool();
config.mUseIPv6 = mAgent.config()[CONFIG_IPV6].asBool();
//config.mDetectNetworkChange = true;
//config.mNetworkCheckInterval = 5000;
session->mIceStack = resip::SharedPtr<ice::Stack>(ice::Stack::makeICEBox(config));
session->mIceStack->setEventHandler(session, this);
session->mIceStack->setRole(icerole);
}
void Account::process()
{
if (mRefreshStunServerIpTimer.isTimeToSend())
queryStunServerIp();
}
void Account::onSuccess(resip::ClientRegistrationHandle h, const resip::SipMessage &response)
{
// Save registration handle
mRegistrationHandle = h;
// Copy user info to registration handle
for (UserInfo::iterator iter = mUserInfo.begin(); iter != mUserInfo.end(); iter++)
mRegistrationHandle->setCustomHeader(resip::Data(iter->first.c_str()), resip::Data(iter->second.c_str()));
// Get the Via
const resip::Via& via = response.header(resip::h_Vias).front();
// Get the sent host
const resip::Data& sentHost = via.sentHost();//response.header(h_Contacts).front().uri().host();
// Get the sentPort
int sentPort = via.sentPort();
const resip::Data& sourceHost = response.getSource().toData(resip::UDP);
int rport = 0;
if (via.exists(resip::p_rport))
rport = via.param(resip::p_rport).port();
resip::Data received = "";
if (via.exists(resip::p_received))
received = via.param(resip::p_received);
bool hostChanged = sentHost != received && received.size() > 0;
bool portChanged = sentPort != rport && rport != 0;
// Save external port and IP address
if (received.size() > 0 /*&& mConfig->at(CONFIG_EXTERNALIP).asBool()*/)
{
mExternalAddress.setIp(received.c_str());
mExternalAddress.setPort(rport ? rport : sentPort);
// Add new external address to domain list
if (mAgent.mStack)
mAgent.mStack->addAlias(resip::Data(mExternalAddress.ip()), mExternalAddress.port());
if (mAgent.mDum)
mAgent.mDum->addDomain(resip::Data(mExternalAddress.ip()));
}
const resip::Transport* transport = response.getReceivedTransport();
mUsedTransport = transport->transport();
bool streamTransport = transport->transport() == resip::TCP || transport->transport() == resip::TLS;
// Retry registration for stream based transport too
if ( (hostChanged || portChanged) && mRegistrationState == RegistrationState::Registering /*&& !streamTransport*/ && mConfig->at(CONFIG_EXTERNALIP).asBool())
{
//mRegistrationHandle->requestRefresh();
// Unregister at first
mRegistrationHandle->removeAll();
mRegistrationState = RegistrationState::Reregistering;
return;
}
// So here we registered ok
mRegistrationState = RegistrationState::Registered;
mAgent.onAccountStart(mAgent.getAccount(this));
}
void Account::onRemoved(resip::ClientRegistrationHandle h, const resip::SipMessage &response)
{
// Check if this unregistering is a part of rport pr
if (mRegistrationState == RegistrationState::Reregistering)
{
//if (/*this->mUseExternalIP && */response.getSource().getType() == resip::UDP)
{
resip::Uri hostport(contact(SecureScheme::TlsOnly).uri());
hostport.host() = resip::Data(mExternalAddress.ip());
hostport.port() = mExternalAddress.port();
if (mUsedTransport != resip::UDP)
{
const char* transportName = nullptr;
switch (mUsedTransport)
{
case resip::TCP: transportName = "tcp"; break;
case resip::TLS: transportName = "tls"; break;
}
hostport.param(resip::p_transport) = resip::Data(transportName);
}
mProfile->setOverrideHostAndPort(hostport);
//mProfile->setDefaultFrom(from);
}
mProfile->setRegId(mConfig->at(CONFIG_REGID).asInt());
resip::SharedPtr<resip::SipMessage> regmessage = mAgent.mDum->makeRegistration(mProfile->getDefaultFrom(), mProfile, UA_REGISTRATION_TIME);
for (UserInfo::const_iterator iter = mUserInfo.begin(); iter != mUserInfo.end(); iter++)
regmessage->header(resip::ExtensionHeader(iter->first.c_str())).push_back(resip::StringCategory(iter->second.c_str()));
mAgent.mDum->send(regmessage);
return;
}
else
{
mRegistration = NULL;
mRegistrationState = RegistrationState::None;
mRegistrationHandle = resip::ClientRegistrationHandle();
mAgent.onAccountStop(mAgent.getAccount(this), response.header(resip::h_StatusLine).statusCode());
}
}
void Account::onFailure(resip::ClientRegistrationHandle h, const resip::SipMessage& response)
{
// Reset registration handle
mRegistrationHandle = resip::ClientRegistrationHandle();
mRegistrationState = RegistrationState::None;
mRegistration = NULL;
mAgent.onAccountStop(mAgent.getAccount(this), response.header(resip::h_StatusLine).statusCode());
}
void Account::onDnsResult(const resip::DNSResult<resip::DnsHostRecord>& result)
{
if (result.status == 0)
{
resip::Data foundAddress = result.records.front().host();
ICELogCritical( << "Success to resolve STUN/TURN address to " << foundAddress.c_str());
mConfig->at(CONFIG_STUNSERVER_IP) = std::string(foundAddress.c_str());
// Here the IP address of STUN/TURN server is found. If account is registered already - it means account is ready.
if (mRegistrationState == RegistrationState::Registered)
mAgent.onAccountStart(mAgent.getAccount(this));
}
else
{
ICELogCritical( << "Failed to resolve STUN or TURN server IP address.");
if (mRegistrationState == RegistrationState::Registered)
{
int startCode = mConfig->at(CONFIG_STUNSERVER_NAME).asStdString().empty() ? 0 : 503;
mAgent.onAccountStop(mAgent.getAccount(this), startCode);
}
}
}
void Account::onDnsResult(const resip::DNSResult<resip::DnsAAAARecord>&)
{
}
void Account::onDnsResult(const resip::DNSResult<resip::DnsSrvRecord>& result)
{
if (result.status == 0)
{
// Find lowest priority
int priority = 0x7FFFFFFF;
for (size_t i=0; i<result.records.size(); i++)
if (result.records[i].priority() < priority)
priority = result.records[i].priority();
size_t index = 0;
int weight = 0;
for (size_t i=0; i<result.records.size(); i++)
{
if (result.records[i].priority() == priority && result.records[i].weight() >= weight)
{
index = i;
weight = result.records[i].weight();
}
}
mConfig->at(CONFIG_STUNSERVER_PORT) = result.records[index].port();
const char* host = result.records[index].target().c_str();
ICELogCritical( << "Success to find STUN/TURN server on " << result.records[index].target().c_str() <<
":" << (int)result.records[index].port());
if (inet_addr(host) == INADDR_NONE)
{
// Try to resolve domain name now
mAgent.mStack->getDnsStub().lookup<resip::RR_A>(result.records[index].target(), this);
//mStack->getDnsStub().lookup<resip::RR_AAAA>(result.records[index].target(), this);
}
else
{
mConfig->at(CONFIG_STUNSERVER_IP) = std::string(host);
}
}
else
{
ICELogCritical( << "Failed to find STUN or TURN service for specified domain.");
//mAgent::shutdown();
}
}
void Account::onDnsResult(const resip::DNSResult<resip::DnsNaptrRecord>&)
{
}
void Account::onDnsResult(const resip::DNSResult<resip::DnsCnameRecord>&)
{
}
bool Account::isResponsibleFor(const resip::NameAddr &addr)
{
std::string user = addr.uri().user().c_str();
std::string domain = addr.uri().host().c_str();
int p = addr.uri().port();
if (mConfig->at(CONFIG_USERNAME).asStdString() == user && mConfig->at(CONFIG_DOMAIN).asStdString() == domain)
{
// Check if ports are the same or port is not specified at all
if (mConfig->exists(CONFIG_DOMAINPORT))
return mConfig->at(CONFIG_DOMAINPORT).asInt() == p || !p;
else
return true;
}
else
return false;
}
void Account::setUserInfo(const UserInfo &info)
{
mUserInfo = info;
if (mRegistrationHandle.isValid())
{
for (UserInfo::iterator iter = mUserInfo.begin(); iter != mUserInfo.end(); iter++)
mRegistrationHandle->setCustomHeader(resip::Data(iter->first.c_str()), resip::Data(iter->second.c_str()));
}
}
Account::UserInfo Account::getUserInfo() const
{
return mUserInfo;
}
resip::AtomicCounter Account::IdGenerator;
int Account::generateId()
{
return IdGenerator.increment();
}

View File

@@ -0,0 +1,143 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef EP_ACCOUNT_H
#define EP_ACCOUNT_H
#include "../helper/HL_Pointer.h"
#include "../helper/HL_VariantMap.h"
#include "ice/ICEAddress.h"
#include "ice/ICETime.h"
#include "ice/ICEBox.h"
#include "resip/dum/UserProfile.hxx"
#include "resip/dum/ClientRegistration.hxx"
#include "resip/dum/ClientPublication.hxx"
#include "resip/stack/DnsInterface.hxx"
#include "resip/stack/NameAddr.hxx"
#include "EP_Observer.h"
class UserAgent;
class Session;
class Account: public resip::DnsResultSink
{
friend class UserAgent;
friend class NATDecorator;
public:
Account(PVariantMap config, UserAgent& agent);
~Account();
void start();
void stop();
void refresh();
bool active();
int id() const;
enum class RegistrationState
{
None,
Registering,
Reregistering,
Registered,
Unregistering
};
RegistrationState registrationState();
/* Publishes new presence information */
void publishPresence(bool online, const std::string& content, int seconds = 600);
/* Stops publishing of presence */
void stopPublish();
/* Starts observing on specified target / package */
PClientObserver observe(const std::string& target, const std::string& package, void* tag);
/* Queues message to peer with specified mime type. Returns ID of message. */
int sendMsg(const std::string& peer, const void* ptr, unsigned length, const std::string& mime, void* tag);
/* Returns name of account - <sip:user@domain> */
std::string name();
/* Updates account with configuration */
void setup(VariantMap& config);
/* Returns corresponding resiprocate profile */
resip::SharedPtr<resip::UserProfile> getUserProfile() const { return mProfile; }
typedef std::map<std::string, std::string> UserInfo;
void setUserInfo(const UserInfo& info);
UserInfo getUserInfo() const;
protected:
PVariantMap mConfig;
// Registration
ResipSession* mRegistration;
resip::ClientRegistrationHandle mRegistrationHandle;
resip::ClientPublicationHandle mPublication;
resip::TransportType mUsedTransport;
RegistrationState mRegistrationState;
ice::NetworkAddress mExternalAddress;
resip::SharedPtr<resip::UserProfile> mProfile;
UserAgent& mAgent;
bool mPresenceOnline;
std::string mPresenceContent;
// Timer to refresh STUN server IP
ice::ICEScheduleTimer mRefreshStunServerIpTimer;
// Cached auth
resip::Auth mCachedAuth;
// Id of account
int mId;
// User info about current state
UserInfo mUserInfo;
// List of client subscriptions sent from this account
typedef std::set<PClientObserver> ClientObserverSet;
ClientObserverSet mClientObserverSet;
void process();
// Method queries new stun server ip from dns (if stun server is specified as dns name)
void queryStunServerIp();
bool isResponsibleFor(const resip::NameAddr& addr);
enum class SecureScheme
{
SipsAndTls,
SipsOnly,
TlsOnly,
Nothing
};
resip::NameAddr contact(SecureScheme ss = SecureScheme::SipsOnly);
// This method prepares configuration, creates ice stack and sets ownership to session
void prepareIceStack(Session* session, ice::AgentRole role);
void onSuccess(resip::ClientRegistrationHandle h, const resip::SipMessage& response);
void onRemoved(resip::ClientRegistrationHandle h, const resip::SipMessage& response);
void onFailure(resip::ClientRegistrationHandle, const resip::SipMessage& response);
#pragma region DnsResultSink implementation
void onDnsResult(const resip::DNSResult<resip::DnsHostRecord>&);
void onDnsResult(const resip::DNSResult<resip::DnsAAAARecord>&);
void onDnsResult(const resip::DNSResult<resip::DnsSrvRecord>&);
void onDnsResult(const resip::DNSResult<resip::DnsNaptrRecord>&);
void onDnsResult(const resip::DNSResult<resip::DnsCnameRecord>&);
#pragma endregion
static int generateId();
static resip::AtomicCounter IdGenerator;
};
typedef std::shared_ptr<Account> PAccount;
#endif // EP_ACCOUNT_H

View File

@@ -0,0 +1,380 @@
/* Copyright(C) 2007-2017 VoIPobjects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "EP_AudioProvider.h"
#include "EP_Engine.h"
#include "../media/MT_Box.h"
#include "../media/MT_AudioStream.h"
#include "../media/MT_SrtpHelper.h"
#include "../media/MT_Stream.h"
#include "../helper/HL_Rtp.h"
#include "../helper/HL_StreamState.h"
#include "../helper/HL_Log.h"
#include "../helper/HL_String.h"
#define LOG_SUBSYSTEM "AudioProvider"
AudioProvider::AudioProvider(UserAgent& agent, MT::Terminal& terminal)
:mUserAgent(agent), mTerminal(terminal), mState(0),
mRemoteTelephoneCodec(0), mRemoteNoSdp(false)
{
mActive = mfActive;
mRemoteState = msSendRecv;
mActiveStream = mTerminal.createStream(MT::Stream::Audio, mUserAgent.config());
if (mUserAgent.config().exists(CONFIG_CODEC_PRIORITY))
mCodecPriority.setupFrom(mUserAgent.config()[CONFIG_CODEC_PRIORITY].asVMap());
mSrtpSuite = SRTP_NONE;
setState((int)StreamState::SipRecv | (int)StreamState::SipSend | (int)StreamState::Receiving | (int)StreamState::Sending);
}
AudioProvider::~AudioProvider()
{
}
std::string AudioProvider::streamName()
{
return "audio";
}
std::string AudioProvider::streamProfile()
{
if (mState & (int)StreamState::Srtp)
return "RTP/SAVP";
else
return "RTP/AVP";
}
// Sets destination IP address
void AudioProvider::setDestinationAddress(const RtpPair<InternetAddress>& addr)
{
if (!mActiveStream)
return;
mActiveStream->setDestination(addr);
}
void AudioProvider::configureMediaObserver(MT::Stream::MediaObserver *observer, void* userTag)
{
mMediaObserver = observer;
mMediaObserverTag = userTag;
if (mActiveStream)
mActiveStream->configureMediaObserver(observer, userTag);
}
// Processes incoming data
void AudioProvider::processData(PDatagramSocket s, const void* dataBuffer, int dataSize, InternetAddress& source)
{
if (!mActiveStream)
return;
if (RtpHelper::isRtpOrRtcp(dataBuffer, dataSize))
{
ICELogMedia(<<"Adding new data to stream processing");
mActiveStream->dataArrived(s, dataBuffer, dataSize, source);
}
}
// This method is called by user agent to send ICE packet from mediasocket
void AudioProvider::sendData(PDatagramSocket s, InternetAddress& destination, const void* buffer, unsigned int size)
{
s->sendDatagram(destination, buffer, size);
}
// Create SDP offer
void AudioProvider::updateSdpOffer(resip::SdpContents::Session::Medium& sdp, SdpDirection direction)
{
if (mRemoteNoSdp)
return;
if (mState & (int)StreamState::Srtp)
{
// Check if SRTP suite is found already or not
if (mSrtpSuite == SRTP_NONE)
{
for (int suite = SRTP_AES_128_AUTH_80; suite <= SRTP_LAST; suite++)
sdp.addAttribute("crypto", resip::Data(createCryptoAttribute((SrtpSuite)suite)));
}
else
sdp.addAttribute("crypto", resip::Data(createCryptoAttribute(mSrtpSuite)));
}
// Use CodecListPriority mCodecPriority adapter to work with codec priorities
if (mAvailableCodecs.empty())
{
for (int i=0; i<mCodecPriority.count(mTerminal.codeclist()); i++)
mCodecPriority.codecAt(mTerminal.codeclist(), i).updateSdp(sdp.codecs(), direction);
sdp.addCodec(resip::SdpContents::Session::Codec::TelephoneEvent);
}
else
{
mAvailableCodecs.front().mFactory->updateSdp(sdp.codecs(), direction);
if (mRemoteTelephoneCodec)
sdp.addCodec(resip::SdpContents::Session::Codec::TelephoneEvent);
}
// Publish stream state
const char* attr = nullptr;
switch (mActive)
{
case mfActive:
switch(mRemoteState)
{
case msSendonly: attr = "recvonly"; break;
case msInactive: attr = "recvonly"; break;
}
break;
case mfPaused:
switch (mRemoteState)
{
case msRecvonly: attr = "sendonly"; break;
case msSendonly: attr = "inactive"; break;
case msInactive: attr = "inactive"; break;
case msSendRecv: attr = "sendonly"; break;
}
break;
}
if (attr)
sdp.addAttribute(attr);
}
void AudioProvider::sessionDeleted()
{
sessionTerminated();
}
void AudioProvider::sessionTerminated()
{
ICELogDebug(<< "sessionTerminated() for audio provider");
setState(state() & ~((int)StreamState::Sending | (int)StreamState::Receiving));
if (mActiveStream)
{
ICELogDebug(<< "Copy statistics from existing stream before freeing.");
// Copy statistics - maybe it will be requested later
mBackupStats = mActiveStream->statistics();
ICELogDebug(<< "Remove stream from terminal");
mTerminal.freeStream(mActiveStream);
// Retrieve final statistics
MT::AudioStream* audio_stream = dynamic_cast<MT::AudioStream*>(mActiveStream.get());
if (audio_stream)
audio_stream->setFinalStatisticsOutput(&mBackupStats);
ICELogDebug(<< "Reset reference to stream.");
mActiveStream.reset();
}
}
void AudioProvider::sessionEstablished(int conntype)
{
// Start media streams
setState(state() | (int)StreamState::Receiving | (int)StreamState::Sending);
// Available codec list can be empty in case of no-sdp offers.
if (conntype == EV_SIP && !mAvailableCodecs.empty() && mActiveStream)
{
RemoteCodec& rc = mAvailableCodecs.front();
mActiveStream->setTransmittingCodec(*rc.mFactory, rc.mRemotePayloadType);
dynamic_cast<MT::AudioStream*>(mActiveStream.get())->setTelephoneCodec(mRemoteTelephoneCodec);
}
}
void AudioProvider::setSocket(const RtpPair<PDatagramSocket>& p4, const RtpPair<PDatagramSocket>& p6)
{
mSocket4 = p4;
mSocket6 = p6;
mActiveStream->setSocket(p4);
}
RtpPair<PDatagramSocket>& AudioProvider::socket(int family)
{
switch (family)
{
case AF_INET:
return mSocket4;
case AF_INET6:
return mSocket6;
}
return mSocket4;
}
bool AudioProvider::processSdpOffer(const resip::SdpContents::Session::Medium& media, SdpDirection sdpDirection)
{
// Check if there is compatible codec
mAvailableCodecs.clear();
mRemoteTelephoneCodec = 0;
// Check if there is SDP at all
mRemoteNoSdp = media.codecs().empty();
if (mRemoteNoSdp)
return true;
// Update RFC2833 related information
findRfc2833(media.codecs());
// Use CodecListPriority mCodecPriority to work with codec priorities
int pt;
for (int localIndex=0; localIndex<mCodecPriority.count(mTerminal.codeclist()); localIndex++)
{
MT::Codec::Factory& factory = mCodecPriority.codecAt(mTerminal.codeclist(), localIndex);
if ((pt = factory.processSdp(media.codecs(), sdpDirection)) != -1)
mAvailableCodecs.push_back(RemoteCodec(&factory, pt));
}
if (!mAvailableCodecs.size())
return false;
// Iterate SRTP crypto: attributes
if (media.exists("crypto"))
{
// Find the most strong crypt suite
const std::list<resip::Data>& vl = media.getValues("crypto");
SrtpSuite ss = SRTP_NONE;
ByteBuffer key;
for (std::list<resip::Data>::const_iterator attrIter = vl.begin(); attrIter != vl.end(); attrIter++)
{
const resip::Data& attr = *attrIter;
ByteBuffer tempkey;
SrtpSuite suite = processCryptoAttribute(attr, tempkey);
if (suite > ss)
{
ss = suite;
mSrtpSuite = suite;
key = tempkey;
}
}
// If SRTP suite is agreed
if (ss != SRTP_NONE)
{
ICELogInfo(<< "Found SRTP suite " << ss);
mActiveStream->srtp().open(key, ss);
setState(state() | (int)StreamState::Srtp);
}
else
ICELogInfo(<< "Did not find valid SRTP suite");
}
DataProvider::processSdpOffer(media, sdpDirection);
return true;
}
void AudioProvider::setState(unsigned state)
{
mState = state;
if (mActiveStream)
mActiveStream->setState(state);
}
unsigned AudioProvider::state()
{
return mState;
}
MT::Statistics AudioProvider::getStatistics()
{
if (mActiveStream)
return mActiveStream->statistics();
else
return mBackupStats;
}
MT::PStream AudioProvider::activeStream()
{
return mActiveStream;
}
std::string AudioProvider::createCryptoAttribute(SrtpSuite suite)
{
if (!mActiveStream)
return "";
// Use tag 1 - it is ok, as we use only single crypto attribute
int srtpTag = 1;
// Print key to base64 string
PByteBuffer keyBuffer = mActiveStream->srtp().outgoingKey(suite).first;
resip::Data d(keyBuffer->data(), keyBuffer->size());
resip::Data keyText = d.base64encode();
// Create "crypto" attribute value
char buffer[512];
const char* suiteName = NULL;
switch (suite)
{
case SRTP_AES_128_AUTH_80: suiteName = SRTP_SUITE_NAME_1; break;
case SRTP_AES_256_AUTH_80: suiteName = SRTP_SUITE_NAME_2; break;
default: assert(0);
}
sprintf(buffer, "%d %s inline:%s", srtpTag, suiteName, keyText.c_str());
return buffer;
}
SrtpSuite AudioProvider::processCryptoAttribute(const resip::Data& value, ByteBuffer& key)
{
int srtpTag = 0;
char suite[64], keyChunk[256];
int components = sscanf(value.c_str(), "%d %63s inline: %255s", &srtpTag, suite, keyChunk);
if (components != 3)
return SRTP_NONE;
const char* delimiter = strchr(keyChunk, '|');
resip::Data keyText;
if (delimiter)
keyText = resip::Data(keyChunk, delimiter - keyChunk);
else
keyText = resip::Data(keyChunk);
resip::Data rawkey = keyText.base64decode();
key = ByteBuffer(rawkey.c_str(), rawkey.size());
// Open srtp
SrtpSuite result = SRTP_NONE;
if (strcmp(suite, SRTP_SUITE_NAME_1) == 0)
result = SRTP_AES_128_AUTH_80;
else
if (strcmp(suite, SRTP_SUITE_NAME_2) == 0)
result = SRTP_AES_256_AUTH_80;
return result;
}
void AudioProvider::findRfc2833(const resip::SdpContents::Session::Medium::CodecContainer& codecs)
{
resip::SdpContents::Session::Medium::CodecContainer::const_iterator codecIter;
for (codecIter = codecs.begin(); codecIter != codecs.end(); codecIter++)
{
if (strcmp("TELEPHONE-EVENT", codecIter->getName().c_str()) == 0 ||
strcmp("telephone-event", codecIter->getName().c_str()) == 0)
mRemoteTelephoneCodec = codecIter->payloadType();
}
}
void AudioProvider::readFile(const Audio::PWavFileReader& stream, MT::Stream::MediaDirection direction)
{
// Iterate stream list
if (mActiveStream)
mActiveStream->readFile(stream, direction);
}
void AudioProvider::writeFile(const Audio::PWavFileWriter& stream, MT::Stream::MediaDirection direction)
{
if (mActiveStream)
mActiveStream->writeFile(stream, direction);
}
void AudioProvider::setupMirror(bool enable)
{
if (mActiveStream)
mActiveStream->setupMirror(enable);
}

View File

@@ -0,0 +1,117 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __AUDIO_PROVIDER_H
#define __AUDIO_PROVIDER_H
#include "EP_DataProvider.h"
#include "../helper/HL_InternetAddress.h"
#include "../helper/HL_Rtp.h"
#include "../media/MT_Box.h"
#include "../media/MT_Stream.h"
#include "../media/MT_Codec.h"
#include "../audio/Audio_Interface.h"
#include "rutil/ThreadIf.hxx"
#include <vector>
#include <string>
class UserAgent;
class AudioProvider: public DataProvider
{
public:
AudioProvider(UserAgent& agent, MT::Terminal& terminal);
virtual ~AudioProvider();
// Returns provider RTP name
std::string streamName();
// Returns provider RTP profile name
std::string streamProfile();
// Sets destination IP address
void setDestinationAddress(const RtpPair<InternetAddress>& addr);
// Processes incoming data
void processData(PDatagramSocket s, const void* dataBuffer, int dataSize, InternetAddress& source);
// This method is called by user agent to send ICE packet from mediasocket
void sendData(PDatagramSocket s, InternetAddress& destination, const void* dataBuffer, unsigned int datasize);
// Updates SDP offer
void updateSdpOffer(resip::SdpContents::Session::Medium& sdp, SdpDirection direction);
// Called by user agent when session is deleted.
void sessionDeleted();
// Called by user agent when session is terminated.
void sessionTerminated();
// Called by user agent when session is started.
void sessionEstablished(int conntype);
// Called by user agent to save media socket for this provider
void setSocket(const RtpPair<PDatagramSocket>& p4, const RtpPair<PDatagramSocket>& p6);
// Called by user agent to get media socket for this provider
RtpPair<PDatagramSocket>& socket(int family);
// Called by user agent to process media stream description from remote peer.
// Returns true if description is processed succesfully. Otherwise method returns false.
// myAnswer sets if the answer will be sent after.
bool processSdpOffer(const resip::SdpContents::Session::Medium& media, SdpDirection sdpDirection);
void setState(unsigned state);
unsigned state();
MT::Statistics getStatistics();
MT::PStream activeStream();
void readFile(const Audio::PWavFileReader& stream, MT::Stream::MediaDirection direction);
void writeFile(const Audio::PWavFileWriter& stream, MT::Stream::MediaDirection direction);
void setupMirror(bool enable);
void configureMediaObserver(MT::Stream::MediaObserver* observer, void* userTag);
protected:
// SDP's stream name
std::string mStreamName;
// Socket handles to operate
RtpPair<PDatagramSocket> mSocket4, mSocket6;
// Destination IP4/6 address
RtpPair<InternetAddress> mDestination;
MT::PStream mActiveStream;
UserAgent& mUserAgent;
MT::Terminal& mTerminal;
MT::Statistics mBackupStats;
unsigned mState;
SrtpSuite mSrtpSuite;
struct RemoteCodec
{
RemoteCodec(MT::Codec::Factory* factory, int payloadType)
:mFactory(factory), mRemotePayloadType(payloadType)
{ }
MT::Codec::Factory* mFactory;
int mRemotePayloadType;
};
std::vector<RemoteCodec> mAvailableCodecs;
int mRemoteTelephoneCodec; // Payload type of remote rfc2833 codec
bool mRemoteNoSdp; // Marks if we got no-sdp offer
MT::CodecListPriority mCodecPriority;
MT::Stream::MediaObserver* mMediaObserver = nullptr;
void* mMediaObserverTag = nullptr;
std::string createCryptoAttribute(SrtpSuite suite);
SrtpSuite processCryptoAttribute(const resip::Data& value, ByteBuffer& key);
void findRfc2833(const resip::SdpContents::Session::Medium::CodecContainer& codecs);
};
#endif

View File

@@ -0,0 +1,74 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "EP_DataProvider.h"
#include "../helper/HL_StreamState.h"
bool DataProvider::isSupported(const char* name)
{
return !strcmp(name, "audio");
//return (!strcmp(name, "screen") || !strcmp(name, "data") || !strcmp(name, "audio") || !strcmp(name, "video"));
}
void DataProvider::pause()
{
/*if (state() & STATE_SIPRECV)
setState( state() & ~STATE_SIPRECV );*/
// Stop receive RTP stream
if (state() & (int)StreamState::Receiving)
setState( state() & ~(int)StreamState::Receiving );
mActive = mfPaused;
}
void DataProvider::resume()
{
// Tell remote peer about resumed receiving in SDP
//setState( state() | STATE_SIPRECV );
// Start receive RTP stream
setState( state() | (int)StreamState::Receiving );
mActive = mfActive;
}
bool DataProvider::processSdpOffer(const resip::SdpContents::Session::Medium& media, SdpDirection sdpDirection)
{
// Process paused and inactive calls
if (media.exists("sendonly"))
{
mRemoteState = msSendonly;
setState(state() & ~(int)StreamState::Sending);
}
else
if (media.exists("recvonly"))
{
mRemoteState = msRecvonly;
setState(state() & ~(int)StreamState::Receiving);
}
else
if (media.exists("inactive"))
{
mRemoteState = msInactive;
setState(state() & ~((int)StreamState::Sending | (int)StreamState::Receiving) );
}
else
{
mRemoteState = msSendRecv;
switch (mActive)
{
case mfActive:
setState(state() | (int)StreamState::Sending | (int)StreamState::Receiving);
break;
case mfPaused:
setState(state() | (int)StreamState::Sending );
break;
}
}
return true;
}

View File

@@ -0,0 +1,92 @@
/* Copyright(C) 2007-2016 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __DATA_PROVIDER_H
#define __DATA_PROVIDER_H
#include <string>
#include <vector>
#include "resip/stack/SdpContents.hxx"
#include "rutil/SharedPtr.hxx"
#include "../helper/HL_InternetAddress.h"
#include "../helper/HL_NetworkSocket.h"
#include "../helper/HL_Pointer.h"
#include "../media/MT_Stream.h"
class DataProvider
{
public:
enum MediaFlow
{
mfActive,
mfPaused
};
enum MediaState
{
msSendRecv,
msSendonly,
msRecvonly,
msInactive
};
static bool isSupported(const char* name);
// Returns provider RTP name
virtual std::string streamName() = 0;
// Returns provider RTP profile name
virtual std::string streamProfile() = 0;
// Sets destination IP address
virtual void setDestinationAddress(const RtpPair<InternetAddress>& addr) = 0;
// Processes incoming data
virtual void processData(PDatagramSocket s, const void* dataBuffer, int dataSize, InternetAddress& address) = 0;
// This method is called by user agent to send ICE packet from mediasocket
virtual void sendData(PDatagramSocket s, InternetAddress& destination, const void* dataBuffer, unsigned int datasize) = 0;
// Updates SDP offer
virtual void updateSdpOffer(resip::SdpContents::Session::Medium& sdp, SdpDirection direction) = 0;
// Called by user agent when session is deleted. Comes after sessionTerminated().
virtual void sessionDeleted() = 0;
// Called by user agent when session is terminated.
virtual void sessionTerminated() = 0;
// Called by user agent when session is started.
virtual void sessionEstablished(int conntype) = 0;
// Called by user agent to save media socket for this provider
virtual void setSocket(const RtpPair<PDatagramSocket>& p4, const RtpPair<PDatagramSocket>& p6) = 0;
// Called by user agent to get media socket for this provider
virtual RtpPair<PDatagramSocket>& socket(int family) = 0;
// Called by user agent to process media stream description from remote peer.
// Returns true if description is processed succesfully. Otherwise method returns false.
virtual bool processSdpOffer(const resip::SdpContents::Session::Medium& media, SdpDirection sdpDirection) = 0;
virtual unsigned state() = 0;
virtual void setState(unsigned state) = 0;
virtual void pause();
virtual void resume();
virtual MT::Statistics getStatistics() = 0;
protected:
MediaFlow mActive;
MediaState mRemoteState;
};
typedef std::shared_ptr<DataProvider> PDataProvider;
typedef std::vector<PDataProvider> DataProviderVector;
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,484 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __ENGINE_H
#define __ENGINE_H
#include "resip/stack/SdpContents.hxx"
#include "resip/stack/SipMessage.hxx"
#include "resip/stack/ShutdownMessage.hxx"
#include "resip/stack/SipStack.hxx"
#include "resip/stack/InternalTransport.hxx"
#include "resip/dum/ClientAuthManager.hxx"
#include "resip/dum/ClientInviteSession.hxx"
#include "resip/dum/ClientRegistration.hxx"
#include "resip/dum/DialogUsageManager.hxx"
#include "resip/dum/DumShutdownHandler.hxx"
#include "resip/dum/InviteSessionHandler.hxx"
#include "resip/dum/MasterProfile.hxx"
#include "resip/dum/RegistrationHandler.hxx"
#include "resip/dum/ServerInviteSession.hxx"
#include "resip/dum/ServerOutOfDialogReq.hxx"
#include "resip/dum/OutOfDialogHandler.hxx"
#include "resip/dum/AppDialog.hxx"
#include "resip/dum/AppDialogSet.hxx"
#include "resip/dum/AppDialogSetFactory.hxx"
#include "resip/dum/ClientPublication.hxx"
#include "resip/dum/ClientSubscription.hxx"
#include "resip/dum/SubscriptionHandler.hxx"
#include "resip/dum/PagerMessageHandler.hxx"
#include "resip/dum/PublicationHandler.hxx"
#include "resip/dum/ClientPagerMessage.hxx"
#include "resip/dum/ServerPagerMessage.hxx"
#include "rutil/Log.hxx"
#include "rutil/Logger.hxx"
#include "rutil/Random.hxx"
#include "rutil/WinLeakCheck.hxx"
#include "rutil/DnsUtil.hxx"
#include "resip/stack/DnsResult.hxx"
#include "resip/stack/SipStack.hxx"
#include "rutil/dns/RRVip.hxx"
#include "rutil/dns/QueryTypes.hxx"
#include "rutil/dns/DnsStub.hxx"
#include "../ice/ICEBox.h"
#include "../ice/ICETime.h"
#include <sstream>
#include <time.h>
#include "../config.h"
#include "EP_Session.h"
#include "EP_Observer.h"
#include "EP_DataProvider.h"
#include "../helper/HL_VariantMap.h"
#include "../helper/HL_SocketHeap.h"
#include "../helper/HL_Sync.h"
#include "../helper/HL_ByteBuffer.h"
#include "../media/MT_Stream.h"
#define RESIPROCATE_SUBSYSTEM Subsystem::TEST
using namespace std;
enum
{
CONFIG_IPV4 = 0, // Use IP4
CONFIG_IPV6, // Use IP6.
CONFIG_USERNAME, // Username. String value.
CONFIG_DOMAIN, // Domain. String value.
CONFIG_PASSWORD, // Password. String value.
CONFIG_RINSTANCE, // Determines if SIP rinstance field has to be used during registration. Boolean value.
CONFIG_INSTANCE_ID, // Instance id. It is alternative option to rinstance.
CONFIG_DISPLAYNAME, // Optional user display name. String value.
CONFIG_DOMAINPORT, // Optional domain port number. Integer value.
CONFIG_REGISTERDURATION, // Wanted duration for registration. Integer value. It is MANDATORY value.
CONFIG_RPORT, // Use SIP rport field. Recommended to set it to true. Boolean value.
CONFIG_KEEPALIVETIME, // Interval between UDP keep-alive messages. Boolean value.
CONFIG_RELAY, // Sets if TURN server must be used instead of STUN. Boolean value.
CONFIG_ICETIMEOUT, // Optional timeout for ICE connectivity checks and candidate gathering. Integer value.
CONFIG_ICEUSERNAME, // Optional username for TURN server. String value.
CONFIG_ICEPASSWORD, // Optional password for TURN server. String value.
CONFIG_SIPS, // Marks if account credentials are sips: scheme. Boolean value.
CONFIG_STUNSERVER_IP, // Optional IP address of STUN/TURN server. String value. It is better to use CONFIG_STUNSERVER_NAME.
CONFIG_STUNSERVER_NAME, // Host name of STUN/TURN server. stun.xten.com for example. String value.
CONFIG_STUNSERVER_PORT, // Port number of STUN/TURN server. Integer value.
CONFIG_USERAGENT, // Name of user agent in SIP headers. String value.
CONFIG_ICEREQUIRED, // ICE MUST be present in remote peer offers and answers. Boolean value.
CONFIG_TRANSPORT, // 0 - all transports, 1 - UDP, 2 - TCP, 3 - TLS,
CONFIG_SUBSCRIPTION_TIME, // Subscription time (in seconds)
CONFIG_SUBSCRIPTION_REFRESHTIME, // Refresh interval for subscriptions
CONFIG_DNS_CACHE_TIME, // DNS cache time; default is 86400 seconds
CONFIG_PRESENCE_ID, // Tuple ID used in presence publishing; determines source device
CONFIG_ROOTCERT, // Additional root cert in PEM format; string.
CONFIG_CACHECREDENTIALS, // Attempt to cache credentials that comes in response from PBX. Use them when possible to reduce number of steps of SIP transaction
CONFIG_RTCP_ATTR, // Use "rtcp" attribute in sdp. Default value is true.
CONFIG_MULTIPLEXING, // Do rtp/rtcp multiplexing
CONFIG_DEFERRELAYED, // Defer relayed media path
CONFIG_PROXY, // Proxy host name or IP address
CONFIG_PROXYPORT, // Proxy port number
CONFIG_CODEC_PRIORITY, // Another VariantMap with codec priorities,
CONFIG_ACCOUNT, // VariantMap with account configuration
CONFIG_EXTERNALIP, // Use external/public IP in outgoing requests
CONFIG_OWN_DNS, // Use predefined DNS servers
CONFIG_REGID // reg-id value from RFC5626
};
// Conntype parameter for OnSessionEstablished event
enum
{
EV_SIP = 1,
EV_ICE = 2
};
class UserAgent;
// Define a type for asynchronous requests to user agent
class SIPAction
{
public:
virtual void Run(UserAgent& ua) = 0;
};
typedef std::vector<SIPAction*> SIPActionVector;
// Session termination reason
enum
{
Error,
Timeout,
Replaced,
LocalBye,
RemoteBye,
LocalCancel,
RemoteCancel,
Rejected, //Only as UAS, UAC has distinct onFailure callback
Referred
};
class UserAgent: public resip::ClientRegistrationHandler,
public resip::InviteSessionHandler,
public resip::DumShutdownHandler,
public resip::ExternalLogger,
public resip::DnsResultSink,
public resip::ClientSubscriptionHandler,
public resip::ServerSubscriptionHandler,
public resip::ClientPagerMessageHandler,
public resip::ServerPagerMessageHandler,
public resip::ClientPublicationHandler,
public resip::InternalTransport::TransportLogger
{
friend class Account;
friend class Session;
friend class ResipSession;
friend class NATDecorator;
friend class WatcherQueue;
public:
/* Compares two sip addresses. Returns true if they represent the same entity - user and domain are the same. Otherwise returns false. */
static bool compareSipAddresses(std::string sip1, std::string sip2);
static std::string formatSipAddress(std::string sip);
static bool isSipAddressValid(std::string sip);
struct SipAddress
{
bool mValid;
std::string mScheme;
std::string mUsername;
std::string mDomain;
std::string mDisplayname;
};
static SipAddress parseSipAddress(const std::string& sip);
UserAgent();
virtual ~UserAgent();
/* Brings user agent online. Basically it creates a signalling socket(s).
This is asynchronous method. */
void start();
/* Shutdowns user agent. It closes all sessions, tries to unregister from server and disconnects from it.
This is asynchronous method. onStop() event will be called later */
void shutdown();
/* Emergency stop. Please always call shutdown() before this. Kills registration, sessions & presence - everything. onStop() is called in context of this method. */
void stop();
/* Checks if user agent is active (started). */
bool active();
/* Used to refresh existing registration(s), publication, subscriptions. */
void refresh();
/* Runs sip & ice stacks. Event handlers are called in its context. */
void process();
/* Adds root cert in PEM format. Usable after start() call. */
void addRootCert(const ByteBuffer& data);
PAccount createAccount(PVariantMap config);
void deleteAccount(PAccount account);
/* Creates session. Returns session ID. */
PSession createSession(PAccount account);
// Must be called when IP interface list is changed
void updateInterfaceList();
// Called on new incoming session; providers shoukld
virtual PDataProvider onProviderNeeded(const std::string& name) = 0;
// Called on new session offer
virtual void onNewSession(PSession s) = 0;
// Called when session is terminated
virtual void onSessionTerminated(PSession s, int responsecode, int reason) = 0;
// Called when session is established ok i.e. after all ICE signalling is finished
// Conntype is type of establish event - EV_SIP or EV_ICE
virtual void onSessionEstablished(PSession s, int conntype, const RtpPair<InternetAddress>& p) = 0;
// Called when client session gets
virtual void onSessionProvisional(PSession s, int code) = 0;
// Called when user agent started
virtual void onStart(int errorcode) = 0;
// Called when user agent stopped
virtual void onStop() = 0;
// Called when account registered
virtual void onAccountStart(PAccount account) = 0;
// Called when account removed or failed (non zero error code)
virtual void onAccountStop(PAccount account, int error) = 0;
// Called when connectivity checks failed.
virtual void onConnectivityFailed(PSession s) = 0;
// Called when new candidate is gathered
virtual void onCandidateGathered(PSession s, const char* address);
// Called when network change detected
virtual void onNetworkChange(PSession s) = 0;
// Called when all candidates are gathered
virtual void onGathered(PSession s);
// Called when new connectivity check is finished
virtual void onCheckFinished(PSession s, const char* description);
// Called when log message must be recorded
virtual void onLog(const char* msg);
// Called when problem with SIP connection(s) detected
virtual void onSipConnectionFailed() = 0;
// Subscribe/publish presence methods
virtual void onPublicationSuccess(PAccount acc);
virtual void onPublicationTerminated(PAccount acc, int code);
virtual void onClientObserverStart(PClientObserver observer);
virtual void onServerObserverStart(PServerObserver observer);
virtual void onClientObserverStop(PClientObserver observer, int code);
virtual void onServerObserverStop(PServerObserver observer, int code);
virtual void onPresenceUpdate(PClientObserver observer, const std::string& peer, bool online, const std::string& content);
virtual void onMessageArrived(PAccount account, const std::string& peer, const void* ptr, unsigned length);
virtual void onMessageFailed(PAccount account, int id, const std::string& peer, int code, void* tag);
virtual void onMessageSent(PAccount account, int id, const std::string& peer, void* tag);
// Configuration methods
VariantMap& config();
public:
// InviteSessionHandler implementation
#pragma region InviteSessionHandler implementation
/// called when an initial INVITE or the intial response to an outoing invite
virtual void onNewSession(resip::ClientInviteSessionHandle, resip::InviteSession::OfferAnswerType oat, const resip::SipMessage& msg) override;
virtual void onNewSession(resip::ServerInviteSessionHandle, resip::InviteSession::OfferAnswerType oat, const resip::SipMessage& msg) override;
/// Received a failure response from UAS
virtual void onFailure(resip::ClientInviteSessionHandle, const resip::SipMessage& msg) override;
/// called when an in-dialog provisional response is received that contains an SDP body
virtual void onEarlyMedia(resip::ClientInviteSessionHandle, const resip::SipMessage&, const resip::SdpContents&) override;
/// called when dialog enters the Early state - typically after getting 18x
virtual void onProvisional(resip::ClientInviteSessionHandle, const resip::SipMessage&) override;
/// called when a dialog initiated as a UAC enters the connected state
virtual void onConnected(resip::ClientInviteSessionHandle, const resip::SipMessage& msg) override;
/// called when a dialog initiated as a UAS enters the connected state
virtual void onConnected(resip::InviteSessionHandle, const resip::SipMessage& msg) override;
virtual void onTerminated(resip::InviteSessionHandle, resip::InviteSessionHandler::TerminatedReason reason, const resip::SipMessage* related=0) override;
/// called when a fork that was created through a 1xx never receives a 2xx
/// because another fork answered and this fork was canceled by a proxy.
virtual void onForkDestroyed(resip::ClientInviteSessionHandle) override;
/// called when a 3xx with valid targets is encountered in an early dialog
/// This is different then getting a 3xx in onTerminated, as another
/// request will be attempted, so the DialogSet will not be destroyed.
/// Basically an onTermintated that conveys more information.
/// checking for 3xx respones in onTerminated will not work as there may
/// be no valid targets.
virtual void onRedirected(resip::ClientInviteSessionHandle, const resip::SipMessage& msg) override;
/// called when an SDP answer is received - has nothing to do with user
/// answering the call
virtual void onAnswer(resip::InviteSessionHandle, const resip::SipMessage& msg, const resip::SdpContents&) override;
/// called when an SDP offer is received - must send an answer soon after this
virtual void onOffer(resip::InviteSessionHandle, const resip::SipMessage& msg, const resip::SdpContents&) override;
/// called when an Invite w/out SDP is sent, or any other context which
/// requires an SDP offer from the user
virtual void onOfferRequired(resip::InviteSessionHandle, const resip::SipMessage& msg) override;
/// called if an offer in a UPDATE or re-INVITE was rejected - not real
/// useful. A SipMessage is provided if one is available
virtual void onOfferRejected(resip::InviteSessionHandle, const resip::SipMessage* msg) override;
/// called when INFO message is received
virtual void onInfo(resip::InviteSessionHandle, const resip::SipMessage& msg) override;
/// called when response to INFO message is received
virtual void onInfoSuccess(resip::InviteSessionHandle, const resip::SipMessage& msg) override;
virtual void onInfoFailure(resip::InviteSessionHandle, const resip::SipMessage& msg) override;
/// called when MESSAGE message is received
virtual void onMessage(resip::InviteSessionHandle, const resip::SipMessage& msg) override;
/// called when response to MESSAGE message is received
virtual void onMessageSuccess(resip::InviteSessionHandle, const resip::SipMessage& msg) override;
virtual void onMessageFailure(resip::InviteSessionHandle, const resip::SipMessage& msg) override;
/// called when an REFER message is received. The refer is accepted or
/// rejected using the server subscription. If the offer is accepted,
/// DialogUsageManager::makeInviteSessionFromRefer can be used to create an
/// InviteSession that will send notify messages using the ServerSubscription
virtual void onRefer(resip::InviteSessionHandle, resip::ServerSubscriptionHandle, const resip::SipMessage& msg) override;
virtual void onReferNoSub(resip::InviteSessionHandle, const resip::SipMessage& msg) override;
/// called when an REFER message receives a failure response
virtual void onReferRejected(resip::InviteSessionHandle, const resip::SipMessage& msg) override;
/// called when an REFER message receives an accepted response
virtual void onReferAccepted(resip::InviteSessionHandle, resip::ClientSubscriptionHandle, const resip::SipMessage& msg) override;
#pragma endregion
// ClientRegistrationHandler implementation
#pragma region ClientRegistrationHandler implementation
/// Called when registraion succeeds or each time it is sucessfully
/// refreshed.
void onSuccess(resip::ClientRegistrationHandle, const resip::SipMessage& response) override;
// Called when all of my bindings have been removed
void onRemoved(resip::ClientRegistrationHandle, const resip::SipMessage& response) override;
/// call on Retry-After failure.
/// return values: -1 = fail, 0 = retry immediately, N = retry in N seconds
int onRequestRetry(resip::ClientRegistrationHandle, int retrySeconds, const resip::SipMessage& response) override;
/// Called if registration fails, usage will be destroyed (unless a
/// Registration retry interval is enabled in the Profile)
void onFailure(resip::ClientRegistrationHandle, const resip::SipMessage& response) override;
#pragma endregion
#pragma region ExternalLogger implementation
/** return true to also do default logging, false to suppress default logging. */
virtual bool operator()(resip::Log::Level level,
const resip::Subsystem& subsystem,
const resip::Data& appName,
const char* file,
int line,
const resip::Data& message,
const resip::Data& messageWithHeaders) override;
#pragma endregion
#pragma region DnsResultSink implementation
virtual void onDnsResult(const resip::DNSResult<resip::DnsHostRecord>&) override;
virtual void onDnsResult(const resip::DNSResult<resip::DnsAAAARecord>&) override;
virtual void onDnsResult(const resip::DNSResult<resip::DnsSrvRecord>&) override;
virtual void onDnsResult(const resip::DNSResult<resip::DnsNaptrRecord>&) override;
virtual void onDnsResult(const resip::DNSResult<resip::DnsCnameRecord>&) override;
#pragma endregion
#pragma region TransportLogger implementation
void onSipMessage(int flow, const char* msg, unsigned int length, const sockaddr* addr, unsigned int addrlen) override;
#pragma endregion
#pragma region ClientPublicationHandler
void onSuccess(resip::ClientPublicationHandle, const resip::SipMessage& status) override;
void onRemove(resip::ClientPublicationHandle, const resip::SipMessage& status) override;
void onFailure(resip::ClientPublicationHandle, const resip::SipMessage& status) override;
int onRequestRetry(resip::ClientPublicationHandle, int retrySeconds, const resip::SipMessage& status) override;
#pragma endregion
#pragma region SubscriptionHandler
void onUpdate(resip::ClientSubscriptionHandle h, const resip::SipMessage& notify);
void onUpdatePending(resip::ClientSubscriptionHandle, const resip::SipMessage& notify, bool outOfOrder) override;
void onUpdateActive(resip::ClientSubscriptionHandle, const resip::SipMessage& notify, bool outOfOrder) override;
//unknown Subscription-State value
void onUpdateExtension(resip::ClientSubscriptionHandle, const resip::SipMessage& notify, bool outOfOrder) override;
int onRequestRetry(resip::ClientSubscriptionHandle, int retrySeconds, const resip::SipMessage& notify) override;
//subscription can be ended through a notify or a failure response.
void onTerminated(resip::ClientSubscriptionHandle, const resip::SipMessage* msg) override;
//not sure if this has any value.
void onNewSubscription(resip::ClientSubscriptionHandle, const resip::SipMessage& notify) override;
/// called to allow app to adorn a message.
void onReadyToSend(resip::ClientSubscriptionHandle, resip::SipMessage& msg) override;
void onNotifyNotReceived(resip::ClientSubscriptionHandle) override;
/// Called when a TCP or TLS flow to the server has terminated. This can be caused by socket
/// errors, or missing CRLF keep alives pong responses from the server.
// Called only if clientOutbound is enabled on the UserProfile and the first hop server
/// supports RFC5626 (outbound).
/// Default implementation is to re-form the subscription using a new flow
void onFlowTerminated(resip::ClientSubscriptionHandle) override;
void onNewSubscription(resip::ServerSubscriptionHandle, const resip::SipMessage& sub) override;
void onTerminated(resip::ServerSubscriptionHandle) override;
#pragma endregion
#pragma region PagerHandler
void onSuccess(resip::ClientPagerMessageHandle, const resip::SipMessage& status) override;
void onFailure(resip::ClientPagerMessageHandle, const resip::SipMessage& status, std::auto_ptr<resip::Contents> contents) override;
void onMessageArrived(resip::ServerPagerMessageHandle, const resip::SipMessage& message) override;
#pragma endregion
void onDumCanBeDeleted() override;
protected:
// Mutex to protect this instance
Mutex mGuard;
// Smart pointer to resiprocate's master profile instance. The stack configuration holds here.
resip::SharedPtr<resip::MasterProfile> mProfile;
// Resiprocate's SIP stack object pointer
resip::SipStack* mStack;
// Resiprocate's dialog usage manager object pointer
resip::DialogUsageManager* mDum;
// List of available transports. They are owned by SipStack - so there is no need to delete instances in UserAgent.
std::vector<resip::InternalTransport*> mTransportList;
typedef std::map<int, PSession> SessionMap;
// Session's map
SessionMap mSessionMap;
// Used configuration
VariantMap mConfig;
// Action vector
SIPActionVector mActionVector;
typedef std::map<int, PClientObserver> ClientObserverMap;
ClientObserverMap mClientObserverMap;
typedef std::map<int, PServerObserver> ServerObserverMap;
ServerObserverMap mServerObserverMap;
typedef std::set<PAccount> AccountSet;
AccountSet mAccountSet;
// Constructs and sends INVITE to remote peer. Remote peer address is stored inside session object.
void sendOffer(Session* session);
void internalStopSession(Session& session);
void processWatchingList();
bool handleMultipartRelatedNotify(const resip::SipMessage& notify);
PSession getUserSession(int sessionId);
PAccount getAccount(const resip::NameAddr& myAddr);
PAccount getAccount(Account* account);
PAccount getAccount(int sessionId);
};
#endif

View File

@@ -0,0 +1,182 @@
#include "EP_NetworkQueue.h"
#include "EP_Engine.h"
WatcherQueue::WatcherQueue(UserAgent& ua)
:mActiveId(0), mAgent(ua)
{}
WatcherQueue::~WatcherQueue()
{}
int WatcherQueue::add(std::string peer, std::string package, void* tag)
{
ice::Lock l(mGuard);
// Check if queue has similar item
for (unsigned i=0; i<mItemList.size(); i++)
{
Item& item = mItemList[i];
if (item.mTarget == peer && item.mPackage == package &&
item.mState != Item::State_Deleting)
return item.mId;
}
Item item;
item.mTarget = peer;
item.mPackage = package;
item.mTag = tag;
item.mState = Item::State_ScheduledToAdd;
item.mSession = new ResipSession(*mAgent.mDum);
item.mSession->setUa(&mAgent);
item.mSession->setType(ResipSession::Type_Subscription);
item.mSession->setTag(tag);
item.mId = item.mSession->sessionId();
item.mSession->setRemoteAddress(peer);
item.mTag = tag;
mItemList.push_back(item);
process();
return item.mId;
}
void WatcherQueue::remove(int id)
{
ice::Lock l(mGuard);
// Check if queue has similar item
for (unsigned i=0; i<mItemList.size(); i++)
{
Item& item = mItemList[i];
if (item.mId == id && !id)
{
if (item.mState != Item::State_Deleting)
item.mState = Item::State_ScheduledToDelete;
}
}
process();
}
void WatcherQueue::refresh(int id)
{
ice::Lock l(mGuard);
// Check if queue has similar item
for (unsigned i=0; i<mItemList.size(); i++)
{
Item& item = mItemList[i];
if (item.mId == id && !id)
{
if (item.mState == Item::State_ScheduledToDelete || item.mState == Item::State_Active)
item.mState = Item::State_ScheduledToRefresh;
}
}
process();
}
void WatcherQueue::process()
{
while (!mActiveId)
{
// Find next item to process
ItemList::iterator i = mItemList.begin();
for (;i != mItemList.end() && !i->scheduled(); i++)
;
if (i == mItemList.end())
return;
resip::SharedPtr<resip::SipMessage> msg;
int expires = DEFAULT_SUBSCRIPTION_TIME, refresh = DEFAULT_SUBSCRIPTION_REFRESHTIME;
switch (i->mState)
{
case Item::State_ScheduledToAdd:
if (mAgent.mConfig.exists(CONFIG_SUBSCRIPTION_TIME))
expires = mAgent.mConfig[CONFIG_SUBSCRIPTION_TIME].asInt();
if (mAgent.mConfig.exists(CONFIG_SUBSCRIPTION_REFRESHTIME))
refresh = mAgent.mConfig[CONFIG_SUBSCRIPTION_REFRESHTIME].asInt();
msg = mAgent.mDum->makeSubscription(resip::NameAddr(resip::Data(i->mTarget)), resip::Data(i->mPackage),
expires, refresh, i->mSession);
msg->header(resip::h_Accepts) = mAgent.mDum->getMasterProfile()->getSupportedMimeTypes(resip::NOTIFY);
mActiveId = i->mId;
i->mState = Item::State_Adding;
mAgent.mDum->send(msg);
break;
case Item::State_ScheduledToDelete:
i->mSession->runTerminatedEvent(ResipSession::Type_Subscription, 0, 0);
if (i->mHandle.isValid())
{
mActiveId = i->mId;
i->mHandle->end();
i->mState = Item::State_Deleting;
break;
}
else
mItemList.erase(i);
break;
case Item::State_ScheduledToRefresh:
if (i->mHandle.isValid())
{
mActiveId = i->mId;
i->mState = Item::State_Refreshing;
i->mHandle->requestRefresh();
}
else
mItemList.erase(i);
break;
default:
break;
}
}
}
void WatcherQueue::onTerminated(int id, int code)
{
ice::Lock l(mGuard);
ItemList::iterator i = findById(id);
if (i != mItemList.end())
{
if (i->mSession)
i->mSession->runTerminatedEvent(ResipSession::Type_Subscription, code, 0);
mItemList.erase(i);
if (i->mId == mActiveId)
mActiveId = 0;
}
process();
}
void WatcherQueue::onEstablished(int id, int code)
{
ice::Lock l(mGuard);
ItemList::iterator i = findById(id);
if (i != mItemList.end())
{
i->mState = Item::State_Active;
if (i->mId == mActiveId)
mActiveId = 0;
}
process();
}
WatcherQueue::ItemList::iterator WatcherQueue::findById(int id)
{
for (ItemList::iterator i=mItemList.begin(); i != mItemList.end(); i++)
if (i->mId == id)
return i;
return mItemList.end();
}
void WatcherQueue::clear()
{
ice::Lock l(mGuard);
for (ItemList::iterator i=mItemList.begin(); i != mItemList.end(); i++)
{
if (i->mHandle.isValid())
i->mHandle->end();
}
mItemList.clear();
}

View File

@@ -0,0 +1,69 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __NETWORK_QUEUE_H
#define __NETWORK_QUEUE_H
#include "EP_Session.h"
#include <resip/dum/ClientSubscription.hxx>
class UserAgent;
class WatcherQueue
{
public:
struct Item
{
enum State
{
State_None,
State_Active,
State_ScheduledToAdd,
State_Adding,
State_ScheduledToRefresh,
State_Refreshing,
State_ScheduledToDelete,
State_Deleting
};
resip::ClientSubscriptionHandle mHandle; // Subscription handle
ResipSession* mSession;
State mState;
std::string mTarget; // Target's address
std::string mPackage; // Event package
void* mTag; // User tag
int mId;
Item()
:mSession(NULL), mState(State_None), mTag(NULL), mId(0)
{}
bool scheduled()
{
return mState == State_ScheduledToAdd || mState == State_ScheduledToDelete || mState == State_ScheduledToRefresh;
}
};
WatcherQueue(UserAgent& agent);
~WatcherQueue();
int add(std::string peer, std::string package, void* tag);
void remove(int id);
void refresh(int id);
void clear();
void onTerminated(int id, int code);
void onEstablished(int id, int code);
protected:
typedef std::vector<Item> ItemList;
ItemList mItemList;
ice::Mutex mGuard;
UserAgent& mAgent;
int mActiveId;
void process();
ItemList::iterator findById(int id);
};
#endif

View File

@@ -0,0 +1,106 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "EP_Observer.h"
#include "EP_Session.h"
#include <resip/stack/Pidf.hxx>
#include <resip/dum/ClientSubscription.hxx>
ClientObserver::ClientObserver()
{
}
ClientObserver::~ClientObserver()
{
}
void ClientObserver::refresh()
{
if (mHandle.isValid())
mHandle->requestRefresh();
}
void ClientObserver::stop()
{
if (mHandle.isValid())
mHandle->end();
else
if (mSession)
{
mSession->runTerminatedEvent(ResipSession::Type_Subscription);
if (mSession)
mSession->end();
}
mSession = NULL;
}
std::string ClientObserver::peer()
{
return mPeer;
}
ServerObserver::ServerObserver()
:mState(State_Incoming)
{
}
ServerObserver::~ServerObserver()
{
stop();
}
std::string ServerObserver::peer() const
{
return mPeer;
}
std::string ServerObserver::package() const
{
return mPackage;
}
void ServerObserver::update(std::string simpleId, bool online, std::string msg)
{
if (mState != State_Active)
return;
resip::Pidf p;
p.setEntity(mContact);
p.setSimpleId(resip::Data(simpleId));
p.setSimpleStatus(online, resip::Data(msg));
if (mHandle.isValid())
mHandle->send(mHandle->update(&p));
}
void ServerObserver::accept()
{
if (mHandle.isValid() && mState == State_Incoming)
{
mState = State_Active;
mHandle->accept();
}
}
void ServerObserver::stop()
{
if (!mHandle.isValid())
return;
switch (mState)
{
case State_Incoming:
mHandle->reject(404);
break;
case State_Active:
mHandle->end();
break;
default:
break;
}
mState = State_Closed;
}

View File

@@ -0,0 +1,73 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef EP_OBSERVER_H
#define EP_OBSERVER_H
#include "../helper/HL_Pointer.h"
#include "../helper/HL_VariantMap.h"
#include "ice/ICEAddress.h"
#include "ice/ICETime.h"
#include "resip/dum/UserProfile.hxx"
#include "resip/dum/ClientRegistration.hxx"
#include "resip/dum/ClientPublication.hxx"
#include "resip/stack/DnsInterface.hxx"
class UserAgent;
class Session;
class ResipSession;
class ClientObserver
{
friend class Account;
friend class UserAgent;
public:
ClientObserver();
~ClientObserver();
void refresh();
void stop();
std::string peer();
protected:
resip::ClientSubscriptionHandle mHandle;
ResipSession* mSession;
int mSessionId;
std::string mPeer;
};
typedef SharedPtr<ClientObserver> PClientObserver;
class ServerObserver
{
friend class UserAgent;
public:
ServerObserver();
~ServerObserver();
std::string peer() const;
std::string package() const;
void accept();
void update(std::string simpleId, bool online, std::string msg);
void stop();
protected:
enum State
{
State_Incoming,
State_Active,
State_Closed
};
State mState;
resip::ServerSubscriptionHandle mHandle;
std::string mPeer, mPackage;
resip::Uri mContact;
int mSessionId;
};
typedef SharedPtr<ServerObserver> PServerObserver;
#endif // EP_OBSERVER_H

View File

@@ -0,0 +1,304 @@
/*
* Copyright (C) 2007-2012 Dmytro Bogovych <dmytro.bogovych@gmail.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 2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef _WIN32
# include <winsock2.h>
# include <windows.h>
#endif
#include <algorithm>
#include "EP_ReliableTunnel.h"
#include "EP_Engine.h"
#include "Log.h"
#include "../ICE/ICECRC32.h"
enum
{
CONFIRMATION_PT = 1,
DATA_PT = 2
};
#define CONFIRMATION_TIMEOUT 500
#define LOG_SUBSYSTEM "RT"
ReliableTunnel::ReliableTunnel(const char* streamname)
{
mStack.setEncryption(this);
mStreamName = streamname;
mBandwidth = 0;
mExitSignal = ::CreateEvent(NULL, FALSE, FALSE, NULL);
mDataSignal = ::CreateEvent(NULL, FALSE, FALSE, NULL);
}
ReliableTunnel::~ReliableTunnel()
{
::CloseHandle(mDataSignal);
::CloseHandle(mExitSignal);
}
std::string ReliableTunnel::streamName()
{
return mStreamName;
}
std::string ReliableTunnel::streamProfile()
{
return "RTP/DP";
}
void ReliableTunnel::setDestinationAddress(InternetAddress& addr)
{
mDestination = addr;
}
void ReliableTunnel::queueData(const void* bufferptr, int buffersize)
{
assert(bufferptr != NULL);
assert(buffersize != 0);
resip::Lock l(mNewQueuedGuard);
mNewQueued.push_back(std::string((const char*)bufferptr, buffersize));
::SetEvent(mDataSignal);
}
// This method is called by user agent to send ICE packet from mediasocket
void ReliableTunnel::sendData(InternetAddress& addr, const void* dataBuffer, unsigned int datasize)
{
switch (addr.type())
{
case AF_INET:
mSocket4.sendDatagram(addr, dataBuffer, datasize);
return;
case AF_INET6:
mSocket4.sendDatagram(addr, dataBuffer, datasize);
return;
}
}
void ReliableTunnel::sessionEstablished(int conntype)
{
// Start worker thread
if (conntype == EV_ICE)
run();
}
void ReliableTunnel::sessionTerminated()
{
// Stop worker thread
::SetEvent(mExitSignal);
shutdown();
join();
}
void ReliableTunnel::updateSdpOffer(resip::SdpContents::Session::Medium& sdp)
{
// Get new destination port
mDestination.setPort((unsigned short)sdp.port());
sdp.addCodec(resip::SdpContents::Session::Codec("rt", 104));
}
void ReliableTunnel::setSocket(DatagramSocket& socket4, DatagramSocket& socket6)
{
mSocket4 = socket4;
mSocket6 = socket6;
}
DatagramSocket& ReliableTunnel::socket(int family)
{
switch (family)
{
case AF_INET:
return mSocket4;
case AF_INET6:
return mSocket4;
default:
assert(0);
}
}
bool ReliableTunnel::processSdpOffer(const resip::SdpContents::Session::Medium& media)
{
//check for default port number
mDestination.setPort(media.port());
return true;
}
void ReliableTunnel::thread()
{
// Construct event array
while (true)
{
HANDLE eventarray[2] = { mDataSignal, mExitSignal };
DWORD rescode = ::WaitForMultipleObjects(2, eventarray, FALSE, INFINITE);
if (rescode == WAIT_OBJECT_0)
{
resip::Lock l(mNewQueuedGuard);
for (unsigned i = 0; i<mNewQueued.size(); i++)
mStack.queueOutgoing(mNewQueued[i].c_str(), mNewQueued[i].size());
mNewQueued.clear();
sendOutgoing();
}
else
break;
}
}
void ReliableTunnel::setBandwidth(unsigned int bytesPerSecond)
{
mBandwidth = bytesPerSecond;
}
unsigned int ReliableTunnel::bandwidth()
{
return mBandwidth;
}
void ReliableTunnel::processData(const void* dataptr, int datasize)
{
resip::Lock l(mStackGuard);
mStack.processIncoming(dataptr, datasize);
}
bool ReliableTunnel::hasData()
{
resip::Lock l(mStackGuard);
return mIncomingData.size() || mStack.hasAppData();
}
unsigned ReliableTunnel::getData(void* ptr, unsigned capacity)
{
resip::Lock l(mStackGuard);
char* dataOut = (char*)ptr;
while (capacity && hasData())
{
// Check if mIncomingData is empty
if (!mIncomingData.size())
{
unsigned available = mStack.appData(NULL);
if (!available)
return 0;
mIncomingData.resize(available);
mIncomingData.rewind();
mStack.appData(mIncomingData.mutableData());
}
if (mIncomingData.size())
{
unsigned toCopy = min(capacity, mIncomingData.size());
mIncomingData.dequeueBuffer(dataOut, toCopy);
dataOut += toCopy;
capacity -= toCopy;
}
}
return dataOut - (char*)ptr;
}
// Returns block size for encryption algorythm
int ReliableTunnel::blockSize()
{
return 8;
}
// Encrypts dataPtr buffer inplace. dataSize must be odd to GetBlockSize() returned value.
void ReliableTunnel::encrypt(void* dataPtr, int dataSize)
{
if (mEncryptionKey.empty())
return;
#ifdef USE_OPENSSL
for (unsigned i=0; i<dataSize / blockSize(); i++)
BF_ecb_encrypt((unsigned char*)dataPtr + i * blockSize(), (unsigned char*)dataPtr + i * blockSize(), &mCipher, BF_ENCRYPT);
#endif
#ifdef USE_CRYPTOPP
for (unsigned i=0; i<dataSize / blockSize(); i++)
mEncryptor.ProcessBlock((unsigned char*)dataPtr + i * blockSize());
#endif
}
// Decrypts dataPtr buffer inplace. dataSize must be odd to GetBlockSize() returned value.
void ReliableTunnel::decrypt(void* dataPtr, int dataSize)
{
if (mEncryptionKey.empty())
return;
#ifdef USE_OPENSSL
for (unsigned i=0; i<dataSize / blockSize(); i++)
BF_ecb_encrypt((unsigned char*)dataPtr + i * blockSize(), (unsigned char*)dataPtr + i * blockSize(), &mCipher, BF_DECRYPT);
#endif
#ifdef USE_CRYPTOPP
for (unsigned i=0; i<dataSize / blockSize(); i++)
mDecryptor.ProcessBlock((unsigned char*)dataPtr + i * blockSize());
#endif
}
// Calculates CRC
unsigned ReliableTunnel::crc(const void* dataptr, int datasize)
{
unsigned long result;
ICEImpl::CRC32 crc;
crc.fullCrc((const unsigned char*)dataptr, datasize, &result);
return result;
}
void ReliableTunnel::sendOutgoing()
{
// Check if stack has to send smth
if (mStack.hasPacketToSend())
{
// Get data to send
char buffer[2048];
int length = sizeof(buffer);
mStack.getPacketToSend(buffer, length);
// Send it over UDP
sendData(this->mDestination, buffer, length);
}
}
void ReliableTunnel::setEncryptionKey(void* ptr, unsigned length)
{
#ifdef USE_OPENSSL
BF_set_key(&mCipher, length, (const unsigned char*)ptr);
#endif
#ifdef USE_CRYPTOPP
mEncryptor.SetKey((unsigned char*)ptr, length);
mDecryptor.SetKey((unsigned char*)ptr, length);
#endif
// Save key
mEncryptionKey = std::string((const char*)ptr, length);
}

View File

@@ -0,0 +1,147 @@
/*
* Copyright (C) 2007-2010 Dmytro Bogovych <dmytro.bogovych@gmail.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 2 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __RELIABLE_TUNNEL_H
#define __RELIABLE_TUNNEL_H
#include "DataProvider.h"
#include "InternetAddress.h"
#include "rutil/ThreadIf.hxx"
#include <vector>
#include <string>
#include "../ICE/ICEReliableTransport.h"
#ifdef USE_CRYPTOPP
# include "../Libs/CryptoPP/blowfish.h"
#endif
#ifdef USE_OPENSSL
# include "../Libs/openssl/include/openssl/blowfish.h"
#endif
class ReliableTunnel: public DataProvider, public resip::ThreadIf, public ICEImpl::ReliableTransport::Encryption
{
public:
ReliableTunnel(const char* streamname);
virtual ~ReliableTunnel();
// Returns provider RTP name
virtual std::string streamName();
// Returns provider RTP profile name
virtual std::string streamProfile();
// Sets destination IP address
virtual void setDestinationAddress(InternetAddress& addr);
// Processes incoming data
virtual void processData(const void* dataBuffer, int dataSize);
// This method is called by user agent to send ICE packet from mediasocket
virtual void sendData(InternetAddress& destination, const void* dataBuffer, unsigned int datasize);
// Updates SDP offer
virtual void updateSdpOffer(resip::SdpContents::Session::Medium& sdp);
// Called by user agent when session is terminated.
virtual void sessionTerminated();
// Called by user agent when session is started.
virtual void sessionEstablished(int conntype);
// Called by user agent to save media socket for this provider
virtual void setSocket(DatagramSocket& socket4, DatagramSocket& socket6);
// Called by user agent to get media socket for this provider
virtual DatagramSocket& socket(int family);
// Called by user agent to process media stream description from remote peer.
// Returns true if description is processed succesfully. Otherwise method returns false.
virtual bool processSdpOffer(const resip::SdpContents::Session::Medium& media);
virtual void thread();
// Enqueues outgoing packet to sending queue
void queueData(const void* bufferPtr, int bufferSize);
void setBandwidth(unsigned int bytesPerSecond);
unsigned int bandwidth();
// Checks if there is any received application data
bool hasData();
// Reads received data. If ptr is NULL - the length of available data is returned.
unsigned getData(void* ptr, unsigned capacity);
void setEncryptionKey(void* ptr, unsigned length);
protected:
// SDP's stream name
std::string mStreamName;
// Transport stack
ICEImpl::ReliableTransport mStack;
// Socket handles to operate
DatagramSocket mSocket4;
DatagramSocket mSocket6;
// Destination IP4/6 address
InternetAddress mDestination;
// Win32 exit signal
HANDLE mExitSignal;
// Win32 "new outgoing data" signal
HANDLE mDataSignal;
// Mutex to protect queuing/sending outgoing data
resip::Mutex mOutgoingMtx;
std::vector<std::string>
mNewQueued;
resip::Mutex mNewQueuedGuard;
resip::Mutex mStackGuard;
unsigned int mBandwidth;
std::string mEncryptionKey;
#ifdef USE_CRYPTOPP
CryptoPP::BlowfishEncryption mEncryptor;
CryptoPP::BlowfishDecryption mDecryptor;
#endif
#ifdef USE_OPENSSL
BF_KEY mCipher;
#endif
ICEImpl::ICEByteBuffer mIncomingData;
// Returns block size for encryption algorythm
int blockSize();
// Encrypts dataPtr buffer inplace. dataSize must be odd to GetBlockSize() returned value.
void encrypt(void* dataPtr, int dataSize);
// Decrypts dataPtr buffer inplace. dataSize must be odd to GetBlockSize() returned value.
void decrypt(void* dataPtr, int dataSize);
// Calculates CRC
unsigned crc(const void* dataptr, int datasize);
void sendOutgoing();
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,410 @@
/* Copyright(C) 2007-2014 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __SESSION_H
#define __SESSION_H
#include "resip/stack/SdpContents.hxx"
#include "resip/stack/SipMessage.hxx"
#include "resip/stack/ShutdownMessage.hxx"
#include "resip/stack/SipStack.hxx"
#include "resip/dum/ClientAuthManager.hxx"
#include "resip/dum/ClientInviteSession.hxx"
#include "resip/dum/ClientRegistration.hxx"
#include "resip/dum/DialogUsageManager.hxx"
#include "resip/dum/DumShutdownHandler.hxx"
#include "resip/dum/InviteSessionHandler.hxx"
#include "resip/dum/MasterProfile.hxx"
#include "resip/dum/RegistrationHandler.hxx"
#include "resip/dum/ServerInviteSession.hxx"
#include "resip/dum/ServerOutOfDialogReq.hxx"
#include "resip/dum/OutOfDialogHandler.hxx"
#include "resip/dum/AppDialog.hxx"
#include "resip/dum/AppDialogSet.hxx"
#include "resip/dum/AppDialogSetFactory.hxx"
#include "rutil/Log.hxx"
#include "rutil/Logger.hxx"
#include "rutil/Random.hxx"
#include "rutil/WinLeakCheck.hxx"
#include "rutil/AtomicCounter.hxx"
#include "../ice/ICEBox.h"
#include <sstream>
#include <time.h>
#include "../config.h"
#include "EP_Session.h"
#include "EP_Account.h"
#include "EP_DataProvider.h"
#include "EP_AudioProvider.h"
#include "../helper/HL_VariantMap.h"
#include "../helper/HL_SocketHeap.h"
using namespace std;
class UserAgent;
class ResipSession;
enum SessionInfo
{
SessionInfo_RemoteSipAddress, // remote sip address
SessionInfo_ReceivedTraffic, // amount of received traffic in session in bytes
SessionInfo_SentTraffic, // amount of sent traffic in session in bytes
SessionInfo_PacketLoss, // lost packets counter; returns number of 1/1000 fractions (0.1%)
SessionInfo_AudioPeer, // remote peer rtp address in text
SessionInfo_AudioCodec, // selected audio codec as text
SessionInfo_DtmfInterface, // Pointer to DtmfQueue class; returned as void*
SessionInfo_IceState,
SessionInfo_NetworkMos,
SessionInfo_PvqaMos,
SessionInfo_PvqaReport,
SessionInfo_SentRtp,
SessionInfo_SentRtcp,
SessionInfo_ReceivedRtp,
SessionInfo_ReceivedRtcp,
SessionInfo_LostRtp,
SessionInfo_Duration,
SessionInfo_Jitter,
SessionInfo_Rtt,
SessionInfo_BitrateSwitchCounter, // It is for AMR codecs only
SessionInfo_RemotePeer,
SessionInfo_SSRC
};
class Session :
public SocketSink,
public ice::StageHandler
{
public:
class Command
{
public:
virtual void run(Session& s) = 0;
};
// Describes ice stream/component
struct IceInfo
{
IceInfo()
:mStreamId(-1)
{
mPort4 = mPort6 = 0;
mComponentId.mRtp = mComponentId.mRtcp = -1;
}
RtpPair<int> mComponentId;
int mStreamId;
unsigned short mPort4;
unsigned short mPort6;
};
// Describes media stream (audio/video) in session
class Stream
{
public:
Stream();
~Stream();
void setProvider(PDataProvider provider);
PDataProvider provider();
void setSocket4(const RtpPair<PDatagramSocket>& socket);
RtpPair<PDatagramSocket>& socket4();
void setSocket6(const RtpPair<PDatagramSocket>& socket);
RtpPair<PDatagramSocket>& socket6();
void setIceInfo(const IceInfo& info);
IceInfo iceInfo() const;
// rtcpAttr/rtcpMuxAttr signals about corresponding sip attribute in offer/answer from remote peer
bool rtcpAttr() const;
void setRtcpAttr(bool value);
bool rtcpMuxAttr() const;
void setRtcpMuxAttr(bool value);
protected:
// Provider for corresponding stream
PDataProvider mProvider;
// Socket for stream
RtpPair<PDatagramSocket> mSocket4, mSocket6;
bool mRtcpAttr;
bool mRtcpMuxAttr;
IceInfo mIceInfo;
};
Session(PAccount account);
virtual ~Session();
// Starts call to specified peer
void start(const std::string& peer);
// Stops call
void stop();
// Accepts call
void accept();
// Rejects call
void reject(int code);
enum class InfoOptions
{
Standard = 0,
Detailed = 1,
};
void getSessionInfo(InfoOptions options, VariantMap& result);
// Returns integer identifier of the session; it is unique amongst all session in application
int id() const;
// Returns owning account
PAccount account();
typedef std::map<std::string, std::string> UserHeaders;
void setUserHeaders(const UserHeaders& headers);
// Called when new media data are available for this session
void onReceivedData(PDatagramSocket socket, InternetAddress& src, const void* receivedPtr, unsigned receivedSize);
// Called when new candidate is gathered
void onCandidateGathered(ice::Stack* stack, void* tag, const char* address);
// Called when connectivity check is finished
void onCheckFinished(ice::Stack* stack, void* tag, const char* checkDescription);
// Called when ICE candidates are gathered - with success or timeout.
void onGathered(ice::Stack* stack, void* tag);
// Called when ICE connectivity check is good at least for one of required streams
void onSuccess(ice::Stack* stack, void* tag);
// Called when ICE connectivity check is failed for all of required streams
void onFailed(ice::Stack* stack, void* tag);
// Called when ICE stack detects network change during the call
void onNetworkChange(ice::Stack* stack, void* tag);
// Fills SDP according to ICE and provider's data
void buildSdp(resip::SdpContents& sdp, SdpDirection sdpDirection);
// Searches provider by its local port number
PDataProvider findProviderByPort(int family, unsigned short port);
// Add provider to internal list
void addProvider(PDataProvider provider);
PDataProvider providerAt(int index);
int getProviderCount();
void setUserAgent(UserAgent* agent);
UserAgent* userAgent();
// Pauses and resumes all providers; updates states
void pause();
void resume();
void refreshMediaPath();
// Processes new sdp from offer. Returns response code (200 is ok, 488 bad codec, 503 internal error).
int processSdp(UInt64 version, bool iceAvailable, std::string icePwd, std::string iceUfrag,
std::string remoteIp, const resip::SdpContents::Session::MediumContainer& media);
// Session ID
int mSessionId;
// Media streams collection
std::vector<Stream> mStreamList;
// Smart pointer to ICE stack. Actually stack is created in CreateICEStack() method
resip::SharedPtr<ice::Stack> mIceStack;
// Pointer to owner user agent instance
UserAgent* mUserAgent;
// Remote peer SIP address
resip::NameAddr mRemotePeer;
// Mutex to protect this instance
Mutex mGuard;
// SDP's origin version for sending
int mOriginVersion;
UInt64 mRemoteOriginVersion;
// SDP's session version
int mSessionVersion;
// Marks if this session does not need OnNewSession event
bool mAcceptedByEngine;
bool mAcceptedByUser;
// Invite session handle
resip::InviteSessionHandle mInviteHandle;
// Dialog set object pointer
ResipSession* mResipSession;
// Reference counter
int mRefCount;
enum
{
Initiator = 1,
Acceptor = 2
};
// Specifies session role - caller (Initiator) or callee (Acceptor)
volatile int mRole;
// Marks if candidates are gather already
volatile bool mGatheredCandidates;
// Marks if OnTerminated event was called already on session
volatile bool mTerminated;
// User friend remote peer's sip address
std::string mRemoteAddress;
// Application specific data
void* mTag;
// Used to count number of transistions to Connected state and avoid multiple onEstablished events.
int mOfferAnswerCounter;
// List of turn prefixes related to sessioj
std::vector<int> mTurnPrefixList;
// True if user agent has to send offer
bool mHasToSendOffer;
// True if user agent has to enqueue offer after ice gather finished
bool mSendOfferUpdateAfterIceGather;
// Related sip account
PAccount mAccount;
// User headers for INVITE transaction
UserHeaders mUserHeaders;
std::string remoteAddress() const;
void setRemoteAddress(const std::string& address);
void* tag();
void setTag(void* tag);
int sessionId();
int increaseSdpVersion();
int addRef();
int release();
// Deletes providers and media sockets
void clearProvidersAndSockets();
// Deletes providers
void clearProviders();
// Helper method to find audio provider for active sip stream
AudioProvider* findProviderForActiveAudio();
void processCommandList();
void addCommand(Command* cmd);
void enqueueOffer();
void processQueuedOffer();
static int generateId();
static resip::AtomicCounter IdGenerator;
static resip::AtomicCounter InstanceCounter;
};
typedef SharedPtr<Session> PSession;
/////////////////////////////////////////////////////////////////////////////////
//
// Classes that provide the mapping between Application Data and DUM
// dialogs/dialogsets
//
// The DUM layer creates an AppDialog/AppDialogSet object for inbound/outbound
// SIP Request that results in Dialog creation.
//
/////////////////////////////////////////////////////////////////////////////////
class ResipSessionAppDialog : public resip::AppDialog
{
public:
ResipSessionAppDialog(resip::HandleManager& ham);
virtual ~ResipSessionAppDialog();
};
class ResipSession: public resip::AppDialogSet
{
friend class UserAgent;
friend class Account;
public:
enum Type
{
Type_None,
Type_Registration,
Type_Subscription,
Type_Call,
Type_Auto
};
static resip::AtomicCounter InstanceCounter;
ResipSession(resip::DialogUsageManager& dum);
virtual ~ResipSession();
virtual resip::AppDialog* createAppDialog(const resip::SipMessage& msg);
virtual resip::SharedPtr<resip::UserProfile> selectUASUserProfile(const resip::SipMessage& msg);
void setType(Type type);
Type type();
Session* session();
void setSession(Session* session);
UserAgent* ua();
void setUa(UserAgent* ua);
// Used for subscriptions/messages
int sessionId();
// Used for subscriptions/messages
void* tag() const;
void setTag(void* tag);
// Used for subscriptions/messages
std::string remoteAddress() const;
void setRemoteAddress(std::string address);
void runTerminatedEvent(Type type, int code = 0, int reason = 0);
void setUASProfile(SharedPtr<resip::UserProfile> profile);
protected:
bool mTerminated;
UserAgent* mUserAgent;
Type mType;
Session* mSession;
int mSessionId;
std::string mRemoteAddress;
void* mTag;
bool mOnWatchingStartSent;
SharedPtr<resip::UserProfile> mUASProfile;
};
class ResipSessionFactory : public resip::AppDialogSetFactory
{
public:
ResipSessionFactory(UserAgent* agent);
virtual resip::AppDialogSet* createAppDialogSet(resip::DialogUsageManager& dum, const resip::SipMessage& msg);
protected:
UserAgent* mAgent;
};
#endif