]> git.tdb.fi Git - libs/net.git/blob - source/communicator.cpp
Style update: spaces around assignments
[libs/net.git] / source / 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 {
64         socket.signal_data_available.connect(sigc::mem_fun(this, &Communicator::data_available));
65 }
66
67 Communicator::~Communicator()
68 {
69         delete[] in_buf;
70         delete[] out_buf;
71 }
72
73 void Communicator::initiate_handshake()
74 {
75         if(handshake_status!=0)
76                 throw InvalidState("Handshaking is already underway or done");
77
78         send_handshake();
79         handshake_status = 1;
80 }
81
82 void Communicator::data_available()
83 {
84         in_end += socket.read(in_end, in_buf+buf_size-in_end);
85         try
86         {
87                 bool more = true;
88                 while(more)
89                 {
90                         if(handshake_status==2)
91                         {
92                                 more = receive_packet(protocol, receiver);
93                         }
94                         else
95                         {
96                                 HandshakeProtocol hsproto;
97                                 HandshakeReceiver hsrecv;
98                                 if((more = receive_packet(hsproto, hsrecv)))
99                                 {
100                                         if(hsrecv.get_hash()==protocol.get_hash())
101                                         {
102                                                 if(handshake_status==0)
103                                                         send_handshake();
104                                                 handshake_status = 2;
105                                                 signal_handshake_done.emit();
106                                         }
107                                         else
108                                                 socket.close();
109                                 }
110                         }
111                 }
112         }
113         catch(...)
114         {
115                 socket.close();
116                 throw;
117         }
118 }
119
120 bool Communicator::receive_packet(const Protocol &proto, ReceiverBase &recv)
121 {
122         int psz = proto.get_packet_size(in_begin, in_end-in_begin);
123         if(psz && psz<=in_end-in_begin)
124         {
125                 char *pkt = in_begin;
126                 in_begin += psz;
127                 proto.disassemble(recv, pkt, psz);
128                 return true;
129         }
130         else
131         {
132                 if(in_end==in_buf+buf_size)
133                 {
134                         unsigned used = in_end-in_begin;
135                         memmove(in_buf, in_begin, used);
136                         in_begin = in_buf;
137                         in_end = in_begin+used;
138                 }
139                 return false;
140         }
141 }
142
143 void Communicator::send_handshake()
144 {
145         Handshake shake;
146         shake.hash = protocol.get_hash();
147
148         HandshakeProtocol hsproto;
149         unsigned size = hsproto.assemble(shake, out_buf, buf_size);
150         socket.write(out_buf, size);
151 }
152
153 } // namespace Net
154 } // namespace Msp