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 */