]> git.lizzy.rs Git - minetest.git/blob - src/unittest/test_connection.cpp
8x block meshes (#13133)
[minetest.git] / src / unittest / test_connection.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "test.h"
21
22 #include "log.h"
23 #include "porting.h"
24 #include "settings.h"
25 #include "util/serialize.h"
26 #include "network/connection.h"
27 #include "network/networkpacket.h"
28 #include "network/socket.h"
29
30 class TestConnection : public TestBase {
31 public:
32         TestConnection()
33         {
34                 if (INTERNET_SIMULATOR == false)
35                         TestManager::registerTestModule(this);
36         }
37
38         const char *getName() { return "TestConnection"; }
39
40         void runTests(IGameDef *gamedef);
41
42         void testNetworkPacketSerialize();
43         void testHelpers();
44         void testConnectSendReceive();
45 };
46
47 static TestConnection g_test_instance;
48
49 void TestConnection::runTests(IGameDef *gamedef)
50 {
51         TEST(testNetworkPacketSerialize);
52         TEST(testHelpers);
53         TEST(testConnectSendReceive);
54 }
55
56 ////////////////////////////////////////////////////////////////////////////////
57
58 struct Handler : public con::PeerHandler
59 {
60         Handler(const char *a_name) : name(a_name) {}
61
62         void peerAdded(con::Peer *peer)
63         {
64                 infostream << "Handler(" << name << ")::peerAdded(): "
65                         "id=" << peer->id << std::endl;
66                 last_id = peer->id;
67                 count++;
68         }
69
70         void deletingPeer(con::Peer *peer, bool timeout)
71         {
72                 infostream << "Handler(" << name << ")::deletingPeer(): "
73                         "id=" << peer->id << ", timeout=" << timeout << std::endl;
74                 last_id = peer->id;
75                 count--;
76         }
77
78         s32 count = 0;
79         u16 last_id = 0;
80         const char *name;
81 };
82
83 void TestConnection::testNetworkPacketSerialize()
84 {
85         const static u8 expected[] = {
86                 0x00, 0x7b,
87                 0x00, 0x02, 0xd8, 0x42, 0xdf, 0x9a
88         };
89
90         if (sizeof(wchar_t) == 2)
91                 warningstream << __FUNCTION__ << " may fail on this platform." << std::endl;
92
93         {
94                 NetworkPacket pkt(123, 0);
95
96                 // serializing wide strings should do surrogate encoding, we test that here
97                 pkt << std::wstring(L"\U00020b9a");
98
99                 auto buf = pkt.oldForgePacket();
100                 UASSERTEQ(int, buf.getSize(), sizeof(expected));
101                 UASSERT(!memcmp(expected, &buf[0], buf.getSize()));
102         }
103
104         {
105                 NetworkPacket pkt;
106                 pkt.putRawPacket(expected, sizeof(expected), 0);
107
108                 // same for decoding
109                 std::wstring pkt_s;
110                 pkt >> pkt_s;
111
112                 UASSERT(pkt_s == L"\U00020b9a");
113         }
114 }
115
116 void TestConnection::testHelpers()
117 {
118         // Some constants for testing
119         u32 proto_id = 0x12345678;
120         session_t peer_id = 123;
121         u8 channel = 2;
122         SharedBuffer<u8> data1(1);
123         data1[0] = 100;
124         Address a(127,0,0,1, 10);
125         const u16 seqnum = 34352;
126
127         con::BufferedPacketPtr p1 = con::makePacket(a, data1,
128                         proto_id, peer_id, channel);
129         /*
130                 We should now have a packet with this data:
131                 Header:
132                         [0] u32 protocol_id
133                         [4] session_t sender_peer_id
134                         [6] u8 channel
135                 Data:
136                         [7] u8 data1[0]
137         */
138         UASSERT(readU32(&p1->data[0]) == proto_id);
139         UASSERT(readU16(&p1->data[4]) == peer_id);
140         UASSERT(readU8(&p1->data[6]) == channel);
141         UASSERT(readU8(&p1->data[7]) == data1[0]);
142
143         //infostream<<"initial data1[0]="<<((u32)data1[0]&0xff)<<std::endl;
144
145         SharedBuffer<u8> p2 = con::makeReliablePacket(data1, seqnum);
146
147         /*infostream<<"p2.getSize()="<<p2.getSize()<<", data1.getSize()="
148                         <<data1.getSize()<<std::endl;
149         infostream<<"readU8(&p2[3])="<<readU8(&p2[3])
150                         <<" p2[3]="<<((u32)p2[3]&0xff)<<std::endl;
151         infostream<<"data1[0]="<<((u32)data1[0]&0xff)<<std::endl;*/
152
153         UASSERT(p2.getSize() == 3 + data1.getSize());
154         UASSERT(readU8(&p2[0]) == con::PACKET_TYPE_RELIABLE);
155         UASSERT(readU16(&p2[1]) == seqnum);
156         UASSERT(readU8(&p2[3]) == data1[0]);
157 }
158
159
160 void TestConnection::testConnectSendReceive()
161 {
162         /*
163                 Test some real connections
164
165                 NOTE: This mostly tests the legacy interface.
166         */
167
168         u32 proto_id = 0xad26846a;
169
170         Handler hand_server("server");
171         Handler hand_client("client");
172
173         Address address(0, 0, 0, 0, 30001);
174         Address bind_addr(0, 0, 0, 0, 30001);
175         /*
176          * Try to use the bind_address for servers with no localhost address
177          * For example: FreeBSD jails
178          */
179         std::string bind_str = g_settings->get("bind_address");
180         try {
181                 bind_addr.Resolve(bind_str.c_str());
182
183                 if (!bind_addr.isIPv6()) {
184                         address = bind_addr;
185                 }
186         } catch (ResolveError &e) {
187         }
188
189         infostream << "** Creating server Connection" << std::endl;
190         con::Connection server(proto_id, 512, 5.0, false, &hand_server);
191         server.Serve(address);
192
193         infostream << "** Creating client Connection" << std::endl;
194         con::Connection client(proto_id, 512, 5.0, false, &hand_client);
195
196         UASSERT(hand_server.count == 0);
197         UASSERT(hand_client.count == 0);
198
199         sleep_ms(50);
200
201         Address server_address(127, 0, 0, 1, 30001);
202         if (address != Address(0, 0, 0, 0, 30001)) {
203                 server_address = bind_addr;
204         }
205
206         infostream << "** running client.Connect()" << std::endl;
207         client.Connect(server_address);
208
209         sleep_ms(50);
210
211         // Client should not have added client yet
212         UASSERT(hand_client.count == 0);
213
214         try {
215                 NetworkPacket pkt;
216                 infostream << "** running client.Receive()" << std::endl;
217                 client.Receive(&pkt);
218                 infostream << "** Client received: peer_id=" << pkt.getPeerId()
219                         << ", size=" << pkt.getSize() << std::endl;
220         } catch (con::NoIncomingDataException &e) {
221         }
222
223         // Client should have added server now
224         UASSERT(hand_client.count == 1);
225         UASSERT(hand_client.last_id == 1);
226         // Server should not have added client yet
227         UASSERT(hand_server.count == 0);
228
229         sleep_ms(100);
230
231         try {
232                 NetworkPacket pkt;
233                 infostream << "** running server.Receive()" << std::endl;
234                 server.Receive(&pkt);
235                 infostream << "** Server received: peer_id=" << pkt.getPeerId()
236                                 << ", size=" << pkt.getSize()
237                                 << std::endl;
238         } catch (con::NoIncomingDataException &e) {
239                 // No actual data received, but the client has
240                 // probably been connected
241         }
242
243         // Client should be the same
244         UASSERT(hand_client.count == 1);
245         UASSERT(hand_client.last_id == 1);
246         // Server should have the client
247         UASSERT(hand_server.count == 1);
248         UASSERT(hand_server.last_id == 2);
249
250         //sleep_ms(50);
251
252         while (client.Connected() == false) {
253                 try {
254                         NetworkPacket pkt;
255                         infostream << "** running client.Receive()" << std::endl;
256                         client.Receive(&pkt);
257                         infostream << "** Client received: peer_id=" << pkt.getPeerId()
258                                 << ", size=" << pkt.getSize() << std::endl;
259                 } catch (con::NoIncomingDataException &e) {
260                 }
261                 sleep_ms(50);
262         }
263
264         sleep_ms(50);
265
266         try {
267                 NetworkPacket pkt;
268                 infostream << "** running server.Receive()" << std::endl;
269                 server.Receive(&pkt);
270                 infostream << "** Server received: peer_id=" << pkt.getPeerId()
271                                 << ", size=" << pkt.getSize()
272                                 << std::endl;
273         } catch (con::NoIncomingDataException &e) {
274         }
275
276         /*
277                 Simple send-receive test
278         */
279         {
280                 NetworkPacket pkt;
281                 pkt.putRawPacket((u8*) "Hello World !", 14, 0);
282
283                 auto sentdata = pkt.oldForgePacket();
284
285                 infostream<<"** running client.Send()"<<std::endl;
286                 client.Send(PEER_ID_SERVER, 0, &pkt, true);
287
288                 sleep_ms(50);
289
290                 NetworkPacket recvpacket;
291                 infostream << "** running server.Receive()" << std::endl;
292                 server.Receive(&recvpacket);
293                 infostream << "** Server received: peer_id=" << pkt.getPeerId()
294                                 << ", size=" << pkt.getSize()
295                                 << ", data=" << (const char*)pkt.getU8Ptr(0)
296                                 << std::endl;
297
298                 auto recvdata = pkt.oldForgePacket();
299
300                 UASSERT(memcmp(*sentdata, *recvdata, recvdata.getSize()) == 0);
301         }
302
303         session_t peer_id_client = 2;
304         /*
305                 Send a large packet
306         */
307         {
308                 const int datasize = 30000;
309                 NetworkPacket pkt(0, datasize);
310                 for (u16 i=0; i<datasize; i++) {
311                         pkt << (u8) i/4;
312                 }
313
314                 infostream << "Sending data (size=" << datasize << "):";
315                 for (int i = 0; i < datasize && i < 20; i++) {
316                         if (i % 2 == 0)
317                                 infostream << " ";
318                         char buf[10];
319                         porting::mt_snprintf(buf, sizeof(buf), "%.2X",
320                                 ((int)((const char *)pkt.getU8Ptr(0))[i]) & 0xff);
321                         infostream<<buf;
322                 }
323                 if (datasize > 20)
324                         infostream << "...";
325                 infostream << std::endl;
326
327                 auto sentdata = pkt.oldForgePacket();
328
329                 server.Send(peer_id_client, 0, &pkt, true);
330
331                 //sleep_ms(3000);
332
333                 Buffer<u8> recvdata;
334                 infostream << "** running client.Receive()" << std::endl;
335                 session_t peer_id = 132;
336                 u16 size = 0;
337                 bool received = false;
338                 u64 timems0 = porting::getTimeMs();
339                 for (;;) {
340                         if (porting::getTimeMs() - timems0 > 5000 || received)
341                                 break;
342                         try {
343                                 NetworkPacket pkt;
344                                 client.Receive(&pkt);
345                                 size = pkt.getSize();
346                                 peer_id = pkt.getPeerId();
347                                 recvdata = pkt.oldForgePacket();
348                                 received = true;
349                         } catch (con::NoIncomingDataException &e) {
350                         }
351                         sleep_ms(10);
352                 }
353                 UASSERT(received);
354                 infostream << "** Client received: peer_id=" << peer_id
355                         << ", size=" << size << std::endl;
356
357                 infostream << "Received data (size=" << size << "): ";
358                 for (int i = 0; i < size && i < 20; i++) {
359                         if (i % 2 == 0)
360                                 infostream << " ";
361                         char buf[10];
362                         porting::mt_snprintf(buf, sizeof(buf), "%.2X", ((int)(recvdata[i])) & 0xff);
363                         infostream << buf;
364                 }
365                 if (size > 20)
366                         infostream << "...";
367                 infostream << std::endl;
368
369                 UASSERT(memcmp(*sentdata, *recvdata, recvdata.getSize()) == 0);
370                 UASSERT(peer_id == PEER_ID_SERVER);
371         }
372
373         // Check peer handlers
374         UASSERT(hand_client.count == 1);
375         UASSERT(hand_client.last_id == 1);
376         UASSERT(hand_server.count == 1);
377         UASSERT(hand_server.last_id == 2);
378 }