about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/base/system.c3
-rw-r--r--src/engine/client/client.cpp35
-rw-r--r--src/engine/client/serverbrowser.cpp27
-rw-r--r--src/engine/masterserver.h1
-rw-r--r--src/engine/server/register.cpp20
-rw-r--r--src/engine/shared/engine.cpp3
-rw-r--r--src/engine/shared/jobs.h1
-rw-r--r--src/engine/shared/masterserver.cpp42
-rw-r--r--src/engine/shared/network_server.cpp19
-rw-r--r--src/mastersrv/mastersrv.cpp97
-rw-r--r--src/mastersrv/mastersrv.h17
-rw-r--r--src/tools/crapnet.cpp13
-rw-r--r--src/tools/mastersrv_old.cpp449
-rw-r--r--src/tools/mastersrv_old.h28
14 files changed, 626 insertions, 129 deletions
diff --git a/src/base/system.c b/src/base/system.c
index ef3a38bf..e694f80e 100644
--- a/src/base/system.c
+++ b/src/base/system.c
@@ -593,7 +593,7 @@ static int priv_net_extract(const char *hostname, char *host, int max_host, int
 	if(hostname[0] == '[')
 	{
 		// ipv6 mode
-		for(i = 1; i < max_host-1 && hostname[i] && hostname[i] != ']'; i++)
+		for(i = 1; i < max_host && hostname[i] && hostname[i] != ']'; i++)
 			host[i-1] = hostname[i];
 		host[i-1] = 0;
 		if(hostname[i] != ']') // malformatted
@@ -711,6 +711,7 @@ int net_addr_from_str(NETADDR *addr, const char *string)
 		struct sockaddr_in6 sa6;
 		char buf[128];
 		int i;
+		str++;
 		for(i = 0; i < 127 && str[i] && str[i] != ']'; i++)
 			buf[i] = str[i];
 		buf[i] = 0;
diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp
index a39bfb5b..28c0fad4 100644
--- a/src/engine/client/client.cpp
+++ b/src/engine/client/client.cpp
@@ -698,7 +698,7 @@ void CClient::Connect(const char *pAddress)
 		char aBufMsg[256];
 		str_format(aBufMsg, sizeof(aBufMsg), "could not find the address of %s, connecting to localhost", aBuf);
 		m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "client", aBufMsg);
-		net_host_lookup("localhost", &m_ServerAddress, NETTYPE_IPV4);
+		net_host_lookup("localhost", &m_ServerAddress, NETTYPE_ALL);
 	}
 
 	m_RconAuthed = 0;
@@ -1052,34 +1052,31 @@ void CClient::ProcessConnlessPacket(CNetChunk *pPacket)
 		bool Valid = false;
 		for(int i = 0; i < IMasterServer::MAX_MASTERSERVERS; ++i)
 		{
-			NETADDR Addr = m_pMasterServer->GetAddr(i);
-			if(net_addr_comp(&pPacket->m_Address, &Addr) == 0)
+			if(m_pMasterServer->IsValid(i))
 			{
-				Valid = true;
-				break;
+				NETADDR Addr = m_pMasterServer->GetAddr(i);
+				if(net_addr_comp(&pPacket->m_Address, &Addr) == 0)
+				{
+					Valid = true;
+					break;
+				}
 			}
 		}
 		if(!Valid)
 			return;
 
 		int Size = pPacket->m_DataSize-sizeof(SERVERBROWSE_LIST);
-		int Num = Size/sizeof(MASTERSRV_ADDR);
-		MASTERSRV_ADDR *pAddrs = (MASTERSRV_ADDR *)((char*)pPacket->m_pData+sizeof(SERVERBROWSE_LIST));
-		int i;
-
-		for(i = 0; i < Num; i++)
+		int Num = Size/sizeof(CMastersrvAddr);
+		CMastersrvAddr *pAddrs = (CMastersrvAddr *)((char*)pPacket->m_pData+sizeof(SERVERBROWSE_LIST));
+		for(int i = 0; i < Num; i++)
 		{
 			NETADDR Addr;
 
-			// convert address
-			mem_zero(&Addr, sizeof(Addr));
-			Addr.type = NETTYPE_IPV4;
-			Addr.ip[0] = pAddrs[i].m_aIp[0];
-			Addr.ip[1] = pAddrs[i].m_aIp[1];
-			Addr.ip[2] = pAddrs[i].m_aIp[2];
-			Addr.ip[3] = pAddrs[i].m_aIp[3];
-			Addr.port = (pAddrs[i].m_aPort[1]<<8) | pAddrs[i].m_aPort[0];
-
+			// copy address
+			Addr.type = (pAddrs->m_aType[0]<<24) | (pAddrs->m_aType[1]<<16) | (pAddrs->m_aType[2]<<8) | pAddrs->m_aType[3];
+			mem_copy(Addr.ip, pAddrs->m_aIp, sizeof(Addr.ip));
+			Addr.port = (pAddrs->m_aPort[0]<<8) | pAddrs->m_aPort[1];
+			
 			m_ServerBrowser.Set(Addr, IServerBrowser::SET_MASTER_ADD, -1, 0x0);
 		}
 	}
diff --git a/src/engine/client/serverbrowser.cpp b/src/engine/client/serverbrowser.cpp
index 55d25f8a..36447922 100644
--- a/src/engine/client/serverbrowser.cpp
+++ b/src/engine/client/serverbrowser.cpp
@@ -380,15 +380,8 @@ CServerBrowser::CServerEntry *CServerBrowser::Add(const NETADDR &Addr)
 	pEntry->m_Info.m_NetAddr = Addr;
 
 	pEntry->m_Info.m_Latency = 999;
-	str_format(pEntry->m_Info.m_aAddress, sizeof(pEntry->m_Info.m_aAddress), "%d.%d.%d.%d:%d",
-		Addr.ip[0], Addr.ip[1], Addr.ip[2],
-		Addr.ip[3], Addr.port);
-	str_format(pEntry->m_Info.m_aName, sizeof(pEntry->m_Info.m_aName), "%d.%d.%d.%d:%d",
-		Addr.ip[0], Addr.ip[1], Addr.ip[2],
-		Addr.ip[3], Addr.port);
-
-	/*if(serverlist_type == IServerBrowser::TYPE_LAN)
-		pEntry->m_Info.latency = (time_get()-broadcast_time)*1000/time_freq();*/
+	net_addr_str(&Addr, pEntry->m_Info.m_aAddress, sizeof(pEntry->m_Info.m_aAddress));
+	str_copy(pEntry->m_Info.m_aName, pEntry->m_Info.m_aAddress, sizeof(pEntry->m_Info.m_aName));
 
 	// check if it's a favorite
 	for(i = 0; i < m_NumFavoriteServers; i++)
@@ -526,10 +519,10 @@ void CServerBrowser::RequestImpl(const NETADDR &Addr, CServerEntry *pEntry) cons
 
 	if(g_Config.m_Debug)
 	{
+		char aAddrStr[NETADDR_MAXSTRSIZE];
+		net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr));
 		char aBuf[256];
