rtphone/src/engine/endpoint/EP_ReliableTunnel.cpp

305 lines
7.2 KiB
C++

/*
* 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);
}