From 548a919ea379a3b9d1d9e41cf4dad6b4779fd3e6 Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Sun, 10 Feb 2008 21:54:52 +0000 Subject: [PATCH] merged 0.3.4 changes to trunk --- src/engine/client/ec_client.c | 33 +++- src/engine/client/ec_srvbrowse.c | 20 ++- src/engine/e_config.c | 72 +-------- src/engine/e_config_variables.h | 2 +- src/engine/e_engine.c | 215 +++++++++++++++++++++++++- src/engine/e_engine.h | 17 ++ src/engine/e_linereader.c | 62 ++++++++ src/engine/e_linereader.h | 14 ++ src/engine/e_system.c | 47 ++++++ src/engine/e_system.h | 13 +- src/engine/server/es_register.c | 258 +++++++++++++++++++++++++++++++ src/engine/server/es_server.c | 100 +++--------- src/game/server/gs_server.cpp | 3 + src/mastersrv/mastersrv.cpp | 28 ++++ src/mastersrv/mastersrv.h | 3 + src/tools/fake_server.c | 27 ++-- 16 files changed, 735 insertions(+), 179 deletions(-) create mode 100644 src/engine/e_linereader.c create mode 100644 src/engine/e_linereader.h create mode 100644 src/engine/server/es_register.c diff --git a/src/engine/client/ec_client.c b/src/engine/client/ec_client.c index 9c63f7cbf..f93cb5e5a 100644 --- a/src/engine/client/ec_client.c +++ b/src/engine/client/ec_client.c @@ -1098,12 +1098,36 @@ static void client_update() } /* STRESS TEST: join the server again */ - if(client_state() == CLIENTSTATE_OFFLINE && config.dbg_stress && (frames%100) == 0) - client_connect(config.dbg_stress_server); + if(config.dbg_stress) + { + static int64 action_taken = 0; + int64 now = time_get(); + if(client_state() == CLIENTSTATE_OFFLINE) + { + if(now > action_taken+time_freq()*2) + { + dbg_msg("stress", "reconnecting!"); + client_connect(config.dbg_stress_server); + action_taken = now; + } + } + else + { + if(now > action_taken+time_freq()*(10+config.dbg_stress)) + { + dbg_msg("stress", "disconnecting!"); + client_disconnect(); + action_taken = now; + } + } + } /* pump the network */ client_pump_network(); + /* update the maser server registry */ + mastersrv_update(); + /* update the server browser */ client_serverbrowse_update(); } @@ -1128,12 +1152,15 @@ static void client_run() if(!gfx_init()) return; + /* start refreshing addresses while we load */ + mastersrv_refresh_addresses(); + /* init the editor */ editor_init(); /* sound is allowed to fail */ snd_init(); - + /* load data */ if(!client_load_data()) return; diff --git a/src/engine/client/ec_srvbrowse.c b/src/engine/client/ec_srvbrowse.c index 74d09b8d6..0a6ebbf89 100644 --- a/src/engine/client/ec_srvbrowse.c +++ b/src/engine/client/ec_srvbrowse.c @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -341,18 +342,27 @@ void client_serverbrowse_refresh(int lan) } else { - NETADDR4 master_server; + NETADDR4 addr; NETPACKET p; - - net_host_lookup(config.masterserver, MASTERSERVER_PORT, &master_server); + int i; + + /*net_host_lookup(config.masterserver, MASTERSERVER_PORT, &master_server);*/ mem_zero(&p, sizeof(p)); p.client_id = -1; - p.address = master_server; p.flags = PACKETFLAG_CONNLESS; p.data_size = sizeof(SERVERBROWSE_GETLIST); p.data = SERVERBROWSE_GETLIST; - netclient_send(net, &p); + + for(i = 0; i < MAX_MASTERSERVERS; i++) + { + addr = mastersrv_get(i); + if(!addr.ip[0] && !addr.ip[1] && !addr.ip[2] && !addr.ip[3]) + continue; + + p.address = addr; + netclient_send(net, &p); + } if(config.debug) dbg_msg("client", "requesting server list"); diff --git a/src/engine/e_config.c b/src/engine/e_config.c index 44008b776..ddb6c7424 100644 --- a/src/engine/e_config.c +++ b/src/engine/e_config.c @@ -6,77 +6,7 @@ #include "e_system.h" #include "e_config.h" - -/* buffered stream for reading lines, should perhaps be something smaller */ -typedef struct -{ - char buffer[4*1024]; - unsigned buffer_pos; - unsigned buffer_size; - unsigned buffer_max_size; - IOHANDLE io; -} LINEREADER; - -void linereader_init(LINEREADER *lr, IOHANDLE io) -{ - lr->buffer_max_size = 4*1024; - lr->buffer_size = 0; - lr->buffer_pos = 0; - lr->io = io; -} - -char *linereader_get(LINEREADER *lr) -{ - unsigned line_start = lr->buffer_pos; - - while(1) - { - if(lr->buffer_pos >= lr->buffer_size) - { - /* fetch more */ - - /* move the remaining part to the front */ - unsigned read; - unsigned left = lr->buffer_size - line_start; - - if(line_start > lr->buffer_size) - left = 0; - if(left) - mem_move(lr->buffer, &lr->buffer[line_start], left); - lr->buffer_pos = left; - - /* fill the buffer */ - read = io_read(lr->io, &lr->buffer[lr->buffer_pos], lr->buffer_max_size-lr->buffer_pos); - lr->buffer_size = left + read; - line_start = 0; - - if(!read) - { - if(left) - { - lr->buffer[left] = 0; /* return the last line */ - lr->buffer_pos = left; - lr->buffer_size = left; - return lr->buffer; - } - else - return 0x0; /* we are done! */ - } - } - else - { - if(lr->buffer[lr->buffer_pos] == '\n' || lr->buffer[lr->buffer_pos] == '\r') - { - /* line found */ - lr->buffer[lr->buffer_pos] = 0; - lr->buffer_pos++; - return &lr->buffer[line_start]; - } - else - lr->buffer_pos++; - } - } -} +#include "e_linereader.h" CONFIGURATION config; diff --git a/src/engine/e_config_variables.h b/src/engine/e_config_variables.h index 7271c5301..01b35dc03 100644 --- a/src/engine/e_config_variables.h +++ b/src/engine/e_config_variables.h @@ -46,7 +46,7 @@ MACRO_CONFIG_INT(gfx_debug_resizable, 0, 0, 0) MACRO_CONFIG_INT(key_screenshot, 267, 32, 512) MACRO_CONFIG_INT(inp_mousesens, 100, 5, 100000) -MACRO_CONFIG_STR(masterserver, 128, "master.teewars.com") +/*MACRO_CONFIG_STR(masterserver, 128, "master.teewars.com")*/ MACRO_CONFIG_STR(sv_name, 128, "unnamed server") MACRO_CONFIG_STR(sv_bindaddr, 128, "") diff --git a/src/engine/e_engine.c b/src/engine/e_engine.c index f4f1ed3b8..b85f1eb33 100644 --- a/src/engine/e_engine.c +++ b/src/engine/e_engine.c @@ -7,7 +7,8 @@ /*#include */ #include #include - +#include +#include "e_linereader.h" static void con_dbg_dumpmem(void *result, void *user_data) { @@ -24,7 +25,7 @@ const char *engine_savepath(const char *filename, char *buffer, int max) } -void engine_init(const char *appname, int argc, char **argv) +void engine_init(const char *appname) { dbg_msg("engine", "running on %s-%s-%s", CONF_FAMILY_STRING, CONF_PLATFORM_STRING, CONF_ARCH_STRING); #ifdef CONF_ARCH_ENDIAN_LITTLE @@ -37,7 +38,7 @@ void engine_init(const char *appname, int argc, char **argv) /* init the network */ net_init(); - + /* create storage location */ { char path[1024] = {0}; @@ -92,6 +93,10 @@ void engine_parse_arguments(int argc, char **argv) for(i = 1; i < argc; i++) config_set(argv[i]); } + + /* set default servers and load from disk*/ + mastersrv_default(); + mastersrv_load(); } void engine_writeconfig() @@ -175,3 +180,207 @@ void perf_dump(PERFORMACE_INFO *top) { perf_dump_imp(top, 0); } + +/* master server functions */ +enum +{ + NUM_LOOKUP_THREADS=4, + + STATE_PROCESSED=0, + STATE_RESULT, + STATE_QUERYING +}; + +typedef struct +{ + char hostname[128]; + NETADDR4 addr; + + /* these are used for lookups */ + struct { + NETADDR4 addr; + int result; + void *thread; + volatile int state; + } lookup; +} MASTER_INFO; + +typedef struct +{ + int start; + int num; +} THREAD_INFO; + +static MASTER_INFO master_servers[MAX_MASTERSERVERS] = {{{0}}}; +static THREAD_INFO thread_info[NUM_LOOKUP_THREADS]; +static int needs_update = 0; + +void lookup_thread(void *user) +{ + THREAD_INFO *info = (THREAD_INFO *)user; + int i; + + for(i = 0; i < info->num; i++) + { + int index = info->start+i; + master_servers[index].lookup.result = net_host_lookup(master_servers[index].hostname, 8300, &master_servers[index].lookup.addr); + master_servers[index].lookup.state = STATE_RESULT; + } +} + +int mastersrv_refresh_addresses() +{ + int i; + dbg_msg("engine/mastersrv", "refreshing master server addresses"); + + /* spawn threads that does the lookups */ + for(i = 0; i < NUM_LOOKUP_THREADS; i++) + { + thread_info[i].start = MAX_MASTERSERVERS/NUM_LOOKUP_THREADS * i; + thread_info[i].num = MAX_MASTERSERVERS/NUM_LOOKUP_THREADS; + master_servers[i].lookup.state = STATE_QUERYING; + master_servers[i].lookup.thread = thread_create(lookup_thread, &thread_info[i]); + } + + needs_update = 1; + return 0; +} + +void mastersrv_update() +{ + int i; + + /* check if we need to update */ + if(!needs_update) + return; + needs_update = 0; + + for(i = 0; i < MAX_MASTERSERVERS; i++) + { + if(master_servers[i].lookup.state == STATE_RESULT) + { + /* we got a result from the lookup ready */ + if(master_servers[i].lookup.result == 0) + master_servers[i].addr = master_servers[i].lookup.addr; + master_servers[i].lookup.state = STATE_PROCESSED; + } + + /* set the needs_update flag if we isn't done */ + if(master_servers[i].lookup.state != STATE_PROCESSED) + needs_update = 1; + } + + if(!needs_update) + { + dbg_msg("engine/mastersrv", "saving addresses"); + mastersrv_save(); + } +} + +int mastersrv_refreshing() +{ + return needs_update; +} + +NETADDR4 mastersrv_get(int index) +{ + return master_servers[index].addr; +} + +const char *mastersrv_name(int index) +{ + return master_servers[index].hostname; +} + +void mastersrv_dump_servers() +{ + int i; + for(i = 0; i < MAX_MASTERSERVERS; i++) + { + dbg_msg("mastersrv", "#%d = %d.%d.%d.%d", i, + master_servers[i].addr.ip[0], master_servers[i].addr.ip[1], + master_servers[i].addr.ip[2], master_servers[i].addr.ip[3]); + } +} + +void mastersrv_default() +{ + int i; + mem_zero(master_servers, sizeof(master_servers)); + for(i = 0; i < MAX_MASTERSERVERS; i++) + sprintf(master_servers[i].hostname, "master%d.teewars.com", i+1); +} + +int mastersrv_load() +{ + LINEREADER lr; + IOHANDLE file; + int count = 0; + char filename[1024]; + + engine_savepath("masters.cfg", filename, sizeof(filename)); + + /* try to open file */ + file = io_open(filename, IOFLAG_READ); + if(!file) + return -1; + + linereader_init(&lr, file); + while(1) + { + MASTER_INFO info = {{0}}; + int ip[4]; + const char *line = linereader_get(&lr); + if(!line) + break; + + /* parse line */ + if(sscanf(line, "%s %d.%d.%d.%d", info.hostname, &ip[0], &ip[1], &ip[2], &ip[3]) == 5) + { + info.addr.ip[0] = (unsigned char)ip[0]; + info.addr.ip[1] = (unsigned char)ip[1]; + info.addr.ip[2] = (unsigned char)ip[2]; + info.addr.ip[3] = (unsigned char)ip[3]; + info.addr.port = 8300; + if(count != MAX_MASTERSERVERS) + { + master_servers[count] = info; + count++; + } + else + dbg_msg("engine/mastersrv", "warning: skipped master server '%s' due to limit of %d", line, MAX_MASTERSERVERS); + } + else + dbg_msg("engine/mastersrv", "warning: couldn't parse master server '%s'", line); + } + + io_close(file); + return 0; +} + +int mastersrv_save() +{ + IOHANDLE file; + int i; + char filename[1024]; + + engine_savepath("masters.cfg", filename, sizeof(filename)); + + /* try to open file */ + file = io_open(filename, IOFLAG_WRITE); + if(!file) + return -1; + + for(i = 0; i < MAX_MASTERSERVERS; i++) + { + char buf[1024]; + sprintf(buf, "%s %d.%d.%d.%d\n", master_servers[i].hostname, + master_servers[i].addr.ip[0], master_servers[i].addr.ip[1], + master_servers[i].addr.ip[2], master_servers[i].addr.ip[3]); + + io_write(file, buf, strlen(buf)); + } + + io_close(file); + return 0; +} diff --git a/src/engine/e_engine.h b/src/engine/e_engine.h index ba880bb05..6974db1d5 100644 --- a/src/engine/e_engine.h +++ b/src/engine/e_engine.h @@ -4,3 +4,20 @@ const char *engine_savepath(const char *filename, char *buffer, int max); void engine_init(const char *appname); void engine_parse_arguments(int argc, char **argv); void engine_writeconfig(); + + +enum +{ + MAX_MASTERSERVERS=16 +}; + +void mastersrv_default(); +int mastersrv_load(); +int mastersrv_save(); + +int mastersrv_refresh_addresses(); +void mastersrv_update(); +int mastersrv_refreshing(); +void mastersrv_dump_servers(); +NETADDR4 mastersrv_get(int index); +const char *mastersrv_name(int index); diff --git a/src/engine/e_linereader.c b/src/engine/e_linereader.c new file mode 100644 index 000000000..57ba9a856 --- /dev/null +++ b/src/engine/e_linereader.c @@ -0,0 +1,62 @@ +#include "e_linereader.h" + +void linereader_init(LINEREADER *lr, IOHANDLE io) +{ + lr->buffer_max_size = 4*1024; + lr->buffer_size = 0; + lr->buffer_pos = 0; + lr->io = io; +} + +char *linereader_get(LINEREADER *lr) +{ + unsigned line_start = lr->buffer_pos; + + while(1) + { + if(lr->buffer_pos >= lr->buffer_size) + { + /* fetch more */ + + /* move the remaining part to the front */ + unsigned read; + unsigned left = lr->buffer_size - line_start; + + if(line_start > lr->buffer_size) + left = 0; + if(left) + mem_move(lr->buffer, &lr->buffer[line_start], left); + lr->buffer_pos = left; + + /* fill the buffer */ + read = io_read(lr->io, &lr->buffer[lr->buffer_pos], lr->buffer_max_size-lr->buffer_pos); + lr->buffer_size = left + read; + line_start = 0; + + if(!read) + { + if(left) + { + lr->buffer[left] = 0; /* return the last line */ + lr->buffer_pos = left; + lr->buffer_size = left; + return lr->buffer; + } + else + return 0x0; /* we are done! */ + } + } + else + { + if(lr->buffer[lr->buffer_pos] == '\n' || lr->buffer[lr->buffer_pos] == '\r') + { + /* line found */ + lr->buffer[lr->buffer_pos] = 0; + lr->buffer_pos++; + return &lr->buffer[line_start]; + } + else + lr->buffer_pos++; + } + } +} diff --git a/src/engine/e_linereader.h b/src/engine/e_linereader.h new file mode 100644 index 000000000..d9d050d03 --- /dev/null +++ b/src/engine/e_linereader.h @@ -0,0 +1,14 @@ +#include "e_system.h" + +/* buffered stream for reading lines, should perhaps be something smaller */ +typedef struct +{ + char buffer[4*1024]; + unsigned buffer_pos; + unsigned buffer_size; + unsigned buffer_max_size; + IOHANDLE io; +} LINEREADER; + +void linereader_init(LINEREADER *lr, IOHANDLE io); +char *linereader_get(LINEREADER *lr); diff --git a/src/engine/e_system.c b/src/engine/e_system.c index c175f7c98..9a8b2a94f 100644 --- a/src/engine/e_system.c +++ b/src/engine/e_system.c @@ -268,6 +268,45 @@ int io_close(IOHANDLE io) return 1; } +void *thread_create(void (*threadfunc)(void *), void *u) +{ +#if defined(CONF_FAMILY_UNIX) + pthread_t id; + pthread_create(&id, NULL, (void *(*)(void*))threadfunc, u); + return (void*)id; +#elif defined(CONF_FAMILY_WINDOWS) + return CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadfunc, u, 0, NULL); +#else + #error not implemented +#endif +} + +void thread_wait(void *thread) +{ +#if defined(CONF_FAMILY_UNIX) + pthread_join((pthread_t)thread, NULL); +#elif defined(CONF_FAMILY_WINDOWS) + WaitForSingleObject((HANDLE)thread, INFINITE); +#else + #error not implemented +#endif +} + +void thread_destroy(void *thread) +{ +} + +void thread_yield() +{ +#if defined(CONF_FAMILY_UNIX) + sched_yield(); +#elif defined(CONF_FAMILY_WINDOWS) + Sleep(0); +#else + #error not implemented +#endif +} + void thread_sleep(int milliseconds) { #if defined(CONF_FAMILY_UNIX) @@ -279,6 +318,9 @@ void thread_sleep(int milliseconds) #endif } + + + #if defined(CONF_FAMILY_UNIX) typedef pthread_mutex_t LOCKINTERNAL; #elif defined(CONF_FAMILY_WINDOWS) @@ -757,6 +799,11 @@ int net_socket_read_wait(NETSOCKET sock, int time) #endif*/ } +unsigned time_timestamp() +{ + return time(0); +} + #if defined(__cplusplus) } #endif diff --git a/src/engine/e_system.h b/src/engine/e_system.h index f271d71ac..bfd8cd8cd 100644 --- a/src/engine/e_system.h +++ b/src/engine/e_system.h @@ -268,13 +268,6 @@ int io_close(IOHANDLE io); /**** Group: Threads ****/ -int thread_create(); /* NOT IMPLEMENTED */ -int thread_destory(); /* NOT IMPLEMENTED */ - -int thread_run(); /* NOT IMPLEMENTED */ -int thread_pause(); /* NOT IMPLEMENTED */ -int thread_wait(); /* NOT IMPLEMENTED */ - /***** Function: thread_sleep @@ -517,6 +510,12 @@ int net_socket_read_wait(NETSOCKET sock, int time); void mem_debug_dump(); int mem_allocated(); +void *thread_create(void (*threadfunc)(void *), void *user); +void thread_wait(void *thread); +void thread_destroy(void *thread); +void thread_yield(); +unsigned time_timestamp(); + void swap_endian(void *data, unsigned elem_size, unsigned num); /* #define cache_prefetch(addr) __builtin_prefetch(addr) */ diff --git a/src/engine/server/es_register.c b/src/engine/server/es_register.c new file mode 100644 index 000000000..c7f4bcc92 --- /dev/null +++ b/src/engine/server/es_register.c @@ -0,0 +1,258 @@ +#include +#include +#include +#include +#include + +#include + +extern NETSERVER *net; + +enum +{ + REGISTERSTATE_START=0, + REGISTERSTATE_UPDATE_ADDRS, + REGISTERSTATE_QUERY_COUNT, + REGISTERSTATE_HEARTBEAT, + REGISTERSTATE_REGISTERED, + REGISTERSTATE_ERROR +}; + +static int register_state = REGISTERSTATE_START; +static int64 register_state_start = 0; +static int register_first = 1; + +static void register_new_state(int state) +{ + register_state = state; + register_state_start = time_get(); +} + +static void register_send_fwcheckresponse(NETADDR4 *addr) +{ + NETPACKET packet; + packet.client_id = -1; + packet.address = *addr; + packet.flags = PACKETFLAG_CONNLESS; + packet.data_size = sizeof(SERVERBROWSE_FWRESPONSE); + packet.data = SERVERBROWSE_FWRESPONSE; + netserver_send(net, &packet); +} + +static void register_send_heartbeat(NETADDR4 addr) +{ + static unsigned char data[sizeof(SERVERBROWSE_HEARTBEAT) + 2]; + unsigned short port = config.sv_port; + NETPACKET packet; + + mem_copy(data, SERVERBROWSE_HEARTBEAT, sizeof(SERVERBROWSE_HEARTBEAT)); + + packet.client_id = -1; + packet.address = addr; + packet.flags = PACKETFLAG_CONNLESS; + packet.data_size = sizeof(SERVERBROWSE_HEARTBEAT) + 2; + packet.data = &data; + + /* supply the set port that the master can use if it has problems */ + if(config.sv_external_port) + port = config.sv_external_port; + data[sizeof(SERVERBROWSE_HEARTBEAT)] = port >> 8; + data[sizeof(SERVERBROWSE_HEARTBEAT)+1] = port&0xff; + netserver_send(net, &packet); +} + +static void register_send_count_request(NETADDR4 addr) +{ + NETPACKET packet; + packet.client_id = -1; + packet.address = addr; + packet.flags = PACKETFLAG_CONNLESS; + packet.data_size = sizeof(SERVERBROWSE_GETCOUNT); + packet.data = SERVERBROWSE_GETCOUNT; + netserver_send(net, &packet); +} + +typedef struct +{ + NETADDR4 addr; + int count; + int valid; + int64 last_send; +} MASTERSERVER_INFO; + +static MASTERSERVER_INFO masterserver_info[MAX_MASTERSERVERS] = {{{{0}}}}; +static int register_registered_server = -1; + +void register_update() +{ + int64 now = time_get(); + int64 freq = time_freq(); + mastersrv_update(); + + if(register_state == REGISTERSTATE_START) + { + register_first = 1; + register_new_state(REGISTERSTATE_UPDATE_ADDRS); + mastersrv_refresh_addresses(); + dbg_msg("register", "refreshing ip addresses"); + } + else if(register_state == REGISTERSTATE_UPDATE_ADDRS) + { + register_registered_server = -1; + + if(!mastersrv_refreshing()) + { + int i; + for(i = 0; i < MAX_MASTERSERVERS; i++) + { + NETADDR4 addr = mastersrv_get(i); + masterserver_info[i].addr = addr; + masterserver_info[i].count = 0; + + if(!addr.ip[0] && !addr.ip[1] && !addr.ip[2] && !addr.ip[3]) + masterserver_info[i].valid = 0; + else + { + masterserver_info[i].valid = 1; + masterserver_info[i].count = -1; + masterserver_info[i].last_send = 0; + } + } + + dbg_msg("register", "fetching server counts"); + register_new_state(REGISTERSTATE_QUERY_COUNT); + } + } + else if(register_state == REGISTERSTATE_QUERY_COUNT) + { + int i; + int left = 0; + for(i = 0; i < MAX_MASTERSERVERS; i++) + { + if(!masterserver_info[i].valid) + continue; + + if(masterserver_info[i].count == -1) + { + left++; + if(masterserver_info[i].last_send+freq < now) + { + masterserver_info[i].last_send = now; + register_send_count_request(masterserver_info[i].addr); + } + } + } + + /* check if we are done or timed out */ + if(left == 0 || now > register_state_start+freq*3) + { + /* choose server */ + int best = -1; + int i; + for(i = 0; i < MAX_MASTERSERVERS; i++) + { + if(!masterserver_info[i].valid || masterserver_info[i].count == -1) + continue; + + if(best == -1 || masterserver_info[i].count < masterserver_info[best].count) + best = i; + } + + /* server chosen */ + register_registered_server = best; + if(register_registered_server == -1) + { + dbg_msg("register", "WARNING: No master servers. Retrying in 60 seconds"); + register_new_state(REGISTERSTATE_ERROR); + } + else + { + dbg_msg("register", "choosen '%s' as master, sending heartbeats", mastersrv_name(register_registered_server)); + masterserver_info[register_registered_server].last_send = 0; + register_new_state(REGISTERSTATE_HEARTBEAT); + } + } + } + else if(register_state == REGISTERSTATE_HEARTBEAT) + { + /* check if we should send heartbeat */ + if(now > masterserver_info[register_registered_server].last_send+freq*15) + { + masterserver_info[register_registered_server].last_send = now; + register_send_heartbeat(masterserver_info[register_registered_server].addr); + } + + if(now > register_state_start+freq*60) + { + dbg_msg("register", "WARNING: Master server is not responding, switching master"); + register_new_state(REGISTERSTATE_START); + } + } + else if(register_state == REGISTERSTATE_REGISTERED) + { + if(register_first) + dbg_msg("register", "server registered"); + + register_first = 0; + + /* check if we should send new heartbeat again */ + if(now > register_state_start+freq*30) + register_new_state(REGISTERSTATE_HEARTBEAT); + } + else if(register_state == REGISTERSTATE_ERROR) + { + /* check for restart */ + if(now > register_state_start+freq*60) + register_new_state(REGISTERSTATE_START); + } +} + +static void register_got_count(NETPACKET *p) +{ + unsigned char *data = (unsigned char *)p->data; + int count = (data[sizeof(SERVERBROWSE_COUNT)]<<8) | data[sizeof(SERVERBROWSE_COUNT)+1]; + int i; + + for(i = 0; i < MAX_MASTERSERVERS; i++) + { + if(net_addr4_cmp(&masterserver_info[i].addr, &p->address) == 0) + { + masterserver_info[i].count = count; + break; + } + } +} + +int register_process_packet(NETPACKET *packet) +{ + if(packet->data_size == sizeof(SERVERBROWSE_FWCHECK) && + memcmp(packet->data, SERVERBROWSE_FWCHECK, sizeof(SERVERBROWSE_FWCHECK)) == 0) + { + register_send_fwcheckresponse(&packet->address); + return 1; + } + else if(packet->data_size == sizeof(SERVERBROWSE_FWOK) && + memcmp(packet->data, SERVERBROWSE_FWOK, sizeof(SERVERBROWSE_FWOK)) == 0) + { + if(register_first) + dbg_msg("register", "no firewall/nat problems detected"); + register_new_state(REGISTERSTATE_REGISTERED); + return 1; + } + else if(packet->data_size == sizeof(SERVERBROWSE_FWERROR) && + memcmp(packet->data, SERVERBROWSE_FWERROR, sizeof(SERVERBROWSE_FWERROR)) == 0) + { + dbg_msg("register", "ERROR: the master server reports that clients can not connect to this server."); + dbg_msg("register", "ERROR: configure your firewall/nat to let trough udp on port %d.", config.sv_port); + register_new_state(REGISTERSTATE_ERROR); + return 1; + } + else if(packet->data_size == sizeof(SERVERBROWSE_COUNT)+2 && + memcmp(packet->data, SERVERBROWSE_COUNT, sizeof(SERVERBROWSE_COUNT)) == 0) + { + register_got_count(packet); + return 1; + } + + return 0; +} diff --git a/src/engine/server/es_server.c b/src/engine/server/es_server.c index c677d1545..415b67fe8 100644 --- a/src/engine/server/es_server.c +++ b/src/engine/server/es_server.c @@ -29,7 +29,7 @@ static int browseinfo_gametype = -1; static int browseinfo_progression = -1; static int64 lastheartbeat; -static NETADDR4 master_server; +/*static NETADDR4 master_server;*/ static char current_map[64]; static int current_map_crc; @@ -101,7 +101,7 @@ typedef struct } CLIENT; static CLIENT clients[MAX_CLIENTS]; -static NETSERVER *net; +NETSERVER *net; static void snap_init_id() { @@ -535,29 +535,6 @@ static void server_send_map(int cid) msg_pack_end(); server_send_msg(cid); } - -static void server_send_heartbeat() -{ - static unsigned char data[sizeof(SERVERBROWSE_HEARTBEAT) + 2]; - unsigned short port = config.sv_port; - NETPACKET packet; - - mem_copy(data, SERVERBROWSE_HEARTBEAT, sizeof(SERVERBROWSE_HEARTBEAT)); - - packet.client_id = -1; - packet.address = master_server; - packet.flags = PACKETFLAG_CONNLESS; - packet.data_size = sizeof(SERVERBROWSE_HEARTBEAT) + 2; - packet.data = &data; - - /* supply the set port that the master can use if it has problems */ - if(config.sv_external_port) - port = config.sv_external_port; - data[sizeof(SERVERBROWSE_HEARTBEAT)] = port >> 8; - data[sizeof(SERVERBROWSE_HEARTBEAT)+1] = port&0xff; - - netserver_send(net, &packet); -} static void server_process_client_packet(NETPACKET *packet) { @@ -631,7 +608,7 @@ static void server_process_client_packet(NETPACKET *packet) } else if(msg == NETMSG_ENTERGAME) { - if(clients[cid].state != SRVCLIENT_STATE_INGAME) + if(clients[cid].state == SRVCLIENT_STATE_READY) { dbg_msg("server", "player as entered the game. cid=%x", cid); clients[cid].state = SRVCLIENT_STATE_INGAME; @@ -783,18 +760,8 @@ static void server_dump_status() } - - -static void server_send_fwcheckresponse(NETADDR4 *addr) -{ - NETPACKET packet; - packet.client_id = -1; - packet.address = *addr; - packet.flags = PACKETFLAG_CONNLESS; - packet.data_size = sizeof(SERVERBROWSE_FWRESPONSE); - packet.data = SERVERBROWSE_FWRESPONSE; - netserver_send(net, &packet); -} +extern int register_process_packet(NETPACKET *packet); +extern int register_update(); static void server_pump_network() { @@ -808,32 +775,18 @@ static void server_pump_network() if(packet.client_id == -1) { /* stateless */ - if(packet.data_size == sizeof(SERVERBROWSE_GETINFO) && - memcmp(packet.data, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO)) == 0) + if(!register_process_packet(&packet)) { - server_send_serverinfo(&packet.address, 0); - } - else if(packet.data_size == sizeof(SERVERBROWSE_GETINFO_LAN) && - memcmp(packet.data, SERVERBROWSE_GETINFO_LAN, sizeof(SERVERBROWSE_GETINFO_LAN)) == 0) - { - server_send_serverinfo(&packet.address, 1); - } - else if(packet.data_size == sizeof(SERVERBROWSE_FWCHECK) && - memcmp(packet.data, SERVERBROWSE_FWCHECK, sizeof(SERVERBROWSE_FWCHECK)) == 0) - { - server_send_fwcheckresponse(&packet.address); - } - else if(packet.data_size == sizeof(SERVERBROWSE_FWOK) && - memcmp(packet.data, SERVERBROWSE_FWOK, sizeof(SERVERBROWSE_FWOK)) == 0) - { - if(config.debug) - dbg_msg("server", "no firewall/nat problems detected"); - } - else if(packet.data_size == sizeof(SERVERBROWSE_FWERROR) && - memcmp(packet.data, SERVERBROWSE_FWERROR, sizeof(SERVERBROWSE_FWERROR)) == 0) - { - dbg_msg("server", "ERROR: the master server reports that clients can not connect to this server."); - dbg_msg("server", "ERROR: configure your firewall/nat to let trough udp on port %d.", config.sv_port); + if(packet.data_size == sizeof(SERVERBROWSE_GETINFO) && + memcmp(packet.data, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO)) == 0) + { + server_send_serverinfo(&packet.address, 0); + } + else if(packet.data_size == sizeof(SERVERBROWSE_GETINFO_LAN) && + memcmp(packet.data, SERVERBROWSE_GETINFO_LAN, sizeof(SERVERBROWSE_GETINFO_LAN)) == 0) + { + server_send_serverinfo(&packet.address, 1); + } } } else @@ -873,7 +826,6 @@ static int server_load_map(const char *mapname) return 1; } - static int server_run() { NETADDR4 bindaddr; @@ -910,19 +862,12 @@ static int server_run() netserver_set_callbacks(net, new_client_callback, del_client_callback, 0); dbg_msg("server", "server name is '%s'", config.sv_name); - dbg_msg("server", "masterserver is '%s'", config.masterserver); - if(net_host_lookup(config.masterserver, MASTERSERVER_PORT, &master_server) != 0) - { - /* TODO: fix me */ - /*master_server = netaddr4(0, 0, 0, 0, 0); */ - } - + mods_init(); dbg_msg("server", "version %s", mods_net_version()); /* start game */ { - int64 time_per_heartbeat = time_freq() * 30; int64 reporttime = time_get(); int reportinterval = 3; @@ -1025,15 +970,10 @@ static int server_run() perf_end(); } } + + /* master server stuff */ + register_update(); - if(config.sv_sendheartbeats) - { - if (t > lastheartbeat+time_per_heartbeat) - { - server_send_heartbeat(); - lastheartbeat = t+time_per_heartbeat; - } - } { static PERFORMACE_INFO scope = {"net", 0}; diff --git a/src/game/server/gs_server.cpp b/src/game/server/gs_server.cpp index bcab00e57..53ad4c2ba 100644 --- a/src/game/server/gs_server.cpp +++ b/src/game/server/gs_server.cpp @@ -576,6 +576,7 @@ player::player() void player::init() { proximity_radius = phys_size; + dbg_msg("", "%p %d -> %d (init)", this, client_id, -1); client_id = -1; team = -1; // -1 == spectator @@ -2116,6 +2117,7 @@ void mods_client_enter(int client_id) void mods_connected(int client_id) { players[client_id].init(); + dbg_msg("", "%p %d -> %d (mods_connected)", &players[client_id], players[client_id].client_id, client_id); players[client_id].client_id = client_id; //dbg_msg("game", "connected player='%d:%s'", client_id, server_clientname(client_id)); @@ -2144,6 +2146,7 @@ void mods_client_drop(int client_id) gameobj->on_player_death(&players[client_id], 0, -1); world->remove_entity(&players[client_id]); world->core.players[client_id] = 0x0; + dbg_msg("", "%p %d -> %d (mods_client_drop)", &players[client_id], players[client_id].client_id, -1); players[client_id].client_id = -1; } diff --git a/src/mastersrv/mastersrv.cpp b/src/mastersrv/mastersrv.cpp index aa7999190..b83330a5f 100644 --- a/src/mastersrv/mastersrv.cpp +++ b/src/mastersrv/mastersrv.cpp @@ -27,6 +27,14 @@ static struct packet_data unsigned char header[sizeof(SERVERBROWSE_LIST)]; NETADDR4 servers[MAX_SERVERS]; } data; + +static struct count_packet_data +{ + 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; @@ -41,6 +49,9 @@ void send_ok(NETADDR4 *addr) p.flags = PACKETFLAG_CONNLESS; p.data_size = sizeof(SERVERBROWSE_FWOK); p.data = SERVERBROWSE_FWOK; + + // send on both to be sure + net_checker.send(&p); net_op.send(&p); } @@ -183,6 +194,8 @@ int main(int argc, char **argv) // TODO: check socket for errors mem_copy(data.header, SERVERBROWSE_LIST, sizeof(SERVERBROWSE_LIST)); + mem_copy(count_data.header, SERVERBROWSE_COUNT, sizeof(SERVERBROWSE_COUNT)); + dbg_msg("mastersrv", "started"); while(1) @@ -207,6 +220,21 @@ int main(int argc, char **argv) // add it add_checkserver(&packet.address, &alt); } + 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); + + NETPACKET p; + p.client_id = -1; + p.address = packet.address; + p.flags = PACKETFLAG_CONNLESS; + 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) { diff --git a/src/mastersrv/mastersrv.h b/src/mastersrv/mastersrv.h index 1de5b9ef5..b53479145 100644 --- a/src/mastersrv/mastersrv.h +++ b/src/mastersrv/mastersrv.h @@ -10,6 +10,9 @@ static const unsigned char SERVERBROWSE_HEARTBEAT[] = {255, 255, 255, 255, 'b', 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', 'f'}; static const unsigned char SERVERBROWSE_INFO[] = {255, 255, 255, 255, 'i', 'n', 'f', 'o'}; diff --git a/src/tools/fake_server.c b/src/tools/fake_server.c index c81dfaaa6..a2af1a0a2 100644 --- a/src/tools/fake_server.c +++ b/src/tools/fake_server.c @@ -45,20 +45,29 @@ int player_scores[16] = {0}; int num_players = 0; int max_players = 0; + + static void send_heartbeats() { - int i = 0; - - NETPACKET p; - p.client_id = -1; - p.flags = PACKETFLAG_CONNLESS; - p.data_size = sizeof(SERVERBROWSE_HEARTBEAT); - p.data = SERVERBROWSE_HEARTBEAT; + static unsigned char data[sizeof(SERVERBROWSE_HEARTBEAT) + 2]; + NETPACKET packet; + int i; + + mem_copy(data, SERVERBROWSE_HEARTBEAT, sizeof(SERVERBROWSE_HEARTBEAT)); + + packet.client_id = -1; + packet.flags = PACKETFLAG_CONNLESS; + packet.data_size = sizeof(SERVERBROWSE_HEARTBEAT) + 2; + packet.data = &data; + /* supply the set port that the master can use if it has problems */ + data[sizeof(SERVERBROWSE_HEARTBEAT)] = 0; + data[sizeof(SERVERBROWSE_HEARTBEAT)+1] = 0; + for(i = 0; i < num_masters; i++) { - p.address = master_servers[i]; - netserver_send(net, &p); + packet.address = master_servers[i]; + netserver_send(net, &packet); } }