-		str_format(aBuf, sizeof(aBuf),"requesting server info from %d.%d.%d.%d:%d",
-			Addr.ip[0], Addr.ip[1], Addr.ip[2],
-			Addr.ip[3], Addr.port);
+		str_format(aBuf, sizeof(aBuf),"requesting server info from %s", aAddrStr);
 		m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", aBuf);
 	}
 
@@ -556,7 +549,7 @@ void CServerBrowser::Request(const NETADDR &Addr) const
 
 void CServerBrowser::Update(bool ForceResort)
 {
-	int64 Timeout = time_freq()/2;	// TODO 0.6: increase this again
+	int64 Timeout = time_freq();
 	int64 Now = time_get();
 	int Count;
 	CServerEntry *pEntry, *pNext;
@@ -578,10 +571,10 @@ void CServerBrowser::Update(bool ForceResort)
 
 		for(i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++)
 		{
-			Addr = m_pMasterServer->GetAddr(i);
-			if(!Addr.ip[0] && !Addr.ip[1] && !Addr.ip[2] && !Addr.ip[3])
+			if(!m_pMasterServer->IsValid(i))
 				continue;
 
+			Addr = m_pMasterServer->GetAddr(i);
 			Packet.m_Address = Addr;
 			m_pNetClient->Send(&Packet);
 		}
@@ -667,8 +660,10 @@ void CServerBrowser::AddFavorite(const NETADDR &Addr)
 
     if(g_Config.m_Debug)
 	{
+		char aAddrStr[NETADDR_MAXSTRSIZE];
+		net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr));
 		char aBuf[256];
-        str_format(aBuf, sizeof(aBuf), "added fav, %d.%d.%d.%d:%d", Addr.ip[0], Addr.ip[1], Addr.ip[2], Addr.ip[3], Addr.port);
+		str_format(aBuf, sizeof(aBuf), "added fav, %s", aAddrStr);
 		m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", aBuf);
 	}
 }
diff --git a/src/engine/masterserver.h b/src/engine/masterserver.h
index 1788a18d..98a9cf0a 100644
--- a/src/engine/masterserver.h
+++ b/src/engine/masterserver.h
@@ -26,6 +26,7 @@ public:
 	virtual void DumpServers() = 0;
 	virtual NETADDR GetAddr(int Index) = 0;
 	virtual const char *GetName(int Index) = 0;
+	virtual bool IsValid(int Index) = 0;
 };
 
 class IEngineMasterServer : public IMasterServer
diff --git a/src/engine/server/register.cpp b/src/engine/server/register.cpp
index 20c7d173..5f43e292 100644
--- a/src/engine/server/register.cpp
+++ b/src/engine/server/register.cpp
@@ -124,18 +124,18 @@ void CRegister::RegisterUpdate()
 			int i;
 			for(i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++)
 			{
-				NETADDR Addr = m_pMasterServer->GetAddr(i);
-				m_aMasterserverInfo[i].m_Addr = Addr;
-				m_aMasterserverInfo[i].m_Count = 0;
-			
-				if(!Addr.ip[0] && !Addr.ip[1] && !Addr.ip[2] && !Addr.ip[3])
-					m_aMasterserverInfo[i].m_Valid = 0;
-				else
+				if(!m_pMasterServer->IsValid(i))
 				{
-					m_aMasterserverInfo[i].m_Valid = 1;
-					m_aMasterserverInfo[i].m_Count = -1;
-					m_aMasterserverInfo[i].m_LastSend = 0;
+					m_aMasterserverInfo[i].m_Valid = 0;
+					m_aMasterserverInfo[i].m_Count = 0;
+					continue;
 				}
+
+				NETADDR Addr = m_pMasterServer->GetAddr(i);
+				m_aMasterserverInfo[i].m_Addr = Addr;
+				m_aMasterserverInfo[i].m_Valid = 1;
+				m_aMasterserverInfo[i].m_Count = -1;
+				m_aMasterserverInfo[i].m_LastSend = 0;
 			}
 			
 			m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "register", "fetching server counts");
diff --git a/src/engine/shared/engine.cpp b/src/engine/shared/engine.cpp
index 6839cc64..c7a1daad 100644
--- a/src/engine/shared/engine.cpp
+++ b/src/engine/shared/engine.cpp
@@ -13,8 +13,7 @@
 static int HostLookupThread(void *pUser)
 {
 	CHostLookup *pLookup = (CHostLookup *)pUser;
-	net_host_lookup(pLookup->m_aHostname, &pLookup->m_Addr, NETTYPE_IPV4);
-	return 0;
+	return net_host_lookup(pLookup->m_aHostname, &pLookup->m_Addr, NETTYPE_ALL);
 }
 
 class CEngine : public IEngine
diff --git a/src/engine/shared/jobs.h b/src/engine/shared/jobs.h
index 61835186..2b0d7d15 100644
--- a/src/engine/shared/jobs.h
+++ b/src/engine/shared/jobs.h
@@ -34,6 +34,7 @@ public:
 	};
 	
 	int Status() const { return m_Status; }
+	int Result() const {return m_Result; }
 };
 
 class CJobPool
diff --git a/src/engine/shared/masterserver.cpp b/src/engine/shared/masterserver.cpp
index 545cc16c..3037d152 100644
--- a/src/engine/shared/masterserver.cpp
+++ b/src/engine/shared/masterserver.cpp
@@ -18,6 +18,7 @@ public:
 	{
 		char m_aHostname[128];
 		NETADDR m_Addr;
+		bool m_Valid;
 		
 		CHostLookup m_Lookup;
 	} ;
@@ -44,8 +45,11 @@ public:
 		dbg_msg("engine/mastersrv", "refreshing master server addresses");
 
 		// add lookup jobs
-		for(i = 0; i < MAX_MASTERSERVERS; i++)	
+		for(i = 0; i < MAX_MASTERSERVERS; i++)
+		{
 			m_pEngine->HostLookup(&m_aMasterServers[i].m_Lookup, m_aMasterServers[i].m_aHostname);
+			m_aMasterServers[i].m_Valid = false;
+		}
 		
 		m_NeedsUpdate = 1;
 		return 0;
@@ -64,8 +68,14 @@ public:
 				m_NeedsUpdate = 1;
 			else
 			{
-				m_aMasterServers[i].m_Addr = m_aMasterServers[i].m_Lookup.m_Addr;
-				m_aMasterServers[i].m_Addr.port = 8300;
+				if(m_aMasterServers[i].m_Lookup.m_Job.Result() == 0)
+				{
+					m_aMasterServers[i].m_Addr = m_aMasterServers[i].m_Lookup.m_Addr;
+					m_aMasterServers[i].m_Addr.port = 8300;
+					m_aMasterServers[i].m_Valid = true;
+				}
+				else
+					m_aMasterServers[i].m_Valid = false;
 			}
 		}
 		
@@ -91,13 +101,18 @@ public:
 		return m_aMasterServers[Index].m_aHostname;
 	}
 
