#include "connectionbase.h" #include #include #include #include #include #include #include #include #include #include #include void ConnectionBase::start_recv() { request_data(4); } void ConnectionBase::got_data(uint8_t* data, std::size_t bytes) { if(pending_size == 0) { if(bytes != 4) { 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(bytes != pending_size) { std::cout << "Bytes: " << bytes << " Pending size: " << pending_size << std::endl; error("Deserialization attempted with incomplete data."); // TODO: Calling got_data() with incomplete data should be allowed. } pending_size = 0; try { // Create Boost.Serialization archive of data. std::istringstream is(std::string((char*)data, bytes)); boost::archive::binary_iarchive ia(is); switch(pending_type) { case Message::Types::Hello: { Message::Hello::p m = make_shared(); ia & m; got_message(m); } break; case Message::Types::Login: { Message::Login::p m = make_shared(); ia & m; got_message(m); } break; case Message::Types::LoginResponse: { Message::LoginResponse::p m = make_shared(); ia & m; got_message(m); } break; case Message::Types::LobbyStatus: { Message::LobbyStatus::p m = make_shared(); ia & m; got_message(m); } break; case Message::Types::LobbyAction: { Message::LobbyAction::p m = make_shared(); ia & m; got_message(m); } break; case Message::Types::GameStart: { Message::GameStart::p m = make_shared(); ia & m; got_message(m); } break; case Message::Types::Ready: { Message::Ready::p m = make_shared(); ia & m; got_message(m); } break; case Message::Types::RoundStart: { Message::RoundStart::p m = make_shared(); ia & m; got_message(m); } break; case Message::Types::RoundState: { Message::RoundState::p m = make_shared(); ia & m; got_message(m); } break; case Message::Types::RoundAction: { Message::RoundAction::p m = make_shared(); ia & m; got_message(m); } break; case Message::Types::RoundEnd: { Message::RoundEnd::p m = make_shared(); ia & m; got_message(m); } break; case Message::Types::GameEnd: { Message::GameEnd::p m = make_shared(); ia & m; got_message(m); } break; default: throw std::runtime_error("Deserialization attempted on unknown message type."); } } catch(std::exception& e) { error(std::string("Deserialization failed: ") + e.what()); } } void ConnectionBase::send(const Message::p& msg) { // Create Boost.Serialization archive. std::ostringstream os; boost::archive::binary_oarchive oa(os); switch(msg->type) { case Message::Types::Hello: { Message::Hello::p m = dynamic_pointer_cast(msg); oa & m; } break; case Message::Types::Login: { Message::Login::p m = dynamic_pointer_cast(msg); oa & m; } break; case Message::Types::LoginResponse: { Message::LoginResponse::p m = dynamic_pointer_cast(msg); oa & m; } break; case Message::Types::LobbyStatus: { Message::LobbyStatus::p m = dynamic_pointer_cast(msg); oa & m; } break; case Message::Types::LobbyAction: { Message::LobbyAction::p m = dynamic_pointer_cast(msg); oa & m; } break; case Message::Types::GameStart: { Message::GameStart::p m = dynamic_pointer_cast(msg); oa & m; } break; case Message::Types::Ready: { Message::Ready::p m = dynamic_pointer_cast(msg); oa & m; } break; case Message::Types::RoundStart: { Message::RoundStart::p m = dynamic_pointer_cast(msg); oa & m; } break; case Message::Types::RoundState: { Message::RoundState::p m = dynamic_pointer_cast(msg); oa & m; } break; case Message::Types::RoundAction: { Message::RoundAction::p m = dynamic_pointer_cast(msg); oa & m; } break; case Message::Types::RoundEnd: { Message::RoundEnd::p m = dynamic_pointer_cast(msg); oa & m; } break; default: throw std::runtime_error("Serialization attempted on unknown message type."); } // Extract data. std::string s = os.str(); // Allocate buffer. uint8_t* buf = new uint8_t[4 + s.size()]; // Write header. uint16_t* header = (uint16_t*)buf; header[0] = uint16_t(msg->type); header[1] = uint16_t(s.size()); // Copy data. memcpy(buf + 4, s.c_str(), s.size()); // Send buffer. write_data(buf, 4 + s.size()); } ConnectionBase::ConnectionBase() { pending_size = 0; } ConnectionBase::~ConnectionBase() { std::cout << "Connection destroyed." << std::endl; }