]> git.tdb.fi Git - libs/net.git/blob - source/net/communicator.h
Add a dynamic receiver class for more flexible packet handling
[libs/net.git] / source / net / communicator.h
1 #ifndef MSP_NET_COMMUNICATOR_H_
2 #define MSP_NET_COMMUNICATOR_H_
3
4 #include <msp/core/except.h>
5 #include <msp/core/noncopyable.h>
6 #include <sigc++/signal.h>
7 #include "mspnet_api.h"
8 #include "protocol.h"
9
10 namespace Msp {
11 namespace Net {
12
13 class StreamSocket;
14
15 class MSPNET_API sequence_error: public invalid_state
16 {
17 public:
18         sequence_error(const std::string &w): invalid_state(w) { }
19 };
20
21 class MSPNET_API incompatible_protocol: public std::runtime_error
22 {
23 public:
24         incompatible_protocol(const std::string &w): std::runtime_error(w) { }
25 };
26
27
28 class MSPNET_API Communicator: public NonCopyable
29 {
30 public:
31         sigc::signal<void, const Protocol &> signal_protocol_ready;
32         sigc::signal<void, const std::exception &> signal_error;
33
34 private:
35         struct ActiveProtocol
36         {
37                 std::uint64_t hash = 0;
38                 std::uint16_t base = 0;
39                 std::uint16_t last = 0;
40                 bool accepted = false;
41                 bool ready = false;
42                 const Protocol *protocol = nullptr;
43                 ReceiverBase *receiver = nullptr;
44
45                 ActiveProtocol(std::uint16_t, const Protocol &, ReceiverBase &);
46                 ActiveProtocol(std::uint16_t, std::uint64_t);
47         };
48
49         struct Handshake;
50
51         StreamSocket &socket;
52         std::vector<ActiveProtocol> protocols;
53         Handshake *handshake = nullptr;
54         std::size_t buf_size = 65536;
55         char *in_buf = nullptr;
56         char *in_begin = nullptr;
57         char *in_end = nullptr;
58         char *out_buf = nullptr;
59         bool good = true;
60
61 public:
62         Communicator(StreamSocket &);
63         Communicator(StreamSocket &, const Protocol &, ReceiverBase &);
64         ~Communicator();
65
66         void add_protocol(const Protocol &, ReceiverBase &);
67         bool is_protocol_ready(const Protocol &) const;
68
69         template<typename P>
70         void send(const P &);
71
72 private:
73         void send_data(std::size_t);
74
75         void connect_finished(const std::exception *);
76         void data_available();
77         bool receive_packet();
78
79         void prepare_protocol(const ActiveProtocol &);
80         void accept_protocol(ActiveProtocol &);
81 };
82
83 template<typename P>
84 void Communicator::send(const P &pkt)
85 {
86         auto i = find_if(protocols, [](const ActiveProtocol &p){ return p.protocol && p.protocol->has_packet<P>(); });
87         if(i==protocols.end())
88                 throw key_error(typeid(P).name());
89         else if(!i->ready)
90                 throw sequence_error("protocol not ready");
91         send_data(i->protocol->serialize(pkt, out_buf, buf_size, i->base));
92 }
93
94 } // namespace Net
95 } // namespace Msp
96
97 #endif