]>
git.cameronkatri.com Git - bsdgames-darwin.git/blob - hunt/hunt/server.c
a909d2d0ffd094430ec427693cdf44af90f514c4
1 /* $NetBSD: server.c,v 1.6 2014/03/30 04:31:21 dholland Exp $ */
3 * Copyright (c) 1983-2003, Regents of the University of California.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * + Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * + Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * + Neither the name of the University of California, San Francisco nor
16 * the names of its contributors may be used to endorse or promote
17 * products derived from this software without specific prior written
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 __RCSID("$NetBSD: server.c,v 1.6 2014/03/30 04:31:21 dholland Exp $");
36 #include <sys/param.h>
50 #include "hunt_common.h"
51 #include "pathnames.h"
52 #include "hunt_private.h"
57 * Code for finding and talking to hunt daemons.
60 static SOCKET
*daemons
;
61 static unsigned int numdaemons
, maxdaemons
;
66 static bool initial
= true;
67 static struct in_addr local_address
;
68 static const char *explicit_host
;
72 serverlist_setup(const char *explicit_host_arg
, uint16_t port_arg
)
74 char local_name
[MAXHOSTNAMELEN
+ 1];
77 if (gethostname(local_name
, sizeof(local_name
)) < 0) {
78 leavex(1, "Sorry, I have no hostname.");
80 local_name
[sizeof(local_name
) - 1] = '\0';
81 if ((hp
= gethostbyname(local_name
)) == NULL
) {
82 leavex(1, "Can't find myself.");
84 memcpy(&local_address
, hp
->h_addr
, sizeof(local_address
));
88 daemons
= malloc(maxdaemons
* sizeof(daemons
[0]));
89 if (daemons
== NULL
) {
90 leavex(1, "Out of memory.");
93 if (explicit_host_arg
) {
94 explicit_host
= explicit_host_arg
;
100 add_daemon_addr(const struct sockaddr_storage
*addr
, uint16_t port_num
)
102 const struct sockaddr_in
*sin
;
104 if (addr
->ss_family
!= AF_INET
) {
107 sin
= (const struct sockaddr_in
*)addr
;
109 assert(numdaemons
<= maxdaemons
);
110 if (numdaemons
== maxdaemons
) {
112 daemons
= realloc(daemons
, maxdaemons
* sizeof(daemons
[0]));
113 if (daemons
== NULL
) {
119 * Note that we do *not* convert from network to host
120 * order since the port number we were sent *should*
121 * already be in network order.
123 * The result may be either the port number for the hunt
124 * socket or the port number for the stats socket... or the
125 * number of players connected and not a port number at all,
126 * depending on the packet type.
128 * For now at least it is ok to stuff it in here, because the
129 * usage of the various different packet types and the
130 * persistence of the results vs. the program exiting does not
131 * cause us to get confused. If the game is made more
132 * self-contained in the future we'll need to be more careful
133 * about this, especially if we make the caching of results
136 daemons
[numdaemons
] = *sin
;
137 daemons
[numdaemons
].sin_port
= port_num
;
142 have_daemon_addr(const struct sockaddr_storage
*addr
)
145 const struct sockaddr_in
*sin
;
147 if (addr
->ss_family
!= AF_INET
) {
150 sin
= (const struct sockaddr_in
*)addr
;
152 for (j
= 0; j
< numdaemons
; j
++) {
153 if (sin
->sin_addr
.s_addr
== daemons
[j
].sin_addr
.s_addr
) {
161 getbroadcastaddrs(struct sockaddr_in
**vector
)
164 struct ifaddrs
*ifp
, *ip
;
167 if (getifaddrs(&ifp
) < 0)
171 for (ip
= ifp
; ip
; ip
= ip
->ifa_next
)
172 if ((ip
->ifa_addr
->sa_family
== AF_INET
) &&
173 (ip
->ifa_flags
& IFF_BROADCAST
))
176 *vector
= malloc(vec_cnt
* sizeof(struct sockaddr_in
));
179 for (ip
= ifp
; ip
; ip
= ip
->ifa_next
)
180 if ((ip
->ifa_addr
->sa_family
== AF_INET
) &&
181 (ip
->ifa_flags
& IFF_BROADCAST
))
182 memcpy(&(*vector
)[vec_cnt
++], ip
->ifa_broadaddr
,
183 sizeof(struct sockaddr_in
));
190 send_messages(int contactsock
, unsigned short msg
)
192 struct sockaddr_in contactaddr
;
198 contactaddr
.sin_family
= SOCK_FAMILY
;
199 contactaddr
.sin_port
= htons(port
);
201 if (explicit_host
!= NULL
) { /* explicit host given */
202 hp
= gethostbyname(explicit_host
);
204 leavex(1, "%s: Unknown host", explicit_host
);
206 memcpy(&contactaddr
.sin_addr
, hp
->h_addr
,
207 sizeof(contactaddr
.sin_addr
));
208 wiremsg
= htons(msg
);
209 (void) sendto(contactsock
, &wiremsg
, sizeof(wiremsg
), 0,
210 (struct sockaddr
*)&contactaddr
,
211 sizeof(contactaddr
));
216 /* favor host of previous session by contacting it first */
217 contactaddr
.sin_addr
= Daemon
.sin_addr
;
219 /* Must be playing! */
220 assert(msg
== C_PLAYER
);
221 wiremsg
= htons(msg
);
223 (void) sendto(contactsock
, &wiremsg
, sizeof(wiremsg
), 0,
224 (struct sockaddr
*)&contactaddr
, sizeof(contactaddr
));
228 brdc
= getbroadcastaddrs(&brdv
);
231 /* Sun's will broadcast even though this option can't be set */
233 if (setsockopt(contactsock
, SOL_SOCKET
, SO_BROADCAST
,
234 &option
, sizeof option
) < 0) {
235 leave(1, "setsockopt broadcast");
240 /* send broadcast packets on all interfaces */
241 wiremsg
= htons(msg
);
242 for (i
= 0; i
< brdc
; i
++) {
243 contactaddr
.sin_addr
= brdv
[i
].sin_addr
;
244 if (sendto(contactsock
, &wiremsg
, sizeof(wiremsg
), 0,
245 (struct sockaddr
*)&contactaddr
,
246 sizeof(contactaddr
)) < 0) {
250 contactaddr
.sin_addr
= local_address
;
251 if (sendto(contactsock
, &wiremsg
, sizeof(wiremsg
), 0,
252 (struct sockaddr
*)&contactaddr
, sizeof(contactaddr
)) < 0) {
258 get_responses(int contactsock
)
260 struct pollfd set
[1];
261 struct sockaddr_storage addr
;
267 /* forget all old responses */
271 set
[0].fd
= contactsock
;
272 set
[0].events
= POLLIN
;
274 r
= poll(set
, 1, 1000);
276 if (errno
== EINTR
) {
285 addrlen
= sizeof(addr
);
286 portlen
= recvfrom(contactsock
, &port_num
, sizeof(port_num
), 0,
287 (struct sockaddr
*)&addr
, &addrlen
);
289 if (errno
== EINTR
) {
292 leave(1, "recvfrom");
295 leavex(1, "recvfrom: Unexpected EOF");
297 if ((size_t)portlen
!= sizeof(port_num
)) {
298 /* trash, ignore it */
301 if (have_daemon_addr(&addr
)) {
302 /* this shouldn't happen */
306 add_daemon_addr(&addr
, port_num
);
313 serverlist_query(unsigned short msg
)
317 if (!initial
&& explicit_host
!= NULL
) {
318 /* already did the work, no point doing it again */
322 contactsock
= socket(SOCK_FAMILY
, SOCK_DGRAM
, 0);
323 if (contactsock
< 0) {
324 leave(1, "socket system call failed");
327 send_messages(contactsock
, msg
);
328 get_responses(contactsock
);
330 (void) close(contactsock
);
339 const struct sockaddr_storage
*
340 serverlist_gethost(unsigned i
, socklen_t
*len_ret
)
342 struct sockaddr_in
*ret
;
344 assert(i
< numdaemons
);
346 *len_ret
= sizeof(*ret
);
347 return (struct sockaddr_storage
*)ret
;
351 serverlist_getresponse(unsigned i
)
353 assert(i
< numdaemons
);
354 return daemons
[i
].sin_port
;
357 #endif /* INTERNET */