]> git.tdb.fi Git - libs/net.git/blobdiff - source/net/communicator.h
Add a dynamic receiver class for more flexible packet handling
[libs/net.git] / source / net / communicator.h
index 822b16ef998dbd706d1ea1617950175d488496ca..eb9893d861a2ca8eaa3679aeedcddcd6fde24ea4 100644 (file)
@@ -2,7 +2,9 @@
 #define MSP_NET_COMMUNICATOR_H_
 
 #include <msp/core/except.h>
+#include <msp/core/noncopyable.h>
 #include <sigc++/signal.h>
+#include "mspnet_api.h"
 #include "protocol.h"
 
 namespace Msp {
@@ -10,30 +12,45 @@ namespace Net {
 
 class StreamSocket;
 
-class sequence_error: public invalid_state
+class MSPNET_API sequence_error: public invalid_state
 {
 public:
        sequence_error(const std::string &w): invalid_state(w) { }
 };
 
-class incompatible_protocol: public std::runtime_error
+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<void> signal_handshake_done;
+       sigc::signal<void, const Protocol &> signal_protocol_ready;
        sigc::signal<void, const std::exception &> 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 = 0;
+       std::vector<ActiveProtocol> protocols;
+       Handshake *handshake = nullptr;
        std::size_t buf_size = 65536;
        char *in_buf = nullptr;
        char *in_begin = nullptr;
@@ -42,11 +59,12 @@ private:
        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<typename P>
        void send(const P &);
@@ -54,15 +72,23 @@ public:
 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<typename P>
 void Communicator::send(const P &pkt)
 {
-       send_data(protocol.serialize(pkt, out_buf, buf_size));
+       auto i = find_if(protocols, [](const ActiveProtocol &p){ return p.protocol && p.protocol->has_packet<P>(); });
+       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