fixed a nasty noise problem. Closes #812
[twcon.git] / src / mastersrv / mastersrv.cpp
blob70e4aecfe897050037afa00caf6ee343c6ee77c6
1 /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2 /* If you are missing that file, acquire a complete release at teeworlds.com. */
3 #include <base/system.h>
4 #include <engine/shared/network.h>
5 #include <engine/shared/config.h>
6 #include <engine/console.h>
7 #include <engine/storage.h>
8 #include <engine/kernel.h>
10 #include "mastersrv.h"
12 enum {
13 MTU = 1400,
14 MAX_SERVERS_PER_PACKET=75,
15 MAX_PACKETS=16,
16 MAX_SERVERS=MAX_SERVERS_PER_PACKET*MAX_PACKETS,
17 MAX_BANS=128,
18 EXPIRE_TIME = 90
21 struct CCheckServer
23 enum ServerType m_Type;
24 NETADDR m_Address;
25 NETADDR m_AltAddress;
26 int m_TryCount;
27 int64 m_TryTime;
30 static CCheckServer m_aCheckServers[MAX_SERVERS];
31 static int m_NumCheckServers = 0;
33 struct CServerEntry
35 enum ServerType m_Type;
36 NETADDR m_Address;
37 int64 m_Expire;
40 static CServerEntry m_aServers[MAX_SERVERS];
41 static int m_NumServers = 0;
43 struct CPacketData
45 int m_Size;
46 struct {
47 unsigned char m_aHeader[sizeof(SERVERBROWSE_LIST)];
48 CMastersrvAddr m_aServers[MAX_SERVERS_PER_PACKET];
49 } m_Data;
52 CPacketData m_aPackets[MAX_PACKETS];
53 static int m_NumPackets = 0;
55 // legacy code
56 struct CPacketDataLegacy
58 int m_Size;
59 struct {
60 unsigned char m_aHeader[sizeof(SERVERBROWSE_LIST_LEGACY)];
61 CMastersrvAddrLegacy m_aServers[MAX_SERVERS_PER_PACKET];
62 } m_Data;
65 CPacketDataLegacy m_aPacketsLegacy[MAX_PACKETS];
66 static int m_NumPacketsLegacy = 0;
69 struct CCountPacketData
71 unsigned char m_Header[sizeof(SERVERBROWSE_COUNT)];
72 unsigned char m_High;
73 unsigned char m_Low;
76 static CCountPacketData m_CountData;
77 static CCountPacketData m_CountDataLegacy;
80 struct CBanEntry
82 NETADDR m_Address;
83 int64 m_Expire;
86 static CBanEntry m_aBans[MAX_BANS];
87 static int m_NumBans = 0;
89 static CNetClient m_NetChecker; // NAT/FW checker
90 static CNetClient m_NetOp; // main
92 IConsole *m_pConsole;
94 void BuildPackets()
96 CServerEntry *pCurrent = &m_aServers[0];
97 int ServersLeft = m_NumServers;
98 m_NumPackets = 0;
99 m_NumPacketsLegacy = 0;
100 int PacketIndex = 0;
101 int PacketIndexLegacy = 0;
102 while(ServersLeft-- && (m_NumPackets + m_NumPacketsLegacy) < MAX_PACKETS)
104 if(pCurrent->m_Type == SERVERTYPE_NORMAL)
106 if(PacketIndex % MAX_SERVERS_PER_PACKET == 0)
108 PacketIndex = 0;
109 m_NumPackets++;
112 // copy header
113 mem_copy(m_aPackets[m_NumPackets-1].m_Data.m_aHeader, SERVERBROWSE_LIST, sizeof(SERVERBROWSE_LIST));
115 // copy server addresses
116 if(pCurrent->m_Address.type == NETTYPE_IPV6)
118 mem_copy(m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aIp, pCurrent->m_Address.ip,
119 sizeof(m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aIp));
121 else
123 static char IPV4Mapping[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
125 mem_copy(m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aIp, IPV4Mapping, sizeof(IPV4Mapping));
126 m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aIp[12] = pCurrent->m_Address.ip[0];
127 m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aIp[13] = pCurrent->m_Address.ip[1];
128 m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aIp[14] = pCurrent->m_Address.ip[2];
129 m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aIp[15] = pCurrent->m_Address.ip[3];
132 m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aPort[0] = (pCurrent->m_Address.port>>8)&0xff;
133 m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aPort[1] = pCurrent->m_Address.port&0xff;
135 PacketIndex++;
137 m_aPackets[m_NumPackets-1].m_Size = sizeof(SERVERBROWSE_LIST) + sizeof(CMastersrvAddr)*PacketIndex;
139 pCurrent++;
141 else if(pCurrent->m_Type == SERVERTYPE_LEGACY)
143 if(PacketIndexLegacy % MAX_SERVERS_PER_PACKET == 0)
145 PacketIndexLegacy = 0;
146 m_NumPacketsLegacy++;
149 // copy header
150 mem_copy(m_aPacketsLegacy[m_NumPacketsLegacy-1].m_Data.m_aHeader, SERVERBROWSE_LIST_LEGACY, sizeof(SERVERBROWSE_LIST_LEGACY));
152 // copy server addresses
153 mem_copy(m_aPacketsLegacy[m_NumPacketsLegacy-1].m_Data.m_aServers[PacketIndexLegacy].m_aIp, pCurrent->m_Address.ip,
154 sizeof(m_aPacketsLegacy[m_NumPacketsLegacy-1].m_Data.m_aServers[PacketIndexLegacy].m_aIp));
155 // 0.5 has the port in little endian on the network
156 m_aPacketsLegacy[m_NumPacketsLegacy-1].m_Data.m_aServers[PacketIndexLegacy].m_aPort[0] = pCurrent->m_Address.port&0xff;
157 m_aPacketsLegacy[m_NumPacketsLegacy-1].m_Data.m_aServers[PacketIndexLegacy].m_aPort[1] = (pCurrent->m_Address.port>>8)&0xff;
159 PacketIndexLegacy++;
161 m_aPacketsLegacy[m_NumPacketsLegacy-1].m_Size = sizeof(SERVERBROWSE_LIST_LEGACY) + sizeof(CMastersrvAddrLegacy)*PacketIndexLegacy;
163 pCurrent++;
165 else
167 *pCurrent = m_aServers[m_NumServers-1];
168 m_NumServers--;
169 dbg_msg("mastersrv", "error: server of invalid type, dropping it");
174 void SendOk(NETADDR *pAddr)
176 CNetChunk p;
177 p.m_ClientID = -1;
178 p.m_Address = *pAddr;
179 p.m_Flags = NETSENDFLAG_CONNLESS;
180 p.m_DataSize = sizeof(SERVERBROWSE_FWOK);
181 p.m_pData = SERVERBROWSE_FWOK;
183 // send on both to be sure
184 m_NetChecker.Send(&p);
185 m_NetOp.Send(&p);
188 void SendError(NETADDR *pAddr)
190 CNetChunk p;
191 p.m_ClientID = -1;
192 p.m_Address = *pAddr;
193 p.m_Flags = NETSENDFLAG_CONNLESS;
194 p.m_DataSize = sizeof(SERVERBROWSE_FWERROR);
195 p.m_pData = SERVERBROWSE_FWERROR;
196 m_NetOp.Send(&p);
199 void SendCheck(NETADDR *pAddr)
201 CNetChunk p;
202 p.m_ClientID = -1;
203 p.m_Address = *pAddr;
204 p.m_Flags = NETSENDFLAG_CONNLESS;
205 p.m_DataSize = sizeof(SERVERBROWSE_FWCHECK);
206 p.m_pData = SERVERBROWSE_FWCHECK;
207 m_NetChecker.Send(&p);
210 void AddCheckserver(NETADDR *pInfo, NETADDR *pAlt, ServerType Type)
212 // add server
213 if(m_NumCheckServers == MAX_SERVERS)
215 dbg_msg("mastersrv", "error: mastersrv is full");
216 return;
219 char aAddrStr[NETADDR_MAXSTRSIZE];
220 net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr));
221 char aAltAddrStr[NETADDR_MAXSTRSIZE];
222 net_addr_str(pAlt, aAltAddrStr, sizeof(aAltAddrStr));
223 dbg_msg("mastersrv", "checking: %s (%s)", aAddrStr, aAltAddrStr);
224 m_aCheckServers[m_NumCheckServers].m_Address = *pInfo;
225 m_aCheckServers[m_NumCheckServers].m_AltAddress = *pAlt;
226 m_aCheckServers[m_NumCheckServers].m_TryCount = 0;
227 m_aCheckServers[m_NumCheckServers].m_TryTime = 0;
228 m_aCheckServers[m_NumCheckServers].m_Type = Type;
229 m_NumCheckServers++;
232 void AddServer(NETADDR *pInfo, ServerType Type)
234 // see if server already exists in list
235 for(int i = 0; i < m_NumServers; i++)
237 if(net_addr_comp(&m_aServers[i].m_Address, pInfo) == 0)
239 char aAddrStr[NETADDR_MAXSTRSIZE];
240 net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr));
241 dbg_msg("mastersrv", "updated: %s", aAddrStr);
242 m_aServers[i].m_Expire = time_get()+time_freq()*EXPIRE_TIME;
243 return;
247 // add server
248 if(m_NumServers == MAX_SERVERS)
250 dbg_msg("mastersrv", "error: mastersrv is full");
251 return;
254 char aAddrStr[NETADDR_MAXSTRSIZE];
255 net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr));
256 dbg_msg("mastersrv", "added: %s", aAddrStr);
257 m_aServers[m_NumServers].m_Address = *pInfo;
258 m_aServers[m_NumServers].m_Expire = time_get()+time_freq()*EXPIRE_TIME;
259 m_aServers[m_NumServers].m_Type = Type;
260 m_NumServers++;
263 void UpdateServers()
265 int64 Now = time_get();
266 int64 Freq = time_freq();
267 for(int i = 0; i < m_NumCheckServers; i++)
269 if(Now > m_aCheckServers[i].m_TryTime+Freq)
271 if(m_aCheckServers[i].m_TryCount == 10)
273 char aAddrStr[NETADDR_MAXSTRSIZE];
274 net_addr_str(&m_aCheckServers[i].m_Address, aAddrStr, sizeof(aAddrStr));
275 char aAltAddrStr[NETADDR_MAXSTRSIZE];
276 net_addr_str(&m_aCheckServers[i].m_AltAddress, aAltAddrStr, sizeof(aAltAddrStr));
277 dbg_msg("mastersrv", "check failed: %s (%s)", aAddrStr, aAltAddrStr);
279 // FAIL!!
280 SendError(&m_aCheckServers[i].m_Address);
281 m_aCheckServers[i] = m_aCheckServers[m_NumCheckServers-1];
282 m_NumCheckServers--;
283 i--;
285 else
287 m_aCheckServers[i].m_TryCount++;
288 m_aCheckServers[i].m_TryTime = Now;
289 if(m_aCheckServers[i].m_TryCount&1)
290 SendCheck(&m_aCheckServers[i].m_Address);
291 else
292 SendCheck(&m_aCheckServers[i].m_AltAddress);
298 void PurgeServers()
300 int64 Now = time_get();
301 int i = 0;
302 while(i < m_NumServers)
304 if(m_aServers[i].m_Expire < Now)
306 // remove server
307 char aAddrStr[NETADDR_MAXSTRSIZE];
308 net_addr_str(&m_aServers[i].m_Address, aAddrStr, sizeof(aAddrStr));
309 dbg_msg("mastersrv", "expired: %s", aAddrStr);
310 m_aServers[i] = m_aServers[m_NumServers-1];
311 m_NumServers--;
313 else
314 i++;
318 bool CheckBan(NETADDR Addr)
320 for(int i = 0; i < m_NumBans; i++)
322 if(net_addr_comp(&m_aBans[i].m_Address, &Addr) == 0)
324 return true;
327 Addr.port = 0;
328 for(int i = 0; i < m_NumBans; i++)
330 if(net_addr_comp(&m_aBans[i].m_Address, &Addr) == 0)
332 return true;
335 return false;
338 void ConAddBan(IConsole::IResult *pResult, void *pUser)
340 if(m_NumBans == MAX_BANS)
342 dbg_msg("mastersrv", "error: banlist is full");
343 return;
346 if(net_addr_from_str(&m_aBans[m_NumBans].m_Address, pResult->GetString(0)) != 0)
348 dbg_msg("mastersrv", "error: invalid address");
349 return;
352 if(CheckBan(m_aBans[m_NumBans].m_Address))
354 dbg_msg("mastersrv", "duplicate ban: %s", pResult->GetString(0));
355 return;
358 dbg_msg("mastersrv", "ban added: %s", pResult->GetString(0));
359 m_NumBans++;
362 void ReloadBans()
364 m_NumBans = 0;
365 m_pConsole->ExecuteFile("master.cfg");
368 int main(int argc, const char **argv) // ignore_convention
370 int64 LastBuild = 0, LastBanReload = 0;
371 ServerType Type = SERVERTYPE_INVALID;
372 NETADDR BindAddr;
374 dbg_logger_stdout();
375 net_init();
377 mem_zero(&BindAddr, sizeof(BindAddr));
378 BindAddr.type = NETTYPE_ALL;
379 BindAddr.port = MASTERSERVER_PORT;
381 if(!m_NetOp.Open(BindAddr, 0))
383 dbg_msg("mastersrv", "couldn't start network (op)");
384 return -1;
387 BindAddr.port = MASTERSERVER_PORT+1;
388 if(!m_NetChecker.Open(BindAddr, 0))
390 dbg_msg("mastersrv", "couldn't start network (checker)");
391 return -1;
394 mem_copy(m_CountData.m_Header, SERVERBROWSE_COUNT, sizeof(SERVERBROWSE_COUNT));
395 mem_copy(m_CountDataLegacy.m_Header, SERVERBROWSE_COUNT_LEGACY, sizeof(SERVERBROWSE_COUNT_LEGACY));
397 IKernel *pKernel = IKernel::Create();
398 IStorage *pStorage = CreateStorage("Teeworlds", argc, argv);
400 m_pConsole = CreateConsole(CFGFLAG_MASTER);
401 m_pConsole->Register("ban", "s", CFGFLAG_MASTER, ConAddBan, 0, "Ban IP from mastersrv");
403 bool RegisterFail = !pKernel->RegisterInterface(pStorage);
404 RegisterFail |= !pKernel->RegisterInterface(m_pConsole);
406 if(RegisterFail)
407 return -1;
409 dbg_msg("mastersrv", "started");
411 while(1)
413 m_NetOp.Update();
414 m_NetChecker.Update();
416 // process m_aPackets
417 CNetChunk Packet;
418 while(m_NetOp.Recv(&Packet))
420 // check if the server is banned
421 if(CheckBan(Packet.m_Address)) continue;
423 if(Packet.m_DataSize == sizeof(SERVERBROWSE_HEARTBEAT)+2 &&
424 mem_comp(Packet.m_pData, SERVERBROWSE_HEARTBEAT, sizeof(SERVERBROWSE_HEARTBEAT)) == 0)
426 NETADDR Alt;
427 unsigned char *d = (unsigned char *)Packet.m_pData;
428 Alt = Packet.m_Address;
429 Alt.port =
430 (d[sizeof(SERVERBROWSE_HEARTBEAT)]<<8) |
431 d[sizeof(SERVERBROWSE_HEARTBEAT)+1];
433 // add it
434 AddCheckserver(&Packet.m_Address, &Alt, SERVERTYPE_NORMAL);
436 else if(Packet.m_DataSize == sizeof(SERVERBROWSE_HEARTBEAT_LEGACY)+2 &&
437 mem_comp(Packet.m_pData, SERVERBROWSE_HEARTBEAT_LEGACY, sizeof(SERVERBROWSE_HEARTBEAT_LEGACY)) == 0)
439 NETADDR Alt;
440 unsigned char *d = (unsigned char *)Packet.m_pData;
441 Alt = Packet.m_Address;
442 Alt.port =
443 (d[sizeof(SERVERBROWSE_HEARTBEAT)]<<8) |
444 d[sizeof(SERVERBROWSE_HEARTBEAT)+1];
446 // add it
447 AddCheckserver(&Packet.m_Address, &Alt, SERVERTYPE_LEGACY);
450 else if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETCOUNT) &&
451 mem_comp(Packet.m_pData, SERVERBROWSE_GETCOUNT, sizeof(SERVERBROWSE_GETCOUNT)) == 0)
453 dbg_msg("mastersrv", "count requested, responding with %d", m_NumServers);
455 CNetChunk p;
456 p.m_ClientID = -1;
457 p.m_Address = Packet.m_Address;
458 p.m_Flags = NETSENDFLAG_CONNLESS;
459 p.m_DataSize = sizeof(m_CountData);
460 p.m_pData = &m_CountData;
461 m_CountData.m_High = (m_NumServers>>8)&0xff;
462 m_CountData.m_Low = m_NumServers&0xff;
463 m_NetOp.Send(&p);
465 else if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETCOUNT_LEGACY) &&
466 mem_comp(Packet.m_pData, SERVERBROWSE_GETCOUNT_LEGACY, sizeof(SERVERBROWSE_GETCOUNT_LEGACY)) == 0)
468 dbg_msg("mastersrv", "count requested, responding with %d", m_NumServers);
470 CNetChunk p;
471 p.m_ClientID = -1;
472 p.m_Address = Packet.m_Address;
473 p.m_Flags = NETSENDFLAG_CONNLESS;
474 p.m_DataSize = sizeof(m_CountData);
475 p.m_pData = &m_CountDataLegacy;
476 m_CountDataLegacy.m_High = (m_NumServers>>8)&0xff;
477 m_CountDataLegacy.m_Low = m_NumServers&0xff;
478 m_NetOp.Send(&p);
480 else if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETLIST) &&
481 mem_comp(Packet.m_pData, SERVERBROWSE_GETLIST, sizeof(SERVERBROWSE_GETLIST)) == 0)
483 // someone requested the list
484 dbg_msg("mastersrv", "requested, responding with %d m_aServers", m_NumServers);
486 CNetChunk p;
487 p.m_ClientID = -1;
488 p.m_Address = Packet.m_Address;
489 p.m_Flags = NETSENDFLAG_CONNLESS;
491 for(int i = 0; i < m_NumPackets; i++)
493 p.m_DataSize = m_aPackets[i].m_Size;
494 p.m_pData = &m_aPackets[i].m_Data;
495 m_NetOp.Send(&p);
498 else if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETLIST_LEGACY) &&
499 mem_comp(Packet.m_pData, SERVERBROWSE_GETLIST_LEGACY, sizeof(SERVERBROWSE_GETLIST_LEGACY)) == 0)
501 // someone requested the list
502 dbg_msg("mastersrv", "requested, responding with %d m_aServers", m_NumServers);
504 CNetChunk p;
505 p.m_ClientID = -1;
506 p.m_Address = Packet.m_Address;
507 p.m_Flags = NETSENDFLAG_CONNLESS;
509 for(int i = 0; i < m_NumPacketsLegacy; i++)
511 p.m_DataSize = m_aPacketsLegacy[i].m_Size;
512 p.m_pData = &m_aPacketsLegacy[i].m_Data;
513 m_NetOp.Send(&p);
518 // process m_aPackets
519 while(m_NetChecker.Recv(&Packet))
521 // check if the server is banned
522 if(CheckBan(Packet.m_Address)) continue;
524 if(Packet.m_DataSize == sizeof(SERVERBROWSE_FWRESPONSE) &&
525 mem_comp(Packet.m_pData, SERVERBROWSE_FWRESPONSE, sizeof(SERVERBROWSE_FWRESPONSE)) == 0)
527 Type = SERVERTYPE_INVALID;
528 // remove it from checking
529 for(int i = 0; i < m_NumCheckServers; i++)
531 if(net_addr_comp(&m_aCheckServers[i].m_Address, &Packet.m_Address) == 0 ||
532 net_addr_comp(&m_aCheckServers[i].m_AltAddress, &Packet.m_Address) == 0)
534 Type = m_aCheckServers[i].m_Type;
535 m_NumCheckServers--;
536 m_aCheckServers[i] = m_aCheckServers[m_NumCheckServers];
537 break;
541 // drops servers that were not in the CheckServers list
542 if(Type == SERVERTYPE_INVALID)
543 continue;
545 AddServer(&Packet.m_Address, Type);
546 SendOk(&Packet.m_Address);
550 if(time_get()-LastBanReload > time_freq()*300)
552 LastBanReload = time_get();
554 ReloadBans();
557 if(time_get()-LastBuild > time_freq()*5)
559 LastBuild = time_get();
561 PurgeServers();
562 UpdateServers();
563 BuildPackets();
566 // be nice to the CPU
567 thread_sleep(1);
570 return 0;