summaryrefslogtreecommitdiffstats
path: root/hunt/hunt/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'hunt/hunt/server.c')
-rw-r--r--hunt/hunt/server.c207
1 files changed, 123 insertions, 84 deletions
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 <sys/cdefs.h>
-__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 <sys/param.h>
#include <sys/stat.h>
@@ -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;
@@ -166,6 +187,74 @@ getbroadcastaddrs(struct sockaddr_in **vector)
}
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)
{
struct pollfd set[1];
@@ -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 */