From 440ae5f977e53fd5606140b8b2fc0c5e1a78fe0e Mon Sep 17 00:00:00 2001 From: xtreme8000 Date: Thu, 15 Oct 2020 20:43:48 +0200 Subject: [PATCH] Ping code rewrite --- src/hud.c | 15 +--- src/ping.c | 220 +++++++++++++++++++++++++++-------------------------- src/ping.h | 7 +- 3 files changed, 118 insertions(+), 124 deletions(-) diff --git a/src/hud.c b/src/hud.c index 5a6291c..13da6d4 100644 --- a/src/hud.c +++ b/src/hud.c @@ -1997,24 +1997,19 @@ static int hud_serverlist_sort_ping(const void* a, const void* b) { return aa->ping - bb->ping; } -static void hud_serverlist_pingupdate(void* e, float time_delta, void* user_data) { +static void hud_serverlist_pingupdate(void* e, float time_delta, char* aos) { pthread_mutex_lock(&serverlist_lock); if(!e) { for(int k = 0; k < server_count; k++) - if(strcmp(serverlist[k].identifier, user_data) == 0) { + if(!strcmp(serverlist[k].identifier, aos)) { serverlist[k].ping = ceil(time_delta * 1000.0F); break; } } else { serverlist = realloc(serverlist, (++server_count) * sizeof(struct serverlist_entry)); - memcpy(&serverlist[server_count - 1], e, sizeof(struct serverlist_entry)); + memcpy(serverlist + server_count - 1, e, sizeof(struct serverlist_entry)); } - qsort(serverlist, server_count, sizeof(struct serverlist_entry), hud_serverlist_sort); - pthread_mutex_unlock(&serverlist_lock); -} -static void hud_serverlist_pingcomplete() { - pthread_mutex_lock(&serverlist_lock); qsort(serverlist, server_count, sizeof(struct serverlist_entry), hud_serverlist_sort); pthread_mutex_unlock(&serverlist_lock); } @@ -2345,7 +2340,7 @@ static void hud_serverlist_render(mu_Context* ctx, float scalex, float scaley) { serverlist = realloc(serverlist, server_count * sizeof(struct serverlist_entry)); CHECK_ALLOCATION_ERROR(serverlist) - ping_stop(); + ping_start(hud_serverlist_pingupdate); player_count = 0; for(int k = 0; k < server_count; k++) { @@ -2373,8 +2368,6 @@ static void hud_serverlist_render(mu_Context* ctx, float scalex, float scaley) { player_count += serverlist[k].current; } - ping_start(hud_serverlist_pingcomplete, hud_serverlist_pingupdate); - qsort(serverlist, server_count, sizeof(struct serverlist_entry), hud_serverlist_sort); pthread_mutex_unlock(&serverlist_lock); diff --git a/src/ping.c b/src/ping.c index a3f7135..f81cde7 100644 --- a/src/ping.c +++ b/src/ping.c @@ -29,16 +29,17 @@ #include "parson.h" #include "list.h" #include "hud.h" +#include "channel.h" +#include "hashtable.h" +#include "utils.h" -struct list list_pings; +struct channel ping_queue; ENetSocket sock, lan; pthread_t ping_thread; -pthread_mutex_t ping_lock; -void (*ping_finished)(); -void (*ping_result)(void*, float time_delta, void* user_data); +void (*ping_result)(void*, float time_delta, char* aos); void ping_init() { - list_create(&list_pings, sizeof(struct ping_entry)); + channel_create(&ping_queue, sizeof(struct ping_entry), 64); sock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM); enet_socket_set_option(sock, ENET_SOCKOPT_NONBLOCK, 1); @@ -47,151 +48,152 @@ void ping_init() { enet_socket_set_option(lan, ENET_SOCKOPT_NONBLOCK, 1); enet_socket_set_option(lan, ENET_SOCKOPT_BROADCAST, 1); - pthread_mutex_init(&ping_lock, NULL); + pthread_create(&ping_thread, NULL, ping_update, NULL); } void ping_deinit() { - pthread_mutex_lock(&ping_lock); // stop the ping thread from running enet_socket_destroy(sock); enet_socket_destroy(lan); } +static void ping_lan() { + ENetAddress addr = {.host = 0xFFFFFFFF}; // 255.255.255.255 + + ENetBuffer buffer = { + .data = "HELLOLAN", + .dataLength = 8, + }; + + for(addr.port = 32882; addr.port < 32892; addr.port++) + enet_socket_send(lan, &addr, &buffer, 1); +} + +static bool pings_retry(void* key, void* value, void* user) { + struct ping_entry* entry = (struct ping_entry*)value; + + if(window_time() - entry->time_start > 2.0F) { // timeout + // try up to 3 times after first failed attempt + if(entry->trycount >= 3) { + return true; + } else { + enet_socket_send(sock, &entry->addr, &(ENetBuffer) {.data = "HELLO", .dataLength = 5}, 1); + entry->time_start = window_time(); + entry->trycount++; + log_warn("Ping timeout on %s, retrying", entry->aos); + } + } + + return false; +} + +#define IP_KEY(addr) (((uint64_t)addr.host << 16) | (addr.port)); + void* ping_update(void* data) { + pthread_detach(pthread_self()); + ping_lan(); float ping_start = window_time(); + HashTable pings; + ht_setup(&pings, sizeof(uint64_t), sizeof(struct ping_entry), 64); + while(1) { - char tmp[512]; + size_t drain = channel_size(&ping_queue); + for(size_t k = 0; (k < drain) || (!pings.size && window_time() - ping_start >= 8.0F); k++) { + struct ping_entry entry; + channel_await(&ping_queue, &entry); - ENetBuffer buf; - buf.data = tmp; + uint64_t ID = IP_KEY(entry.addr); + ht_insert(&pings, &ID, &entry); + } + char tmp[512]; ENetAddress from; - pthread_mutex_lock(&ping_lock); + ENetBuffer buf = { + .data = tmp, + .dataLength = sizeof(tmp), + }; while(1) { - buf.dataLength = 512; - memset(tmp, 0, buf.dataLength); - int response = enet_socket_receive(sock, &from, &buf, 1); - if(response != 0) { - struct ping_entry* entry; - int k; - for(k = list_size(&list_pings) - 1; k >= 0; k--) { - entry = list_get(&list_pings, k); - if(entry->addr.host == from.host && entry->addr.port == from.port) - break; - } - - switch(response) { - default: // received something! - if(strcmp(buf.data, "HI") == 0) { - ping_result(NULL, window_time() - entry->time_start, entry->user_data); + int recvLength = enet_socket_receive(sock, &from, &buf, 1); + uint64_t ID = IP_KEY(from); + + if(recvLength != 0) { + struct ping_entry* entry = ht_lookup(&pings, &ID); + + if(entry) { + if(recvLength > 0) { // received something! + if(!strncmp(buf.data, "HI", recvLength)) { + ping_result(NULL, window_time() - entry->time_start, entry->aos); + ht_erase(&pings, &ID); + } else { + entry->trycount++; } - case -1: // connection was closed - list_remove(&list_pings, k); + } else { // connection was closed + ht_erase(&pings, &ID); + } } } else { // would block break; } } - int retry = 0; - for(int k = list_size(&list_pings) - 1; k >= 0; k--) { - struct ping_entry* entry = list_get(&list_pings, k); - - if(window_time() - entry->time_start > 2.0F) { // timeout - if(entry->trycount < 3) { // try up to 3 times after first failed attempt - retry = 1; - ENetBuffer buffer; - buffer.data = "HELLO"; - buffer.dataLength = 5; - entry->time_start = window_time(); - enet_socket_send(sock, &entry->addr, &buffer, 1); - entry->trycount++; - } else { - list_remove(&list_pings, k); - continue; - } - } - } - - if(retry) - log_warn("Ping timeout on some server(s), retrying"); + ht_iterate_remove(&pings, NULL, pings_retry); - buf.dataLength = 512; - memset(tmp, 0, buf.dataLength); int length = enet_socket_receive(lan, &from, &buf, 1); if(length) { - struct serverlist_entry e; - - strcpy(e.country, "LAN"); - e.ping = ceil((window_time() - ping_start) * 1000.0F); - snprintf(e.identifier, sizeof(e.identifier) - 1, "aos://%u:%u", from.host, from.port); - - JSON_Value* js = json_parse_string(tmp); - JSON_Object* root = json_value_get_object(js); - strncpy(e.name, json_object_get_string(root, "name"), sizeof(e.name) - 1); - strncpy(e.gamemode, json_object_get_string(root, "game_mode"), sizeof(e.gamemode) - 1); - strncpy(e.map, json_object_get_string(root, "map"), sizeof(e.map) - 1); - e.current = json_object_get_number(root, "players_current"); - e.max = json_object_get_number(root, "players_max"); - json_value_free(js); - ping_result(&e, window_time() - ping_start, NULL); - } - - if(!list_size(&list_pings)) { - ping_finished(); - log_info("Ping thread stopped"); - pthread_mutex_unlock(&ping_lock); - return NULL; + JSON_Value* js = json_parse_string(buf.data); + if(js) { + JSON_Object* root = json_value_get_object(js); + + struct serverlist_entry e; + + strcpy(e.country, "LAN"); + e.ping = ceil((window_time() - ping_start) * 1000.0F); + snprintf(e.identifier, sizeof(e.identifier) - 1, "aos://%u:%u", from.host, from.port); + + strncpy(e.name, json_object_get_string(root, "name"), sizeof(e.name) - 1); + e.name[sizeof(e.name) - 1] = 0; + strncpy(e.gamemode, json_object_get_string(root, "game_mode"), sizeof(e.gamemode) - 1); + e.gamemode[sizeof(e.gamemode) - 1] = 0; + strncpy(e.map, json_object_get_string(root, "map"), sizeof(e.map) - 1); + e.map[sizeof(e.map) - 1] = 0; + e.current = json_object_get_number(root, "players_current"); + e.max = json_object_get_number(root, "players_max"); + ping_result(&e, window_time() - ping_start, NULL); + + json_value_free(js); + } } - pthread_mutex_unlock(&ping_lock); - - usleep(1); + usleep(1000); } } -void ping_lan() { - ENetAddress addr; - addr.host = 0xFFFFFFFF; // 255.255.255.255 - - ENetBuffer buffer; - buffer.data = "HELLOLAN"; - buffer.dataLength = 8; - for(addr.port = 32880; addr.port < 32890; addr.port++) - enet_socket_send(lan, &addr, &buffer, 1); -} - -void ping_check(char* addr, int port, void* user_data) { - pthread_mutex_lock(&ping_lock); - struct ping_entry* entry = list_add(&list_pings, NULL); +void ping_check(char* addr, int port, char* aos) { + struct ping_entry entry = { + .trycount = 0, + .addr.port = port, + .time_start = window_time(), + }; - strcpy(entry->user_data, user_data); - entry->trycount = 0; + strncpy(entry.aos, aos, sizeof(entry.aos) - 1); + entry.aos[sizeof(entry.aos) - 1] = 0; - enet_address_set_host(&entry->addr, addr); - entry->addr.port = port; + enet_address_set_host(&entry.addr, addr); - ENetBuffer buffer; - buffer.data = "HELLO"; - buffer.dataLength = 5; + channel_put(&ping_queue, &entry); - entry->time_start = window_time(); - enet_socket_send(sock, &entry->addr, &buffer, 1); - pthread_mutex_unlock(&ping_lock); + enet_socket_send(sock, &entry.addr, &(ENetBuffer) {.data = "HELLO", .dataLength = 5}, 1); } -void ping_start(void (*finished)(), void (*result)(void*, float, void*)) { - pthread_create(&ping_thread, NULL, ping_update, NULL); - ping_finished = finished; +void ping_start(void (*result)(void*, float, char*)) { + ping_stop(); + ping_result = result; } void ping_stop() { - pthread_mutex_lock(&ping_lock); - if(list_created(&list_pings)) - list_clear(&list_pings); - pthread_mutex_unlock(&ping_lock); + channel_clear(&ping_queue); } diff --git a/src/ping.h b/src/ping.h index 7ebbb6f..fb905b6 100644 --- a/src/ping.h +++ b/src/ping.h @@ -24,17 +24,16 @@ struct ping_entry { ENetAddress addr; + char aos[64]; float time_start; - char user_data[32]; int trycount; }; void ping_init(); void ping_deinit(); -void ping_check(char* addr, int port, void* user_data); +void ping_check(char* addr, int port, char* aos); void* ping_update(void* data); -void ping_start(void (*finished)(), void (*result)(void*, float, void*)); -void ping_lan(); +void ping_start(void (*result)(void*, float, char*)); void ping_stop(); #endif