+	virtual bool IsValid(int Index)
+	{
+		return m_aMasterServers[Index].m_Valid;
+	}
+
 	virtual void DumpServers()
 	{
 		for(int i = 0; i < MAX_MASTERSERVERS; i++)
 		{
-			dbg_msg("mastersrv", "#%d = %d.%d.%d.%d", i,
-				m_aMasterServers[i].m_Addr.ip[0], m_aMasterServers[i].m_Addr.ip[1],
-				m_aMasterServers[i].m_Addr.ip[2], m_aMasterServers[i].m_Addr.ip[3]);
+			char aAddrStr[NETADDR_MAXSTRSIZE];
+			net_addr_str(&m_aMasterServers[i].m_Addr, aAddrStr, sizeof(aAddrStr));
+			dbg_msg("mastersrv", "#%d = %s", i, aAddrStr);
 		}
 	}
 
@@ -136,13 +151,10 @@ public:
 			if(!pLine)
 				break;
 
-			// parse line	
-			if(sscanf(pLine, "%s %d.%d.%d.%d", Info.m_aHostname, &aIp[0], &aIp[1], &aIp[2], &aIp[3]) == 5)
+			// parse line
+			char aAddrStr[NETADDR_MAXSTRSIZE];
+			if(sscanf(pLine, "%s %s", Info.m_aHostname, aAddrStr) == 2 && net_addr_from_str(&Info.m_Addr, aAddrStr) == 0)
 			{
-				Info.m_Addr.ip[0] = (unsigned char)aIp[0];
-				Info.m_Addr.ip[1] = (unsigned char)aIp[1];
-				Info.m_Addr.ip[2] = (unsigned char)aIp[2];
-				Info.m_Addr.ip[3] = (unsigned char)aIp[3];
 				Info.m_Addr.port = 8300;
 				if(Count != MAX_MASTERSERVERS)
 				{
@@ -174,10 +186,10 @@ public:
 
 		for(int i = 0; i < MAX_MASTERSERVERS; i++)
 		{
+			char aAddrStr[NETADDR_MAXSTRSIZE];
+			net_addr_str(&m_aMasterServers[i].m_Addr, aAddrStr, sizeof(aAddrStr));
 			char aBuf[1024];
-			str_format(aBuf, sizeof(aBuf), "%s %d.%d.%d.%d\n", m_aMasterServers[i].m_aHostname,
-				m_aMasterServers[i].m_Addr.ip[0], m_aMasterServers[i].m_Addr.ip[1],
-				m_aMasterServers[i].m_Addr.ip[2], m_aMasterServers[i].m_Addr.ip[3]);
+			str_format(aBuf, sizeof(aBuf), "%s %s\n", m_aMasterServers[i].m_aHostname, aAddrStr);
 				
 			io_write(File, aBuf, str_length(aBuf));
 		}
diff --git a/src/engine/shared/network_server.cpp b/src/engine/shared/network_server.cpp
index 88aac789..76d5f695 100644
--- a/src/engine/shared/network_server.cpp
+++ b/src/engine/shared/network_server.cpp
@@ -117,9 +117,13 @@ int CNetServer::BanNum()
 
 void CNetServer::BanRemoveByObject(CBan *pBan)
 {
-	int IpHash = (pBan->m_Info.m_Addr.ip[0]+pBan->m_Info.m_Addr.ip[1]+pBan->m_Info.m_Addr.ip[2]+pBan->m_Info.m_Addr.ip[3])&0xff;
-	dbg_msg("netserver", "removing ban on %d.%d.%d.%d",
-		pBan->m_Info.m_Addr.ip[0], pBan->m_Info.m_Addr.ip[1], pBan->m_Info.m_Addr.ip[2], pBan->m_Info.m_Addr.ip[3]);
+	int IpHash = (pBan->m_Info.m_Addr.ip[0]+pBan->m_Info.m_Addr.ip[1]+pBan->m_Info.m_Addr.ip[2]+pBan->m_Info.m_Addr.ip[3]+
+					pBan->m_Info.m_Addr.ip[4]+pBan->m_Info.m_Addr.ip[5]+pBan->m_Info.m_Addr.ip[6]+pBan->m_Info.m_Addr.ip[7]+
+					pBan->m_Info.m_Addr.ip[8]+pBan->m_Info.m_Addr.ip[9]+pBan->m_Info.m_Addr.ip[10]+pBan->m_Info.m_Addr.ip[11]+
+					pBan->m_Info.m_Addr.ip[12]+pBan->m_Info.m_Addr.ip[13]+pBan->m_Info.m_Addr.ip[14]+pBan->m_Info.m_Addr.ip[15])&0xff;
+	char aAddrStr[NETADDR_MAXSTRSIZE];
+	net_addr_str(&pBan->m_Info.m_Addr, aAddrStr, sizeof(aAddrStr));
+	dbg_msg("netserver", "removing ban on %s", aAddrStr);
 	MACRO_LIST_UNLINK(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext);
 	MACRO_LIST_UNLINK(pBan, m_aBans[IpHash], m_pHashPrev, m_pHashNext);
 	MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstFree, m_pPrev, m_pNext);
@@ -127,7 +131,8 @@ void CNetServer::BanRemoveByObject(CBan *pBan)
 
 int CNetServer::BanRemove(NETADDR Addr)
 {
-	int IpHash = (Addr.ip[0]+Addr.ip[1]+Addr.ip[2]+Addr.ip[3])&0xff;
+	int IpHash = (Addr.ip[0]+Addr.ip[1]+Addr.ip[2]+Addr.ip[3]+Addr.ip[4]+Addr.ip[5]+Addr.ip[6]+Addr.ip[7]+
+					Addr.ip[8]+Addr.ip[9]+Addr.ip[10]+Addr.ip[11]+Addr.ip[12]+Addr.ip[13]+Addr.ip[14]+Addr.ip[15])&0xff;
 	CBan *pBan = m_aBans[IpHash];
 	
 	MACRO_LIST_FIND(pBan, m_pHashNext, net_addr_comp(&pBan->m_Info.m_Addr, &Addr) == 0);
@@ -143,7 +148,8 @@ int CNetServer::BanRemove(NETADDR Addr)
 
 int CNetServer::BanAdd(NETADDR Addr, int Seconds, const char *pReason)
 {
-	int IpHash = (Addr.ip[0]+Addr.ip[1]+Addr.ip[2]+Addr.ip[3])&0xff;
+	int IpHash = (Addr.ip[0]+Addr.ip[1]+Addr.ip[2]+Addr.ip[3]+Addr.ip[4]+Addr.ip[5]+Addr.ip[6]+Addr.ip[7]+
+					Addr.ip[8]+Addr.ip[9]+Addr.ip[10]+Addr.ip[11]+Addr.ip[12]+Addr.ip[13]+Addr.ip[14]+Addr.ip[15])&0xff;
 	int Stamp = -1;
 	CBan *pBan;
 	
@@ -284,7 +290,8 @@ int CNetServer::Recv(CNetChunk *pChunk)
 		{
 			CBan *pBan = 0;
 			NETADDR BanAddr = Addr;
-			int IpHash = (BanAddr.ip[0]+BanAddr.ip[1]+BanAddr.ip[2]+BanAddr.ip[3])&0xff;
+			int IpHash = (BanAddr.ip[0]+BanAddr.ip[1]+BanAddr.ip[2]+BanAddr.ip[3]+BanAddr.ip[4]+BanAddr.ip[5]+BanAddr.ip[6]+BanAddr.ip[7]+
+							BanAddr.ip[8]+BanAddr.ip[9]+BanAddr.ip[10]+BanAddr.ip[11]+BanAddr.ip[12]+BanAddr.ip[13]+BanAddr.ip[14]+BanAddr.ip[15])&0xff;
 			int Found = 0;
 			BanAddr.port = 0;
 			
diff --git a/src/mastersrv/mastersrv.cpp b/src/mastersrv/mastersrv.cpp
index 10440e7d..c63ff03e 100644
--- a/src/mastersrv/mastersrv.cpp
+++ b/src/mastersrv/mastersrv.cpp
@@ -11,7 +11,7 @@
 
 enum {
 	MTU = 1400,
-	MAX_SERVERS_PER_PACKET=128,
+	MAX_SERVERS_PER_PACKET=40,
 	MAX_PACKETS=16,
 	MAX_SERVERS=MAX_SERVERS_PER_PACKET*MAX_PACKETS,
 	MAX_BANS=128,
@@ -29,12 +29,6 @@ struct CCheckServer
 static CCheckServer m_aCheckServers[MAX_SERVERS];
 static int m_NumCheckServers = 0;
 
-struct NETADDR_IPv4
-{
-	unsigned char m_aIp[4];
-	unsigned short m_Port;
-};
-
 struct CServerEntry
 {
 	NETADDR m_Address;
@@ -49,7 +43,7 @@ struct CPacketData
 	int m_Size;
 	struct {
 		unsigned char m_aHeader[sizeof(SERVERBROWSE_LIST)];
-		NETADDR_IPv4 m_aServers[MAX_SERVERS_PER_PACKET];
+		CMastersrvAddr m_aServers[MAX_SERVERS_PER_PACKET];
 	} m_Data;
 };
 
@@ -75,8 +69,6 @@ struct CBanEntry
 static CBanEntry m_aBans[MAX_BANS];
 static int m_NumBans = 0;
 
-//static int64 server_expire[MAX_SERVERS];
-
 static CNetClient m_NetChecker; // NAT/FW checker
 static CNetClient m_NetOp; // main
 
@@ -100,16 +92,19 @@ void BuildPackets()
 		// copy server addresses
 		for(int i = 0; i < Chunk; i++)
 		{
-			// TODO: ipv6 support
-			m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_aIp[0] = pCurrent->m_Address.ip[0];
-			m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_aIp[1] = pCurrent->m_Address.ip[1];
-			m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_aIp[2] = pCurrent->m_Address.ip[2];
-			m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_aIp[3] = pCurrent->m_Address.ip[3];
-			m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_Port = pCurrent->m_Address.port;
+			m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_aType[0] = (pCurrent->m_Address.type>>24)&0xff;
+			m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_aType[1] = (pCurrent->m_Address.type>>16)&0xff;
+			m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_aType[2] = (pCurrent->m_Address.type>>8)&0xff;
+			m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_aType[3] = pCurrent->m_Address.type&0xff;
+			mem_copy(m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_aIp, pCurrent->m_Address.ip,
+				sizeof(m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_aIp));
+			m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_aPort[0] = (pCurrent->m_Address.port>>8)&0xff;
+			m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_aPort[1] = pCurrent->m_Address.port&0xff;
+
 			pCurrent++;
 		}
 		
-		m_aPackets[m_NumPackets].m_Size = sizeof(SERVERBROWSE_LIST) + sizeof(NETADDR_IPv4)*Chunk;
+		m_aPackets[m_NumPackets].m_Size = sizeof(SERVERBROWSE_LIST) + sizeof(NETADDR)*Chunk;
 		
 		m_NumPackets++;
 	}
@@ -160,9 +155,11 @@ void AddCheckserver(NETADDR *pInfo, NETADDR *pAlt)
 		return;
 	}
 	
-	dbg_msg("mastersrv", "checking: %d.%d.%d.%d:%d (%d.%d.%d.%d:%d)",
-		pInfo->ip[0], pInfo->ip[1], pInfo->ip[2], pInfo->ip[3], pInfo->port,
-		pAlt->ip[0], pAlt->ip[1], pAlt->ip[2], pAlt->ip[3], pAlt->port);
+	char aAddrStr[NETADDR_MAXSTRSIZE];
+	net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr));
+	char aAltAddrStr[NETADDR_MAXSTRSIZE];
+	net_addr_str(pAlt, aAltAddrStr, sizeof(aAltAddrStr));
+	dbg_msg("mastersrv", "checking: %s (%s)", aAddrStr, aAltAddrStr);
 	m_aCheckServers[m_NumCheckServers].m_Address = *pInfo;
 	m_aCheckServers[m_NumCheckServers].m_AltAddress = *pAlt;
 	m_aCheckServers[m_NumCheckServers].m_TryCount = 0;
@@ -173,13 +170,13 @@ void AddCheckserver(NETADDR *pInfo, NETADDR *pAlt)
 void AddServer(NETADDR *pInfo)
 {
 	// see if server already exists in list
-	int i;
-	for(i = 0; i < m_NumServers; i++)
+	for(int i = 0; i < m_NumServers; i++)
 	{
 		if(net_addr_comp(&m_aServers[i].m_Address, pInfo) == 0)
 		{
-			dbg_msg("mastersrv", "updated: %d.%d.%d.%d:%d",
-				pInfo->ip[0], pInfo->ip[1], pInfo->ip[2], pInfo->ip[3], pInfo->port);
+			char aAddrStr[NETADDR_MAXSTRSIZE];
+			net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr));
+			dbg_msg("mastersrv", "updated: %s", aAddrStr);
 			m_aServers[i].m_Expire = time_get()+time_freq()*EXPIRE_TIME;
 			return;
 		}
@@ -192,8 +189,9 @@ void AddServer(NETADDR *pInfo)
 		return;
 	}
 	
-	dbg_msg("mastersrv", "added: %d.%d.%d.%d:%d",
-		pInfo->ip[0], pInfo->ip[1], pInfo->ip[2], pInfo->ip[3], pInfo->port);
+	char aAddrStr[NETADDR_MAXSTRSIZE];
+	net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr));
+	dbg_msg("mastersrv", "added: %s", aAddrStr);
 	m_aServers[m_NumServers].m_Address = *pInfo;
 	m_aServers[m_NumServers].m_Expire = time_get()+time_freq()*EXPIRE_TIME;
 	m_NumServers++;
