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