diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e9e631d6..72c7f8b70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,9 +140,11 @@ set(STUB_SOURCES Stub/sound.cpp Stub/storm.cpp Stub/storm_net.cpp - Stub/dvlnet_null.cpp - Stub/dvlnet_udp.cpp - Stub/dvlnet_udp_packet.cpp + + Stub/dvlnet/loopback.cpp + Stub/dvlnet/packet.cpp + Stub/dvlnet/base.cpp + Stub/dvlnet/udp_p2p.cpp Stub/DiabloUI/credits.cpp Stub/DiabloUI/diabloui.cpp diff --git a/Stub/dvlnet.h b/Stub/dvlnet.h deleted file mode 100644 index f39fa590a..000000000 --- a/Stub/dvlnet.h +++ /dev/null @@ -1,267 +0,0 @@ -#include "sodium.h" -#include -#include -#include -#include - -class dvlnet { -public: - typedef std::vector buffer_t; - static std::unique_ptr inst; - - 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, void(__stdcall *func)(struct _SNETEVENT *)) = 0; - virtual void *SNetUnregisterEventHandler(event_type evtype, void(__stdcall *func)(struct _SNETEVENT *)) = 0; - virtual ~dvlnet() {} -}; - -class dvlnet_null: public dvlnet { -private: - std::queue 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, void(__stdcall *func)(struct _SNETEVENT *)); - virtual void *SNetUnregisterEventHandler(event_type evtype, void(__stdcall *func)(struct _SNETEVENT *)); -}; - -// exact meaning yet to be worked out -#define PS_CONNECTED 0x10000 -#define PS_TURN_ARRIVED 0x20000 -#define PS_ACTIVE 0x40000 - -class dvlnet_udp : public dvlnet { -public: - dvlnet_udp(buffer_t info); - 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, void(__stdcall *func)(struct _SNETEVENT *)); - virtual void *SNetUnregisterEventHandler(event_type evtype, void(__stdcall *func)(struct _SNETEVENT *)); - - static constexpr unsigned short max_packet_size = 0xFFFF; - - enum packet_type : uint8_t { - PT_MESSAGE = 0x01, - PT_TURN = 0x02, - PT_JOIN_REQUEST = 0x11, - PT_JOIN_ACCEPT = 0x12, - PT_LEAVE_GAME = 0x13, - }; - typedef uint8_t plr_t; - typedef uint32_t cookie_t; - typedef int turn_t; // change int to something else in devilution code later - typedef std::array key_t; - class packet_exception : public std::exception {}; - typedef asio::ip::udp::endpoint endpoint; - static const endpoint none; - - 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; - plr_t m_oldplr; - buffer_t m_info; - - 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(); - plr_t oldplr(); - const buffer_t &info(); - }; - - template class packet_proc : public packet { - public: - using packet::packet; - void process_data(); - }; - - class packet_in : public packet_proc { - public: - using packet_proc::packet_proc; - void create(buffer_t buf); - void process_element(buffer_t &x); - template void process_element(T &x); - void decrypt(); - }; - - class packet_out : public packet_proc { - public: - using packet_proc::packet_proc; - void create(packet_type t, plr_t s, plr_t d, buffer_t m); - void create(packet_type t, plr_t s, plr_t d, turn_t u); - void create(packet_type t, plr_t s, plr_t d, cookie_t c); - void create(packet_type t, plr_t s, plr_t d, cookie_t c, plr_t n, buffer_t i); - void create(packet_type t, plr_t s, plr_t d, plr_t o); - void process_element(buffer_t &x); - template void process_element(T &x); - template static const unsigned char *begin(const T &x); - template static const unsigned char *end(const T &x); - void encrypt(); - }; - - typedef std::unique_ptr upacket; - upacket make_packet(buffer_t buf); - template upacket make_packet(T t, Args... args); - -private: - static constexpr unsigned short default_port = 6112; - static constexpr unsigned short try_ports = 512; - static constexpr daddr_t ADDR_BROADCAST = 0xFF; - static constexpr daddr_t ADDR_MASTER = 0xFE; - static constexpr int ACTIVE = 60; - - std::map 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::queue message_queue; - std::array turn_last = { 0 }; - std::array, MAX_PLRS> turn_queue; - - plr_t plr_self = ADDR_BROADCAST; - unsigned short udpport_self = 0; - cookie_t cookie_self = 0; - - key_t key = { 0 }; - endpoint master; - - std::set connection_requests_pending; - std::array nexthop_table; - std::array active_table = { 0 }; - asio::io_context context; - asio::ip::udp::socket sock = asio::ip::udp::socket(context); - - unsigned short bind(); - void setup_password(std::string pw); - - void handle_join_request(upacket &pkt, endpoint sender); - void handle_accept(upacket &pkt); - void recv(); - void send(upacket &pkt, endpoint sender = none); - void recv_decrypted(upacket &pkt, endpoint sender); - std::set dests_for_addr(plr_t dest, endpoint sender); - void run_event_handler(_SNETEVENT &ev); -}; - -template void dvlnet_udp::packet_proc

::process_data() -{ - P &self = static_cast(*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); - break; - case PT_JOIN_ACCEPT: - self.process_element(m_cookie); - self.process_element(m_newplr); - self.process_element(m_info); - break; - case PT_LEAVE_GAME: - break; - } -} - -inline dvlnet_udp::upacket dvlnet_udp::make_packet(buffer_t buf) -{ - auto ret = std::make_unique(key); - ret->create(std::move(buf)); - ret->decrypt(); - return ret; -} - -template dvlnet_udp::upacket dvlnet_udp::make_packet(T t, Args... args) -{ - auto ret = std::make_unique(key); - ret->create(t, args...); - ret->encrypt(); - return ret; -} - -inline void dvlnet_udp::packet_in::process_element(buffer_t &x) -{ - x.insert(x.begin(), decrypted_buffer.begin(), decrypted_buffer.end()); - decrypted_buffer.resize(0); -} - -template void dvlnet_udp::packet_in::process_element(T &x) -{ - if (decrypted_buffer.size() < sizeof(T)) - throw packet_exception(); - x = *reinterpret_cast(decrypted_buffer.data()); - decrypted_buffer.erase(decrypted_buffer.begin(), decrypted_buffer.begin() + sizeof(T)); -} - -inline void dvlnet_udp::packet_out::process_element(buffer_t &x) -{ - encrypted_buffer.insert(encrypted_buffer.end(), x.begin(), x.end()); -} - -template void dvlnet_udp::packet_out::process_element(T &x) -{ - encrypted_buffer.insert(encrypted_buffer.end(), begin(x), end(x)); -} - -template const unsigned char *dvlnet_udp::packet_out::begin(const T &x) -{ - return reinterpret_cast(&x); -} - -template const unsigned char *dvlnet_udp::packet_out::end(const T &x) -{ - return reinterpret_cast(&x) + sizeof(T); -} diff --git a/Stub/dvlnet/base.cpp b/Stub/dvlnet/base.cpp new file mode 100644 index 000000000..2dad0818f --- /dev/null +++ b/Stub/dvlnet/base.cpp @@ -0,0 +1,135 @@ +#include "../types.h" + +using namespace dvlnet; + +void base::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(salt.data()), + crypto_pwhash_OPSLIMIT_INTERACTIVE, + crypto_pwhash_MEMLIMIT_INTERACTIVE, + crypto_pwhash_ALG_DEFAULT)) + ABORT(); +} + +void base::run_event_handler(_SNETEVENT& ev) +{ + auto f = registered_handlers[static_cast(ev.eventid)]; + if(f) { + f(&ev); + } +} + +void base::recv_local(upacket& pkt) +{ + switch (pkt->type()) { + case PT_MESSAGE: + message_queue.push(message_t(pkt->src(), pkt->message())); + break; + case PT_TURN: + turn_queue[pkt->src()].push(pkt->turn()); + break; + case PT_LEAVE_GAME: + // todo + break; + // otherwise drop + } +} + +bool base::SNetReceiveMessage(int* sender, char** data, int* size) +{ + poll(); + 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(message_last.payload.data()); + return true; +} + +bool base::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(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 base::SNetReceiveTurns(char **data, unsigned int *size, DWORD *status) +{ + poll(); + for (auto i = 0; i < MAX_PLRS; ++i) { + status[i] = 0; + if (i == plr_self || active(i)) { + status[i] |= PS_ACTIVE; + } + if (i == plr_self || connected(i)) { + status[i] |= PS_CONNECTED; + } + if (!turn_queue[i].empty()) { + size[i] = sizeof(turn_t); + status[i] |= PS_TURN_ARRIVED; + turn_last[i] = turn_queue[i].front(); + turn_queue[i].pop(); + data[i] = reinterpret_cast(&turn_last[i]); + } + } + return true; +} + +bool base::SNetSendTurn(char* data, unsigned int size) +{ + if (size != sizeof(turn_t)) + ABORT(); + upacket pkt = make_packet(PT_TURN, plr_self, ADDR_BROADCAST, *reinterpret_cast(data)); + send(pkt); + return true; +} + +int base::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* base::SNetUnregisterEventHandler(event_type evtype, void(__stdcall* func)(struct _SNETEVENT *)) +{ + registered_handlers.erase(evtype); + return (void*)func; +} + +void* base::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 +} diff --git a/Stub/dvlnet/base.h b/Stub/dvlnet/base.h new file mode 100644 index 000000000..b5f6b65d0 --- /dev/null +++ b/Stub/dvlnet/base.h @@ -0,0 +1,73 @@ +// exact meaning yet to be worked out +#define PS_CONNECTED 0x10000 +#define PS_TURN_ARRIVED 0x20000 +#define PS_ACTIVE 0x40000 + +namespace dvlnet { + class base : public dvlnet { + 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, void(__stdcall* func)(struct _SNETEVENT*)); + virtual void* SNetUnregisterEventHandler(event_type evtype, void(__stdcall* func)(struct _SNETEVENT*)); + + virtual void poll() = 0; + virtual void send(upacket& pkt) = 0; + virtual bool connected(plr_t p) = 0; + virtual bool active(plr_t p) = 0; + + static constexpr unsigned short max_packet_size = 0xFFFF; + upacket make_packet(buffer_t buf); + template upacket make_packet(T t, Args... args); + + protected: + static constexpr daddr_t ADDR_BROADCAST = 0xFF; + static constexpr daddr_t ADDR_MASTER = 0xFE; + + std::map 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::queue message_queue; + std::array turn_last = { 0 }; + std::array, MAX_PLRS> turn_queue; + + plr_t plr_self = ADDR_BROADCAST; + cookie_t cookie_self = 0; + + key_t key = { 0 }; + + void setup_password(std::string pw); + void recv_local(upacket &pkt); + void run_event_handler(_SNETEVENT &ev); + }; + + inline upacket base::make_packet(buffer_t buf) + { + auto ret = std::make_unique(key); + ret->create(std::move(buf)); + ret->decrypt(); + return ret; + } + + template upacket base::make_packet(T t, Args... args) + { + auto ret = std::make_unique(key); + ret->create(t, args...); + ret->encrypt(); + return ret; + } +} diff --git a/Stub/dvlnet/dvlnet.h b/Stub/dvlnet/dvlnet.h new file mode 100644 index 000000000..95f7c7fcd --- /dev/null +++ b/Stub/dvlnet/dvlnet.h @@ -0,0 +1,27 @@ +#pragma once +#include "sodium.h" +#include +#include +#include +#include + +namespace dvlnet { + class dvlnet { + 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, void(__stdcall *func)(struct _SNETEVENT *)) = 0; + virtual void *SNetUnregisterEventHandler(event_type evtype, void(__stdcall *func)(struct _SNETEVENT *)) = 0; + virtual ~dvlnet() {} + }; +} + +#include "dvlnet/packet.h" +#include "dvlnet/loopback.h" +#include "dvlnet/base.h" +#include "dvlnet/udp_p2p.h" diff --git a/Stub/dvlnet_null.cpp b/Stub/dvlnet/loopback.cpp similarity index 64% rename from Stub/dvlnet_null.cpp rename to Stub/dvlnet/loopback.cpp index 342f9a79e..f8e862100 100644 --- a/Stub/dvlnet_null.cpp +++ b/Stub/dvlnet/loopback.cpp @@ -1,18 +1,18 @@ #include "../types.h" -std::unique_ptr dvlnet::inst; +using namespace dvlnet; -int dvlnet_null::create(std::string addrstr, std::string passwd) +int loopback::create(std::string addrstr, std::string passwd) { return plr_single; } -int dvlnet_null::join(std::string addrstr, std::string passwd) +int loopback::join(std::string addrstr, std::string passwd) { ABORT(); } -bool dvlnet_null::SNetReceiveMessage(int *sender, char **data, int *size) +bool loopback::SNetReceiveMessage(int *sender, char **data, int *size) { if (message_queue.empty()) return false; @@ -24,7 +24,7 @@ bool dvlnet_null::SNetReceiveMessage(int *sender, char **data, int *size) return true; } -bool dvlnet_null::SNetSendMessage(int dest, void *data, unsigned int size) +bool loopback::SNetSendMessage(int dest, void *data, unsigned int size) { if (dest == plr_single || dest == SNPLAYER_ALL) { auto raw_message = reinterpret_cast(data); @@ -34,19 +34,19 @@ bool dvlnet_null::SNetSendMessage(int dest, void *data, unsigned int size) return true; } -bool dvlnet_null::SNetReceiveTurns(char **data, unsigned int *size, DWORD *status) +bool loopback::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) +bool loopback::SNetSendTurn(char *data, unsigned int size) { // todo: check that this is safe return true; } -int dvlnet_null::SNetGetProviderCaps(struct _SNETCAPS *caps) +int loopback::SNetGetProviderCaps(struct _SNETCAPS *caps) { caps->size = 0; // engine writes only ?!? caps->flags = 0; // unused @@ -60,14 +60,14 @@ int dvlnet_null::SNetGetProviderCaps(struct _SNETCAPS *caps) return 1; } -void *dvlnet_null::SNetRegisterEventHandler(event_type evtype, void(__stdcall *func)(struct _SNETEVENT *)) +void *loopback::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 *)) +void *loopback::SNetUnregisterEventHandler(event_type evtype, void(__stdcall *func)(struct _SNETEVENT *)) { // not called in real singleplayer mode // not needed in pseudo multiplayer mode (?) diff --git a/Stub/dvlnet/loopback.h b/Stub/dvlnet/loopback.h new file mode 100644 index 000000000..67378723a --- /dev/null +++ b/Stub/dvlnet/loopback.h @@ -0,0 +1,21 @@ +#pragma once + +namespace dvlnet { + class loopback : public dvlnet { + private: + std::queue 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, void(__stdcall *func)(struct _SNETEVENT *)); + virtual void *SNetUnregisterEventHandler(event_type evtype, void(__stdcall *func)(struct _SNETEVENT *)); + }; +} diff --git a/Stub/dvlnet_udp_packet.cpp b/Stub/dvlnet/packet.cpp similarity index 65% rename from Stub/dvlnet_udp_packet.cpp rename to Stub/dvlnet/packet.cpp index 942b435d6..dc1b119f9 100644 --- a/Stub/dvlnet_udp_packet.cpp +++ b/Stub/dvlnet/packet.cpp @@ -1,90 +1,92 @@ #include "../types.h" +using namespace dvlnet; + static constexpr bool disable_encryption = false; -const dvlnet_udp::buffer_t &dvlnet_udp::packet::data() +const buffer_t& packet::data() { if (!have_decrypted || !have_encrypted) ABORT(); return encrypted_buffer; } -dvlnet_udp::packet_type dvlnet_udp::packet::type() +packet_type packet::type() { if (!have_decrypted) ABORT(); return m_type; } -dvlnet_udp::plr_t dvlnet_udp::packet::src() +plr_t packet::src() { if (!have_decrypted) ABORT(); return m_src; } -dvlnet_udp::plr_t dvlnet_udp::packet::dest() +plr_t packet::dest() { if (!have_decrypted) ABORT(); return m_dest; } -const dvlnet_udp::buffer_t &dvlnet_udp::packet::message() +const buffer_t &packet::message() { if (!have_decrypted) ABORT(); if (m_type != PT_MESSAGE) - throw dvlnet_udp::packet_exception(); + throw packet_exception(); return m_message; } -dvlnet_udp::turn_t dvlnet_udp::packet::turn() +turn_t packet::turn() { if (!have_decrypted) ABORT(); if (m_type != PT_TURN) - throw dvlnet_udp::packet_exception(); + throw packet_exception(); return m_turn; } -dvlnet_udp::cookie_t dvlnet_udp::packet::cookie() +cookie_t packet::cookie() { if (!have_decrypted) ABORT(); if (m_type != PT_JOIN_REQUEST && m_type != PT_JOIN_ACCEPT) - throw dvlnet_udp::packet_exception(); + throw packet_exception(); return m_cookie; } -dvlnet_udp::plr_t dvlnet_udp::packet::newplr() +plr_t packet::newplr() { if (!have_decrypted) ABORT(); if (m_type != PT_JOIN_ACCEPT) - throw dvlnet_udp::packet_exception(); + throw packet_exception(); return m_newplr; } -dvlnet_udp::plr_t dvlnet_udp::packet::oldplr() +plr_t packet::oldplr() { if (!have_decrypted) ABORT(); if (m_type != PT_LEAVE_GAME) - throw dvlnet_udp::packet_exception(); + throw packet_exception(); return m_oldplr; } -const dvlnet_udp::buffer_t &dvlnet_udp::packet::info() +const buffer_t &packet::info() { if (!have_decrypted) ABORT(); if (m_type != PT_JOIN_ACCEPT) - throw dvlnet_udp::packet_exception(); + throw packet_exception(); return m_info; } -void dvlnet_udp::packet_in::create(dvlnet_udp::buffer_t buf) +void packet_in::create(buffer_t buf) { if (have_encrypted || have_decrypted) ABORT(); @@ -92,7 +94,7 @@ void dvlnet_udp::packet_in::create(dvlnet_udp::buffer_t buf) have_encrypted = true; } -void dvlnet_udp::packet_in::decrypt() +void packet_in::decrypt() { if (!have_encrypted) ABORT(); @@ -101,7 +103,7 @@ void dvlnet_udp::packet_in::decrypt() 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(); + throw 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(), @@ -109,10 +111,10 @@ void dvlnet_udp::packet_in::decrypt() encrypted_buffer.size() - crypto_secretbox_NONCEBYTES, encrypted_buffer.data(), key.data())) - throw dvlnet_udp::packet_exception(); + throw packet_exception(); } else { if (encrypted_buffer.size() < sizeof(packet_type) + 2 * sizeof(plr_t)) - throw dvlnet_udp::packet_exception(); + throw packet_exception(); decrypted_buffer = encrypted_buffer; } @@ -121,10 +123,10 @@ void dvlnet_udp::packet_in::decrypt() 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) +void packet_out::create(packet_type t, + plr_t s, + plr_t d, + buffer_t m) { if (have_encrypted || have_decrypted) ABORT(); @@ -137,10 +139,10 @@ void dvlnet_udp::packet_out::create(dvlnet_udp::packet_type t, 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) +void packet_out::create(packet_type t, + plr_t s, + plr_t d, + turn_t u) { if (have_encrypted || have_decrypted) ABORT(); @@ -153,10 +155,10 @@ void dvlnet_udp::packet_out::create(dvlnet_udp::packet_type t, 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) +void packet_out::create(packet_type t, + plr_t s, + plr_t d, + cookie_t c) { if (have_encrypted || have_decrypted) ABORT(); @@ -169,12 +171,12 @@ void dvlnet_udp::packet_out::create(dvlnet_udp::packet_type t, 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) +void packet_out::create(packet_type t, + plr_t s, + plr_t d, + cookie_t c, + plr_t n, + buffer_t i) { if (have_encrypted || have_decrypted) ABORT(); @@ -189,10 +191,10 @@ void dvlnet_udp::packet_out::create(dvlnet_udp::packet_type t, 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) +void packet_out::create(packet_type t, + plr_t s, + plr_t d, + plr_t o) { if (have_encrypted || have_decrypted) ABORT(); @@ -205,7 +207,7 @@ void dvlnet_udp::packet_out::create(dvlnet_udp::packet_type t, m_oldplr = o; } -void dvlnet_udp::packet_out::encrypt() +void packet_out::encrypt() { if (!have_decrypted) ABORT(); diff --git a/Stub/dvlnet/packet.h b/Stub/dvlnet/packet.h new file mode 100644 index 000000000..0fa97074e --- /dev/null +++ b/Stub/dvlnet/packet.h @@ -0,0 +1,145 @@ +#pragma once + +namespace dvlnet { + enum packet_type : uint8_t { + PT_MESSAGE = 0x01, + PT_TURN = 0x02, + PT_JOIN_REQUEST = 0x11, + PT_JOIN_ACCEPT = 0x12, + PT_LEAVE_GAME = 0x13, + }; + + typedef uint8_t plr_t; + typedef uint32_t cookie_t; + typedef int turn_t; // change int to something else in devilution code later + typedef std::vector buffer_t; + typedef std::array key_t; + + class packet_exception : public std::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; + plr_t m_oldplr; + buffer_t m_info; + + 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(); + plr_t oldplr(); + const buffer_t &info(); + }; + + template class packet_proc : public packet { + public: + using packet::packet; + void process_data(); + }; + + typedef std::unique_ptr upacket; + + class packet_in : public packet_proc { + public: + using packet_proc::packet_proc; + void create(buffer_t buf); + void process_element(buffer_t &x); + template void process_element(T &x); + void decrypt(); + }; + + class packet_out : public packet_proc { + public: + using packet_proc::packet_proc; + void create(packet_type t, plr_t s, plr_t d, buffer_t m); + void create(packet_type t, plr_t s, plr_t d, turn_t u); + void create(packet_type t, plr_t s, plr_t d, cookie_t c); + void create(packet_type t, plr_t s, plr_t d, cookie_t c, plr_t n, buffer_t i); + void create(packet_type t, plr_t s, plr_t d, plr_t o); + void process_element(buffer_t &x); + template void process_element(T &x); + template static const unsigned char *begin(const T &x); + template static const unsigned char *end(const T &x); + void encrypt(); + }; + + template void packet_proc

