/* Minetest Copyright (C) 2013 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "test.h" #include "log.h" #include "porting.h" #include "settings.h" #include "util/serialize.h" #include "network/connection.h" #include "network/networkpacket.h" #include "network/socket.h" class TestConnection : public TestBase { public: TestConnection() { if (INTERNET_SIMULATOR == false) TestManager::registerTestModule(this); } const char *getName() { return "TestConnection"; } void runTests(IGameDef *gamedef); void testNetworkPacketSerialize(); void testHelpers(); void testConnectSendReceive(); }; static TestConnection g_test_instance; void TestConnection::runTests(IGameDef *gamedef) { TEST(testNetworkPacketSerialize); TEST(testHelpers); TEST(testConnectSendReceive); } //////////////////////////////////////////////////////////////////////////////// struct Handler : public con::PeerHandler { Handler(const char *a_name) : name(a_name) {} void peerAdded(con::Peer *peer) { infostream << "Handler(" << name << ")::peerAdded(): " "id=" << peer->id << std::endl; last_id = peer->id; count++; } void deletingPeer(con::Peer *peer, bool timeout) { infostream << "Handler(" << name << ")::deletingPeer(): " "id=" << peer->id << ", timeout=" << timeout << std::endl; last_id = peer->id; count--; } s32 count = 0; u16 last_id = 0; const char *name; }; void TestConnection::testNetworkPacketSerialize() { const static u8 expected[] = { 0x00, 0x7b, 0x00, 0x02, 0xd8, 0x42, 0xdf, 0x9a }; if (sizeof(wchar_t) == 2) warningstream << __FUNCTION__ << " may fail on this platform." << std::endl; { NetworkPacket pkt(123, 0); // serializing wide strings should do surrogate encoding, we test that here pkt << std::wstring(L"\U00020b9a"); auto buf = pkt.oldForgePacket(); UASSERTEQ(int, buf.getSize(), sizeof(expected)); UASSERT(!memcmp(expected, &buf[0], buf.getSize())); } { NetworkPacket pkt; pkt.putRawPacket(expected, sizeof(expected), 0); // same for decoding std::wstring pkt_s; pkt >> pkt_s; UASSERT(pkt_s == L"\U00020b9a"); } } void TestConnection::testHelpers() { // Some constants for testing u32 proto_id = 0x12345678; session_t peer_id = 123; u8 channel = 2; SharedBuffer data1(1); data1[0] = 100; Address a(127,0,0,1, 10); const u16 seqnum = 34352; con::BufferedPacketPtr p1 = con::makePacket(a, data1, proto_id, peer_id, channel); /* We should now have a packet with this data: Header: [0] u32 protocol_id [4] session_t sender_peer_id [6] u8 channel Data: [7] u8 data1[0] */ UASSERT(readU32(&p1->data[0]) == proto_id); UASSERT(readU16(&p1->data[4]) == peer_id); UASSERT(readU8(&p1->data[6]) == channel); UASSERT(readU8(&p1->data[7]) == data1[0]); //infostream<<"initial data1[0]="<<((u32)data1[0]&0xff)< p2 = con::makeReliablePacket(data1, seqnum); /*infostream<<"p2.getSize()="<get("bind_address"); try { bind_addr.Resolve(bind_str.c_str()); if (!bind_addr.isIPv6()) { address = bind_addr; } } catch (ResolveError &e) { } infostream << "** Creating server Connection" << std::endl; con::Connection server(proto_id, 512, 5.0, false, &hand_server); server.Serve(address); infostream << "** Creating client Connection" << std::endl; con::Connection client(proto_id, 512, 5.0, false, &hand_client); UASSERT(hand_server.count == 0); UASSERT(hand_client.count == 0); sleep_ms(50); Address server_address(127, 0, 0, 1, 30001); if (address != Address(0, 0, 0, 0, 30001)) { server_address = bind_addr; } infostream << "** running client.Connect()" << std::endl; client.Connect(server_address); sleep_ms(50); // Client should not have added client yet UASSERT(hand_client.count == 0); try { NetworkPacket pkt; infostream << "** running client.Receive()" << std::endl; client.Receive(&pkt); infostream << "** Client received: peer_id=" << pkt.getPeerId() << ", size=" << pkt.getSize() << std::endl; } catch (con::NoIncomingDataException &e) { } // Client should have added server now UASSERT(hand_client.count == 1); UASSERT(hand_client.last_id == 1); // Server should not have added client yet UASSERT(hand_server.count == 0); sleep_ms(100); try { NetworkPacket pkt; infostream << "** running server.Receive()" << std::endl; server.Receive(&pkt); infostream << "** Server received: peer_id=" << pkt.getPeerId() << ", size=" << pkt.getSize() << std::endl; } catch (con::NoIncomingDataException &e) { // No actual data received, but the client has // probably been connected } // Client should be the same UASSERT(hand_client.count == 1); UASSERT(hand_client.last_id == 1); // Server should have the client UASSERT(hand_server.count == 1); UASSERT(hand_server.last_id == 2); //sleep_ms(50); while (client.Connected() == false) { try { NetworkPacket pkt; infostream << "** running client.Receive()" << std::endl; client.Receive(&pkt); infostream << "** Client received: peer_id=" << pkt.getPeerId() << ", size=" << pkt.getSize() << std::endl; } catch (con::NoIncomingDataException &e) { } sleep_ms(50); } sleep_ms(50); try { NetworkPacket pkt; infostream << "** running server.Receive()" << std::endl; server.Receive(&pkt); infostream << "** Server received: peer_id=" << pkt.getPeerId() << ", size=" << pkt.getSize() << std::endl; } catch (con::NoIncomingDataException &e) { } /* Simple send-receive test */ { NetworkPacket pkt; pkt.putRawPacket((u8*) "Hello World !", 14, 0); auto sentdata = pkt.oldForgePacket(); infostream<<"** running client.Send()"< 20) infostream << "..."; infostream << std::endl; auto sentdata = pkt.oldForgePacket(); server.Send(peer_id_client, 0, &pkt, true); //sleep_ms(3000); Buffer recvdata; infostream << "** running client.Receive()" << std::endl; session_t peer_id = 132; u16 size = 0; bool received = false; u64 timems0 = porting::getTimeMs(); for (;;) { if (porting::getTimeMs() - timems0 > 5000 || received) break; try { NetworkPacket pkt; client.Receive(&pkt); size = pkt.getSize(); peer_id = pkt.getPeerId(); recvdata = pkt.oldForgePacket(); received = true; } catch (con::NoIncomingDataException &e) { } sleep_ms(10); } UASSERT(received); infostream << "** Client received: peer_id=" << peer_id << ", size=" << size << std::endl; infostream << "Received data (size=" << size << "): "; for (int i = 0; i < size && i < 20; i++) { if (i % 2 == 0) infostream << " "; char buf[10]; porting::mt_snprintf(buf, sizeof(buf), "%.2X", ((int)(recvdata[i])) & 0xff); infostream << buf; } if (size > 20) infostream << "..."; infostream << std::endl; UASSERT(memcmp(*sentdata, *recvdata, recvdata.getSize()) == 0); UASSERT(peer_id == PEER_ID_SERVER); } // Check peer handlers UASSERT(hand_client.count == 1); UASSERT(hand_client.last_id == 1); UASSERT(hand_server.count == 1); UASSERT(hand_server.last_id == 2); }