hex

hex.git
git clone git://git.lenczewski.org/hex.git
Log | Files | Refs

hex_server.h (6232B)


      1 #ifndef HEX_SERVER_H
      2 #define HEX_SERVER_H
      3 
      4 #define _XOPEN_SOURCE 700
      5 #define _GNU_SOURCE
      6 #define _DEFAULT_SOURCE
      7 
      8 #include <assert.h>
      9 #include <errno.h>
     10 #include <inttypes.h>
     11 #include <limits.h>
     12 #include <stdarg.h>
     13 #include <stdbool.h>
     14 #include <stdint.h>
     15 #include <stdio.h>
     16 #include <stdlib.h>
     17 #include <string.h>
     18 #include <time.h>
     19 #include <unistd.h>
     20 
     21 #include <arpa/inet.h>
     22 #include <fcntl.h>
     23 #include <netdb.h>
     24 #include <poll.h>
     25 #include <signal.h>
     26 #include <sys/resource.h>
     27 #include <sys/socket.h>
     28 #include <sys/stat.h>
     29 #include <sys/types.h>
     30 #include <sys/wait.h>
     31 
     32 /* hex network protocol definitions */
     33 #include "hex.h"
     34 
     35 typedef int32_t b32;
     36 
     37 typedef unsigned char c8;
     38 
     39 typedef uint8_t u8;
     40 typedef uint16_t u16;
     41 typedef uint32_t u32;
     42 typedef uint64_t u64;
     43 
     44 typedef int8_t s8;
     45 typedef int16_t s16;
     46 typedef int32_t s32;
     47 typedef int64_t s64;
     48 
     49 typedef float f32;
     50 typedef double f64;
     51 
     52 #define ARRLEN(arr) (sizeof (arr) / sizeof (arr)[0])
     53 
     54 #define MIN(a, b) ((a) > (b) ? (a) : (b))
     55 #define MAX(a, b) ((a) < (b) ? (b) : (a))
     56 
     57 #define RELPTR_NULL (0)
     58 
     59 #define _RELPTR_MASK(ty_relptr) ((ty_relptr)1 << ((sizeof(ty_relptr) * 8) - 1))
     60 #define _RELPTR_ENC(ty_relptr, ptroff) \
     61 	((ty_relptr)((ptroff) ^ _RELPTR_MASK(ty_relptr)))
     62 #define _RELPTR_DEC(ty_relptr, relptr) \
     63 	((ty_relptr)((relptr) ^ _RELPTR_MASK(ty_relptr)))
     64 
     65 #define RELPTR_ABS2REL(ty_relptr, base, absptr) \
     66 	((absptr) \
     67 	 ? _RELPTR_ENC(ty_relptr, (u8 *) absptr - (u8 *) base) \
     68 	 : RELPTR_NULL)
     69 
     70 #define RELPTR_REL2ABS(ty_absptr, ty_relptr, base, relptr) \
     71 	((relptr) \
     72 	 ? ((ty_absptr)((u8 *) base + _RELPTR_DEC(ty_relptr, relptr))) \
     73 	 : NULL)
     74 
     75 #define NANOSECS (1000000000ULL)
     76 
     77 #define TIMESPEC_TO_NANOS(sec, nsec) (((u64) (sec) * NANOSECS) + (nsec))
     78 
     79 #define KiB (1024)
     80 #define MiB (1024 * KiB)
     81 #define GiB (1024 * MiB)
     82 
     83 inline void
     84 difftimespec(struct timespec *restrict lhs, struct timespec *restrict rhs, struct timespec *restrict out)
     85 {
     86 	if (lhs->tv_sec <= rhs->tv_sec && lhs->tv_nsec < rhs->tv_nsec) {
     87 		out->tv_sec = 0;
     88 		out->tv_nsec = 0;
     89 	} else {
     90 		out->tv_sec = lhs->tv_sec - rhs->tv_sec - (lhs->tv_nsec < rhs->tv_nsec);
     91 		out->tv_nsec = lhs->tv_nsec - rhs->tv_nsec + (lhs->tv_nsec < rhs->tv_nsec) * NANOSECS;
     92 	}
     93 }
     94 
     95 /* hex server definitions */
     96 
     97 /* timeout for accept()-ing an agent connection before assuming a forfeit
     98  */
     99 #define HEX_AGENT_ACCEPT_TIMEOUT_MS (1 * 1000)
    100 
    101 #define HEX_AGENT_LOGFILE_TEMPLATE "/tmp/hex-agent.XXXXXX"
    102 #define HEX_AGENT_LOGFILE_MODE (0666)
    103 
    104 struct opts {
    105 	char *agent_1;
    106 	uid_t agent_1_uid;
    107 	char *agent_2;
    108 	uid_t agent_2_uid;
    109 	u32 board_size;
    110 	u32 game_secs;
    111 	u32 agent_threads;
    112 	u32 agent_mem_mib;
    113 	b32 verbose;
    114 };
    115 
    116 extern struct opts opts;
    117 
    118 inline void
    119 errlog(char *fmt, ...)
    120 {
    121 	va_list va;
    122 
    123 	va_start(va, fmt);
    124 	vfprintf(stderr, fmt, va);
    125 	va_end(va);
    126 }
    127 
    128 inline void
    129 dbglog(char *fmt, ...)
    130 {
    131 	va_list va;
    132 
    133 	if (!opts.verbose)
    134 		return;
    135 
    136 	va_start(va, fmt);
    137 	vfprintf(stderr, fmt, va);
    138 	va_end(va);
    139 }
    140 
    141 enum hex_error {
    142 	HEX_ERROR_OK,
    143 	HEX_ERROR_GAME_OVER,
    144 	HEX_ERROR_TIMEOUT,
    145 	HEX_ERROR_BAD_MOVE,
    146 	HEX_ERROR_BAD_MSG,
    147 	HEX_ERROR_DISCONNECT,
    148 	HEX_ERROR_SERVER,
    149 };
    150 
    151 inline char const *
    152 hexerrorstr(enum hex_error val)
    153 {
    154 	switch (val) {
    155 		case HEX_ERROR_OK:		return "OK";
    156 		case HEX_ERROR_GAME_OVER:	return "GAME_OVER";
    157 		case HEX_ERROR_TIMEOUT:		return "TIMEOUT";
    158 		case HEX_ERROR_BAD_MOVE:	return "BAD_MOVE";
    159 		case HEX_ERROR_BAD_MSG:		return "BAD_MSG";
    160 		case HEX_ERROR_DISCONNECT:	return "DISCONNECT";
    161 		case HEX_ERROR_SERVER:		return "SERVER";
    162 		default:			return "UNKNOWN";
    163 	}
    164 }
    165 
    166 struct statistics {
    167 	char *agent_1;
    168 	b32 agent_1_won;
    169 	u32 agent_1_rounds;
    170 	f32 agent_1_secs;
    171 	enum hex_error agent_1_err;
    172 	char *agent_2;
    173 	b32 agent_2_won;
    174 	u32 agent_2_rounds;
    175 	f32 agent_2_secs;
    176 	enum hex_error agent_2_err;
    177 };
    178 
    179 struct agent_state {
    180 	/* which player are we, and what agent do we run */
    181 	enum hex_player player;
    182 	char *agent;
    183 	uid_t agent_uid;
    184 	char logfile[PATH_MAX];
    185 
    186 	/* how much time this agent has left to execute before it times out */
    187 	struct timespec timer;
    188 
    189 	/* socket for communicating with agent */
    190 	int sockfd;
    191 	struct sockaddr_storage sock_addr;
    192 	socklen_t sock_addrlen;
    193 };
    194 
    195 enum cell_state {
    196 	CELL_EMPTY,
    197 	CELL_BLACK,
    198 	CELL_WHITE,
    199 };
    200 
    201 struct board_segment {
    202 	s16 parent_relptr; /* pointer to root of rooted tree */
    203 	u8 rank; /* disambiguation between identical segments */
    204 	u8 cell; /* the owner of the current cell */
    205 };
    206 
    207 static inline s16
    208 board_segment_abs2rel(struct board_segment *base, struct board_segment *absptr) {
    209 	return RELPTR_ABS2REL(s16, base, absptr);
    210 }
    211 
    212 static inline struct board_segment *
    213 board_segment_rel2abs(struct board_segment *base, s16 relptr) {
    214 	return RELPTR_REL2ABS(struct board_segment *, s16, base, relptr);
    215 }
    216 
    217 extern struct board_segment *
    218 board_segment_root(struct board_segment *self);
    219 
    220 extern void
    221 board_segment_merge(struct board_segment *restrict self, struct board_segment *restrict elem);
    222 
    223 extern b32
    224 board_segment_joined(struct board_segment *self, struct board_segment *elem);
    225 
    226 struct board_state {
    227 	u32 size;
    228 
    229 	/* track connections between board "segments" (groups of cells owned
    230 	 * by one player), and the edges for each player
    231 	 */
    232 	struct board_segment black_source, black_sink, white_source, white_sink;
    233 	struct board_segment segments[];
    234 };
    235 
    236 extern struct board_state *
    237 board_alloc(size_t size);
    238 
    239 extern void
    240 board_free(struct board_state *self);
    241 
    242 extern void
    243 board_print(struct board_state *self);
    244 
    245 extern b32
    246 board_play(struct board_state *self, enum hex_player player, s32 x, s32 y);
    247 
    248 extern void
    249 board_swap(struct board_state *self);
    250 
    251 extern b32
    252 board_completed(struct board_state *self, enum hex_player *winner);
    253 
    254 struct server_state {
    255 	struct agent_state black_agent, white_agent;
    256 	struct board_state *board;
    257 
    258 	/* socket for accepting agent connections */
    259 	int servfd;
    260 	struct sockaddr_storage serv_addr;
    261 	socklen_t serv_addrlen;
    262 	char serv_host[NI_MAXHOST], serv_port[NI_MAXSERV];
    263 };
    264 
    265 extern bool
    266 server_init(struct server_state *state);
    267 
    268 extern void
    269 server_free(struct server_state *state);
    270 
    271 extern bool
    272 server_spawn_agent(struct server_state *state, struct agent_state *agent_state);
    273 
    274 extern void
    275 server_wait_all_agents(struct server_state *state);
    276 
    277 extern void
    278 server_run(struct server_state *state, struct statistics *statistics);
    279 
    280 #endif /* HEX_SERVER_H */