diff options
| author | Kai Stevenson <kai@kaistevenson.com> | 2023-03-20 03:51:08 -0700 |
|---|---|---|
| committer | Kai Stevenson <kai@kaistevenson.com> | 2023-03-20 03:51:08 -0700 |
| commit | ad900636080477eb2c8df7a225a71825e5380d3d (patch) | |
| tree | 2fabfebada8ac863b6b4e2e0a128a3146a887be1 | |
| parent | 1a3b3fb05f86e357b099812c0a09a084934fd111 (diff) | |
added proper cancellation token handling; cleanup when host is found to be unresponsive
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | src/chess.c | 9 | ||||
| -rw-r--r-- | src/fscomch.c | 63 | ||||
| -rw-r--r-- | src/fscomch.h | 11 |
4 files changed, 72 insertions, 15 deletions
@@ -1,5 +1,7 @@ CC=gcc -CFLAGS=-I. +CFLAGS=-I. -pthread -std=c99 -march=native -O3 -lm +CFLAGS+= -Wshadow -Wundef -Wcast-align +CFLAGS+= -Wunreachable-code -Wswitch-enum generate: $(CC) -o chess src/chess.c src/vector.c src/chesshelpers.c src/console.c src/fscomch.c $(CFLAGS) diff --git a/src/chess.c b/src/chess.c index adb5ce2..5e52482 100644 --- a/src/chess.c +++ b/src/chess.c @@ -44,7 +44,7 @@ int main(int argc, char **argv) { isHost = 1; /* we are acting as the host--await a connection */ printf("Awaiting connection\n"); - match = await_match(matchFile, NULL); + match = await_match(matchFile, init_cancel_token_never()); printf("Connection completed. Match is %s\n", match.uuid); } else { @@ -52,11 +52,12 @@ int main(int argc, char **argv) { /* we are joining an existing match */ printf("Attempting to join existing match\n"); match = join_match(); - if (match.uuid != NULL) { + if (strlen(match.uuid) == 36) { printf("Joined match %s\n", match.uuid); } else { - printf("Error joining match. reload the program\n"); + printf("Error joining match. Reload the program\n"); + exit(1); } } sleep(2); @@ -71,7 +72,7 @@ int main(int argc, char **argv) { /* awaiting the remote player */ printf("Waiting for %s's move\n", turn ? "black" : "white"); while (1) { - char* message = read_message(match, NULL); + char* message = read_message(match, init_cancel_token_never()); /* try to parse the message as a move */ if (strncmp(message, "move=", 5) == 0) { vector_t rOrigin = init_vector(message[5] - '0', message[6] - '0'); diff --git a/src/fscomch.c b/src/fscomch.c index 412f9cf..16dcdcf 100644 --- a/src/fscomch.c +++ b/src/fscomch.c @@ -5,8 +5,25 @@ #include <time.h> #include <sys/stat.h> #include <string.h> +#include <pthread.h> #include "fscomch.h" +cancelToken_t init_cancel_token_timeout(int seconds) { + cancelToken_t token; + token.timeout = seconds; + token.value = calloc(1, sizeof(char)); + pthread_t cancelTimer; + cancelToken_t* memToken = malloc(sizeof(cancelToken_t)); + *memToken = token; + pthread_create(&cancelTimer, NULL, cancel_in_secs, (void*)memToken); + return token; +} +cancelToken_t init_cancel_token_never() { + cancelToken_t token; + token.timeout = -1; + token.value = NULL; + return token; +} match_t init_match(char* uuid, FILE* streamIn, FILE* streamOut) { match_t match; match.uuid = uuid; @@ -28,10 +45,10 @@ FILE* try_lock_match() { } return fdopen(fd, "r"); } -match_t await_match(FILE* matchFile, char* cancelToken) { +match_t await_match(FILE* matchFile, cancelToken_t cancelToken) { /* await match UUID */ char* uuid = calloc(37, sizeof(char)); - while (cancelToken == NULL || *cancelToken) { + while (cancelToken.value == NULL || !*cancelToken.value) { if (fgets(uuid, 37, matchFile) != NULL) { break; } @@ -51,7 +68,9 @@ match_t await_match(FILE* matchFile, char* cancelToken) { /* connection complete, delete the match file and the join lock */ remove("/tmp/chess/match"); remove("/tmp/chess/matchjoin"); - return init_match(uuid, streamIn, streamOut); + match_t match = init_match(uuid, streamIn, streamOut); + send_message("ping", match); + return match; } match_t join_match() { /* create a join lock so that no one else can join this match */ @@ -62,6 +81,7 @@ match_t join_match() { match_t match; return match; } + close(fd); /* this is definitely the only process joining the game proceed to generate a uuid */ char* uuid = make_uuid(); @@ -77,17 +97,34 @@ match_t join_match() { FILE* matchFile = fopen("/tmp/chess/match", "a"); fputs(uuid, matchFile); fclose(matchFile); - /* joining match complete, close the descriptor */ - close(fd); - return match; + /* handshake */ + cancelToken_t token = init_cancel_token_timeout(2); + char* message = read_message(match, token); + if (message != NULL) { + if (strcmp(message, "ping") == 0) { + return match; + } + else { + printf("Extreme de-sync. Aborting\n"); + exit(1); + } + } + printf("Host is dead. Cleaning up\n"); + fclose(streamIn); + fclose(streamOut); + remove("/tmp/chess/match"); + remove("/tmp/chess/matchjoin"); + remove(aName); + remove(bName); + exit(1); } void send_message(char* content, match_t match) { fprintf(match.streamOut, "%s\n", content); fflush(match.streamOut); } -char* read_message(match_t match, char* cancelToken) { +char* read_message(match_t match, cancelToken_t cancelToken) { char* buffer = calloc(256, sizeof(char)); - while (cancelToken == NULL || *cancelToken) { + while (cancelToken.value == NULL || !*cancelToken.value) { if (fgets(buffer, 256, match.streamIn) != NULL) { break; } @@ -98,6 +135,11 @@ char* read_message(match_t match, char* cancelToken) { req.tv_nsec = awaitMoveNs; nanosleep(&req, NULL); } + /* if we cancelled via token, return NULL */ + if (cancelToken.value != NULL && *cancelToken.value == 1) { + free(buffer); + return NULL; + } /* overwrite potential newline */ buffer[strlen(buffer) - 1] = '\0'; return buffer; @@ -117,3 +159,8 @@ char* make_uuid() { out[37] = '\0'; return out; } +void* cancel_in_secs(void* token) { + sleep(((cancelToken_t*)token)->timeout); + *(((cancelToken_t*)token)->value) = 1; + free(token); +} diff --git a/src/fscomch.h b/src/fscomch.h index bc92467..6aa7fb7 100644 --- a/src/fscomch.h +++ b/src/fscomch.h @@ -14,15 +14,22 @@ typedef struct Match { } match_t; match_t init_match(char* uuid, FILE* streamIn, FILE* streamOut); void destroy_match(match_t match); +typedef struct CancellationToken { + int timeout; + volatile char* value; +} cancelToken_t; +cancelToken_t init_cancel_token_timeout(int seconds); +cancelToken_t init_cancel_token_never(); /* returns null if the matchfile is already extant */ FILE* try_lock_match(); /* creates a new match, waits for it to be joined by another player */ -match_t await_match(FILE* matchFile, char* cancelToken); +match_t await_match(FILE* matchFile, cancelToken_t cancelToken); /* joins an existing match */ match_t join_match(); void send_message(char* content, match_t match); /* blocks */ -char* read_message(match_t match, char* cancelToken); +char* read_message(match_t match, cancelToken_t cancelToken); char* make_uuid(); +void* cancel_in_secs(void* token); #endif |
