2007-11-25 19:42:40 +00:00
|
|
|
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
|
2007-07-21 18:07:27 +00:00
|
|
|
#include <string.h>
|
2008-08-14 17:19:13 +00:00
|
|
|
#include <base/system.h>
|
2007-08-22 07:52:33 +00:00
|
|
|
|
|
|
|
extern "C" {
|
2007-12-15 10:24:49 +00:00
|
|
|
#include <engine/e_network.h>
|
2007-08-22 07:52:33 +00:00
|
|
|
}
|
2007-07-21 18:07:27 +00:00
|
|
|
|
|
|
|
#include "mastersrv.h"
|
|
|
|
|
|
|
|
enum {
|
|
|
|
MTU = 1400,
|
2008-11-15 13:29:56 +00:00
|
|
|
MAX_SERVERS_PER_PACKET=128,
|
|
|
|
MAX_PACKETS=16,
|
|
|
|
MAX_SERVERS=MAX_SERVERS_PER_PACKET*MAX_PACKETS,
|
2007-07-21 18:07:27 +00:00
|
|
|
EXPIRE_TIME = 90
|
|
|
|
};
|
|
|
|
|
2008-07-06 11:21:21 +00:00
|
|
|
static struct CHECK_SERVER
|
2007-07-21 21:28:56 +00:00
|
|
|
{
|
2008-07-06 11:21:21 +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;
|
|
|
|
|
2008-11-15 13:29:56 +00:00
|
|
|
|
|
|
|
typedef struct NETADDR_IPv4
|
|
|
|
{
|
|
|
|
unsigned char ip[4];
|
|
|
|
unsigned short port;
|
|
|
|
} NETADDR_IPv4;
|
|
|
|
|
|
|
|
static struct SERVER_ENTRY
|
|
|
|
{
|
|
|
|
NETADDR address;
|
|
|
|
int64 expire;
|
|
|
|
} servers[MAX_SERVERS];
|
|
|
|
static int num_servers = 0;
|
|
|
|
|
2008-07-06 11:21:21 +00:00
|
|
|
static struct PACKET_DATA
|
2007-07-21 18:07:27 +00:00
|
|
|
{
|
2008-11-15 13:29:56 +00:00
|
|
|
int size;
|
|
|
|
struct {
|
|
|
|
unsigned char header[sizeof(SERVERBROWSE_LIST)];
|
|
|
|
NETADDR_IPv4 servers[MAX_SERVERS_PER_PACKET];
|
|
|
|
} data;
|
|
|
|
} packets[MAX_PACKETS];
|
|
|
|
static int num_packets = 0;
|
2008-02-10 21:54:52 +00:00
|
|
|
|
2008-07-06 11:21:21 +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;
|
|
|
|
|
2008-11-15 13:29:56 +00:00
|
|
|
//static int64 server_expire[MAX_SERVERS];
|
2007-07-21 18:07:27 +00:00
|
|
|
|
2007-07-21 21:28:56 +00:00
|
|
|
static net_client net_checker; // NAT/FW checker
|
|
|
|
static net_client net_op; // main
|
|
|
|
|
2008-11-15 13:29:56 +00:00
|
|
|
void build_packets()
|
|
|
|
{
|
|
|
|
SERVER_ENTRY *current = &servers[0];
|
|
|
|
int servers_left = num_servers;
|
|
|
|
int i;
|
|
|
|
num_packets = 0;
|
|
|
|
while(servers_left && num_packets < MAX_PACKETS)
|
|
|
|
{
|
|
|
|
int chunk = servers_left;
|
|
|
|
if(chunk > MAX_SERVERS_PER_PACKET)
|
|
|
|
chunk = MAX_SERVERS_PER_PACKET;
|
|
|
|
servers_left -= chunk;
|
|
|
|
|
|
|
|
// copy header
|
|
|
|
mem_copy(packets[num_packets].data.header, SERVERBROWSE_LIST, sizeof(SERVERBROWSE_LIST));
|
|
|
|
|
|
|
|
// copy server addresses
|
|
|
|
for(i = 0; i < chunk; i++)
|
|
|
|
{
|
|
|
|
// TODO: ipv6 support
|
|
|
|
packets[num_packets].data.servers[i].ip[0] = current->address.ip[0];
|
|
|
|
packets[num_packets].data.servers[i].ip[1] = current->address.ip[1];
|
|
|
|
packets[num_packets].data.servers[i].ip[2] = current->address.ip[2];
|
|
|
|
packets[num_packets].data.servers[i].ip[3] = current->address.ip[3];
|
|
|
|
packets[num_packets].data.servers[i].port = current->address.port;
|
|
|
|
current++;
|
|
|
|
}
|
|
|
|
|
|
|
|
packets[num_packets].size = sizeof(SERVERBROWSE_LIST) + sizeof(NETADDR_IPv4)*chunk;
|
|
|
|
|
|
|
|
num_packets++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-06 11:21:21 +00:00
|
|
|
void send_ok(NETADDR *addr)
|
2007-07-21 21:28:56 +00:00
|
|
|
{
|
2008-04-05 14:50:43 +00:00
|
|
|
NETCHUNK p;
|
2007-07-21 21:28:56 +00:00
|
|
|
p.client_id = -1;
|
|
|
|
p.address = *addr;
|
2008-04-05 14:50:43 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2008-07-06 11:21:21 +00:00
|
|
|
void send_error(NETADDR *addr)
|
2007-07-21 21:28:56 +00:00
|
|
|
{
|
2008-04-05 14:50:43 +00:00
|
|
|
NETCHUNK p;
|
2007-07-21 21:28:56 +00:00
|
|
|
p.client_id = -1;
|
|
|
|
p.address = *addr;
|
2008-04-05 14:50:43 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2008-07-06 11:21:21 +00:00
|
|
|
void send_check(NETADDR *addr)
|
2007-07-21 21:28:56 +00:00
|
|
|
{
|
2008-04-05 14:50:43 +00:00
|
|
|
NETCHUNK p;
|
2007-07-21 21:28:56 +00:00
|
|
|
p.client_id = -1;
|
|
|
|
p.address = *addr;
|
2008-04-05 14:50:43 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2008-07-06 11:21:21 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-12-13 20:07:23 +00:00
|
|
|
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;
|
2007-12-13 20:07:23 +00:00
|
|
|
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++;
|
|
|
|
}
|
2007-07-21 18:07:27 +00:00
|
|
|
|
2008-07-06 11:21:21 +00:00
|
|
|
void add_server(NETADDR *info)
|
2007-07-21 18:07:27 +00:00
|
|
|
{
|
|
|
|
// see if server already exists in list
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < num_servers; i++)
|
|
|
|
{
|
2008-11-15 13:29:56 +00:00
|
|
|
if(net_addr_comp(&servers[i].address, info) == 0)
|
2007-07-21 18:07:27 +00:00
|
|
|
{
|
|
|
|
dbg_msg("mastersrv", "updated: %d.%d.%d.%d:%d",
|
|
|
|
info->ip[0], info->ip[1], info->ip[2], info->ip[3], info->port);
|
2008-11-15 13:29:56 +00:00
|
|
|
servers[i].expire = time_get()+time_freq()*EXPIRE_TIME;
|
2007-07-21 18:07:27 +00:00
|
|
|
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);
|
2008-11-15 13:29:56 +00:00
|
|
|
servers[num_servers].address = *info;
|
|
|
|
servers[num_servers].expire = time_get()+time_freq()*EXPIRE_TIME;
|
2007-07-21 18:07:27 +00:00
|
|
|
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)
|
|
|
|
{
|
2007-12-13 20:07:23 +00:00
|
|
|
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],
|
2007-12-13 20:07:23 +00:00
|
|
|
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;
|
2007-12-13 20:08:08 +00:00
|
|
|
if(check_servers[i].try_count&1)
|
2007-12-13 20:07:23 +00:00
|
|
|
send_check(&check_servers[i].address);
|
2007-12-13 20:08:08 +00:00
|
|
|
else
|
|
|
|
send_check(&check_servers[i].alt_address);
|
2007-07-21 21:28:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-21 18:07:27 +00:00
|
|
|
void purge_servers()
|
|
|
|
{
|
|
|
|
int64 now = time_get();
|
|
|
|
int i = 0;
|
|
|
|
while(i < num_servers)
|
|
|
|
{
|
2008-11-15 13:29:56 +00:00
|
|
|
if(servers[i].expire < now)
|
2007-07-21 18:07:27 +00:00
|
|
|
{
|
|
|
|
// remove server
|
|
|
|
dbg_msg("mastersrv", "expired: %d.%d.%d.%d:%d",
|
2008-11-15 13:29:56 +00:00
|
|
|
servers[i].address.ip[0], servers[i].address.ip[1],
|
|
|
|
servers[i].address.ip[2], servers[i].address.ip[3], servers[i].address.port);
|
|
|
|
servers[i] = servers[num_servers-1];
|
2007-07-21 18:07:27 +00:00
|
|
|
num_servers--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
2008-11-15 13:29:56 +00:00
|
|
|
int64 last_build = 0;
|
2008-07-06 11:21:21 +00:00
|
|
|
NETADDR bindaddr;
|
2008-10-01 18:34:43 +00:00
|
|
|
|
|
|
|
dbg_logger_stdout();
|
|
|
|
net_init();
|
|
|
|
|
2007-08-05 14:19:13 +00:00
|
|
|
mem_zero(&bindaddr, sizeof(bindaddr));
|
|
|
|
bindaddr.port = MASTERSERVER_PORT;
|
|
|
|
|
2008-10-01 18:34:43 +00:00
|
|
|
|
2007-08-05 14:19:13 +00:00
|
|
|
net_op.open(bindaddr, 0);
|
|
|
|
|
|
|
|
bindaddr.port = MASTERSERVER_PORT+1;
|
|
|
|
net_checker.open(bindaddr, 0);
|
2007-07-21 18:07:27 +00:00
|
|
|
// TODO: check socket for errors
|
|
|
|
|
2008-11-15 13:29:56 +00:00
|
|
|
//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));
|
|
|
|
|
2007-07-21 18:07:27 +00:00
|
|
|
dbg_msg("mastersrv", "started");
|
|
|
|
|
|
|
|
while(1)
|
|
|
|
{
|
2007-07-21 21:28:56 +00:00
|
|
|
net_op.update();
|
|
|
|
net_checker.update();
|
2007-07-21 18:07:27 +00:00
|
|
|
|
|
|
|
// process packets
|
2008-04-05 14:50:43 +00:00
|
|
|
NETCHUNK packet;
|
2007-07-21 21:28:56 +00:00
|
|
|
while(net_op.recv(&packet))
|
2007-07-21 18:07:27 +00:00
|
|
|
{
|
2007-12-13 20:07:23 +00:00
|
|
|
if(packet.data_size == sizeof(SERVERBROWSE_HEARTBEAT)+2 &&
|
2007-07-21 18:07:27 +00:00
|
|
|
memcmp(packet.data, SERVERBROWSE_HEARTBEAT, sizeof(SERVERBROWSE_HEARTBEAT)) == 0)
|
|
|
|
{
|
2008-07-06 11:21:21 +00:00
|
|
|
NETADDR alt;
|
2007-12-13 20:07:23 +00:00
|
|
|
unsigned char *d = (unsigned char *)packet.data;
|
|
|
|
alt = packet.address;
|
|
|
|
alt.port =
|
|
|
|
(d[sizeof(SERVERBROWSE_HEARTBEAT)]<<8) |
|
|
|
|
d[sizeof(SERVERBROWSE_HEARTBEAT)+1];
|
|
|
|
|
2007-07-21 18:07:27 +00:00
|
|
|
// add it
|
2007-12-13 20:07:23 +00:00
|
|
|
add_checkserver(&packet.address, &alt);
|
2007-07-21 18:07:27 +00:00
|
|
|
}
|
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);
|
|
|
|
|
2008-04-05 14:50:43 +00:00
|
|
|
NETCHUNK p;
|
2008-02-10 21:54:52 +00:00
|
|
|
p.client_id = -1;
|
|
|
|
p.address = packet.address;
|
2008-04-05 14:50:43 +00:00
|
|
|
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);
|
|
|
|
}
|
2007-07-21 18:07:27 +00:00
|
|
|
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);
|
2008-04-05 14:50:43 +00:00
|
|
|
NETCHUNK p;
|
2007-07-21 18:07:27 +00:00
|
|
|
p.client_id = -1;
|
|
|
|
p.address = packet.address;
|
2008-04-05 14:50:43 +00:00
|
|
|
p.flags = NETSENDFLAG_CONNLESS;
|
2008-11-15 13:29:56 +00:00
|
|
|
|
|
|
|
for(int i = 0; i < num_packets; i++)
|
|
|
|
{
|
|
|
|
p.data_size = packets[i].size;
|
|
|
|
p.data = &packets[i].data;
|
|
|
|
net_op.send(&p);
|
|
|
|
}
|
2007-07-21 18:07:27 +00:00
|
|
|
}
|
2007-07-21 21:28:56 +00:00
|
|
|
}
|
2007-07-21 18:07:27 +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++)
|
|
|
|
{
|
2008-07-06 11:21:21 +00:00
|
|
|
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);
|
|
|
|
}
|
2007-07-21 18:07:27 +00:00
|
|
|
}
|
|
|
|
|
2008-11-15 13:29:56 +00:00
|
|
|
if(time_get()-last_build > time_freq()*5)
|
|
|
|
{
|
|
|
|
last_build = time_get();
|
|
|
|
|
|
|
|
purge_servers();
|
|
|
|
update_servers();
|
|
|
|
build_packets();
|
|
|
|
}
|
2007-07-21 18:07:27 +00:00
|
|
|
|
|
|
|
// be nice to the CPU
|
|
|
|
thread_sleep(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|