@@ -209,11 +207,11 @@ void UpdateServers()
 		{
 			if(m_aCheckServers[i].m_TryCount == 10)
 			{
-				dbg_msg("mastersrv", "check failed: %d.%d.%d.%d:%d",
-					m_aCheckServers[i].m_Address.ip[0], m_aCheckServers[i].m_Address.ip[1],
-					m_aCheckServers[i].m_Address.ip[2], m_aCheckServers[i].m_Address.ip[3],m_aCheckServers[i].m_Address.port,
-					m_aCheckServers[i].m_AltAddress.ip[0], m_aCheckServers[i].m_AltAddress.ip[1],
-					m_aCheckServers[i].m_AltAddress.ip[2], m_aCheckServers[i].m_AltAddress.ip[3],m_aCheckServers[i].m_AltAddress.port);
+				char aAddrStr[NETADDR_MAXSTRSIZE];
+				net_addr_str(&m_aCheckServers[i].m_Address, aAddrStr, sizeof(aAddrStr));
+				char aAltAddrStr[NETADDR_MAXSTRSIZE];
+				net_addr_str(&m_aCheckServers[i].m_AltAddress, aAltAddrStr, sizeof(aAltAddrStr));
+				dbg_msg("mastersrv", "check failed: %s (%s)", aAddrStr, aAltAddrStr);
 					
 				// FAIL!!
 				SendError(&m_aCheckServers[i].m_Address);
@@ -243,9 +241,9 @@ void PurgeServers()
 		if(m_aServers[i].m_Expire < Now)
 		{
 			// remove server
-			dbg_msg("mastersrv", "expired: %d.%d.%d.%d:%d",
-				m_aServers[i].m_Address.ip[0], m_aServers[i].m_Address.ip[1],
-				m_aServers[i].m_Address.ip[2], m_aServers[i].m_Address.ip[3], m_aServers[i].m_Address.port);
+			char aAddrStr[NETADDR_MAXSTRSIZE];
+			net_addr_str(&m_aServers[i].m_Address, aAddrStr, sizeof(aAddrStr));
+			dbg_msg("mastersrv", "expired: %s", aAddrStr);
 			m_aServers[i] = m_aServers[m_NumServers-1];
 			m_NumServers--;
 		}
@@ -282,21 +280,19 @@ void ConAddBan(IConsole::IResult *pResult, void *pUser)
 		return;
 	}
 	
-	net_addr_from_str(&m_aBans[m_NumBans].m_Address, pResult->GetString(0));
+	if(net_addr_from_str(&m_aBans[m_NumBans].m_Address, pResult->GetString(0)) != 0)
+	{
+		dbg_msg("mastersrv", "error: invalid address");
+		return;
+	}
 	
 	if(CheckBan(m_aBans[m_NumBans].m_Address))
 	{
-		dbg_msg("mastersrv", "duplicate ban: %d.%d.%d.%d:%d",
-			m_aBans[m_NumBans].m_Address.ip[0], m_aBans[m_NumBans].m_Address.ip[1],
-			m_aBans[m_NumBans].m_Address.ip[2], m_aBans[m_NumBans].m_Address.ip[3],
-			m_aBans[m_NumBans].m_Address.port);
+		dbg_msg("mastersrv", "duplicate ban: %s", pResult->GetString(0));
 		return;
 	}
 	
-	dbg_msg("mastersrv", "ban added: %d.%d.%d.%d:%d",
-		m_aBans[m_NumBans].m_Address.ip[0], m_aBans[m_NumBans].m_Address.ip[1],
-		m_aBans[m_NumBans].m_Address.ip[2], m_aBans[m_NumBans].m_Address.ip[3],
-		m_aBans[m_NumBans].m_Address.port);
+	dbg_msg("mastersrv", "ban added: %s", pResult->GetString(0));
 	m_NumBans++;
 }
 
