- initial import
This commit is contained in:
493
src/libs/ice/ICEStunTransaction.cpp
Normal file
493
src/libs/ice/ICEStunTransaction.cpp
Normal file
@@ -0,0 +1,493 @@
|
||||
/* 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 "ICEPlatform.h"
|
||||
#include "ICEStunTransaction.h"
|
||||
#include "ICEStunAttributes.h"
|
||||
#include "ICELog.h"
|
||||
#include "ICEError.h"
|
||||
#include "ICEAction.h"
|
||||
#include "ICETime.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
# include <stdexcept>
|
||||
#endif
|
||||
|
||||
using namespace ice;
|
||||
#define LOG_SUBSYSTEM "ICE"
|
||||
|
||||
const char* Transaction::stateToString(State state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case Running: return "Running";
|
||||
case Failed: return "Failed";
|
||||
case Success: return "Success";
|
||||
}
|
||||
return "Undefined";
|
||||
}
|
||||
|
||||
Transaction::Transaction()
|
||||
{
|
||||
mTransportType = IPv4;
|
||||
|
||||
// There is no default ICE stack
|
||||
mStackID = 0;
|
||||
|
||||
// There is no default logger
|
||||
mLog = NULL;
|
||||
|
||||
// Packet is not composed in constructor
|
||||
mComposed = false;
|
||||
|
||||
// Initial state of transaction - "Running"
|
||||
mState = Transaction::Running;
|
||||
|
||||
// Reset user data
|
||||
mTag = 0;
|
||||
|
||||
// Do not use message integrity attribute by default
|
||||
mMessageIntegrity = false;
|
||||
|
||||
// Do not use fingerprint attribute by default
|
||||
mFingerprint = false;
|
||||
|
||||
// Do not use long term credentials by default
|
||||
mLongTerm = false;
|
||||
|
||||
// Do not use short term credentials by default
|
||||
mShortTerm = false;
|
||||
|
||||
// Create new transaction ID
|
||||
generateId();
|
||||
|
||||
// CONTROLLING attribute is not used by default
|
||||
mEnableControlling = false;
|
||||
|
||||
// CONTROLLED attribute is not used by default
|
||||
mEnableControlled = false;
|
||||
|
||||
// PRIORITY attribute is not used by default
|
||||
mEnablePriority = false;
|
||||
mPriority = 0;
|
||||
|
||||
// Transaction is not cancelled
|
||||
mCancelled = false;
|
||||
|
||||
// Transaction is not relayed by default
|
||||
mRelayed = false;
|
||||
|
||||
// Component port is not set by default
|
||||
mComponent = 0;
|
||||
|
||||
mKeepalive = false;
|
||||
mInterval = 0;
|
||||
mUserObject = NULL;
|
||||
mType = None;
|
||||
mRemoved = false;
|
||||
mFailoverId = 0;
|
||||
}
|
||||
|
||||
Transaction::~Transaction()
|
||||
{
|
||||
}
|
||||
|
||||
void Transaction::generateId()
|
||||
{
|
||||
for (size_t i=0; i<12; i++)
|
||||
mTransactionID.mValue[i] = rand();
|
||||
}
|
||||
void Transaction::setStackId(int id)
|
||||
{
|
||||
mStackID = id;
|
||||
}
|
||||
|
||||
int Transaction::stackId()
|
||||
{
|
||||
return mStackID;
|
||||
}
|
||||
|
||||
void Transaction::setTransportType(int _type)
|
||||
{
|
||||
assert(_type == IPv4 || _type == IPv6);
|
||||
mTransportType = _type;
|
||||
}
|
||||
|
||||
int Transaction::transportType()
|
||||
{
|
||||
return mTransportType;
|
||||
}
|
||||
|
||||
std::string Transaction::toStdString()
|
||||
{
|
||||
std::ostringstream output;
|
||||
output << "State: " << Transaction::stateToString(mState) << ", ";
|
||||
output << "Transport: " << (mTransportType == IPv4 ? "IPv4" : "IPv6") << ", ";
|
||||
output << (mCancelled ? "Cancelled, " : "");
|
||||
output << "Destination: " << mDestination.toStdString().c_str() << ", ";
|
||||
output << "Comment: " << mComment.c_str();
|
||||
|
||||
return output.str();
|
||||
}
|
||||
|
||||
void Transaction::setTag(unsigned int tag)
|
||||
{
|
||||
mTag = tag;
|
||||
}
|
||||
|
||||
unsigned Transaction::tag()
|
||||
{
|
||||
return mTag;
|
||||
}
|
||||
|
||||
void Transaction::enqueueMessage(ice::StunMessage& msg)
|
||||
{
|
||||
// Clear outgoing buffer
|
||||
mOutgoingData.clear();
|
||||
|
||||
// Check if message should be secured by message integrity
|
||||
std::string password = mPassword;
|
||||
if (true == mMessageIntegrity)
|
||||
{
|
||||
// Ensure credentials are enabled
|
||||
assert(mLongTerm || mShortTerm);
|
||||
|
||||
// Create username attribute
|
||||
Username* attr = new Username();
|
||||
|
||||
// Set username value
|
||||
if (mLongTerm || mShortTerm)
|
||||
attr->setValue(mUsername);
|
||||
|
||||
// Add username attribute itself
|
||||
msg.setAttribute(attr);
|
||||
|
||||
// Add message integrity attribute
|
||||
msg.setAttribute(new MessageIntegrity());
|
||||
}
|
||||
|
||||
if (mFingerprint)
|
||||
msg.setAttribute(new Fingerprint());
|
||||
|
||||
// Add ICE-CONTROLLED attribute if needed
|
||||
if (mEnableControlled)
|
||||
{
|
||||
assert(mTieBreaker.length() == 8);
|
||||
|
||||
ControlledAttr* attr = new ControlledAttr();
|
||||
attr->setTieBreaker(mTieBreaker);
|
||||
msg.setAttribute(attr);
|
||||
}
|
||||
|
||||
// Add ICE-CONTROLLING attribute if needed
|
||||
if (mEnableControlling)
|
||||
{
|
||||
assert(mTieBreaker.length() == 8);
|
||||
|
||||
ControllingAttr* attr = new ControllingAttr();
|
||||
attr->setTieBreaker(mTieBreaker);
|
||||
msg.setAttribute(attr);
|
||||
}
|
||||
|
||||
// Add ICE-PRIORITY attribute if needed
|
||||
if (mEnablePriority)
|
||||
{
|
||||
ICEPriority* attr = new ICEPriority();
|
||||
attr->setPriority(mPriority);
|
||||
msg.setAttribute(attr);
|
||||
}
|
||||
|
||||
msg.buildPacket(mOutgoingData, password);
|
||||
}
|
||||
|
||||
ByteBuffer* Transaction::generateData(bool force)
|
||||
{
|
||||
if (mCancelled)
|
||||
return NULL;
|
||||
|
||||
// Check if there is any outgoing data
|
||||
if (mOutgoingData.size() == 0)
|
||||
return NULL;
|
||||
|
||||
// Check if there is timeout for next transmission attempt
|
||||
if (mRTOTimer.isTimeout() && !force)
|
||||
{
|
||||
ICELogCritical(<< "Transaction " << mComment << " timeouted.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check if transmission was made too much times - client should not send billions of packets.
|
||||
if (mRTOTimer.isAttemptLimitReached() && !force)
|
||||
return NULL;
|
||||
|
||||
// Check if time to retransmit now
|
||||
if (mRTOTimer.isTimeToRetransmit() || force)
|
||||
{
|
||||
mRTOTimer.attemptMade();
|
||||
|
||||
// Copy outgoing data
|
||||
ByteBuffer* buffer = new ByteBuffer(mOutgoingData);
|
||||
|
||||
buffer->setComment(mComment);
|
||||
buffer->setRemoteAddress(destination());
|
||||
buffer->setComponent(component());
|
||||
buffer->setComment(comment());
|
||||
buffer->setTag(this);
|
||||
return buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Transaction::restart()
|
||||
{
|
||||
mComposed = false;
|
||||
mState = Transaction::Running;
|
||||
mOutgoingData.clear();
|
||||
mRemoved = false;
|
||||
mRTOTimer.stop();
|
||||
mRTOTimer.start();
|
||||
}
|
||||
|
||||
bool Transaction::isTimeout()
|
||||
{
|
||||
if (mRTOTimer.isTimeout())
|
||||
{
|
||||
mState = Failed;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void Transaction::addMessageIntegrity(bool enable)
|
||||
{
|
||||
mMessageIntegrity = enable;
|
||||
}
|
||||
|
||||
void Transaction::addFingerprint(bool enable)
|
||||
{
|
||||
mFingerprint = enable;
|
||||
}
|
||||
|
||||
void Transaction::addShortTermCredentials(bool enable)
|
||||
{
|
||||
this->mShortTerm = enable;
|
||||
}
|
||||
|
||||
void Transaction::addLongTermCredentials(bool enable)
|
||||
{
|
||||
this->mLongTerm = enable;
|
||||
}
|
||||
|
||||
void Transaction::addControllingRole(const std::string& tieBreaker)
|
||||
{
|
||||
mEnableControlling = true;
|
||||
mTieBreaker = tieBreaker;
|
||||
}
|
||||
|
||||
void Transaction::addControlledRole(const std::string& tieBreaker)
|
||||
{
|
||||
mEnableControlled = true;
|
||||
mTieBreaker = tieBreaker;
|
||||
}
|
||||
|
||||
void Transaction::addPriority(unsigned int priority)
|
||||
{
|
||||
mEnablePriority = true;
|
||||
mPriority = priority;
|
||||
}
|
||||
|
||||
unsigned int Transaction::priorityValue()
|
||||
{
|
||||
if (!mEnablePriority)
|
||||
throw Exception(NO_PRIORITY_ATTRIBUTE);
|
||||
|
||||
return mPriority;
|
||||
}
|
||||
|
||||
|
||||
void Transaction::setUsername(const std::string& username)
|
||||
{
|
||||
mUsername = username;
|
||||
}
|
||||
|
||||
void Transaction::setPassword(const std::string& password)
|
||||
{
|
||||
mPassword = password;
|
||||
}
|
||||
|
||||
Transaction::State Transaction::state() const
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
void Transaction::setAction(PAction action)
|
||||
{
|
||||
mAction = action;
|
||||
}
|
||||
|
||||
PAction Transaction::action() const
|
||||
{
|
||||
return mAction;
|
||||
}
|
||||
|
||||
void Transaction::cancel()
|
||||
{
|
||||
mCancelled = true;
|
||||
}
|
||||
|
||||
bool Transaction::isCancelled() const
|
||||
{
|
||||
return mCancelled;
|
||||
}
|
||||
|
||||
void Transaction::setComment(const std::string& comment)
|
||||
{
|
||||
mComment = comment;
|
||||
}
|
||||
|
||||
std::string Transaction::comment() const
|
||||
{
|
||||
return mComment;
|
||||
}
|
||||
|
||||
void Transaction::setDestination(const NetworkAddress& addr)
|
||||
{
|
||||
mDestination = addr;
|
||||
}
|
||||
|
||||
void Transaction::setComponent(int component)
|
||||
{
|
||||
mComponent = component;
|
||||
}
|
||||
|
||||
int Transaction::component()
|
||||
{
|
||||
return mComponent;
|
||||
}
|
||||
|
||||
NetworkAddress& Transaction::destination()
|
||||
{
|
||||
return mDestination;
|
||||
}
|
||||
|
||||
bool Transaction::relayed()
|
||||
{
|
||||
return mRelayed;
|
||||
}
|
||||
|
||||
void Transaction::setRelayed(bool relayed)
|
||||
{
|
||||
mRelayed = relayed;
|
||||
}
|
||||
|
||||
bool Transaction::keepalive()
|
||||
{
|
||||
return mKeepalive;
|
||||
}
|
||||
|
||||
void Transaction::setKeepalive(bool keepalive)
|
||||
{
|
||||
mKeepalive = keepalive;
|
||||
}
|
||||
|
||||
unsigned Transaction::interval()
|
||||
{
|
||||
return mInterval;
|
||||
}
|
||||
|
||||
void Transaction::setInterval(unsigned interval)
|
||||
{
|
||||
mInterval = interval;
|
||||
}
|
||||
|
||||
void* Transaction::userObject()
|
||||
{
|
||||
return mUserObject;
|
||||
}
|
||||
|
||||
void Transaction::setUserObject(void* obj)
|
||||
{
|
||||
mUserObject = obj;
|
||||
}
|
||||
|
||||
Transaction::Type Transaction::type()
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
void Transaction::setType(Transaction::Type t)
|
||||
{
|
||||
mType = t;
|
||||
}
|
||||
|
||||
bool Transaction::removed()
|
||||
{
|
||||
return mRemoved;
|
||||
}
|
||||
|
||||
void Transaction::setRemoved(bool removed)
|
||||
{
|
||||
if (!mRemoved && removed)
|
||||
ICELogDebug(<< "Transaction " << mComment << " removed.");
|
||||
|
||||
mRemoved = removed;
|
||||
}
|
||||
|
||||
unsigned Transaction::timestamp()
|
||||
{
|
||||
return mTimestamp;
|
||||
}
|
||||
|
||||
void Transaction::setTimestamp(unsigned timestamp)
|
||||
{
|
||||
mTimestamp = timestamp;
|
||||
}
|
||||
|
||||
StunMessage::TransactionID Transaction::transactionId()
|
||||
{
|
||||
return mTransactionID;
|
||||
}
|
||||
|
||||
bool Transaction::hasToRunNow()
|
||||
{
|
||||
if (!mKeepalive)
|
||||
return true;
|
||||
|
||||
//bool cf = (mComment == "ClientRefresh");
|
||||
|
||||
unsigned current = ICETimeHelper::timestamp();
|
||||
/*if (cf)
|
||||
{
|
||||
ICELogDebug(<< "ClientRefresh interval: " << ICETimeHelper::findDelta(timestamp(), current) << ", interval " << interval()*1000);
|
||||
}*/
|
||||
|
||||
if (timestamp())
|
||||
{
|
||||
if (ICETimeHelper::findDelta(timestamp(), current) < interval() * 1000)
|
||||
return false;
|
||||
|
||||
setTimestamp(current);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
setTimestamp(current);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Transaction::setFailoverId(int failoverId)
|
||||
{
|
||||
mFailoverId = failoverId;
|
||||
}
|
||||
|
||||
int Transaction::failoverId() const
|
||||
{
|
||||
return mFailoverId;
|
||||
}
|
||||
Reference in New Issue
Block a user