]> git.tdb.fi Git - libs/net.git/blob - source/net/communicator.cpp
Prepare for assimilating msphttp
[libs/net.git] / source / net / communicator.cpp
1 #include <cstring>
2 #include "communicator.h"
3
4 namespace {
5
6 using namespace Msp::Net;
7
8 struct Handshake
9 {
10         unsigned hash;
11 };
12
13
14 class HandshakeProtocol: public Protocol
15 {
16 public:
17         HandshakeProtocol();
18 };
19
20 HandshakeProtocol::HandshakeProtocol():
21         Protocol(0x7F00)
22 {
23         add<Handshake>()(&Handshake::hash);
24 }
25
26
27 class HandshakeReceiver: public PacketReceiver<Handshake>
28 {
29 private:
30         unsigned hash;
31
32 public:
33         HandshakeReceiver();
34         unsigned get_hash() const { return hash; }
35         virtual void receive(const Handshake &);
36 };
37
38 HandshakeReceiver::HandshakeReceiver():
39         hash(0)
40 { }
41
42 void HandshakeReceiver::receive(const Handshake &shake)
43 {
44         hash = shake.hash;
45 }
46
47 }
48
49
50 namespace Msp {
51 namespace Net {
52
53 Communicator::Communicator(StreamSocket &s, const Protocol &p, ReceiverBase &r):
54         socket(s),
55         protocol(p),
56         receiver(r),
57         handshake_status(0),
58         buf_size(1024),
59         in_buf(new char[buf_size]),
60         in_begin(in_buf),
61         in_end(in_buf),
62         out_buf(new char[buf_size]),
63         good(true)
64 {
65         socket.signal_data_available.connect(sigc::mem_fun(this, &Communicator::data_available));
66 }
67
68 Communicator::~Communicator()
69 {
70         delete[] in_buf;
71         delete[] out_buf;
72 }
73
74 void Communicator::initiate_handshake()
75 {
76         if(handshake_status!=0)
77                 throw sequence_error("handshaking already done");
78
79         send_handshake();
80         handshake_status = 1;
81 }
82
83 void Communicator::data_available()
84 {
85         if(!good)
86                 return;
87
88         in_end += socket.read(in_end, in_buf+buf_size-in_end);
89         try
90         {
91                 bool more = true;
92                 while(more)
93                 {
94                         if(handshake_status==2)
95                         {
96                                 more = receive_packet(protocol, receiver);
97                         }
98                         else
99                         {
100                                 HandshakeProtocol hsproto;
101                                 HandshakeReceiver hsrecv;
102                                 if((more = receive_packet(hsproto, hsrecv)))
103                                 {
104                                         if(hsrecv.get_hash()==protocol.get_hash())
105                                         {
106                                                 if(handshake_status==0)
107                                                         send_handshake();
108                                                 handshake_status = 2;
109                                                 signal_handshake_done.emit();
110                                         }
111                                         else
112                                                 good = false;
113                                 }
114                         }
115                 }
116         }
117         catch(...)
118         {
119                 good = false;
120                 throw;
121         }
122 }
123
124 bool Communicator::receive_packet(const Protocol &proto, ReceiverBase &recv)
125 {
126         int psz = proto.get_packet_size(in_begin, in_end-in_begin);
127         if(psz && psz<=in_end-in_begin)
128         {
129                 char *pkt = in_begin;
130                 in_begin += psz;
131                 proto.disassemble(recv, pkt, psz);
132                 return true;
133         }
134         else
135         {
136                 if(in_end==in_buf+buf_size)
137                 {
138                         unsigned used = in_end-in_begin;
139                         memmove(in_buf, in_begin, used);
140                         in_begin = in_buf;
141                         in_end = in_begin+used;
142                 }
143                 return false;
144         }
145 }
146
147 void Communicator::send_handshake()
148 {
149         Handshake shake;
150         shake.hash = protocol.get_hash();
151
152         HandshakeProtocol hsproto;
153         unsigned size = hsproto.assemble(shake, out_buf, buf_size);
154         socket.write(out_buf, size);
155 }
156
157 } // namespace Net
158 } // namespace Msp