#pragma once #include #include #include #include #ifndef NONET #include #endif #include "dvlnet/abstract_net.h" #include "stubs.h" 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 #ifndef NONET typedef std::array key_t; #endif 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 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; template void create(Args... args); 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); 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 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(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(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(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(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(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(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 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); } class packet_factory { key_t key = {}; public: static constexpr unsigned short max_packet_size = 0xFFFF; packet_factory(std::string pw = ""); std::unique_ptr make_packet(buffer_t buf); template std::unique_ptr make_packet(Args... args); }; inline std::unique_ptr packet_factory::make_packet(buffer_t buf) { std::unique_ptr ret(new packet_in(key)); ret->create(std::move(buf)); ret->decrypt(); return std::unique_ptr(std::move(ret)); } template std::unique_ptr packet_factory::make_packet(Args... args) { std::unique_ptr ret(new packet_out(key)); ret->create(args...); ret->encrypt(); return std::unique_ptr(std::move(ret)); } } // namespace net } // namespace dvl