Files
rtphone/src/libs/ice/ICEBoxImpl.cpp

447 lines
12 KiB
C++

/* Copyright(C) 2007-2018 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 "ICEBoxImpl.h"
#include "ICELog.h"
#include <assert.h>
#define LOG_SUBSYSTEM "ICE"
using namespace ice;
StackImpl::StackImpl(const ServerConfig& config)
:mConfig(config), mEventHandler(NULL), mEventTag(NULL), mTimeout(false), mActionTimestamp(0)
{
setup(config);
}
StackImpl::~StackImpl()
{
}
void StackImpl::setEventHandler(StageHandler* handler, void* tag)
{
mEventHandler = handler;
mEventTag = tag;
}
int StackImpl::addStream()
{
return mSession.addStream();
}
int StackImpl::addComponent(int streamID, void* tag, unsigned short port4, unsigned short port6)
{
return mSession.addComponent(streamID, tag, port4, port6);
}
void StackImpl::removeStream(int streamID)
{
mSession.removeStream(streamID);
}
bool StackImpl::findStreamAndComponent(int family, unsigned short port, int* stream, int* component)
{
return mSession.findStreamAndComponent(family, port, stream, component);
}
bool StackImpl::hasStream(int streamId)
{
return mSession.hasStream(streamId);
}
bool StackImpl::hasComponent(int streamId, int componentId)
{
return mSession.hasComponent(streamId, componentId);
}
void StackImpl::setComponentPort(int streamId, int componentId, unsigned short port4, unsigned short port6)
{
mSession.setComponentPort(streamId, componentId, port4, port6);
}
void StackImpl::setRole(AgentRole role)
{
mSession.setRole(role);
}
AgentRole StackImpl::role()
{
return mSession.role();
}
bool StackImpl::processIncomingData(int stream, int component, ByteBuffer& incomingData)
{
#if defined(ICE_EMULATE_SYMMETRIC_NAT) //&& (TARGET_IPHONE_SIMULATOR)
if (!isRelayHost(incomingData.remoteAddress()))
{
ICELogDebug(<<"Discard packet as symmetric NAT is emulating now");
return false;
}
#endif
if (incomingData.remoteAddress().isEmpty())
{
ICELogDebug(<< "Incoming packet; remote address is unknown");
incomingData.setRemoteAddress(NetworkAddress::LoopbackAddress4);
}
else
{
ICELogDebug(<< "Incoming packet from " << incomingData.remoteAddress().toStdString());
}
// Save previous ICE stack state
int icestate = state();
incomingData.setComponent(component);
bool result = mSession.processData(incomingData, stream, component);
// Run handlers
if (result && mEventHandler)
{
int newicestate = state();
if (icestate < IceCheckSuccess && newicestate >= IceCheckSuccess)
{
// Connectivity check finished
if (newicestate == IceCheckSuccess)
mEventHandler->onSuccess(this, mEventTag);
else
mEventHandler->onFailed(this, mEventTag);
}
else
if (icestate < IceGathered && newicestate >= IceGathered)
{
// Candidates are gathered
mEventHandler->onGathered(this, mEventTag);
}
}
return result;
}
PByteBuffer StackImpl::generateOutgoingData(bool& response, int& stream, int& component, void*& tag)
{
// Get current timestamp
unsigned timestamp = ICETimeHelper::timestamp();
// Find amount of spent time
unsigned spent = ICETimeHelper::findDelta(mActionTimestamp, timestamp);
// Check for timeout
if (mConfig.mTimeout && spent > mConfig.mTimeout)
{
ice::RunningState sessionState = mSession.state();
bool timeout = sessionState == ice::ConnCheck || sessionState == ice::CandidateGathering;
if (!mTimeout && timeout)
{
// Mark stack as timeouted
mTimeout = true;
ICELogInfo(<< "Timeout detected.");
if (sessionState == ice::CandidateGathering)
mSession.cancelAllocations();
// Find default address amongst host candidates
mSession.chooseDefaults();
if (mEventHandler)
{
if (sessionState == ice::ConnCheck)
{
// Session should not be cleared here - the CT uses direct path for connectivity checks and relayed if checks are failed. Relayed allocations will not be refreshed in such case
mEventHandler->onFailed(this, this->mEventTag);
}
else
mEventHandler->onGathered(this, this->mEventTag);
}
}
if (timeout)
{
// Check if keepalive transactions are scheduled
if (!mSession.hasAllocations())
return PByteBuffer();
}
}
// No timeout, proceed...
PByteBuffer result = mSession.getDataToSend(response, stream, component, tag);
if (result)
ICELogInfo(<< "Sending: " << result->comment() << " to " << result->remoteAddress().toStdString() << ". Data: \r\n" << result->hexstring());
return result;
}
void StackImpl::gatherCandidates()
{
mActionTimestamp = ICETimeHelper::timestamp();
mSession.gatherCandidates();
// If there is no STUN server set or IP6 only interfaces - the candidate gathering can finish without network I/O
if (mSession.state() == CreatingSDP && mEventHandler)
mEventHandler->onGathered(this, mEventTag);
}
void StackImpl::checkConnectivity()
{
// Connectivity check can work if candidate gathering timeout-ed yet - it relies on host candidates only in this case
// So timeout flag is reset
mTimeout = false;
mActionTimestamp = ICETimeHelper::timestamp();
mSession.checkConnectivity();
}
void StackImpl::stopChecks()
{
mTimeout = false;
mActionTimestamp = 0;
mSession.stopChecks();
}
IceState StackImpl::state()
{
if (mTimeout)
return IceTimeout;
switch (mSession.state())
{
case ice::None: return IceNone;
case ice::CandidateGathering: return IceGathering;
case ice::CreatingSDP: return IceGathered;
case ice::ConnCheck: return IceChecking;
case ice::Failed: return IceFailed;
case ice::Success: return IceCheckSuccess;
default:
break;
}
assert(0);
return IceNone; // to avoid compiler warning
}
void StackImpl::createSdp(std::vector<std::string>& commonPart)
{
mSession.createSdp(commonPart);
}
NetworkAddress StackImpl::defaultAddress(int stream, int component)
{
return mSession.defaultAddress(stream, component);
}
void StackImpl::fillCandidateList(int streamID, int componentID, std::vector<std::string>& candidateList)
{
mSession.fillCandidateList(streamID, componentID, candidateList);
}
bool StackImpl::processSdpOffer(int streamIndex, std::vector<std::string>& candidateList,
const std::string& defaultIP, unsigned short defaultPort, bool deleteRelayed)
{
return mSession.processSdpOffer(streamIndex, candidateList, defaultIP, defaultPort, deleteRelayed);
}
NetworkAddress StackImpl::getRemoteRelayedCandidate(int stream, int component)
{
return mSession.getRemoteRelayedCandidate(stream, component);
}
NetworkAddress StackImpl::getRemoteReflexiveCandidate(int stream, int component)
{
return mSession.getRemoteReflexiveCandidate(stream, component);
}
void StackImpl::setRemotePassword(const std::string& pwd, int streamId)
{
mSession.setRemotePassword(pwd, streamId);
}
std::string StackImpl::remotePassword(int streamId) const
{
return mSession.remotePassword(streamId);
}
void StackImpl::setRemoteUfrag(const std::string& ufrag, int streamId)
{
mSession.setRemoteUfrag(ufrag, streamId);
}
std::string StackImpl::remoteUfrag(int streamId) const
{
return mSession.remoteUfrag(streamId);
}
std::string StackImpl::localPassword() const
{
return mSession.mLocalPwd;
}
std::string StackImpl::localUfrag() const
{
return mSession.mLocalUfrag;
}
bool StackImpl::hasTurnPrefix(unsigned short prefix)
{
return mSession.hasTurnPrefix((TurnPrefix)prefix);
}
NetworkAddress StackImpl::remoteAddress(int stream, int component)
{
return mSession.remoteAddress(stream, component);
}
NetworkAddress StackImpl::localAddress(int stream, int component)
{
return mSession.localAddress(stream, component);
}
bool StackImpl::findConcludePair(int stream, Candidate& local, Candidate& remote)
{
// Find nominated pair in stream
return mSession.findConcludePair(stream, local, remote);
}
bool StackImpl::candidateListContains(int stream, const std::string& remoteIP, unsigned short remotePort)
{
return mSession.mStreamMap[stream]->candidateListContains(remoteIP, remotePort);
}
void StackImpl::dump(std::ostream& output)
{
mSession.dump(output);
}
bool StackImpl::mustRestart()
{
return mSession.mustRestart();
}
void StackImpl::clear()
{
mSession.clear();
mActionTimestamp = 0;
mTimeout = false;
}
void StackImpl::clearForRestart(bool localNetworkChanged)
{
mSession.clearForRestart(localNetworkChanged);
mActionTimestamp = 0;
mTimeout = false;
}
void StackImpl::refreshPwdUfrag()
{
mSession.refreshPwdUfrag();
}
TurnPrefix StackImpl::bindChannel(int stream, int component, const ice::NetworkAddress &target, ChannelBoundCallback* cb)
{
return mSession.bindChannel(stream, component, target, cb);
}
bool StackImpl::isChannelBindingFailed(int stream, int component, TurnPrefix prefix)
{
return mSession.isChannelBindingFailed(stream, component, prefix);
}
void StackImpl::installPermissions(int stream, int component, const NetworkAddress &address, InstallPermissionsCallback* cb)
{
mSession.installPermissions(stream, component, address, cb);
}
void StackImpl::freeAllocation(int stream, int component, DeleteAllocationCallback* cb)
{
mSession.freeAllocation(stream, component, cb);
}
bool StackImpl::hasAllocations()
{
return mSession.hasAllocations();
}
int StackImpl::errorCode()
{
return mSession.errorCode();
}
std::vector<Candidate>* StackImpl::remoteCandidates(int stream)
{
return mSession.remoteCandidates(stream);
}
NetworkAddress StackImpl::activeStunServer(int stream) const
{
return mSession.activeStunServer(stream);
}
void StackImpl::setup(const ServerConfig& config)
{
mConfig = config;
mSession.mConfig.mServerList4 = config.mServerList4;
mSession.mConfig.mServerList6 = config.mServerList6;
// Set initial STUN/TURN server IP for case if there will no gathering candidates & selecting fastest server.
if (mSession.mConfig.mServerList4.size())
mSession.mConfig.mServerAddr4 = mSession.mConfig.mServerList4.front();
if (mSession.mConfig.mServerList6.size())
mSession.mConfig.mServerAddr6 = mSession.mConfig.mServerList6.front();
mSession.mConfig.mUseIPv4 = config.mUseIPv4;
mSession.mConfig.mUseIPv6 = config.mUseIPv6;
if (mConfig.mRelay)
{
mSession.mConfig.mTurnPassword = config.mPassword;
mSession.mConfig.mTurnUsername = config.mUsername;
mSession.mConfig.mUseTURN = true;
mSession.mConfig.mUseSTUN = false;
}
else
{
mSession.mConfig.mUseTURN = false;
mSession.mConfig.mUseSTUN = true;
}
mSession.mConfig.mTimeout = config.mTimeout;
mSession.setup(mSession.mConfig);
}
bool StackImpl::isRelayHost(const NetworkAddress& remote)
{
for (unsigned i=0; i<mConfig.mServerList4.size(); i++)
{
if (NetworkAddress::isSameHost(mConfig.mServerList4[i], remote))
return true;
}
for (unsigned i=0; i<mConfig.mServerList6.size(); i++)
{
if (NetworkAddress::isSameHost(mConfig.mServerList6[i], remote))
return true;
}
return false;
}
bool StackImpl::isRelayAddress(const NetworkAddress& remote)
{
for (unsigned i=0; i<mConfig.mServerList4.size(); i++)
{
if (mConfig.mServerList4[i] == remote)
return true;
}
for (unsigned i=0; i<mConfig.mServerList6.size(); i++)
{
if (mConfig.mServerList6[i] == remote)
return true;
}
return false;
}