mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 09:15:29 +01:00 
			
		
		
		
	Network: Delete copy constructor and use std::move instead (#11642)
This is a follow-up change which disables class copies where possible to avoid unnecessary memory movements.
This commit is contained in:
		@@ -877,7 +877,7 @@ void Client::ProcessData(NetworkPacket *pkt)
 | 
			
		||||
	*/
 | 
			
		||||
	if(sender_peer_id != PEER_ID_SERVER) {
 | 
			
		||||
		infostream << "Client::ProcessData(): Discarding data not "
 | 
			
		||||
			"coming from server: peer_id=" << sender_peer_id
 | 
			
		||||
			"coming from server: peer_id=" << sender_peer_id << " command=" << pkt->getCommand()
 | 
			
		||||
			<< std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -62,18 +62,27 @@ namespace con
 | 
			
		||||
 | 
			
		||||
#define PING_TIMEOUT 5.0
 | 
			
		||||
 | 
			
		||||
BufferedPacket makePacket(Address &address, const SharedBuffer<u8> &data,
 | 
			
		||||
u16 BufferedPacket::getSeqnum() const
 | 
			
		||||
{
 | 
			
		||||
	if (size() < BASE_HEADER_SIZE + 3)
 | 
			
		||||
		return 0; // should never happen
 | 
			
		||||
 | 
			
		||||
	return readU16(&data[BASE_HEADER_SIZE + 1]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BufferedPacketPtr makePacket(Address &address, const SharedBuffer<u8> &data,
 | 
			
		||||
		u32 protocol_id, session_t sender_peer_id, u8 channel)
 | 
			
		||||
{
 | 
			
		||||
	u32 packet_size = data.getSize() + BASE_HEADER_SIZE;
 | 
			
		||||
	BufferedPacket p(packet_size);
 | 
			
		||||
	p.address = address;
 | 
			
		||||
 | 
			
		||||
	writeU32(&p.data[0], protocol_id);
 | 
			
		||||
	writeU16(&p.data[4], sender_peer_id);
 | 
			
		||||
	writeU8(&p.data[6], channel);
 | 
			
		||||
	BufferedPacketPtr p(new BufferedPacket(packet_size));
 | 
			
		||||
	p->address = address;
 | 
			
		||||
 | 
			
		||||
	memcpy(&p.data[BASE_HEADER_SIZE], *data, data.getSize());
 | 
			
		||||
	writeU32(&p->data[0], protocol_id);
 | 
			
		||||
	writeU16(&p->data[4], sender_peer_id);
 | 
			
		||||
	writeU8(&p->data[6], channel);
 | 
			
		||||
 | 
			
		||||
	memcpy(&p->data[BASE_HEADER_SIZE], *data, data.getSize());
 | 
			
		||||
 | 
			
		||||
	return p;
 | 
			
		||||
}
 | 
			
		||||
@@ -169,9 +178,8 @@ void ReliablePacketBuffer::print()
 | 
			
		||||
	MutexAutoLock listlock(m_list_mutex);
 | 
			
		||||
	LOG(dout_con<<"Dump of ReliablePacketBuffer:" << std::endl);
 | 
			
		||||
	unsigned int index = 0;
 | 
			
		||||
	for (BufferedPacket &bufferedPacket : m_list) {
 | 
			
		||||
		u16 s = readU16(&(bufferedPacket.data[BASE_HEADER_SIZE+1]));
 | 
			
		||||
		LOG(dout_con<<index<< ":" << s << std::endl);
 | 
			
		||||
	for (BufferedPacketPtr &packet : m_list) {
 | 
			
		||||
		LOG(dout_con<<index<< ":" << packet->getSeqnum() << std::endl);
 | 
			
		||||
		index++;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -188,16 +196,13 @@ u32 ReliablePacketBuffer::size()
 | 
			
		||||
	return m_list.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RPBSearchResult ReliablePacketBuffer::findPacket(u16 seqnum)
 | 
			
		||||
RPBSearchResult ReliablePacketBuffer::findPacketNoLock(u16 seqnum)
 | 
			
		||||
{
 | 
			
		||||
	std::list<BufferedPacket>::iterator i = m_list.begin();
 | 
			
		||||
	for(; i != m_list.end(); ++i)
 | 
			
		||||
	{
 | 
			
		||||
		u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
 | 
			
		||||
		if (s == seqnum)
 | 
			
		||||
			break;
 | 
			
		||||
	for (auto it = m_list.begin(); it != m_list.end(); ++it) {
 | 
			
		||||
		if ((*it)->getSeqnum() == seqnum)
 | 
			
		||||
			return it;
 | 
			
		||||
	}
 | 
			
		||||
	return i;
 | 
			
		||||
	return m_list.end();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ReliablePacketBuffer::getFirstSeqnum(u16& result)
 | 
			
		||||
@@ -205,54 +210,54 @@ bool ReliablePacketBuffer::getFirstSeqnum(u16& result)
 | 
			
		||||
	MutexAutoLock listlock(m_list_mutex);
 | 
			
		||||
	if (m_list.empty())
 | 
			
		||||
		return false;
 | 
			
		||||
	const BufferedPacket &p = m_list.front();
 | 
			
		||||
	result = readU16(&p.data[BASE_HEADER_SIZE + 1]);
 | 
			
		||||
	result = m_list.front()->getSeqnum();
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BufferedPacket ReliablePacketBuffer::popFirst()
 | 
			
		||||
BufferedPacketPtr ReliablePacketBuffer::popFirst()
 | 
			
		||||
{
 | 
			
		||||
	MutexAutoLock listlock(m_list_mutex);
 | 
			
		||||
	if (m_list.empty())
 | 
			
		||||
		throw NotFoundException("Buffer is empty");
 | 
			
		||||
	BufferedPacket p = std::move(m_list.front());
 | 
			
		||||
 | 
			
		||||
	BufferedPacketPtr p(m_list.front());
 | 
			
		||||
	m_list.pop_front();
 | 
			
		||||
 | 
			
		||||
	if (m_list.empty()) {
 | 
			
		||||
		m_oldest_non_answered_ack = 0;
 | 
			
		||||
	} else {
 | 
			
		||||
		m_oldest_non_answered_ack =
 | 
			
		||||
				readU16(&m_list.front().data[BASE_HEADER_SIZE + 1]);
 | 
			
		||||
		m_oldest_non_answered_ack = m_list.front()->getSeqnum();
 | 
			
		||||
	}
 | 
			
		||||
	return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BufferedPacket ReliablePacketBuffer::popSeqnum(u16 seqnum)
 | 
			
		||||
BufferedPacketPtr ReliablePacketBuffer::popSeqnum(u16 seqnum)
 | 
			
		||||
{
 | 
			
		||||
	MutexAutoLock listlock(m_list_mutex);
 | 
			
		||||
	RPBSearchResult r = findPacket(seqnum);
 | 
			
		||||
	if (r == notFound()) {
 | 
			
		||||
	RPBSearchResult r = findPacketNoLock(seqnum);
 | 
			
		||||
	if (r == m_list.end()) {
 | 
			
		||||
		LOG(dout_con<<"Sequence number: " << seqnum
 | 
			
		||||
				<< " not found in reliable buffer"<<std::endl);
 | 
			
		||||
		throw NotFoundException("seqnum not found in buffer");
 | 
			
		||||
	}
 | 
			
		||||
	BufferedPacket p = std::move(*r);
 | 
			
		||||
 | 
			
		||||
	BufferedPacketPtr p(*r);
 | 
			
		||||
	m_list.erase(r);
 | 
			
		||||
 | 
			
		||||
	if (m_list.empty()) {
 | 
			
		||||
		m_oldest_non_answered_ack = 0;
 | 
			
		||||
	} else {
 | 
			
		||||
		m_oldest_non_answered_ack =
 | 
			
		||||
				readU16(&m_list.front().data[BASE_HEADER_SIZE + 1]);
 | 
			
		||||
		m_oldest_non_answered_ack = m_list.front()->getSeqnum();
 | 
			
		||||
	}
 | 
			
		||||
	return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ReliablePacketBuffer::insert(const BufferedPacket &p, u16 next_expected)
 | 
			
		||||
void ReliablePacketBuffer::insert(BufferedPacketPtr &p_ptr, u16 next_expected)
 | 
			
		||||
{
 | 
			
		||||
	MutexAutoLock listlock(m_list_mutex);
 | 
			
		||||
	if (p.data.getSize() < BASE_HEADER_SIZE + 3) {
 | 
			
		||||
	const BufferedPacket &p = *p_ptr;
 | 
			
		||||
 | 
			
		||||
	if (p.size() < BASE_HEADER_SIZE + 3) {
 | 
			
		||||
		errorstream << "ReliablePacketBuffer::insert(): Invalid data size for "
 | 
			
		||||
			"reliable packet" << std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
@@ -263,7 +268,7 @@ void ReliablePacketBuffer::insert(const BufferedPacket &p, u16 next_expected)
 | 
			
		||||
			<< std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	u16 seqnum = readU16(&p.data[BASE_HEADER_SIZE + 1]);
 | 
			
		||||
	const u16 seqnum = p.getSeqnum();
 | 
			
		||||
 | 
			
		||||
	if (!seqnum_in_window(seqnum, next_expected, MAX_RELIABLE_WINDOW_SIZE)) {
 | 
			
		||||
		errorstream << "ReliablePacketBuffer::insert(): seqnum is outside of "
 | 
			
		||||
@@ -280,44 +285,44 @@ void ReliablePacketBuffer::insert(const BufferedPacket &p, u16 next_expected)
 | 
			
		||||
 | 
			
		||||
	// Find the right place for the packet and insert it there
 | 
			
		||||
	// If list is empty, just add it
 | 
			
		||||
	if (m_list.empty())
 | 
			
		||||
	{
 | 
			
		||||
		m_list.push_back(p);
 | 
			
		||||
	if (m_list.empty()) {
 | 
			
		||||
		m_list.push_back(p_ptr);
 | 
			
		||||
		m_oldest_non_answered_ack = seqnum;
 | 
			
		||||
		// Done.
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Otherwise find the right place
 | 
			
		||||
	std::list<BufferedPacket>::iterator i = m_list.begin();
 | 
			
		||||
	auto it = m_list.begin();
 | 
			
		||||
	// Find the first packet in the list which has a higher seqnum
 | 
			
		||||
	u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
 | 
			
		||||
	u16 s = (*it)->getSeqnum();
 | 
			
		||||
 | 
			
		||||
	/* case seqnum is smaller then next_expected seqnum */
 | 
			
		||||
	/* this is true e.g. on wrap around */
 | 
			
		||||
	if (seqnum < next_expected) {
 | 
			
		||||
		while(((s < seqnum) || (s >= next_expected)) && (i != m_list.end())) {
 | 
			
		||||
			++i;
 | 
			
		||||
			if (i != m_list.end())
 | 
			
		||||
				s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
 | 
			
		||||
		while(((s < seqnum) || (s >= next_expected)) && (it != m_list.end())) {
 | 
			
		||||
			++it;
 | 
			
		||||
			if (it != m_list.end())
 | 
			
		||||
				s = (*it)->getSeqnum();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/* non wrap around case (at least for incoming and next_expected */
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		while(((s < seqnum) && (s >= next_expected)) && (i != m_list.end())) {
 | 
			
		||||
			++i;
 | 
			
		||||
			if (i != m_list.end())
 | 
			
		||||
				s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
 | 
			
		||||
		while(((s < seqnum) && (s >= next_expected)) && (it != m_list.end())) {
 | 
			
		||||
			++it;
 | 
			
		||||
			if (it != m_list.end())
 | 
			
		||||
				s = (*it)->getSeqnum();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (s == seqnum) {
 | 
			
		||||
		/* nothing to do this seems to be a resent packet */
 | 
			
		||||
		/* for paranoia reason data should be compared */
 | 
			
		||||
		auto &i = *it;
 | 
			
		||||
		if (
 | 
			
		||||
			(readU16(&(i->data[BASE_HEADER_SIZE+1])) != seqnum) ||
 | 
			
		||||
			(i->data.getSize() != p.data.getSize()) ||
 | 
			
		||||
			(i->getSeqnum() != seqnum) ||
 | 
			
		||||
			(i->size() != p.size()) ||
 | 
			
		||||
			(i->address != p.address)
 | 
			
		||||
			)
 | 
			
		||||
		{
 | 
			
		||||
@@ -325,51 +330,52 @@ void ReliablePacketBuffer::insert(const BufferedPacket &p, u16 next_expected)
 | 
			
		||||
			fprintf(stderr,
 | 
			
		||||
					"Duplicated seqnum %d non matching packet detected:\n",
 | 
			
		||||
					seqnum);
 | 
			
		||||
			fprintf(stderr, "Old: seqnum: %05d size: %04d, address: %s\n",
 | 
			
		||||
					readU16(&(i->data[BASE_HEADER_SIZE+1])),i->data.getSize(),
 | 
			
		||||
			fprintf(stderr, "Old: seqnum: %05d size: %04zu, address: %s\n",
 | 
			
		||||
					i->getSeqnum(), i->size(),
 | 
			
		||||
					i->address.serializeString().c_str());
 | 
			
		||||
			fprintf(stderr, "New: seqnum: %05d size: %04u, address: %s\n",
 | 
			
		||||
					readU16(&(p.data[BASE_HEADER_SIZE+1])),p.data.getSize(),
 | 
			
		||||
			fprintf(stderr, "New: seqnum: %05d size: %04zu, address: %s\n",
 | 
			
		||||
					p.getSeqnum(), p.size(),
 | 
			
		||||
					p.address.serializeString().c_str());
 | 
			
		||||
			throw IncomingDataCorruption("duplicated packet isn't same as original one");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/* insert or push back */
 | 
			
		||||
	else if (i != m_list.end()) {
 | 
			
		||||
		m_list.insert(i, p);
 | 
			
		||||
	else if (it != m_list.end()) {
 | 
			
		||||
		m_list.insert(it, p_ptr);
 | 
			
		||||
	} else {
 | 
			
		||||
		m_list.push_back(p);
 | 
			
		||||
		m_list.push_back(p_ptr);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* update last packet number */
 | 
			
		||||
	m_oldest_non_answered_ack = readU16(&m_list.front().data[BASE_HEADER_SIZE+1]);
 | 
			
		||||
	m_oldest_non_answered_ack = m_list.front()->getSeqnum();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ReliablePacketBuffer::incrementTimeouts(float dtime)
 | 
			
		||||
{
 | 
			
		||||
	MutexAutoLock listlock(m_list_mutex);
 | 
			
		||||
	for (BufferedPacket &bufferedPacket : m_list) {
 | 
			
		||||
		bufferedPacket.time += dtime;
 | 
			
		||||
		bufferedPacket.totaltime += dtime;
 | 
			
		||||
	for (auto &packet : m_list) {
 | 
			
		||||
		packet->time += dtime;
 | 
			
		||||
		packet->totaltime += dtime;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::list<BufferedPacket>
 | 
			
		||||
std::list<ConstSharedPtr<BufferedPacket>>
 | 
			
		||||
	ReliablePacketBuffer::getTimedOuts(float timeout, u32 max_packets)
 | 
			
		||||
{
 | 
			
		||||
	MutexAutoLock listlock(m_list_mutex);
 | 
			
		||||
	std::list<BufferedPacket> timed_outs;
 | 
			
		||||
	for (BufferedPacket &bufferedPacket : m_list) {
 | 
			
		||||
		if (bufferedPacket.time >= timeout) {
 | 
			
		||||
			// caller will resend packet so reset time and increase counter
 | 
			
		||||
			bufferedPacket.time = 0.0f;
 | 
			
		||||
			bufferedPacket.resend_count++;
 | 
			
		||||
	std::list<ConstSharedPtr<BufferedPacket>> timed_outs;
 | 
			
		||||
	for (auto &packet : m_list) {
 | 
			
		||||
		if (packet->time < timeout)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
			timed_outs.push_back(bufferedPacket);
 | 
			
		||||
		// caller will resend packet so reset time and increase counter
 | 
			
		||||
		packet->time = 0.0f;
 | 
			
		||||
		packet->resend_count++;
 | 
			
		||||
 | 
			
		||||
			if (timed_outs.size() >= max_packets)
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
		timed_outs.emplace_back(packet);
 | 
			
		||||
 | 
			
		||||
		if (timed_outs.size() >= max_packets)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
	return timed_outs;
 | 
			
		||||
}
 | 
			
		||||
@@ -428,11 +434,13 @@ IncomingSplitBuffer::~IncomingSplitBuffer()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SharedBuffer<u8> IncomingSplitBuffer::insert(const BufferedPacket &p, bool reliable)
 | 
			
		||||
SharedBuffer<u8> IncomingSplitBuffer::insert(BufferedPacketPtr &p_ptr, bool reliable)
 | 
			
		||||
{
 | 
			
		||||
	MutexAutoLock listlock(m_map_mutex);
 | 
			
		||||
	const BufferedPacket &p = *p_ptr;
 | 
			
		||||
 | 
			
		||||
	u32 headersize = BASE_HEADER_SIZE + 7;
 | 
			
		||||
	if (p.data.getSize() < headersize) {
 | 
			
		||||
	if (p.size() < headersize) {
 | 
			
		||||
		errorstream << "Invalid data size for split packet" << std::endl;
 | 
			
		||||
		return SharedBuffer<u8>();
 | 
			
		||||
	}
 | 
			
		||||
@@ -473,7 +481,7 @@ SharedBuffer<u8> IncomingSplitBuffer::insert(const BufferedPacket &p, bool relia
 | 
			
		||||
				<<std::endl);
 | 
			
		||||
 | 
			
		||||
	// Cut chunk data out of packet
 | 
			
		||||
	u32 chunkdatasize = p.data.getSize() - headersize;
 | 
			
		||||
	u32 chunkdatasize = p.size() - headersize;
 | 
			
		||||
	SharedBuffer<u8> chunkdata(chunkdatasize);
 | 
			
		||||
	memcpy(*chunkdata, &(p.data[headersize]), chunkdatasize);
 | 
			
		||||
 | 
			
		||||
@@ -520,14 +528,67 @@ void IncomingSplitBuffer::removeUnreliableTimedOuts(float dtime, float timeout)
 | 
			
		||||
	ConnectionCommand
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
void ConnectionCommand::send(session_t peer_id_, u8 channelnum_, NetworkPacket *pkt,
 | 
			
		||||
	bool reliable_)
 | 
			
		||||
ConnectionCommandPtr ConnectionCommand::create(ConnectionCommandType type)
 | 
			
		||||
{
 | 
			
		||||
	type = CONNCMD_SEND;
 | 
			
		||||
	peer_id = peer_id_;
 | 
			
		||||
	channelnum = channelnum_;
 | 
			
		||||
	data = pkt->oldForgePacket();
 | 
			
		||||
	reliable = reliable_;
 | 
			
		||||
	return ConnectionCommandPtr(new ConnectionCommand(type));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConnectionCommandPtr ConnectionCommand::serve(Address address)
 | 
			
		||||
{
 | 
			
		||||
	auto c = create(CONNCMD_SERVE);
 | 
			
		||||
	c->address = address;
 | 
			
		||||
	return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConnectionCommandPtr ConnectionCommand::connect(Address address)
 | 
			
		||||
{
 | 
			
		||||
	auto c = create(CONNCMD_CONNECT);
 | 
			
		||||
	c->address = address;
 | 
			
		||||
	return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConnectionCommandPtr ConnectionCommand::disconnect()
 | 
			
		||||
{
 | 
			
		||||
	return create(CONNCMD_DISCONNECT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConnectionCommandPtr ConnectionCommand::disconnect_peer(session_t peer_id)
 | 
			
		||||
{
 | 
			
		||||
	auto c = create(CONNCMD_DISCONNECT_PEER);
 | 
			
		||||
	c->peer_id = peer_id;
 | 
			
		||||
	return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConnectionCommandPtr ConnectionCommand::send(session_t peer_id, u8 channelnum,
 | 
			
		||||
	NetworkPacket *pkt, bool reliable)
 | 
			
		||||
{
 | 
			
		||||
	auto c = create(CONNCMD_SEND);
 | 
			
		||||
	c->peer_id = peer_id;
 | 
			
		||||
	c->channelnum = channelnum;
 | 
			
		||||
	c->reliable = reliable;
 | 
			
		||||
	c->data = pkt->oldForgePacket();
 | 
			
		||||
	return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConnectionCommandPtr ConnectionCommand::ack(session_t peer_id, u8 channelnum, const Buffer<u8> &data)
 | 
			
		||||
{
 | 
			
		||||
	auto c = create(CONCMD_ACK);
 | 
			
		||||
	c->peer_id = peer_id;
 | 
			
		||||
	c->channelnum = channelnum;
 | 
			
		||||
	c->reliable = false;
 | 
			
		||||
	data.copyTo(c->data);
 | 
			
		||||
	return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConnectionCommandPtr ConnectionCommand::createPeer(session_t peer_id, const Buffer<u8> &data)
 | 
			
		||||
{
 | 
			
		||||
	auto c = create(CONCMD_CREATE_PEER);
 | 
			
		||||
	c->peer_id = peer_id;
 | 
			
		||||
	c->channelnum = 0;
 | 
			
		||||
	c->reliable = true;
 | 
			
		||||
	c->raw = true;
 | 
			
		||||
	data.copyTo(c->data);
 | 
			
		||||
	return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -562,39 +623,38 @@ void Channel::setNextSplitSeqNum(u16 seqnum)
 | 
			
		||||
u16 Channel::getOutgoingSequenceNumber(bool& successful)
 | 
			
		||||
{
 | 
			
		||||
	MutexAutoLock internal(m_internal_mutex);
 | 
			
		||||
 | 
			
		||||
	u16 retval = next_outgoing_seqnum;
 | 
			
		||||
	u16 lowest_unacked_seqnumber;
 | 
			
		||||
	successful = false;
 | 
			
		||||
 | 
			
		||||
	/* shortcut if there ain't any packet in outgoing list */
 | 
			
		||||
	if (outgoing_reliables_sent.empty())
 | 
			
		||||
	{
 | 
			
		||||
	if (outgoing_reliables_sent.empty()) {
 | 
			
		||||
		successful = true;
 | 
			
		||||
		next_outgoing_seqnum++;
 | 
			
		||||
		return retval;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (outgoing_reliables_sent.getFirstSeqnum(lowest_unacked_seqnumber))
 | 
			
		||||
	{
 | 
			
		||||
	u16 lowest_unacked_seqnumber;
 | 
			
		||||
	if (outgoing_reliables_sent.getFirstSeqnum(lowest_unacked_seqnumber)) {
 | 
			
		||||
		if (lowest_unacked_seqnumber < next_outgoing_seqnum) {
 | 
			
		||||
			// ugly cast but this one is required in order to tell compiler we
 | 
			
		||||
			// know about difference of two unsigned may be negative in general
 | 
			
		||||
			// but we already made sure it won't happen in this case
 | 
			
		||||
			if (((u16)(next_outgoing_seqnum - lowest_unacked_seqnumber)) > m_window_size) {
 | 
			
		||||
				successful = false;
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
		} else {
 | 
			
		||||
			// ugly cast but this one is required in order to tell compiler we
 | 
			
		||||
			// know about difference of two unsigned may be negative in general
 | 
			
		||||
			// but we already made sure it won't happen in this case
 | 
			
		||||
			if ((next_outgoing_seqnum + (u16)(SEQNUM_MAX - lowest_unacked_seqnumber)) >
 | 
			
		||||
					m_window_size) {
 | 
			
		||||
				successful = false;
 | 
			
		||||
				return 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	successful = true;
 | 
			
		||||
	next_outgoing_seqnum++;
 | 
			
		||||
	return retval;
 | 
			
		||||
}
 | 
			
		||||
@@ -946,45 +1006,45 @@ bool UDPPeer::Ping(float dtime,SharedBuffer<u8>& data)
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UDPPeer::PutReliableSendCommand(ConnectionCommand &c,
 | 
			
		||||
void UDPPeer::PutReliableSendCommand(ConnectionCommandPtr &c,
 | 
			
		||||
		unsigned int max_packet_size)
 | 
			
		||||
{
 | 
			
		||||
	if (m_pending_disconnect)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	Channel &chan = channels[c.channelnum];
 | 
			
		||||
	Channel &chan = channels[c->channelnum];
 | 
			
		||||
 | 
			
		||||
	if (chan.queued_commands.empty() &&
 | 
			
		||||
			/* don't queue more packets then window size */
 | 
			
		||||
			(chan.queued_reliables.size() < chan.getWindowSize() / 2)) {
 | 
			
		||||
			(chan.queued_reliables.size() + 1 < chan.getWindowSize() / 2)) {
 | 
			
		||||
		LOG(dout_con<<m_connection->getDesc()
 | 
			
		||||
				<<" processing reliable command for peer id: " << c.peer_id
 | 
			
		||||
				<<" data size: " << c.data.getSize() << std::endl);
 | 
			
		||||
		if (!processReliableSendCommand(c,max_packet_size)) {
 | 
			
		||||
			chan.queued_commands.push_back(c);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
				<<" processing reliable command for peer id: " << c->peer_id
 | 
			
		||||
				<<" data size: " << c->data.getSize() << std::endl);
 | 
			
		||||
		if (processReliableSendCommand(c, max_packet_size))
 | 
			
		||||
			return;
 | 
			
		||||
	} else {
 | 
			
		||||
		LOG(dout_con<<m_connection->getDesc()
 | 
			
		||||
				<<" Queueing reliable command for peer id: " << c.peer_id
 | 
			
		||||
				<<" data size: " << c.data.getSize() <<std::endl);
 | 
			
		||||
		chan.queued_commands.push_back(c);
 | 
			
		||||
		if (chan.queued_commands.size() >= chan.getWindowSize() / 2) {
 | 
			
		||||
				<<" Queueing reliable command for peer id: " << c->peer_id
 | 
			
		||||
				<<" data size: " << c->data.getSize() <<std::endl);
 | 
			
		||||
 | 
			
		||||
		if (chan.queued_commands.size() + 1 >= chan.getWindowSize() / 2) {
 | 
			
		||||
			LOG(derr_con << m_connection->getDesc()
 | 
			
		||||
					<< "Possible packet stall to peer id: " << c.peer_id
 | 
			
		||||
					<< "Possible packet stall to peer id: " << c->peer_id
 | 
			
		||||
					<< " queued_commands=" << chan.queued_commands.size()
 | 
			
		||||
					<< std::endl);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	chan.queued_commands.push_back(c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool UDPPeer::processReliableSendCommand(
 | 
			
		||||
				ConnectionCommand &c,
 | 
			
		||||
				ConnectionCommandPtr &c_ptr,
 | 
			
		||||
				unsigned int max_packet_size)
 | 
			
		||||
{
 | 
			
		||||
	if (m_pending_disconnect)
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	const auto &c = *c_ptr;
 | 
			
		||||
	Channel &chan = channels[c.channelnum];
 | 
			
		||||
 | 
			
		||||
	u32 chunksize_max = max_packet_size
 | 
			
		||||
@@ -1003,9 +1063,9 @@ bool UDPPeer::processReliableSendCommand(
 | 
			
		||||
		chan.setNextSplitSeqNum(split_sequence_number);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool have_sequence_number = true;
 | 
			
		||||
	bool have_sequence_number = false;
 | 
			
		||||
	bool have_initial_sequence_number = false;
 | 
			
		||||
	std::queue<BufferedPacket> toadd;
 | 
			
		||||
	std::queue<BufferedPacketPtr> toadd;
 | 
			
		||||
	volatile u16 initial_sequence_number = 0;
 | 
			
		||||
 | 
			
		||||
	for (SharedBuffer<u8> &original : originals) {
 | 
			
		||||
@@ -1024,25 +1084,23 @@ bool UDPPeer::processReliableSendCommand(
 | 
			
		||||
		SharedBuffer<u8> reliable = makeReliablePacket(original, seqnum);
 | 
			
		||||
 | 
			
		||||
		// Add base headers and make a packet
 | 
			
		||||
		BufferedPacket p = con::makePacket(address, reliable,
 | 
			
		||||
		BufferedPacketPtr p = con::makePacket(address, reliable,
 | 
			
		||||
				m_connection->GetProtocolID(), m_connection->GetPeerID(),
 | 
			
		||||
				c.channelnum);
 | 
			
		||||
 | 
			
		||||
		toadd.push(std::move(p));
 | 
			
		||||
		toadd.push(p);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (have_sequence_number) {
 | 
			
		||||
		volatile u16 pcount = 0;
 | 
			
		||||
		while (!toadd.empty()) {
 | 
			
		||||
			BufferedPacket p = std::move(toadd.front());
 | 
			
		||||
			BufferedPacketPtr p = toadd.front();
 | 
			
		||||
			toadd.pop();
 | 
			
		||||
//			LOG(dout_con<<connection->getDesc()
 | 
			
		||||
//					<< " queuing reliable packet for peer_id: " << c.peer_id
 | 
			
		||||
//					<< " channel: " << (c.channelnum&0xFF)
 | 
			
		||||
//					<< " seqnum: " << readU16(&p.data[BASE_HEADER_SIZE+1])
 | 
			
		||||
//					<< std::endl)
 | 
			
		||||
			chan.queued_reliables.push(std::move(p));
 | 
			
		||||
			pcount++;
 | 
			
		||||
			chan.queued_reliables.push(p);
 | 
			
		||||
		}
 | 
			
		||||
		sanity_check(chan.queued_reliables.size() < 0xFFFF);
 | 
			
		||||
		return true;
 | 
			
		||||
@@ -1051,6 +1109,7 @@ bool UDPPeer::processReliableSendCommand(
 | 
			
		||||
	volatile u16 packets_available = toadd.size();
 | 
			
		||||
	/* we didn't get a single sequence number no need to fill queue */
 | 
			
		||||
	if (!have_initial_sequence_number) {
 | 
			
		||||
		LOG(derr_con << m_connection->getDesc() << "Ran out of sequence numbers!" << std::endl);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -1096,18 +1155,18 @@ void UDPPeer::RunCommandQueues(
 | 
			
		||||
				(channel.queued_reliables.size() < maxtransfer) &&
 | 
			
		||||
				(commands_processed < maxcommands)) {
 | 
			
		||||
			try {
 | 
			
		||||
				ConnectionCommand c = channel.queued_commands.front();
 | 
			
		||||
				ConnectionCommandPtr c = channel.queued_commands.front();
 | 
			
		||||
 | 
			
		||||
				LOG(dout_con << m_connection->getDesc()
 | 
			
		||||
						<< " processing queued reliable command " << std::endl);
 | 
			
		||||
 | 
			
		||||
				// Packet is processed, remove it from queue
 | 
			
		||||
				if (processReliableSendCommand(c,max_packet_size)) {
 | 
			
		||||
				if (processReliableSendCommand(c, max_packet_size)) {
 | 
			
		||||
					channel.queued_commands.pop_front();
 | 
			
		||||
				} else {
 | 
			
		||||
					LOG(dout_con << m_connection->getDesc()
 | 
			
		||||
							<< " Failed to queue packets for peer_id: " << c.peer_id
 | 
			
		||||
							<< ", delaying sending of " << c.data.getSize()
 | 
			
		||||
							<< " Failed to queue packets for peer_id: " << c->peer_id
 | 
			
		||||
							<< ", delaying sending of " << c->data.getSize()
 | 
			
		||||
							<< " bytes" << std::endl);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
@@ -1130,13 +1189,70 @@ void UDPPeer::setNextSplitSequenceNumber(u8 channel, u16 seqnum)
 | 
			
		||||
	channels[channel].setNextSplitSeqNum(seqnum);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SharedBuffer<u8> UDPPeer::addSplitPacket(u8 channel, const BufferedPacket &toadd,
 | 
			
		||||
SharedBuffer<u8> UDPPeer::addSplitPacket(u8 channel, BufferedPacketPtr &toadd,
 | 
			
		||||
	bool reliable)
 | 
			
		||||
{
 | 
			
		||||
	assert(channel < CHANNEL_COUNT); // Pre-condition
 | 
			
		||||
	return channels[channel].incoming_splits.insert(toadd, reliable);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	ConnectionEvent
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
const char *ConnectionEvent::describe() const
 | 
			
		||||
{
 | 
			
		||||
	switch(type) {
 | 
			
		||||
	case CONNEVENT_NONE:
 | 
			
		||||
		return "CONNEVENT_NONE";
 | 
			
		||||
	case CONNEVENT_DATA_RECEIVED:
 | 
			
		||||
		return "CONNEVENT_DATA_RECEIVED";
 | 
			
		||||
	case CONNEVENT_PEER_ADDED:
 | 
			
		||||
		return "CONNEVENT_PEER_ADDED";
 | 
			
		||||
	case CONNEVENT_PEER_REMOVED:
 | 
			
		||||
		return "CONNEVENT_PEER_REMOVED";
 | 
			
		||||
	case CONNEVENT_BIND_FAILED:
 | 
			
		||||
		return "CONNEVENT_BIND_FAILED";
 | 
			
		||||
	}
 | 
			
		||||
	return "Invalid ConnectionEvent";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ConnectionEventPtr ConnectionEvent::create(ConnectionEventType type)
 | 
			
		||||
{
 | 
			
		||||
	return std::shared_ptr<ConnectionEvent>(new ConnectionEvent(type));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConnectionEventPtr ConnectionEvent::dataReceived(session_t peer_id, const Buffer<u8> &data)
 | 
			
		||||
{
 | 
			
		||||
	auto e = create(CONNEVENT_DATA_RECEIVED);
 | 
			
		||||
	e->peer_id = peer_id;
 | 
			
		||||
	data.copyTo(e->data);
 | 
			
		||||
	return e;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConnectionEventPtr ConnectionEvent::peerAdded(session_t peer_id, Address address)
 | 
			
		||||
{
 | 
			
		||||
	auto e = create(CONNEVENT_PEER_ADDED);
 | 
			
		||||
	e->peer_id = peer_id;
 | 
			
		||||
	e->address = address;
 | 
			
		||||
	return e;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConnectionEventPtr ConnectionEvent::peerRemoved(session_t peer_id, bool is_timeout, Address address)
 | 
			
		||||
{
 | 
			
		||||
	auto e = create(CONNEVENT_PEER_REMOVED);
 | 
			
		||||
	e->peer_id = peer_id;
 | 
			
		||||
	e->timeout = is_timeout;
 | 
			
		||||
	e->address = address;
 | 
			
		||||
	return e;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConnectionEventPtr ConnectionEvent::bindFailed()
 | 
			
		||||
{
 | 
			
		||||
	return create(CONNEVENT_BIND_FAILED);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Connection
 | 
			
		||||
*/
 | 
			
		||||
@@ -1186,18 +1302,12 @@ Connection::~Connection()
 | 
			
		||||
 | 
			
		||||
/* Internal stuff */
 | 
			
		||||
 | 
			
		||||
void Connection::putEvent(const ConnectionEvent &e)
 | 
			
		||||
void Connection::putEvent(ConnectionEventPtr e)
 | 
			
		||||
{
 | 
			
		||||
	assert(e.type != CONNEVENT_NONE); // Pre-condition
 | 
			
		||||
	assert(e->type != CONNEVENT_NONE); // Pre-condition
 | 
			
		||||
	m_event_queue.push_back(e);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::putEvent(ConnectionEvent &&e)
 | 
			
		||||
{
 | 
			
		||||
	assert(e.type != CONNEVENT_NONE); // Pre-condition
 | 
			
		||||
	m_event_queue.push_back(std::move(e));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::TriggerSend()
 | 
			
		||||
{
 | 
			
		||||
	m_sendThread->Trigger();
 | 
			
		||||
@@ -1260,11 +1370,9 @@ bool Connection::deletePeer(session_t peer_id, bool timeout)
 | 
			
		||||
	Address peer_address;
 | 
			
		||||
	//any peer has a primary address this never fails!
 | 
			
		||||
	peer->getAddress(MTP_PRIMARY, peer_address);
 | 
			
		||||
	// Create event
 | 
			
		||||
	ConnectionEvent e;
 | 
			
		||||
	e.peerRemoved(peer_id, timeout, peer_address);
 | 
			
		||||
	putEvent(e);
 | 
			
		||||
 | 
			
		||||
	// Create event
 | 
			
		||||
	putEvent(ConnectionEvent::peerRemoved(peer_id, timeout, peer_address));
 | 
			
		||||
 | 
			
		||||
	peer->Drop();
 | 
			
		||||
	return true;
 | 
			
		||||
@@ -1272,18 +1380,16 @@ bool Connection::deletePeer(session_t peer_id, bool timeout)
 | 
			
		||||
 | 
			
		||||
/* Interface */
 | 
			
		||||
 | 
			
		||||
ConnectionEvent Connection::waitEvent(u32 timeout_ms)
 | 
			
		||||
ConnectionEventPtr Connection::waitEvent(u32 timeout_ms)
 | 
			
		||||
{
 | 
			
		||||
	try {
 | 
			
		||||
		return m_event_queue.pop_front(timeout_ms);
 | 
			
		||||
	} catch(ItemNotFoundException &ex) {
 | 
			
		||||
		ConnectionEvent e;
 | 
			
		||||
		e.type = CONNEVENT_NONE;
 | 
			
		||||
		return e;
 | 
			
		||||
		return ConnectionEvent::create(CONNEVENT_NONE);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::putCommand(const ConnectionCommand &c)
 | 
			
		||||
void Connection::putCommand(ConnectionCommandPtr c)
 | 
			
		||||
{
 | 
			
		||||
	if (!m_shutting_down) {
 | 
			
		||||
		m_command_queue.push_back(c);
 | 
			
		||||
@@ -1291,26 +1397,14 @@ void Connection::putCommand(const ConnectionCommand &c)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::putCommand(ConnectionCommand &&c)
 | 
			
		||||
{
 | 
			
		||||
	if (!m_shutting_down) {
 | 
			
		||||
		m_command_queue.push_back(std::move(c));
 | 
			
		||||
		m_sendThread->Trigger();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::Serve(Address bind_addr)
 | 
			
		||||
{
 | 
			
		||||
	ConnectionCommand c;
 | 
			
		||||
	c.serve(bind_addr);
 | 
			
		||||
	putCommand(c);
 | 
			
		||||
	putCommand(ConnectionCommand::serve(bind_addr));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::Connect(Address address)
 | 
			
		||||
{
 | 
			
		||||
	ConnectionCommand c;
 | 
			
		||||
	c.connect(address);
 | 
			
		||||
	putCommand(c);
 | 
			
		||||
	putCommand(ConnectionCommand::connect(address));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Connection::Connected()
 | 
			
		||||
@@ -1332,9 +1426,7 @@ bool Connection::Connected()
 | 
			
		||||
 | 
			
		||||
void Connection::Disconnect()
 | 
			
		||||
{
 | 
			
		||||
	ConnectionCommand c;
 | 
			
		||||
	c.disconnect();
 | 
			
		||||
	putCommand(c);
 | 
			
		||||
	putCommand(ConnectionCommand::disconnect());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Connection::Receive(NetworkPacket *pkt, u32 timeout)
 | 
			
		||||
@@ -1345,11 +1437,15 @@ bool Connection::Receive(NetworkPacket *pkt, u32 timeout)
 | 
			
		||||
		This is not considered to be a problem (is it?)
 | 
			
		||||
	*/
 | 
			
		||||
	for(;;) {
 | 
			
		||||
		ConnectionEvent e = waitEvent(timeout);
 | 
			
		||||
		if (e.type != CONNEVENT_NONE)
 | 
			
		||||
		ConnectionEventPtr e_ptr = waitEvent(timeout);
 | 
			
		||||
		const ConnectionEvent &e = *e_ptr;
 | 
			
		||||
 | 
			
		||||
		if (e.type != CONNEVENT_NONE) {
 | 
			
		||||
			LOG(dout_con << getDesc() << ": Receive: got event: "
 | 
			
		||||
					<< e.describe() << std::endl);
 | 
			
		||||
		switch(e.type) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch (e.type) {
 | 
			
		||||
		case CONNEVENT_NONE:
 | 
			
		||||
			return false;
 | 
			
		||||
		case CONNEVENT_DATA_RECEIVED:
 | 
			
		||||
@@ -1397,10 +1493,7 @@ void Connection::Send(session_t peer_id, u8 channelnum,
 | 
			
		||||
{
 | 
			
		||||
	assert(channelnum < CHANNEL_COUNT); // Pre-condition
 | 
			
		||||
 | 
			
		||||
	ConnectionCommand c;
 | 
			
		||||
 | 
			
		||||
	c.send(peer_id, channelnum, pkt, reliable);
 | 
			
		||||
	putCommand(std::move(c));
 | 
			
		||||
	putCommand(ConnectionCommand::send(peer_id, channelnum, pkt, reliable));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Address Connection::GetPeerAddress(session_t peer_id)
 | 
			
		||||
@@ -1499,41 +1592,31 @@ u16 Connection::createPeer(Address& sender, MTProtocols protocol, int fd)
 | 
			
		||||
	LOG(dout_con << getDesc()
 | 
			
		||||
			<< "createPeer(): giving peer_id=" << peer_id_new << std::endl);
 | 
			
		||||
 | 
			
		||||
	ConnectionCommand cmd;
 | 
			
		||||
	Buffer<u8> reply(4);
 | 
			
		||||
	writeU8(&reply[0], PACKET_TYPE_CONTROL);
 | 
			
		||||
	writeU8(&reply[1], CONTROLTYPE_SET_PEER_ID);
 | 
			
		||||
	writeU16(&reply[2], peer_id_new);
 | 
			
		||||
	cmd.createPeer(peer_id_new,reply);
 | 
			
		||||
	putCommand(std::move(cmd));
 | 
			
		||||
	{
 | 
			
		||||
		Buffer<u8> reply(4);
 | 
			
		||||
		writeU8(&reply[0], PACKET_TYPE_CONTROL);
 | 
			
		||||
		writeU8(&reply[1], CONTROLTYPE_SET_PEER_ID);
 | 
			
		||||
		writeU16(&reply[2], peer_id_new);
 | 
			
		||||
		putCommand(ConnectionCommand::createPeer(peer_id_new, reply));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Create peer addition event
 | 
			
		||||
	ConnectionEvent e;
 | 
			
		||||
	e.peerAdded(peer_id_new, sender);
 | 
			
		||||
	putEvent(e);
 | 
			
		||||
	putEvent(ConnectionEvent::peerAdded(peer_id_new, sender));
 | 
			
		||||
 | 
			
		||||
	// We're now talking to a valid peer_id
 | 
			
		||||
	return peer_id_new;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::PrintInfo(std::ostream &out)
 | 
			
		||||
{
 | 
			
		||||
	m_info_mutex.lock();
 | 
			
		||||
	out<<getDesc()<<": ";
 | 
			
		||||
	m_info_mutex.unlock();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const std::string Connection::getDesc()
 | 
			
		||||
{
 | 
			
		||||
	MutexAutoLock _(m_info_mutex);
 | 
			
		||||
	return std::string("con(")+
 | 
			
		||||
			itos(m_udpSocket.GetHandle())+"/"+itos(m_peer_id)+")";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::DisconnectPeer(session_t peer_id)
 | 
			
		||||
{
 | 
			
		||||
	ConnectionCommand discon;
 | 
			
		||||
	discon.disconnect_peer(peer_id);
 | 
			
		||||
	putCommand(discon);
 | 
			
		||||
	putCommand(ConnectionCommand::disconnect_peer(peer_id));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Connection::sendAck(session_t peer_id, u8 channelnum, u16 seqnum)
 | 
			
		||||
@@ -1545,14 +1628,12 @@ void Connection::sendAck(session_t peer_id, u8 channelnum, u16 seqnum)
 | 
			
		||||
			" channel: " << (channelnum & 0xFF) <<
 | 
			
		||||
			" seqnum: " << seqnum << std::endl);
 | 
			
		||||
 | 
			
		||||
	ConnectionCommand c;
 | 
			
		||||
	SharedBuffer<u8> ack(4);
 | 
			
		||||
	writeU8(&ack[0], PACKET_TYPE_CONTROL);
 | 
			
		||||
	writeU8(&ack[1], CONTROLTYPE_ACK);
 | 
			
		||||
	writeU16(&ack[2], seqnum);
 | 
			
		||||
 | 
			
		||||
	c.ack(peer_id, channelnum, ack);
 | 
			
		||||
	putCommand(std::move(c));
 | 
			
		||||
	putCommand(ConnectionCommand::ack(peer_id, channelnum, ack));
 | 
			
		||||
	m_sendThread->Trigger();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,95 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <map>
 | 
			
		||||
 | 
			
		||||
#define MAX_UDP_PEERS 65535
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
=== NOTES ===
 | 
			
		||||
 | 
			
		||||
A packet is sent through a channel to a peer with a basic header:
 | 
			
		||||
	Header (7 bytes):
 | 
			
		||||
	[0] u32 protocol_id
 | 
			
		||||
	[4] session_t sender_peer_id
 | 
			
		||||
	[6] u8 channel
 | 
			
		||||
sender_peer_id:
 | 
			
		||||
	Unique to each peer.
 | 
			
		||||
	value 0 (PEER_ID_INEXISTENT) is reserved for making new connections
 | 
			
		||||
	value 1 (PEER_ID_SERVER) is reserved for server
 | 
			
		||||
	these constants are defined in constants.h
 | 
			
		||||
channel:
 | 
			
		||||
	Channel numbers have no intrinsic meaning. Currently only 0, 1, 2 exist.
 | 
			
		||||
*/
 | 
			
		||||
#define BASE_HEADER_SIZE 7
 | 
			
		||||
#define CHANNEL_COUNT 3
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Packet types:
 | 
			
		||||
 | 
			
		||||
CONTROL: This is a packet used by the protocol.
 | 
			
		||||
- When this is processed, nothing is handed to the user.
 | 
			
		||||
	Header (2 byte):
 | 
			
		||||
	[0] u8 type
 | 
			
		||||
	[1] u8 controltype
 | 
			
		||||
controltype and data description:
 | 
			
		||||
	CONTROLTYPE_ACK
 | 
			
		||||
		[2] u16 seqnum
 | 
			
		||||
	CONTROLTYPE_SET_PEER_ID
 | 
			
		||||
		[2] session_t peer_id_new
 | 
			
		||||
	CONTROLTYPE_PING
 | 
			
		||||
	- There is no actual reply, but this can be sent in a reliable
 | 
			
		||||
	  packet to get a reply
 | 
			
		||||
	CONTROLTYPE_DISCO
 | 
			
		||||
*/
 | 
			
		||||
enum ControlType : u8 {
 | 
			
		||||
	CONTROLTYPE_ACK = 0,
 | 
			
		||||
	CONTROLTYPE_SET_PEER_ID = 1,
 | 
			
		||||
	CONTROLTYPE_PING = 2,
 | 
			
		||||
	CONTROLTYPE_DISCO = 3,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
ORIGINAL: This is a plain packet with no control and no error
 | 
			
		||||
checking at all.
 | 
			
		||||
- When this is processed, it is directly handed to the user.
 | 
			
		||||
	Header (1 byte):
 | 
			
		||||
	[0] u8 type
 | 
			
		||||
*/
 | 
			
		||||
//#define TYPE_ORIGINAL 1
 | 
			
		||||
#define ORIGINAL_HEADER_SIZE 1
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
SPLIT: These are sequences of packets forming one bigger piece of
 | 
			
		||||
data.
 | 
			
		||||
- When processed and all the packet_nums 0...packet_count-1 are
 | 
			
		||||
  present (this should be buffered), the resulting data shall be
 | 
			
		||||
  directly handed to the user.
 | 
			
		||||
- If the data fails to come up in a reasonable time, the buffer shall
 | 
			
		||||
  be silently discarded.
 | 
			
		||||
- These can be sent as-is or atop of a RELIABLE packet stream.
 | 
			
		||||
	Header (7 bytes):
 | 
			
		||||
	[0] u8 type
 | 
			
		||||
	[1] u16 seqnum
 | 
			
		||||
	[3] u16 chunk_count
 | 
			
		||||
	[5] u16 chunk_num
 | 
			
		||||
*/
 | 
			
		||||
//#define TYPE_SPLIT 2
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
RELIABLE: Delivery of all RELIABLE packets shall be forced by ACKs,
 | 
			
		||||
and they shall be delivered in the same order as sent. This is done
 | 
			
		||||
with a buffer in the receiving and transmitting end.
 | 
			
		||||
- When this is processed, the contents of each packet is recursively
 | 
			
		||||
  processed as packets.
 | 
			
		||||
	Header (3 bytes):
 | 
			
		||||
	[0] u8 type
 | 
			
		||||
	[1] u16 seqnum
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
//#define TYPE_RELIABLE 3
 | 
			
		||||
#define RELIABLE_HEADER_SIZE 3
 | 
			
		||||
#define SEQNUM_INITIAL 65500
 | 
			
		||||
#define SEQNUM_MAX 65535
 | 
			
		||||
 | 
			
		||||
class NetworkPacket;
 | 
			
		||||
 | 
			
		||||
namespace con
 | 
			
		||||
@@ -46,9 +135,13 @@ typedef enum MTProtocols {
 | 
			
		||||
	MTP_MINETEST_RELIABLE_UDP
 | 
			
		||||
} MTProtocols;
 | 
			
		||||
 | 
			
		||||
#define MAX_UDP_PEERS 65535
 | 
			
		||||
 | 
			
		||||
#define SEQNUM_MAX 65535
 | 
			
		||||
enum PacketType : u8 {
 | 
			
		||||
	PACKET_TYPE_CONTROL = 0,
 | 
			
		||||
	PACKET_TYPE_ORIGINAL = 1,
 | 
			
		||||
	PACKET_TYPE_SPLIT = 2,
 | 
			
		||||
	PACKET_TYPE_RELIABLE = 3,
 | 
			
		||||
	PACKET_TYPE_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline bool seqnum_higher(u16 totest, u16 base)
 | 
			
		||||
{
 | 
			
		||||
@@ -85,24 +178,40 @@ static inline float CALC_DTIME(u64 lasttime, u64 curtime)
 | 
			
		||||
	return MYMAX(MYMIN(value,0.1),0.0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct BufferedPacket
 | 
			
		||||
{
 | 
			
		||||
	BufferedPacket(u8 *a_data, u32 a_size):
 | 
			
		||||
		data(a_data, a_size)
 | 
			
		||||
	{}
 | 
			
		||||
	BufferedPacket(u32 a_size):
 | 
			
		||||
		data(a_size)
 | 
			
		||||
	{}
 | 
			
		||||
	Buffer<u8> data; // Data of the packet, including headers
 | 
			
		||||
/*
 | 
			
		||||
	Struct for all kinds of packets. Includes following data:
 | 
			
		||||
		BASE_HEADER
 | 
			
		||||
		u8[] packet data (usually copied from SharedBuffer<u8>)
 | 
			
		||||
*/
 | 
			
		||||
struct BufferedPacket {
 | 
			
		||||
	BufferedPacket(u32 a_size)
 | 
			
		||||
	{
 | 
			
		||||
		m_data.resize(a_size);
 | 
			
		||||
		data = &m_data[0];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DISABLE_CLASS_COPY(BufferedPacket)
 | 
			
		||||
 | 
			
		||||
	u16 getSeqnum() const;
 | 
			
		||||
 | 
			
		||||
	inline const size_t size() const { return m_data.size(); }
 | 
			
		||||
 | 
			
		||||
	u8 *data; // Direct memory access
 | 
			
		||||
	float time = 0.0f; // Seconds from buffering the packet or re-sending
 | 
			
		||||
	float totaltime = 0.0f; // Seconds from buffering the packet
 | 
			
		||||
	u64 absolute_send_time = -1;
 | 
			
		||||
	Address address; // Sender or destination
 | 
			
		||||
	unsigned int resend_count = 0;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	std::vector<u8> m_data; // Data of the packet, including headers
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef std::shared_ptr<BufferedPacket> BufferedPacketPtr;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// This adds the base headers to the data and makes a packet out of it
 | 
			
		||||
BufferedPacket makePacket(Address &address, const SharedBuffer<u8> &data,
 | 
			
		||||
BufferedPacketPtr makePacket(Address &address, const SharedBuffer<u8> &data,
 | 
			
		||||
		u32 protocol_id, session_t sender_peer_id, u8 channel);
 | 
			
		||||
 | 
			
		||||
// Depending on size, make a TYPE_ORIGINAL or TYPE_SPLIT packet
 | 
			
		||||
@@ -136,101 +245,12 @@ private:
 | 
			
		||||
	std::map<u16, SharedBuffer<u8>> chunks;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
=== NOTES ===
 | 
			
		||||
 | 
			
		||||
A packet is sent through a channel to a peer with a basic header:
 | 
			
		||||
	Header (7 bytes):
 | 
			
		||||
	[0] u32 protocol_id
 | 
			
		||||
	[4] session_t sender_peer_id
 | 
			
		||||
	[6] u8 channel
 | 
			
		||||
sender_peer_id:
 | 
			
		||||
	Unique to each peer.
 | 
			
		||||
	value 0 (PEER_ID_INEXISTENT) is reserved for making new connections
 | 
			
		||||
	value 1 (PEER_ID_SERVER) is reserved for server
 | 
			
		||||
	these constants are defined in constants.h
 | 
			
		||||
channel:
 | 
			
		||||
	Channel numbers have no intrinsic meaning. Currently only 0, 1, 2 exist.
 | 
			
		||||
*/
 | 
			
		||||
#define BASE_HEADER_SIZE 7
 | 
			
		||||
#define CHANNEL_COUNT 3
 | 
			
		||||
/*
 | 
			
		||||
Packet types:
 | 
			
		||||
 | 
			
		||||
CONTROL: This is a packet used by the protocol.
 | 
			
		||||
- When this is processed, nothing is handed to the user.
 | 
			
		||||
	Header (2 byte):
 | 
			
		||||
	[0] u8 type
 | 
			
		||||
	[1] u8 controltype
 | 
			
		||||
controltype and data description:
 | 
			
		||||
	CONTROLTYPE_ACK
 | 
			
		||||
		[2] u16 seqnum
 | 
			
		||||
	CONTROLTYPE_SET_PEER_ID
 | 
			
		||||
		[2] session_t peer_id_new
 | 
			
		||||
	CONTROLTYPE_PING
 | 
			
		||||
	- There is no actual reply, but this can be sent in a reliable
 | 
			
		||||
	  packet to get a reply
 | 
			
		||||
	CONTROLTYPE_DISCO
 | 
			
		||||
*/
 | 
			
		||||
//#define TYPE_CONTROL 0
 | 
			
		||||
#define CONTROLTYPE_ACK 0
 | 
			
		||||
#define CONTROLTYPE_SET_PEER_ID 1
 | 
			
		||||
#define CONTROLTYPE_PING 2
 | 
			
		||||
#define CONTROLTYPE_DISCO 3
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
ORIGINAL: This is a plain packet with no control and no error
 | 
			
		||||
checking at all.
 | 
			
		||||
- When this is processed, it is directly handed to the user.
 | 
			
		||||
	Header (1 byte):
 | 
			
		||||
	[0] u8 type
 | 
			
		||||
*/
 | 
			
		||||
//#define TYPE_ORIGINAL 1
 | 
			
		||||
#define ORIGINAL_HEADER_SIZE 1
 | 
			
		||||
/*
 | 
			
		||||
SPLIT: These are sequences of packets forming one bigger piece of
 | 
			
		||||
data.
 | 
			
		||||
- When processed and all the packet_nums 0...packet_count-1 are
 | 
			
		||||
  present (this should be buffered), the resulting data shall be
 | 
			
		||||
  directly handed to the user.
 | 
			
		||||
- If the data fails to come up in a reasonable time, the buffer shall
 | 
			
		||||
  be silently discarded.
 | 
			
		||||
- These can be sent as-is or atop of a RELIABLE packet stream.
 | 
			
		||||
	Header (7 bytes):
 | 
			
		||||
	[0] u8 type
 | 
			
		||||
	[1] u16 seqnum
 | 
			
		||||
	[3] u16 chunk_count
 | 
			
		||||
	[5] u16 chunk_num
 | 
			
		||||
*/
 | 
			
		||||
//#define TYPE_SPLIT 2
 | 
			
		||||
/*
 | 
			
		||||
RELIABLE: Delivery of all RELIABLE packets shall be forced by ACKs,
 | 
			
		||||
and they shall be delivered in the same order as sent. This is done
 | 
			
		||||
with a buffer in the receiving and transmitting end.
 | 
			
		||||
- When this is processed, the contents of each packet is recursively
 | 
			
		||||
  processed as packets.
 | 
			
		||||
	Header (3 bytes):
 | 
			
		||||
	[0] u8 type
 | 
			
		||||
	[1] u16 seqnum
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
//#define TYPE_RELIABLE 3
 | 
			
		||||
#define RELIABLE_HEADER_SIZE 3
 | 
			
		||||
#define SEQNUM_INITIAL 65500
 | 
			
		||||
 | 
			
		||||
enum PacketType: u8 {
 | 
			
		||||
	PACKET_TYPE_CONTROL = 0,
 | 
			
		||||
	PACKET_TYPE_ORIGINAL = 1,
 | 
			
		||||
	PACKET_TYPE_SPLIT = 2,
 | 
			
		||||
	PACKET_TYPE_RELIABLE = 3,
 | 
			
		||||
	PACKET_TYPE_MAX
 | 
			
		||||
};
 | 
			
		||||
/*
 | 
			
		||||
	A buffer which stores reliable packets and sorts them internally
 | 
			
		||||
	for fast access to the smallest one.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
typedef std::list<BufferedPacket>::iterator RPBSearchResult;
 | 
			
		||||
typedef std::list<BufferedPacketPtr>::iterator RPBSearchResult;
 | 
			
		||||
 | 
			
		||||
class ReliablePacketBuffer
 | 
			
		||||
{
 | 
			
		||||
@@ -239,12 +259,12 @@ public:
 | 
			
		||||
 | 
			
		||||
	bool getFirstSeqnum(u16& result);
 | 
			
		||||
 | 
			
		||||
	BufferedPacket popFirst();
 | 
			
		||||
	BufferedPacket popSeqnum(u16 seqnum);
 | 
			
		||||
	void insert(const BufferedPacket &p, u16 next_expected);
 | 
			
		||||
	BufferedPacketPtr popFirst();
 | 
			
		||||
	BufferedPacketPtr popSeqnum(u16 seqnum);
 | 
			
		||||
	void insert(BufferedPacketPtr &p_ptr, u16 next_expected);
 | 
			
		||||
 | 
			
		||||
	void incrementTimeouts(float dtime);
 | 
			
		||||
	std::list<BufferedPacket> getTimedOuts(float timeout, u32 max_packets);
 | 
			
		||||
	std::list<ConstSharedPtr<BufferedPacket>> getTimedOuts(float timeout, u32 max_packets);
 | 
			
		||||
 | 
			
		||||
	void print();
 | 
			
		||||
	bool empty();
 | 
			
		||||
@@ -252,10 +272,9 @@ public:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	RPBSearchResult findPacket(u16 seqnum); // does not perform locking
 | 
			
		||||
	inline RPBSearchResult notFound() { return m_list.end(); }
 | 
			
		||||
	RPBSearchResult findPacketNoLock(u16 seqnum);
 | 
			
		||||
 | 
			
		||||
	std::list<BufferedPacket> m_list;
 | 
			
		||||
	std::list<BufferedPacketPtr> m_list;
 | 
			
		||||
 | 
			
		||||
	u16 m_oldest_non_answered_ack;
 | 
			
		||||
 | 
			
		||||
@@ -274,7 +293,7 @@ public:
 | 
			
		||||
		Returns a reference counted buffer of length != 0 when a full split
 | 
			
		||||
		packet is constructed. If not, returns one of length 0.
 | 
			
		||||
	*/
 | 
			
		||||
	SharedBuffer<u8> insert(const BufferedPacket &p, bool reliable);
 | 
			
		||||
	SharedBuffer<u8> insert(BufferedPacketPtr &p_ptr, bool reliable);
 | 
			
		||||
 | 
			
		||||
	void removeUnreliableTimedOuts(float dtime, float timeout);
 | 
			
		||||
 | 
			
		||||
@@ -285,25 +304,6 @@ private:
 | 
			
		||||
	std::mutex m_map_mutex;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct OutgoingPacket
 | 
			
		||||
{
 | 
			
		||||
	session_t peer_id;
 | 
			
		||||
	u8 channelnum;
 | 
			
		||||
	SharedBuffer<u8> data;
 | 
			
		||||
	bool reliable;
 | 
			
		||||
	bool ack;
 | 
			
		||||
 | 
			
		||||
	OutgoingPacket(session_t peer_id_, u8 channelnum_, const SharedBuffer<u8> &data_,
 | 
			
		||||
			bool reliable_,bool ack_=false):
 | 
			
		||||
		peer_id(peer_id_),
 | 
			
		||||
		channelnum(channelnum_),
 | 
			
		||||
		data(data_),
 | 
			
		||||
		reliable(reliable_),
 | 
			
		||||
		ack(ack_)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum ConnectionCommandType{
 | 
			
		||||
	CONNCMD_NONE,
 | 
			
		||||
	CONNCMD_SERVE,
 | 
			
		||||
@@ -316,9 +316,13 @@ enum ConnectionCommandType{
 | 
			
		||||
	CONCMD_CREATE_PEER
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ConnectionCommand;
 | 
			
		||||
typedef std::shared_ptr<ConnectionCommand> ConnectionCommandPtr;
 | 
			
		||||
 | 
			
		||||
// This is very similar to ConnectionEvent
 | 
			
		||||
struct ConnectionCommand
 | 
			
		||||
{
 | 
			
		||||
	enum ConnectionCommandType type = CONNCMD_NONE;
 | 
			
		||||
	const ConnectionCommandType type;
 | 
			
		||||
	Address address;
 | 
			
		||||
	session_t peer_id = PEER_ID_INEXISTENT;
 | 
			
		||||
	u8 channelnum = 0;
 | 
			
		||||
@@ -326,48 +330,21 @@ struct ConnectionCommand
 | 
			
		||||
	bool reliable = false;
 | 
			
		||||
	bool raw = false;
 | 
			
		||||
 | 
			
		||||
	ConnectionCommand() = default;
 | 
			
		||||
	DISABLE_CLASS_COPY(ConnectionCommand);
 | 
			
		||||
 | 
			
		||||
	void serve(Address address_)
 | 
			
		||||
	{
 | 
			
		||||
		type = CONNCMD_SERVE;
 | 
			
		||||
		address = address_;
 | 
			
		||||
	}
 | 
			
		||||
	void connect(Address address_)
 | 
			
		||||
	{
 | 
			
		||||
		type = CONNCMD_CONNECT;
 | 
			
		||||
		address = address_;
 | 
			
		||||
	}
 | 
			
		||||
	void disconnect()
 | 
			
		||||
	{
 | 
			
		||||
		type = CONNCMD_DISCONNECT;
 | 
			
		||||
	}
 | 
			
		||||
	void disconnect_peer(session_t peer_id_)
 | 
			
		||||
	{
 | 
			
		||||
		type = CONNCMD_DISCONNECT_PEER;
 | 
			
		||||
		peer_id = peer_id_;
 | 
			
		||||
	}
 | 
			
		||||
	static ConnectionCommandPtr serve(Address address);
 | 
			
		||||
	static ConnectionCommandPtr connect(Address address);
 | 
			
		||||
	static ConnectionCommandPtr disconnect();
 | 
			
		||||
	static ConnectionCommandPtr disconnect_peer(session_t peer_id);
 | 
			
		||||
	static ConnectionCommandPtr send(session_t peer_id, u8 channelnum, NetworkPacket *pkt, bool reliable);
 | 
			
		||||
	static ConnectionCommandPtr ack(session_t peer_id, u8 channelnum, const Buffer<u8> &data);
 | 
			
		||||
	static ConnectionCommandPtr createPeer(session_t peer_id, const Buffer<u8> &data);
 | 
			
		||||
 | 
			
		||||
	void send(session_t peer_id_, u8 channelnum_, NetworkPacket *pkt, bool reliable_);
 | 
			
		||||
private:
 | 
			
		||||
	ConnectionCommand(ConnectionCommandType type_) :
 | 
			
		||||
		type(type_) {}
 | 
			
		||||
 | 
			
		||||
	void ack(session_t peer_id_, u8 channelnum_, const Buffer<u8> &data_)
 | 
			
		||||
	{
 | 
			
		||||
		type = CONCMD_ACK;
 | 
			
		||||
		peer_id = peer_id_;
 | 
			
		||||
		channelnum = channelnum_;
 | 
			
		||||
		data = data_;
 | 
			
		||||
		reliable = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void createPeer(session_t peer_id_, const Buffer<u8> &data_)
 | 
			
		||||
	{
 | 
			
		||||
		type = CONCMD_CREATE_PEER;
 | 
			
		||||
		peer_id = peer_id_;
 | 
			
		||||
		data = data_;
 | 
			
		||||
		channelnum = 0;
 | 
			
		||||
		reliable = true;
 | 
			
		||||
		raw = true;
 | 
			
		||||
	}
 | 
			
		||||
	static ConnectionCommandPtr create(ConnectionCommandType type);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* maximum window size to use, 0xFFFF is theoretical maximum. don't think about
 | 
			
		||||
@@ -402,10 +379,10 @@ public:
 | 
			
		||||
	ReliablePacketBuffer outgoing_reliables_sent;
 | 
			
		||||
 | 
			
		||||
	//queued reliable packets
 | 
			
		||||
	std::queue<BufferedPacket> queued_reliables;
 | 
			
		||||
	std::queue<BufferedPacketPtr> queued_reliables;
 | 
			
		||||
 | 
			
		||||
	//queue commands prior splitting to packets
 | 
			
		||||
	std::deque<ConnectionCommand> queued_commands;
 | 
			
		||||
	std::deque<ConnectionCommandPtr> queued_commands;
 | 
			
		||||
 | 
			
		||||
	IncomingSplitBuffer incoming_splits;
 | 
			
		||||
 | 
			
		||||
@@ -514,7 +491,7 @@ class Peer {
 | 
			
		||||
	public:
 | 
			
		||||
		friend class PeerHelper;
 | 
			
		||||
 | 
			
		||||
		Peer(Address address_,u16 id_,Connection* connection) :
 | 
			
		||||
		Peer(Address address_,session_t id_,Connection* connection) :
 | 
			
		||||
			id(id_),
 | 
			
		||||
			m_connection(connection),
 | 
			
		||||
			address(address_),
 | 
			
		||||
@@ -528,11 +505,11 @@ class Peer {
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		// Unique id of the peer
 | 
			
		||||
		u16 id;
 | 
			
		||||
		const session_t id;
 | 
			
		||||
 | 
			
		||||
		void Drop();
 | 
			
		||||
 | 
			
		||||
		virtual void PutReliableSendCommand(ConnectionCommand &c,
 | 
			
		||||
		virtual void PutReliableSendCommand(ConnectionCommandPtr &c,
 | 
			
		||||
						unsigned int max_packet_size) {};
 | 
			
		||||
 | 
			
		||||
		virtual bool getAddress(MTProtocols type, Address& toset) = 0;
 | 
			
		||||
@@ -549,7 +526,7 @@ class Peer {
 | 
			
		||||
 | 
			
		||||
		virtual u16 getNextSplitSequenceNumber(u8 channel) { return 0; };
 | 
			
		||||
		virtual void setNextSplitSequenceNumber(u8 channel, u16 seqnum) {};
 | 
			
		||||
		virtual SharedBuffer<u8> addSplitPacket(u8 channel, const BufferedPacket &toadd,
 | 
			
		||||
		virtual SharedBuffer<u8> addSplitPacket(u8 channel, BufferedPacketPtr &toadd,
 | 
			
		||||
				bool reliable)
 | 
			
		||||
		{
 | 
			
		||||
			errorstream << "Peer::addSplitPacket called,"
 | 
			
		||||
@@ -586,7 +563,7 @@ class Peer {
 | 
			
		||||
		bool IncUseCount();
 | 
			
		||||
		void DecUseCount();
 | 
			
		||||
 | 
			
		||||
		std::mutex m_exclusive_access_mutex;
 | 
			
		||||
		mutable std::mutex m_exclusive_access_mutex;
 | 
			
		||||
 | 
			
		||||
		bool m_pending_deletion = false;
 | 
			
		||||
 | 
			
		||||
@@ -634,7 +611,7 @@ public:
 | 
			
		||||
	UDPPeer(u16 a_id, Address a_address, Connection* connection);
 | 
			
		||||
	virtual ~UDPPeer() = default;
 | 
			
		||||
 | 
			
		||||
	void PutReliableSendCommand(ConnectionCommand &c,
 | 
			
		||||
	void PutReliableSendCommand(ConnectionCommandPtr &c,
 | 
			
		||||
							unsigned int max_packet_size);
 | 
			
		||||
 | 
			
		||||
	bool getAddress(MTProtocols type, Address& toset);
 | 
			
		||||
@@ -642,7 +619,7 @@ public:
 | 
			
		||||
	u16 getNextSplitSequenceNumber(u8 channel);
 | 
			
		||||
	void setNextSplitSequenceNumber(u8 channel, u16 seqnum);
 | 
			
		||||
 | 
			
		||||
	SharedBuffer<u8> addSplitPacket(u8 channel, const BufferedPacket &toadd,
 | 
			
		||||
	SharedBuffer<u8> addSplitPacket(u8 channel, BufferedPacketPtr &toadd,
 | 
			
		||||
		bool reliable);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
@@ -671,7 +648,7 @@ private:
 | 
			
		||||
	float resend_timeout = 0.5;
 | 
			
		||||
 | 
			
		||||
	bool processReliableSendCommand(
 | 
			
		||||
					ConnectionCommand &c,
 | 
			
		||||
					ConnectionCommandPtr &c_ptr,
 | 
			
		||||
					unsigned int max_packet_size);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -679,7 +656,7 @@ private:
 | 
			
		||||
	Connection
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
enum ConnectionEventType{
 | 
			
		||||
enum ConnectionEventType {
 | 
			
		||||
	CONNEVENT_NONE,
 | 
			
		||||
	CONNEVENT_DATA_RECEIVED,
 | 
			
		||||
	CONNEVENT_PEER_ADDED,
 | 
			
		||||
@@ -687,56 +664,32 @@ enum ConnectionEventType{
 | 
			
		||||
	CONNEVENT_BIND_FAILED,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ConnectionEvent;
 | 
			
		||||
typedef std::shared_ptr<ConnectionEvent> ConnectionEventPtr;
 | 
			
		||||
 | 
			
		||||
// This is very similar to ConnectionCommand
 | 
			
		||||
struct ConnectionEvent
 | 
			
		||||
{
 | 
			
		||||
	enum ConnectionEventType type = CONNEVENT_NONE;
 | 
			
		||||
	const ConnectionEventType type;
 | 
			
		||||
	session_t peer_id = 0;
 | 
			
		||||
	Buffer<u8> data;
 | 
			
		||||
	bool timeout = false;
 | 
			
		||||
	Address address;
 | 
			
		||||
 | 
			
		||||
	ConnectionEvent() = default;
 | 
			
		||||
	// We don't want to copy "data"
 | 
			
		||||
	DISABLE_CLASS_COPY(ConnectionEvent);
 | 
			
		||||
 | 
			
		||||
	const char *describe() const
 | 
			
		||||
	{
 | 
			
		||||
		switch(type) {
 | 
			
		||||
		case CONNEVENT_NONE:
 | 
			
		||||
			return "CONNEVENT_NONE";
 | 
			
		||||
		case CONNEVENT_DATA_RECEIVED:
 | 
			
		||||
			return "CONNEVENT_DATA_RECEIVED";
 | 
			
		||||
		case CONNEVENT_PEER_ADDED:
 | 
			
		||||
			return "CONNEVENT_PEER_ADDED";
 | 
			
		||||
		case CONNEVENT_PEER_REMOVED:
 | 
			
		||||
			return "CONNEVENT_PEER_REMOVED";
 | 
			
		||||
		case CONNEVENT_BIND_FAILED:
 | 
			
		||||
			return "CONNEVENT_BIND_FAILED";
 | 
			
		||||
		}
 | 
			
		||||
		return "Invalid ConnectionEvent";
 | 
			
		||||
	}
 | 
			
		||||
	static ConnectionEventPtr create(ConnectionEventType type);
 | 
			
		||||
	static ConnectionEventPtr dataReceived(session_t peer_id, const Buffer<u8> &data);
 | 
			
		||||
	static ConnectionEventPtr peerAdded(session_t peer_id, Address address);
 | 
			
		||||
	static ConnectionEventPtr peerRemoved(session_t peer_id, bool is_timeout, Address address);
 | 
			
		||||
	static ConnectionEventPtr bindFailed();
 | 
			
		||||
 | 
			
		||||
	void dataReceived(session_t peer_id_, const Buffer<u8> &data_)
 | 
			
		||||
	{
 | 
			
		||||
		type = CONNEVENT_DATA_RECEIVED;
 | 
			
		||||
		peer_id = peer_id_;
 | 
			
		||||
		data = data_;
 | 
			
		||||
	}
 | 
			
		||||
	void peerAdded(session_t peer_id_, Address address_)
 | 
			
		||||
	{
 | 
			
		||||
		type = CONNEVENT_PEER_ADDED;
 | 
			
		||||
		peer_id = peer_id_;
 | 
			
		||||
		address = address_;
 | 
			
		||||
	}
 | 
			
		||||
	void peerRemoved(session_t peer_id_, bool timeout_, Address address_)
 | 
			
		||||
	{
 | 
			
		||||
		type = CONNEVENT_PEER_REMOVED;
 | 
			
		||||
		peer_id = peer_id_;
 | 
			
		||||
		timeout = timeout_;
 | 
			
		||||
		address = address_;
 | 
			
		||||
	}
 | 
			
		||||
	void bindFailed()
 | 
			
		||||
	{
 | 
			
		||||
		type = CONNEVENT_BIND_FAILED;
 | 
			
		||||
	}
 | 
			
		||||
	const char *describe() const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	ConnectionEvent(ConnectionEventType type_) :
 | 
			
		||||
		type(type_) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class PeerHandler;
 | 
			
		||||
@@ -752,10 +705,9 @@ public:
 | 
			
		||||
	~Connection();
 | 
			
		||||
 | 
			
		||||
	/* Interface */
 | 
			
		||||
	ConnectionEvent waitEvent(u32 timeout_ms);
 | 
			
		||||
	// Warning: creates an unnecessary copy, prefer putCommand(T&&) if possible
 | 
			
		||||
	void putCommand(const ConnectionCommand &c);
 | 
			
		||||
	void putCommand(ConnectionCommand &&c);
 | 
			
		||||
	ConnectionEventPtr waitEvent(u32 timeout_ms);
 | 
			
		||||
 | 
			
		||||
	void putCommand(ConnectionCommandPtr c);
 | 
			
		||||
 | 
			
		||||
	void SetTimeoutMs(u32 timeout) { m_bc_receive_timeout = timeout; }
 | 
			
		||||
	void Serve(Address bind_addr);
 | 
			
		||||
@@ -785,8 +737,6 @@ protected:
 | 
			
		||||
 | 
			
		||||
	void sendAck(session_t peer_id, u8 channelnum, u16 seqnum);
 | 
			
		||||
 | 
			
		||||
	void PrintInfo(std::ostream &out);
 | 
			
		||||
 | 
			
		||||
	std::vector<session_t> getPeerIDs()
 | 
			
		||||
	{
 | 
			
		||||
		MutexAutoLock peerlock(m_peers_mutex);
 | 
			
		||||
@@ -795,13 +745,11 @@ protected:
 | 
			
		||||
 | 
			
		||||
	UDPSocket m_udpSocket;
 | 
			
		||||
	// Command queue: user -> SendThread
 | 
			
		||||
	MutexedQueue<ConnectionCommand> m_command_queue;
 | 
			
		||||
	MutexedQueue<ConnectionCommandPtr> m_command_queue;
 | 
			
		||||
 | 
			
		||||
	bool Receive(NetworkPacket *pkt, u32 timeout);
 | 
			
		||||
 | 
			
		||||
	// Warning: creates an unnecessary copy, prefer putEvent(T&&) if possible
 | 
			
		||||
	void putEvent(const ConnectionEvent &e);
 | 
			
		||||
	void putEvent(ConnectionEvent &&e);
 | 
			
		||||
	void putEvent(ConnectionEventPtr e);
 | 
			
		||||
 | 
			
		||||
	void TriggerSend();
 | 
			
		||||
	
 | 
			
		||||
@@ -811,7 +759,7 @@ protected:
 | 
			
		||||
	}
 | 
			
		||||
private:
 | 
			
		||||
	// Event queue: ReceiveThread -> user
 | 
			
		||||
	MutexedQueue<ConnectionEvent> m_event_queue;
 | 
			
		||||
	MutexedQueue<ConnectionEventPtr> m_event_queue;
 | 
			
		||||
 | 
			
		||||
	session_t m_peer_id = 0;
 | 
			
		||||
	u32 m_protocol_id;
 | 
			
		||||
@@ -823,7 +771,7 @@ private:
 | 
			
		||||
	std::unique_ptr<ConnectionSendThread> m_sendThread;
 | 
			
		||||
	std::unique_ptr<ConnectionReceiveThread> m_receiveThread;
 | 
			
		||||
 | 
			
		||||
	std::mutex m_info_mutex;
 | 
			
		||||
	mutable std::mutex m_info_mutex;
 | 
			
		||||
 | 
			
		||||
	// Backwards compatibility
 | 
			
		||||
	PeerHandler *m_bc_peerhandler;
 | 
			
		||||
 
 | 
			
		||||
@@ -50,11 +50,11 @@ std::mutex log_conthread_mutex;
 | 
			
		||||
 | 
			
		||||
#define WINDOW_SIZE 5
 | 
			
		||||
 | 
			
		||||
static session_t readPeerId(u8 *packetdata)
 | 
			
		||||
static session_t readPeerId(const u8 *packetdata)
 | 
			
		||||
{
 | 
			
		||||
	return readU16(&packetdata[4]);
 | 
			
		||||
}
 | 
			
		||||
static u8 readChannel(u8 *packetdata)
 | 
			
		||||
static u8 readChannel(const u8 *packetdata)
 | 
			
		||||
{
 | 
			
		||||
	return readU8(&packetdata[6]);
 | 
			
		||||
}
 | 
			
		||||
@@ -114,9 +114,9 @@ void *ConnectionSendThread::run()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* translate commands to packets */
 | 
			
		||||
		ConnectionCommand c = m_connection->m_command_queue.pop_frontNoEx(0);
 | 
			
		||||
		while (c.type != CONNCMD_NONE) {
 | 
			
		||||
			if (c.reliable)
 | 
			
		||||
		auto c = m_connection->m_command_queue.pop_frontNoEx(0);
 | 
			
		||||
		while (c && c->type != CONNCMD_NONE) {
 | 
			
		||||
			if (c->reliable)
 | 
			
		||||
				processReliableCommand(c);
 | 
			
		||||
			else
 | 
			
		||||
				processNonReliableCommand(c);
 | 
			
		||||
@@ -227,21 +227,21 @@ void ConnectionSendThread::runTimeouts(float dtime)
 | 
			
		||||
			m_iteration_packets_avaialble -= timed_outs.size();
 | 
			
		||||
 | 
			
		||||
			for (const auto &k : timed_outs) {
 | 
			
		||||
				u8 channelnum = readChannel(*k.data);
 | 
			
		||||
				u16 seqnum = readU16(&(k.data[BASE_HEADER_SIZE + 1]));
 | 
			
		||||
				u8 channelnum = readChannel(k->data);
 | 
			
		||||
				u16 seqnum = k->getSeqnum();
 | 
			
		||||
 | 
			
		||||
				channel.UpdateBytesLost(k.data.getSize());
 | 
			
		||||
				channel.UpdateBytesLost(k->size());
 | 
			
		||||
 | 
			
		||||
				LOG(derr_con << m_connection->getDesc()
 | 
			
		||||
					<< "RE-SENDING timed-out RELIABLE to "
 | 
			
		||||
					<< k.address.serializeString()
 | 
			
		||||
					<< k->address.serializeString()
 | 
			
		||||
					<< "(t/o=" << resend_timeout << "): "
 | 
			
		||||
					<< "count=" << k.resend_count
 | 
			
		||||
					<< "count=" << k->resend_count
 | 
			
		||||
					<< ", channel=" << ((int) channelnum & 0xff)
 | 
			
		||||
					<< ", seqnum=" << seqnum
 | 
			
		||||
					<< std::endl);
 | 
			
		||||
 | 
			
		||||
				rawSend(k);
 | 
			
		||||
				rawSend(k.get());
 | 
			
		||||
 | 
			
		||||
				// do not handle rtt here as we can't decide if this packet was
 | 
			
		||||
				// lost or really takes more time to transmit
 | 
			
		||||
@@ -274,25 +274,24 @@ void ConnectionSendThread::runTimeouts(float dtime)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConnectionSendThread::rawSend(const BufferedPacket &packet)
 | 
			
		||||
void ConnectionSendThread::rawSend(const BufferedPacket *p)
 | 
			
		||||
{
 | 
			
		||||
	try {
 | 
			
		||||
		m_connection->m_udpSocket.Send(packet.address, *packet.data,
 | 
			
		||||
			packet.data.getSize());
 | 
			
		||||
		m_connection->m_udpSocket.Send(p->address, p->data, p->size());
 | 
			
		||||
		LOG(dout_con << m_connection->getDesc()
 | 
			
		||||
			<< " rawSend: " << packet.data.getSize()
 | 
			
		||||
			<< " rawSend: " << p->size()
 | 
			
		||||
			<< " bytes sent" << std::endl);
 | 
			
		||||
	} catch (SendFailedException &e) {
 | 
			
		||||
		LOG(derr_con << m_connection->getDesc()
 | 
			
		||||
			<< "Connection::rawSend(): SendFailedException: "
 | 
			
		||||
			<< packet.address.serializeString() << std::endl);
 | 
			
		||||
			<< p->address.serializeString() << std::endl);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConnectionSendThread::sendAsPacketReliable(BufferedPacket &p, Channel *channel)
 | 
			
		||||
void ConnectionSendThread::sendAsPacketReliable(BufferedPacketPtr &p, Channel *channel)
 | 
			
		||||
{
 | 
			
		||||
	try {
 | 
			
		||||
		p.absolute_send_time = porting::getTimeMs();
 | 
			
		||||
		p->absolute_send_time = porting::getTimeMs();
 | 
			
		||||
		// Buffer the packet
 | 
			
		||||
		channel->outgoing_reliables_sent.insert(p,
 | 
			
		||||
			(channel->readOutgoingSequenceNumber() - MAX_RELIABLE_WINDOW_SIZE)
 | 
			
		||||
@@ -305,7 +304,7 @@ void ConnectionSendThread::sendAsPacketReliable(BufferedPacket &p, Channel *chan
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Send the packet
 | 
			
		||||
	rawSend(p);
 | 
			
		||||
	rawSend(p.get());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ConnectionSendThread::rawSendAsPacket(session_t peer_id, u8 channelnum,
 | 
			
		||||
@@ -321,11 +320,10 @@ bool ConnectionSendThread::rawSendAsPacket(session_t peer_id, u8 channelnum,
 | 
			
		||||
	Channel *channel = &(dynamic_cast<UDPPeer *>(&peer)->channels[channelnum]);
 | 
			
		||||
 | 
			
		||||
	if (reliable) {
 | 
			
		||||
		bool have_sequence_number_for_raw_packet = true;
 | 
			
		||||
		u16 seqnum =
 | 
			
		||||
			channel->getOutgoingSequenceNumber(have_sequence_number_for_raw_packet);
 | 
			
		||||
		bool have_seqnum = false;
 | 
			
		||||
		const u16 seqnum = channel->getOutgoingSequenceNumber(have_seqnum);
 | 
			
		||||
 | 
			
		||||
		if (!have_sequence_number_for_raw_packet)
 | 
			
		||||
		if (!have_seqnum)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		SharedBuffer<u8> reliable = makeReliablePacket(data, seqnum);
 | 
			
		||||
@@ -333,13 +331,12 @@ bool ConnectionSendThread::rawSendAsPacket(session_t peer_id, u8 channelnum,
 | 
			
		||||
		peer->getAddress(MTP_MINETEST_RELIABLE_UDP, peer_address);
 | 
			
		||||
 | 
			
		||||
		// Add base headers and make a packet
 | 
			
		||||
		BufferedPacket p = con::makePacket(peer_address, reliable,
 | 
			
		||||
		BufferedPacketPtr p = con::makePacket(peer_address, reliable,
 | 
			
		||||
			m_connection->GetProtocolID(), m_connection->GetPeerID(),
 | 
			
		||||
			channelnum);
 | 
			
		||||
 | 
			
		||||
		// first check if our send window is already maxed out
 | 
			
		||||
		if (channel->outgoing_reliables_sent.size()
 | 
			
		||||
			< channel->getWindowSize()) {
 | 
			
		||||
		if (channel->outgoing_reliables_sent.size() < channel->getWindowSize()) {
 | 
			
		||||
			LOG(dout_con << m_connection->getDesc()
 | 
			
		||||
				<< " INFO: sending a reliable packet to peer_id " << peer_id
 | 
			
		||||
				<< " channel: " << (u32)channelnum
 | 
			
		||||
@@ -352,19 +349,19 @@ bool ConnectionSendThread::rawSendAsPacket(session_t peer_id, u8 channelnum,
 | 
			
		||||
			<< " INFO: queueing reliable packet for peer_id: " << peer_id
 | 
			
		||||
			<< " channel: " << (u32)channelnum
 | 
			
		||||
			<< " seqnum: " << seqnum << std::endl);
 | 
			
		||||
		channel->queued_reliables.push(std::move(p));
 | 
			
		||||
		channel->queued_reliables.push(p);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Address peer_address;
 | 
			
		||||
	if (peer->getAddress(MTP_UDP, peer_address)) {
 | 
			
		||||
		// Add base headers and make a packet
 | 
			
		||||
		BufferedPacket p = con::makePacket(peer_address, data,
 | 
			
		||||
		BufferedPacketPtr p = con::makePacket(peer_address, data,
 | 
			
		||||
			m_connection->GetProtocolID(), m_connection->GetPeerID(),
 | 
			
		||||
			channelnum);
 | 
			
		||||
 | 
			
		||||
		// Send the packet
 | 
			
		||||
		rawSend(p);
 | 
			
		||||
		rawSend(p.get());
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -374,11 +371,11 @@ bool ConnectionSendThread::rawSendAsPacket(session_t peer_id, u8 channelnum,
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConnectionSendThread::processReliableCommand(ConnectionCommand &c)
 | 
			
		||||
void ConnectionSendThread::processReliableCommand(ConnectionCommandPtr &c)
 | 
			
		||||
{
 | 
			
		||||
	assert(c.reliable);  // Pre-condition
 | 
			
		||||
	assert(c->reliable);  // Pre-condition
 | 
			
		||||
 | 
			
		||||
	switch (c.type) {
 | 
			
		||||
	switch (c->type) {
 | 
			
		||||
		case CONNCMD_NONE:
 | 
			
		||||
			LOG(dout_con << m_connection->getDesc()
 | 
			
		||||
				<< "UDP processing reliable CONNCMD_NONE" << std::endl);
 | 
			
		||||
@@ -399,7 +396,7 @@ void ConnectionSendThread::processReliableCommand(ConnectionCommand &c)
 | 
			
		||||
		case CONCMD_CREATE_PEER:
 | 
			
		||||
			LOG(dout_con << m_connection->getDesc()
 | 
			
		||||
				<< "UDP processing reliable CONCMD_CREATE_PEER" << std::endl);
 | 
			
		||||
			if (!rawSendAsPacket(c.peer_id, c.channelnum, c.data, c.reliable)) {
 | 
			
		||||
			if (!rawSendAsPacket(c->peer_id, c->channelnum, c->data, c->reliable)) {
 | 
			
		||||
				/* put to queue if we couldn't send it immediately */
 | 
			
		||||
				sendReliable(c);
 | 
			
		||||
			}
 | 
			
		||||
@@ -412,13 +409,14 @@ void ConnectionSendThread::processReliableCommand(ConnectionCommand &c)
 | 
			
		||||
			FATAL_ERROR("Got command that shouldn't be reliable as reliable command");
 | 
			
		||||
		default:
 | 
			
		||||
			LOG(dout_con << m_connection->getDesc()
 | 
			
		||||
				<< " Invalid reliable command type: " << c.type << std::endl);
 | 
			
		||||
				<< " Invalid reliable command type: " << c->type << std::endl);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void ConnectionSendThread::processNonReliableCommand(ConnectionCommand &c)
 | 
			
		||||
void ConnectionSendThread::processNonReliableCommand(ConnectionCommandPtr &c_ptr)
 | 
			
		||||
{
 | 
			
		||||
	const ConnectionCommand &c = *c_ptr;
 | 
			
		||||
	assert(!c.reliable); // Pre-condition
 | 
			
		||||
 | 
			
		||||
	switch (c.type) {
 | 
			
		||||
@@ -480,9 +478,7 @@ void ConnectionSendThread::serve(Address bind_address)
 | 
			
		||||
	}
 | 
			
		||||
	catch (SocketException &e) {
 | 
			
		||||
		// Create event
 | 
			
		||||
		ConnectionEvent ce;
 | 
			
		||||
		ce.bindFailed();
 | 
			
		||||
		m_connection->putEvent(ce);
 | 
			
		||||
		m_connection->putEvent(ConnectionEvent::bindFailed());
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -495,9 +491,7 @@ void ConnectionSendThread::connect(Address address)
 | 
			
		||||
	UDPPeer *peer = m_connection->createServerPeer(address);
 | 
			
		||||
 | 
			
		||||
	// Create event
 | 
			
		||||
	ConnectionEvent e;
 | 
			
		||||
	e.peerAdded(peer->id, peer->address);
 | 
			
		||||
	m_connection->putEvent(e);
 | 
			
		||||
	m_connection->putEvent(ConnectionEvent::peerAdded(peer->id, peer->address));
 | 
			
		||||
 | 
			
		||||
	Address bind_addr;
 | 
			
		||||
 | 
			
		||||
@@ -586,9 +580,9 @@ void ConnectionSendThread::send(session_t peer_id, u8 channelnum,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConnectionSendThread::sendReliable(ConnectionCommand &c)
 | 
			
		||||
void ConnectionSendThread::sendReliable(ConnectionCommandPtr &c)
 | 
			
		||||
{
 | 
			
		||||
	PeerHelper peer = m_connection->getPeerNoEx(c.peer_id);
 | 
			
		||||
	PeerHelper peer = m_connection->getPeerNoEx(c->peer_id);
 | 
			
		||||
	if (!peer)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
@@ -604,7 +598,7 @@ void ConnectionSendThread::sendToAll(u8 channelnum, const SharedBuffer<u8> &data
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConnectionSendThread::sendToAllReliable(ConnectionCommand &c)
 | 
			
		||||
void ConnectionSendThread::sendToAllReliable(ConnectionCommandPtr &c)
 | 
			
		||||
{
 | 
			
		||||
	std::vector<session_t> peerids = m_connection->getPeerIDs();
 | 
			
		||||
 | 
			
		||||
@@ -663,8 +657,12 @@ void ConnectionSendThread::sendPackets(float dtime)
 | 
			
		||||
		// first send queued reliable packets for all peers (if possible)
 | 
			
		||||
		for (unsigned int i = 0; i < CHANNEL_COUNT; i++) {
 | 
			
		||||
			Channel &channel = udpPeer->channels[i];
 | 
			
		||||
			u16 next_to_ack = 0;
 | 
			
		||||
 | 
			
		||||
			// Reduces logging verbosity
 | 
			
		||||
			if (channel.queued_reliables.empty())
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			u16 next_to_ack = 0;
 | 
			
		||||
			channel.outgoing_reliables_sent.getFirstSeqnum(next_to_ack);
 | 
			
		||||
			u16 next_to_receive = 0;
 | 
			
		||||
			channel.incoming_reliables.getFirstSeqnum(next_to_receive);
 | 
			
		||||
@@ -694,13 +692,13 @@ void ConnectionSendThread::sendPackets(float dtime)
 | 
			
		||||
					channel.outgoing_reliables_sent.size()
 | 
			
		||||
					< channel.getWindowSize() &&
 | 
			
		||||
					peer->m_increment_packets_remaining > 0) {
 | 
			
		||||
				BufferedPacket p = std::move(channel.queued_reliables.front());
 | 
			
		||||
				BufferedPacketPtr p = channel.queued_reliables.front();
 | 
			
		||||
				channel.queued_reliables.pop();
 | 
			
		||||
 | 
			
		||||
				LOG(dout_con << m_connection->getDesc()
 | 
			
		||||
					<< " INFO: sending a queued reliable packet "
 | 
			
		||||
					<< " channel: " << i
 | 
			
		||||
					<< ", seqnum: " << readU16(&p.data[BASE_HEADER_SIZE + 1])
 | 
			
		||||
					<< ", seqnum: " << p->getSeqnum()
 | 
			
		||||
					<< std::endl);
 | 
			
		||||
 | 
			
		||||
				sendAsPacketReliable(p, &channel);
 | 
			
		||||
@@ -881,17 +879,14 @@ void ConnectionReceiveThread::receive(SharedBuffer<u8> &packetdata,
 | 
			
		||||
	try {
 | 
			
		||||
		// First, see if there any buffered packets we can process now
 | 
			
		||||
		if (packet_queued) {
 | 
			
		||||
			bool data_left = true;
 | 
			
		||||
			session_t peer_id;
 | 
			
		||||
			SharedBuffer<u8> resultdata;
 | 
			
		||||
			while (data_left) {
 | 
			
		||||
			while (true) {
 | 
			
		||||
				try {
 | 
			
		||||
					data_left = getFromBuffers(peer_id, resultdata);
 | 
			
		||||
					if (data_left) {
 | 
			
		||||
						ConnectionEvent e;
 | 
			
		||||
						e.dataReceived(peer_id, resultdata);
 | 
			
		||||
						m_connection->putEvent(std::move(e));
 | 
			
		||||
					}
 | 
			
		||||
					if (!getFromBuffers(peer_id, resultdata))
 | 
			
		||||
						break;
 | 
			
		||||
 | 
			
		||||
					m_connection->putEvent(ConnectionEvent::dataReceived(peer_id, resultdata));
 | 
			
		||||
				}
 | 
			
		||||
				catch (ProcessedSilentlyException &e) {
 | 
			
		||||
					/* try reading again */
 | 
			
		||||
@@ -908,7 +903,7 @@ void ConnectionReceiveThread::receive(SharedBuffer<u8> &packetdata,
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		if ((received_size < BASE_HEADER_SIZE) ||
 | 
			
		||||
			(readU32(&packetdata[0]) != m_connection->GetProtocolID())) {
 | 
			
		||||
				(readU32(&packetdata[0]) != m_connection->GetProtocolID())) {
 | 
			
		||||
			LOG(derr_con << m_connection->getDesc()
 | 
			
		||||
				<< "Receive(): Invalid incoming packet, "
 | 
			
		||||
				<< "size: " << received_size
 | 
			
		||||
@@ -999,9 +994,7 @@ void ConnectionReceiveThread::receive(SharedBuffer<u8> &packetdata,
 | 
			
		||||
				<< ", channel: " << (u32)channelnum << ", returned "
 | 
			
		||||
				<< resultdata.getSize() << " bytes" << std::endl);
 | 
			
		||||
 | 
			
		||||
			ConnectionEvent e;
 | 
			
		||||
			e.dataReceived(peer_id, resultdata);
 | 
			
		||||
			m_connection->putEvent(std::move(e));
 | 
			
		||||
			m_connection->putEvent(ConnectionEvent::dataReceived(peer_id, resultdata));
 | 
			
		||||
		}
 | 
			
		||||
		catch (ProcessedSilentlyException &e) {
 | 
			
		||||
		}
 | 
			
		||||
@@ -1026,10 +1019,11 @@ bool ConnectionReceiveThread::getFromBuffers(session_t &peer_id, SharedBuffer<u8
 | 
			
		||||
		if (!peer)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (dynamic_cast<UDPPeer *>(&peer) == 0)
 | 
			
		||||
		UDPPeer *p = dynamic_cast<UDPPeer *>(&peer);
 | 
			
		||||
		if (!p)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		for (Channel &channel : (dynamic_cast<UDPPeer *>(&peer))->channels) {
 | 
			
		||||
		for (Channel &channel : p->channels) {
 | 
			
		||||
			if (checkIncomingBuffers(&channel, peer_id, dst)) {
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
@@ -1042,32 +1036,34 @@ bool ConnectionReceiveThread::checkIncomingBuffers(Channel *channel,
 | 
			
		||||
	session_t &peer_id, SharedBuffer<u8> &dst)
 | 
			
		||||
{
 | 
			
		||||
	u16 firstseqnum = 0;
 | 
			
		||||
	if (channel->incoming_reliables.getFirstSeqnum(firstseqnum)) {
 | 
			
		||||
		if (firstseqnum == channel->readNextIncomingSeqNum()) {
 | 
			
		||||
			BufferedPacket p = channel->incoming_reliables.popFirst();
 | 
			
		||||
			peer_id = readPeerId(*p.data);
 | 
			
		||||
			u8 channelnum = readChannel(*p.data);
 | 
			
		||||
			u16 seqnum = readU16(&p.data[BASE_HEADER_SIZE + 1]);
 | 
			
		||||
	if (!channel->incoming_reliables.getFirstSeqnum(firstseqnum))
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
			LOG(dout_con << m_connection->getDesc()
 | 
			
		||||
				<< "UNBUFFERING TYPE_RELIABLE"
 | 
			
		||||
				<< " seqnum=" << seqnum
 | 
			
		||||
				<< " peer_id=" << peer_id
 | 
			
		||||
				<< " channel=" << ((int) channelnum & 0xff)
 | 
			
		||||
				<< std::endl);
 | 
			
		||||
	if (firstseqnum != channel->readNextIncomingSeqNum())
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
			channel->incNextIncomingSeqNum();
 | 
			
		||||
	BufferedPacketPtr p = channel->incoming_reliables.popFirst();
 | 
			
		||||
 | 
			
		||||
			u32 headers_size = BASE_HEADER_SIZE + RELIABLE_HEADER_SIZE;
 | 
			
		||||
			// Get out the inside packet and re-process it
 | 
			
		||||
			SharedBuffer<u8> payload(p.data.getSize() - headers_size);
 | 
			
		||||
			memcpy(*payload, &p.data[headers_size], payload.getSize());
 | 
			
		||||
	peer_id = readPeerId(p->data); // Carried over to caller function
 | 
			
		||||
	u8 channelnum = readChannel(p->data);
 | 
			
		||||
	u16 seqnum = p->getSeqnum();
 | 
			
		||||
 | 
			
		||||
			dst = processPacket(channel, payload, peer_id, channelnum, true);
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false;
 | 
			
		||||
	LOG(dout_con << m_connection->getDesc()
 | 
			
		||||
		<< "UNBUFFERING TYPE_RELIABLE"
 | 
			
		||||
		<< " seqnum=" << seqnum
 | 
			
		||||
		<< " peer_id=" << peer_id
 | 
			
		||||
		<< " channel=" << ((int) channelnum & 0xff)
 | 
			
		||||
		<< std::endl);
 | 
			
		||||
 | 
			
		||||
	channel->incNextIncomingSeqNum();
 | 
			
		||||
 | 
			
		||||
	u32 headers_size = BASE_HEADER_SIZE + RELIABLE_HEADER_SIZE;
 | 
			
		||||
	// Get out the inside packet and re-process it
 | 
			
		||||
	SharedBuffer<u8> payload(p->size() - headers_size);
 | 
			
		||||
	memcpy(*payload, &p->data[headers_size], payload.getSize());
 | 
			
		||||
 | 
			
		||||
	dst = processPacket(channel, payload, peer_id, channelnum, true);
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SharedBuffer<u8> ConnectionReceiveThread::processPacket(Channel *channel,
 | 
			
		||||
@@ -1115,7 +1111,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Control(Channel *chan
 | 
			
		||||
	if (packetdata.getSize() < 2)
 | 
			
		||||
		throw InvalidIncomingDataException("packetdata.getSize() < 2");
 | 
			
		||||
 | 
			
		||||
	u8 controltype = readU8(&(packetdata[1]));
 | 
			
		||||
	ControlType controltype = (ControlType)readU8(&(packetdata[1]));
 | 
			
		||||
 | 
			
		||||
	if (controltype == CONTROLTYPE_ACK) {
 | 
			
		||||
		assert(channel != NULL);
 | 
			
		||||
@@ -1131,7 +1127,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Control(Channel *chan
 | 
			
		||||
			<< seqnum << " ]" << std::endl);
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
			BufferedPacket p = channel->outgoing_reliables_sent.popSeqnum(seqnum);
 | 
			
		||||
			BufferedPacketPtr p = channel->outgoing_reliables_sent.popSeqnum(seqnum);
 | 
			
		||||
 | 
			
		||||
			// the rtt calculation will be a bit off for re-sent packets but that's okay
 | 
			
		||||
			{
 | 
			
		||||
@@ -1140,14 +1136,14 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Control(Channel *chan
 | 
			
		||||
 | 
			
		||||
				// a overflow is quite unlikely but as it'd result in major
 | 
			
		||||
				// rtt miscalculation we handle it here
 | 
			
		||||
				if (current_time > p.absolute_send_time) {
 | 
			
		||||
					float rtt = (current_time - p.absolute_send_time) / 1000.0;
 | 
			
		||||
				if (current_time > p->absolute_send_time) {
 | 
			
		||||
					float rtt = (current_time - p->absolute_send_time) / 1000.0;
 | 
			
		||||
 | 
			
		||||
					// Let peer calculate stuff according to it
 | 
			
		||||
					// (avg_rtt and resend_timeout)
 | 
			
		||||
					dynamic_cast<UDPPeer *>(peer)->reportRTT(rtt);
 | 
			
		||||
				} else if (p.totaltime > 0) {
 | 
			
		||||
					float rtt = p.totaltime;
 | 
			
		||||
				} else if (p->totaltime > 0) {
 | 
			
		||||
					float rtt = p->totaltime;
 | 
			
		||||
 | 
			
		||||
					// Let peer calculate stuff according to it
 | 
			
		||||
					// (avg_rtt and resend_timeout)
 | 
			
		||||
@@ -1156,7 +1152,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Control(Channel *chan
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// put bytes for max bandwidth calculation
 | 
			
		||||
			channel->UpdateBytesSent(p.data.getSize(), 1);
 | 
			
		||||
			channel->UpdateBytesSent(p->size(), 1);
 | 
			
		||||
			if (channel->outgoing_reliables_sent.size() == 0)
 | 
			
		||||
				m_connection->TriggerSend();
 | 
			
		||||
		} catch (NotFoundException &e) {
 | 
			
		||||
@@ -1204,7 +1200,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Control(Channel *chan
 | 
			
		||||
		throw ProcessedSilentlyException("Got a DISCO");
 | 
			
		||||
	} else {
 | 
			
		||||
		LOG(derr_con << m_connection->getDesc()
 | 
			
		||||
			<< "INVALID TYPE_CONTROL: invalid controltype="
 | 
			
		||||
			<< "INVALID controltype="
 | 
			
		||||
			<< ((int) controltype & 0xff) << std::endl);
 | 
			
		||||
		throw InvalidIncomingDataException("Invalid control type");
 | 
			
		||||
	}
 | 
			
		||||
@@ -1232,7 +1228,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Split(Channel *channe
 | 
			
		||||
	if (peer->getAddress(MTP_UDP, peer_address)) {
 | 
			
		||||
		// We have to create a packet again for buffering
 | 
			
		||||
		// This isn't actually too bad an idea.
 | 
			
		||||
		BufferedPacket packet = makePacket(peer_address,
 | 
			
		||||
		BufferedPacketPtr packet = con::makePacket(peer_address,
 | 
			
		||||
			packetdata,
 | 
			
		||||
			m_connection->GetProtocolID(),
 | 
			
		||||
			peer->id,
 | 
			
		||||
@@ -1267,7 +1263,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Reliable(Channel *cha
 | 
			
		||||
	if (packetdata.getSize() < RELIABLE_HEADER_SIZE)
 | 
			
		||||
		throw InvalidIncomingDataException("packetdata.getSize() < RELIABLE_HEADER_SIZE");
 | 
			
		||||
 | 
			
		||||
	u16 seqnum = readU16(&packetdata[1]);
 | 
			
		||||
	const u16 seqnum = readU16(&packetdata[1]);
 | 
			
		||||
	bool is_future_packet = false;
 | 
			
		||||
	bool is_old_packet = false;
 | 
			
		||||
 | 
			
		||||
@@ -1311,7 +1307,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Reliable(Channel *cha
 | 
			
		||||
		// This one comes later, buffer it.
 | 
			
		||||
		// Actually we have to make a packet to buffer one.
 | 
			
		||||
		// Well, we have all the ingredients, so just do it.
 | 
			
		||||
		BufferedPacket packet = con::makePacket(
 | 
			
		||||
		BufferedPacketPtr packet = con::makePacket(
 | 
			
		||||
			peer_address,
 | 
			
		||||
			packetdata,
 | 
			
		||||
			m_connection->GetProtocolID(),
 | 
			
		||||
@@ -1328,9 +1324,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Reliable(Channel *cha
 | 
			
		||||
			throw ProcessedQueued("Buffered future reliable packet");
 | 
			
		||||
		} catch (AlreadyExistsException &e) {
 | 
			
		||||
		} catch (IncomingDataCorruption &e) {
 | 
			
		||||
			ConnectionCommand discon;
 | 
			
		||||
			discon.disconnect_peer(peer->id);
 | 
			
		||||
			m_connection->putCommand(discon);
 | 
			
		||||
			m_connection->putCommand(ConnectionCommand::disconnect_peer(peer->id));
 | 
			
		||||
 | 
			
		||||
			LOG(derr_con << m_connection->getDesc()
 | 
			
		||||
				<< "INVALID, TYPE_RELIABLE peer_id: " << peer->id
 | 
			
		||||
@@ -1351,7 +1345,7 @@ SharedBuffer<u8> ConnectionReceiveThread::handlePacketType_Reliable(Channel *cha
 | 
			
		||||
	u16 queued_seqnum = 0;
 | 
			
		||||
	if (channel->incoming_reliables.getFirstSeqnum(queued_seqnum)) {
 | 
			
		||||
		if (queued_seqnum == seqnum) {
 | 
			
		||||
			BufferedPacket queued_packet = channel->incoming_reliables.popFirst();
 | 
			
		||||
			BufferedPacketPtr queued_packet = channel->incoming_reliables.popFirst();
 | 
			
		||||
			/** TODO find a way to verify the new against the old packet */
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,25 @@ namespace con
 | 
			
		||||
 | 
			
		||||
class Connection;
 | 
			
		||||
 | 
			
		||||
struct OutgoingPacket
 | 
			
		||||
{
 | 
			
		||||
	session_t peer_id;
 | 
			
		||||
	u8 channelnum;
 | 
			
		||||
	SharedBuffer<u8> data;
 | 
			
		||||
	bool reliable;
 | 
			
		||||
	bool ack;
 | 
			
		||||
 | 
			
		||||
	OutgoingPacket(session_t peer_id_, u8 channelnum_, const SharedBuffer<u8> &data_,
 | 
			
		||||
			bool reliable_,bool ack_=false):
 | 
			
		||||
		peer_id(peer_id_),
 | 
			
		||||
		channelnum(channelnum_),
 | 
			
		||||
		data(data_),
 | 
			
		||||
		reliable(reliable_),
 | 
			
		||||
		ack(ack_)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class ConnectionSendThread : public Thread
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
@@ -51,27 +70,27 @@ public:
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	void runTimeouts(float dtime);
 | 
			
		||||
	void rawSend(const BufferedPacket &packet);
 | 
			
		||||
	void rawSend(const BufferedPacket *p);
 | 
			
		||||
	bool rawSendAsPacket(session_t peer_id, u8 channelnum,
 | 
			
		||||
			const SharedBuffer<u8> &data, bool reliable);
 | 
			
		||||
 | 
			
		||||
	void processReliableCommand(ConnectionCommand &c);
 | 
			
		||||
	void processNonReliableCommand(ConnectionCommand &c);
 | 
			
		||||
	void processReliableCommand(ConnectionCommandPtr &c);
 | 
			
		||||
	void processNonReliableCommand(ConnectionCommandPtr &c);
 | 
			
		||||
	void serve(Address bind_address);
 | 
			
		||||
	void connect(Address address);
 | 
			
		||||
	void disconnect();
 | 
			
		||||
	void disconnect_peer(session_t peer_id);
 | 
			
		||||
	void send(session_t peer_id, u8 channelnum, const SharedBuffer<u8> &data);
 | 
			
		||||
	void sendReliable(ConnectionCommand &c);
 | 
			
		||||
	void sendReliable(ConnectionCommandPtr &c);
 | 
			
		||||
	void sendToAll(u8 channelnum, const SharedBuffer<u8> &data);
 | 
			
		||||
	void sendToAllReliable(ConnectionCommand &c);
 | 
			
		||||
	void sendToAllReliable(ConnectionCommandPtr &c);
 | 
			
		||||
 | 
			
		||||
	void sendPackets(float dtime);
 | 
			
		||||
 | 
			
		||||
	void sendAsPacket(session_t peer_id, u8 channelnum, const SharedBuffer<u8> &data,
 | 
			
		||||
			bool ack = false);
 | 
			
		||||
 | 
			
		||||
	void sendAsPacketReliable(BufferedPacket &p, Channel *channel);
 | 
			
		||||
	void sendAsPacketReliable(BufferedPacketPtr &p, Channel *channel);
 | 
			
		||||
 | 
			
		||||
	bool packetsQueued();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -124,7 +124,7 @@ void TestConnection::testHelpers()
 | 
			
		||||
	Address a(127,0,0,1, 10);
 | 
			
		||||
	const u16 seqnum = 34352;
 | 
			
		||||
 | 
			
		||||
	con::BufferedPacket p1 = con::makePacket(a, data1,
 | 
			
		||||
	con::BufferedPacketPtr p1 = con::makePacket(a, data1,
 | 
			
		||||
			proto_id, peer_id, channel);
 | 
			
		||||
	/*
 | 
			
		||||
		We should now have a packet with this data:
 | 
			
		||||
@@ -135,10 +135,10 @@ void TestConnection::testHelpers()
 | 
			
		||||
		Data:
 | 
			
		||||
			[7] u8 data1[0]
 | 
			
		||||
	*/
 | 
			
		||||
	UASSERT(readU32(&p1.data[0]) == proto_id);
 | 
			
		||||
	UASSERT(readU16(&p1.data[4]) == peer_id);
 | 
			
		||||
	UASSERT(readU8(&p1.data[6]) == channel);
 | 
			
		||||
	UASSERT(readU8(&p1.data[7]) == data1[0]);
 | 
			
		||||
	UASSERT(readU32(&p1->data[0]) == proto_id);
 | 
			
		||||
	UASSERT(readU16(&p1->data[4]) == peer_id);
 | 
			
		||||
	UASSERT(readU8(&p1->data[6]) == channel);
 | 
			
		||||
	UASSERT(readU8(&p1->data[7]) == data1[0]);
 | 
			
		||||
 | 
			
		||||
	//infostream<<"initial data1[0]="<<((u32)data1[0]&0xff)<<std::endl;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
#include "irrlichttypes.h"
 | 
			
		||||
#include "debug.h" // For assert()
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <memory> // std::shared_ptr
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template<typename T> class ConstSharedPtr {
 | 
			
		||||
public:
 | 
			
		||||
	ConstSharedPtr(T *ptr) : ptr(ptr) {}
 | 
			
		||||
	ConstSharedPtr(const std::shared_ptr<T> &ptr) : ptr(ptr) {}
 | 
			
		||||
 | 
			
		||||
	const T* get() const noexcept { return ptr.get(); }
 | 
			
		||||
	const T& operator*() const noexcept { return *ptr.get(); }
 | 
			
		||||
	const T* operator->() const noexcept { return ptr.get(); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	std::shared_ptr<T> ptr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
class Buffer
 | 
			
		||||
@@ -40,17 +55,11 @@ public:
 | 
			
		||||
		else
 | 
			
		||||
			data = NULL;
 | 
			
		||||
	}
 | 
			
		||||
	Buffer(const Buffer &buffer)
 | 
			
		||||
	{
 | 
			
		||||
		m_size = buffer.m_size;
 | 
			
		||||
		if(m_size != 0)
 | 
			
		||||
		{
 | 
			
		||||
			data = new T[buffer.m_size];
 | 
			
		||||
			memcpy(data, buffer.data, buffer.m_size);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
			data = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Disable class copy
 | 
			
		||||
	Buffer(const Buffer &) = delete;
 | 
			
		||||
	Buffer &operator=(const Buffer &) = delete;
 | 
			
		||||
 | 
			
		||||
	Buffer(Buffer &&buffer)
 | 
			
		||||
	{
 | 
			
		||||
		m_size = buffer.m_size;
 | 
			
		||||
@@ -81,21 +90,6 @@ public:
 | 
			
		||||
		drop();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Buffer& operator=(const Buffer &buffer)
 | 
			
		||||
	{
 | 
			
		||||
		if(this == &buffer)
 | 
			
		||||
			return *this;
 | 
			
		||||
		drop();
 | 
			
		||||
		m_size = buffer.m_size;
 | 
			
		||||
		if(m_size != 0)
 | 
			
		||||
		{
 | 
			
		||||
			data = new T[buffer.m_size];
 | 
			
		||||
			memcpy(data, buffer.data, buffer.m_size);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
			data = NULL;
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
	Buffer& operator=(Buffer &&buffer)
 | 
			
		||||
	{
 | 
			
		||||
		if(this == &buffer)
 | 
			
		||||
@@ -113,6 +107,18 @@ public:
 | 
			
		||||
		return *this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void copyTo(Buffer &buffer) const
 | 
			
		||||
	{
 | 
			
		||||
		buffer.drop();
 | 
			
		||||
		buffer.m_size = m_size;
 | 
			
		||||
		if (m_size != 0) {
 | 
			
		||||
			buffer.data = new T[m_size];
 | 
			
		||||
			memcpy(buffer.data, data, m_size);
 | 
			
		||||
		} else {
 | 
			
		||||
			buffer.data = nullptr;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	T & operator[](unsigned int i) const
 | 
			
		||||
	{
 | 
			
		||||
		return data[i];
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user