Browse Source

Fix strict aliasing violations in netcode

pull/41/head
Xadhoom 7 years ago
parent
commit
24f746ae6a
  1. 6
      SourceX/dvlnet/abstract_net.cpp
  2. 61
      SourceX/dvlnet/abstract_net.h
  3. 10
      SourceX/dvlnet/base.cpp
  4. 116
      SourceX/dvlnet/base.h
  5. 10
      SourceX/dvlnet/frame_queue.cpp
  6. 48
      SourceX/dvlnet/frame_queue.h
  7. 6
      SourceX/dvlnet/loopback.cpp
  8. 56
      SourceX/dvlnet/loopback.h
  9. 6
      SourceX/dvlnet/packet.cpp
  10. 505
      SourceX/dvlnet/packet.h
  11. 6
      SourceX/dvlnet/tcp_client.cpp
  12. 50
      SourceX/dvlnet/tcp_client.h
  13. 6
      SourceX/dvlnet/tcp_server.cpp
  14. 92
      SourceX/dvlnet/tcp_server.h
  15. 8
      SourceX/dvlnet/udp_p2p.cpp
  16. 70
      SourceX/dvlnet/udp_p2p.h

6
SourceX/dvlnet/abstract_net.cpp

@ -5,7 +5,8 @@
#include "dvlnet/udp_p2p.h"
#include "dvlnet/loopback.h"
namespace dvl { namespace net {
namespace dvl {
namespace net {
abstract_net::~abstract_net()
{
@ -24,4 +25,5 @@ std::unique_ptr<abstract_net> abstract_net::make_net(provider_t provider)
}
}
}}
} // namespace net
} // namespace dvl

61
SourceX/dvlnet/abstract_net.h