@@ -315,15 +311,22 @@ int main(int argc, const char **argv) // ignore_convention
 	net_init();
 
 	mem_zero(&BindAddr, sizeof(BindAddr));
+	BindAddr.type = NETTYPE_ALL;
 	BindAddr.port = MASTERSERVER_PORT;
 		
-	m_NetOp.Open(BindAddr, 0);
+	if(!m_NetOp.Open(BindAddr, 0))
+	{
+		dbg_msg("mastersrv", "couldn't start network (op)");
+		return -1;
+	}
 
 	BindAddr.port = MASTERSERVER_PORT+1;
-	m_NetChecker.Open(BindAddr, 0);
-	// TODO: check socket for errors
+	if(!m_NetChecker.Open(BindAddr, 0))
+	{
+		dbg_msg("mastersrv", "couldn't start network (checker)");
+		return -1;
+	}
 	
-	//mem_copy(data.header, SERVERBROWSE_LIST, sizeof(SERVERBROWSE_LIST));
 	mem_copy(m_CountData.m_Header, SERVERBROWSE_COUNT, sizeof(SERVERBROWSE_COUNT));
 
 	IKernel *pKernel = IKernel::Create();
diff --git a/src/mastersrv/mastersrv.h b/src/mastersrv/mastersrv.h
index 9da82bff..bbe2e8fb 100644
--- a/src/mastersrv/mastersrv.h
+++ b/src/mastersrv/mastersrv.h
@@ -4,19 +4,20 @@
 #define MASTERSRV_MASTERSRV_H
 static const int MASTERSERVER_PORT = 8300;
 
-typedef struct MASTERSRV_ADDR
+struct CMastersrvAddr
 {
-	unsigned char m_aIp[4];
+	unsigned char m_aType[4];
+	unsigned char m_aIp[16];
 	unsigned char m_aPort[2];
-} MASTERSRV_ADDR;
+};
 
-static const unsigned char SERVERBROWSE_HEARTBEAT[] = {255, 255, 255, 255, 'b', 'e', 'a', 't'};
+static const unsigned char SERVERBROWSE_HEARTBEAT[] = {255, 255, 255, 255, 'b', 'e', 'a', '2'};
 
-static const unsigned char SERVERBROWSE_GETLIST[] = {255, 255, 255, 255, 'r', 'e', 'q', 't'};
-static const unsigned char SERVERBROWSE_LIST[] = {255, 255, 255, 255, 'l', 'i', 's', 't'};
+static const unsigned char SERVERBROWSE_GETLIST[] = {255, 255, 255, 255, 'r', 'e', 'q', '2'};
+static const unsigned char SERVERBROWSE_LIST[] = {255, 255, 255, 255, 'l', 'i', 's', '2'};
 
-static const unsigned char SERVERBROWSE_GETCOUNT[] = {255, 255, 255, 255, 'c', 'o', 'u', 'n'};
-static const unsigned char SERVERBROWSE_COUNT[] = {255, 255, 255, 255, 's', 'i', 'z', 'e'};
+static const unsigned char SERVERBROWSE_GETCOUNT[] = {255, 255, 255, 255, 'c', 'o', 'u', '2'};
+static const unsigned char SERVERBROWSE_COUNT[] = {255, 255, 255, 255, 's', 'i', 'z', '2'};
 
 static const unsigned char SERVERBROWSE_GETINFO[] = {255, 255, 255, 255, 'g', 'i', 'e', '3'};
 static const unsigned char SERVERBROWSE_INFO[] = {255, 255, 255, 255, 'i', 'n', 'f', '3'};
