aboutsummaryrefslogtreecommitdiff
path: root/src/nameidmapping.cpp
Commit message (Collapse)AuthorAge
* (se)SerializeString: Include max length in the nameSmallJoker2020-10-01
| | | | | | | This commit clarifies the maximal length of the serialized strings. It will avoid accidental use of serializeString() when a larger string can be expected. Removes unused Wide String serialization functions
* Code modernization: src/n*, src/o* (#6280)Loïc Blot2017-08-19
| | | | | | | | | | | * Code modernization: src/n*, src/o* * empty function * default constructor/destructor * for range-based loops * use emplace_back instead of push_back * remove unused IWritableNodeDefManager::clone() * C++ STL header style * Pointer constness in some functions
* C++11 patchset 2: remove util/cpp11.h and util/cpp11_container.h (#5821)Loïc Blot2017-06-04
|
* Pass clang-format on various cpp/header files (#5559)Loïc Blot2017-04-23
|
* Permit usage of std::unordered_map & std::unorderered_set on c++11 compilers ↵Ner'zhul2016-08-10
| | | | | | | | | (#4430) This fallback to std::map & std::set for older compilers Use UNORDERED_SET as an example in decoration and ore biome sets Use UNORDERED_MAP as an example in nameidmapping
* Change i++ to ++iDavid Jones2015-08-25
|
* Omnicleanup: header cleanup, add ModApiUtil shared between game and mainmenuKahrl2013-08-14
|
* Update Copyright YearsSfan52013-02-24
|
* Change Minetest-c55 to MinetestPilzAdam2013-02-24
|
* Properly and efficiently use split utility headersPerttu Ahola2012-06-17
|
* Switch the license to be LGPLv2/later, with small parts still remaining as ↵Perttu Ahola2012-06-05
| | | | GPLv2/later, by agreement of major contributors
* Node definition namesPerttu Ahola2011-11-29
229'>229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
/*
Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>

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<u8> 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)<<std::endl;

	SharedBuffer<u8> p2 = con::makeReliablePacket(data1, seqnum);

	/*infostream<<"p2.getSize()="<<p2.getSize()<<", data1.getSize()="
			<<data1.getSize()<<std::endl;
	infostream<<"readU8(&p2[3])="<<readU8(&p2[3])
			<<" p2[3]="<<((u32)p2[3]&0xff)<<std::endl;
	infostream<<"data1[0]="<<((u32)data1[0]&0xff)<<std::endl;*/

	UASSERT(p2.getSize() == 3 + data1.getSize());
	UASSERT(readU8(&p2[0]) == con::PACKET_TYPE_RELIABLE);
	UASSERT(readU16(&p2[1]) == seqnum);
	UASSERT(readU8(&p2[3]) == data1[0]);
}


void TestConnection::testConnectSendReceive()
{
	/*
		Test some real connections

		NOTE: This mostly tests the legacy interface.
	*/

	u32 proto_id = 0xad26846a;

	Handler hand_server("server");
	Handler hand_client("client");

	Address address(0, 0, 0, 0, 30001);
	Address bind_addr(0, 0, 0, 0, 30001);
	/*
	 * Try to use the bind_address for servers with no localhost address
	 * For example: FreeBSD jails
	 */
	std::string bind_str = g_settings->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()"<<std::endl;
		client.Send(PEER_ID_SERVER, 0, &pkt, true);

		sleep_ms(50);

		NetworkPacket recvpacket;
		infostream << "** running server.Receive()" << std::endl;
		server.Receive(&recvpacket);
		infostream << "** Server received: peer_id=" << pkt.getPeerId()
				<< ", size=" << pkt.getSize()
				<< ", data=" << (const char*)pkt.getU8Ptr(0)
				<< std::endl;

		auto recvdata = pkt.oldForgePacket();

		UASSERT(memcmp(*sentdata, *recvdata, recvdata.getSize()) == 0);
	}

	session_t peer_id_client = 2;
	/*
		Send a large packet
	*/
	{
		const int datasize = 30000;
		NetworkPacket pkt(0, datasize);
		for (u16 i=0; i<datasize; i++) {
			pkt << (u8) i/4;
		}

		infostream << "Sending data (size=" << datasize << "):";
		for (int i = 0; i < datasize && i < 20; i++) {
			if (i % 2 == 0)
				infostream << " ";
			char buf[10];
			porting::mt_snprintf(buf, sizeof(buf), "%.2X",
				((int)((const char *)pkt.getU8Ptr(0))[i]) & 0xff);
			infostream<<buf;
		}
		if (datasize > 20)
			infostream << "...";
		infostream << std::endl;

		auto sentdata = pkt.oldForgePacket();

		server.Send(peer_id_client, 0, &pkt, true);

		//sleep_ms(3000);

		Buffer<u8> 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);
}