diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/connectionbase.cpp | 77 | ||||
-rw-r--r-- | common/connectionbase.h | 8 | ||||
-rw-r--r-- | common/message.cpp | 76 | ||||
-rw-r--r-- | common/message.h | 107 | ||||
-rw-r--r-- | common/payload.h | 49 |
5 files changed, 190 insertions, 127 deletions
diff --git a/common/connectionbase.cpp b/common/connectionbase.cpp index 23860d2..b399884 100644 --- a/common/connectionbase.cpp +++ b/common/connectionbase.cpp @@ -1,35 +1,88 @@ #include "connectionbase.h" +#include <stdexcept> + #include <iostream> void ConnectionBase::prepare_next_message() { - next_message = Message::create(); + //next_message = make_shared<Message::Hello>(); - request_data(next_message->deserialize(0, 0)); + //request_data(next_message->deserialize(0, 0)); } void ConnectionBase::connected() { std::cout << "Connection established." << std::endl; - prepare_next_message(); + request_data(4); } void ConnectionBase::got_data(uint8_t* data, std::size_t bytes) { - size_t remaining = next_message->deserialize(data, bytes); + if(pending_size == 0) { + if(bytes != 4) { + throw std::runtime_error("Deserialization header error."); + } + + uint16_t* header = (uint16_t*)data; + + pending_type = (Message::Type)header[0]; + pending_size = (std::size_t)header[1]; + + if(pending_size) { + request_data(pending_size); + return; + } + + bytes = 0; + } - if(remaining) { - request_data(remaining); - } else { - recv_queue.push(next_message); + if(bytes != pending_size) { + std::cout << "Bytes: " << bytes << " Pending size: " << pending_size << std::endl; + throw std::runtime_error("Deserialization attempted with incomplete data."); + // TODO: Calling got_data() with incomplete data should be allowed. + } + + pending_size = 0; + + Message::p m; + + switch(pending_type) { + case Message::Types::Hello: + m = make_shared<Message::Hello>(); + break; + + case Message::Types::Login: + m = make_shared<Message::Login>(); + break; - prepare_next_message(); + case Message::Types::LoginResponse: + m = make_shared<Message::LoginResponse>(); + break; + + default: + throw std::runtime_error("Deserialization attempted on unknown message type."); + } + + if(bytes) { + m->deserialize(data, bytes); } + + recv_queue.push(m); + + request_data(4); } void ConnectionBase::send(const Message::p& msg) { + uint16_t* header = new uint16_t[2]; + std::pair<uint8_t*, std::size_t> smsg = msg->serialize(); - write_data(smsg.first, smsg.second); + header[0] = uint16_t(msg->type); + header[1] = uint16_t(smsg.second); + + write_data((uint8_t*)header, 4); + if(smsg.second) { + write_data(smsg.first, smsg.second); + } } Message::p ConnectionBase::recv() { @@ -43,6 +96,10 @@ Message::p ConnectionBase::recv() { return msg; } +ConnectionBase::ConnectionBase() { + pending_size = 0; +} + ConnectionBase::~ConnectionBase() { std::cout << "Connection destroyed." << std::endl; } diff --git a/common/connectionbase.h b/common/connectionbase.h index 13721dc..78e3fe4 100644 --- a/common/connectionbase.h +++ b/common/connectionbase.h @@ -11,7 +11,8 @@ class ConnectionBase { private: std::queue<Message::p> recv_queue; - Message::p next_message; + Message::Type pending_type; + std::size_t pending_size; //! Create a new message and initiate reception. void prepare_next_message(); @@ -35,13 +36,14 @@ class ConnectionBase { virtual void write_data(uint8_t* data, std::size_t bytes) = 0; public: + ConnectionBase(); + virtual ~ConnectionBase(); + //! Send a message. void send(const Message::p& msg); //! Get received message or null if queue empty. Message::p recv(); - - virtual ~ConnectionBase(); }; #endif diff --git a/common/message.cpp b/common/message.cpp index ddfaaa7..6e1901d 100644 --- a/common/message.cpp +++ b/common/message.cpp @@ -5,54 +5,64 @@ #include <iostream> -std::pair<uint8_t*, std::size_t> Message::serialize() { - //std::size_t s = payload.size(); +Message::Hello::Hello() : Base(Types::Hello) { - //uint8_t* buf = new uint8_t[4 + s]; +} + +Message::Hello::Hello(const std::string& v) : Base(Types::Hello), version(v) { - //*(uint16_t*)buf = (uint16_t)s; +} + +std::pair<uint8_t*, std::size_t> Message::Hello::serialize() { + std::size_t s = version.size(); + uint8_t* buf = new uint8_t[s]; - //memcpy(buf + 4, payload.c_str(), payload.size()); + memcpy(buf, version.c_str(), version.size()); - //return std::pair<uint8_t*, std::size_t>(buf, 4 + s); - return std::pair<uint8_t*, std::size_t>(0, 0); + return std::pair<uint8_t*, std::size_t>(buf, s); } -std::size_t Message::deserialize(uint8_t* data, std::size_t bytes) { - if(deserialize_size == 0 && bytes == 0) { - return 4; - } - - if(deserialize_size == 0 && bytes == 4) { - uint16_t* header = (uint16_t*)data; - - deserialize_size = (std::size_t)header[0]; - payload_type = (Payload::Type)header[1]; - - return deserialize_size; - } +void Message::Hello::deserialize(uint8_t* data, std::size_t bytes) { + version = std::string((char*)data, bytes); +} + +Message::Login::Login() : Base(Types::Login) { - if(!deserialize_size) { - throw std::runtime_error("Deserialization header error."); - } +} + +Message::Login::Login(const std::string& n) : Base(Types::Login), nick(n) { - if(bytes != deserialize_size) { - throw std::runtime_error("Deserialization attempted with incomplete data."); - } +} + +std::pair<uint8_t*, std::size_t> Message::Login::serialize() { + std::size_t s = nick.size(); + uint8_t* buf = new uint8_t[s]; - //payload = std::string((char*)data, bytes); + memcpy(buf, nick.c_str(), nick.size()); - return 0; + return std::pair<uint8_t*, std::size_t>(buf, s); } -Message::Message() : deserialize_size(0) { +void Message::Login::deserialize(uint8_t* data, std::size_t bytes) { + nick = std::string((char*)data, bytes); +} + +Message::LoginResponse::LoginResponse() : Base(Types::LoginResponse) { + +} + +Message::LoginResponse::LoginResponse(bool ok) : Base(Types::LoginResponse), login_ok(ok) { } -Message::p Message::create() { - return Message::p(new Message); +std::pair<uint8_t*, std::size_t> Message::LoginResponse::serialize() { + uint8_t* buf = new uint8_t[1]; + + buf[1] = uint8_t(login_ok); + + return std::pair<uint8_t*, std::size_t>(buf, 1); } -Payload::Type Message::type() { - return payload_type; +void Message::LoginResponse::deserialize(uint8_t* data, std::size_t bytes) { + login_ok = bool(data[0]); } diff --git a/common/message.h b/common/message.h index 44343ae..56096ed 100644 --- a/common/message.h +++ b/common/message.h @@ -1,43 +1,86 @@ #ifndef MESSAGE_H #define MESSAGE_H -#include "payload.h" - #include <boost/shared_ptr.hpp> +#include <boost/make_shared.hpp> +using boost::make_shared; +using boost::dynamic_pointer_cast; #include <stdint.h> #include <string> -class Message { - private: - Message(); - - std::size_t deserialize_size; - - friend class ConnectionBase; - - //! Serialize message. - std::pair<uint8_t*, std::size_t> serialize(); - - //! Deserialize message. - std::size_t deserialize(uint8_t* data, std::size_t bytes); - - Payload::Type payload_type; - Payload::Base* payload_data; - - public: - typedef boost::shared_ptr<Message> p; - - static p create(); - - //! Return payload type. - Payload::Type type(); - - //! Return reference to payload. - template <class T> - T& payload() { - return dynamic_cast<T&>(*payload_data); - } +namespace Message { + namespace Types { + //! Message types. + enum Type { + Undefined, + Hello, + Login, + LoginResponse, + LobbyStatus, + LobbyAction, + GameStart, + Ready, + RoundStart, + RoundState, + RoundAction, + RoundEnd, + GameEnd + }; + } + using Types::Type; + + class Base { + protected: + Base(Type t) : type(t) {} + + public: + const Type type; + + virtual std::pair<uint8_t*, std::size_t> serialize() = 0; + virtual void deserialize(uint8_t* data, std::size_t bytes) = 0; + }; + + class Hello : public Base { + public: + typedef boost::shared_ptr<Hello> p; + + Hello(); + Hello(const std::string& v); + + std::string version; + + virtual std::pair<uint8_t*, std::size_t> serialize(); + virtual void deserialize(uint8_t* data, std::size_t bytes); + }; + + class Login : public Base { + public: + typedef boost::shared_ptr<Login> p; + + Login(); + Login(const std::string& n); + + std::string nick; + + virtual std::pair<uint8_t*, std::size_t> serialize(); + virtual void deserialize(uint8_t* data, std::size_t bytes); + }; + + class LoginResponse : public Base { + public: + typedef boost::shared_ptr<LoginResponse> p; + + LoginResponse(); + LoginResponse(bool ok); + + bool login_ok; + + virtual std::pair<uint8_t*, std::size_t> serialize(); + virtual void deserialize(uint8_t* data, std::size_t bytes); + }; + + typedef boost::shared_ptr<Base> p; }; #endif diff --git a/common/payload.h b/common/payload.h deleted file mode 100644 index fbdcd1d..0000000 --- a/common/payload.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef PAYLOAD_H -#define PAYLOAD_H - -#include <utility> -#include <stdint.h> - -namespace Payload { - namespace Types { - //! Payload types. - enum Type { - Undefined, - Hello, - Login, - LoginResponse, - LobbyStatus, - LobbyAction, - GameStart, - Ready, - RoundStart, - RoundState, - RoundAction, - RoundEnd, - GameEnd - }; - } - using Types::Type; - - class Base { - protected: - friend class Message; - - virtual std::pair<uint8_t*, std::size_t> serialize() = 0; - - Base(Type t) : type(t) {} - - public: - const Type type; - }; - - class Hello : public Base { - protected: - virtual std::pair<uint8_t*, std::size_t> serialize(); - - public: - Hello() : Base(Types::Hello) {} - }; -}; - -#endif |