ddnet/src/packet.h

288 lines
5.5 KiB
C
Raw Normal View History

2007-05-22 15:03:32 +00:00
#include <baselib/stream/file.h>
#include <baselib/network.h>
// TODO: this is not KISS
class packet
{
protected:
enum
{
MAX_PACKET_SIZE = 1024,
};
// packet data
struct header
{
unsigned msg;
unsigned ack;
unsigned seq;
};
2007-05-24 10:57:18 +00:00
unsigned char packet_data[MAX_PACKET_SIZE];
2007-05-22 15:03:32 +00:00
unsigned char *current;
// these are used to prepend data in the packet
// used for debugging so we have checks that we
// pack and unpack the same way
enum
{
DEBUG_TYPE_INT=0x1,
DEBUG_TYPE_STR=0x2,
DEBUG_TYPE_RAW=0x3,
};
// writes an int to the packet
void write_int_raw(int i)
{
// TODO: check for overflow
*(int*)current = i;
current += sizeof(int);
}
// reads an int from the packet
2007-05-24 10:57:18 +00:00
int read_int_raw()
2007-05-22 15:03:32 +00:00
{
// TODO: check for overflow
2007-05-24 10:57:18 +00:00
int i = *(int*)current;
2007-05-22 15:03:32 +00:00
current += sizeof(int);
2007-05-24 10:57:18 +00:00
return i;
}
void debug_insert_mark(int type, int size)
{
write_int_raw((type<<16)|size);
}
void debug_verify_mark(int type, int size)
{
if(read_int_raw() == ((type<<16) | size))
dbg_assert(0, "error during packet disassembly");
2007-05-22 15:03:32 +00:00
}
public:
packet(unsigned msg=0)
{
current = packet_data;
current += sizeof(header);
((header*)packet_data)->msg = msg;
}
void set_header(unsigned ack, unsigned seq)
{
((header*)packet_data)->ack = ack;
((header*)packet_data)->seq = seq;
}
// writes an int to the packet
void write_int(int i)
{
2007-05-24 10:57:18 +00:00
debug_insert_mark(DEBUG_TYPE_INT, 4);
2007-05-22 15:03:32 +00:00
write_int_raw(i);
}
void write_raw(const char *raw, int size)
{
2007-05-24 10:57:18 +00:00
debug_insert_mark(DEBUG_TYPE_RAW, size);
2007-05-22 15:03:32 +00:00
while(size--)
*current++ = *raw++;
}
// writes a string to the packet
2007-05-24 10:57:18 +00:00
void write_str(const char *str)
2007-05-22 15:03:32 +00:00
{
2007-05-24 10:57:18 +00:00
debug_insert_mark(DEBUG_TYPE_STR, 0);
int s = strlen(str)+1;
write_int_raw(s);
for(;*str; current++, str++)
2007-05-22 15:03:32 +00:00
*current = *str;
2007-05-24 10:57:18 +00:00
*current = 0;
current++;
2007-05-22 15:03:32 +00:00
}
// reads an int from the packet
int read_int()
{
2007-05-24 10:57:18 +00:00
debug_verify_mark(DEBUG_TYPE_INT, 4);
return read_int_raw();
2007-05-22 15:03:32 +00:00
}
// reads a string from the packet
2007-05-24 10:57:18 +00:00
const char *read_str()
{
debug_verify_mark(DEBUG_TYPE_STR, 0);
const char *s = (const char *)current;
int size = read_int_raw();
current += size;
return s;
2007-05-22 15:03:32 +00:00
}
2007-05-24 10:57:18 +00:00
const char *read_raw(int size)
2007-05-22 15:03:32 +00:00
{
2007-05-24 10:57:18 +00:00
debug_verify_mark(DEBUG_TYPE_RAW, size);
const char *d = (const char *)current;
current += size;
return d;
2007-05-22 15:03:32 +00:00
}
// TODO: impelement this
bool is_good() const { return true; }
unsigned msg() const { return ((header*)packet_data)->msg; }
unsigned seq() const { return ((header*)packet_data)->seq; }
unsigned ack() const { return ((header*)packet_data)->ack; }
// access functions to get the size and data
int size() const { return (int)(current-(unsigned char*)packet_data); }
int max_size() const { return MAX_PACKET_SIZE; }
void *data() { return packet_data; }
};
//
class connection
{
baselib::socket_udp4 *socket;
baselib::netaddr4 addr;
unsigned seq;
unsigned ack;
unsigned last_ack;
unsigned counter_sent_bytes;
unsigned counter_recv_bytes;
public:
void counter_reset()
{
counter_sent_bytes = 0;
counter_recv_bytes = 0;
}
void counter_get(unsigned *sent, unsigned *recved)
{
*sent = counter_sent_bytes;
*recved = counter_recv_bytes;
}
void init(baselib::socket_udp4 *socket, const baselib::netaddr4 *addr)
{
this->addr = *addr;
this->socket = socket;
last_ack = 0;
ack = 0;
seq = 0;
counter_reset();
}
void send(packet *p)
{
if(p->msg()&(31<<1))
{
// vital packet
seq++;
// TODO: save packet, we might need to retransmit
}
p->set_header(ack, seq);
socket->send(&address(), p->data(), p->size());
counter_sent_bytes += p->size();
}
packet *feed(packet *p)
{
counter_recv_bytes += p->size();
if(p->msg()&(31<<1))
{
if(p->seq() == ack+1)
{
// packet in seqence, ack it
ack++;
//dbg_msg("network/connection", "packet in sequence. seq/ack=%x", ack);
return p;
}
else if(p->seq() > ack)
{
// TODO: request resend
// packet loss
dbg_msg("network/connection", "packet loss! seq=%x ack=%x+1", p->seq(), ack);
return p;
}
else
{
// we already got this packet
return 0x0;
}
}
if(last_ack != p->ack())
{
// TODO: remove acked packets
}
return p;
}
const baselib::netaddr4 &address() const { return addr; }
void update()
{
}
};
//const char *NETWORK_VERSION = "development";
enum
{
NETMSG_VITAL=0x80000000,
NETMSG_CONTEXT_CONNECT=0x00010000,
NETMSG_CONTEXT_GAME=0x00020000,
NETMSG_CONTEXT_GLOBAL=0x00040000,
// connection phase
NETMSG_CLIENT_CONNECT=NETMSG_CONTEXT_CONNECT|1,
// str32 name
// str32 clan
// str32 password
// str32 skin
// TODO: These should be implemented to make the server send the map to the client on connect
// NETMSG_CLIENT_FETCH,
// NETMSG_SERVER_MAPDATA,
NETMSG_SERVER_ACCEPT=NETMSG_CONTEXT_CONNECT|2,
// str32 mapname
NETMSG_CLIENT_DONE=NETMSG_VITAL|NETMSG_CONTEXT_CONNECT|3,
// nothing
// game phase
NETMSG_SERVER_SNAP = NETMSG_CONTEXT_GAME|1, // server will spam these
// int num_parts
// int part
// int size
// data *
NETMSG_CLIENT_INPUT = NETMSG_CONTEXT_GAME|1, // client will spam these
// int input[MAX_INPUTS]
NETMSG_SERVER_EVENT = NETMSG_CONTEXT_GAME|NETMSG_VITAL|2,
NETMSG_CLIENT_EVENT = NETMSG_CONTEXT_GAME|NETMSG_VITAL|2,
NETMSG_CLIENT_CHECKALIVE = NETMSG_CONTEXT_GAME|NETMSG_VITAL|3, // check if client is alive
NETMSG_CLIENT_ERROR=0x0fffffff,
// str128 reason
NETMSG_SERVER_ERROR=0x0fffffff,
// str128 reason
};
enum
{
MAX_NAME_LENGTH=32,
MAX_CLANNAME_LENGTH=32,
MAX_INPUT_SIZE=128,
MAX_SNAPSHOT_SIZE=64*1024,
MAX_SNAPSHOT_PACKSIZE=768
};