::process_data() + { + P &self = static_cast(*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); + break; + case PT_JOIN_ACCEPT: + self.process_element(m_cookie); + self.process_element(m_newplr); + self.process_element(m_info); + break; + case PT_LEAVE_GAME: + 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 void packet_in::process_element(T &x) + { + if (decrypted_buffer.size() < sizeof(T)) + throw packet_exception(); + x = *reinterpret_cast(decrypted_buffer.data()); + decrypted_buffer.erase(decrypted_buffer.begin(), decrypted_buffer.begin() + sizeof(T)); + } + + inline void packet_out::process_element(buffer_t &x) + { + encrypted_buffer.insert(encrypted_buffer.end(), x.begin(), x.end()); + } + + template void packet_out::process_element(T &x) + { + encrypted_buffer.insert(encrypted_buffer.end(), begin(x), end(x)); + } + + template const unsigned char* packet_out::begin(const T &x) + { + return reinterpret_cast(&x); + } + + template const unsigned char* packet_out::end(const T &x) + { + return reinterpret_cast(&x) + sizeof(T); + } +} diff --git a/Stub/dvlnet/udp_p2p.cpp b/Stub/dvlnet/udp_p2p.cpp new file mode 100644 index 000000000..2b553b5a7 --- /dev/null +++ b/Stub/dvlnet/udp_p2p.cpp @@ -0,0 +1,191 @@ +#include "../types.h" + +using namespace dvlnet; + +const udp_p2p::endpoint udp_p2p::none; + +udp_p2p::udp_p2p(buffer_t info) +{ + if (sodium_init() < 0) + abort(); + game_init_info = std::move(info); +} + + +int udp_p2p::create(std::string addrstr, std::string passwd) +{ + sock = asio::ip::udp::socket(io_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 udp_p2p::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(&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 udp_p2p::poll() +{ + recv(); +} + +void udp_p2p::send(upacket& pkt) +{ + send_internal(pkt, none); +} + +bool udp_p2p::connected(plr_t p) +{ + return active_table[p]; +} + +bool udp_p2p::active(plr_t p) +{ + return active_table[p]; +} + +void udp_p2p::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 udp_p2p::send_internal(upacket &pkt, endpoint sender) +{ + for (auto &dest : dests_for_addr(pkt->dest(), sender)) { + sock.send_to(asio::buffer(pkt->data()), dest); + } +} + +std::set udp_p2p::dests_for_addr(plr_t dest, endpoint sender) +{ + auto ret = std::set(); + 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 udp_p2p::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 udp_p2p::recv_decrypted(upacket &pkt, endpoint sender) +{ + // 1. route + send_internal(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 + if(pkt->type() == PT_JOIN_ACCEPT) + handle_accept(pkt); + else + recv_local(pkt); +} + +void udp_p2p::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 = const_cast(pkt->info().data()); + ev.databytes = pkt->info().size(); + run_event_handler(ev); +} diff --git a/Stub/dvlnet/udp_p2p.h b/Stub/dvlnet/udp_p2p.h new file mode 100644 index 000000000..c484d6ba7 --- /dev/null +++ b/Stub/dvlnet/udp_p2p.h @@ -0,0 +1,38 @@ +namespace dvlnet { + class udp_p2p : public base { + public: + udp_p2p(buffer_t info); + virtual int create(std::string addrstr, std::string passwd); + virtual int join(std::string addrstr, std::string passwd); + virtual void poll(); + virtual void send(upacket& pkt); + virtual bool connected(plr_t p); + virtual bool active(plr_t p); + + 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 connection_requests_pending; + std::array nexthop_table; + std::array active_table = { 0 }; + + asio::ip::udp::socket sock = asio::ip::udp::socket(io_context); + + void recv(); + void handle_join_request(upacket &pkt, endpoint sender); + void handle_accept(upacket &pkt); + void send_internal(upacket& pkt, endpoint sender = none); + std::set dests_for_addr(plr_t dest, endpoint sender); + void recv_decrypted(upacket &pkt, endpoint sender); + }; +} diff --git a/Stub/dvlnet_udp.cpp b/Stub/dvlnet_udp.cpp deleted file mode 100644 index 74136812f..000000000 --- a/Stub/dvlnet_udp.cpp +++ /dev/null @@ -1,292 +0,0 @@ -#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(&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(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::dests_for_addr(plr_t dest, endpoint sender) -{ - auto ret = std::set(); - 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) -{ - auto f = registered_handlers[static_cast(ev.eventid)]; - if(f) { - 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 = const_cast(pkt->info().data()); - ev.databytes = pkt->info().size(); - 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_queue[pkt->src()].push(pkt->turn()); - 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(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(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); - } - if (!turn_queue[i].empty()) { - size[i] = sizeof(turn_t); - status[i] |= PS_TURN_ARRIVED; - turn_last[i] = turn_queue[i].front(); - turn_queue[i].pop(); - data[i] = reinterpret_cast(&turn_last[i]); - } - } - 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(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 -} diff --git a/Stub/storm_net.cpp b/Stub/storm_net.cpp index 7c2a77062..8ce0f6d82 100644 --- a/Stub/storm_net.cpp +++ b/Stub/storm_net.cpp @@ -1,8 +1,10 @@ #include "../types.h" +static std::unique_ptr dvlnet_inst; + BOOL STORMAPI SNetReceiveMessage(int *senderplayerid, char **data, int *databytes) { - if (!dvlnet::inst->SNetReceiveMessage(senderplayerid, data, databytes)) { + if (!dvlnet_inst->SNetReceiveMessage(senderplayerid, data, databytes)) { SErrSetLastError(STORM_ERROR_NO_MESSAGES_WAITING); return FALSE; } @@ -11,7 +13,7 @@ BOOL STORMAPI SNetReceiveMessage(int *senderplayerid, char **data, int *databyte BOOL STORMAPI SNetSendMessage(int playerID, void *data, unsigned int databytes) { - return dvlnet::inst->SNetSendMessage(playerID, data, databytes); + return dvlnet_inst->SNetSendMessage(playerID, data, databytes); } BOOL STORMAPI SNetReceiveTurns(int a1, int arraysize, char **arraydata, unsigned int *arraydatabytes, @@ -21,27 +23,27 @@ BOOL STORMAPI SNetReceiveTurns(int a1, int arraysize, char **arraydata, unsigned UNIMPLEMENTED(); if (arraysize != MAX_PLRS) UNIMPLEMENTED(); - return dvlnet::inst->SNetReceiveTurns(arraydata, arraydatabytes, arrayplayerstatus); + return dvlnet_inst->SNetReceiveTurns(arraydata, arraydatabytes, arrayplayerstatus); } BOOL STORMAPI SNetSendTurn(char *data, unsigned int databytes) { - return dvlnet::inst->SNetSendTurn(data, databytes); + return dvlnet_inst->SNetSendTurn(data, databytes); } int __stdcall SNetGetProviderCaps(struct _SNETCAPS *caps) { - return dvlnet::inst->SNetGetProviderCaps(caps); + return dvlnet_inst->SNetGetProviderCaps(caps); } void *__stdcall SNetUnregisterEventHandler(int evtype, void(__stdcall *func)(struct _SNETEVENT *)) { - return dvlnet::inst->SNetUnregisterEventHandler(evtype, func); + return dvlnet_inst->SNetUnregisterEventHandler(evtype, func); } void *__stdcall SNetRegisterEventHandler(int evtype, void(__stdcall *func)(struct _SNETEVENT *)) { - return dvlnet::inst->SNetRegisterEventHandler(evtype, func); + return dvlnet_inst->SNetRegisterEventHandler(evtype, func); } BOOL STORMAPI SNetDestroy() @@ -85,9 +87,9 @@ int __stdcall SNetInitializeProvider(unsigned long provider, struct _SNETPROGRAM if (provider == 'UDPN') { dvlnet::buffer_t game_init_info((char*)client_info->initdata, (char*)client_info->initdata + client_info->initdatabytes); - dvlnet::inst = std::make_unique(std::move(game_init_info)); + dvlnet_inst = std::make_unique(std::move(game_init_info)); } else if (provider == 'SCBL' || provider == 0) { - dvlnet::inst = std::make_unique(); + dvlnet_inst = std::make_unique(); } else { ABORT(); } @@ -105,8 +107,8 @@ BOOL STORMAPI SNetCreateGame(const char *pszGameName, const char *pszGamePasswor // hack: cannot create game until UI is ready // first instance will create, second will join int ret; - if (ret = dvlnet::inst->create("0.0.0.0", "mypass") == -1) - ret = dvlnet::inst->join("127.0.0.1", "mypass"); + if (ret = dvlnet_inst->create("0.0.0.0", "mypass") == -1) + ret = dvlnet_inst->join("127.0.0.1", "mypass"); *playerID = ret; return TRUE; } diff --git a/types.h b/types.h index cefc5c87e..4a525c7b6 100644 --- a/types.h +++ b/types.h @@ -56,7 +56,7 @@ #include "3rdParty/PKWare/pkware.h" #ifdef MINIWIN -#include "dvlnet.h" +#include "dvlnet/dvlnet.h" #endif // If defined, use copy protection [Default -> Defined]