8 changed files with 699 additions and 680 deletions
@ -1,531 +0,0 @@ |
|||||||
#include "../types.h" |
|
||||||
|
|
||||||
std::unique_ptr<devilution_net> devilution_net::inst; |
|
||||||
const devilution_net_udp::endpoint devilution_net_udp::none; |
|
||||||
|
|
||||||
static constexpr bool disable_encryption = false; |
|
||||||
|
|
||||||
void devilution_net_udp::packet::create(devilution_net_udp::packet_type t, |
|
||||||
devilution_net_udp::plr_t s, |
|
||||||
devilution_net_udp::plr_t d, |
|
||||||
devilution_net_udp::buffer_t m) |
|
||||||
{ |
|
||||||
if (have_encrypted || have_decrypted) |
|
||||||
ABORT(); |
|
||||||
if (t != PT_MESSAGE) |
|
||||||
ABORT(); |
|
||||||
have_decrypted = true; |
|
||||||
m_type = t; |
|
||||||
m_src = s; |
|
||||||
m_dest = d; |
|
||||||
m_message = std::move(m); |
|
||||||
} |
|
||||||
|
|
||||||
void devilution_net_udp::packet::create(devilution_net_udp::packet_type t, |
|
||||||
devilution_net_udp::plr_t s, |
|
||||||
devilution_net_udp::plr_t d, |
|
||||||
devilution_net_udp::turn_t u) |
|
||||||
{ |
|
||||||
if (have_encrypted || have_decrypted) |
|
||||||
ABORT(); |
|
||||||
if (t != PT_TURN) |
|
||||||
ABORT(); |
|
||||||
have_decrypted = true; |
|
||||||
m_type = t; |
|
||||||
m_src = s; |
|
||||||
m_dest = d; |
|
||||||
m_turn = u; |
|
||||||
} |
|
||||||
|
|
||||||
void devilution_net_udp::packet::create(devilution_net_udp::packet_type t, |
|
||||||
devilution_net_udp::plr_t s, |
|
||||||
devilution_net_udp::plr_t d, |
|
||||||
devilution_net_udp::cookie_t c) |
|
||||||
{ |
|
||||||
if (have_encrypted || have_decrypted) |
|
||||||
ABORT(); |
|
||||||
if (t != PT_JOIN_REQUEST) |
|
||||||
ABORT(); |
|
||||||
have_decrypted = true; |
|
||||||
m_type = t; |
|
||||||
m_src = s; |
|
||||||
m_dest = d; |
|
||||||
m_cookie = c; |
|
||||||
} |
|
||||||
|
|
||||||
void devilution_net_udp::packet::create(devilution_net_udp::packet_type t, |
|
||||||
devilution_net_udp::plr_t s, |
|
||||||
devilution_net_udp::plr_t d, |
|
||||||
devilution_net_udp::cookie_t c, |
|
||||||
devilution_net_udp::plr_t n, |
|
||||||
devilution_net_udp::buffer_t i) |
|
||||||
{ |
|
||||||
if (have_encrypted || have_decrypted) |
|
||||||
ABORT(); |
|
||||||
if (t != PT_JOIN_ACCEPT) |
|
||||||
ABORT(); |
|
||||||
have_decrypted = true; |
|
||||||
m_type = t; |
|
||||||
m_src = s; |
|
||||||
m_dest = d; |
|
||||||
m_cookie = c; |
|
||||||
m_newplr = n; |
|
||||||
m_info = i; |
|
||||||
} |
|
||||||
|
|
||||||
void devilution_net_udp::packet::create(devilution_net_udp::packet_type t, |
|
||||||
devilution_net_udp::plr_t s, |
|
||||||
devilution_net_udp::plr_t d, |
|
||||||
devilution_net_udp::plr_t o) |
|
||||||
{ |
|
||||||
if (have_encrypted || have_decrypted) |
|
||||||
ABORT(); |
|
||||||
if (t != PT_LEAVE_GAME) |
|
||||||
ABORT(); |
|
||||||
have_decrypted = true; |
|
||||||
m_type = t; |
|
||||||
m_src = s; |
|
||||||
m_dest = d; |
|
||||||
m_oldplr = o; |
|
||||||
} |
|
||||||
|
|
||||||
void devilution_net_udp::packet::create(devilution_net_udp::buffer_t buf) |
|
||||||
{ |
|
||||||
if (have_encrypted || have_decrypted) |
|
||||||
ABORT(); |
|
||||||
encrypted_buffer = std::move(buf); |
|
||||||
have_encrypted = true; |
|
||||||
} |
|
||||||
|
|
||||||
const devilution_net_udp::buffer_t &devilution_net_udp::packet::data() |
|
||||||
{ |
|
||||||
if (!have_decrypted || !have_encrypted) |
|
||||||
ABORT(); |
|
||||||
return encrypted_buffer; |
|
||||||
} |
|
||||||
|
|
||||||
devilution_net_udp::packet_type devilution_net_udp::packet::type() |
|
||||||
{ |
|
||||||
if (!have_decrypted) |
|
||||||
ABORT(); |
|
||||||
return m_type; |
|
||||||
} |
|
||||||
|
|
||||||
devilution_net_udp::plr_t devilution_net_udp::packet::src() |
|
||||||
{ |
|
||||||
if (!have_decrypted) |
|
||||||
ABORT(); |
|
||||||
return m_src; |
|
||||||
} |
|
||||||
|
|
||||||
devilution_net_udp::plr_t devilution_net_udp::packet::dest() |
|
||||||
{ |
|
||||||
if (!have_decrypted) |
|
||||||
ABORT(); |
|
||||||
return m_dest; |
|
||||||
} |
|
||||||
|
|
||||||
const devilution_net_udp::buffer_t &devilution_net_udp::packet::message() |
|
||||||
{ |
|
||||||
if (!have_decrypted) |
|
||||||
ABORT(); |
|
||||||
if (m_type != PT_MESSAGE) |
|
||||||
throw devilution_net_udp::packet_exception(); |
|
||||||
return m_message; |
|
||||||
} |
|
||||||
|
|
||||||
devilution_net_udp::turn_t devilution_net_udp::packet::turn() |
|
||||||
{ |
|
||||||
if (!have_decrypted) |
|
||||||
ABORT(); |
|
||||||
if (m_type != PT_TURN) |
|
||||||
throw devilution_net_udp::packet_exception(); |
|
||||||
return m_turn; |
|
||||||
} |
|
||||||
|
|
||||||
devilution_net_udp::cookie_t devilution_net_udp::packet::cookie() |
|
||||||
{ |
|
||||||
if (!have_decrypted) |
|
||||||
ABORT(); |
|
||||||
if (m_type != PT_JOIN_REQUEST && m_type != PT_JOIN_ACCEPT) |
|
||||||
throw devilution_net_udp::packet_exception(); |
|
||||||
return m_cookie; |
|
||||||
} |
|
||||||
|
|
||||||
devilution_net_udp::plr_t devilution_net_udp::packet::newplr() |
|
||||||
{ |
|
||||||
if (!have_decrypted) |
|
||||||
ABORT(); |
|
||||||
if (m_type != PT_JOIN_ACCEPT) |
|
||||||
throw devilution_net_udp::packet_exception(); |
|
||||||
return m_newplr; |
|
||||||
} |
|
||||||
|
|
||||||
devilution_net_udp::plr_t devilution_net_udp::packet::oldplr() |
|
||||||
{ |
|
||||||
if (!have_decrypted) |
|
||||||
ABORT(); |
|
||||||
if (m_type != PT_LEAVE_GAME) |
|
||||||
throw devilution_net_udp::packet_exception(); |
|
||||||
return m_oldplr; |
|
||||||
} |
|
||||||
|
|
||||||
const devilution_net_udp::buffer_t &devilution_net_udp::packet::info() |
|
||||||
{ |
|
||||||
if (!have_decrypted) |
|
||||||
ABORT(); |
|
||||||
if (m_type != PT_JOIN_ACCEPT) |
|
||||||
throw devilution_net_udp::packet_exception(); |
|
||||||
return m_info; |
|
||||||
} |
|
||||||
|
|
||||||
void devilution_net_udp::packet::encrypt() |
|
||||||
{ |
|
||||||
if (!have_decrypted) |
|
||||||
ABORT(); |
|
||||||
if (have_encrypted) |
|
||||||
return; |
|
||||||
|
|
||||||
process_data<encrypt_mode_t>(); |
|
||||||
|
|
||||||
if (!disable_encryption) { |
|
||||||
auto len_cleartext = encrypted_buffer.size(); |
|
||||||
encrypted_buffer.insert(encrypted_buffer.begin(), crypto_secretbox_NONCEBYTES, 0); |
|
||||||
encrypted_buffer.insert(encrypted_buffer.end(), crypto_secretbox_MACBYTES, 0); |
|
||||||
randombytes_buf(encrypted_buffer.data(), crypto_secretbox_NONCEBYTES); |
|
||||||
if (crypto_secretbox_easy(encrypted_buffer.data() + crypto_secretbox_NONCEBYTES, |
|
||||||
encrypted_buffer.data() + crypto_secretbox_NONCEBYTES, |
|
||||||
len_cleartext, |
|
||||||
encrypted_buffer.data(), |
|
||||||
key.data())) |
|
||||||
ABORT(); |
|
||||||
} |
|
||||||
have_encrypted = true; |
|
||||||
} |
|
||||||
|
|
||||||
void devilution_net_udp::packet::decrypt() |
|
||||||
{ |
|
||||||
if (!have_encrypted) |
|
||||||
ABORT(); |
|
||||||
if (have_decrypted) |
|
||||||
return; |
|
||||||
if (!disable_encryption) { |
|
||||||
if (encrypted_buffer.size() < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES + sizeof(packet_type) + 2 * sizeof(plr_t)) |
|
||||||
throw devilution_net_udp::packet_exception(); |
|
||||||
auto pktlen = encrypted_buffer.size() - crypto_secretbox_NONCEBYTES - crypto_secretbox_MACBYTES; |
|
||||||
decrypted_buffer.resize(pktlen); |
|
||||||
if (crypto_secretbox_open_easy(decrypted_buffer.data(), |
|
||||||
encrypted_buffer.data() + crypto_secretbox_NONCEBYTES, |
|
||||||
encrypted_buffer.size() - crypto_secretbox_NONCEBYTES, |
|
||||||
encrypted_buffer.data(), |
|
||||||
key.data())) |
|
||||||
throw devilution_net_udp::packet_exception(); |
|
||||||
} else { |
|
||||||
if (encrypted_buffer.size() < sizeof(packet_type) + 2 * sizeof(plr_t)) |
|
||||||
throw devilution_net_udp::packet_exception(); |
|
||||||
decrypted_buffer = encrypted_buffer; |
|
||||||
} |
|
||||||
|
|
||||||
process_data<decrypt_mode_t>(); |
|
||||||
|
|
||||||
have_decrypted = true; |
|
||||||
} |
|
||||||
|
|
||||||
devilution_net_udp::devilution_net_udp(buffer_t info) |
|
||||||
{ |
|
||||||
if (sodium_init() < 0) |
|
||||||
abort(); |
|
||||||
game_init_info = std::move(info); |
|
||||||
} |
|
||||||
|
|
||||||
int devilution_net_udp::create(std::string addrstr, std::string passwd) |
|
||||||
{ |
|
||||||
sock = asio::ip::udp::socket(context); // to be removed later
|
|
||||||
setup_password(passwd); |
|
||||||
auto ipaddr = asio::ip::make_address(addrstr); |
|
||||||
if (ipaddr.is_v4()) |
|
||||||
sock.open(asio::ip::udp::v4()); |
|
||||||
else if (ipaddr.is_v6()) |
|
||||||
sock.open(asio::ip::udp::v6()); |
|
||||||
sock.non_blocking(true); |
|
||||||
unsigned short port = default_port; |
|
||||||
/*
|
|
||||||
while(port <= default_port+try_ports) { |
|
||||||
try { |
|
||||||
sock.bind(asio::ip::udp::endpoint(asio::ip::address_v6(), port)); |
|
||||||
} catch (std::exception e) { |
|
||||||
eprintf("bind: %s, %s\n", asio::ip::address_v6().to_string(), e.what()); |
|
||||||
} |
|
||||||
++port; |
|
||||||
} |
|
||||||
*/ |
|
||||||
try { |
|
||||||
sock.bind(endpoint(ipaddr, port)); |
|
||||||
} catch (std::exception e) { |
|
||||||
return -1; |
|
||||||
} |
|
||||||
plr_self = 0; |
|
||||||
return plr_self; |
|
||||||
} |
|
||||||
|
|
||||||
int devilution_net_udp::join(std::string addrstr, std::string passwd) |
|
||||||
{ |
|
||||||
setup_password(passwd); |
|
||||||
auto ipaddr = asio::ip::make_address(addrstr); |
|
||||||
endpoint themaster(ipaddr, default_port); |
|
||||||
sock.connect(themaster); |
|
||||||
master = themaster; |
|
||||||
{ // hack: try to join for 5 seconds
|
|
||||||
randombytes_buf(reinterpret_cast<unsigned char *>(&cookie_self), |
|
||||||
sizeof(cookie_t)); |
|
||||||
packet pkt(key); |
|
||||||
pkt.create(PT_JOIN_REQUEST, ADDR_BROADCAST, ADDR_MASTER, cookie_self); |
|
||||||
send(pkt); |
|
||||||
for (auto i = 0; i < 5; ++i) { |
|
||||||
recv(); |
|
||||||
if (plr_self != ADDR_BROADCAST) |
|
||||||
break; // join successful
|
|
||||||
sleep(1); |
|
||||||
} |
|
||||||
} |
|
||||||
return (plr_self == ADDR_BROADCAST ? 4 : plr_self); |
|
||||||
} |
|
||||||
|
|
||||||
void devilution_net_udp::setup_password(std::string pw) |
|
||||||
{ |
|
||||||
//pw.resize(std::min(pw.size(), crypto_pwhash_PASSWD_MAX));
|
|
||||||
//pw.resize(std::max(pw.size(), crypto_pwhash_PASSWD_MIN), 0);
|
|
||||||
std::string salt("devilution-salt"); |
|
||||||
salt.resize(crypto_pwhash_SALTBYTES, 0); |
|
||||||
if (crypto_pwhash(key.data(), crypto_secretbox_KEYBYTES, |
|
||||||
pw.data(), pw.size(), |
|
||||||
reinterpret_cast<const unsigned char *>(salt.data()), |
|
||||||
crypto_pwhash_OPSLIMIT_INTERACTIVE, |
|
||||||
crypto_pwhash_MEMLIMIT_INTERACTIVE, |
|
||||||
crypto_pwhash_ALG_DEFAULT)) |
|
||||||
ABORT(); |
|
||||||
} |
|
||||||
|
|
||||||
void devilution_net_udp::recv() |
|
||||||
{ |
|
||||||
try { |
|
||||||
while (1) { // read until kernel buffer is empty?
|
|
||||||
try { |
|
||||||
endpoint sender; |
|
||||||
buffer_t pkt_buf(max_packet_size); |
|
||||||
size_t pkt_len; |
|
||||||
pkt_len = sock.receive_from(asio::buffer(pkt_buf), sender); |
|
||||||
pkt_buf.resize(pkt_len); |
|
||||||
packet pkt(key); |
|
||||||
pkt.create(pkt_buf); |
|
||||||
pkt.decrypt(); |
|
||||||
recv_decrypted(pkt, sender); |
|
||||||
} catch (packet_exception e) { |
|
||||||
// drop packet
|
|
||||||
} |
|
||||||
} |
|
||||||
} catch (std::exception e) { |
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void devilution_net_udp::send(devilution_net_udp::packet &pkt, endpoint sender) |
|
||||||
{ |
|
||||||
pkt.encrypt(); |
|
||||||
for (auto &dest : dests_for_addr(pkt.dest(), sender)) { |
|
||||||
sock.send_to(asio::buffer(pkt.data()), dest); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
std::set<devilution_net_udp::endpoint> devilution_net_udp::dests_for_addr(plr_t dest, endpoint sender) |
|
||||||
{ |
|
||||||
auto ret = std::set<endpoint>(); |
|
||||||
if (dest == plr_self) |
|
||||||
return ret; |
|
||||||
|
|
||||||
if (0 <= dest && dest < MAX_PLRS) { |
|
||||||
if (active_table[dest]) |
|
||||||
ret.insert(nexthop_table[dest]); |
|
||||||
} else if (dest == ADDR_BROADCAST) { |
|
||||||
for (auto i = 0; i < MAX_PLRS; ++i) |
|
||||||
if (i != plr_self && active_table[i]) |
|
||||||
ret.insert(nexthop_table[i]); |
|
||||||
ret.insert(connection_requests_pending.begin(), connection_requests_pending.end()); |
|
||||||
} else if (dest == ADDR_MASTER) { |
|
||||||
if (master != none) |
|
||||||
ret.insert(master); |
|
||||||
} |
|
||||||
ret.erase(sender); |
|
||||||
return ret; |
|
||||||
} |
|
||||||
|
|
||||||
void devilution_net_udp::handle_join_request(packet &pkt, endpoint sender) |
|
||||||
{ |
|
||||||
plr_t i; |
|
||||||
for (i = 0; i < MAX_PLRS; ++i) { |
|
||||||
if (i != plr_self && nexthop_table[i] == none) { |
|
||||||
nexthop_table[i] = sender; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
packet reply(key); |
|
||||||
reply.create(PT_JOIN_ACCEPT, plr_self, ADDR_BROADCAST, pkt.cookie(), i, game_init_info); |
|
||||||
send(reply); |
|
||||||
} |
|
||||||
|
|
||||||
void devilution_net_udp::run_event_handler(_SNETEVENT &ev) |
|
||||||
{ |
|
||||||
auto f = registered_handlers[static_cast<event_type>(ev.eventid)]; |
|
||||||
if(f) { |
|
||||||
printf("RUNNING HANDLER"); |
|
||||||
f(&ev); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void devilution_net_udp::handle_accept(packet &pkt) |
|
||||||
{ |
|
||||||
if (plr_self != ADDR_BROADCAST) |
|
||||||
return; // already have player id
|
|
||||||
if (pkt.cookie() == cookie_self) |
|
||||||
plr_self = pkt.newplr(); |
|
||||||
_SNETEVENT ev; |
|
||||||
ev.eventid = EVENT_TYPE_PLAYER_CREATE_GAME; |
|
||||||
ev.playerid = plr_self; |
|
||||||
ev.data = pkt.info().data(); |
|
||||||
ev.databytes = pkt.info().size(); |
|
||||||
printf("GOT SEED!!"); |
|
||||||
run_event_handler(ev); |
|
||||||
} |
|
||||||
|
|
||||||
void devilution_net_udp::recv_decrypted(packet &pkt, endpoint sender) |
|
||||||
{ |
|
||||||
// 1. route
|
|
||||||
send(pkt, sender); |
|
||||||
// 2. handle local
|
|
||||||
if (pkt.src() == ADDR_BROADCAST && pkt.dest() == ADDR_MASTER) { |
|
||||||
connection_requests_pending.insert(sender); |
|
||||||
if (master == none) { |
|
||||||
handle_join_request(pkt, sender); |
|
||||||
} |
|
||||||
} |
|
||||||
// normal packets
|
|
||||||
if (pkt.src() < 0 || pkt.src() >= MAX_PLRS) |
|
||||||
return; //drop packet
|
|
||||||
if (active_table[pkt.src()]) { //WRONG?!?
|
|
||||||
if (sender != nexthop_table[pkt.src()]) |
|
||||||
return; //rpfilter fail: drop packet
|
|
||||||
} else { |
|
||||||
nexthop_table[pkt.src()] = sender; // new connection: accept
|
|
||||||
} |
|
||||||
active_table[pkt.src()] = ACTIVE; |
|
||||||
if (pkt.dest() != plr_self && pkt.dest() != ADDR_BROADCAST) |
|
||||||
return; //packet not for us, drop
|
|
||||||
switch (pkt.type()) { |
|
||||||
case PT_MESSAGE: |
|
||||||
message_queue.push(message_t(pkt.src(), pkt.message())); |
|
||||||
break; |
|
||||||
case PT_TURN: |
|
||||||
turn_last[pkt.src()] = pkt.turn(); |
|
||||||
turn_new[pkt.src()] = true; |
|
||||||
break; |
|
||||||
case PT_JOIN_ACCEPT: |
|
||||||
handle_accept(pkt); |
|
||||||
break; |
|
||||||
case PT_LEAVE_GAME: |
|
||||||
// todo
|
|
||||||
break; |
|
||||||
// otherwise drop
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
bool devilution_net_udp::SNetReceiveMessage(int *sender, char **data, int *size) |
|
||||||
{ |
|
||||||
recv(); |
|
||||||
if (message_queue.empty()) |
|
||||||
return false; |
|
||||||
message_last = message_queue.front(); |
|
||||||
message_queue.pop(); |
|
||||||
*sender = message_last.sender; |
|
||||||
*size = message_last.payload.size(); |
|
||||||
*data = reinterpret_cast<char *>(message_last.payload.data()); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
bool devilution_net_udp::SNetSendMessage(int playerID, void *data, unsigned int size) |
|
||||||
{ |
|
||||||
if (playerID != SNPLAYER_ALL && playerID != SNPLAYER_OTHERS && (playerID < 0 || playerID >= MAX_PLRS)) |
|
||||||
abort(); |
|
||||||
auto raw_message = reinterpret_cast<unsigned char *>(data); |
|
||||||
buffer_t message(raw_message, raw_message + size); |
|
||||||
if (playerID == plr_self || playerID == SNPLAYER_ALL) |
|
||||||
message_queue.push(message_t(plr_self, message)); |
|
||||||
plr_t dest; |
|
||||||
if (playerID == SNPLAYER_ALL || playerID == SNPLAYER_OTHERS) |
|
||||||
dest = ADDR_BROADCAST; |
|
||||||
else |
|
||||||
dest = playerID; |
|
||||||
packet pkt(key); |
|
||||||
pkt.create(PT_MESSAGE, plr_self, dest, message); |
|
||||||
send(pkt); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
bool devilution_net_udp::SNetReceiveTurns(char **data, unsigned int *size, DWORD *status) |
|
||||||
{ |
|
||||||
recv(); |
|
||||||
for (auto i = 0; i < MAX_PLRS; ++i) { |
|
||||||
status[i] = 0; |
|
||||||
if (i == plr_self || nexthop_table[i] != none) { |
|
||||||
status[i] |= (PS_ACTIVE | PS_CONNECTED); |
|
||||||
} |
|
||||||
size[i] = sizeof(turn_t); |
|
||||||
if (turn_new[i] = true) { |
|
||||||
status[i] |= PS_HASMSG; |
|
||||||
data[i] = reinterpret_cast<char *>(&turn_last[i]); |
|
||||||
turn_new[i] = false; |
|
||||||
} |
|
||||||
} |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
bool devilution_net_udp::SNetSendTurn(char *data, unsigned int size) |
|
||||||
{ |
|
||||||
if (size != sizeof(turn_t)) |
|
||||||
ABORT(); |
|
||||||
packet pkt(key); |
|
||||||
pkt.create(PT_TURN, plr_self, ADDR_BROADCAST, *reinterpret_cast<turn_t *>(data)); |
|
||||||
send(pkt); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
int devilution_net_udp::SNetGetProviderCaps(struct _SNETCAPS *caps) |
|
||||||
{ |
|
||||||
caps->size = 0; // engine writes only ?!?
|
|
||||||
caps->flags = 0; // unused
|
|
||||||
caps->maxmessagesize = 512; // capped to 512; underflow if < 24
|
|
||||||
caps->maxqueuesize = 0; // unused
|
|
||||||
caps->maxplayers = MAX_PLRS; // capped to 4
|
|
||||||
caps->bytessec = 1000000; // ?
|
|
||||||
caps->latencyms = 0; // unused
|
|
||||||
caps->defaultturnssec = 10; // ?
|
|
||||||
caps->defaultturnsintransit = 1; // maximum acceptable number of turns in queue?
|
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
void *devilution_net_udp::SNetUnregisterEventHandler(event_type evtype, void(__stdcall *func)(struct _SNETEVENT *)) |
|
||||||
{ |
|
||||||
registered_handlers.erase(evtype); |
|
||||||
return (void*)func; |
|
||||||
} |
|
||||||
|
|
||||||
void *devilution_net_udp::SNetRegisterEventHandler(event_type evtype, void(__stdcall *func)(struct _SNETEVENT *)) |
|
||||||
{ |
|
||||||
registered_handlers[evtype] = func; |
|
||||||
return (void*)func; |
|
||||||
// need to handle:
|
|
||||||
// EVENT_TYPE_PLAYER_LEAVE_GAME
|
|
||||||
// EVENT_TYPE_PLAYER_CREATE_GAME (raised during SNetCreateGame?)
|
|
||||||
// EVENT_TYPE_PLAYER_MESSAGE
|
|
||||||
// all by the same function
|
|
||||||
} |
|
||||||
@ -0,0 +1,67 @@ |
|||||||
|
#include "../types.h" |
||||||
|
|
||||||
|
std::unique_ptr<dvlnet> dvlnet::inst; |
||||||
|
|
||||||
|
int dvlnet_null::create(std::string addrstr, std::string passwd) |
||||||
|
{ |
||||||
|
return plr_single; |
||||||
|
} |
||||||
|
|
||||||
|
int dvlnet_null::join(std::string addrstr, std::string passwd) |
||||||
|
{ |
||||||
|
ABORT(); |
||||||
|
} |
||||||
|
|
||||||
|
bool dvlnet_null::SNetReceiveMessage(int *sender, char **data, int *size) |
||||||
|
{ |
||||||
|
if (message_queue.empty()) |
||||||
|
return false; |
||||||
|
message_last = message_queue.front(); |
||||||
|
message_queue.pop(); |
||||||
|
*sender = plr_single; |
||||||
|
*size = message_last.size(); |
||||||
|
*data = reinterpret_cast<char *>(message_last.data()); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
bool dvlnet_null::SNetSendMessage(int dest, void *data, unsigned int size) |
||||||
|
{ |
||||||
|
if (dest == plr_single || dest == SNPLAYER_ALL) { |
||||||
|
auto raw_message = reinterpret_cast<unsigned char *>(data); |
||||||
|
buffer_t message(raw_message, raw_message + size); |
||||||
|
message_queue.push(message); |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
bool dvlnet_null::SNetReceiveTurns(char **data, unsigned int *size, DWORD *status) |
||||||
|
{ |
||||||
|
// todo: check that this is safe
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
bool dvlnet_null::SNetSendTurn(char *data, unsigned int size) |
||||||
|
{ |
||||||
|
// todo: check that this is safe
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
int dvlnet_null::SNetGetProviderCaps(struct _SNETCAPS *caps) |
||||||
|
{ |
||||||
|
// todo: check that this is safe
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
void *dvlnet_null::SNetRegisterEventHandler(event_type evtype, void(__stdcall *func)(struct _SNETEVENT *)) |
||||||
|
{ |
||||||
|
// not called in real singleplayer mode
|
||||||
|
// not needed in pseudo multiplayer mode (?)
|
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
void *dvlnet_null::SNetUnregisterEventHandler(event_type evtype, void(__stdcall *func)(struct _SNETEVENT *)) |
||||||
|
{ |
||||||
|
// not called in real singleplayer mode
|
||||||
|
// not needed in pseudo multiplayer mode (?)
|
||||||
|
return this; |
||||||
|
} |
||||||
@ -0,0 +1,297 @@ |
|||||||
|
#include "../types.h" |
||||||
|
|
||||||
|
const dvlnet_udp::endpoint dvlnet_udp::none; |
||||||
|
|
||||||
|
dvlnet_udp::dvlnet_udp(buffer_t info) |
||||||
|
{ |
||||||
|
if (sodium_init() < 0) |
||||||
|
abort(); |
||||||
|
game_init_info = std::move(info); |
||||||
|
} |
||||||
|
|
||||||
|
int dvlnet_udp::create(std::string addrstr, std::string passwd) |
||||||
|
{ |
||||||
|
sock = asio::ip::udp::socket(context); // to be removed later
|
||||||
|
setup_password(passwd); |
||||||
|
auto ipaddr = asio::ip::make_address(addrstr); |
||||||
|
if (ipaddr.is_v4()) |
||||||
|
sock.open(asio::ip::udp::v4()); |
||||||
|
else if (ipaddr.is_v6()) |
||||||
|
sock.open(asio::ip::udp::v6()); |
||||||
|
sock.non_blocking(true); |
||||||
|
unsigned short port = default_port; |
||||||
|
/*
|
||||||
|
while(port <= default_port+try_ports) { |
||||||
|
try { |
||||||
|
sock.bind(asio::ip::udp::endpoint(asio::ip::address_v6(), port)); |
||||||
|
} catch (std::exception e) { |
||||||
|
eprintf("bind: %s, %s\n", asio::ip::address_v6().to_string(), e.what()); |
||||||
|
} |
||||||
|
++port; |
||||||
|
} |
||||||
|
*/ |
||||||
|
try { |
||||||
|
sock.bind(endpoint(ipaddr, port)); |
||||||
|
} catch (std::exception e) { |
||||||
|
return -1; |
||||||
|
} |
||||||
|
plr_self = 0; |
||||||
|
return plr_self; |
||||||
|
} |
||||||
|
|
||||||
|
int dvlnet_udp::join(std::string addrstr, std::string passwd) |
||||||
|
{ |
||||||
|
setup_password(passwd); |
||||||
|
auto ipaddr = asio::ip::make_address(addrstr); |
||||||
|
endpoint themaster(ipaddr, default_port); |
||||||
|
sock.connect(themaster); |
||||||
|
master = themaster; |
||||||
|
{ // hack: try to join for 5 seconds
|
||||||
|
randombytes_buf(reinterpret_cast<unsigned char *>(&cookie_self), |
||||||
|
sizeof(cookie_t)); |
||||||
|
upacket pkt = make_packet(PT_JOIN_REQUEST, ADDR_BROADCAST, ADDR_MASTER, cookie_self); |
||||||
|
send(pkt); |
||||||
|
for (auto i = 0; i < 5; ++i) { |
||||||
|
recv(); |
||||||
|
if (plr_self != ADDR_BROADCAST) |
||||||
|
break; // join successful
|
||||||
|
sleep(1); |
||||||
|
} |
||||||
|
} |
||||||
|
return (plr_self == ADDR_BROADCAST ? 4 : plr_self); |
||||||
|
} |
||||||
|
|
||||||
|
void dvlnet_udp::setup_password(std::string pw) |
||||||
|
{ |
||||||
|
//pw.resize(std::min(pw.size(), crypto_pwhash_PASSWD_MAX));
|
||||||
|
//pw.resize(std::max(pw.size(), crypto_pwhash_PASSWD_MIN), 0);
|
||||||
|
std::string salt("devilution-salt"); |
||||||
|
salt.resize(crypto_pwhash_SALTBYTES, 0); |
||||||
|
if (crypto_pwhash(key.data(), crypto_secretbox_KEYBYTES, |
||||||
|
pw.data(), pw.size(), |
||||||
|
reinterpret_cast<const unsigned char *>(salt.data()), |
||||||
|
crypto_pwhash_OPSLIMIT_INTERACTIVE, |
||||||
|
crypto_pwhash_MEMLIMIT_INTERACTIVE, |
||||||
|
crypto_pwhash_ALG_DEFAULT)) |
||||||
|
ABORT(); |
||||||
|
} |
||||||
|
|
||||||
|
void dvlnet_udp::recv() |
||||||
|
{ |
||||||
|
try { |
||||||
|
while (1) { // read until kernel buffer is empty?
|
||||||
|
try { |
||||||
|
endpoint sender; |
||||||
|
buffer_t pkt_buf(max_packet_size); |
||||||
|
size_t pkt_len; |
||||||
|
pkt_len = sock.receive_from(asio::buffer(pkt_buf), sender); |
||||||
|
pkt_buf.resize(pkt_len); |
||||||
|
upacket pkt = make_packet(pkt_buf); |
||||||
|
recv_decrypted(pkt, sender); |
||||||
|
} catch (packet_exception e) { |
||||||
|
// drop packet
|
||||||
|
} |
||||||
|
} |
||||||
|
} catch (std::exception e) { |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void dvlnet_udp::send(dvlnet_udp::upacket &pkt, endpoint sender) |
||||||
|
{ |
||||||
|
for (auto &dest : dests_for_addr(pkt->dest(), sender)) { |
||||||
|
sock.send_to(asio::buffer(pkt->data()), dest); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
std::set<dvlnet_udp::endpoint> dvlnet_udp::dests_for_addr(plr_t dest, endpoint sender) |
||||||
|
{ |
||||||
|
auto ret = std::set<endpoint>(); |
||||||
|
if (dest == plr_self) |
||||||
|
return ret; |
||||||
|
|
||||||
|
if (0 <= dest && dest < MAX_PLRS) { |
||||||
|
if (active_table[dest]) |
||||||
|
ret.insert(nexthop_table[dest]); |
||||||
|
} else if (dest == ADDR_BROADCAST) { |
||||||
|
for (auto i = 0; i < MAX_PLRS; ++i) |
||||||
|
if (i != plr_self && active_table[i]) |
||||||
|
ret.insert(nexthop_table[i]); |
||||||
|
ret.insert(connection_requests_pending.begin(), connection_requests_pending.end()); |
||||||
|
} else if (dest == ADDR_MASTER) { |
||||||
|
if (master != none) |
||||||
|
ret.insert(master); |
||||||
|
} |
||||||
|
ret.erase(sender); |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
void dvlnet_udp::handle_join_request(upacket &pkt, endpoint sender) |
||||||
|
{ |
||||||
|
plr_t i; |
||||||
|
for (i = 0; i < MAX_PLRS; ++i) { |
||||||
|
if (i != plr_self && nexthop_table[i] == none) { |
||||||
|
nexthop_table[i] = sender; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
upacket reply = make_packet(PT_JOIN_ACCEPT, plr_self, ADDR_BROADCAST, pkt->cookie(), i, game_init_info); |
||||||
|
send(reply); |
||||||
|
} |
||||||
|
|
||||||
|
void dvlnet_udp::run_event_handler(_SNETEVENT &ev) |
||||||
|
{ |
||||||
|
/* disable until UI ready
|
||||||
|
auto f = registered_handlers[static_cast<event_type>(ev.eventid)]; |
||||||
|
if(f) { |
||||||
|
printf("RUNNING HANDLER"); |
||||||
|
f(&ev); |
||||||
|
} |
||||||
|
*/ |
||||||
|
} |
||||||
|
|
||||||
|
void dvlnet_udp::handle_accept(upacket &pkt) |
||||||
|
{ |
||||||
|
if (plr_self != ADDR_BROADCAST) |
||||||
|
return; // already have player id
|
||||||
|
if (pkt->cookie() == cookie_self) |
||||||
|
plr_self = pkt->newplr(); |
||||||
|
_SNETEVENT ev; |
||||||
|
ev.eventid = EVENT_TYPE_PLAYER_CREATE_GAME; |
||||||
|
ev.playerid = plr_self; |
||||||
|
ev.data = pkt->info().data(); |
||||||
|
ev.databytes = pkt->info().size(); |
||||||
|
printf("GOT SEED!!"); |
||||||
|
run_event_handler(ev); |
||||||
|
} |
||||||
|
|
||||||
|
void dvlnet_udp::recv_decrypted(upacket &pkt, endpoint sender) |
||||||
|
{ |
||||||
|
// 1. route
|
||||||
|
send(pkt, sender); |
||||||
|
// 2. handle local
|
||||||
|
if (pkt->src() == ADDR_BROADCAST && pkt->dest() == ADDR_MASTER) { |
||||||
|
connection_requests_pending.insert(sender); |
||||||
|
if (master == none) { |
||||||
|
handle_join_request(pkt, sender); |
||||||
|
} |
||||||
|
} |
||||||
|
// normal packets
|
||||||
|
if (pkt->src() < 0 || pkt->src() >= MAX_PLRS) |
||||||
|
return; //drop packet
|
||||||
|
if (active_table[pkt->src()]) { //WRONG?!?
|
||||||
|
if (sender != nexthop_table[pkt->src()]) |
||||||
|
return; //rpfilter fail: drop packet
|
||||||
|
} else { |
||||||
|
nexthop_table[pkt->src()] = sender; // new connection: accept
|
||||||
|
} |
||||||
|
active_table[pkt->src()] = ACTIVE; |
||||||
|
if (pkt->dest() != plr_self && pkt->dest() != ADDR_BROADCAST) |
||||||
|
return; //packet not for us, drop
|
||||||
|
switch (pkt->type()) { |
||||||
|
case PT_MESSAGE: |
||||||
|
message_queue.push(message_t(pkt->src(), pkt->message())); |
||||||
|
break; |
||||||
|
case PT_TURN: |
||||||
|
turn_last[pkt->src()] = pkt->turn(); |
||||||
|
turn_new[pkt->src()] = true; |
||||||
|
break; |
||||||
|
case PT_JOIN_ACCEPT: |
||||||
|
handle_accept(pkt); |
||||||
|
break; |
||||||
|
case PT_LEAVE_GAME: |
||||||
|
// todo
|
||||||
|
break; |
||||||
|
// otherwise drop
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool dvlnet_udp::SNetReceiveMessage(int *sender, char **data, int *size) |
||||||
|
{ |
||||||
|
recv(); |
||||||
|
if (message_queue.empty()) |
||||||
|
return false; |
||||||
|
message_last = message_queue.front(); |
||||||
|
message_queue.pop(); |
||||||
|
*sender = message_last.sender; |
||||||
|
*size = message_last.payload.size(); |
||||||
|
*data = reinterpret_cast<char *>(message_last.payload.data()); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
bool dvlnet_udp::SNetSendMessage(int playerID, void *data, unsigned int size) |
||||||
|
{ |
||||||
|
if (playerID != SNPLAYER_ALL && playerID != SNPLAYER_OTHERS && (playerID < 0 || playerID >= MAX_PLRS)) |
||||||
|
abort(); |
||||||
|
auto raw_message = reinterpret_cast<unsigned char *>(data); |
||||||
|
buffer_t message(raw_message, raw_message + size); |
||||||
|
if (playerID == plr_self || playerID == SNPLAYER_ALL) |
||||||
|
message_queue.push(message_t(plr_self, message)); |
||||||
|
plr_t dest; |
||||||
|
if (playerID == SNPLAYER_ALL || playerID == SNPLAYER_OTHERS) |
||||||
|
dest = ADDR_BROADCAST; |
||||||
|
else |
||||||
|
dest = playerID; |
||||||
|
upacket pkt = make_packet(PT_MESSAGE, plr_self, dest, message); |
||||||
|
send(pkt); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
bool dvlnet_udp::SNetReceiveTurns(char **data, unsigned int *size, DWORD *status) |
||||||
|
{ |
||||||
|
recv(); |
||||||
|
for (auto i = 0; i < MAX_PLRS; ++i) { |
||||||
|
status[i] = 0; |
||||||
|
if (i == plr_self || nexthop_table[i] != none) { |
||||||
|
status[i] |= (PS_ACTIVE | PS_CONNECTED); |
||||||
|
} |
||||||
|
size[i] = sizeof(turn_t); |
||||||
|
if (turn_new[i] = true) { |
||||||
|
status[i] |= PS_HASMSG; |
||||||
|
data[i] = reinterpret_cast<char *>(&turn_last[i]); |
||||||
|
turn_new[i] = false; |
||||||
|
} |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
bool dvlnet_udp::SNetSendTurn(char *data, unsigned int size) |
||||||
|
{ |
||||||
|
if (size != sizeof(turn_t)) |
||||||
|
ABORT(); |
||||||
|
upacket pkt = make_packet(PT_TURN, plr_self, ADDR_BROADCAST, *reinterpret_cast<turn_t *>(data)); |
||||||
|
send(pkt); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
int dvlnet_udp::SNetGetProviderCaps(struct _SNETCAPS *caps) |
||||||
|
{ |
||||||
|
caps->size = 0; // engine writes only ?!?
|
||||||
|
caps->flags = 0; // unused
|
||||||
|
caps->maxmessagesize = 512; // capped to 512; underflow if < 24
|
||||||
|
caps->maxqueuesize = 0; // unused
|
||||||
|
caps->maxplayers = MAX_PLRS; // capped to 4
|
||||||
|
caps->bytessec = 1000000; // ?
|
||||||
|
caps->latencyms = 0; // unused
|
||||||
|
caps->defaultturnssec = 10; // ?
|
||||||
|
caps->defaultturnsintransit = 1; // maximum acceptable number of turns in queue?
|
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void *dvlnet_udp::SNetUnregisterEventHandler(event_type evtype, void(__stdcall *func)(struct _SNETEVENT *)) |
||||||
|
{ |
||||||
|
registered_handlers.erase(evtype); |
||||||
|
return (void*)func; |
||||||
|
} |
||||||
|
|
||||||
|
void *dvlnet_udp::SNetRegisterEventHandler(event_type evtype, void(__stdcall *func)(struct _SNETEVENT *)) |
||||||
|
{ |
||||||
|
registered_handlers[evtype] = func; |
||||||
|
return (void*)func; |
||||||
|
// need to handle:
|
||||||
|
// EVENT_TYPE_PLAYER_LEAVE_GAME
|
||||||
|
// EVENT_TYPE_PLAYER_CREATE_GAME (raised during SNetCreateGame?)
|
||||||
|
// EVENT_TYPE_PLAYER_MESSAGE
|
||||||
|
// all by the same function
|
||||||
|
} |
||||||
@ -0,0 +1,230 @@ |
|||||||
|
#include "../types.h" |
||||||
|
|
||||||
|
static constexpr bool disable_encryption = false; |
||||||
|
|
||||||
|
const dvlnet_udp::buffer_t &dvlnet_udp::packet::data() |
||||||
|
{ |
||||||
|
if (!have_decrypted || !have_encrypted) |
||||||
|
ABORT(); |
||||||
|
return encrypted_buffer; |
||||||
|
} |
||||||
|
|
||||||
|
dvlnet_udp::packet_type dvlnet_udp::packet::type() |
||||||
|
{ |
||||||
|
if (!have_decrypted) |
||||||
|
ABORT(); |
||||||
|
return m_type; |
||||||
|
} |
||||||
|
|
||||||
|
dvlnet_udp::plr_t dvlnet_udp::packet::src() |
||||||
|
{ |
||||||
|
if (!have_decrypted) |
||||||
|
ABORT(); |
||||||
|
return m_src; |
||||||
|
} |
||||||
|
|
||||||
|
dvlnet_udp::plr_t dvlnet_udp::packet::dest() |
||||||
|
{ |
||||||
|
if (!have_decrypted) |
||||||
|
ABORT(); |
||||||
|
return m_dest; |
||||||
|
} |
||||||
|
|
||||||
|
const dvlnet_udp::buffer_t &dvlnet_udp::packet::message() |
||||||
|
{ |
||||||
|
if (!have_decrypted) |
||||||
|
ABORT(); |
||||||
|
if (m_type != PT_MESSAGE) |
||||||
|
throw dvlnet_udp::packet_exception(); |
||||||
|
return m_message; |
||||||
|
} |
||||||
|
|
||||||
|
dvlnet_udp::turn_t dvlnet_udp::packet::turn() |
||||||
|
{ |
||||||
|
if (!have_decrypted) |
||||||
|
ABORT(); |
||||||
|
if (m_type != PT_TURN) |
||||||
|
throw dvlnet_udp::packet_exception(); |
||||||
|
return m_turn; |
||||||
|
} |
||||||
|
|
||||||
|
dvlnet_udp::cookie_t dvlnet_udp::packet::cookie() |
||||||
|
{ |
||||||
|
if (!have_decrypted) |
||||||
|
ABORT(); |
||||||
|
if (m_type != PT_JOIN_REQUEST && m_type != PT_JOIN_ACCEPT) |
||||||
|
throw dvlnet_udp::packet_exception(); |
||||||
|
return m_cookie; |
||||||
|
} |
||||||
|
|
||||||
|
dvlnet_udp::plr_t dvlnet_udp::packet::newplr() |
||||||
|
{ |
||||||
|
if (!have_decrypted) |
||||||
|
ABORT(); |
||||||
|
if (m_type != PT_JOIN_ACCEPT) |
||||||
|
throw dvlnet_udp::packet_exception(); |
||||||
|
return m_newplr; |
||||||
|
} |
||||||
|
|
||||||
|
dvlnet_udp::plr_t dvlnet_udp::packet::oldplr() |
||||||
|
{ |
||||||
|
if (!have_decrypted) |
||||||
|
ABORT(); |
||||||
|
if (m_type != PT_LEAVE_GAME) |
||||||
|
throw dvlnet_udp::packet_exception(); |
||||||
|
return m_oldplr; |
||||||
|
} |
||||||
|
|
||||||
|
const dvlnet_udp::buffer_t &dvlnet_udp::packet::info() |
||||||
|
{ |
||||||
|
if (!have_decrypted) |
||||||
|
ABORT(); |
||||||
|
if (m_type != PT_JOIN_ACCEPT) |
||||||
|
throw dvlnet_udp::packet_exception(); |
||||||
|
return m_info; |
||||||
|
} |
||||||
|
|
||||||
|
void dvlnet_udp::packet_in::create(dvlnet_udp::buffer_t buf) |
||||||
|
{ |
||||||
|
if (have_encrypted || have_decrypted) |
||||||
|
ABORT(); |
||||||
|
encrypted_buffer = std::move(buf); |
||||||
|
have_encrypted = true; |
||||||
|
} |
||||||
|
|
||||||
|
void dvlnet_udp::packet_in::decrypt() |
||||||
|
{ |
||||||
|
if (!have_encrypted) |
||||||
|
ABORT(); |
||||||
|
if (have_decrypted) |
||||||
|
return; |
||||||
|
if (!disable_encryption) { |
||||||
|
if (encrypted_buffer.size() < crypto_secretbox_NONCEBYTES + |
||||||
|
crypto_secretbox_MACBYTES + sizeof(packet_type) + 2 * sizeof(plr_t)) |
||||||
|
throw dvlnet_udp::packet_exception(); |
||||||
|
auto pktlen = encrypted_buffer.size() - crypto_secretbox_NONCEBYTES - crypto_secretbox_MACBYTES; |
||||||
|
decrypted_buffer.resize(pktlen); |
||||||
|
if (crypto_secretbox_open_easy(decrypted_buffer.data(), |
||||||
|
encrypted_buffer.data() + crypto_secretbox_NONCEBYTES, |
||||||
|
encrypted_buffer.size() - crypto_secretbox_NONCEBYTES, |
||||||
|
encrypted_buffer.data(), |
||||||
|
key.data())) |
||||||
|
throw dvlnet_udp::packet_exception(); |
||||||
|
} else { |
||||||
|
if (encrypted_buffer.size() < sizeof(packet_type) + 2 * sizeof(plr_t)) |
||||||
|
throw dvlnet_udp::packet_exception(); |
||||||
|
decrypted_buffer = encrypted_buffer; |
||||||
|
} |
||||||
|
|
||||||
|
process_data(*this); |
||||||
|
|
||||||
|
have_decrypted = true; |
||||||
|
} |
||||||
|
|
||||||
|
void dvlnet_udp::packet_out::create(dvlnet_udp::packet_type t, |
||||||
|
dvlnet_udp::plr_t s, |
||||||
|
dvlnet_udp::plr_t d, |
||||||
|
dvlnet_udp::buffer_t m) |
||||||
|
{ |
||||||
|
if (have_encrypted || have_decrypted) |
||||||
|
ABORT(); |
||||||
|
if (t != PT_MESSAGE) |
||||||
|
ABORT(); |
||||||
|
have_decrypted = true; |
||||||
|
m_type = t; |
||||||
|
m_src = s; |
||||||
|
m_dest = d; |
||||||
|
m_message = std::move(m); |
||||||
|
} |
||||||
|
|
||||||
|
void dvlnet_udp::packet_out::create(dvlnet_udp::packet_type t, |
||||||
|
dvlnet_udp::plr_t s, |
||||||
|
dvlnet_udp::plr_t d, |
||||||
|
dvlnet_udp::turn_t u) |
||||||
|
{ |
||||||
|
if (have_encrypted || have_decrypted) |
||||||
|
ABORT(); |
||||||
|
if (t != PT_TURN) |
||||||
|
ABORT(); |
||||||
|
have_decrypted = true; |
||||||
|
m_type = t; |
||||||
|
m_src = s; |
||||||
|
m_dest = d; |
||||||
|
m_turn = u; |
||||||
|
} |
||||||
|
|
||||||
|
void dvlnet_udp::packet_out::create(dvlnet_udp::packet_type t, |
||||||
|
dvlnet_udp::plr_t s, |
||||||
|
dvlnet_udp::plr_t d, |
||||||
|
dvlnet_udp::cookie_t c) |
||||||
|
{ |
||||||
|
if (have_encrypted || have_decrypted) |
||||||
|
ABORT(); |
||||||
|
if (t != PT_JOIN_REQUEST) |
||||||
|
ABORT(); |
||||||
|
have_decrypted = true; |
||||||
|
m_type = t; |
||||||
|
m_src = s; |
||||||
|
m_dest = d; |
||||||
|
m_cookie = c; |
||||||
|
} |
||||||
|
|
||||||
|
void dvlnet_udp::packet_out::create(dvlnet_udp::packet_type t, |
||||||
|
dvlnet_udp::plr_t s, |
||||||
|
dvlnet_udp::plr_t d, |
||||||
|
dvlnet_udp::cookie_t c, |
||||||
|
dvlnet_udp::plr_t n, |
||||||
|
dvlnet_udp::buffer_t i) |
||||||
|
{ |
||||||
|
if (have_encrypted || have_decrypted) |
||||||
|
ABORT(); |
||||||
|
if (t != PT_JOIN_ACCEPT) |
||||||
|
ABORT(); |
||||||
|
have_decrypted = true; |
||||||
|
m_type = t; |
||||||
|
m_src = s; |
||||||
|
m_dest = d; |
||||||
|
m_cookie = c; |
||||||
|
m_newplr = n; |
||||||
|
m_info = i; |
||||||
|
} |
||||||
|
|
||||||
|
void dvlnet_udp::packet_out::create(dvlnet_udp::packet_type t, |
||||||
|
dvlnet_udp::plr_t s, |
||||||
|
dvlnet_udp::plr_t d, |
||||||
|
dvlnet_udp::plr_t o) |
||||||
|
{ |
||||||
|
if (have_encrypted || have_decrypted) |
||||||
|
ABORT(); |
||||||
|
if (t != PT_LEAVE_GAME) |
||||||
|
ABORT(); |
||||||
|
have_decrypted = true; |
||||||
|
m_type = t; |
||||||
|
m_src = s; |
||||||
|
m_dest = d; |
||||||
|
m_oldplr = o; |
||||||
|
} |
||||||
|
|
||||||
|
void dvlnet_udp::packet_out::encrypt() |
||||||
|
{ |
||||||
|
if (!have_decrypted) |
||||||
|
ABORT(); |
||||||
|
if (have_encrypted) |
||||||
|
return; |
||||||
|
|
||||||
|
process_data(*this); |
||||||
|
|
||||||
|
if (!disable_encryption) { |
||||||
|
auto len_cleartext = encrypted_buffer.size(); |
||||||
|
encrypted_buffer.insert(encrypted_buffer.begin(), crypto_secretbox_NONCEBYTES, 0); |
||||||
|
encrypted_buffer.insert(encrypted_buffer.end(), crypto_secretbox_MACBYTES, 0); |
||||||
|
randombytes_buf(encrypted_buffer.data(), crypto_secretbox_NONCEBYTES); |
||||||
|
if (crypto_secretbox_easy(encrypted_buffer.data() + crypto_secretbox_NONCEBYTES, |
||||||
|
encrypted_buffer.data() + crypto_secretbox_NONCEBYTES, |
||||||
|
len_cleartext, |
||||||
|
encrypted_buffer.data(), |
||||||
|
key.data())) |
||||||
|
ABORT(); |
||||||
|
} |
||||||
|
have_encrypted = true; |
||||||
|
} |
||||||
Loading…
Reference in new issue