1 // _________ __ __
2 // / _____// |_____________ _/ |______ ____ __ __ ______
3 // \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
4 // / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
5 // /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
6 // \/ \/ \//_____/ \/
7 // ______________________ ______________________
8 // T H E W A R B E G I N S
9 // Stratagus - A free fantasy real time strategy game engine
10 //
11 /**@name test_net_lowlevel.cpp - The test file for net_lowlevel.cpp. */
12 //
13 // (c) Copyright 2013 by Joris Dauphin
14 //
15 // This program is free software; you can redistribute it and/or modify
16 // it under the terms of the GNU General Public License as published by
17 // the Free Software Foundation; only version 2 of the License.
18 //
19 // This program is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 // GNU General Public License for more details.
23 //
24 // You should have received a copy of the GNU General Public License
25 // along with this program; if not, write to the Free Software
26 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 // 02111-1307, USA.
28 //
29
30 #include <UnitTest++.h>
31
32 #include "stratagus.h"
33 #include "net_lowlevel.h"
34 #include <stdio.h>
35 #include <pthread.h>
36 #include <unistd.h>
37
38 class AutoNetwork
39 {
40 public:
AutoNetwork()41 AutoNetwork() { NetInit(); }
~AutoNetwork()42 ~AutoNetwork() { NetExit(); }
43 };
44
TEST_FIXTURE(AutoNetwork,NetResolveHost)45 TEST_FIXTURE(AutoNetwork, NetResolveHost)
46 {
47 const unsigned long localhost = htonl(0x7F000001); // 127.0.0.1
48
49 CHECK_EQUAL(localhost, NetResolveHost("127.0.0.1"));
50 CHECK_EQUAL(localhost, NetResolveHost("localhost"));
51 }
52
53 class Job
54 {
55 public:
~Job()56 virtual ~Job() {}
57
Run()58 void Run() { pthread_create(&tid, NULL, Job::ThreadRun, this); }
Wait()59 void Wait() { pthread_join(tid, NULL); }
60
61 private:
62 virtual void DoJob() = 0;
63
ThreadRun(void * data)64 static void *ThreadRun(void *data)
65 {
66 Job *that = reinterpret_cast<Job*>(data);
67 that->DoJob();
68 return NULL;
69 }
70
71 private:
72 pthread_t tid;
73 };
74
GetMyIP()75 static unsigned long GetMyIP()
76 {
77 char buf[128];
78
79 gethostname(buf, sizeof(buf));
80 //DebugPrint("%s\n" _C_ buf);
81 return NetResolveHost(buf);
82 }
83
84 template<typename T>
TCPWrite(Socket socket,const T & obj)85 void TCPWrite(Socket socket, const T &obj)
86 {
87 const char *buf = reinterpret_cast<const char *>(&obj);
88 size_t s = 0;
89 while (s != sizeof(T)) {
90 s += NetSendTCP(socket, buf + s, sizeof(T) - s);
91 }
92 }
93
94 template<typename T>
TCPRead(Socket socket,T * obj)95 void TCPRead(Socket socket, T *obj)
96 {
97 char *buf = reinterpret_cast<char *>(obj);
98 size_t s = 0;
99 while (s != sizeof(T)) {
100 s += NetRecvTCP(socket, buf + s, sizeof(T) - s);
101 }
102 }
103
104 class ServerTCP
105 {
106 public:
ServerTCP(int port)107 explicit ServerTCP(int port) { socket = NetOpenTCP(NULL, port); }
~ServerTCP()108 ~ServerTCP() { NetCloseTCP(socket); }
109
Listen()110 bool Listen() { return NetListenTCP(socket) != -1; }
Accept()111 void Accept() { clientSocket = NetAcceptTCP(socket, &clientHost, &clientPort); }
112
113 template <typename T>
Write(const T & obj)114 void Write(const T &obj) { TCPWrite(clientSocket, obj); }
115
GetClientHost() const116 unsigned long GetClientHost() const { return clientHost; }
GetClientPort() const117 int GetClientPort() const { return clientPort; }
118
119 private:
120 Socket socket;
121 Socket clientSocket;
122 unsigned long clientHost;
123 int clientPort;
124 };
125
126 class ClientTCP
127 {
128 public:
ClientTCP(int port)129 explicit ClientTCP(int port) { socket = NetOpenTCP(NULL, port); }
~ClientTCP()130 ~ClientTCP() { NetCloseTCP(socket); }
131
Connect(const char * host,int port)132 bool Connect(const char *host, int port) { return NetConnectTCP(socket, NetResolveHost(host), port) != -1; }
133
134 template <typename T>
Read(T * obj)135 void Read(T *obj) { TCPRead(socket, obj); }
136
137 private:
138 Socket socket;
139 };
140
141 class Foo
142 {
143 public:
Foo()144 Foo() { memset(&data, 0, sizeof(data)); }
145
Fill()146 void Fill()
147 {
148 for (int i = 0; i != 42; ++i) {
149 data[i] = i;
150 }
151 }
152
Check() const153 bool Check() const
154 {
155 for (int i = 0; i != 42; ++i) {
156 if (data[i] != i) {
157 return false;
158 }
159 }
160 return true;
161 }
162 public:
163 char data[42];
164 };
165
166 class ReceiverTCPJob : public Job
167 {
168 public:
ReceiverTCPJob(ClientTCP & client)169 explicit ReceiverTCPJob(ClientTCP& client) : client(&client), check(false) {}
170
Check() const171 bool Check() const { return check; }
172 private:
173
DoJob()174 virtual void DoJob()
175 {
176 Foo foo;
177
178 client->Read(&foo);
179 check = foo.Check();
180 }
181 private:
182 ClientTCP *client;
183 bool check;
184 };
185
186 class SenderTCPJob : public Job
187 {
188 public:
SenderTCPJob(ServerTCP & server)189 explicit SenderTCPJob(ServerTCP& server) : server(&server) {}
190
191 private:
DoJob()192 virtual void DoJob()
193 {
194 server->Listen();
195 server->Accept();
196
197 Foo foo;
198
199 foo.Fill();
200 server->Write(foo);
201 }
202 private:
203 ServerTCP *server;
204 };
205
TEST_FIXTURE(AutoNetwork,ExchangeTCP)206 TEST_FIXTURE(AutoNetwork, ExchangeTCP)
207 {
208 const int serverPort = 6500;
209 const int clientPort = 6501;
210
211 ServerTCP server(serverPort);
212 SenderTCPJob sender(server);
213 sender.Run();
214
215 ClientTCP client(clientPort);
216 client.Connect("localhost", serverPort);
217 ReceiverTCPJob receiver(client);
218 receiver.Run();
219
220 receiver.Wait();
221 sender.Wait();
222 CHECK(receiver.Check());
223 CHECK_EQUAL(clientPort, htons(server.GetClientPort()));
224 const unsigned long localhost = 0x7F000001; // 127.0.0.1
225
226 CHECK(GetMyIP() == ntohl(server.GetClientHost())
227 || localhost == ntohl(server.GetClientHost()));
228 }
229
230 template<typename T>
UDPWrite(Socket socket,const char * hostname,int port,const T & obj)231 void UDPWrite(Socket socket, const char *hostname, int port, const T &obj)
232 {
233 const long host = NetResolveHost(hostname);
234 const char *buf = reinterpret_cast<const char *>(&obj);
235 port = htons(port);
236 NetSendUDP(socket, host, port, buf, sizeof(T));
237 }
238
239 template<typename T>
UDPRead(Socket socket,T * obj,unsigned long * hostFrom,int * portFrom)240 void UDPRead(Socket socket, T *obj, unsigned long *hostFrom, int *portFrom)
241 {
242 char *buf = reinterpret_cast<char *>(obj);
243 size_t s = 0;
244 while (s != sizeof(T)) {
245 s += NetRecvUDP(socket, buf + s, sizeof(T) - s, hostFrom, portFrom);
246 }
247 }
248
249 class ClientUDP
250 {
251 public:
ClientUDP(int port)252 explicit ClientUDP(int port) { socket = NetOpenUDP(htonl(0x7F000001), htons(port)); }
~ClientUDP()253 ~ClientUDP() { NetCloseUDP(socket); }
254
255 template <typename T>
Read(T * obj)256 void Read(T *obj) { UDPRead(socket, obj, &hostFrom, &portFrom); }
257
258 template <typename T>
Write(const char * hostname,long port,const T & obj)259 void Write(const char *hostname, long port, const T &obj) { UDPWrite(socket, hostname, port, obj); }
260
GetHostFrom() const261 unsigned long GetHostFrom() const { return hostFrom; }
GetPortFrom() const262 int GetPortFrom() const { return portFrom; }
263
264 private:
265 Socket socket;
266 unsigned long hostFrom;
267 int portFrom;
268 };
269
270 class ReceiverUDPJob : public Job
271 {
272 public:
ReceiverUDPJob(ClientUDP & client)273 explicit ReceiverUDPJob(ClientUDP& client) : client(&client), check(false) {}
274
Check() const275 bool Check() const { return check; }
276 private:
277
DoJob()278 virtual void DoJob()
279 {
280 Foo foo;
281
282 client->Read(&foo);
283 check = foo.Check();
284 }
285 private:
286 ClientUDP *client;
287 bool check;
288 };
289
290 class SenderUDPJob : public Job
291 {
292 public:
SenderUDPJob(ClientUDP & client,const char * hostname,int port)293 explicit SenderUDPJob(ClientUDP& client, const char *hostname, int port) :
294 client(&client),
295 hostname(hostname),
296 port(port)
297 {}
298
299 private:
DoJob()300 virtual void DoJob()
301 {
302 Foo foo;
303
304 foo.Fill();
305 client->Write(hostname, port, foo);
306 }
307 private:
308 ClientUDP *client;
309 const char *hostname;
310 long port;
311 };
312
TEST_FIXTURE(AutoNetwork,ExchangeUDP)313 TEST_FIXTURE(AutoNetwork, ExchangeUDP)
314 {
315 const int receiverPort = 6501;
316 const int senderPort = 6500;
317
318 ClientUDP client(receiverPort);
319 ReceiverUDPJob receiver(client);
320 receiver.Run();
321
322 ClientUDP server(senderPort);
323 SenderUDPJob sender(server, "localhost", receiverPort);
324 sender.Run();
325
326 receiver.Wait();
327 sender.Wait();
328 CHECK(receiver.Check());
329 CHECK_EQUAL(senderPort, htons(client.GetPortFrom()));
330 const unsigned long localhost = 0x7F000001; // 127.0.0.1
331
332 CHECK(GetMyIP() == ntohl(client.GetHostFrom())
333 || localhost == ntohl(client.GetHostFrom()));
334 }
335