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