diff --git a/src/tools/crapnet.cpp b/src/tools/crapnet.cpp
index 065eaad0..35ca09bc 100644
--- a/src/tools/crapnet.cpp
+++ b/src/tools/crapnet.cpp
@@ -127,7 +127,11 @@ void Run(int Port, NETADDR Dest)
 			Delaycounter--;
 	
 			if(m_ConfigLog)
-				dbg_msg("crapnet", "<< %08d %d.%d.%d.%d:%5d (%d)", p->m_ID, From.ip[0], From.ip[1], From.ip[2], From.ip[3], From.port, p->m_DataSize);
+			{
+				char aAddrStr[NETADDR_MAXSTRSIZE];
+				net_addr_str(&From, aAddrStr, sizeof(aAddrStr));
+				dbg_msg("crapnet", "<< %08d %s (%d)", p->m_ID, aAddrStr, p->m_DataSize);
+			}
 		}
 		
 		//
@@ -188,10 +192,9 @@ void Run(int Port, NETADDR Dest)
 
 				if(m_ConfigLog)
 				{
-					dbg_msg("crapnet", ">> %08d %d.%d.%d.%d:%5d (%d) %s", p->m_ID,
-						p->m_SendTo.ip[0], p->m_SendTo.ip[1],
-						p->m_SendTo.ip[2], p->m_SendTo.ip[3],
-						p->m_SendTo.port, p->m_DataSize, aFlags);
+					char aAddrStr[NETADDR_MAXSTRSIZE];
+					net_addr_str(&p->m_SendTo, aAddrStr, sizeof(aAddrStr));
+					dbg_msg("crapnet", ">> %08d %s (%d) %s", p->m_ID, aAddrStr, p->m_DataSize, aFlags);
 				}
 				
 