@ -7,36 +7,39 @@
#include "devilution.h"
namespace dvl { namespace net {
typedef std::vector<unsigned char> buffer_t;
typedef void(*snet_event_func)(struct _SNETEVENT*);
typedef unsigned long provider_t;
class dvlnet_exception : public std::exception {};
namespace dvl {
namespace net {
class abstract_net {
public:
virtual int create(std::string addrstr, std::string passwd) = 0;
virtual int join(std::string addrstr, std::string passwd) = 0;
virtual bool SNetReceiveMessage(int* sender, char** data,
int* size) = 0;
virtual bool SNetSendMessage(int dest, void* data,
unsigned int size) = 0;
virtual bool SNetReceiveTurns(char** data, unsigned int* size,
DWORD* status) = 0;
virtual bool SNetSendTurn(char* data, unsigned int size) = 0;
virtual int SNetGetProviderCaps(struct _SNETCAPS* caps) = 0;
virtual void* SNetRegisterEventHandler(event_type evtype,
snet_event_func func) = 0;
virtual void* SNetUnregisterEventHandler(event_type evtype,
snet_event_func func) = 0;
virtual bool SNetLeaveGame(int type) = 0;
virtual bool SNetDropPlayer(int playerid, DWORD flags) = 0;
virtual bool SNetGetOwnerTurnsWaiting(DWORD *turns) = 0;
virtual bool SNetGetTurnsInTransit(int *turns) = 0;
virtual void setup_gameinfo(buffer_t info) = 0;
virtual ~abstract_net();
typedef std::vector<unsigned char> buffer_t;
typedef void(*snet_event_func)(struct _SNETEVENT*);
typedef unsigned long provider_t;
class dvlnet_exception : public std::exception {};
static std::unique_ptr<abstract_net> make_net(provider_t provider);
class abstract_net {
public:
virtual int create(std::string addrstr, std::string passwd) = 0;
virtual int join(std::string addrstr, std::string passwd) = 0;
virtual bool SNetReceiveMessage(int* sender, char** data,
int* size) = 0;
virtual bool SNetSendMessage(int dest, void* data,
unsigned int size) = 0;
virtual bool SNetReceiveTurns(char** data, unsigned int* size,
DWORD* status) = 0;
virtual bool SNetSendTurn(char* data, unsigned int size) = 0;
virtual int SNetGetProviderCaps(struct _SNETCAPS* caps) = 0;
virtual void* SNetRegisterEventHandler(event_type evtype,
snet_event_func func) = 0;
virtual void* SNetUnregisterEventHandler(event_type evtype,
snet_event_func func) = 0;
virtual bool SNetLeaveGame(int type) = 0;
virtual bool SNetDropPlayer(int playerid, DWORD flags) = 0;
virtual bool SNetGetOwnerTurnsWaiting(DWORD *turns) = 0;
virtual bool SNetGetTurnsInTransit(int *turns) = 0;
virtual void setup_gameinfo(buffer_t info) = 0;
virtual ~abstract_net();
static std::unique_ptr<abstract_net> make_net(provider_t provider);
};
}}
} // namespace net
} // namespace dvl

10
SourceX/dvlnet/base.cpp

@ -1,8 +1,10 @@
#include "dvlnet/base.h"
#include <algorithm>
#include <cstring>
namespace dvl { namespace net {
namespace dvl {
namespace net {
void base::setup_gameinfo(buffer_t info)
{
@ -170,7 +172,8 @@ bool base::SNetSendTurn(char* data, unsigned int size)
{
if (size != sizeof(turn_t))
ABORT();
turn_t turn = *reinterpret_cast<turn_t*>(data);
turn_t turn;
std::memcpy(&turn, data, sizeof(turn));
auto pkt = pktfty->make_packet<PT_TURN>(plr_self, PLR_BROADCAST, turn);
send(*pkt);
turn_queue[plr_self].push_back(pkt->turn());
@ -253,4 +256,5 @@ bool base::SNetGetTurnsInTransit(int *turns)
return true;
}
}}
} // namespace net
} // namespace dvl

116
SourceX/dvlnet/base.h

@ -18,60 +18,64 @@
#define LEAVE_ENDING 0x40000004
#define LEAVE_DROP 0x40000006
namespace dvl { namespace net {
class base : public abstract_net {
public:
virtual int create(std::string addrstr, std::string passwd) = 0;
virtual int join(std::string addrstr, std::string passwd) = 0;
virtual bool SNetReceiveMessage(int* sender, char** data, int* size);
virtual bool SNetSendMessage(int dest, void* data, unsigned int size);
virtual bool SNetReceiveTurns(char** data, unsigned int* size,
DWORD* status);
virtual bool SNetSendTurn(char* data, unsigned int size);
virtual int SNetGetProviderCaps(struct _SNETCAPS* caps);
virtual void* SNetRegisterEventHandler(event_type evtype,
snet_event_func func);
virtual void* SNetUnregisterEventHandler(event_type evtype,
snet_event_func func);
virtual bool SNetLeaveGame(int type);
virtual bool SNetDropPlayer(int playerid, DWORD flags);
virtual bool SNetGetOwnerTurnsWaiting(DWORD *turns);
virtual bool SNetGetTurnsInTransit(int *turns);
virtual void poll() = 0;
virtual void send(packet& pkt) = 0;
void setup_gameinfo(buffer_t info);
protected:
std::map<event_type, snet_event_func> registered_handlers;
buffer_t game_init_info;
struct message_t {
int sender; // change int to something else in devilution code later
buffer_t payload;
message_t() : sender(-1), payload({}) {}
message_t(int s, buffer_t p) : sender(s), payload(p) {}
};
message_t message_last;
std::deque<message_t> message_queue;
std::array<turn_t, MAX_PLRS> turn_last = {};
std::array<std::deque<turn_t>, MAX_PLRS> turn_queue;
std::array<bool, MAX_PLRS> connected_table = {};
plr_t plr_self = PLR_BROADCAST;
cookie_t cookie_self = 0;
std::unique_ptr<packet_factory> pktfty;
void setup_password(std::string pw);
void handle_accept(packet& pkt);
void recv_local(packet& pkt);
void run_event_handler(_SNETEVENT& ev);
private:
plr_t get_owner();
void clear_msg(plr_t plr);
namespace dvl {
namespace net {
class base : public abstract_net {
public:
virtual int create(std::string addrstr, std::string passwd) = 0;
virtual int join(std::string addrstr, std::string passwd) = 0;
virtual bool SNetReceiveMessage(int* sender, char** data, int* size);
virtual bool SNetSendMessage(int dest, void* data, unsigned int size);
virtual bool SNetReceiveTurns(char** data, unsigned int* size,
DWORD* status);
virtual bool SNetSendTurn(char* data, unsigned int size);
virtual int SNetGetProviderCaps(struct _SNETCAPS* caps);
virtual void* SNetRegisterEventHandler(event_type evtype,
snet_event_func func);
virtual void* SNetUnregisterEventHandler(event_type evtype,
snet_event_func func);
virtual bool SNetLeaveGame(int type);
virtual bool SNetDropPlayer(int playerid, DWORD flags);
virtual bool SNetGetOwnerTurnsWaiting(DWORD *turns);
virtual bool SNetGetTurnsInTransit(int *turns);
virtual void poll() = 0;
virtual void send(packet& pkt) = 0;
void setup_gameinfo(buffer_t info);
protected:
std::map<event_type, snet_event_func> registered_handlers;
buffer_t game_init_info;
struct message_t {
int sender; // change int to something else in devilution code later
buffer_t payload;
message_t() : sender(-1), payload({}) {}
message_t(int s, buffer_t p) : sender(s), payload(p) {}
};
}}
message_t message_last;
std::deque<message_t> message_queue;
std::array<turn_t, MAX_PLRS> turn_last = {};
std::array<std::deque<turn_t>, MAX_PLRS> turn_queue;
std::array<bool, MAX_PLRS> connected_table = {};
plr_t plr_self = PLR_BROADCAST;
cookie_t cookie_self = 0;
std::unique_ptr<packet_factory> pktfty;
void setup_password(std::string pw);
void handle_accept(packet& pkt);
void recv_local(packet& pkt);
void run_event_handler(_SNETEVENT& ev);
private:
plr_t get_owner();
void clear_msg(plr_t plr);
};
} // namespace net
} // namespace dvl

10
SourceX/dvlnet/frame_queue.cpp

@ -1,8 +1,11 @@
#include "dvlnet/frame_queue.h"
#include <cstring>
#include "dvlnet/packet.h"
namespace dvl { namespace net {
namespace dvl {
namespace net {
size_t frame_queue::size()
{
@ -45,7 +48,7 @@ bool frame_queue::packet_ready()
if(size() < sizeof(framesize_t))
return false;
auto szbuf = read(sizeof(framesize_t));
nextsize = *(reinterpret_cast<framesize_t*>(&szbuf[0]));
std::memcpy(&nextsize, &szbuf[0], sizeof(nextsize));
if(!nextsize)
throw frame_queue_exception();
}
@ -75,4 +78,5 @@ buffer_t frame_queue::make_frame(buffer_t packetbuf)
return std::move(ret);
}
}}
} // namespace net
} // namespace dvl

48
SourceX/dvlnet/frame_queue.h

@ -4,25 +4,29 @@
#include "dvlnet/abstract_net.h"
namespace dvl { namespace net {
class frame_queue_exception : public dvlnet_exception {};
class frame_queue {
public:
typedef uint32_t framesize_t;
constexpr static framesize_t max_frame_size = 0xFFFF;
private:
size_t current_size = 0;
std::deque<buffer_t> buffer_deque;
size_t nextsize = 0;
size_t size();
buffer_t read(size_t s);
public:
bool packet_ready();
buffer_t read_packet();
void write(buffer_t buf);
static buffer_t make_frame(buffer_t packetbuf);
};
}}
namespace dvl {
namespace net {
class frame_queue_exception : public dvlnet_exception {};
class frame_queue {
public:
typedef uint32_t framesize_t;
constexpr static framesize_t max_frame_size = 0xFFFF;
private:
size_t current_size = 0;
std::deque<buffer_t> buffer_deque;
size_t nextsize = 0;
size_t size();
buffer_t read(size_t s);
public:
bool packet_ready();
buffer_t read_packet();
void write(buffer_t buf);
static buffer_t make_frame(buffer_t packetbuf);
};
} // namespace net
} // namespace dvl

6
SourceX/dvlnet/loopback.cpp

@ -1,7 +1,8 @@
#include "dvlnet/loopback.h"
#include "stubs.h"
namespace dvl { namespace net {
namespace dvl {
namespace net {
int loopback::create(std::string addrstr, std::string passwd)
{
@ -104,4 +105,5 @@ bool loopback::SNetGetTurnsInTransit(int *turns)
return true;
}
}}
} // namespace net
} // namespace dvl

56
SourceX/dvlnet/loopback.h

@ -6,30 +6,34 @@
#include "devilution.h"
#include "dvlnet/abstract_net.h"
namespace dvl { namespace net {
class loopback : public abstract_net {
private:
std::queue<buffer_t> message_queue;
buffer_t message_last;
const int plr_single = 0;
namespace dvl {
namespace net {
public:
virtual int create(std::string addrstr, std::string passwd);
virtual int join(std::string addrstr, std::string passwd);
virtual bool SNetReceiveMessage(int* sender, char** data, int* size);
virtual bool SNetSendMessage(int dest, void* data, unsigned int size);
virtual bool SNetReceiveTurns(char** data, unsigned int* size,
DWORD* status);
virtual bool SNetSendTurn(char* data, unsigned int size);
virtual int SNetGetProviderCaps(struct _SNETCAPS* caps);
virtual void *SNetRegisterEventHandler(event_type evtype,
snet_event_func func);
virtual void *SNetUnregisterEventHandler(event_type evtype,
snet_event_func func);
virtual bool SNetLeaveGame(int type);
virtual bool SNetDropPlayer(int playerid, DWORD flags);
virtual bool SNetGetOwnerTurnsWaiting(DWORD *turns);
virtual bool SNetGetTurnsInTransit(int *turns);
virtual void setup_gameinfo(buffer_t info);
};
}}
class loopback : public abstract_net {
private:
std::queue<buffer_t> message_queue;
buffer_t message_last;
const int plr_single = 0;
public:
virtual int create(std::string addrstr, std::string passwd);
virtual int join(std::string addrstr, std::string passwd);
virtual bool SNetReceiveMessage(int* sender, char** data, int* size);
virtual bool SNetSendMessage(int dest, void* data, unsigned int size);
virtual bool SNetReceiveTurns(char** data, unsigned int* size,
DWORD* status);
virtual bool SNetSendTurn(char* data, unsigned int size);
virtual int SNetGetProviderCaps(struct _SNETCAPS* caps);
virtual void *SNetRegisterEventHandler(event_type evtype,
snet_event_func func);
virtual void *SNetUnregisterEventHandler(event_type evtype,
snet_event_func func);
virtual bool SNetLeaveGame(int type);
virtual bool SNetDropPlayer(int playerid, DWORD flags);
virtual bool SNetGetOwnerTurnsWaiting(DWORD *turns);
virtual bool SNetGetTurnsInTransit(int *turns);
virtual void setup_gameinfo(buffer_t info);
};
} // namespace net
} // namespace dvl

6
SourceX/dvlnet/packet.cpp

@ -1,6 +1,7 @@
#include "dvlnet/packet.h"
namespace dvl { namespace net {
namespace dvl {
namespace net {
static constexpr bool disable_encryption = false;
@ -174,4 +175,5 @@ packet_factory::packet_factory(std::string pw)
ABORT();
}
}}
} // namespace net
} // namespace dvl

505
SourceX/dvlnet/packet.h

@ -3,267 +3,272 @@
#include <string>
#include <memory>
#include <array>
#include <cstring>
#include <sodium.h>
#include "dvlnet/abstract_net.h"
#include "stubs.h"
namespace dvl { namespace net {
enum packet_type : uint8_t {
namespace dvl {
namespace net {
enum packet_type : uint8_t {
PT_MESSAGE = 0x01,
PT_TURN = 0x02,
PT_JOIN_REQUEST = 0x11,
PT_JOIN_ACCEPT = 0x12,
PT_CONNECT = 0x13,
PT_DISCONNECT = 0x14,
};
typedef uint8_t plr_t;
typedef uint32_t cookie_t;
typedef int turn_t; // change int to something else in devilution code later
typedef int leaveinfo_t; // also change later
typedef std::array<unsigned char, crypto_secretbox_KEYBYTES> key_t;
static constexpr plr_t PLR_MASTER = 0xFE;
static constexpr plr_t PLR_BROADCAST = 0xFF;
class packet_exception : public dvlnet_exception {};
class packet {
protected:
packet_type m_type;
plr_t m_src;
plr_t m_dest;
buffer_t m_message;
turn_t m_turn;
cookie_t m_cookie;
plr_t m_newplr;
buffer_t m_info;
leaveinfo_t m_leaveinfo;
const key_t& key;
bool have_encrypted = false;
bool have_decrypted = false;
buffer_t encrypted_buffer;
buffer_t decrypted_buffer;
public:
packet(const key_t& k) : key(k) {};
const buffer_t& data();
packet_type type();
plr_t src();
plr_t dest();
const buffer_t& message();
turn_t turn();
cookie_t cookie();
plr_t newplr();
const buffer_t& info();
leaveinfo_t leaveinfo();
};
template<class P> class packet_proc : public packet {
public:
using packet::packet;
void process_data();
};
class packet_in : public packet_proc<packet_in> {
public:
using packet_proc<packet_in>::packet_proc;
void create(buffer_t buf);
void process_element(buffer_t& x);
template <class T> void process_element(T& x);
void decrypt();
};
class packet_out : public packet_proc<packet_out> {
public:
using packet_proc<packet_out>::packet_proc;
template<packet_type t, typename... Args>
void create(Args... args);
void process_element(buffer_t& x);
template<class T> void process_element(T& x);
template<class T> static const unsigned char* begin(const T& x);
template<class T> static const unsigned char* end(const T& x);
void encrypt();
};
template<class P> void packet_proc<P>::process_data()
{
P& self = static_cast<P&>(*this);
self.process_element(m_type);
self.process_element(m_src);
self.process_element(m_dest);
switch (m_type) {
case PT_MESSAGE:
self.process_element(m_message);
break;
case PT_TURN:
self.process_element(m_turn);
break;
case PT_JOIN_REQUEST:
self.process_element(m_cookie);
self.process_element(m_info);
break;
case PT_JOIN_ACCEPT:
self.process_element(m_cookie);
self.process_element(m_newplr);
self.process_element(m_info);
break;
case PT_CONNECT:
self.process_element(m_newplr);
break;
case PT_DISCONNECT:
self.process_element(m_newplr);
self.process_element(m_leaveinfo);
break;
}
}
inline void packet_in::process_element(buffer_t& x)
{
x.insert(x.begin(), decrypted_buffer.begin(), decrypted_buffer.end());
decrypted_buffer.resize(0);
}
template <class T> void packet_in::process_element(T& x)
{
if (decrypted_buffer.size() < sizeof(T))
throw packet_exception();
x = *reinterpret_cast<T *>(decrypted_buffer.data());
decrypted_buffer.erase(decrypted_buffer.begin(),
decrypted_buffer.begin() + sizeof(T));
}
template<>
inline void packet_out::create<PT_MESSAGE>(plr_t s, plr_t d, buffer_t m)
{
if (have_encrypted || have_decrypted)
ABORT();
have_decrypted = true;
m_type = PT_MESSAGE;
m_src = s;
m_dest = d;
m_message = std::move(m);
}
template<>
inline void packet_out::create<PT_TURN>(plr_t s, plr_t d, turn_t u)
{
if (have_encrypted || have_decrypted)
ABORT();
have_decrypted = true;
m_type = PT_TURN;
m_src = s;
m_dest = d;
m_turn = u;
}
template<>
inline void packet_out::create<PT_JOIN_REQUEST>(plr_t s, plr_t d,
cookie_t c, buffer_t i)
{
if (have_encrypted || have_decrypted)
ABORT();
have_decrypted = true;
m_type = PT_JOIN_REQUEST;
m_src = s;
m_dest = d;
m_cookie = c;
m_info = i;
}
template<>
inline void packet_out::create<PT_JOIN_ACCEPT>(plr_t s, plr_t d, cookie_t c,
plr_t n, buffer_t i)
{
if (have_encrypted || have_decrypted)
ABORT();
have_decrypted = true;
m_type = PT_JOIN_ACCEPT;
m_src = s;
m_dest = d;
m_cookie = c;
m_newplr = n;
m_info = i;
}
template<>
inline void packet_out::create<PT_CONNECT>(plr_t s, plr_t d, plr_t n)
{
if (have_encrypted || have_decrypted)
ABORT();
have_decrypted = true;
m_type = PT_CONNECT;
m_src = s;
m_dest = d;
m_newplr = n;
}
template<>
inline void packet_out::create<PT_DISCONNECT>(plr_t s, plr_t d, plr_t n,
leaveinfo_t l)
{
if (have_encrypted || have_decrypted)
ABORT();
have_decrypted = true;
m_type = PT_DISCONNECT;
m_src = s;
m_dest = d;
m_newplr = n;
m_leaveinfo = l;
}
inline void packet_out::process_element(buffer_t& x)
{
encrypted_buffer.insert(encrypted_buffer.end(), x.begin(), x.end());
}
template <class T> void packet_out::process_element(T& x)
{
encrypted_buffer.insert(encrypted_buffer.end(), begin(x), end(x));
}
template <class T> const unsigned char* packet_out::begin(const T& x)
{
return reinterpret_cast<const unsigned char *>(&x);
}
template <class T> const unsigned char* packet_out::end(const T& x)
{
return reinterpret_cast<const unsigned char *>(&x) + sizeof(T);
}
class packet_factory {
key_t key = {};
public:
static constexpr unsigned short max_packet_size = 0xFFFF;
packet_factory(std::string pw = "");
std::unique_ptr<packet> make_packet(buffer_t buf);
template<packet_type t, typename... Args>
std::unique_ptr<packet> make_packet(Args... args);
};
inline std::unique_ptr<packet> packet_factory::make_packet(buffer_t buf)
{
auto ret = std::make_unique<packet_in>(key);
ret->create(std::move(buf));
ret->decrypt();
return ret;
}
};
typedef uint8_t plr_t;
typedef uint32_t cookie_t;
typedef int turn_t; // change int to something else in devilution code later
typedef int leaveinfo_t; // also change later
typedef std::array<unsigned char, crypto_secretbox_KEYBYTES> key_t;
static constexpr plr_t PLR_MASTER = 0xFE;
static constexpr plr_t PLR_BROADCAST = 0xFF;
class packet_exception : public dvlnet_exception {};
class packet {
protected:
packet_type m_type;
plr_t m_src;
plr_t m_dest;
buffer_t m_message;
turn_t m_turn;
cookie_t m_cookie;
plr_t m_newplr;
buffer_t m_info;
leaveinfo_t m_leaveinfo;
const key_t& key;
bool have_encrypted = false;
bool have_decrypted = false;
buffer_t encrypted_buffer;
buffer_t decrypted_buffer;
public:
packet(const key_t& k) : key(k) {};
const buffer_t& data();
packet_type type();
plr_t src();
plr_t dest();
const buffer_t& message();
turn_t turn();
cookie_t cookie();
plr_t newplr();
const buffer_t& info();
leaveinfo_t leaveinfo();
};
template<class P> class packet_proc : public packet {
public:
using packet::packet;
void process_data();
};
class packet_in : public packet_proc<packet_in> {
public:
using packet_proc<packet_in>::packet_proc;
void create(buffer_t buf);
void process_element(buffer_t& x);
template <class T> void process_element(T& x);
void decrypt();
};
class packet_out : public packet_proc<packet_out> {
public:
using packet_proc<packet_out>::packet_proc;
template<packet_type t, typename... Args>
std::unique_ptr<packet> packet_factory::make_packet(Args... args)
{
auto ret = std::make_unique<packet_out>(key);
ret->create<t>(args...);
ret->encrypt();
return ret;
void create(Args... args);
void process_element(buffer_t& x);
template<class T> void process_element(T& x);
template<class T> static const unsigned char* begin(const T& x);
template<class T> static const unsigned char* end(const T& x);
void encrypt();
};
template<class P> void packet_proc<P>::process_data()
{
P& self = static_cast<P&>(*this);
self.process_element(m_type);
self.process_element(m_src);
self.process_element(m_dest);
switch (m_type) {
case PT_MESSAGE:
self.process_element(m_message);
break;
case PT_TURN:
self.process_element(m_turn);
break;
case PT_JOIN_REQUEST:
self.process_element(m_cookie);
self.process_element(m_info);
break;
case PT_JOIN_ACCEPT:
self.process_element(m_cookie);
self.process_element(m_newplr);
self.process_element(m_info);
break;
case PT_CONNECT:
self.process_element(m_newplr);
break;
case PT_DISCONNECT:
self.process_element(m_newplr);
self.process_element(m_leaveinfo);
break;
}
}}
}
inline void packet_in::process_element(buffer_t& x)
{
x.insert(x.begin(), decrypted_buffer.begin(), decrypted_buffer.end());
decrypted_buffer.resize(0);
}
template <class T> void packet_in::process_element(T& x)
{
if (decrypted_buffer.size() < sizeof(T))
throw packet_exception();
std::memcpy(&x, decrypted_buffer.data(), sizeof(T));
decrypted_buffer.erase(decrypted_buffer.begin(),
decrypted_buffer.begin() + sizeof(T));
}
template<>
inline void packet_out::create<PT_MESSAGE>(plr_t s, plr_t d, buffer_t m)
{
if (have_encrypted || have_decrypted)
ABORT();
have_decrypted = true;
m_type = PT_MESSAGE;
m_src = s;
m_dest = d;
m_message = std::move(m);
}
template<>
inline void packet_out::create<PT_TURN>(plr_t s, plr_t d, turn_t u)
{
if (have_encrypted || have_decrypted)
ABORT();
have_decrypted = true;
m_type = PT_TURN;
m_src = s;
m_dest = d;
m_turn = u;
}
template<>
inline void packet_out::create<PT_JOIN_REQUEST>(plr_t s, plr_t d,
cookie_t c, buffer_t i)
{
if (have_encrypted || have_decrypted)
ABORT();
have_decrypted = true;
m_type = PT_JOIN_REQUEST;
m_src = s;
m_dest = d;
m_cookie = c;
m_info = i;
}
template<>
inline void packet_out::create<PT_JOIN_ACCEPT>(plr_t s, plr_t d, cookie_t c,
plr_t n, buffer_t i)
{
if (have_encrypted || have_decrypted)
ABORT();
have_decrypted = true;
m_type = PT_JOIN_ACCEPT;
m_src = s;
m_dest = d;
m_cookie = c;
m_newplr = n;
m_info = i;
}
template<>
inline void packet_out::create<PT_CONNECT>(plr_t s, plr_t d, plr_t n)
{
if (have_encrypted || have_decrypted)
ABORT();
have_decrypted = true;
m_type = PT_CONNECT;
m_src = s;
m_dest = d;
m_newplr = n;
}
template<>
inline void packet_out::create<PT_DISCONNECT>(plr_t s, plr_t d, plr_t n,
leaveinfo_t l)
{
if (have_encrypted || have_decrypted)
ABORT();
have_decrypted = true;
m_type = PT_DISCONNECT;
m_src = s;
m_dest = d;
m_newplr = n;
m_leaveinfo = l;
}
inline void packet_out::process_element(buffer_t& x)
{
encrypted_buffer.insert(encrypted_buffer.end(), x.begin(), x.end());
}
template <class T> void packet_out::process_element(T& x)
{
encrypted_buffer.insert(encrypted_buffer.end(), begin(x), end(x));
}
template <class T> const unsigned char* packet_out::begin(const T& x)
{
return reinterpret_cast<const unsigned char *>(&x);
}
template <class T> const unsigned char* packet_out::end(const T& x)
{
return reinterpret_cast<const unsigned char *>(&x) + sizeof(T);
}
class packet_factory {
key_t key = {};
public:
static constexpr unsigned short max_packet_size = 0xFFFF;
packet_factory(std::string pw = "");
std::unique_ptr<packet> make_packet(buffer_t buf);
template<packet_type t, typename... Args>
std::unique_ptr<packet> make_packet(Args... args);
};
inline std::unique_ptr<packet> packet_factory::make_packet(buffer_t buf)
{
auto ret = std::make_unique<packet_in>(key);
ret->create(std::move(buf));
ret->decrypt();
return ret;
}
template<packet_type t, typename... Args>
std::unique_ptr<packet> packet_factory::make_packet(Args... args)
{
auto ret = std::make_unique<packet_out>(key);
ret->create<t>(args...);
ret->encrypt();
return ret;
}
} // namespace net
} // namespace dvl

6
SourceX/dvlnet/tcp_client.cpp

@ -7,7 +7,8 @@
#include <sodium.h>
#include <SDL.h>
namespace dvl { namespace net {
namespace dvl {
namespace net {
int tcp_client::create(std::string addrstr, std::string passwd)
{
@ -102,4 +103,5 @@ void tcp_client::send(packet& pkt)
std::placeholders::_1, std::placeholders::_2));
}
}}
} // namespace net
} // namespace dvl

