Blob Blame Raw

#include <cstring>

#include "tunnel.h"
#include "connection.h"
#include "udprecvqueue.h"



UdpRecvQueue::UdpRecvQueue(Connection &connection):
	connection(connection),
	nextConfirmSendTime(connection.tunnel.time + connection.tunnel.udpConfirmDuration),
	confirmRequired(),
	finalEntryAdded(),
	entries(),
	currentIndex(),
	endIndex()
	{ }


UdpRecvQueue::~UdpRecvQueue()
	{ }


bool UdpRecvQueue::recvUdp(unsigned int index, const void *data, int size) {
	confirmRequired = true;
	
	if (size < 0 || size > PACKET_SIZE)
		return false;
	if (cycleLess(index, currentIndex) || !cycleLess(index, currentIndex + PACKETS_COUNT))
		return false;
	if (finalEntryAdded && !cycleLess(index, endIndex))
		return false;
	Entry &e = entries[(current + (index - currentIndex))%PACKETS_COUNT];
	if (e.received)
		return false;
	
	e.received = true;
	e.size = size;
	if (e.size) {
		memcpy(e.data, data, e.size);
		if (cycleLess(endIndex, index + 1)) endIndex = index + 1;
	} else {
		finalEntryAdded = true;
		endIndex = index + 1;
	}
	
	return true;
}


bool UdpRecvQueue::sendUdpConfirm(bool force) {
	Time time = connection.tunnel.time;
	if (!force && (!confirmRequired || timeLess(time, nextConfirmSendTime)))
		return false;
	
	unsigned int count = endIndex - currentIndex;
	unsigned int bytesCount = count ? (count - 1)/8 + 1 : 0;
	
	Packet packet;
	packet.init(connection.id.id, currentIndex, CMD_CONFIRM, bytesCount);
	for(int i = 0; i < (int)count; ++i)
		if (entries[(current + i)%PACKETS_COUNT].received)
			packet.payload[i/8] |= (1 << (i%8));
	connection.tunnel.sendUdpPacket(connection.id.address, packet);
	
	confirmRequired = false;
	nextConfirmSendTime = time + connection.tunnel.udpConfirmDuration;
	return true;
}


bool UdpRecvQueue::canSentToTcp() const
	{ return cycleLess(currentIndex, endIndex) && entries[current].received && entries[current].size; }


int UdpRecvQueue::sendTcp() {
	int sent = 0;
	while(cycleLess(currentIndex, endIndex)) {
		Entry &e = entries[current];
		if (!e.received)
			break;

		if (!e.size) { 
			connection.udpActive = false;
			connection.tunnel.termQueue.insert(connection.id);
		} else
		if (!connection.tcpSendQueue.push(e.data, e.size)) {
			break;
		}
		
		++sent;
		memset(&e, 0, sizeof(e));
		current = (current + 1)%PACKETS_COUNT;
	}
	if (sent) confirmRequired = true;
	return sent;
}


void UdpRecvQueue::whenWriteToUdp(Time &t) const {
	if (confirmRequired && timeLess(nextConfirmSendTime, t))
		t = nextConfirmSendTime;
}