/*
Minetest-c55
Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "connection.h"
#include "main.h"
#include "serialization.h"
#include "log.h"
#include "porting.h"
#include "util/serialize.h"
#include "util/numeric.h"
#include "util/string.h"
#include "settings.h"
namespace con
{
static u16 readPeerId(u8 *packetdata)
{
return readU16(&packetdata[4]);
}
static u8 readChannel(u8 *packetdata)
{
return readU8(&packetdata[6]);
}
BufferedPacket makePacket(Address &address, u8 *data, u32 datasize,
u32 protocol_id, u16 sender_peer_id, u8 channel)
{
u32 packet_size = datasize + 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);
memcpy(&p.data[BASE_HEADER_SIZE], data, datasize);
return p;
}
BufferedPacket makePacket(Address &address, SharedBuffer<u8> &data,
u32 protocol_id, u16 sender_peer_id, u8 channel)
{
return makePacket(address, *data, data.getSize(),
protocol_id, sender_peer_id, channel);
}
SharedBuffer<u8> makeOriginalPacket(
SharedBuffer<u8> data)
{
u32 header_size = 1;
u32 packet_size = data.getSize() + header_size;
SharedBuffer<u8> b(packet_size);
writeU8(&b[0], TYPE_ORIGINAL);
memcpy(&b[header_size], *data, data.getSize());
return b;
}
core::list<SharedBuffer<u8> > makeSplitPacket(
SharedBuffer<u8> data,
u32 chunksize_max,
u16 seqnum)
{
// Chunk packets, containing the TYPE_SPLIT header
core::list<SharedBuffer<u8> > chunks;
u32 chunk_header_size = 7;
u32 maximum_data_size = chunksize_max - chunk_header_size;
u32 start = 0;
u32 end = 0;
u32 chunk_num = 0;
do{
end = start + maximum_data_size - 1;
if(end > data.getSize() - 1)
end = data.getSize() - 1;
u32 payload_size = end - start + 1;
u32 packet_size = chunk_header_size + payload_size;
SharedBuffer<u8> chunk(packet_size);
writeU8(&chunk[0], TYPE_SPLIT);
writeU16(&chunk[1], seqnum);
// [3] u16 chunk_count is written at next stage
writeU16(&chunk[5], chunk_num);
memcpy(&chunk[chunk_header_size], &data[start], payload_size);
chunks.push_back(chunk);
start = end + 1;
chunk_num++;
}
while(end != data.getSize() - 1);
u16 chunk_count = chunks.getSize();
core::list<SharedBuffer<u8> >::Iterator i = chunks.begin();
for(; i != chunks.end(); i++)
{
// Write chunk_count
writeU16(&((*i)[3]), chunk_count);
}
return chunks;
}
core::list<SharedBuffer<u8> > makeAutoSplitPacket(
SharedBuffer<u8> data,
u32 chunksize_max,
u16 &split_seqnum)
{
u32 original_header_size = 1;
core::list<SharedBuffer<u8> > list;
if(data.getSize() + original_header_size > chunksize_max)
{
list = makeSplitPacket(data, chunksize_max, split_seqnum);
split_seqnum++;
return list;
}
else
{
list.push_back(makeOriginalPacket(data));
}
return list;
}
SharedBuffer<u8> makeReliablePacket(
SharedBuffer<u8> data,
u16 seqnum)
{
/*dstream<<"BEGIN SharedBuffer<u8> makeReliablePacket()"<<std::endl;
dstream<<"data.getSize()="<<data.getSize()<<", data[0]="
<<((unsigned int)data[0]&0xff)<<std::endl;*/
u32 header_size = 3;
u32 packet_size = data.getSize() + header_size;
SharedBuffer<u8> b(packet_size);
writeU8(&b[0], TYPE_RELIABLE);
writeU16(&b[1], seqnum);
memcpy(&b[header_size], *data, data.getSize());
/*dstream<<"data.getSize()="<<data.getSize()<<", data[0]="
<<((unsigned int)data[0]&0xff)<<std::endl;*/
//dstream<<"END SharedBuffer<u8> makeReliablePacket()"<<std::endl;
return b;
}
/*
ReliablePacketBuffer
*/
void ReliablePacketBuffer::print()
{
core::list<BufferedPacket>::Iterator i;
i = m_list.begin();
for(; i != m_list.end(); i++)
{
u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
dout_con<<s<<" ";
}
}
bool ReliablePacketBuffer::empty()
{
return m_list.empty();
}
u32 ReliablePacketBuffer::size()
{
return m_list.getSize();
}
RPBSearchResult ReliablePacketBuffer::findPacket(u16 seqnum)
{
core::list<BufferedPacket>::Iterator i;
i = m_list.begin();
for(; i != m_list.end(); i++)
{
u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
/*dout_con<<"findPacket(): finding seqnum="<<seqnum
<<", comparing to s="<<s<<std::endl;*/
if(s == seqnum)
break;
}
return i;
}
RPBSearchResult ReliablePacketBuffer::notFound()
{
return m_list.end();
}
u16 ReliablePacketBuffer::getFirstSeqnum()
{
if(empty())
throw NotFoundException("Buffer is empty");
BufferedPacket p = *m_list.begin();
return readU16(&p.data[BASE_HEADER_SIZE+1]);
}
BufferedPacket ReliablePacketBuffer::popFirst()
{
if(empty())
throw NotFoundException("Buffer is empty");
BufferedPacket p = *m_list.begin();
core::list<BufferedPacket>::Iterator i = m_list.begin();
m_list.erase(i);
return p;
}
BufferedPacket ReliablePacketBuffer::popSeqnum(u16 seqnum)
{
RPBSearchResult r = findPacket(seqnum);
if(r == notFound()){
dout_con<<"Not found"<<std::endl;
throw NotFoundException("seqnum not found in buffer");
}
BufferedPacket p = *r;
m_list.erase(r);
return p;
}
void ReliablePacketBuffer::insert(BufferedPacket &p)
{
assert(p.data.getSize() >= BASE_HEADER_SIZE+3);
u8 type = readU8(&p.data[BASE_HEADER_SIZE+0]);
assert(type == TYPE_RELIABLE);
u16 seqnum = readU16(&p.data[BASE_HEADER_SIZE+1]);
// 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);
// Done.
return;
}
// Otherwise find the right place
core::list<BufferedPacket>::Iterator i;
i = m_list.begin();
// Find the first packet in the list which has a higher seqnum
for(; i != m_list.end(); i++){
u16 s = readU16(&(i->data[BASE_HEADER_SIZE+1]));
if(s == seqnum){
throw AlreadyExistsException("Same seqnum in list");
}
if(seqnum_higher(s, seqnum)){
break;
}
}
// If we're at the end of the list, add the packet to the
// end of the list
if(i == m_list.end())
{
m_list.push_back(p);
// Done.
return;
}
// Insert before i
m_list.insert_before(i, p);
}
void ReliablePacketBuffer::incrementTimeouts(float dtime)
{
core::list<BufferedPacket>::Iterator i;
i = m_list.begin();
for(; i != m_list.end(); i++){
i->time += dtime;
i->totaltime += dtime;
}
}
void ReliablePacketBuffer::resetTimedOuts(float timeout)
{
core::list<BufferedPacket>::Iterator i;
i = m_list.begin();
for(; i != m_list.end(); i++){
if(i->time >= timeout)
i->time = 0.0;
}
}
bool ReliablePacketBuffer::anyTotaltimeReached(float timeout)
{
core::list<BufferedPacket>::Iterator i;
i = m_list.begin();
for(; i != m_list.end(); i++){
if(i->totaltime >= timeout)
return true;
}
return false;
}
core::list<BufferedPacket> ReliablePacketBuffer::getTimedOuts(float timeout)
{
core::list<BufferedPacket> timed_outs;
core::list<BufferedPacket>::Iterator i;
i = m_list.begin();
for(; i != m_list.end(); i++)
{
if(i->time >= timeout)
timed_outs.push_back(*i);
}
return timed_outs;
}
/*
IncomingSplitBuffer
*/
IncomingSplitBuffer::~IncomingSplitBuffer()
{
core::map<u16, IncomingSplitPacket*>::Iterator i;
i = m_buf.getIterator();
for(; i.atEnd() == false; i++)
{
delete i.getNode()->getValue();
}
}
/*
This will throw a GotSplitPacketException when a full
split packet is constructed.
*/
SharedBuffer<u8> IncomingSplitBuffer::insert(BufferedPacket &p, bool reliable)
{
u32 headersize = BASE_HEADER_SIZE + 7;
assert(p.data.getSize() >= headersize);
u8 type = readU8(&p.data[BASE_HEADER_SIZE+0]);
assert(type == TYPE_SPLIT);
u16 seqnum = readU16(&p.data[BASE_HEADER_SIZE+1]);
u16 chunk_count = readU16(&p.data[BASE_HEADER_SIZE+3]);
u16 chunk_num = readU16(&p.data[BASE_HEADER_SIZE+5]);
// Add if doesn't exist
if(m_buf.find(seqnum) == NULL)
{
IncomingSplitPacket *sp = new IncomingSplitPacket();
sp->chunk_count = chunk_count;
sp->reliable = reliable;
m_buf[seqnum] = sp;
}
IncomingSplitPacket *sp = m_buf[seqnum];
// TODO: These errors should be thrown or something? Dunno.
if(chunk_count != sp->chunk_count)
derr_con<<"Connection: WARNING: chunk_count="<<chunk_count
<<" != sp->chunk_count="<<sp->chunk_count
<<std::endl;
if(reliable != sp->reliable)
derr_con<<"Connection: WARNING: reliable="<<reliable
<<" != sp->reliable="<<sp->reliable
|