50
SourceX/dvlnet/tcp_client.h

@ -12,26 +12,30 @@
#include "dvlnet/base.h"
#include "dvlnet/tcp_server.h"
namespace dvl { namespace net {
class tcp_client : public base {
public:
int create(std::string addrstr, std::string passwd);
int join(std::string addrstr, std::string passwd);
constexpr static unsigned short default_port = 6112;
virtual void poll();
virtual void send(packet& pkt);
private:
frame_queue recv_queue;
buffer_t recv_buffer = buffer_t(frame_queue::max_frame_size);
asio::io_context ioc;
asio::ip::tcp::socket sock = asio::ip::tcp::socket(ioc);
std::unique_ptr<tcp_server> local_server; // must be declared *after* ioc
void handle_recv(const asio::error_code& error, size_t bytes_read);
void start_recv();
void handle_send(const asio::error_code& error, size_t bytes_sent);
};
}}
namespace dvl {
namespace net {
class tcp_client : public base {
public:
int create(std::string addrstr, std::string passwd);
int join(std::string addrstr, std::string passwd);
constexpr static unsigned short default_port = 6112;
virtual void poll();
virtual void send(packet& pkt);
private:
frame_queue recv_queue;
buffer_t recv_buffer = buffer_t(frame_queue::max_frame_size);
asio::io_context ioc;
asio::ip::tcp::socket sock = asio::ip::tcp::socket(ioc);
std::unique_ptr<tcp_server> local_server; // must be declared *after* ioc
void handle_recv(const asio::error_code& error, size_t bytes_read);
void start_recv();
void handle_send(const asio::error_code& error, size_t bytes_sent);
};
} // namespace net
} // namespace dvl

