#include #include #include #include #include #include #include #include #define TIMEOUT 30 #define NTOKENS 20 #define TOKENLEN 50 char tokens[NTOKENS][TOKENLEN]; int ntokens; char *admonishment = "Try for fewer guesses next time!\n"; struct state { time_t death; uint16_t answer; uint16_t guesses; }; #define NSTATES 500 struct state states[NSTATES] = { 0 }; int bind_port(struct in6_addr *addr, int fd, uint16_t port) { struct sockaddr_in6 saddr = { 0 }; saddr.sin6_family = AF_INET6; saddr.sin6_port = htons(port); memcpy(&saddr.sin6_addr, addr, sizeof *addr); return bind(fd, (struct sockaddr *) &saddr, sizeof saddr); } struct newgame { uint16_t offset; uint16_t token; }; void new_game(int sock, time_t now, struct sockaddr_in6 *from, socklen_t fromlen) { int i; struct newgame g; for (g.offset = 0; g.offset < NSTATES; g.offset += 1) { struct state *s = &states[g.offset]; if (s->death < now) { s->death = now + TIMEOUT; s->guesses = 0; s->answer = 0; for (i = 0; i < 4; i += 1) { s->answer = (s->answer << 4) | ((random() % 6) + 1); } g.token = s->answer; break; } } printf("=%02x\n", g.token); if (g.offset < NSTATES) { sendto(sock, &g, sizeof(g), 0, (struct sockaddr *) from, fromlen); } } struct guess { uint16_t offset; uint16_t token; uint16_t guess; }; void loop(int sock) { struct guess g; struct state *cur; struct sockaddr_in6 from; socklen_t fromlen = sizeof from; time_t now = time(NULL); /* * Read guess */ { ssize_t inlen; inlen = recvfrom(sock, &g, sizeof g, 0, (struct sockaddr *) &from, &fromlen); if (inlen != sizeof g) { return; } } /* * Bounds check */ if (g.offset >= NSTATES) { g.offset = 0; } cur = &states[g.offset]; if ((g.token != cur->answer) || /* Wrong token? */ (cur->death < now) || /* Old game? */ (cur->guesses++ > 100)) { /* Too dumb? */ /* * Start a new game */ new_game(sock, now, &from, fromlen); return; } else { uint8_t reply = 0; int i; for (i = 0; i < 4; i += 1) { int s = (g.guess >> (i * 4)) & 0xf; int a = (cur->answer >> (i * 4)) & 0xf; if ((s < 1) || (s > 7)) { reply = 0; break; } else if (s == a) { reply += 0x10; } else if (s & a) { reply += 0x01; } } printf("%02x ? %02x\n", g.guess, reply); if (reply == 0x40) { char *r; if (cur->guesses <= ntokens) { r = tokens[cur->guesses - 1]; } else { r = admonishment; } sendto(sock, r, strlen(r) - 1, 0, (struct sockaddr *) &from, fromlen); cur->death = 0; } else { sendto(sock, &reply, sizeof reply, 0, (struct sockaddr *) &from, fromlen); } } } int main(int argc, char *argv[]) { int sock; int i; struct in6_addr addr; srand(time(NULL)); if (argc > 1) { if (0 >= inet_pton(AF_INET6, argv[1], &addr)) { fprintf(stderr, "invalid address: %s\n", argv[1]); return EX_IOERR; } } else { memcpy(&addr, &in6addr_any, sizeof addr); } /* * Read in tokens */ for (ntokens = 0; ntokens < NTOKENS; ntokens += 1) { if (NULL == fgets(tokens[ntokens], TOKENLEN, stdin)) { break; } } printf("Read %d tokens.\n", ntokens); /* * Set up socket */ sock = socket(AF_INET6, SOCK_DGRAM, 0); i = bind_port(&addr, sock, 3782); if (-1 == i) { perror("Bind port 3782"); return EX_IOERR; } while (1) { loop(sock); } return 0; }