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"
14 MAX_SERVERS_PER_PACKET
=75,
16 MAX_SERVERS
=MAX_SERVERS_PER_PACKET
*MAX_PACKETS
,
23 enum ServerType m_Type
;
30 static CCheckServer m_aCheckServers
[MAX_SERVERS
];
31 static int m_NumCheckServers
= 0;
35 enum ServerType m_Type
;
40 static CServerEntry m_aServers
[MAX_SERVERS
];
41 static int m_NumServers
= 0;
47 unsigned char m_aHeader
[sizeof(SERVERBROWSE_LIST
)];
48 CMastersrvAddr m_aServers
[MAX_SERVERS_PER_PACKET
];
52 CPacketData m_aPackets
[MAX_PACKETS
];
53 static int m_NumPackets
= 0;
56 struct CPacketDataLegacy
60 unsigned char m_aHeader
[sizeof(SERVERBROWSE_LIST_LEGACY
)];
61 CMastersrvAddrLegacy m_aServers
[MAX_SERVERS_PER_PACKET
];
65 CPacketDataLegacy m_aPacketsLegacy
[MAX_PACKETS
];
66 static int m_NumPacketsLegacy
= 0;
69 struct CCountPacketData
71 unsigned char m_Header
[sizeof(SERVERBROWSE_COUNT
)];
76 static CCountPacketData m_CountData
;
77 static CCountPacketData m_CountDataLegacy
;
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
96 CServerEntry
*pCurrent
= &m_aServers
[0];
97 int ServersLeft
= m_NumServers
;
99 m_NumPacketsLegacy
= 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)
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
));
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;
137 m_aPackets
[m_NumPackets
-1].m_Size
= sizeof(SERVERBROWSE_LIST
) + sizeof(CMastersrvAddr
)*PacketIndex
;
141 else if(pCurrent
->m_Type
== SERVERTYPE_LEGACY
)
143 if(PacketIndexLegacy
% MAX_SERVERS_PER_PACKET
== 0)
145 PacketIndexLegacy
= 0;
146 m_NumPacketsLegacy
++;
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;
161 m_aPacketsLegacy
[m_NumPacketsLegacy
-1].m_Size
= sizeof(SERVERBROWSE_LIST_LEGACY
) + sizeof(CMastersrvAddrLegacy
)*PacketIndexLegacy
;
167 *pCurrent
= m_aServers
[m_NumServers
-1];
169 dbg_msg("mastersrv", "error: server of invalid type, dropping it");
174 void SendOk(NETADDR
*pAddr
)
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
);
188 void SendError(NETADDR
*pAddr
)
192 p
.m_Address
= *pAddr
;
193 p
.m_Flags
= NETSENDFLAG_CONNLESS
;
194 p
.m_DataSize
= sizeof(SERVERBROWSE_FWERROR
);
195 p
.m_pData
= SERVERBROWSE_FWERROR
;
199 void SendCheck(NETADDR
*pAddr
)
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
)
213 if(m_NumCheckServers
== MAX_SERVERS
)
215 dbg_msg("mastersrv", "error: mastersrv is full");
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
;
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
;
248 if(m_NumServers
== MAX_SERVERS
)
250 dbg_msg("mastersrv", "error: mastersrv is full");
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
;
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
);
280 SendError(&m_aCheckServers
[i
].m_Address
);
281 m_aCheckServers
[i
] = m_aCheckServers
[m_NumCheckServers
-1];
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
);
292 SendCheck(&m_aCheckServers
[i
].m_AltAddress
);
300 int64 Now
= time_get();
302 while(i
< m_NumServers
)
304 if(m_aServers
[i
].m_Expire
< Now
)
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];
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)
328 for(int i
= 0; i
< m_NumBans
; i
++)
330 if(net_addr_comp(&m_aBans
[i
].m_Address
, &Addr
) == 0)
338 void ConAddBan(IConsole::IResult
*pResult
, void *pUser
)
340 if(m_NumBans
== MAX_BANS
)
342 dbg_msg("mastersrv", "error: banlist is full");
346 if(net_addr_from_str(&m_aBans
[m_NumBans
].m_Address
, pResult
->GetString(0)) != 0)
348 dbg_msg("mastersrv", "error: invalid address");
352 if(CheckBan(m_aBans
[m_NumBans
].m_Address
))
354 dbg_msg("mastersrv", "duplicate ban: %s", pResult
->GetString(0));
358 dbg_msg("mastersrv", "ban added: %s", pResult
->GetString(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
;
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)");
387 BindAddr
.port
= MASTERSERVER_PORT
+1;
388 if(!m_NetChecker
.Open(BindAddr
, 0))
390 dbg_msg("mastersrv", "couldn't start network (checker)");
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
);
409 dbg_msg("mastersrv", "started");
414 m_NetChecker
.Update();
416 // process m_aPackets
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)
427 unsigned char *d
= (unsigned char *)Packet
.m_pData
;
428 Alt
= Packet
.m_Address
;
430 (d
[sizeof(SERVERBROWSE_HEARTBEAT
)]<<8) |
431 d
[sizeof(SERVERBROWSE_HEARTBEAT
)+1];
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)
440 unsigned char *d
= (unsigned char *)Packet
.m_pData
;
441 Alt
= Packet
.m_Address
;
443 (d
[sizeof(SERVERBROWSE_HEARTBEAT
)]<<8) |
444 d
[sizeof(SERVERBROWSE_HEARTBEAT
)+1];
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
);
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;
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
);
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;
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
);
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
;
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
);
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
;
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
;
536 m_aCheckServers
[i
] = m_aCheckServers
[m_NumCheckServers
];
541 // drops servers that were not in the CheckServers list
542 if(Type
== SERVERTYPE_INVALID
)
545 AddServer(&Packet
.m_Address
, Type
);
546 SendOk(&Packet
.m_Address
);
550 if(time_get()-LastBanReload
> time_freq()*300)
552 LastBanReload
= time_get();
557 if(time_get()-LastBuild
> time_freq()*5)
559 LastBuild
= time_get();
566 // be nice to the CPU