#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"
namespace Msp {
class StreamSocket;
-class sequence_error: public std::logic_error
+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 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) { }
- virtual ~incompatible_protocol() throw() { }
};
-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;
- std::size_t 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 &);
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