From 4c815854a9d17ac78d0088e0955ada99898b5ca5 Mon Sep 17 00:00:00 2001 From: dholland Date: Sun, 30 Mar 2014 04:31:21 +0000 Subject: Clean up the handling of the list of hunt daemons. --- hunt/hunt/hunt.c | 158 ++++++++++++++++++++++-------------- hunt/hunt/hunt_private.h | 14 ++-- hunt/hunt/server.c | 207 ++++++++++++++++++++++++++++------------------- 3 files changed, 230 insertions(+), 149 deletions(-) (limited to 'hunt') diff --git a/hunt/hunt/hunt.c b/hunt/hunt/hunt.c index 5da57db3..ca481383 100644 --- a/hunt/hunt/hunt.c +++ b/hunt/hunt/hunt.c @@ -1,4 +1,4 @@ -/* $NetBSD: hunt.c,v 1.50 2014/03/30 03:35:26 dholland Exp $ */ +/* $NetBSD: hunt.c,v 1.51 2014/03/30 04:31:21 dholland Exp $ */ /* * Copyright (c) 1983-2003, Regents of the University of California. * All rights reserved. @@ -32,7 +32,7 @@ #include #ifndef lint -__RCSID("$NetBSD: hunt.c,v 1.50 2014/03/30 03:35:26 dholland Exp $"); +__RCSID("$NetBSD: hunt.c,v 1.51 2014/03/30 04:31:21 dholland Exp $"); #endif /* not lint */ #include @@ -47,7 +47,7 @@ __RCSID("$NetBSD: hunt.c,v 1.50 2014/03/30 03:35:26 dholland Exp $"); #include #include #include -#include +#include #include "hunt_common.h" #include "pathnames.h" @@ -64,7 +64,7 @@ static const char Driver[] = PATH_HUNTD; #endif #ifdef INTERNET -uint16_t Test_port = TEST_PORT; +static uint16_t Test_port = TEST_PORT; #else static const char Sock_name[] = PATH_HUNTSOCKET; #endif @@ -79,7 +79,7 @@ char Buf[BUFSIZ]; /*static*/ int Socket; #ifdef INTERNET -char *Sock_host; +static char *Sock_host; static char *use_port; char *Send_message = NULL; #endif @@ -101,17 +101,34 @@ static int in_visual; extern int cur_row, cur_col; -static void dump_scores(SOCKET); +static void dump_scores(const struct sockaddr_storage *, socklen_t); static long env_init(long); static void fill_in_blanks(void); static void fincurs(void); static void rmnl(char *); static void sigterm(int) __dead; static void sigusr1(int) __dead; -static void find_driver(bool); +static void find_driver(void); static void start_driver(void); extern int Otto_mode; + +static const char * +lookuphost(const struct sockaddr_storage *host, socklen_t hostlen) +{ + static char buf[NI_MAXHOST]; + int flags, result; + + flags = NI_NOFQDN; + + result = getnameinfo((const struct sockaddr *)host, hostlen, + buf, sizeof(buf), NULL, 0, NI_NOFQDN); + if (result) { + leavex(1, "getnameinfo: %s", gai_strerror(result)); + } + return buf; +} + /* * main: * Main program for local process @@ -215,29 +232,36 @@ main(int ac, char **av) #endif #ifdef INTERNET + serverlist_setup(Sock_host, Test_port); + if (Show_scores) { - SOCKET *hosts; + const struct sockaddr_storage *host; + socklen_t hostlen; u_short msg = C_SCORES; + unsigned i; - for (hosts = list_drivers(msg); hosts->sin_port != 0; hosts += 1) - dump_scores(*hosts); + serverlist_query(msg); + for (i = 0; i < serverlist_num(); i++) { + host = serverlist_gethost(i, &hostlen); + dump_scores(host, hostlen); + } exit(0); } if (Query_driver) { - SOCKET *hosts; + const struct sockaddr_storage *host; + socklen_t hostlen; u_short msg = C_MESSAGE; + u_short num_players; + unsigned i; - for (hosts = list_drivers(msg); hosts->sin_port != 0; hosts += 1) { - struct hostent *hp; - int num_players; + serverlist_query(msg); + for (i = 0; i < serverlist_num(); i++) { + host = serverlist_gethost(i, &hostlen); + num_players = ntohs(serverlist_getresponse(i)); - hp = gethostbyaddr((char *) &hosts->sin_addr, - sizeof hosts->sin_addr, AF_INET); - num_players = ntohs(hosts->sin_port); printf("%d player%s hunting on %s!\n", num_players, (num_players == 1) ? "" : "s", - hp != NULL ? hp->h_name : - inet_ntoa(hosts->sin_addr)); + lookuphost(host, hostlen)); } exit(0); } @@ -267,7 +291,7 @@ main(int ac, char **av) for (;;) { #ifdef INTERNET - find_driver(true); + find_driver(); if (Daemon.sin_port == 0) leavex(1, "Game not found, try again"); @@ -348,73 +372,81 @@ main(int ac, char **av) #ifdef INTERNET static void -find_driver(bool do_startup) +find_driver(void) { - SOCKET *hosts; - u_short msg = C_PLAYER; - + u_short msg; + const struct sockaddr_storage *host; + socklen_t hostlen; + unsigned num; + int i, c; + char buf[128]; + + msg = C_PLAYER; #ifdef MONITOR if (Am_monitor) { msg = C_MONITOR; } #endif - hosts = list_drivers(msg); - if (hosts[0].sin_port != htons(0)) { - int i, c; - - if (hosts[1].sin_port == htons(0)) { - Daemon = hosts[0]; + serverlist_query(msg); + num = serverlist_num(); + if (num == 0) { + start_driver(); + sleep(2); + /* try again */ + serverlist_query(msg); + num = serverlist_num(); + if (num == 0) { + /* give up */ return; } - /* go thru list and return host that matches daemon */ + } + + if (num == 1) { + host = serverlist_gethost(0, &hostlen); + } else { clear_the_screen(); move(1, 0); put_str("Pick one:"); - for (i = 0; i < HEIGHT - 4 && hosts[i].sin_port != htons(0); - i += 1) { - struct hostent *hp; - char buf[80]; - + for (i = 0; i < HEIGHT - 4 && i < (int)num; i++) { move(3 + i, 0); - hp = gethostbyaddr((char *) &hosts[i].sin_addr, - sizeof hosts[i].sin_addr, AF_INET); + host = serverlist_gethost(i, &hostlen); (void) snprintf(buf, sizeof(buf), - "%8c %.64s", 'a' + i, - hp != NULL ? hp->h_name - : inet_ntoa(hosts->sin_addr)); + "%8c %.64s", 'a' + i, + lookuphost(host, hostlen)); put_str(buf); } move(4 + i, 0); put_str("Enter letter: "); refresh(); - while (!islower(c = getchar()) || (c -= 'a') >= i) { + while (1) { + c = getchar(); + if (c == EOF) { + leavex(1, "EOF on stdin"); + } + if (islower((unsigned char)c) && c - 'a' < i) { + break; + } beep(); refresh(); } - Daemon = hosts[c]; clear_the_screen(); - return; + host = serverlist_gethost(c - 'a', &hostlen); } - if (!do_startup) - return; - start_driver(); - sleep(2); - find_driver(false); + /* XXX fix this (won't work in ipv6) */ + assert(hostlen == sizeof(Daemon)); + memcpy(&Daemon, host, sizeof(Daemon)); } static void -dump_scores(SOCKET host) +dump_scores(const struct sockaddr_storage *host, socklen_t hostlen) { - struct hostent *hp; int s; char buf[BUFSIZ]; - int cnt; + ssize_t cnt; - hp = gethostbyaddr((char *) &host.sin_addr, sizeof host.sin_addr, - AF_INET); - printf("\n%s:\n", hp != NULL ? hp->h_name : inet_ntoa(host.sin_addr)); + printf("\n%s:\n", lookuphost(host, hostlen)); fflush(stdout); s = socket(SOCK_FAMILY, SOCK_STREAM, 0); @@ -597,12 +629,16 @@ fincurs(void) * tty stats, and print errno. */ void -leave(int eval, const char *mesg) +leave(int exitval, const char *fmt, ...) { int serrno = errno; + va_list ap; + fincurs(); + va_start(ap, fmt); errno = serrno; - err(eval, "%s", mesg ? mesg : ""); + verr(exitval, fmt, ap); + va_end(ap); } /* @@ -611,10 +647,14 @@ leave(int eval, const char *mesg) * tty stats. */ void -leavex(int eval, const char *mesg) +leavex(int exitval, const char *fmt, ...) { + va_list ap; + fincurs(); - errx(eval, "%s", mesg ? mesg : ""); + va_start(ap, fmt); + verrx(exitval, fmt, ap); + va_end(ap); } static long diff --git a/hunt/hunt/hunt_private.h b/hunt/hunt/hunt_private.h index db1c8672..7e5ba3a6 100644 --- a/hunt/hunt/hunt_private.h +++ b/hunt/hunt/hunt_private.h @@ -1,4 +1,4 @@ -/* $NetBSD: hunt_private.h,v 1.6 2014/03/30 03:35:26 dholland Exp $ */ +/* $NetBSD: hunt_private.h,v 1.7 2014/03/30 04:31:21 dholland Exp $ */ /* * Copyright (c) 1983-2003, Regents of the University of California. @@ -66,8 +66,6 @@ extern bool no_beep; #ifdef INTERNET /* XXX this pile had to be made public to split off server.c; fix them up */ extern SOCKET Daemon; -extern uint16_t Test_port; -extern char *Sock_host; #endif /* @@ -80,8 +78,8 @@ void do_connect(char *, char, long); /* in hunt.c */ __dead void bad_con(void); __dead void bad_ver(void); -__dead void leave(int, const char *); -__dead void leavex(int, const char *); +__dead __printflike(2, 3) void leave(int, const char *, ...); +__dead __printflike(2, 3) void leavex(int, const char *, ...); void intr(int); /* in otto.c */ @@ -95,5 +93,9 @@ void do_message(void); /* in server.c */ #ifdef INTERNET -SOCKET *list_drivers(unsigned short msg); +void serverlist_setup(const char *, uint16_t); +void serverlist_query(unsigned short msg); +unsigned serverlist_num(void); +const struct sockaddr_storage *serverlist_gethost(unsigned, socklen_t *); +unsigned short serverlist_getresponse(unsigned); #endif diff --git a/hunt/hunt/server.c b/hunt/hunt/server.c index ac7a4fde..a909d2d0 100644 --- a/hunt/hunt/server.c +++ b/hunt/hunt/server.c @@ -1,4 +1,4 @@ -/* $NetBSD: server.c,v 1.5 2014/03/30 03:26:19 dholland Exp $ */ +/* $NetBSD: server.c,v 1.6 2014/03/30 04:31:21 dholland Exp $ */ /* * Copyright (c) 1983-2003, Regents of the University of California. * All rights reserved. @@ -31,7 +31,7 @@ */ #include -__RCSID("$NetBSD: server.c,v 1.5 2014/03/30 03:26:19 dholland Exp $"); +__RCSID("$NetBSD: server.c,v 1.6 2014/03/30 04:31:21 dholland Exp $"); #include #include @@ -60,13 +60,16 @@ __RCSID("$NetBSD: server.c,v 1.5 2014/03/30 03:26:19 dholland Exp $"); static SOCKET *daemons; static unsigned int numdaemons, maxdaemons; +static SOCKET *brdv; +static int brdc; + static bool initial = true; static struct in_addr local_address; -static int brdc; -static SOCKET *brdv; +static const char *explicit_host; +static uint16_t port; -static void -serverlist_setup(void) +void +serverlist_setup(const char *explicit_host_arg, uint16_t port_arg) { char local_name[MAXHOSTNAMELEN + 1]; struct hostent *hp; @@ -86,6 +89,11 @@ serverlist_setup(void) if (daemons == NULL) { leavex(1, "Out of memory."); } + + if (explicit_host_arg) { + explicit_host = explicit_host_arg; + } + port = port_arg; } static void @@ -111,6 +119,19 @@ add_daemon_addr(const struct sockaddr_storage *addr, uint16_t port_num) * Note that we do *not* convert from network to host * order since the port number we were sent *should* * already be in network order. + * + * The result may be either the port number for the hunt + * socket or the port number for the stats socket... or the + * number of players connected and not a port number at all, + * depending on the packet type. + * + * For now at least it is ok to stuff it in here, because the + * usage of the various different packet types and the + * persistence of the results vs. the program exiting does not + * cause us to get confused. If the game is made more + * self-contained in the future we'll need to be more careful + * about this, especially if we make the caching of results + * less scattershot. */ daemons[numdaemons] = *sin; daemons[numdaemons].sin_port = port_num; @@ -165,6 +186,74 @@ getbroadcastaddrs(struct sockaddr_in **vector) return vec_cnt; } +static void +send_messages(int contactsock, unsigned short msg) +{ + struct sockaddr_in contactaddr; + struct hostent *hp; + uint16_t wiremsg; + int option; + int i; + + contactaddr.sin_family = SOCK_FAMILY; + contactaddr.sin_port = htons(port); + + if (explicit_host != NULL) { /* explicit host given */ + hp = gethostbyname(explicit_host); + if (hp == NULL) { + leavex(1, "%s: Unknown host", explicit_host); + } + memcpy(&contactaddr.sin_addr, hp->h_addr, + sizeof(contactaddr.sin_addr)); + wiremsg = htons(msg); + (void) sendto(contactsock, &wiremsg, sizeof(wiremsg), 0, + (struct sockaddr *)&contactaddr, + sizeof(contactaddr)); + return; + } + + if (!initial) { + /* favor host of previous session by contacting it first */ + contactaddr.sin_addr = Daemon.sin_addr; + + /* Must be playing! */ + assert(msg == C_PLAYER); + wiremsg = htons(msg); + + (void) sendto(contactsock, &wiremsg, sizeof(wiremsg), 0, + (struct sockaddr *)&contactaddr, sizeof(contactaddr)); + } + + if (initial) + brdc = getbroadcastaddrs(&brdv); + +#ifdef SO_BROADCAST + /* Sun's will broadcast even though this option can't be set */ + option = 1; + if (setsockopt(contactsock, SOL_SOCKET, SO_BROADCAST, + &option, sizeof option) < 0) { + leave(1, "setsockopt broadcast"); + /* NOTREACHED */ + } +#endif + + /* send broadcast packets on all interfaces */ + wiremsg = htons(msg); + for (i = 0; i < brdc; i++) { + contactaddr.sin_addr = brdv[i].sin_addr; + if (sendto(contactsock, &wiremsg, sizeof(wiremsg), 0, + (struct sockaddr *)&contactaddr, + sizeof(contactaddr)) < 0) { + leave(1, "sendto"); + } + } + contactaddr.sin_addr = local_address; + if (sendto(contactsock, &wiremsg, sizeof(wiremsg), 0, + (struct sockaddr *)&contactaddr, sizeof(contactaddr)) < 0) { + leave(1, "sendto"); + } +} + static void get_responses(int contactsock) { @@ -217,102 +306,52 @@ get_responses(int contactsock) add_daemon_addr(&addr, port_num); } - /* terminate list with local address */ - { - struct sockaddr_in sin; - - sin.sin_family = SOCK_FAMILY; - sin.sin_addr = local_address; - sin.sin_port = htons(0); - add_daemon_addr((struct sockaddr_storage *)&sin, htons(0)); - } - initial = false; } -SOCKET * -list_drivers(unsigned short msg) +void +serverlist_query(unsigned short msg) { - struct hostent *hp; - struct sockaddr_in contactaddr; - int option; - uint16_t wiremsg; int contactsock; - int i; - - if (initial) { - /* do one time initialization */ - serverlist_setup(); - } - if (!initial && Sock_host != NULL) { - /* address already valid */ - return daemons; + if (!initial && explicit_host != NULL) { + /* already did the work, no point doing it again */ + return; } contactsock = socket(SOCK_FAMILY, SOCK_DGRAM, 0); if (contactsock < 0) { leave(1, "socket system call failed"); } - contactaddr.sin_family = SOCK_FAMILY; - contactaddr.sin_port = htons(Test_port); - if (Sock_host != NULL) { /* explicit host given */ - if ((hp = gethostbyname(Sock_host)) == NULL) { - leavex(1, "Unknown host"); - /* NOTREACHED */ - } - memcpy(&contactaddr.sin_addr, hp->h_addr, - sizeof(contactaddr.sin_addr)); - wiremsg = htons(msg); - (void) sendto(contactsock, &wiremsg, sizeof(wiremsg), 0, - (struct sockaddr *)&contactaddr, - sizeof(contactaddr)); - get_responses(contactsock); - (void) close(contactsock); - return daemons; - } + send_messages(contactsock, msg); + get_responses(contactsock); - if (!initial) { - /* favor host of previous session by contacting it first */ - contactaddr.sin_addr = Daemon.sin_addr; - wiremsg = htons(C_PLAYER); /* Must be playing! */ - (void) sendto(contactsock, &wiremsg, sizeof(wiremsg), 0, - (struct sockaddr *)&contactaddr, sizeof(contactaddr)); - } + (void) close(contactsock); +} - if (initial) - brdc = getbroadcastaddrs(&brdv); +unsigned +serverlist_num(void) +{ + return numdaemons; +} -#ifdef SO_BROADCAST - /* Sun's will broadcast even though this option can't be set */ - option = 1; - if (setsockopt(contactsock, SOL_SOCKET, SO_BROADCAST, - &option, sizeof option) < 0) { - leave(1, "setsockopt broadcast"); - /* NOTREACHED */ - } -#endif +const struct sockaddr_storage * +serverlist_gethost(unsigned i, socklen_t *len_ret) +{ + struct sockaddr_in *ret; - /* send broadcast packets on all interfaces */ - wiremsg = htons(msg); - for (i = 0; i < brdc; i++) { - contactaddr.sin_addr = brdv[i].sin_addr; - if (sendto(contactsock, &wiremsg, sizeof(wiremsg), 0, - (struct sockaddr *)&contactaddr, - sizeof(contactaddr)) < 0) { - leave(1, "sendto"); - } - } - contactaddr.sin_addr = local_address; - if (sendto(contactsock, &wiremsg, sizeof(wiremsg), 0, - (struct sockaddr *)&contactaddr, sizeof(contactaddr)) < 0) { - leave(1, "sendto"); - } + assert(i < numdaemons); + ret = &daemons[i]; + *len_ret = sizeof(*ret); + return (struct sockaddr_storage *)ret; +} - get_responses(contactsock); - (void) close(contactsock); - return daemons; +unsigned short +serverlist_getresponse(unsigned i) +{ + assert(i < numdaemons); + return daemons[i].sin_port; } #endif /* INTERNET */ -- cgit v1.2.3-56-ge451