-- Leo's gemini proxy
-- Connecting to git.thebackupbox.net:1965...
-- Connected
-- Sending request
-- Meta line: 20 text/gemini
repo: game-server action: commit revision: path_from: revision_from: 1062a91c5cad5bcf96e0e4e8994a0f04b3ac2adf: path_to: revision_to:
commit 1062a91c5cad5bcf96e0e4e8994a0f04b3ac2adf Author: epoch <epoch@thebackupbox.net> Date: Sat Mar 18 08:26:17 2023 +0000 quick demo diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..43ecef7d1a8ea954fedc1f18d1c0264124ae7f31 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +.PHONEY: all + +PREFIX:=/usr/local + +all: room-server + +install: all + install -Dt $(PREFIX)/libexec lobby.sh + install -Dt $(PREFIX)/libexec room-server diff --git a/lobby.sh b/lobby.sh new file mode 100755 index 0000000000000000000000000000000000000000..85223534963e3d71ad8a79ab812082cd2c39ef06 --- /dev/null +++ b/lobby.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +export ROOM_DIR=/var/cache/game_rooms + +export REMOTE_ADDR="$(/usr/local/libexec/peerip | head -n1)" +export LOCAL_ADDR="$(/usr/local/libexec/sockip | head -n1)" +export REMOTE_PORT="$(/usr/local/libexec/peerip | tail -n1)" +export LOCAL_PORT="$(/usr/local/libexec/sockip | tail -n1)" + +REMOTE_IDENT="$(ident "$LOCAL_ADDR" "$REMOTE_ADDR" 113 "$REMOTE_PORT" "$LOCAL_PORT")" +printf "you have connected to a (currently) Rock Paper Scissors server.\n" +if [ "$REMOTE_IDENT" ];then + printf "hello, %s! :D nice to see you\n" "$REMOTE_IDENT" +else + printf "hello, Anonymous, (from %s) if you'd like a name, run an ident server\n" "$REMOTE_ADDR" + REMOTE_IDENT=Anonymous +fi +printf "games waiting for a player:\n" +ls "${ROOM_DIR}" +printf "please select one, or 'new' for a new room:\n" +read room_path +if [ -f "${ROOM_DIR}/${room_path}" ];then + printf "room %s selected.\n" "$room_path" + exec socat "unix:${ROOM_DIR}/${room_path}" stdio +else + if [ "${room_path}" ];then + printf "room '%s' not found.\n" "${room_path}" + fi + room_path="$(ls "${ROOM_DIR}" | shuf | head -n1)" + if [ "${room_path}" -a "${room_path}" != "new" ];then + printf "selecting a random room. selected: %s\n" "$room_path" + exec socat "unix:${ROOM_DIR}/${room_path}" stdio + fi +fi +if [ "$room_path" == "new" -o "$room_path" == "" ];then + printf "creating a new one.\n" + exec /usr/local/libexec/room-server +fi + +printf "how did you end up here?\n" +exit 0 diff --git a/room-server.c b/room-server.c new file mode 100644 index 0000000000000000000000000000000000000000..8c644e5552d6b910c480210cbbc48516270a97ec --- /dev/null +++ b/room-server.c @@ -0,0 +1,110 @@ +#include <stdio.h> +#include <unistd.h> +#include <time.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <sys/un.h> + +int win_table[4][4]={ +// R P S + {0,1,2}, //R + {2,0,1}, //P + {1,2,0}, //S +}; + +char who_win(int a,int b) { + int c=(a=='R'?0:a=='P'?1:a=='S'?2:-1); + int d=(b=='R'?0:b=='P'?1:b=='S'?2:-1); + if( c == -1 || d == -1) { + return -1; + } + return win_table[c][d]; +} + +int main(int argc,char *argv[]) { + struct sockaddr_un sun; + struct sockaddr_un peer_addr; + int s = socket(AF_UNIX,SOCK_STREAM,0); + int c; + memset( &sun, sizeof(sun), 0 ); + sun.sun_family = AF_UNIX; + + char room_id[sizeof(sun.sun_path)]; + char room_path[sizeof(sun.sun_path)]; + //printf("sun_path size: %d\n",sizeof(sun.sun_path)); // 108 + //return 0; + if(!getenv("ROOM_DIR")) { + printf("well shit, this server is misconfigured.\n"); + return 1; + } + snprintf(room_id,sizeof(room_id),"%d_%d_%d",time(0),getpid(),random()); + snprintf(room_path,sizeof(room_path),"%s/%s",getenv("ROOM_DIR"),room_id); + printf("you have created room: %s\n",room_id); + fflush(stdout); + + strncpy(sun.sun_path, room_path, sizeof(sun.sun_path) - 1); + if(bind(s, (struct sockaddr *) &sun, sizeof(sun)) == -1) { + perror("bind"); + return 1; + } + if(listen(s, 0) == -1) { + perror("listen"); + return 2; + } + // hrm... merp. I think I might have to add the newly accepted connection to an array. + // then select() on all of them for data. + // I've got a library for this kind of shit. + // because it is flaky code, so I only want to have to write it once. + unsigned int len = sizeof(peer_addr); + int good=0; + int over=0; + char buf0[4096]; + char bufc[4096]; + char tmp[1024]; + //todo: probably make this work as a separate program. + if( (c = accept( s, (struct sockaddr *)&peer_addr, &len )) > 0 ) { //or we could limit it to two per room. + printf("received a connection!\n"); + printf("unlinking the socket file\n"); + unlink(room_path); +#define dubwrite(a,b,c) do{write(a,c,strlen(c));write(b,c,strlen(c));} while(0) +#define rite(a,b) write(a,b,strlen(b)) + dubwrite(c,1,"hello\n"); + dubwrite(c,1,"this is rock, paper, scissors.\n"); + dubwrite(c,1,"move choises: R, P, S, Q\n"); + dubwrite(c,1,"Q to quit the game\n"); + dubwrite(c,1,"the game is about to start. please enter your moves like: R\n"); + int p=c; + int wins0=0; + int winsc=0; + for( over=0 ; !over ; p=p?0:c) { + for( good=0 ; !good ; ) { + read(c,bufc,4096); //we'll just toss the rest of it. + bufc[1]=0; + read(0,buf0,4096); + buf0[1]=0; + //collect both moves. either one blocking is fine. + switch( who_win(buf0[0],bufc[0]) ) { + case 0: + dubwrite(c,1,"tie\n"); + break; + case 1: + winsc++; + snprintf(tmp,sizeof(tmp),"you win (%d total)\n",winsc); + rite(c,tmp); + rite(1,"you lose\n"); + break; + case 2: + wins0++; + rite(c,"you lose\n"); + snprintf(tmp,sizeof(tmp),"you win (%d total)\n",wins0); + rite(1,tmp); + break; + default: + dubwrite(c,1,"someone entered an invalid move.\n"); + break; + } + } + } + } + close(s); +}
-----END OF PAGE-----
-- Response ended
-- Page fetched on Sun Jun 2 16:28:07 2024