Skip to content

Commit

Permalink
Ping code rewrite
Browse files Browse the repository at this point in the history
  • Loading branch information
xtreme8000 committed Oct 15, 2020
1 parent dd71c71 commit 440ae5f
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 124 deletions.
15 changes: 4 additions & 11 deletions src/hud.c
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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++) {
Expand Down Expand Up @@ -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);

Expand Down
220 changes: 111 additions & 109 deletions src/ping.c
Expand Up @@ -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);
Expand All @@ -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);
}
7 changes: 3 additions & 4 deletions src/ping.h
Expand Up @@ -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

0 comments on commit 440ae5f

Please sign in to comment.