#ifndef MSP_NET_COMMUNICATOR_H_
#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"
-#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<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;
- unsigned buf_size;
- char *in_buf;
- char *in_begin;
- char *in_end;
- char *out_buf;
- bool good;
+ std::vector<ActiveProtocol> 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<typename P>
- 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);
- socket.write(out_buf, size);
- }
+ 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<typename P>
+void Communicator::send(const P &pkt)
+{
+ 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
} // namespace Msp