diff options
author | David Leonard <d@cvs.openbsd.org> | 1999-12-12 14:53:03 +0000 |
---|---|---|
committer | David Leonard <d@cvs.openbsd.org> | 1999-12-12 14:53:03 +0000 |
commit | 6dee7fa4cf14374061d29daab5809a32f3c523c5 (patch) | |
tree | ac85436b1131a28ab79e65e9ef523da5aeda1866 /games | |
parent | c6c94fa03aa77582cc1d8b8c435eabc2f35e5572 (diff) |
isplit complicated probe_drivers() out to own file. reviewed by pjanzen@
Diffstat (limited to 'games')
-rw-r--r-- | games/hunt/hunt/Makefile | 4 | ||||
-rw-r--r-- | games/hunt/hunt/list.c | 315 | ||||
-rw-r--r-- | games/hunt/hunt/list.h | 18 |
3 files changed, 335 insertions, 2 deletions
diff --git a/games/hunt/hunt/Makefile b/games/hunt/hunt/Makefile index e39325a93b8..192b0cbc5bf 100644 --- a/games/hunt/hunt/Makefile +++ b/games/hunt/hunt/Makefile @@ -1,8 +1,8 @@ # $NetBSD: Makefile,v 1.5 1998/02/18 22:37:31 jtc Exp $ -# $OpenBSD: Makefile,v 1.5 1999/08/30 23:32:10 d Exp $ +# $OpenBSD: Makefile,v 1.6 1999/12/12 14:53:02 d Exp $ PROG= hunt -SRCS= connect.c hunt.c otto.c playit.c display.c +SRCS= connect.c hunt.c otto.c playit.c display.c list.c MAN= hunt.6 LDADD= -lcurses DPADD= ${LIBCURSES} diff --git a/games/hunt/hunt/list.c b/games/hunt/hunt/list.c new file mode 100644 index 00000000000..1e9a22014c5 --- /dev/null +++ b/games/hunt/hunt/list.c @@ -0,0 +1,315 @@ +/* $OpenBSD: list.c,v 1.1 1999/12/12 14:53:02 d Exp $ */ +/* + * Copyright 1999, David Leonard. All rights reserved. + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved. This software + * is provided ``as is'' without express or implied warranty. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <netdb.h> +#include <unistd.h> +#include <errno.h> +#include <err.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/ioctl.h> + +#include <netinet/in.h> +#include <net/if.h> + +#include <arpa/inet.h> + +#include "hunt.h" +#include "list.h" + +/* Wait at most 5 seconds for a reply */ +#define LIST_DELAY 5 + +struct driver * drivers = NULL; +int numdrivers = 0; +int maxdrivers = 0; + +u_int16_t Server_port; + +static int numprobes = 0; +static int probe_sock[64]; +static struct timeval probe_timeout; + +struct driver * +next_driver() +{ + + return next_driver_fd(-1); +} + +struct driver * +next_driver_fd(fd) + int fd; +{ + fd_set r; + int maxfd = -1; + int i, s, ret, len; + struct driver *driver; + u_int16_t resp; + + if (fd == -1 && numprobes == 0) + return NULL; + + again: + FD_ZERO(&r); + if (fd != -1) { + FD_SET(fd, &r); + maxfd =fd; + } + for (i = 0; i < numprobes; i++) { + FD_SET(probe_sock[i], &r); + if (probe_sock[i] > maxfd) + maxfd = probe_sock[i]; + } + + ret = select(maxfd + 1, &r, NULL, NULL, &probe_timeout); + + if (ret == -1) { + if (errno == EINTR) + goto again; + err(1, "select"); + } + + if (ret == 0) { + /* Timeout - close all sockets */ + for (i = 0; i < numprobes; i++) + close(probe_sock[i]); + numprobes = 0; + return NULL; + } + + if (fd != -1 && FD_ISSET(fd, &r)) + /* Keypress. Return magic number */ + return (struct driver *)-1; + + for (i = 0; i < numprobes; i++) + /* Find the first ready socket */ + if (FD_ISSET(probe_sock[i], &r)) + break; + + s = probe_sock[i]; + + if (numdrivers >= maxdrivers) { + if (maxdrivers) { + maxdrivers *= 2; + drivers = realloc(drivers, sizeof *driver * maxdrivers); + } else { + maxdrivers = 16; + drivers = malloc(sizeof *driver * maxdrivers); + } + if (drivers == NULL) + err(1, "malloc"); + } + driver = &drivers[numdrivers]; + len = sizeof driver->addr; + ret = recvfrom(s, &resp, sizeof resp, 0, &driver->addr, &len); + if (ret == -1) + goto again; + driver->response = ntohs(resp); + + switch (driver->addr.sa_family) { + case AF_INET: + case AF_INET6: + ((struct sockaddr_in *)&driver->addr)->sin_port = + htons(driver->response); + break; + } + numdrivers++; + return driver; +} + +/* Return the hostname for a driver. */ +const char * +driver_name(driver) + struct driver *driver; +{ + const char *name; + static char buf[80]; + struct hostent *hp; + struct sockaddr_in *sin; + + name = NULL; + + if (driver->addr.sa_family == AF_INET) { + sin = (struct sockaddr_in *)&driver->addr; + hp = gethostbyaddr((char *)&sin->sin_addr, + sizeof sin->sin_addr, AF_INET); + if (hp != NULL) + name = hp->h_name; + else { + name = inet_ntop(AF_INET, &sin->sin_addr, + buf, sizeof buf); + } + } + + return name ? name : NULL; +} + +static int +start_probe(addr, req) + struct sockaddr *addr; + u_int16_t req; +{ + u_int16_t msg; + int s; + int enable; + + if (numprobes >= (sizeof probe_sock / sizeof probe_sock[0])) { + /* Just ridiculous */ + return -1; + } + + s = socket(addr->sa_family, SOCK_DGRAM, 0); + if (s < 0) { + warn("socket"); + return -1; + } + + enable = 1; + setsockopt(s, SOL_SOCKET, SO_BROADCAST, &enable, sizeof enable); + + switch (addr->sa_family) { + case AF_INET: + case AF_INET6: + ((struct sockaddr_in *)addr)->sin_port = + htons(Server_port); + break; + } + + msg = htons(req); + if (sendto(s, &msg, sizeof msg, 0, addr, addr->sa_len) == -1) + warn("sendto"); + probe_sock[numprobes++] = s; + + return 0; +} + +void +probe_cleanup() +{ + int i; + + for (i = 0; i < numprobes; i++) + close(probe_sock[i]); + numprobes = 0; +} + +/* + * If we have no preferred host then send a broadcast message to everyone. + * Otherwise, send the request message only to the preferred host. + */ +void +probe_drivers(req, preferred) + u_int16_t req; + char * preferred; +{ + struct sockaddr_in *target; + struct sockaddr_in localhost; + struct hostent *he; + char *inbuf = NULL, *ninbuf; + struct ifconf ifc; + struct ifreq *ifr; + int fd, inlen = 8192; + int i, len; + + probe_timeout.tv_sec = LIST_DELAY; + probe_timeout.tv_usec = 0; + numdrivers = 0; + + probe_cleanup(); + + /* Send exclusively to a preferred host. */ + if (preferred) { + struct sockaddr_in sin; + + target = NULL; + + if (!target) { + sin.sin_family = AF_INET; + sin.sin_len = sizeof sin; + if (inet_pton(AF_INET, preferred, &sin.sin_addr) == 1) + target = &sin; + } + + if (!target && (he = gethostbyname(preferred)) != NULL) { + sin.sin_family = he->h_addrtype; + sin.sin_len = sizeof sin; + memcpy(&sin.sin_addr, he->h_addr, he->h_length); + target = &sin; + } + + if (!target) + errx(1, "Bad hostname: %s", preferred); + + start_probe(target, req); + return; + } + + /* Send a query to the local machine: */ + localhost.sin_family = AF_INET; + localhost.sin_len = sizeof localhost; + localhost.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + start_probe((struct sockaddr *)&localhost, req); + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + err(1, "socket"); + + /* Find all attached networks: */ + while (1) { + ifc.ifc_len = inlen; + if ((ninbuf = realloc(inbuf, inlen)) == NULL) + err(1, "malloc"); + ifc.ifc_buf = inbuf = ninbuf; + if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0) + err(1, "SIOCGIFCONF"); + if (ifc.ifc_len + sizeof(*ifr) < inlen) + break; + inlen *= 2; + } + + /* Send a request to every attached broadcast address: */ + ifr = ifc.ifc_req; + for (i = 0; i < ifc.ifc_len; + i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) { + len = sizeof(ifr->ifr_name) + + (ifr->ifr_addr.sa_len > sizeof(struct sockaddr) ? + ifr->ifr_addr.sa_len : sizeof(struct sockaddr)); + + if (ifr->ifr_addr.sa_family != AF_INET) + continue; + + if (ioctl(fd, SIOCGIFFLAGS, (caddr_t)ifr) < 0) { + warn("%s: SIOCGIFFLAGS", ifr->ifr_name); + continue; + } + if ((ifr->ifr_flags & IFF_UP) == 0) + continue; + if ((ifr->ifr_flags & IFF_BROADCAST) != 0) { + if (ioctl(fd, SIOCGIFBRDADDR, (caddr_t)ifr) < 0) { + warn("%s: SIOCGIFBRDADDR", ifr->ifr_name); + continue; + } + target = (struct sockaddr_in *)&ifr->ifr_dstaddr; + } else if ((ifr->ifr_flags & IFF_POINTOPOINT) != 0) { + if (ioctl(fd, SIOCGIFDSTADDR, (caddr_t)ifr) < 0) { + warn("%s: SIOCGIFDSTADDR", ifr->ifr_name); + continue; + } + target = (struct sockaddr_in *)&ifr->ifr_broadaddr; + } else + continue; + + start_probe(target, req); + } + free(inbuf); + (void) close(fd); +} diff --git a/games/hunt/hunt/list.h b/games/hunt/hunt/list.h new file mode 100644 index 00000000000..acde43ca54f --- /dev/null +++ b/games/hunt/hunt/list.h @@ -0,0 +1,18 @@ +/* $OpenBSD: list.h,v 1.1 1999/12/12 14:53:02 d Exp $ */ + +struct driver { + struct sockaddr addr; + u_int16_t response; + int once; +}; + +extern struct driver *drivers; +extern int numdrivers; +extern u_int16_t Server_port; + +struct driver *next_driver __P((void)); +struct driver *next_driver_fd __P((int)); +const char * driver_name __P((struct driver *)); +void probe_drivers __P((u_int16_t, char *)); +void probe_cleanup __P((void)); + |