6
SourceX/dvlnet/tcp_server.cpp

@ -5,7 +5,8 @@
#include "dvlnet/base.h"
namespace dvl { namespace net {
namespace dvl {
namespace net {
tcp_server::tcp_server(asio::io_context& ioc, std::string bindaddr,
unsigned short port, std::string pw) :
@ -208,4 +209,5 @@ void tcp_server::drop_connection(scc con)
con->socket.close();
}
}}
} // namespace net
} // namespace dvl

92
SourceX/dvlnet/tcp_server.h

@ -12,53 +12,57 @@
#include "dvlnet/abstract_net.h"
#include "dvlnet/frame_queue.h"
namespace dvl { namespace net {
class server_exception : public dvlnet_exception {};
namespace dvl {
namespace net {
class tcp_server {
public:
tcp_server(asio::io_context& ioc, std::string bindaddr,
unsigned short port, std::string pw);
std::string localhost_self();
class server_exception : public dvlnet_exception {};
private:
static constexpr int timeout_connect = 30;
static constexpr int timeout_active = 60;
class tcp_server {
public:
tcp_server(asio::io_context& ioc, std::string bindaddr,
unsigned short port, std::string pw);
std::string localhost_self();
struct client_connection {
frame_queue recv_queue;
buffer_t recv_buffer = buffer_t(frame_queue::max_frame_size);
plr_t plr = PLR_BROADCAST;
asio::ip::tcp::socket socket;
asio::steady_timer timer;
int timeout;
client_connection(asio::io_context& ioc) :
socket(ioc), timer(ioc) {}
};
private:
static constexpr int timeout_connect = 30;
static constexpr int timeout_active = 60;
typedef std::shared_ptr<client_connection> scc;
struct client_connection {
frame_queue recv_queue;
buffer_t recv_buffer = buffer_t(frame_queue::max_frame_size);
plr_t plr = PLR_BROADCAST;
asio::ip::tcp::socket socket;
asio::steady_timer timer;
int timeout;
client_connection(asio::io_context& ioc) :
socket(ioc), timer(ioc) {}
};
asio::io_context& ioc;
packet_factory pktfty;
std::unique_ptr<asio::ip::tcp::acceptor> acceptor;
std::array<scc, MAX_PLRS> connections;
buffer_t game_init_info;
typedef std::shared_ptr<client_connection> scc;
scc make_connection();
plr_t next_free();
bool empty();
void start_accept();
void handle_accept(scc con, const asio::error_code& ec);
void start_recv(scc con);
void handle_recv(scc con, const asio::error_code& ec, size_t bytes_read);
void handle_recv_newplr(scc con, packet& pkt);
void handle_recv_packet(packet& pkt);
void send_connect(scc con);
void send_packet(packet& pkt);
void start_send(scc con, packet& pkt);
void handle_send(scc con, const asio::error_code& ec, size_t bytes_sent);
void start_timeout(scc con);
void handle_timeout(scc con, const asio::error_code& ec);
void drop_connection(scc con);
};
}}
asio::io_context& ioc;
packet_factory pktfty;
std::unique_ptr<asio::ip::tcp::acceptor> acceptor;
std::array<scc, MAX_PLRS> connections;
buffer_t game_init_info;
scc make_connection();
plr_t next_free();
bool empty();
void start_accept();
void handle_accept(scc con, const asio::error_code& ec);
void start_recv(scc con);
void handle_recv(scc con, const asio::error_code& ec, size_t bytes_read);
void handle_recv_newplr(scc con, packet& pkt);
void handle_recv_packet(packet& pkt);
void send_connect(scc con);
void send_packet(packet& pkt);
void start_send(scc con, packet& pkt);
void handle_send(scc con, const asio::error_code& ec, size_t bytes_sent);
void start_timeout(scc con);
void handle_timeout(scc con, const asio::error_code& ec);
void drop_connection(scc con);
};
} //namespace net
} //namespace dvl

