From f9ab444cc614db3b2380d02750d142f9b17a8b90 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 2 Dec 2010 18:23:09 +0000 Subject: Register servers with Internet master server. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2181 --- src/net_query.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'src/net_query.c') diff --git a/src/net_query.c b/src/net_query.c index 72650ac2..deb3744a 100644 --- a/src/net_query.c +++ b/src/net_query.c @@ -36,16 +36,86 @@ #include "net_structrw.h" #include "net_sdl.h" +#define MASTER_SERVER_ADDRESS "master.chocolate-doom.org" + typedef struct { net_addr_t *addr; net_querydata_t data; } queryresponse_t; +static boolean registered_with_master = false; + static net_context_t *query_context; static queryresponse_t *responders; static int num_responses; +// Resolve the master server address. + +net_addr_t *NET_Query_ResolveMaster(net_context_t *context) +{ + net_addr_t *addr; + + addr = NET_ResolveAddress(context, MASTER_SERVER_ADDRESS); + + if (addr == NULL) + { + fprintf(stderr, "Warning: Failed to resolve address " + "for master server: %s\n", MASTER_SERVER_ADDRESS); + } + + return addr; +} + +// Send a registration packet to the master server to register +// ourselves with the global list. + +void NET_Query_AddToMaster(net_addr_t *master_addr) +{ + net_packet_t *packet; + + packet = NET_NewPacket(10); + NET_WriteInt16(packet, NET_MASTER_PACKET_TYPE_ADD); + NET_SendPacket(master_addr, packet); + NET_FreePacket(packet); +} + +// Process a packet received from the master server. + +void NET_Query_MasterResponse(net_packet_t *packet) +{ + unsigned int packet_type; + unsigned int result; + + if (!NET_ReadInt16(packet, &packet_type) + || !NET_ReadInt16(packet, &result)) + { + return; + } + + if (packet_type == NET_MASTER_PACKET_TYPE_ADD_RESPONSE) + { + if (result != 0) + { + // Only show the message once. + + if (!registered_with_master) + { + printf("Registered with master server at %s\n", + MASTER_SERVER_ADDRESS); + registered_with_master = true; + } + } + else + { + // Always show rejections. + + printf("Failed to register with master server at %s\n", + MASTER_SERVER_ADDRESS); + } + } +} + // Add a new address to the list of hosts that has responded static queryresponse_t *AddResponder(net_addr_t *addr, @@ -319,3 +389,4 @@ void NET_LANQuery(void) exit(0); } + -- cgit v1.2.3 From bfbffcf197a5d78e90d463945d12c84d0f7deadf Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 2 Dec 2010 19:26:05 +0000 Subject: Refactor query code and add a -masterquery command line parameter to query the master server. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2182 --- src/net_query.c | 472 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 372 insertions(+), 100 deletions(-) (limited to 'src/net_query.c') diff --git a/src/net_query.c b/src/net_query.c index deb3744a..681411c2 100644 --- a/src/net_query.c +++ b/src/net_query.c @@ -38,17 +38,40 @@ #define MASTER_SERVER_ADDRESS "master.chocolate-doom.org" -typedef struct +typedef enum { + QUERY_TARGET_SERVER, // Normal server target. + QUERY_TARGET_MASTER, // The master server. + QUERY_TARGET_BROADCAST // Send a broadcast query +} query_target_type_t; + +typedef enum +{ + QUERY_TARGET_QUEUED, // Query not yet sent + QUERY_TARGET_QUERIED, // Query sent, waiting response + QUERY_TARGET_RESPONDED, // Response received + QUERY_TARGET_TIMED_OUT +} query_target_state_t; + +typedef struct +{ + query_target_type_t type; + query_target_state_t state; net_addr_t *addr; net_querydata_t data; -} queryresponse_t; + unsigned int query_time; + boolean printed; +} query_target_t; + +// Transmit a query packet static boolean registered_with_master = false; static net_context_t *query_context; -static queryresponse_t *responders; -static int num_responses; +static query_target_t *targets; +static int num_targets; + +static boolean printed_header = false; // Resolve the master server address. @@ -116,40 +139,49 @@ void NET_Query_MasterResponse(net_packet_t *packet) } } -// Add a new address to the list of hosts that has responded +// Send a query to the master server. -static queryresponse_t *AddResponder(net_addr_t *addr, - net_querydata_t *data) +static void NET_Query_SendMasterQuery(net_addr_t *addr) { - queryresponse_t *response; - - responders = realloc(responders, - sizeof(queryresponse_t) * (num_responses + 1)); - - response = &responders[num_responses]; - response->addr = addr; - response->data = *data; - ++num_responses; + net_packet_t *packet; - return response; + packet = NET_NewPacket(10); + NET_WriteInt16(packet, NET_MASTER_PACKET_TYPE_QUERY); + NET_SendPacket(addr, packet); + NET_FreePacket(packet); } -// Returns true if the reply is from a host that has not previously -// responded. +// Given the specified address, find the target associated. If no +// target is found, and 'create' is true, a new target is created. -static boolean CheckResponder(net_addr_t *addr) +static query_target_t *GetTargetForAddr(net_addr_t *addr, boolean create) { + query_target_t *target; int i; - for (i=0; itype = QUERY_TARGET_SERVER; + target->state = QUERY_TARGET_QUEUED; + target->printed = false; + target->addr = addr; + ++num_targets; + + return target; } // Transmit a query packet @@ -173,20 +205,225 @@ static void NET_Query_SendQuery(net_addr_t *addr) NET_FreePacket(request); } +static void NET_Query_ParseResponse(net_addr_t *addr, net_packet_t *packet) +{ + unsigned int packet_type; + net_querydata_t querydata; + query_target_t *target; + + // Read the header + + if (!NET_ReadInt16(packet, &packet_type) + || packet_type != NET_PACKET_TYPE_QUERY_RESPONSE) + { + return; + } + + // Read query data + + if (!NET_ReadQueryData(packet, &querydata)) + { + return; + } + + // Find the target that responded, or potentially add a new target + // if it was not already known (for LAN broadcast search) + + target = GetTargetForAddr(addr, true); + + target->state = QUERY_TARGET_RESPONDED; + memcpy(&target->data, &querydata, sizeof(net_querydata_t)); +} + +// Parse a response packet from the master server. + +static void NET_Query_ParseMasterResponse(net_addr_t *master_addr, + net_packet_t *packet) +{ + unsigned int packet_type; + query_target_t *target; + char *addr_str; + net_addr_t *addr; + + // Read the header. We are only interested in query responses. + + if (!NET_ReadInt16(packet, &packet_type) + || packet_type != NET_MASTER_PACKET_TYPE_QUERY_RESPONSE) + { + return; + } + + // Read a list of strings containing the addresses of servers + // that the master knows about. + + for (;;) + { + addr_str = NET_ReadString(packet); + + if (addr_str == NULL) + { + break; + } + + // Resolve address and add to targets list if it is not already + // there. + + addr = NET_ResolveAddress(query_context, addr_str); + + if (addr != NULL) + { + GetTargetForAddr(addr, true); + } + } + + // Mark the master as having responded. + + target = GetTargetForAddr(master_addr, true); + target->state = QUERY_TARGET_RESPONDED; +} + +static void NET_Query_ParsePacket(net_addr_t *addr, net_packet_t *packet) +{ + query_target_t *target; + + // This might be the master server responding. + + target = GetTargetForAddr(addr, false); + + if (target != NULL && target->type == QUERY_TARGET_MASTER) + { + NET_Query_ParseMasterResponse(addr, packet); + } + else + { + NET_Query_ParseResponse(addr, packet); + } +} + +static void NET_Query_GetResponse(void) +{ + net_addr_t *addr; + net_packet_t *packet; + + if (NET_RecvPacket(query_context, &addr, &packet)) + { + NET_Query_ParsePacket(addr, packet); + NET_FreePacket(packet); + } +} + +// Find a target we have not yet queried and send a query. + +static void SendOneQuery(void) +{ + unsigned int i; + + for (i = 0; i < num_targets; ++i) + { + if (targets[i].state == QUERY_TARGET_QUEUED) + { + break; + } + } + + if (i >= num_targets) + { + return; + } + + // Found a target to query. Send a query; how to do this depends on + // the target type. + + switch (targets[i].type) + { + case QUERY_TARGET_SERVER: + NET_Query_SendQuery(targets[i].addr); + break; + + case QUERY_TARGET_BROADCAST: + NET_Query_SendQuery(NULL); + break; + + case QUERY_TARGET_MASTER: + NET_Query_SendMasterQuery(targets[i].addr); + break; + } + + //printf("Queried %s\n", NET_AddrToString(targets[i].addr)); + targets[i].state = QUERY_TARGET_QUERIED; + targets[i].query_time = I_GetTimeMS(); +} + +// Search the targets list and find a target that has responded. +// If none have responded yet, returns NULL. + +static query_target_t *FindFirstResponder(void) +{ + unsigned int i; + + for (i = 0; i < num_targets; ++i) + { + if (targets[i].type == QUERY_TARGET_SERVER + && targets[i].state == QUERY_TARGET_RESPONDED) + { + return &targets[i]; + } + } + + return NULL; +} + +// Time out servers that have been queried and not responded. + +static void CheckTargetTimeouts(void) +{ + unsigned int i; + unsigned int now; + + now = I_GetTimeMS(); + + for (i = 0; i < num_targets; ++i) + { + if (targets[i].state == QUERY_TARGET_QUERIED + && now - targets[i].query_time > 5000) + { + targets[i].state = QUERY_TARGET_TIMED_OUT; + } + } +} + +// If all targets have responded or timed out, returns true. + +static boolean AllTargetsDone(void) +{ + unsigned int i; + + for (i = 0; i < num_targets; ++i) + { + if (targets[i].state != QUERY_TARGET_RESPONDED + && targets[i].state != QUERY_TARGET_TIMED_OUT) + { + return false; + } + } + + return true; +} + static void formatted_printf(int wide, char *s, ...) { va_list args; int i; - + va_start(args, s); i = vprintf(s, args); va_end(args); - while (i < wide) + while (i < wide) { putchar(' '); ++i; - } + } } static char *GameDescription(GameMode_t mode, GameMission_t mission) @@ -224,115 +461,104 @@ static void PrintHeader(void) putchar('\n'); } -static void PrintResponse(queryresponse_t *response) +static void PrintResponse(query_target_t *target) { - formatted_printf(18, "%s: ", NET_AddrToString(response->addr)); - formatted_printf(8, "%i/%i", response->data.num_players, - response->data.max_players); + formatted_printf(18, "%s: ", NET_AddrToString(target->addr)); + formatted_printf(8, "%i/%i", target->data.num_players, + target->data.max_players); - if (response->data.gamemode != indetermined) + if (target->data.gamemode != indetermined) { - printf("(%s) ", GameDescription(response->data.gamemode, - response->data.gamemission)); + printf("(%s) ", GameDescription(target->data.gamemode, + target->data.gamemission)); } - if (response->data.server_state) + if (target->data.server_state) { printf("(game running) "); } - NET_SafePuts(response->data.description); + NET_SafePuts(target->data.description); } -static void NET_Query_ParsePacket(net_addr_t *addr, net_packet_t *packet) -{ - unsigned int packet_type; - net_querydata_t querydata; - queryresponse_t *response; - - // Have we already received a packet from this host? +// Check for printing information about servers that have responded. - if (!CheckResponder(addr)) - { - return; - } - - // Read the header - - if (!NET_ReadInt16(packet, &packet_type) - || packet_type != NET_PACKET_TYPE_QUERY_RESPONSE) - { - return; - } - - // Read query data - - if (!NET_ReadQueryData(packet, &querydata)) - { - return; - } +static void CheckPrintOutput(void) +{ + unsigned int i; - if (num_responses <= 0) + for (i = 0; i < num_targets; ++i) { - // If this is the first response, print the table header + if (targets[i].type == QUERY_TARGET_SERVER + && targets[i].state == QUERY_TARGET_RESPONDED + && !targets[i].printed) + { + if (!printed_header) + { + PrintHeader(); + printed_header = true; + } - PrintHeader(); + PrintResponse(&targets[i]); + targets[i].printed = true; + } } - - response = AddResponder(addr, &querydata); - - PrintResponse(response); } -static void NET_Query_GetResponse(void) -{ - net_addr_t *addr; - net_packet_t *packet; +// Loop waiting for responses. - if (NET_RecvPacket(query_context, &addr, &packet)) - { - NET_Query_ParsePacket(addr, packet); - NET_FreePacket(packet); - } -} - -static net_addr_t *NET_Query_QueryLoop(net_addr_t *addr, - boolean find_one) +static net_addr_t *NET_Query_QueryLoop(boolean find_first, + boolean silent) { + query_target_t *responder; int start_time; int last_send_time; last_send_time = -1; start_time = I_GetTimeMS(); - while (I_GetTimeMS() < start_time + 5000) + while (!AllTargetsDone()) { - // Send a query once every second + // Send a query. This will only send a single query. + // Because of the delay below, this is therefore rate limited. - if (last_send_time < 0 || I_GetTimeMS() > last_send_time + 1000) - { - NET_Query_SendQuery(addr); - last_send_time = I_GetTimeMS(); - } + SendOneQuery(); // Check for a response NET_Query_GetResponse(); + // Output the responses + + if (!silent) + { + CheckPrintOutput(); + } + // Found a response? - if (find_one && num_responses > 0) + if (find_first && FindFirstResponder()) + { break; - + } + // Don't thrash the CPU - + I_Sleep(100); + + CheckTargetTimeouts(); } - if (num_responses > 0) - return responders[0].addr; + responder = FindFirstResponder(); + + if (responder != NULL) + { + return responder->addr; + } else + { return NULL; + } } void NET_Query_Init(void) @@ -341,14 +567,16 @@ void NET_Query_Init(void) NET_AddModule(query_context, &net_sdl_module); net_sdl_module.InitClient(); - responders = NULL; - num_responses = 0; + targets = NULL; + num_targets = 0; + + printed_header = false; } void NET_QueryAddress(char *addr) { net_addr_t *net_addr; - + NET_Query_Init(); net_addr = NET_ResolveAddress(query_context, addr); @@ -358,9 +586,13 @@ void NET_QueryAddress(char *addr) I_Error("NET_QueryAddress: Host '%s' not found!", addr); } + // Add the address to the list of targets. + + GetTargetForAddr(net_addr, true); + printf("\nQuerying '%s'...\n\n", addr); - if (!NET_Query_QueryLoop(net_addr, true)) + if (!NET_Query_QueryLoop(true, false)) { I_Error("No response from '%s'", addr); } @@ -370,18 +602,32 @@ void NET_QueryAddress(char *addr) net_addr_t *NET_FindLANServer(void) { + query_target_t *target; + NET_Query_Init(); - return NET_Query_QueryLoop(NULL, true); + // Add a broadcast target to the list. + + target = GetTargetForAddr(NULL, true); + target->type = QUERY_TARGET_BROADCAST; + + return NET_Query_QueryLoop(true, true); } void NET_LANQuery(void) { + query_target_t *target; + NET_Query_Init(); printf("\nSearching for servers on local LAN ...\n\n"); - if (!NET_Query_QueryLoop(NULL, false)) + // Add a broadcast target to the list. + + target = GetTargetForAddr(NULL, true); + target->type = QUERY_TARGET_BROADCAST; + + if (!NET_Query_QueryLoop(false, false)) { I_Error("No servers found"); } @@ -389,4 +635,30 @@ void NET_LANQuery(void) exit(0); } +void NET_MasterQuery(void) +{ + net_addr_t *master; + query_target_t *target; + + NET_Query_Init(); + + printf("\nSearching for servers on Internet ...\n\n"); + + // Resolve master address and add to targets list. + + master = NET_Query_ResolveMaster(query_context); + + if (master == NULL) + { + I_Error("Failed to resolve master server address"); + } + + target = GetTargetForAddr(master, true); + target->type = QUERY_TARGET_MASTER; + + if (!NET_Query_QueryLoop(false, false)) + { + I_Error("No servers found"); + } +} -- cgit v1.2.3 From b11030cbfee0d4d4a46673001992e94abc146c8c Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 2 Dec 2010 20:11:24 +0000 Subject: More refactoring of querying code, to not be specific to the purpose of printing out a list. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2184 --- src/net_query.c | 372 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 198 insertions(+), 174 deletions(-) (limited to 'src/net_query.c') diff --git a/src/net_query.c b/src/net_query.c index 681411c2..3dee1b00 100644 --- a/src/net_query.c +++ b/src/net_query.c @@ -71,6 +71,7 @@ static net_context_t *query_context; static query_target_t *targets; static int num_targets; +static boolean query_loop_running = false; static boolean printed_header = false; // Resolve the master server address. @@ -205,7 +206,9 @@ static void NET_Query_SendQuery(net_addr_t *addr) NET_FreePacket(request); } -static void NET_Query_ParseResponse(net_addr_t *addr, net_packet_t *packet) +static void NET_Query_ParseResponse(net_addr_t *addr, net_packet_t *packet, + net_query_callback_t callback, + void *user_data) { unsigned int packet_type; net_querydata_t querydata; @@ -231,8 +234,15 @@ static void NET_Query_ParseResponse(net_addr_t *addr, net_packet_t *packet) target = GetTargetForAddr(addr, true); - target->state = QUERY_TARGET_RESPONDED; - memcpy(&target->data, &querydata, sizeof(net_querydata_t)); + if (target->state != QUERY_TARGET_RESPONDED) + { + target->state = QUERY_TARGET_RESPONDED; + memcpy(&target->data, &querydata, sizeof(net_querydata_t)); + + // Invoke callback to signal that we have a new address. + + callback(addr, &target->data, user_data); + } } // Parse a response packet from the master server. @@ -282,7 +292,9 @@ static void NET_Query_ParseMasterResponse(net_addr_t *master_addr, target->state = QUERY_TARGET_RESPONDED; } -static void NET_Query_ParsePacket(net_addr_t *addr, net_packet_t *packet) +static void NET_Query_ParsePacket(net_addr_t *addr, net_packet_t *packet, + net_query_callback_t callback, + void *user_data) { query_target_t *target; @@ -296,18 +308,19 @@ static void NET_Query_ParsePacket(net_addr_t *addr, net_packet_t *packet) } else { - NET_Query_ParseResponse(addr, packet); + NET_Query_ParseResponse(addr, packet, callback, user_data); } } -static void NET_Query_GetResponse(void) +static void NET_Query_GetResponse(net_query_callback_t callback, + void *user_data) { net_addr_t *addr; net_packet_t *packet; if (NET_RecvPacket(query_context, &addr, &packet)) { - NET_Query_ParsePacket(addr, packet); + NET_Query_ParsePacket(addr, packet, callback, user_data); NET_FreePacket(packet); } } @@ -354,25 +367,6 @@ static void SendOneQuery(void) targets[i].query_time = I_GetTimeMS(); } -// Search the targets list and find a target that has responded. -// If none have responded yet, returns NULL. - -static query_target_t *FindFirstResponder(void) -{ - unsigned int i; - - for (i = 0; i < num_targets; ++i) - { - if (targets[i].type == QUERY_TARGET_SERVER - && targets[i].state == QUERY_TARGET_RESPONDED) - { - return &targets[i]; - } - } - - return NULL; -} - // Time out servers that have been queried and not responded. static void CheckTargetTimeouts(void) @@ -410,197 +404,165 @@ static boolean AllTargetsDone(void) return true; } -static void formatted_printf(int wide, char *s, ...) -{ - va_list args; - int i; - - va_start(args, s); - i = vprintf(s, args); - va_end(args); +// Stop the query loop - while (i < wide) - { - putchar(' '); - ++i; - } +static void NET_Query_ExitLoop(void) +{ + query_loop_running = false; } -static char *GameDescription(GameMode_t mode, GameMission_t mission) +// Loop waiting for responses. +// The specified callback is invoked when a new server responds. + +static void NET_Query_QueryLoop(net_query_callback_t callback, + void *user_data) { - switch (mode) + query_loop_running = true; + + while (query_loop_running && !AllTargetsDone()) { - case shareware: - return "shareware"; - case registered: - return "registered"; - case retail: - return "ultimate"; - case commercial: - if (mission == doom2) - return "doom2"; - else if (mission == pack_tnt) - return "tnt"; - else if (mission == pack_plut) - return "plutonia"; - default: - return "unknown"; - } -} + // Send a query. This will only send a single query. + // Because of the delay below, this is therefore rate limited. -static void PrintHeader(void) -{ - int i; + SendOneQuery(); - formatted_printf(18, "Address"); - formatted_printf(8, "Players"); - puts("Description"); + // Check for a response - for (i=0; i<70; ++i) - putchar('='); - putchar('\n'); + NET_Query_GetResponse(callback, user_data); + + // Don't thrash the CPU + + I_Sleep(100); + + CheckTargetTimeouts(); + } } -static void PrintResponse(query_target_t *target) +void NET_Query_Init(void) { - formatted_printf(18, "%s: ", NET_AddrToString(target->addr)); - formatted_printf(8, "%i/%i", target->data.num_players, - target->data.max_players); + query_context = NET_NewContext(); + NET_AddModule(query_context, &net_sdl_module); + net_sdl_module.InitClient(); - if (target->data.gamemode != indetermined) - { - printf("(%s) ", GameDescription(target->data.gamemode, - target->data.gamemission)); - } + targets = NULL; + num_targets = 0; - if (target->data.server_state) - { - printf("(game running) "); - } + printed_header = false; +} + +// Callback that exits the query loop when the first server is found. - NET_SafePuts(target->data.description); +static void NET_Query_ExitCallback(net_addr_t *addr, net_querydata_t *data, + void *user_data) +{ + NET_Query_ExitLoop(); } -// Check for printing information about servers that have responded. +// Search the targets list and find a target that has responded. +// If none have responded, returns NULL. -static void CheckPrintOutput(void) +static query_target_t *FindFirstResponder(void) { unsigned int i; for (i = 0; i < num_targets; ++i) { if (targets[i].type == QUERY_TARGET_SERVER - && targets[i].state == QUERY_TARGET_RESPONDED - && !targets[i].printed) + && targets[i].state == QUERY_TARGET_RESPONDED) { - if (!printed_header) - { - PrintHeader(); - printed_header = true; - } - - PrintResponse(&targets[i]); - targets[i].printed = true; + return &targets[i]; } } + + return NULL; } -// Loop waiting for responses. +// Return a count of the number of responses. -static net_addr_t *NET_Query_QueryLoop(boolean find_first, - boolean silent) +static int GetNumResponses(void) { - query_target_t *responder; - int start_time; - int last_send_time; + unsigned int i; + int result; - last_send_time = -1; - start_time = I_GetTimeMS(); + result = 0; - while (!AllTargetsDone()) + for (i = 0; i < num_targets; ++i) { - // Send a query. This will only send a single query. - // Because of the delay below, this is therefore rate limited. + if (targets[i].type == QUERY_TARGET_SERVER + && targets[i].state == QUERY_TARGET_RESPONDED) + { + ++result; + } + } - SendOneQuery(); + return result; +} - // Check for a response +void NET_QueryAddress(char *addr_str) +{ + net_addr_t *addr; + query_target_t *target; - NET_Query_GetResponse(); + NET_Query_Init(); - // Output the responses + addr = NET_ResolveAddress(query_context, addr_str); - if (!silent) - { - CheckPrintOutput(); - } + if (addr == NULL) + { + I_Error("NET_QueryAddress: Host '%s' not found!", addr_str); + } - // Found a response? + // Add the address to the list of targets. - if (find_first && FindFirstResponder()) - { - break; - } + target = GetTargetForAddr(addr, true); - // Don't thrash the CPU + printf("\nQuerying '%s'...\n", addr_str); - I_Sleep(100); + // Run query loop. - CheckTargetTimeouts(); - } + NET_Query_QueryLoop(NET_Query_ExitCallback, NULL); - responder = FindFirstResponder(); + // Check if the target responded. - if (responder != NULL) + if (target->state == QUERY_TARGET_RESPONDED) { - return responder->addr; + NET_QueryPrintCallback(addr, &target->data, NULL); } else { - return NULL; + I_Error("No response from '%s'", addr_str); } } -void NET_Query_Init(void) -{ - query_context = NET_NewContext(); - NET_AddModule(query_context, &net_sdl_module); - net_sdl_module.InitClient(); - - targets = NULL; - num_targets = 0; - - printed_header = false; -} - -void NET_QueryAddress(char *addr) +net_addr_t *NET_FindLANServer(void) { - net_addr_t *net_addr; + query_target_t *target; + query_target_t *responder; NET_Query_Init(); - net_addr = NET_ResolveAddress(query_context, addr); + // Add a broadcast target to the list. - if (net_addr == NULL) - { - I_Error("NET_QueryAddress: Host '%s' not found!", addr); - } + target = GetTargetForAddr(NULL, true); + target->type = QUERY_TARGET_BROADCAST; - // Add the address to the list of targets. + // Run the query loop, and stop at the first target found. - GetTargetForAddr(net_addr, true); + NET_Query_QueryLoop(NET_Query_ExitCallback, NULL); - printf("\nQuerying '%s'...\n\n", addr); + responder = FindFirstResponder(); - if (!NET_Query_QueryLoop(true, false)) + if (responder != NULL) { - I_Error("No response from '%s'", addr); + return responder->addr; + } + else + { + return NULL; } - - exit(0); } -net_addr_t *NET_FindLANServer(void) +int NET_LANQuery(net_query_callback_t callback, void *user_data) { query_target_t *target; @@ -611,54 +573,116 @@ net_addr_t *NET_FindLANServer(void) target = GetTargetForAddr(NULL, true); target->type = QUERY_TARGET_BROADCAST; - return NET_Query_QueryLoop(true, true); + NET_Query_QueryLoop(callback, user_data); + + return GetNumResponses(); } -void NET_LANQuery(void) +int NET_MasterQuery(net_query_callback_t callback, void *user_data) { + net_addr_t *master; query_target_t *target; NET_Query_Init(); - printf("\nSearching for servers on local LAN ...\n\n"); + // Resolve master address and add to targets list. - // Add a broadcast target to the list. + master = NET_Query_ResolveMaster(query_context); - target = GetTargetForAddr(NULL, true); - target->type = QUERY_TARGET_BROADCAST; + if (master == NULL) + { + return 0; + } + + target = GetTargetForAddr(master, true); + target->type = QUERY_TARGET_MASTER; - if (!NET_Query_QueryLoop(false, false)) + NET_Query_QueryLoop(callback, user_data); + + return GetNumResponses(); +} + +static void formatted_printf(int wide, char *s, ...) +{ + va_list args; + int i; + + va_start(args, s); + i = vprintf(s, args); + va_end(args); + + while (i < wide) { - I_Error("No servers found"); + putchar(' '); + ++i; } +} - exit(0); +static char *GameDescription(GameMode_t mode, GameMission_t mission) +{ + switch (mode) + { + case shareware: + return "shareware"; + case registered: + return "registered"; + case retail: + return "ultimate"; + case commercial: + if (mission == doom2) + return "doom2"; + else if (mission == pack_tnt) + return "tnt"; + else if (mission == pack_plut) + return "plutonia"; + default: + return "unknown"; + } } -void NET_MasterQuery(void) +static void PrintHeader(void) { - net_addr_t *master; - query_target_t *target; + int i; - NET_Query_Init(); + putchar('\n'); + formatted_printf(18, "Address"); + formatted_printf(8, "Players"); + puts("Description"); - printf("\nSearching for servers on Internet ...\n\n"); + for (i=0; i<70; ++i) + putchar('='); + putchar('\n'); +} - // Resolve master address and add to targets list. +// Callback function that just prints information in a table. - master = NET_Query_ResolveMaster(query_context); +void NET_QueryPrintCallback(net_addr_t *addr, + net_querydata_t *data, + void *user_data) +{ + // If this is the first server, print the header. - if (master == NULL) + if (!printed_header) { - I_Error("Failed to resolve master server address"); + PrintHeader(); + printed_header = true; } - target = GetTargetForAddr(master, true); - target->type = QUERY_TARGET_MASTER; + formatted_printf(18, "%s: ", NET_AddrToString(addr)); + formatted_printf(8, "%i/%i", data->num_players, + data->max_players); - if (!NET_Query_QueryLoop(false, false)) + if (data->gamemode != indetermined) { - I_Error("No servers found"); + printf("(%s) ", GameDescription(data->gamemode, + data->gamemission)); } + + if (data->server_state) + { + printf("(game running) "); + } + + NET_SafePuts(data->description); } -- cgit v1.2.3 From 0ff67f43d6d13d9675e305abc652188ea95a88fe Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 2 Dec 2010 21:34:51 +0000 Subject: Make multiple query attempts to servers before giving up. Display a warning if the master server does not respond. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2187 --- src/net_query.c | 46 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) (limited to 'src/net_query.c') diff --git a/src/net_query.c b/src/net_query.c index 3dee1b00..6a934413 100644 --- a/src/net_query.c +++ b/src/net_query.c @@ -36,8 +36,18 @@ #include "net_structrw.h" #include "net_sdl.h" +// DNS address of the Internet master server. + #define MASTER_SERVER_ADDRESS "master.chocolate-doom.org" +// Time to wait for a response before declaring a timeout. + +#define QUERY_TIMEOUT_SECS 1 + +// Number of query attempts to make before giving up on a server. + +#define QUERY_MAX_ATTEMPTS 5 + typedef enum { QUERY_TARGET_SERVER, // Normal server target. @@ -50,7 +60,7 @@ typedef enum QUERY_TARGET_QUEUED, // Query not yet sent QUERY_TARGET_QUERIED, // Query sent, waiting response QUERY_TARGET_RESPONDED, // Response received - QUERY_TARGET_TIMED_OUT + QUERY_TARGET_NO_RESPONSE } query_target_state_t; typedef struct @@ -60,6 +70,7 @@ typedef struct net_addr_t *addr; net_querydata_t data; unsigned int query_time; + unsigned int query_attempts; boolean printed; } query_target_t; @@ -179,6 +190,7 @@ static query_target_t *GetTargetForAddr(net_addr_t *addr, boolean create) target->type = QUERY_TARGET_SERVER; target->state = QUERY_TARGET_QUEUED; target->printed = false; + target->query_attempts = 0; target->addr = addr; ++num_targets; @@ -329,11 +341,19 @@ static void NET_Query_GetResponse(net_query_callback_t callback, static void SendOneQuery(void) { + unsigned int now; unsigned int i; + now = I_GetTimeMS(); + for (i = 0; i < num_targets; ++i) { - if (targets[i].state == QUERY_TARGET_QUEUED) + // Not queried yet? + // Or last query timed out without a response? + + if (targets[i].state == QUERY_TARGET_QUEUED + || (targets[i].state == QUERY_TARGET_QUERIED + && now - targets[i].query_time > QUERY_TIMEOUT_SECS * 1000)) { break; } @@ -365,6 +385,7 @@ static void SendOneQuery(void) //printf("Queried %s\n", NET_AddrToString(targets[i].addr)); targets[i].state = QUERY_TARGET_QUERIED; targets[i].query_time = I_GetTimeMS(); + ++targets[i].query_attempts; } // Time out servers that have been queried and not responded. @@ -378,10 +399,15 @@ static void CheckTargetTimeouts(void) for (i = 0; i < num_targets; ++i) { + // We declare a target to be "no response" when we've sent + // multiple query packets to it (QUERY_MAX_ATTEMPTS) and + // received no response to any of them. + if (targets[i].state == QUERY_TARGET_QUERIED - && now - targets[i].query_time > 5000) + && targets[i].query_attempts >= QUERY_MAX_ATTEMPTS + && now - targets[i].query_time > QUERY_TIMEOUT_SECS * 1000) { - targets[i].state = QUERY_TARGET_TIMED_OUT; + targets[i].state = QUERY_TARGET_NO_RESPONSE; } } } @@ -395,7 +421,7 @@ static boolean AllTargetsDone(void) for (i = 0; i < num_targets; ++i) { if (targets[i].state != QUERY_TARGET_RESPONDED - && targets[i].state != QUERY_TARGET_TIMED_OUT) + && targets[i].state != QUERY_TARGET_NO_RESPONSE) { return false; } @@ -432,7 +458,7 @@ static void NET_Query_QueryLoop(net_query_callback_t callback, // Don't thrash the CPU - I_Sleep(100); + I_Sleep(50); CheckTargetTimeouts(); } @@ -599,6 +625,14 @@ int NET_MasterQuery(net_query_callback_t callback, void *user_data) NET_Query_QueryLoop(callback, user_data); + // Check that we got a response from the master, and display + // a warning if we didn't. + + if (target->state == QUERY_TARGET_NO_RESPONSE) + { + fprintf(stderr, "NET_MasterQuery: no response from master server.\n"); + } + return GetNumResponses(); } -- cgit v1.2.3 From 3c57887b0a5352da1c7c4fe7f149c94bb6d70c31 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 4 Dec 2010 20:48:07 +0000 Subject: Add ping time to query output. Subversion-branch: /trunk/chocolate-doom Subversion-revision: 2192 --- src/net_query.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'src/net_query.c') diff --git a/src/net_query.c b/src/net_query.c index 6a934413..265e3804 100644 --- a/src/net_query.c +++ b/src/net_query.c @@ -42,11 +42,11 @@ // Time to wait for a response before declaring a timeout. -#define QUERY_TIMEOUT_SECS 1 +#define QUERY_TIMEOUT_SECS 2 // Number of query attempts to make before giving up on a server. -#define QUERY_MAX_ATTEMPTS 5 +#define QUERY_MAX_ATTEMPTS 3 typedef enum { @@ -69,6 +69,7 @@ typedef struct query_target_state_t state; net_addr_t *addr; net_querydata_t data; + unsigned int ping_time; unsigned int query_time; unsigned int query_attempts; boolean printed; @@ -251,9 +252,13 @@ static void NET_Query_ParseResponse(net_addr_t *addr, net_packet_t *packet, target->state = QUERY_TARGET_RESPONDED; memcpy(&target->data, &querydata, sizeof(net_querydata_t)); + // Calculate RTT. + + target->ping_time = I_GetTimeMS() - target->query_time; + // Invoke callback to signal that we have a new address. - callback(addr, &target->data, user_data); + callback(addr, &target->data, target->ping_time, user_data); } } @@ -479,7 +484,7 @@ void NET_Query_Init(void) // Callback that exits the query loop when the first server is found. static void NET_Query_ExitCallback(net_addr_t *addr, net_querydata_t *data, - void *user_data) + unsigned int ping_time, void *user_data) { NET_Query_ExitLoop(); } @@ -552,7 +557,7 @@ void NET_QueryAddress(char *addr_str) if (target->state == QUERY_TARGET_RESPONDED) { - NET_QueryPrintCallback(addr, &target->data, NULL); + NET_QueryPrintCallback(addr, &target->data, target->ping_time, NULL); } else { @@ -679,6 +684,7 @@ static void PrintHeader(void) int i; putchar('\n'); + formatted_printf(5, "Ping"); formatted_printf(18, "Address"); formatted_printf(8, "Players"); puts("Description"); @@ -692,6 +698,7 @@ static void PrintHeader(void) void NET_QueryPrintCallback(net_addr_t *addr, net_querydata_t *data, + unsigned int ping_time, void *user_data) { // If this is the first server, print the header. @@ -702,6 +709,7 @@ void NET_QueryPrintCallback(net_addr_t *addr, printed_header = true; } + formatted_printf(5, "%4i", ping_time); formatted_printf(18, "%s: ", NET_AddrToString(addr)); formatted_printf(8, "%i/%i", data->num_players, data->max_players); -- cgit v1.2.3