2 * Copyright 2001, David Leonard. All rights reserved.
3 * Redistribution and use in source and binary forms with or without
4 * modification are permitted provided that this notice is preserved.
5 * This software is provided ``as is'' without express or implied warranty.
7 * $OpenBSD: list.c,v 1.5 2007/09/04 22:39:31 hshoexer Exp $
8 * $DragonFly: src/games/hunt/hunt/list.c,v 1.2 2008/09/04 16:12:51 swildner Exp $
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <sys/sockio.h>
22 #include <sys/ioctl.h>
24 #include <netinet/in.h>
27 #include <arpa/inet.h>
32 /* Wait at most 5 seconds for a reply */
35 struct driver *drivers = NULL;
39 u_int16_t Server_port;
41 static int numprobes = 0;
42 static int probe_sock[64];
43 static struct timeval probe_timeout;
49 return next_driver_fd(-1);
53 next_driver_fd(int fd)
58 struct driver *driver;
61 if (fd == -1 && numprobes == 0)
70 for (i = 0; i < numprobes; i++) {
71 FD_SET(probe_sock[i], &r);
72 if (probe_sock[i] > maxfd)
73 maxfd = probe_sock[i];
76 probe_timeout.tv_sec = LIST_DELAY;
77 probe_timeout.tv_usec = 0;
78 ret = select(maxfd + 1, &r, NULL, NULL, &probe_timeout);
87 /* Timeout - close all sockets */
88 for (i = 0; i < numprobes; i++)
94 if (fd != -1 && FD_ISSET(fd, &r))
95 /* Keypress. Return magic number */
96 return (struct driver *)-1;
98 for (i = 0; i < numprobes; i++)
99 /* Find the first ready socket */
100 if (FD_ISSET(probe_sock[i], &r))
105 if (numdrivers >= maxdrivers) {
108 drivers = realloc(drivers, sizeof *driver * maxdrivers);
111 drivers = calloc(sizeof *driver, maxdrivers);
116 driver = &drivers[numdrivers];
117 len = sizeof driver->addr;
118 ret = recvfrom(s, &resp, sizeof resp, 0, &driver->addr, &len);
121 driver->response = ntohs(resp);
123 switch (driver->addr.sa_family) {
126 ((struct sockaddr_in *)&driver->addr)->sin_port =
127 htons(driver->response);
134 /* Return the hostname for a driver. */
136 driver_name(struct driver *driver)
141 struct sockaddr_in *sin;
145 if (driver->addr.sa_family == AF_INET) {
146 sin = (struct sockaddr_in *)&driver->addr;
147 hp = gethostbyaddr(&sin->sin_addr, sizeof sin->sin_addr,
152 name = inet_ntop(AF_INET, &sin->sin_addr,
161 start_probe(struct sockaddr *addr, u_int16_t req)
167 if (numprobes >= (int)(sizeof probe_sock / sizeof probe_sock[0])) {
168 /* Just ridiculous */
172 s = socket(addr->sa_family, SOCK_DGRAM, 0);
179 setsockopt(s, SOL_SOCKET, SO_BROADCAST, &enable, sizeof enable);
181 switch (addr->sa_family) {
184 ((struct sockaddr_in *)addr)->sin_port =
190 if (sendto(s, &msg, sizeof msg, 0, addr, addr->sa_len) == -1)
192 probe_sock[numprobes++] = s;
202 for (i = 0; i < numprobes; i++)
203 close(probe_sock[i]);
208 * If we have no preferred host then send a broadcast message to everyone.
209 * Otherwise, send the request message only to the preferred host.
212 probe_drivers(u_int16_t req, char *preferred)
214 struct sockaddr_in *target;
215 struct sockaddr_in localhost;
217 char *inbuf = NULL, *ninbuf;
220 int fd, inlen = 8192;
227 /* Send exclusively to a preferred host. */
229 struct sockaddr_in sin;
234 sin.sin_family = AF_INET;
235 sin.sin_len = sizeof sin;
236 if (inet_pton(AF_INET, preferred, &sin.sin_addr) == 1)
240 if (!target && (he = gethostbyname(preferred)) != NULL) {
241 sin.sin_family = he->h_addrtype;
242 sin.sin_len = sizeof sin;
243 memcpy(&sin.sin_addr, he->h_addr, he->h_length);
248 errx(1, "Bad hostname: %s", preferred);
250 start_probe((struct sockaddr *)target, req);
254 /* Send a query to the local machine: */
255 localhost.sin_family = AF_INET;
256 localhost.sin_len = sizeof localhost;
257 localhost.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
258 start_probe((struct sockaddr *)&localhost, req);
260 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
263 /* Find all attached networks: */
266 if ((ninbuf = realloc(inbuf, inlen)) == NULL)
268 ifc.ifc_buf = inbuf = ninbuf;
269 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0)
270 err(1, "SIOCGIFCONF");
271 if (ifc.ifc_len + (int)sizeof(*ifr) < inlen)
276 /* Send a request to every attached broadcast address: */
278 for (i = 0; i < ifc.ifc_len;
279 i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) {
280 len = sizeof(ifr->ifr_name) +
281 (ifr->ifr_addr.sa_len > sizeof(struct sockaddr) ?
282 ifr->ifr_addr.sa_len : sizeof(struct sockaddr));
284 if (ifr->ifr_addr.sa_family != AF_INET)
287 if (ioctl(fd, SIOCGIFFLAGS, (caddr_t)ifr) < 0) {
288 warn("%s: SIOCGIFFLAGS", ifr->ifr_name);
291 if ((ifr->ifr_flags & IFF_UP) == 0)
293 if ((ifr->ifr_flags & IFF_BROADCAST) != 0) {
294 if (ioctl(fd, SIOCGIFBRDADDR, (caddr_t)ifr) < 0) {
295 warn("%s: SIOCGIFBRDADDR", ifr->ifr_name);
298 target = (struct sockaddr_in *)&ifr->ifr_dstaddr;
299 } else if ((ifr->ifr_flags & IFF_POINTOPOINT) != 0) {
300 if (ioctl(fd, SIOCGIFDSTADDR, (caddr_t)ifr) < 0) {
301 warn("%s: SIOCGIFDSTADDR", ifr->ifr_name);
304 target = (struct sockaddr_in *)&ifr->ifr_broadaddr;
308 start_probe((struct sockaddr *)target, req);