/* 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 "ICEReliableTransport.h" #include "ICETypes.h" #include using namespace ICEImpl; //------------------- ReliableTransport::Packet -------------------------- ReliableTransport::Packet::Packet() { mType = AppData; mSeqno = 0; mAppSeqno = 0; } ReliableTransport::Packet::~Packet() { } bool ReliableTransport::Packet::parse(const void* dataptr, int datasize, Encryption* encryption) { assert(encryption != NULL); assert(dataptr != NULL); assert(datasize != 0); // 1) Check if packet has mEncryption->GetBlockSize() bytes boundary if (datasize % encryption->blockSize()) return false; // 2) Save data mData.enqueueBuffer(dataptr, datasize); // 2) Decrypt it using mEncryption provider encryption->decrypt(mData.mutableData(), mData.size()); // 3) Check CRC from first 4 bytes (it is for little endian only) unsigned crc = mData.dequeueUInt(); if (crc != encryption->crc(mData.data(), mData.size())) return false; // 4) Check next byte for signature unsigned char signature = mData.dequeueUChar(); if (signature != RTSignature) return false; // 5) Next 2 bits are type of packet - AppData, Confirmation, Request or Ack unsigned short ts = mData.dequeueUShort(); mType = (Packet::Type)((ts & 0xC000) >> 14); // 6) Next 14 bits are real size of packet unsigned short realsize = ts & 0x3FFF; // 7) Seqno mSeqno = mData.dequeueUShort(); // 7) Check if we deal with AppData if (mType == AppData) mAppSeqno = mData.dequeueUShort(); // 8) Truncate app data to real size mData.truncate(realsize); return true; } void ReliableTransport::Packet::build(const void* dataptr, int datasize, Encryption* encryption) { assert(encryption && dataptr && datasize); mData.clear(); // Reserve place for CRC mData.enqueueUInt(0); // Signature mData.enqueueUChar(RTSignature); // Real size and type of packet unsigned short ts = (unsigned short)datasize; ts |= mType << 14; // Enqueue real size and type of packet mData.enqueueUShort(ts); // Enqueue sequence number mData.enqueueUShort(mSeqno); // Enqueue application sequence number if needed if (mType == Packet::AppData) mData.enqueueUShort(mAppSeqno); // Enqueue payload data mData.enqueueBuffer(dataptr, datasize); // Padding with zero bytes int tail = mData.size() % encryption->blockSize(); if (tail) { for (int i=0; i < encryption->blockSize() - tail; i++) mData.enqueueUChar(0); } // Get CRC on packet unsigned crc = encryption->crc((const char*)mData.data() + 4, mData.size() - 4); crc = htonl(crc); //It is here as corresponding DequeueUInt does ntohl memcpy(mData.mutableData(), &crc, 4); // Encrypt encryption->encrypt(mData.mutableData(), mData.size()); } void ReliableTransport::Packet::setType(Type packetType) { mType = packetType; } ReliableTransport::Packet::Type ReliableTransport::Packet::type() { return mType; } void ReliableTransport::Packet::setSeqno(unsigned short seqno) { mSeqno = seqno; } unsigned short ReliableTransport::Packet::seqno() { return mSeqno; } void ReliableTransport::Packet::setAppSeqno(unsigned short seqno) { mAppSeqno = seqno; } unsigned short ReliableTransport::Packet::appSeqno() { return mAppSeqno; } ICEByteBuffer& ReliableTransport::Packet::data() { return mData; } //-------------------- ReliableTransport -------------------- ReliableTransport::ReliableTransport() { mEncryption = NULL; mSeqno = 0; } ReliableTransport::~ReliableTransport() { } void ReliableTransport::setMaxDatagram(int size) { mMaxDatagramSize = size; } int ReliableTransport::maxDatagram() { return mMaxDatagramSize; } bool ReliableTransport::processIncoming(const void* dataptr, int datasize) { Packet* p = new Packet(); if (p->parse(dataptr, datasize, mEncryption)) { switch (p->type()) { case Packet::AppData: processAppData(p); break; case Packet::Confirmation: processConfirmation(p); break; case Packet::Ack: processAck(p); break; case Packet::Request: processRequest(p); break; } return true; } else { delete p; return false; } } void ReliableTransport::queueOutgoing(const void *dataPtr, int dataSize) { // Split enqueued data to datagrams using mMaxDatagramSize value. // Do not forget about service bytes - seqno, appseqno, CRC, signature... int payloadsize = this->mMaxDatagramSize - (2 /*CRC*/ + 1 /* signature */ + 2 /* type and size */); // Find packet count int packetcount = dataSize / payloadsize; if (dataSize % payloadsize) packetcount++; // Case input pointer const char* dataIn = (const char*)dataPtr; // Split data to packets for (int i=0; isetSeqno(mSeqno++); p->setAppSeqno(i); if (i == packetcount-1 && dataSize % payloadsize) p->build(dataIn + i * payloadsize, dataSize % payloadsize, mEncryption); else p->build(dataIn + i * payloadsize, payloadsize, mEncryption); mOutgoingData.push_back(p); } } void ReliableTransport::processAck(Packet* p) { // Ack received for confirmation int count = p->data().dequeueUShort(); for (int i=0; idata().dequeueUShort(); // Find corresponding confirmation packet and remove it removePacket(seqno); } delete p; } void ReliableTransport::processConfirmation(Packet* p) { int count = p->data().dequeueUShort(); for (int i=0; idata().dequeueUShort(); // Find corresponding AppData packet and remove it removePacket(seqno); } // Create Ack packet mOutgoingData.push_back(makeAckPacket(p->seqno())); delete p; } void ReliableTransport::processRequest(Packet* p) { int count = p->data().dequeueUShort(); for (int i=0; idata().dequeueUShort(); // Find specified by seqno packet and move to top of list prioritizePacket(seqno); } delete p; } void ReliableTransport::processAppData(Packet* p) { // 1) Add seqno to confirmation list mConfirmationData.push_back(p->seqno()); // 2) Check if confirmation list if big enough to transmit confirmation packet if (mConfirmationData.size() >= (unsigned)MaxConfirmationQueue) { mOutgoingData.push_back(makeConfirmationPacket(mConfirmationData)); mConfirmationData.clear(); } // 3) Move packet to mIncomingAppData with optional packet assembling mIncomingAppData.push_back(p); } void ReliableTransport::removePacket(Packet::Seqno seqno) { PacketList::iterator pit = mOutgoingData.begin(); while (pit != mOutgoingData.end()) { Packet* p = *pit; if (p->seqno() == seqno) { pit = mOutgoingData.erase(pit); delete p; } else pit++; } } void ReliableTransport::prioritizePacket(Packet::Seqno seqno) { PacketList::iterator pit = mOutgoingData.begin(); while (pit != mOutgoingData.end()) { Packet* p = *pit; if (p->seqno() == seqno) { // Remove pointer from old index pit = mOutgoingData.erase(pit); // Insert at beginning of queue mOutgoingData.insert(mOutgoingData.begin(), p); // Exit from loop break; } else pit++; } } ReliableTransport::Packet* ReliableTransport::makeAckPacket(Packet::Seqno seqno) { // Create packet Packet* p = new Packet(); // Set type p->setType(Packet::Ack); // Convert seqno number to network byte order unsigned short value = htons(seqno); // Build packet p->build(&value, sizeof(value), mEncryption); // Return packet return p; } ReliableTransport::Packet* ReliableTransport::makeConfirmationPacket(std::vector seqnovector) { // Convert seqno values to network byte order std::vector value; for (unsigned i=0; isetType(Packet::Ack); // Build packet p->build(&value[0], value.size() * sizeof(Packet::Seqno), mEncryption); // Return packet return p; } bool ReliableTransport::hasAppData() { return !mIncomingAppData.empty(); } unsigned ReliableTransport::appData(void* ptr) { if (mIncomingAppData.empty()) return 0; Packet& p = *mIncomingAppData.front(); unsigned length = p.data().size(); if (!ptr) return length; memcpy(ptr, p.data().data(), length); mIncomingAppData.erase(mIncomingAppData.begin()); return length; } bool ReliableTransport::hasPacketToSend() { return !mOutgoingData.empty(); } void ReliableTransport::getPacketToSend(void* outputptr, int& outputsize) { if (mOutgoingData.empty()) { outputsize = 0; } else { if (!outputptr) { outputsize = mOutgoingData.front()->data().size(); } else { Packet& p = *mOutgoingData.front(); unsigned tocopy = MINVALUE((int)outputsize, (int)p.data().size()); memcpy(outputptr, p.data().data(), p.data().size()); outputsize = tocopy; mOutgoingData.erase(mOutgoingData.begin()); } } } void ReliableTransport::setEncryption(ICEImpl::ReliableTransport::Encryption *encryption) { mEncryption = encryption; }