summaryrefslogtreecommitdiff
path: root/games
diff options
context:
space:
mode:
authorDavid Leonard <d@cvs.openbsd.org>1999-12-12 14:53:03 +0000
committerDavid Leonard <d@cvs.openbsd.org>1999-12-12 14:53:03 +0000
commit6dee7fa4cf14374061d29daab5809a32f3c523c5 (patch)
treeac85436b1131a28ab79e65e9ef523da5aeda1866 /games
parentc6c94fa03aa77582cc1d8b8c435eabc2f35e5572 (diff)
isplit complicated probe_drivers() out to own file. reviewed by pjanzen@
Diffstat (limited to 'games')
-rw-r--r--games/hunt/hunt/Makefile4
-rw-r--r--games/hunt/hunt/list.c315
-rw-r--r--games/hunt/hunt/list.h18
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));
+