X-Git-Url: http://git.tdb.fi/?p=libs%2Fnet.git;a=blobdiff_plain;f=source%2Fnet%2Fcommunicator.cpp;fp=source%2Fnet%2Fcommunicator.cpp;h=c9b277d3748de137381b0df792d5230b0e8e0c62;hp=0000000000000000000000000000000000000000;hb=50e9f9ea7f7385a2c5931fca2b8fb1103078e67c;hpb=21c596567e3b6fd794ed6af73d304ce2bc70e58f diff --git a/source/net/communicator.cpp b/source/net/communicator.cpp new file mode 100644 index 0000000..c9b277d --- /dev/null +++ b/source/net/communicator.cpp @@ -0,0 +1,158 @@ +#include +#include "communicator.h" + +namespace { + +using namespace Msp::Net; + +struct Handshake +{ + unsigned hash; +}; + + +class HandshakeProtocol: public Protocol +{ +public: + HandshakeProtocol(); +}; + +HandshakeProtocol::HandshakeProtocol(): + Protocol(0x7F00) +{ + add()(&Handshake::hash); +} + + +class HandshakeReceiver: public PacketReceiver +{ +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