ddnet/src/mastersrv/mastersrv.cpp

291 lines
7 KiB
C++
Raw Normal View History

2007-11-25 19:42:40 +00:00
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
#include <string.h>
#include <base/system.h>
extern "C" {
2007-12-15 10:24:49 +00:00
#include <engine/e_network.h>
}
#include "mastersrv.h"
enum {
MTU = 1400,
EXPIRE_TIME = 90
};
static struct CHECK_SERVER
2007-07-21 21:28:56 +00:00
{
NETADDR address;
NETADDR alt_address;
2007-07-21 21:28:56 +00:00
int try_count;
int64 try_time;
} check_servers[MAX_SERVERS];
static int num_checkservers = 0;
static struct PACKET_DATA
{
unsigned char header[sizeof(SERVERBROWSE_LIST)];
NETADDR servers[MAX_SERVERS];
} data;
2008-02-10 21:54:52 +00:00
static struct COUNT_PACKET_DATA
2008-02-10 21:54:52 +00:00
{
unsigned char header[sizeof(SERVERBROWSE_COUNT)];
unsigned char high;
unsigned char low;
} count_data;
static int64 server_expire[MAX_SERVERS];
static int num_servers = 0;
2007-07-21 21:28:56 +00:00
static net_client net_checker; // NAT/FW checker
static net_client net_op; // main
void send_ok(NETADDR *addr)
2007-07-21 21:28:56 +00:00
{
NETCHUNK p;
2007-07-21 21:28:56 +00:00
p.client_id = -1;
p.address = *addr;
p.flags = NETSENDFLAG_CONNLESS;
2007-07-21 21:28:56 +00:00
p.data_size = sizeof(SERVERBROWSE_FWOK);
p.data = SERVERBROWSE_FWOK;
2008-02-10 21:54:52 +00:00
// send on both to be sure
net_checker.send(&p);
2007-07-21 21:28:56 +00:00
net_op.send(&p);
}
void send_error(NETADDR *addr)
2007-07-21 21:28:56 +00:00
{
NETCHUNK p;
2007-07-21 21:28:56 +00:00
p.client_id = -1;
p.address = *addr;
p.flags = NETSENDFLAG_CONNLESS;
2007-07-21 21:28:56 +00:00
p.data_size = sizeof(SERVERBROWSE_FWERROR);
p.data = SERVERBROWSE_FWERROR;
net_op.send(&p);
}
void send_check(NETADDR *addr)
2007-07-21 21:28:56 +00:00
{
NETCHUNK p;
2007-07-21 21:28:56 +00:00
p.client_id = -1;
p.address = *addr;
p.flags = NETSENDFLAG_CONNLESS;
2007-07-21 21:28:56 +00:00
p.data_size = sizeof(SERVERBROWSE_FWCHECK);
p.data = SERVERBROWSE_FWCHECK;
net_checker.send(&p);
}
void add_checkserver(NETADDR *info, NETADDR *alt)
2007-07-21 21:28:56 +00:00
{
// add server
if(num_checkservers == MAX_SERVERS)
{
dbg_msg("mastersrv", "error: mastersrv is full");
return;
}
dbg_msg("mastersrv", "checking: %d.%d.%d.%d:%d (%d.%d.%d.%d:%d)",
info->ip[0], info->ip[1], info->ip[2], info->ip[3], info->port,
alt->ip[0], alt->ip[1], alt->ip[2], alt->ip[3], alt->port);
2007-07-21 21:28:56 +00:00
check_servers[num_checkservers].address = *info;
check_servers[num_checkservers].alt_address = *alt;
2007-07-21 21:28:56 +00:00
check_servers[num_checkservers].try_count = 0;
check_servers[num_checkservers].try_time = 0;
num_checkservers++;
}
void add_server(NETADDR *info)
{
// see if server already exists in list
int i;
for(i = 0; i < num_servers; i++)
{
if(net_addr_comp(&data.servers[i], info) == 0)
{
dbg_msg("mastersrv", "updated: %d.%d.%d.%d:%d",
info->ip[0], info->ip[1], info->ip[2], info->ip[3], info->port);
server_expire[i] = time_get()+time_freq()*EXPIRE_TIME;
return;
}
}
// add server
if(num_servers == MAX_SERVERS)
{
dbg_msg("mastersrv", "error: mastersrv is full");
return;
}
dbg_msg("mastersrv", "added: %d.%d.%d.%d:%d",
info->ip[0], info->ip[1], info->ip[2], info->ip[3], info->port);
data.servers[num_servers] = *info;
server_expire[num_servers] = time_get()+time_freq()*EXPIRE_TIME;
num_servers++;
}
2007-07-21 21:28:56 +00:00
void update_servers()
{
int64 now = time_get();
int64 freq = time_freq();
for(int i = 0; i < num_checkservers; i++)
{
if(now > check_servers[i].try_time+freq)
{
if(check_servers[i].try_count == 10)
2007-07-21 21:28:56 +00:00
{
dbg_msg("mastersrv", "check failed: %d.%d.%d.%d:%d",
check_servers[i].address.ip[0], check_servers[i].address.ip[1],
check_servers[i].address.ip[2], check_servers[i].address.ip[3],check_servers[i].address.port,
check_servers[i].alt_address.ip[0], check_servers[i].alt_address.ip[1],
check_servers[i].alt_address.ip[2], check_servers[i].alt_address.ip[3],check_servers[i].alt_address.port);
2007-07-21 21:28:56 +00:00
// FAIL!!
send_error(&check_servers[i].address);
check_servers[i] = check_servers[num_checkservers-1];
num_checkservers--;
i--;
}
else
{
check_servers[i].try_count++;
check_servers[i].try_time = now;
if(check_servers[i].try_count&1)
send_check(&check_servers[i].address);
else
send_check(&check_servers[i].alt_address);
2007-07-21 21:28:56 +00:00
}
}
}
}
void purge_servers()
{
int64 now = time_get();
int i = 0;
while(i < num_servers)
{
if(server_expire[i] < now)
{
// remove server
dbg_msg("mastersrv", "expired: %d.%d.%d.%d:%d",
data.servers[i].ip[0], data.servers[i].ip[1],
data.servers[i].ip[2], data.servers[i].ip[3], data.servers[i].port);
data.servers[i] = data.servers[num_servers-1];
server_expire[i] = server_expire[num_servers-1];
num_servers--;
}
else
i++;
}
}
int main(int argc, char **argv)
{
NETADDR bindaddr;
2008-10-01 18:34:43 +00:00
dbg_logger_stdout();
net_init();
mem_zero(&bindaddr, sizeof(bindaddr));
bindaddr.port = MASTERSERVER_PORT;
2008-10-01 18:34:43 +00:00
net_op.open(bindaddr, 0);
bindaddr.port = MASTERSERVER_PORT+1;
net_checker.open(bindaddr, 0);
// TODO: check socket for errors
mem_copy(data.header, SERVERBROWSE_LIST, sizeof(SERVERBROWSE_LIST));
2008-02-10 21:54:52 +00:00
mem_copy(count_data.header, SERVERBROWSE_COUNT, sizeof(SERVERBROWSE_COUNT));
dbg_msg("mastersrv", "started");
while(1)
{
2007-07-21 21:28:56 +00:00
net_op.update();
net_checker.update();
// process packets
NETCHUNK packet;
2007-07-21 21:28:56 +00:00
while(net_op.recv(&packet))
{
if(packet.data_size == sizeof(SERVERBROWSE_HEARTBEAT)+2 &&
memcmp(packet.data, SERVERBROWSE_HEARTBEAT, sizeof(SERVERBROWSE_HEARTBEAT)) == 0)
{
NETADDR alt;
unsigned char *d = (unsigned char *)packet.data;
alt = packet.address;
alt.port =
(d[sizeof(SERVERBROWSE_HEARTBEAT)]<<8) |
d[sizeof(SERVERBROWSE_HEARTBEAT)+1];
// add it
add_checkserver(&packet.address, &alt);
}
2008-02-10 21:54:52 +00:00
else if(packet.data_size == sizeof(SERVERBROWSE_GETCOUNT) &&
memcmp(packet.data, SERVERBROWSE_GETCOUNT, sizeof(SERVERBROWSE_GETCOUNT)) == 0)
{
dbg_msg("mastersrv", "count requested, responding with %d", num_servers);
NETCHUNK p;
2008-02-10 21:54:52 +00:00
p.client_id = -1;
p.address = packet.address;
p.flags = NETSENDFLAG_CONNLESS;
2008-02-10 21:54:52 +00:00
p.data_size = sizeof(count_data);
p.data = &count_data;
count_data.high = (num_servers>>8)&0xff;
count_data.low = num_servers&0xff;
net_op.send(&p);
}
else if(packet.data_size == sizeof(SERVERBROWSE_GETLIST) &&
memcmp(packet.data, SERVERBROWSE_GETLIST, sizeof(SERVERBROWSE_GETLIST)) == 0)
{
// someone requested the list
dbg_msg("mastersrv", "requested, responding with %d servers", num_servers);
NETCHUNK p;
p.client_id = -1;
p.address = packet.address;
p.flags = NETSENDFLAG_CONNLESS;
p.data_size = num_servers*sizeof(NETADDR)+sizeof(SERVERBROWSE_LIST);
p.data = &data;
2007-07-21 21:28:56 +00:00
net_op.send(&p);
}
2007-07-21 21:28:56 +00:00
}
2007-07-21 21:28:56 +00:00
// process packets
while(net_checker.recv(&packet))
{
if(packet.data_size == sizeof(SERVERBROWSE_FWRESPONSE) &&
memcmp(packet.data, SERVERBROWSE_FWRESPONSE, sizeof(SERVERBROWSE_FWRESPONSE)) == 0)
{
// remove it from checking
for(int i = 0; i < num_checkservers; i++)
{
if(net_addr_comp(&check_servers[i].address, &packet.address) == 0 ||
net_addr_comp(&check_servers[i].alt_address, &packet.address) == 0)
2007-07-21 21:28:56 +00:00
{
num_checkservers--;
check_servers[i] = check_servers[num_checkservers];
break;
}
}
add_server(&packet.address);
send_ok(&packet.address);
}
}
// TODO: shouldn't be done every fuckin frame
purge_servers();
2007-07-21 21:28:56 +00:00
update_servers();
// be nice to the CPU
thread_sleep(1);
}
return 0;
}