]> git.tdb.fi Git - libs/net.git/blob - source/communicator.cpp
Fix a comparison operator on win32
[libs/net.git] / source / communicator.cpp
1 /* $Id$
2
3 This file is part of libmspnet
4 Copyright © 2009  Mikkosoft Productions, Mikko Rasa
5 Distributed under the LGPL
6 */
7
8 #include <cstring>
9 #include "communicator.h"
10
11 namespace {
12
13 using namespace Msp::Net;
14
15 struct Handshake
16 {
17         unsigned hash;
18 };
19
20
21 class HandshakeProtocol: public Protocol
22 {
23 public:
24         HandshakeProtocol();
25 };
26
27 HandshakeProtocol::HandshakeProtocol():
28         Protocol(0x7F00)
29 {
30         add<Handshake>()(&Handshake::hash);
31 }
32
33
34 class HandshakeReceiver: public PacketReceiver<Handshake>
35 {
36 private:
37         unsigned hash;
38
39 public:
40         HandshakeReceiver();
41         unsigned get_hash() const { return hash; }
42         virtual void receive(const Handshake &);
43 };
44
45 HandshakeReceiver::HandshakeReceiver():
46         hash(0)
47 { }
48
49 void HandshakeReceiver::receive(const Handshake &shake)
50 {
51         hash=shake.hash;
52 }
53
54 }
55
56
57 namespace Msp {
58 namespace Net {
59
60 Communicator::Communicator(StreamSocket &s, const Protocol &p, ReceiverBase &r):
61         socket(s),
62         protocol(p),
63         receiver(r),
64         handshake_status(0),
65         buf_size(1024),
66         in_buf(new char[buf_size]),
67         in_begin(in_buf),
68         in_end(in_buf),
69         out_buf(new char[buf_size])
70 {
71         socket.signal_data_available.connect(sigc::mem_fun(this, &Communicator::data_available));
72 }
73
74 Communicator::~Communicator()
75 {
76         delete[] in_buf;
77         delete[] out_buf;
78 }
79
80 void Communicator::initiate_handshake()
81 {
82         if(handshake_status!=0)
83                 throw InvalidState("Handshaking is already underway or done");
84
85         send_handshake();
86         handshake_status=1;
87 }
88
89 void Communicator::data_available()
90 {
91         in_end+=socket.read(in_end, in_buf+buf_size-in_end);
92         try
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                                                 socket.close();
116                                 }
117                         }
118                 }
119         }
120         catch(...)
121         {
122                 socket.close();
123                 throw;
124         }
125 }
126
127 bool Communicator::receive_packet(const Protocol &proto, ReceiverBase &recv)
128 {
129         int psz=proto.get_packet_size(in_begin, in_end-in_begin);
130         if(psz && psz<=in_end-in_begin)
131         {
132                 char *pkt=in_begin;
133                 in_begin+=psz;
134                 proto.disassemble(recv, pkt, psz);
135                 return true;
136         }
137         else
138         {
139                 if(in_end==in_buf+buf_size)
140                 {
141                         unsigned used=in_end-in_begin;
142                         memmove(in_buf, in_begin, used);
143                         in_begin=in_buf;
144                         in_end=in_begin+used;
145                 }
146                 return false;
147         }
148 }
149
150 void Communicator::send_handshake()
151 {
152         Handshake shake;
153         shake.hash=protocol.get_hash();
154
155         HandshakeProtocol hsproto;
156         unsigned size=hsproto.assemble(shake, out_buf, buf_size);
157         socket.write(out_buf, size);
158 }
159
160 } // namespace Net
161 } // namespace Msp