X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fnet%2Fcommunicator.h;h=eb9893d861a2ca8eaa3679aeedcddcd6fde24ea4;hb=b451f834a6b5440fb1064cf96c69eb5447ae86cf;hp=cd465a52d525c25cf837db2cca614a5a6e8cfc98;hpb=a0b7f9bcf0654a7a3f24bac95746ac587b71986b;p=libs%2Fnet.git diff --git a/source/net/communicator.h b/source/net/communicator.h index cd465a5..eb9893d 100644 --- a/source/net/communicator.h +++ b/source/net/communicator.h @@ -1,72 +1,96 @@ #ifndef MSP_NET_COMMUNICATOR_H_ #define MSP_NET_COMMUNICATOR_H_ +#include +#include +#include +#include "mspnet_api.h" #include "protocol.h" -#include "streamsocket.h" namespace Msp { namespace Net { -class sequence_error: public std::logic_error +class StreamSocket; + +class MSPNET_API sequence_error: public invalid_state { public: - sequence_error(const std::string &w): std::logic_error(w) { } - virtual ~sequence_error() throw() { } + sequence_error(const std::string &w): invalid_state(w) { } }; +class MSPNET_API incompatible_protocol: public std::runtime_error +{ +public: + incompatible_protocol(const std::string &w): std::runtime_error(w) { } +}; -class Communicator + +class MSPNET_API Communicator: public NonCopyable { public: - sigc::signal signal_handshake_done; + sigc::signal signal_protocol_ready; sigc::signal signal_error; private: + struct ActiveProtocol + { + std::uint64_t hash = 0; + std::uint16_t base = 0; + std::uint16_t last = 0; + bool accepted = false; + bool ready = false; + const Protocol *protocol = nullptr; + ReceiverBase *receiver = nullptr; + + ActiveProtocol(std::uint16_t, const Protocol &, ReceiverBase &); + ActiveProtocol(std::uint16_t, std::uint64_t); + }; + + struct Handshake; + StreamSocket &socket; - const Protocol &protocol; - ReceiverBase &receiver; - int handshake_status; - unsigned buf_size; - char *in_buf; - char *in_begin; - char *in_end; - char *out_buf; - bool good; + std::vector protocols; + Handshake *handshake = nullptr; + std::size_t buf_size = 65536; + char *in_buf = nullptr; + char *in_begin = nullptr; + char *in_end = nullptr; + char *out_buf = nullptr; + bool good = true; public: + Communicator(StreamSocket &); Communicator(StreamSocket &, const Protocol &, ReceiverBase &); ~Communicator(); - void initiate_handshake(); - bool is_handshake_done() const { return handshake_status==2; } + void add_protocol(const Protocol &, ReceiverBase &); + bool is_protocol_ready(const Protocol &) const; template - void send(const P &pkt) - { - if(!good) - throw sequence_error("connection aborted"); - if(handshake_status!=2) - throw sequence_error("handshaking not done"); - unsigned size = protocol.assemble(pkt, out_buf, buf_size); - try - { - socket.write(out_buf, size); - } - catch(const std::exception &e) - { - good = false; - if(signal_error.empty()) - throw; - signal_error.emit(e); - } - } + void send(const P &); private: + void send_data(std::size_t); + + void connect_finished(const std::exception *); void data_available(); - bool receive_packet(const Protocol &, ReceiverBase &); - void send_handshake(); + bool receive_packet(); + + void prepare_protocol(const ActiveProtocol &); + void accept_protocol(ActiveProtocol &); }; +template +void Communicator::send(const P &pkt) +{ + auto i = find_if(protocols, [](const ActiveProtocol &p){ return p.protocol && p.protocol->has_packet

(); }); + if(i==protocols.end()) + throw key_error(typeid(P).name()); + else if(!i->ready) + throw sequence_error("protocol not ready"); + send_data(i->protocol->serialize(pkt, out_buf, buf_size, i->base)); +} + } // namespace Net } // namespace Msp