]> git.tdb.fi Git - libs/net.git/blobdiff - source/net/communicator.cpp
Prepare for assimilating msphttp
[libs/net.git] / source / net / communicator.cpp
diff --git a/source/net/communicator.cpp b/source/net/communicator.cpp
new file mode 100644 (file)
index 0000000..c9b277d
--- /dev/null
@@ -0,0 +1,158 @@
+#include <cstring>
+#include "communicator.h"
+
+namespace {
+
+using namespace Msp::Net;
+
+struct Handshake
+{
+       unsigned hash;
+};
+
+
+class HandshakeProtocol: public Protocol
+{
+public:
+       HandshakeProtocol();
+};
+
+HandshakeProtocol::HandshakeProtocol():
+       Protocol(0x7F00)
+{
+       add<Handshake>()(&Handshake::hash);
+}
+
+
+class HandshakeReceiver: public PacketReceiver<Handshake>
+{
+private:
+       unsigned hash;
+
+public:
+       HandshakeReceiver();
+       unsigned get_hash() const { return hash; }
+       virtual void receive(const Handshake &);
+};
+
+HandshakeReceiver::HandshakeReceiver():
+       hash(0)
+{ }
+
+void HandshakeReceiver::receive(const Handshake &shake)
+{
+       hash = shake.hash;
+}
+
+}
+
+
+namespace Msp {
+namespace Net {
+
+Communicator::Communicator(StreamSocket &s, const Protocol &p, ReceiverBase &r):
+       socket(s),
+       protocol(p),
+       receiver(r),
+       handshake_status(0),
+       buf_size(1024),
+       in_buf(new char[buf_size]),
+       in_begin(in_buf),
+       in_end(in_buf),
+       out_buf(new char[buf_size]),
+       good(true)
+{
+       socket.signal_data_available.connect(sigc::mem_fun(this, &Communicator::data_available));
+}
+
+Communicator::~Communicator()
+{
+       delete[] in_buf;
+       delete[] out_buf;
+}
+
+void Communicator::initiate_handshake()
+{
+       if(handshake_status!=0)
+               throw sequence_error("handshaking already done");
+
+       send_handshake();
+       handshake_status = 1;
+}
+
+void Communicator::data_available()
+{
+       if(!good)
+               return;
+
+       in_end += socket.read(in_end, in_buf+buf_size-in_end);
+       try
+       {
+               bool more = true;
+               while(more)
+               {
+                       if(handshake_status==2)
+                       {
+                               more = receive_packet(protocol, receiver);
+                       }
+                       else
+                       {
+                               HandshakeProtocol hsproto;
+                               HandshakeReceiver hsrecv;
+                               if((more = receive_packet(hsproto, hsrecv)))
+                               {
+                                       if(hsrecv.get_hash()==protocol.get_hash())
+                                       {
+                                               if(handshake_status==0)
+                                                       send_handshake();
+                                               handshake_status = 2;
+                                               signal_handshake_done.emit();
+                                       }
+                                       else
+                                               good = false;
+                               }
+                       }
+               }
+       }
+       catch(...)
+       {
+               good = false;
+               throw;
+       }
+}
+
+bool Communicator::receive_packet(const Protocol &proto, ReceiverBase &recv)
+{
+       int psz = proto.get_packet_size(in_begin, in_end-in_begin);
+       if(psz && psz<=in_end-in_begin)
+       {
+               char *pkt = in_begin;
+               in_begin += psz;
+               proto.disassemble(recv, pkt, psz);
+               return true;
+       }
+       else
+       {
+               if(in_end==in_buf+buf_size)
+               {
+                       unsigned used = in_end-in_begin;
+                       memmove(in_buf, in_begin, used);
+                       in_begin = in_buf;
+                       in_end = in_begin+used;
+               }
+               return false;
+       }
+}
+
+void Communicator::send_handshake()
+{
+       Handshake shake;
+       shake.hash = protocol.get_hash();
+
+       HandshakeProtocol hsproto;
+       unsigned size = hsproto.assemble(shake, out_buf, buf_size);
+       socket.write(out_buf, size);
+}
+
+} // namespace Net
+} // namespace Msp