summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Stevenson <kai@kaistevenson.com>2023-03-20 03:51:08 -0700
committerKai Stevenson <kai@kaistevenson.com>2023-03-20 03:51:08 -0700
commitad900636080477eb2c8df7a225a71825e5380d3d (patch)
tree2fabfebada8ac863b6b4e2e0a128a3146a887be1
parent1a3b3fb05f86e357b099812c0a09a084934fd111 (diff)
added proper cancellation token handling; cleanup when host is found to be unresponsive
-rw-r--r--Makefile4
-rw-r--r--src/chess.c9
-rw-r--r--src/fscomch.c63
-rw-r--r--src/fscomch.h11
4 files changed, 72 insertions, 15 deletions
diff --git a/Makefile b/Makefile
index 64b3196..5fdc73e 100644
--- a/Makefile
+++ b/Makefile
@@ -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