8
SourceX/dvlnet/udp_p2p.cpp

@ -2,7 +2,8 @@
#include <SDL.h>
namespace dvl { namespace net {
namespace dvl {
namespace net {
const udp_p2p::endpoint udp_p2p::none;
@ -51,7 +52,7 @@ int udp_p2p::join(std::string addrstr, std::string passwd)
sock.connect(themaster);
master = themaster;
{ // hack: try to join for 5 seconds
randombytes_buf(reinterpret_cast<unsigned char *>(&cookie_self),
randombytes_buf(reinterpret_cast<unsigned char*>(&cookie_self),
sizeof(cookie_t));
auto pkt = pktfty->make_packet<PT_JOIN_REQUEST>(PLR_BROADCAST,
PLR_MASTER, cookie_self,
@ -169,4 +170,5 @@ void udp_p2p::recv_decrypted(packet& pkt, endpoint sender)
recv_local(pkt);
}
}}
} // namespace net
} // namespace dvl

70
SourceX/dvlnet/udp_p2p.h

@ -10,36 +10,40 @@
#include "dvlnet/packet.h"
#include "dvlnet/base.h"
namespace dvl { namespace net {
class udp_p2p : public base {
public:
virtual int create(std::string addrstr, std::string passwd);
virtual int join(std::string addrstr, std::string passwd);
virtual void poll();
virtual void send(packet& pkt);
private:
typedef asio::ip::udp::endpoint endpoint;
static const endpoint none;
unsigned short udpport_self = 0;
static constexpr unsigned short default_port = 6112;
static constexpr unsigned short try_ports = 512;
static constexpr int ACTIVE = 60;
asio::io_context io_context;
endpoint master;
std::set<endpoint> connection_requests_pending;
std::array<endpoint, MAX_PLRS> nexthop_table;
asio::ip::udp::socket sock = asio::ip::udp::socket(io_context);
void recv();
void handle_join_request(packet& pkt, endpoint sender);
void send_internal(packet& pkt, endpoint sender = none);
std::set<endpoint> dests_for_addr(plr_t dest, endpoint sender);
void recv_decrypted(packet& pkt, endpoint sender);
};
}}
namespace dvl {
namespace net {
class udp_p2p : public base {
public:
virtual int create(std::string addrstr, std::string passwd);
virtual int join(std::string addrstr, std::string passwd);
virtual void poll();
virtual void send(packet& pkt);
private:
typedef asio::ip::udp::endpoint endpoint;
static const endpoint none;
unsigned short udpport_self = 0;
static constexpr unsigned short default_port = 6112;
static constexpr unsigned short try_ports = 512;
static constexpr int ACTIVE = 60;
asio::io_context io_context;
endpoint master;
std::set<endpoint> connection_requests_pending;
std::array<endpoint, MAX_PLRS> nexthop_table;
asio::ip::udp::socket sock = asio::ip::udp::socket(io_context);
void recv();
void handle_join_request(packet& pkt, endpoint sender);
void send_internal(packet& pkt, endpoint sender = none);
std::set<endpoint> dests_for_addr(plr_t dest, endpoint sender);
void recv_decrypted(packet& pkt, endpoint sender);
};
} // namespace net
} // namespace dvl

Loading…
Cancel
Save