diff --git a/src/tools/mastersrv_old.cpp b/src/tools/mastersrv_old.cpp
new file mode 100644
index 00000000..e8f3677d
--- /dev/null
+++ b/src/tools/mastersrv_old.cpp
@@ -0,0 +1,449 @@
+/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
+/* If you are missing that file, acquire a complete release at teeworlds.com.                */
+#include <base/system.h>
+#include <engine/shared/network.h>
+#include <engine/shared/config.h>
+#include <engine/console.h>
+#include <engine/storage.h>
+#include <engine/kernel.h>
+
+#include "mastersrv_old.h"
+
+enum {
+	MTU = 1400,
+	MAX_SERVERS_PER_PACKET=128,
+	MAX_PACKETS=16,
+	MAX_SERVERS=MAX_SERVERS_PER_PACKET*MAX_PACKETS,
+	MAX_BANS=128,
+	EXPIRE_TIME = 90
+};
+
+struct CCheckServer
+{
+	NETADDR m_Address;
+	NETADDR m_AltAddress;
+	int m_TryCount;
+	int64 m_TryTime;
+};
+
+static CCheckServer m_aCheckServers[MAX_SERVERS];
+static int m_NumCheckServers = 0;
+
+struct NETADDR_IPv4
+{
+	unsigned char m_aIp[4];
+	unsigned short m_Port;
+};
+
+struct CServerEntry
+{
+	NETADDR m_Address;
+	int64 m_Expire;
+};
+
+static CServerEntry m_aServers[MAX_SERVERS];
+static int m_NumServers = 0;
+
+struct CPacketData
+{
+	int m_Size;
+	struct {
+		unsigned char m_aHeader[sizeof(SERVERBROWSE_LIST)];
+		NETADDR_IPv4 m_aServers[MAX_SERVERS_PER_PACKET];
+	} m_Data;
+};
+
+CPacketData m_aPackets[MAX_PACKETS];
+static int m_NumPackets = 0;
+
+struct CCountPacketData
+{
+	unsigned char m_Header[sizeof(SERVERBROWSE_COUNT)];
+	unsigned char m_High;
+	unsigned char m_Low;
+};
+
+static CCountPacketData m_CountData;
+
+
+struct CBanEntry
+{
+	NETADDR m_Address;
+	int64 m_Expire;
+};
+
+static CBanEntry m_aBans[MAX_BANS];
+static int m_NumBans = 0;
+
+//static int64 server_expire[MAX_SERVERS];
+
+static CNetClient m_NetChecker; // NAT/FW checker
+static CNetClient m_NetOp; // main
+
+IConsole *m_pConsole;
+
+void BuildPackets()
+{
+	CServerEntry *pCurrent = &m_aServers[0];
+	int ServersLeft = m_NumServers;
+	m_NumPackets = 0;
+	while(ServersLeft && m_NumPackets < MAX_PACKETS)
+	{
+		int Chunk = ServersLeft;
+		if(Chunk > MAX_SERVERS_PER_PACKET)
+			Chunk = MAX_SERVERS_PER_PACKET;
+		ServersLeft -= Chunk;
+		
+		// copy header	
+		mem_copy(m_aPackets[m_NumPackets].m_Data.m_aHeader, SERVERBROWSE_LIST, sizeof(SERVERBROWSE_LIST));
+		
+		// copy server addresses
+		for(int i = 0; i < Chunk; i++)
+		{
+			// TODO: ipv6 support
+			m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_aIp[0] = pCurrent->m_Address.ip[0];
+			m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_aIp[1] = pCurrent->m_Address.ip[1];
+			m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_aIp[2] = pCurrent->m_Address.ip[2];
+			m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_aIp[3] = pCurrent->m_Address.ip[3];
+			m_aPackets[m_NumPackets].m_Data.m_aServers[i].m_Port = pCurrent->m_Address.port;
+			pCurrent++;
+		}
+		
+		m_aPackets[m_NumPackets].m_Size = sizeof(SERVERBROWSE_LIST) + sizeof(NETADDR_IPv4)*Chunk;
+		
+		m_NumPackets++;
+	}
+}
+
+void SendOk(NETADDR *pAddr)
+{
+	CNetChunk p;
+	p.m_ClientID = -1;
+	p.m_Address = *pAddr;
+	p.m_Flags = NETSENDFLAG_CONNLESS;
+	p.m_DataSize = sizeof(SERVERBROWSE_FWOK);
+	p.m_pData = SERVERBROWSE_FWOK;
+	
+	// send on both to be sure
+	m_NetChecker.Send(&p);
+	m_NetOp.Send(&p);
+}
+
+void SendError(NETADDR *pAddr)
+{
+	CNetChunk p;
+	p.m_ClientID = -1;
+	p.m_Address = *pAddr;
+	p.m_Flags = NETSENDFLAG_CONNLESS;
+	p.m_DataSize = sizeof(SERVERBROWSE_FWERROR);
+	p.m_pData = SERVERBROWSE_FWERROR;
+	m_NetOp.Send(&p);
+}
+
+void SendCheck(NETADDR *pAddr)
+{
+	CNetChunk p;
+	p.m_ClientID = -1;
+	p.m_Address = *pAddr;
+	p.m_Flags = NETSENDFLAG_CONNLESS;
+	p.m_DataSize = sizeof(SERVERBROWSE_FWCHECK);
+	p.m_pData = SERVERBROWSE_FWCHECK;
+	m_NetChecker.Send(&p);
+}
+
+void AddCheckserver(NETADDR *pInfo, NETADDR *pAlt)
+{
+	// add server
+	if(m_NumCheckServers == MAX_SERVERS)
+	{
+		dbg_msg("mastersrv", "error: mastersrv is full");
+		return;
+	}
+	
+	dbg_msg("mastersrv", "checking: %d.%d.%d.%d:%d (%d.%d.%d.%d:%d)",
+		pInfo->ip[0], pInfo->ip[1], pInfo->ip[2], pInfo->ip[3], pInfo->port,
+		pAlt->ip[0], pAlt->ip[1], pAlt->ip[2], pAlt->ip[3], pAlt->port);
+	m_aCheckServers[m_NumCheckServers].m_Address = *pInfo;
+	m_aCheckServers[m_NumCheckServers].m_AltAddress = *pAlt;
+	m_aCheckServers[m_NumCheckServers].m_TryCount = 0;
+	m_aCheckServers[m_NumCheckServers].m_TryTime = 0;
+	m_NumCheckServers++;
+}
+
+void AddServer(NETADDR *pInfo)
+{
+	// see if server already exists in list
+	int i;
+	for(i = 0; i < m_NumServers; i++)
+	{
+		if(net_addr_comp(&m_aServers[i].m_Address, pInfo) == 0)
+		{
+			dbg_msg("mastersrv", "updated: %d.%d.%d.%d:%d",
+				pInfo->ip[0], pInfo->ip[1], pInfo->ip[2], pInfo->ip[3], pInfo->port);
+			m_aServers[i].m_Expire = time_get()+time_freq()*EXPIRE_TIME;
+			return;
+		}
+	}
+	
+	// add server
+	if(m_NumServers == MAX_SERVERS)
+	{
+		dbg_msg("mastersrv", "error: mastersrv is full");
+		return;
+	}
+	
+	dbg_msg("mastersrv", "added: %d.%d.%d.%d:%d",
+		pInfo->ip[0], pInfo->ip[1], pInfo->ip[2], pInfo->ip[3], pInfo->port);
+	m_aServers[m_NumServers].m_Address = *pInfo;
+	m_aServers[m_NumServers].m_Expire = time_get()+time_freq()*EXPIRE_TIME;
+	m_NumServers++;
+}
+
+void UpdateServers()
+{
+	int64 Now = time_get();
+	int64 Freq = time_freq();
+	for(int i = 0; i < m_NumCheckServers; i++)
+	{
+		if(Now > m_aCheckServers[i].m_TryTime+Freq)
+		{
+			if(m_aCheckServers[i].m_TryCount == 10)
+			{
+				dbg_msg("mastersrv", "check failed: %d.%d.%d.%d:%d",
+					m_aCheckServers[i].m_Address.ip[0], m_aCheckServers[i].m_Address.ip[1],
+					m_aCheckServers[i].m_Address.ip[2], m_aCheckServers[i].m_Address.ip[3],m_aCheckServers[i].m_Address.port,
+					m_aCheckServers[i].m_AltAddress.ip[0], m_aCheckServers[i].m_AltAddress.ip[1],
+					m_aCheckServers[i].m_AltAddress.ip[2], m_aCheckServers[i].m_AltAddress.ip[3],m_aCheckServers[i].m_AltAddress.port);
+					
+				// FAIL!!
+				SendError(&m_aCheckServers[i].m_Address);
+				m_aCheckServers[i] = m_aCheckServers[m_NumCheckServers-1];
+				m_NumCheckServers--;
+				i--;
+			}
+			else
+			{
+				m_aCheckServers[i].m_TryCount++;
+				m_aCheckServers[i].m_TryTime = Now;
+				if(m_aCheckServers[i].m_TryCount&1)
+					SendCheck(&m_aCheckServers[i].m_Address);
+				else
+					SendCheck(&m_aCheckServers[i].m_AltAddress);
+			}
+		}
+	}
+}
+
+void PurgeServers()
+{
+	int64 Now = time_get();
+	int i = 0;
+	while(i < m_NumServers)
+	{
+		if(m_aServers[i].m_Expire < Now)
+		{
+			// remove server
+			dbg_msg("mastersrv", "expired: %d.%d.%d.%d:%d",
+				m_aServers[i].m_Address.ip[0], m_aServers[i].m_Address.ip[1],
+				m_aServers[i].m_Address.ip[2], m_aServers[i].m_Address.ip[3], m_aServers[i].m_Address.port);
+			m_aServers[i] = m_aServers[m_NumServers-1];
+			m_NumServers--;
+		}
+		else
+			i++;
+	}
+}
+
+bool CheckBan(NETADDR Addr)
+{
+	for(int i = 0; i < m_NumBans; i++)
+	{
+		if(net_addr_comp(&m_aBans[i].m_Address, &Addr) == 0)
+		{
+			return true;
+		}
+	}
+	Addr.port = 0;
+	for(int i = 0; i < m_NumBans; i++)
+	{
+		if(net_addr_comp(&m_aBans[i].m_Address, &Addr) == 0)
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+void ConAddBan(IConsole::IResult *pResult, void *pUser)
+{
+	if(m_NumBans == MAX_BANS)
+	{
+		dbg_msg("mastersrv", "error: banlist is full");
+		return;
+	}
+	
+	net_addr_from_str(&m_aBans[m_NumBans].m_Address, pResult->GetString(0));
+	
+	if(CheckBan(m_aBans[m_NumBans].m_Address))
+	{
+		dbg_msg("mastersrv", "duplicate ban: %d.%d.%d.%d:%d",
+			m_aBans[m_NumBans].m_Address.ip[0], m_aBans[m_NumBans].m_Address.ip[1],
+			m_aBans[m_NumBans].m_Address.ip[2], m_aBans[m_NumBans].m_Address.ip[3],
+			m_aBans[m_NumBans].m_Address.port);
+		return;
+	}
+	
+	dbg_msg("mastersrv", "ban added: %d.%d.%d.%d:%d",
+		m_aBans[m_NumBans].m_Address.ip[0], m_aBans[m_NumBans].m_Address.ip[1],
+		m_aBans[m_NumBans].m_Address.ip[2], m_aBans[m_NumBans].m_Address.ip[3],
+		m_aBans[m_NumBans].m_Address.port);
+	m_NumBans++;
+}
+
+void ReloadBans()
+{
+	m_NumBans = 0;
+	m_pConsole->ExecuteFile("master.cfg");
+}
+
+int main(int argc, const char **argv) // ignore_convention
+{
+	int64 LastBuild = 0, LastBanReload = 0;
+	NETADDR BindAddr;
+
+	dbg_logger_stdout();
+	net_init();
+
+	mem_zero(&BindAddr, sizeof(BindAddr));
+	BindAddr.port = MASTERSERVER_PORT;
+		
+	m_NetOp.Open(BindAddr, 0);
+
+	BindAddr.port = MASTERSERVER_PORT+1;
+	m_NetChecker.Open(BindAddr, 0);
+	// TODO: check socket for errors
+	
+	//mem_copy(data.header, SERVERBROWSE_LIST, sizeof(SERVERBROWSE_LIST));
+	mem_copy(m_CountData.m_Header, SERVERBROWSE_COUNT, sizeof(SERVERBROWSE_COUNT));
+
+	IKernel *pKernel = IKernel::Create();
+	IStorage *pStorage = CreateStorage("Teeworlds", argc, argv);
+
+	m_pConsole = CreateConsole(CFGFLAG_MASTER);
+	m_pConsole->Register("ban", "s", CFGFLAG_MASTER, ConAddBan, 0, "Ban IP from mastersrv");
+
+	bool RegisterFail = !pKernel->RegisterInterface(pStorage);
+	RegisterFail |= !pKernel->RegisterInterface(m_pConsole);
+
+	if(RegisterFail)
+		return -1;
+	
+	dbg_msg("mastersrv", "started");
+	
+	while(1)
+	{
+		m_NetOp.Update();
+		m_NetChecker.Update();
+		
+		// process m_aPackets
+		CNetChunk Packet;
+		while(m_NetOp.Recv(&Packet))
+		{
+			// check if the server is banned
+			if(CheckBan(Packet.m_Address)) continue;
+
+			if(Packet.m_DataSize == sizeof(SERVERBROWSE_HEARTBEAT)+2 &&
+				mem_comp(Packet.m_pData, SERVERBROWSE_HEARTBEAT, sizeof(SERVERBROWSE_HEARTBEAT)) == 0)
+			{
+				NETADDR Alt;
+				unsigned char *d = (unsigned char *)Packet.m_pData;
+				Alt = Packet.m_Address;
+				Alt.port =
+					(d[sizeof(SERVERBROWSE_HEARTBEAT)]<<8) |
+					d[sizeof(SERVERBROWSE_HEARTBEAT)+1];
+				
+				// add it
+				AddCheckserver(&Packet.m_Address, &Alt);
+			}
+			else if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETCOUNT) &&
+				mem_comp(Packet.m_pData, SERVERBROWSE_GETCOUNT, sizeof(SERVERBROWSE_GETCOUNT)) == 0)
+			{
+				dbg_msg("mastersrv", "count requested, responding with %d", m_NumServers);
+				
+				CNetChunk p;
+				p.m_ClientID = -1;
+				p.m_Address = Packet.m_Address;
+				p.m_Flags = NETSENDFLAG_CONNLESS;
+				p.m_DataSize = sizeof(m_CountData);
+				p.m_pData = &m_CountData;
+				m_CountData.m_High = (m_NumServers>>8)&0xff;
+				m_CountData.m_Low = m_NumServers&0xff;
+				m_NetOp.Send(&p);
+			}
+			else if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETLIST) &&
+				mem_comp(Packet.m_pData, SERVERBROWSE_GETLIST, sizeof(SERVERBROWSE_GETLIST)) == 0)
+			{
+				// someone requested the list
+				dbg_msg("mastersrv", "requested, responding with %d m_aServers", m_NumServers);
+				CNetChunk p;
+				p.m_ClientID = -1;
+				p.m_Address = Packet.m_Address;
+				p.m_Flags = NETSENDFLAG_CONNLESS;
+				
+				for(int i = 0; i < m_NumPackets; i++)
+				{
+					p.m_DataSize = m_aPackets[i].m_Size;
+					p.m_pData = &m_aPackets[i].m_Data;
+					m_NetOp.Send(&p);
+				}
+			}
+		}
+
+		// process m_aPackets
+		while(m_NetChecker.Recv(&Packet))
+		{
+			// check if the server is banned
+			if(CheckBan(Packet.m_Address)) continue;
+			
+			if(Packet.m_DataSize == sizeof(SERVERBROWSE_FWRESPONSE) &&
+				mem_comp(Packet.m_pData, SERVERBROWSE_FWRESPONSE, sizeof(SERVERBROWSE_FWRESPONSE)) == 0)
+			{
+				// remove it from checking
+				for(int i = 0; i < m_NumCheckServers; i++)
+				{
+					if(net_addr_comp(&m_aCheckServers[i].m_Address, &Packet.m_Address) == 0 ||
+						net_addr_comp(&m_aCheckServers[i].m_AltAddress, &Packet.m_Address) == 0)
+					{
+						m_NumCheckServers--;
+						m_aCheckServers[i] = m_aCheckServers[m_NumCheckServers];
+						break;
+					}
+				}
+				
+				AddServer(&Packet.m_Address);
+				SendOk(&Packet.m_Address);
+			}
+		}
+		
+		if(time_get()-LastBanReload > time_freq()*300)
+		{
+			LastBanReload = time_get();
+
+			ReloadBans();
+		}
+
+		if(time_get()-LastBuild > time_freq()*5)
+		{
+			LastBuild = time_get();
+			
+			PurgeServers();
+			UpdateServers();
+			BuildPackets();
+		}
+		
+		// be nice to the CPU
+		thread_sleep(1);
+	}
+	
+	return 0;
+}
diff --git a/src/tools/mastersrv_old.h b/src/tools/mastersrv_old.h
new file mode 100644
index 00000000..9da82bff
--- /dev/null
+++ b/src/tools/mastersrv_old.h
@@ -0,0 +1,28 @@
+/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
+/* If you are missing that file, acquire a complete release at teeworlds.com.                */
+#ifndef MASTERSRV_MASTERSRV_H
+#define MASTERSRV_MASTERSRV_H
+static const int MASTERSERVER_PORT = 8300;
+
+typedef struct MASTERSRV_ADDR
+{
+	unsigned char m_aIp[4];
+	unsigned char m_aPort[2];
+} MASTERSRV_ADDR;
+
+static const unsigned char SERVERBROWSE_HEARTBEAT[] = {255, 255, 255, 255, 'b', 'e', 'a', 't'};
+
+static const unsigned char SERVERBROWSE_GETLIST[] = {255, 255, 255, 255, 'r', 'e', 'q', 't'};
+static const unsigned char SERVERBROWSE_LIST[] = {255, 255, 255, 255, 'l', 'i', 's', 't'};
+
+static const unsigned char SERVERBROWSE_GETCOUNT[] = {255, 255, 255, 255, 'c', 'o', 'u', 'n'};
+static const unsigned char SERVERBROWSE_COUNT[] = {255, 255, 255, 255, 's', 'i', 'z', 'e'};
+
+static const unsigned char SERVERBROWSE_GETINFO[] = {255, 255, 255, 255, 'g', 'i', 'e', '3'};
+static const unsigned char SERVERBROWSE_INFO[] = {255, 255, 255, 255, 'i', 'n', 'f', '3'};
+
+static const unsigned char SERVERBROWSE_FWCHECK[] = {255, 255, 255, 255, 'f', 'w', '?', '?'};
+static const unsigned char SERVERBROWSE_FWRESPONSE[] = {255, 255, 255, 255, 'f', 'w', '!', '!'};
+static const unsigned char SERVERBROWSE_FWOK[] = {255, 255, 255, 255, 'f', 'w', 'o', 'k'};
+static const unsigned char SERVERBROWSE_FWERROR[] = {255, 255, 255, 255, 'f', 'w', 'e', 'r'};
+#endif