Home | History | Annotate | Line # | Download | only in huntd
      1  1.36    rillig /*	$NetBSD: driver.c,v 1.36 2021/05/02 12:50:45 rillig Exp $	*/
      2   1.1       mrg /*
      3   1.9       wiz  * Copyright (c) 1983-2003, Regents of the University of California.
      4   1.9       wiz  * All rights reserved.
      5  1.36    rillig  *
      6  1.36    rillig  * Redistribution and use in source and binary forms, with or without
      7  1.36    rillig  * modification, are permitted provided that the following conditions are
      8   1.9       wiz  * met:
      9  1.36    rillig  *
     10  1.36    rillig  * + Redistributions of source code must retain the above copyright
     11   1.9       wiz  *   notice, this list of conditions and the following disclaimer.
     12  1.36    rillig  * + Redistributions in binary form must reproduce the above copyright
     13  1.36    rillig  *   notice, this list of conditions and the following disclaimer in the
     14   1.9       wiz  *   documentation and/or other materials provided with the distribution.
     15  1.36    rillig  * + Neither the name of the University of California, San Francisco nor
     16  1.36    rillig  *   the names of its contributors may be used to endorse or promote
     17  1.36    rillig  *   products derived from this software without specific prior written
     18   1.9       wiz  *   permission.
     19  1.36    rillig  *
     20  1.36    rillig  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
     21  1.36    rillig  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  1.36    rillig  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
     23  1.36    rillig  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     24  1.36    rillig  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     25  1.36    rillig  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     26  1.36    rillig  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  1.36    rillig  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  1.36    rillig  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  1.36    rillig  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     30   1.9       wiz  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31   1.1       mrg  */
     32   1.1       mrg 
     33   1.2     lukem #include <sys/cdefs.h>
     34   1.2     lukem #ifndef lint
     35  1.36    rillig __RCSID("$NetBSD: driver.c,v 1.36 2021/05/02 12:50:45 rillig Exp $");
     36   1.2     lukem #endif /* not lint */
     37   1.2     lukem 
     38  1.33  dholland #include <sys/types.h>
     39  1.33  dholland #include <sys/socket.h>
     40  1.17  dholland #include <sys/stat.h>
     41  1.17  dholland #include <sys/time.h>
     42  1.35  dholland #include <sys/un.h>
     43  1.35  dholland 
     44  1.35  dholland #include <netinet/in.h>
     45  1.35  dholland #include <netdb.h>
     46  1.35  dholland #include <arpa/inet.h>
     47  1.35  dholland #include <net/if.h>
     48  1.35  dholland 
     49  1.17  dholland #include <stdlib.h>
     50  1.17  dholland #include <unistd.h>
     51  1.35  dholland #include <signal.h>
     52  1.35  dholland #include <errno.h>
     53  1.35  dholland #include <err.h>
     54  1.31  dholland 
     55  1.31  dholland #include "hunt.h"
     56  1.31  dholland #include "pathnames.h"
     57  1.17  dholland 
     58  1.34  dholland /*
     59  1.34  dholland  * There are three listening sockets in this daemon:
     60  1.34  dholland  *    - a datagram socket that listens on a well known port
     61  1.34  dholland  *    - a stream socket for general player connections
     62  1.34  dholland  *    - a second stream socket that prints the stats/scores
     63  1.34  dholland  *
     64  1.34  dholland  * These are (now) named as follows:
     65  1.34  dholland  *    - contact (contactsock, contactaddr, etc.)
     66  1.34  dholland  *    - hunt (huntsock, huntaddr, etc.)
     67  1.34  dholland  *    - stat (statsock, stataddr, etc.)
     68  1.34  dholland  *
     69  1.34  dholland  * Until being cleaned up in 2014 the code used an assortment of
     70  1.34  dholland  * inconsistent and confusing names to refer to the pieces of these:
     71  1.34  dholland  *
     72  1.34  dholland  *    test_port -> contactaddr
     73  1.34  dholland  *    Test_port -> contactport
     74  1.34  dholland  *    Test_socket -> contactsock
     75  1.34  dholland  *
     76  1.34  dholland  *    sock_port -> huntport
     77  1.34  dholland  *    Socket -> huntsock
     78  1.34  dholland  *
     79  1.34  dholland  *    Daemon -> both stataddr and huntaddr
     80  1.34  dholland  *    stat_port -> statport
     81  1.34  dholland  *    status -> statsock
     82  1.34  dholland  *
     83  1.34  dholland  * It isn't clear to me what purpose contactsocket is supposed to
     84  1.34  dholland  * serve; maybe it was supposed to avoid asking inetd to support
     85  1.34  dholland  * tcp/wait sockets? Anyway, we can't really change the protocol at
     86  1.34  dholland  * this point. (To complicate matters, contactsocket doesn't exist if
     87  1.34  dholland  * using AF_UNIX sockets; you just connect to the game socket.)
     88  1.34  dholland  *
     89  1.34  dholland  * When using internet sockets:
     90  1.34  dholland  *    - the contact socket listens on INADDR_ANY using the game port
     91  1.34  dholland  *      (either specified or the default: CONTACT_PORT, currently
     92  1.34  dholland  *      spelled TEST_PORT)
     93  1.34  dholland  *    - the hunt socket listens on INADDR_ANY using whatever port
     94  1.34  dholland  *    - the stat socket listens on INADDR_ANY using whatever port
     95  1.34  dholland  *
     96  1.34  dholland  * When using AF_UNIX sockets:
     97  1.34  dholland  *    - the contact socket isn't used
     98  1.34  dholland  *    - the hunt socket listens on the game socket (either a specified path
     99  1.34  dholland  *      or /tmp/hunt)
    100  1.34  dholland  *    - the stat socket listens on its own socket (huntsocket's path +
    101  1.34  dholland  *      ".stats")
    102  1.34  dholland  */
    103  1.34  dholland 
    104  1.35  dholland static bool localmode;			/* true -> AF_UNIX; false -> AF_INET */
    105  1.35  dholland static bool inetd_spawned;		/* invoked via inetd? */
    106  1.35  dholland static bool standard_port = true;	/* listening on standard port? */
    107  1.35  dholland 
    108  1.35  dholland static struct sockaddr_storage huntaddr;
    109  1.35  dholland static struct sockaddr_storage stataddr;
    110  1.35  dholland static socklen_t huntaddrlen;
    111  1.35  dholland static socklen_t stataddrlen;
    112  1.35  dholland 
    113  1.34  dholland static uint16_t contactport = TEST_PORT;
    114  1.34  dholland static uint16_t	huntport;		/* port # of tcp listen socket */
    115  1.34  dholland static uint16_t	statport;		/* port # of statistics tcp socket */
    116  1.35  dholland 
    117  1.35  dholland static const char *huntsockpath = PATH_HUNTSOCKET;
    118  1.35  dholland static char *statsockpath;
    119  1.35  dholland 
    120  1.34  dholland static int contactsock;			/* socket to answer datagrams */
    121  1.34  dholland int huntsock;				/* main socket */
    122  1.34  dholland static int statsock;			/* stat socket */
    123  1.17  dholland 
    124  1.29  dholland #ifdef VOLCANO
    125  1.29  dholland static int volcano = 0;			/* Explosion size */
    126  1.29  dholland #endif
    127  1.29  dholland 
    128  1.17  dholland static void clear_scores(void);
    129  1.24  dholland static bool havechar(PLAYER *, int);
    130  1.17  dholland static void init(void);
    131  1.17  dholland static void makeboots(void);
    132  1.17  dholland static void send_stats(void);
    133  1.24  dholland static void zap(PLAYER *, bool, int);
    134   1.2     lukem 
    135  1.35  dholland static int
    136  1.35  dholland getnum(const char *s, unsigned long *ret)
    137  1.35  dholland {
    138  1.35  dholland 	char *t;
    139  1.35  dholland 
    140  1.35  dholland 	errno = 0;
    141  1.35  dholland 	*ret = strtoul(s, &t, 0);
    142  1.35  dholland 	if (errno || *t != '\0') {
    143  1.35  dholland 		return -1;
    144  1.35  dholland 	}
    145  1.35  dholland 	return 0;
    146  1.35  dholland }
    147  1.35  dholland 
    148  1.35  dholland static __dead void
    149  1.35  dholland usage(const char *av0)
    150  1.35  dholland {
    151  1.35  dholland 	fprintf(stderr, "Usage: %s [-s] [-p portnumber|socketpath]\n", av0);
    152  1.35  dholland 	exit(1);
    153  1.35  dholland }
    154  1.35  dholland 
    155  1.35  dholland static void
    156  1.35  dholland makeaddr(const char *path, uint16_t port,
    157  1.35  dholland 	 struct sockaddr_storage *ss, socklen_t *len)
    158  1.35  dholland {
    159  1.35  dholland 	struct sockaddr_in *sin;
    160  1.35  dholland 	struct sockaddr_un *sun;
    161  1.35  dholland 
    162  1.35  dholland 	if (path == NULL) {
    163  1.35  dholland 		sin = (struct sockaddr_in *)ss;
    164  1.35  dholland 		sin->sin_family = AF_INET;
    165  1.35  dholland 		sin->sin_addr.s_addr = INADDR_ANY;
    166  1.35  dholland 		sin->sin_port = htons(port);
    167  1.35  dholland 		*len = sizeof(*sin);
    168  1.35  dholland 	} else {
    169  1.35  dholland 		sun = (struct sockaddr_un *)ss;
    170  1.35  dholland 		sun->sun_family = AF_UNIX;
    171  1.35  dholland 		strlcpy(sun->sun_path, path, sizeof(sun->sun_path));
    172  1.35  dholland 		*len = SUN_LEN(sun);
    173  1.35  dholland 	}
    174  1.35  dholland }
    175  1.35  dholland 
    176  1.35  dholland static uint16_t
    177  1.35  dholland getsockport(int sock)
    178  1.35  dholland {
    179  1.35  dholland 	struct sockaddr_storage addr;
    180  1.35  dholland 	socklen_t len;
    181  1.35  dholland 
    182  1.35  dholland 	len = sizeof(addr);
    183  1.35  dholland 	if (getsockname(sock, (struct sockaddr *)&addr, &len) < 0)  {
    184  1.35  dholland 		complain(LOG_ERR, "getsockname");
    185  1.35  dholland 		exit(1);
    186  1.35  dholland 	}
    187  1.35  dholland 	switch (addr.ss_family) {
    188  1.35  dholland 	    case AF_INET:
    189  1.35  dholland 		return ntohs(((struct sockaddr_in *)&addr)->sin_port);
    190  1.35  dholland 	    case AF_INET6:
    191  1.35  dholland 		return ntohs(((struct sockaddr_in6 *)&addr)->sin6_port);
    192  1.35  dholland 	    default:
    193  1.35  dholland 		break;
    194  1.35  dholland 	}
    195  1.35  dholland 	return 0;
    196  1.35  dholland }
    197   1.1       mrg 
    198   1.1       mrg /*
    199   1.1       mrg  * main:
    200   1.1       mrg  *	The main program.
    201   1.1       mrg  */
    202   1.2     lukem int
    203  1.26  dholland main(int ac, char **av)
    204   1.1       mrg {
    205  1.17  dholland 	PLAYER *pp;
    206  1.35  dholland 	unsigned long optargnum;
    207  1.35  dholland 	uint16_t msg, reply;
    208  1.35  dholland 	struct sockaddr_storage msgaddr;
    209  1.35  dholland 	socklen_t msgaddrlen;
    210  1.24  dholland 	static bool first = true;
    211  1.24  dholland 	static bool server = false;
    212  1.17  dholland 	int c, i;
    213  1.17  dholland 	const int linger = 90 * 1000;
    214   1.1       mrg 
    215   1.2     lukem 	while ((c = getopt(ac, av, "sp:")) != -1) {
    216   1.1       mrg 		switch (c) {
    217   1.1       mrg 		  case 's':
    218  1.24  dholland 			server = true;
    219   1.1       mrg 			break;
    220   1.1       mrg 		  case 'p':
    221  1.24  dholland 			standard_port = false;
    222  1.35  dholland 			if (getnum(optarg, &optargnum) < 0) {
    223  1.35  dholland 				localmode = true;
    224  1.35  dholland 				huntsockpath = optarg;
    225  1.35  dholland 			} else if (optargnum < 0xffff) {
    226  1.35  dholland 				localmode = false;
    227  1.35  dholland 				contactport = optargnum;
    228  1.35  dholland 			} else {
    229  1.35  dholland 				usage(av[0]);
    230  1.35  dholland 			}
    231   1.1       mrg 			break;
    232   1.1       mrg 		  default:
    233  1.35  dholland 			usage(av[0]);
    234   1.1       mrg 		}
    235   1.1       mrg 	}
    236   1.1       mrg 	if (optind < ac)
    237  1.35  dholland 		usage(av[0]);
    238   1.1       mrg 
    239  1.35  dholland 	asprintf(&statsockpath, "%s.stats", huntsockpath);
    240   1.1       mrg 	init();
    241   1.1       mrg 
    242   1.1       mrg 
    243   1.1       mrg again:
    244   1.1       mrg 	do {
    245   1.1       mrg 		errno = 0;
    246   1.8   mycroft 		while (poll(fdset, 3+MAXPL+MAXMON, INFTIM) < 0)
    247   1.1       mrg 		{
    248   1.1       mrg 			if (errno != EINTR)
    249  1.32  dholland 				complain(LOG_WARNING, "poll");
    250   1.1       mrg 			errno = 0;
    251   1.1       mrg 		}
    252  1.35  dholland 		if (!localmode && fdset[2].revents & POLLIN) {
    253  1.35  dholland 			msgaddrlen = sizeof(msgaddr);
    254  1.34  dholland 			(void) recvfrom(contactsock, &msg, sizeof msg,
    255  1.35  dholland 				0, (struct sockaddr *)&msgaddr, &msgaddrlen);
    256   1.1       mrg 			switch (ntohs(msg)) {
    257   1.1       mrg 			  case C_MESSAGE:
    258   1.1       mrg 				if (Nplayer <= 0)
    259   1.1       mrg 					break;
    260   1.1       mrg 				reply = htons((u_short) Nplayer);
    261  1.34  dholland 				(void) sendto(contactsock, &reply,
    262   1.1       mrg 					sizeof reply, 0,
    263  1.35  dholland 					(struct sockaddr *)&msgaddr,
    264  1.35  dholland 					msgaddrlen);
    265   1.1       mrg 				break;
    266   1.1       mrg 			  case C_SCORES:
    267  1.34  dholland 				reply = htons(statport);
    268  1.34  dholland 				(void) sendto(contactsock, &reply,
    269   1.1       mrg 					sizeof reply, 0,
    270  1.35  dholland 					(struct sockaddr *)&msgaddr,
    271  1.35  dholland 					msgaddrlen);
    272   1.1       mrg 				break;
    273   1.1       mrg 			  case C_PLAYER:
    274   1.1       mrg 			  case C_MONITOR:
    275   1.1       mrg 				if (msg == C_MONITOR && Nplayer <= 0)
    276   1.1       mrg 					break;
    277  1.34  dholland 				reply = htons(huntport);
    278  1.34  dholland 				(void) sendto(contactsock, &reply,
    279   1.1       mrg 					sizeof reply, 0,
    280  1.35  dholland 					(struct sockaddr *)&msgaddr,
    281  1.35  dholland 					msgaddrlen);
    282   1.1       mrg 				break;
    283   1.1       mrg 			}
    284   1.1       mrg 		}
    285  1.35  dholland 
    286   1.8   mycroft 		{
    287   1.8   mycroft 			for (pp = Player, i = 0; pp < End_player; pp++, i++)
    288   1.8   mycroft 				if (havechar(pp, i + 3)) {
    289   1.1       mrg 					execute(pp);
    290   1.1       mrg 					pp->p_nexec++;
    291   1.1       mrg 				}
    292  1.17  dholland #ifdef MONITOR
    293   1.8   mycroft 			for (pp = Monitor, i = 0; pp < End_monitor; pp++, i++)
    294   1.8   mycroft 				if (havechar(pp, i + MAXPL + 3)) {
    295   1.1       mrg 					mon_execute(pp);
    296   1.1       mrg 					pp->p_nexec++;
    297   1.1       mrg 				}
    298  1.17  dholland #endif
    299   1.1       mrg 			moveshots();
    300   1.8   mycroft 			for (pp = Player, i = 0; pp < End_player; )
    301   1.1       mrg 				if (pp->p_death[0] != '\0')
    302  1.24  dholland 					zap(pp, true, i + 3);
    303   1.1       mrg 				else
    304   1.8   mycroft 					pp++, i++;
    305  1.17  dholland #ifdef MONITOR
    306   1.8   mycroft 			for (pp = Monitor, i = 0; pp < End_monitor; )
    307   1.1       mrg 				if (pp->p_death[0] != '\0')
    308  1.24  dholland 					zap(pp, false, i + MAXPL + 3);
    309   1.1       mrg 				else
    310   1.8   mycroft 					pp++, i++;
    311  1.17  dholland #endif
    312   1.1       mrg 		}
    313   1.8   mycroft 		if (fdset[0].revents & POLLIN)
    314   1.1       mrg 			if (answer()) {
    315  1.27  dholland 				if (first) {
    316  1.27  dholland 					/* announce start of game? */
    317  1.27  dholland 				}
    318  1.24  dholland 				first = false;
    319   1.1       mrg 			}
    320   1.8   mycroft 		if (fdset[1].revents & POLLIN)
    321   1.1       mrg 			send_stats();
    322   1.8   mycroft 		for (pp = Player, i = 0; pp < End_player; pp++, i++) {
    323   1.8   mycroft 			if (fdset[i + 3].revents & POLLIN)
    324   1.1       mrg 				sendcom(pp, READY, pp->p_nexec);
    325   1.1       mrg 			pp->p_nexec = 0;
    326   1.1       mrg 			(void) fflush(pp->p_output);
    327   1.1       mrg 		}
    328  1.17  dholland #ifdef MONITOR
    329   1.8   mycroft 		for (pp = Monitor, i = 0; pp < End_monitor; pp++, i++) {
    330   1.8   mycroft 			if (fdset[i + MAXPL + 3].revents & POLLIN)
    331   1.1       mrg 				sendcom(pp, READY, pp->p_nexec);
    332   1.1       mrg 			pp->p_nexec = 0;
    333   1.1       mrg 			(void) fflush(pp->p_output);
    334   1.1       mrg 		}
    335  1.17  dholland #endif
    336   1.1       mrg 	} while (Nplayer > 0);
    337   1.1       mrg 
    338   1.8   mycroft 	if (poll(fdset, 3+MAXPL+MAXMON, linger) > 0) {
    339   1.1       mrg 		goto again;
    340   1.1       mrg 	}
    341   1.1       mrg 	if (server) {
    342   1.1       mrg 		clear_scores();
    343   1.1       mrg 		makemaze();
    344   1.1       mrg 		clearwalls();
    345  1.17  dholland #ifdef BOOTS
    346   1.1       mrg 		makeboots();
    347  1.17  dholland #endif
    348  1.24  dholland 		first = true;
    349   1.1       mrg 		goto again;
    350   1.1       mrg 	}
    351   1.1       mrg 
    352  1.17  dholland #ifdef MONITOR
    353   1.8   mycroft 	for (pp = Monitor, i = 0; pp < End_monitor; i++)
    354  1.24  dholland 		zap(pp, false, i + MAXPL + 3);
    355  1.17  dholland #endif
    356   1.1       mrg 	cleanup(0);
    357   1.2     lukem 	/* NOTREACHED */
    358   1.2     lukem 	return(0);
    359   1.1       mrg }
    360   1.1       mrg 
    361   1.1       mrg /*
    362   1.1       mrg  * init:
    363   1.1       mrg  *	Initialize the global parameters.
    364   1.1       mrg  */
    365   1.2     lukem static void
    366  1.16  dholland init(void)
    367   1.1       mrg {
    368  1.17  dholland 	int i;
    369  1.35  dholland 	struct sockaddr_storage stdinaddr;
    370  1.35  dholland 	struct sockaddr_storage contactaddr;
    371  1.35  dholland 	socklen_t contactaddrlen;
    372  1.17  dholland 	socklen_t len;
    373   1.1       mrg 
    374  1.17  dholland #ifndef DEBUG
    375  1.17  dholland #ifdef TIOCNOTTY
    376   1.1       mrg 	(void) ioctl(fileno(stdout), TIOCNOTTY, NULL);
    377  1.17  dholland #endif
    378   1.1       mrg 	(void) setpgrp(getpid(), getpid());
    379   1.1       mrg 	(void) signal(SIGHUP, SIG_IGN);
    380   1.1       mrg 	(void) signal(SIGINT, SIG_IGN);
    381   1.1       mrg 	(void) signal(SIGQUIT, SIG_IGN);
    382   1.1       mrg 	(void) signal(SIGTERM, cleanup);
    383  1.17  dholland #endif
    384   1.1       mrg 
    385   1.4       mrg 	(void) chdir("/var/tmp");	/* just in case it core dumps */
    386   1.1       mrg 	(void) umask(0);		/* No privacy at all! */
    387   1.1       mrg 	(void) signal(SIGPIPE, SIG_IGN);
    388   1.1       mrg 
    389  1.17  dholland #ifdef LOG
    390   1.7     lukem 	openlog("huntd", LOG_PID, LOG_DAEMON);
    391  1.17  dholland #endif
    392   1.1       mrg 
    393   1.1       mrg 	/*
    394  1.35  dholland 	 * check for inetd
    395   1.1       mrg 	 */
    396  1.35  dholland 	len = sizeof(stdinaddr);
    397  1.35  dholland 	if (getsockname(STDIN_FILENO, (struct sockaddr *)&stdinaddr,
    398  1.35  dholland 			&len) >= 0) {
    399  1.35  dholland 		inetd_spawned = true;
    400  1.35  dholland 		/* force localmode, assimilate stdin as appropriate */
    401  1.35  dholland 		if (stdinaddr.ss_family == AF_UNIX) {
    402  1.35  dholland 			localmode = true;
    403  1.35  dholland 			contactsock = -1;
    404  1.35  dholland 			huntsock = STDIN_FILENO;
    405  1.35  dholland 		}
    406  1.35  dholland 		else {
    407  1.35  dholland 			localmode = false;
    408  1.35  dholland 			contactsock = STDIN_FILENO;
    409  1.35  dholland 			huntsock = -1;
    410  1.35  dholland 		}
    411  1.35  dholland 	} else {
    412  1.35  dholland 		/* keep value of localmode; no sockets yet */
    413  1.35  dholland 		contactsock = -1;
    414  1.35  dholland 		huntsock = -1;
    415  1.35  dholland 	}
    416   1.1       mrg 
    417  1.35  dholland 	/*
    418  1.35  dholland 	 * initialize contact socket
    419  1.35  dholland 	 */
    420  1.35  dholland 	if (!localmode && contactsock < 0) {
    421  1.35  dholland 		makeaddr(NULL, contactport, &contactaddr, &contactaddrlen);
    422  1.35  dholland 		contactsock = socket(AF_INET, SOCK_DGRAM, 0);
    423  1.35  dholland 		if (bind(contactsock, (struct sockaddr *) &contactaddr,
    424  1.35  dholland 			 contactaddrlen) < 0) {
    425  1.32  dholland 			complain(LOG_ERR, "bind");
    426  1.35  dholland 			exit(1);
    427   1.1       mrg 		}
    428  1.35  dholland 		(void) listen(contactsock, 5);
    429   1.1       mrg 	}
    430   1.1       mrg 
    431  1.35  dholland 	/*
    432  1.35  dholland 	 * Initialize main socket
    433  1.35  dholland 	 */
    434  1.35  dholland 	if (huntsock < 0) {
    435  1.35  dholland 		makeaddr(localmode ? huntsockpath : NULL, 0, &huntaddr,
    436  1.35  dholland 			 &huntaddrlen);
    437  1.35  dholland 		huntsock = socket(huntaddr.ss_family, SOCK_STREAM, 0);
    438  1.35  dholland 		if (bind(huntsock, (struct sockaddr *)&huntaddr,
    439  1.35  dholland 			 huntaddrlen) < 0) {
    440  1.35  dholland 			if (errno == EADDRINUSE)
    441  1.35  dholland 				exit(0);
    442  1.35  dholland 			else {
    443  1.35  dholland 				complain(LOG_ERR, "bind");
    444  1.35  dholland 				cleanup(1);
    445  1.35  dholland 			}
    446  1.35  dholland 		}
    447  1.35  dholland 		(void) listen(huntsock, 5);
    448   1.1       mrg 	}
    449   1.1       mrg 
    450   1.1       mrg 	/*
    451  1.35  dholland 	 * Initialize statistics socket
    452   1.1       mrg 	 */
    453  1.35  dholland 	makeaddr(localmode ? statsockpath : NULL, 0, &stataddr, &stataddrlen);
    454  1.35  dholland 	statsock = socket(stataddr.ss_family, SOCK_STREAM, 0);
    455  1.35  dholland 	if (bind(statsock, (struct sockaddr *)&stataddr, stataddrlen) < 0) {
    456   1.1       mrg 		if (errno == EADDRINUSE)
    457   1.1       mrg 			exit(0);
    458   1.1       mrg 		else {
    459  1.32  dholland 			complain(LOG_ERR, "bind");
    460   1.1       mrg 			cleanup(1);
    461   1.1       mrg 		}
    462   1.1       mrg 	}
    463  1.35  dholland 	(void) listen(statsock, 5);
    464   1.1       mrg 
    465  1.35  dholland 	if (!localmode) {
    466  1.35  dholland 		contactport = getsockport(contactsock);
    467  1.35  dholland 		statport = getsockport(statsock);
    468  1.35  dholland 		huntport = getsockport(huntsock);
    469  1.35  dholland 		if (contactport != TEST_PORT) {
    470  1.35  dholland 			standard_port = false;
    471  1.35  dholland 		}
    472   1.1       mrg 	}
    473   1.1       mrg 
    474   1.1       mrg 	/*
    475  1.12      elad 	 * Initialize minimal poll mask
    476   1.1       mrg 	 */
    477  1.34  dholland 	fdset[0].fd = huntsock;
    478   1.8   mycroft 	fdset[0].events = POLLIN;
    479  1.34  dholland 	fdset[1].fd = statsock;
    480   1.8   mycroft 	fdset[1].events = POLLIN;
    481  1.35  dholland 	if (localmode) {
    482  1.35  dholland 		fdset[2].fd = -1;
    483  1.35  dholland 		fdset[2].events = 0;
    484   1.1       mrg 	} else {
    485  1.35  dholland 		fdset[2].fd = contactsock;
    486  1.35  dholland 		fdset[2].events = POLLIN;
    487   1.1       mrg 	}
    488   1.1       mrg 
    489  1.23  dholland 	srandom(time(NULL));
    490   1.1       mrg 	makemaze();
    491  1.17  dholland #ifdef BOOTS
    492   1.1       mrg 	makeboots();
    493  1.17  dholland #endif
    494   1.1       mrg 
    495   1.1       mrg 	for (i = 0; i < NASCII; i++)
    496  1.24  dholland 		See_over[i] = true;
    497  1.24  dholland 	See_over[DOOR] = false;
    498  1.24  dholland 	See_over[WALL1] = false;
    499  1.24  dholland 	See_over[WALL2] = false;
    500  1.24  dholland 	See_over[WALL3] = false;
    501  1.17  dholland #ifdef REFLECT
    502  1.24  dholland 	See_over[WALL4] = false;
    503  1.24  dholland 	See_over[WALL5] = false;
    504  1.17  dholland #endif
    505   1.1       mrg 
    506   1.1       mrg }
    507   1.1       mrg 
    508  1.17  dholland #ifdef BOOTS
    509   1.1       mrg /*
    510   1.1       mrg  * makeboots:
    511   1.1       mrg  *	Put the boots in the maze
    512   1.1       mrg  */
    513   1.2     lukem static void
    514  1.16  dholland makeboots(void)
    515   1.1       mrg {
    516  1.17  dholland 	int x, y;
    517  1.17  dholland 	PLAYER *pp;
    518   1.1       mrg 
    519   1.1       mrg 	do {
    520   1.1       mrg 		x = rand_num(WIDTH - 1) + 1;
    521   1.1       mrg 		y = rand_num(HEIGHT - 1) + 1;
    522   1.1       mrg 	} while (Maze[y][x] != SPACE);
    523   1.1       mrg 	Maze[y][x] = BOOT_PAIR;
    524   1.1       mrg 	for (pp = Boot; pp < &Boot[NBOOTS]; pp++)
    525   1.1       mrg 		pp->p_flying = -1;
    526   1.1       mrg }
    527  1.17  dholland #endif
    528   1.1       mrg 
    529   1.1       mrg 
    530   1.1       mrg /*
    531   1.1       mrg  * checkdam:
    532   1.1       mrg  *	Check the damage to the given player, and see if s/he is killed
    533   1.1       mrg  */
    534   1.2     lukem void
    535  1.16  dholland checkdam(PLAYER *ouch, PLAYER *gotcha, IDENT *credit, int amt,
    536  1.16  dholland 	 char this_shot_type)
    537   1.1       mrg {
    538  1.17  dholland 	const char *cp;
    539   1.1       mrg 
    540   1.1       mrg 	if (ouch->p_death[0] != '\0')
    541   1.1       mrg 		return;
    542  1.17  dholland #ifdef BOOTS
    543  1.13  dholland 	if (this_shot_type == SLIME)
    544   1.1       mrg 		switch (ouch->p_nboots) {
    545   1.1       mrg 		  default:
    546   1.1       mrg 			break;
    547   1.1       mrg 		  case 1:
    548   1.1       mrg 			amt = (amt + 1) / 2;
    549   1.1       mrg 			break;
    550   1.1       mrg 		  case 2:
    551   1.1       mrg 			if (gotcha != NULL)
    552   1.1       mrg 				message(gotcha, "He has boots on!");
    553   1.1       mrg 			return;
    554   1.1       mrg 		}
    555  1.17  dholland #endif
    556   1.1       mrg 	ouch->p_damage += amt;
    557   1.1       mrg 	if (ouch->p_damage <= ouch->p_damcap) {
    558  1.14  dholland 		(void) snprintf(Buf, sizeof(Buf), "%2d", ouch->p_damage);
    559   1.1       mrg 		cgoto(ouch, STAT_DAM_ROW, STAT_VALUE_COL);
    560   1.1       mrg 		outstr(ouch, Buf, 2);
    561   1.1       mrg 		return;
    562   1.1       mrg 	}
    563   1.1       mrg 
    564   1.1       mrg 	/* Someone DIED */
    565  1.13  dholland 	switch (this_shot_type) {
    566   1.1       mrg 	  default:
    567   1.1       mrg 		cp = "Killed";
    568   1.1       mrg 		break;
    569  1.17  dholland #ifdef FLY
    570   1.1       mrg 	  case FALL:
    571   1.1       mrg 		cp = "Killed on impact";
    572   1.1       mrg 		break;
    573  1.17  dholland #endif
    574   1.1       mrg 	  case KNIFE:
    575   1.1       mrg 		cp = "Stabbed to death";
    576   1.1       mrg 		ouch->p_ammo = 0;		/* No exploding */
    577   1.1       mrg 		break;
    578   1.1       mrg 	  case SHOT:
    579   1.1       mrg 		cp = "Shot to death";
    580   1.1       mrg 		break;
    581   1.1       mrg 	  case GRENADE:
    582   1.1       mrg 	  case SATCHEL:
    583   1.1       mrg 	  case BOMB:
    584   1.1       mrg 		cp = "Bombed";
    585   1.1       mrg 		break;
    586   1.1       mrg 	  case MINE:
    587   1.1       mrg 	  case GMINE:
    588   1.1       mrg 		cp = "Blown apart";
    589   1.1       mrg 		break;
    590  1.17  dholland #ifdef	OOZE
    591   1.1       mrg 	  case SLIME:
    592   1.1       mrg 		cp = "Slimed";
    593   1.1       mrg 		if (credit != NULL)
    594   1.1       mrg 			credit->i_slime++;
    595   1.1       mrg 		break;
    596  1.17  dholland #endif
    597  1.17  dholland #ifdef	VOLCANO
    598   1.1       mrg 	  case LAVA:
    599   1.1       mrg 		cp = "Baked";
    600   1.1       mrg 		break;
    601  1.17  dholland #endif
    602  1.17  dholland #ifdef DRONE
    603   1.1       mrg 	  case DSHOT:
    604   1.1       mrg 		cp = "Eliminated";
    605   1.1       mrg 		break;
    606  1.17  dholland #endif
    607   1.1       mrg 	}
    608   1.1       mrg 	if (credit == NULL) {
    609  1.14  dholland 		(void) snprintf(ouch->p_death, sizeof(ouch->p_death),
    610  1.14  dholland 			"| %s by %s |", cp,
    611  1.13  dholland 			(this_shot_type == MINE || this_shot_type == GMINE) ?
    612   1.1       mrg 			"a mine" : "act of God");
    613   1.1       mrg 		return;
    614   1.1       mrg 	}
    615   1.1       mrg 
    616  1.14  dholland 	(void) snprintf(ouch->p_death, sizeof(ouch->p_death),
    617  1.14  dholland 		"| %s by %s |", cp, credit->i_name);
    618   1.1       mrg 
    619   1.1       mrg 	if (ouch == gotcha) {		/* No use killing yourself */
    620   1.1       mrg 		credit->i_kills--;
    621   1.1       mrg 		credit->i_bkills++;
    622   1.1       mrg 	}
    623   1.1       mrg 	else if (ouch->p_ident->i_team == ' '
    624   1.1       mrg 	|| ouch->p_ident->i_team != credit->i_team) {
    625   1.1       mrg 		credit->i_kills++;
    626   1.1       mrg 		credit->i_gkills++;
    627   1.1       mrg 	}
    628   1.1       mrg 	else {
    629   1.1       mrg 		credit->i_kills--;
    630   1.1       mrg 		credit->i_bkills++;
    631   1.1       mrg 	}
    632   1.1       mrg 	credit->i_score = credit->i_kills / (double) credit->i_entries;
    633   1.1       mrg 	ouch->p_ident->i_deaths++;
    634   1.1       mrg 	if (ouch->p_nchar == 0)
    635   1.1       mrg 		ouch->p_ident->i_stillb++;
    636   1.1       mrg 	if (gotcha == NULL)
    637   1.1       mrg 		return;
    638   1.1       mrg 	gotcha->p_damcap += STABDAM;
    639   1.1       mrg 	gotcha->p_damage -= STABDAM;
    640   1.1       mrg 	if (gotcha->p_damage < 0)
    641   1.1       mrg 		gotcha->p_damage = 0;
    642  1.14  dholland 	(void) snprintf(Buf, sizeof(Buf), "%2d/%2d", gotcha->p_damage,
    643  1.14  dholland 			gotcha->p_damcap);
    644   1.1       mrg 	cgoto(gotcha, STAT_DAM_ROW, STAT_VALUE_COL);
    645   1.1       mrg 	outstr(gotcha, Buf, 5);
    646  1.14  dholland 	(void) snprintf(Buf, sizeof(Buf), "%3d",
    647  1.14  dholland 			(gotcha->p_damcap - MAXDAM) / 2);
    648   1.1       mrg 	cgoto(gotcha, STAT_KILL_ROW, STAT_VALUE_COL);
    649   1.1       mrg 	outstr(gotcha, Buf, 3);
    650  1.14  dholland 	(void) snprintf(Buf, sizeof(Buf), "%5.2f", gotcha->p_ident->i_score);
    651   1.1       mrg 	for (ouch = Player; ouch < End_player; ouch++) {
    652   1.1       mrg 		cgoto(ouch, STAT_PLAY_ROW + 1 + (gotcha - Player),
    653   1.1       mrg 			STAT_NAME_COL);
    654   1.1       mrg 		outstr(ouch, Buf, 5);
    655   1.1       mrg 	}
    656  1.17  dholland #ifdef MONITOR
    657   1.1       mrg 	for (ouch = Monitor; ouch < End_monitor; ouch++) {
    658   1.1       mrg 		cgoto(ouch, STAT_PLAY_ROW + 1 + (gotcha - Player),
    659   1.1       mrg 			STAT_NAME_COL);
    660   1.1       mrg 		outstr(ouch, Buf, 5);
    661   1.1       mrg 	}
    662  1.17  dholland #endif
    663   1.1       mrg }
    664   1.1       mrg 
    665   1.1       mrg /*
    666   1.1       mrg  * zap:
    667   1.1       mrg  *	Kill off a player and take him out of the game.
    668   1.1       mrg  */
    669   1.2     lukem static void
    670  1.24  dholland zap(PLAYER *pp, bool was_player, int i)
    671   1.1       mrg {
    672  1.17  dholland 	int n, len;
    673  1.17  dholland 	BULLET *bp;
    674  1.17  dholland 	PLAYER *np;
    675  1.17  dholland 	int x, y;
    676   1.1       mrg 
    677   1.1       mrg 	if (was_player) {
    678   1.1       mrg 		if (pp->p_undershot)
    679   1.1       mrg 			fixshots(pp->p_y, pp->p_x, pp->p_over);
    680  1.24  dholland 		drawplayer(pp, false);
    681   1.1       mrg 		Nplayer--;
    682   1.1       mrg 	}
    683   1.1       mrg 
    684   1.1       mrg 	len = strlen(pp->p_death);	/* Display the cause of death */
    685   1.1       mrg 	x = (WIDTH - len) / 2;
    686   1.1       mrg 	cgoto(pp, HEIGHT / 2, x);
    687   1.1       mrg 	outstr(pp, pp->p_death, len);
    688   1.8   mycroft 	for (n = 1; n < len; n++)
    689   1.8   mycroft 		pp->p_death[n] = '-';
    690   1.1       mrg 	pp->p_death[0] = '+';
    691   1.1       mrg 	pp->p_death[len - 1] = '+';
    692   1.1       mrg 	cgoto(pp, HEIGHT / 2 - 1, x);
    693   1.1       mrg 	outstr(pp, pp->p_death, len);
    694   1.1       mrg 	cgoto(pp, HEIGHT / 2 + 1, x);
    695   1.1       mrg 	outstr(pp, pp->p_death, len);
    696   1.1       mrg 	cgoto(pp, HEIGHT, 0);
    697   1.1       mrg 
    698  1.17  dholland #ifdef MONITOR
    699   1.1       mrg 	if (was_player) {
    700  1.17  dholland #endif
    701   1.1       mrg 		for (bp = Bullets; bp != NULL; bp = bp->b_next) {
    702   1.1       mrg 			if (bp->b_owner == pp)
    703   1.1       mrg 				bp->b_owner = NULL;
    704   1.1       mrg 			if (bp->b_x == pp->p_x && bp->b_y == pp->p_y)
    705   1.1       mrg 				bp->b_over = SPACE;
    706   1.1       mrg 		}
    707   1.1       mrg 
    708   1.8   mycroft 		n = rand_num(pp->p_ammo);
    709   1.1       mrg 		x = rand_num(pp->p_ammo);
    710   1.8   mycroft 		if (x > n)
    711   1.8   mycroft 			n = x;
    712   1.1       mrg 		if (pp->p_ammo == 0)
    713   1.1       mrg 			x = 0;
    714   1.8   mycroft 		else if (n == pp->p_ammo - 1) {
    715   1.1       mrg 			x = pp->p_ammo;
    716   1.1       mrg 			len = SLIME;
    717   1.1       mrg 		}
    718   1.1       mrg 		else {
    719   1.1       mrg 			for (x = MAXBOMB - 1; x > 0; x--)
    720   1.8   mycroft 				if (n >= shot_req[x])
    721   1.1       mrg 					break;
    722   1.1       mrg 			for (y = MAXSLIME - 1; y > 0; y--)
    723   1.8   mycroft 				if (n >= slime_req[y])
    724   1.1       mrg 					break;
    725   1.1       mrg 			if (y >= 0 && slime_req[y] > shot_req[x]) {
    726   1.1       mrg 				x = slime_req[y];
    727   1.1       mrg 				len = SLIME;
    728   1.1       mrg 			}
    729   1.1       mrg 			else if (x != 0) {
    730   1.1       mrg 				len = shot_type[x];
    731   1.1       mrg 				x = shot_req[x];
    732   1.1       mrg 			}
    733   1.1       mrg 		}
    734   1.1       mrg 		if (x > 0) {
    735   1.1       mrg 			(void) add_shot(len, pp->p_y, pp->p_x, pp->p_face, x,
    736  1.24  dholland 				NULL, true, SPACE);
    737  1.14  dholland 			(void) snprintf(Buf, sizeof(Buf), "%s detonated.",
    738   1.1       mrg 				pp->p_ident->i_name);
    739   1.1       mrg 			for (np = Player; np < End_player; np++)
    740   1.1       mrg 				message(np, Buf);
    741  1.17  dholland #ifdef MONITOR
    742   1.1       mrg 			for (np = Monitor; np < End_monitor; np++)
    743   1.1       mrg 				message(np, Buf);
    744  1.17  dholland #endif
    745  1.17  dholland #ifdef BOOTS
    746   1.1       mrg 			while (pp->p_nboots-- > 0) {
    747   1.1       mrg 				for (np = Boot; np < &Boot[NBOOTS]; np++)
    748   1.1       mrg 					if (np->p_flying < 0)
    749   1.1       mrg 						break;
    750   1.1       mrg 				if (np >= &Boot[NBOOTS])
    751   1.2     lukem 					err(1, "Too many boots");
    752  1.24  dholland 				np->p_undershot = false;
    753   1.1       mrg 				np->p_x = pp->p_x;
    754   1.1       mrg 				np->p_y = pp->p_y;
    755   1.1       mrg 				np->p_flying = rand_num(20);
    756   1.1       mrg 				np->p_flyx = 2 * rand_num(6) - 5;
    757   1.1       mrg 				np->p_flyy = 2 * rand_num(6) - 5;
    758   1.1       mrg 				np->p_over = SPACE;
    759   1.1       mrg 				np->p_face = BOOT;
    760   1.1       mrg 				showexpl(np->p_y, np->p_x, BOOT);
    761   1.1       mrg 			}
    762  1.17  dholland #endif
    763   1.1       mrg 		}
    764  1.17  dholland #ifdef BOOTS
    765   1.1       mrg 		else if (pp->p_nboots > 0) {
    766   1.1       mrg 			if (pp->p_nboots == 2)
    767   1.1       mrg 				Maze[pp->p_y][pp->p_x] = BOOT_PAIR;
    768   1.1       mrg 			else
    769   1.1       mrg 				Maze[pp->p_y][pp->p_x] = BOOT;
    770   1.1       mrg 			if (pp->p_undershot)
    771   1.1       mrg 				fixshots(pp->p_y, pp->p_x,
    772   1.1       mrg 					Maze[pp->p_y][pp->p_x]);
    773   1.1       mrg 		}
    774  1.17  dholland #endif
    775   1.1       mrg 
    776  1.17  dholland #ifdef VOLCANO
    777   1.1       mrg 		volcano += pp->p_ammo - x;
    778   1.1       mrg 		if (rand_num(100) < volcano / 50) {
    779   1.1       mrg 			do {
    780   1.1       mrg 				x = rand_num(WIDTH / 2) + WIDTH / 4;
    781   1.1       mrg 				y = rand_num(HEIGHT / 2) + HEIGHT / 4;
    782   1.1       mrg 			} while (Maze[y][x] != SPACE);
    783   1.1       mrg 			(void) add_shot(LAVA, y, x, LEFTS, volcano,
    784  1.24  dholland 				NULL, true, SPACE);
    785   1.1       mrg 			for (np = Player; np < End_player; np++)
    786   1.1       mrg 				message(np, "Volcano eruption.");
    787   1.1       mrg 			volcano = 0;
    788   1.1       mrg 		}
    789  1.17  dholland #endif
    790   1.1       mrg 
    791  1.17  dholland #ifdef DRONE
    792   1.1       mrg 		if (rand_num(100) < 2) {
    793   1.1       mrg 			do {
    794   1.1       mrg 				x = rand_num(WIDTH / 2) + WIDTH / 4;
    795   1.1       mrg 				y = rand_num(HEIGHT / 2) + HEIGHT / 4;
    796   1.1       mrg 			} while (Maze[y][x] != SPACE);
    797   1.1       mrg 			add_shot(DSHOT, y, x, rand_dir(),
    798   1.1       mrg 				shot_req[MINDSHOT +
    799   1.1       mrg 				rand_num(MAXBOMB - MINDSHOT)],
    800  1.24  dholland 				NULL, false, SPACE);
    801   1.1       mrg 		}
    802  1.17  dholland #endif
    803   1.1       mrg 
    804   1.1       mrg 		sendcom(pp, ENDWIN);
    805   1.1       mrg 		(void) putc(' ', pp->p_output);
    806   1.1       mrg 		(void) fclose(pp->p_output);
    807   1.1       mrg 
    808   1.1       mrg 		End_player--;
    809   1.1       mrg 		if (pp != End_player) {
    810   1.1       mrg 			memcpy(pp, End_player, sizeof (PLAYER));
    811   1.8   mycroft 			fdset[i] = fdset[End_player - Player + 3];
    812   1.8   mycroft 			fdset[End_player - Player + 3].fd = -1;
    813  1.14  dholland 			(void) snprintf(Buf, sizeof(Buf), "%5.2f%c%-10.10s %c",
    814   1.1       mrg 				pp->p_ident->i_score, stat_char(pp),
    815   1.1       mrg 				pp->p_ident->i_name, pp->p_ident->i_team);
    816   1.8   mycroft 			n = STAT_PLAY_ROW + 1 + (pp - Player);
    817   1.1       mrg 			for (np = Player; np < End_player; np++) {
    818   1.8   mycroft 				cgoto(np, n, STAT_NAME_COL);
    819   1.1       mrg 				outstr(np, Buf, STAT_NAME_LEN);
    820   1.1       mrg 			}
    821  1.17  dholland #ifdef MONITOR
    822   1.1       mrg 			for (np = Monitor; np < End_monitor; np++) {
    823   1.8   mycroft 				cgoto(np, n, STAT_NAME_COL);
    824   1.1       mrg 				outstr(np, Buf, STAT_NAME_LEN);
    825   1.1       mrg 			}
    826  1.17  dholland #endif
    827   1.8   mycroft 		} else
    828   1.8   mycroft 			fdset[i].fd = -1;
    829   1.1       mrg 
    830   1.1       mrg 		/* Erase the last player */
    831   1.8   mycroft 		n = STAT_PLAY_ROW + 1 + Nplayer;
    832   1.1       mrg 		for (np = Player; np < End_player; np++) {
    833   1.8   mycroft 			cgoto(np, n, STAT_NAME_COL);
    834   1.1       mrg 			ce(np);
    835   1.1       mrg 		}
    836  1.17  dholland #ifdef MONITOR
    837   1.1       mrg 		for (np = Monitor; np < End_monitor; np++) {
    838   1.8   mycroft 			cgoto(np, n, STAT_NAME_COL);
    839   1.1       mrg 			ce(np);
    840   1.1       mrg 		}
    841   1.1       mrg 	}
    842   1.1       mrg 	else {
    843   1.1       mrg 		sendcom(pp, ENDWIN);
    844   1.1       mrg 		(void) putc(LAST_PLAYER, pp->p_output);
    845   1.1       mrg 		(void) fclose(pp->p_output);
    846   1.1       mrg 
    847   1.1       mrg 		End_monitor--;
    848   1.1       mrg 		if (pp != End_monitor) {
    849   1.1       mrg 			memcpy(pp, End_monitor, sizeof (PLAYER));
    850   1.8   mycroft 			fdset[i] = fdset[End_monitor - Monitor + MAXPL + 3];
    851   1.8   mycroft 			fdset[End_monitor - Monitor + MAXPL + 3].fd = -1;
    852  1.14  dholland 			(void) snprintf(Buf, sizeof(Buf), "%5.5s %-10.10s %c",
    853  1.14  dholland 				" ",
    854   1.1       mrg 				pp->p_ident->i_name, pp->p_ident->i_team);
    855   1.8   mycroft 			n = STAT_MON_ROW + 1 + (pp - Player);
    856   1.1       mrg 			for (np = Player; np < End_player; np++) {
    857   1.8   mycroft 				cgoto(np, n, STAT_NAME_COL);
    858   1.1       mrg 				outstr(np, Buf, STAT_NAME_LEN);
    859   1.1       mrg 			}
    860   1.1       mrg 			for (np = Monitor; np < End_monitor; np++) {
    861   1.8   mycroft 				cgoto(np, n, STAT_NAME_COL);
    862   1.1       mrg 				outstr(np, Buf, STAT_NAME_LEN);
    863   1.1       mrg 			}
    864   1.8   mycroft 		} else
    865   1.8   mycroft 			fdset[i].fd = -1;
    866   1.1       mrg 
    867   1.1       mrg 		/* Erase the last monitor */
    868   1.8   mycroft 		n = STAT_MON_ROW + 1 + (End_monitor - Monitor);
    869   1.1       mrg 		for (np = Player; np < End_player; np++) {
    870   1.8   mycroft 			cgoto(np, n, STAT_NAME_COL);
    871   1.1       mrg 			ce(np);
    872   1.1       mrg 		}
    873   1.1       mrg 		for (np = Monitor; np < End_monitor; np++) {
    874   1.8   mycroft 			cgoto(np, n, STAT_NAME_COL);
    875   1.1       mrg 			ce(np);
    876   1.1       mrg 		}
    877   1.1       mrg 	}
    878  1.17  dholland #endif
    879   1.1       mrg }
    880   1.1       mrg 
    881   1.1       mrg /*
    882   1.1       mrg  * rand_num:
    883   1.1       mrg  *	Return a random number in a given range.
    884   1.1       mrg  */
    885   1.2     lukem int
    886  1.16  dholland rand_num(int range)
    887   1.1       mrg {
    888  1.23  dholland 	return (range == 0 ? 0 : random() % range);
    889   1.1       mrg }
    890   1.1       mrg 
    891   1.1       mrg /*
    892   1.1       mrg  * havechar:
    893   1.1       mrg  *	Check to see if we have any characters in the input queue; if
    894  1.24  dholland  *	we do, read them, stash them away, and return true; else return
    895  1.24  dholland  *	false.
    896   1.1       mrg  */
    897  1.24  dholland static bool
    898  1.16  dholland havechar(PLAYER *pp, int i)
    899   1.1       mrg {
    900   1.1       mrg 
    901   1.1       mrg 	if (pp->p_ncount < pp->p_nchar)
    902  1.24  dholland 		return true;
    903   1.8   mycroft 	if (!(fdset[i].revents & POLLIN))
    904  1.24  dholland 		return false;
    905   1.1       mrg check_again:
    906  1.30  dholland 	pp->p_nchar = read(pp->p_fd, pp->p_cbuf, sizeof pp->p_cbuf);
    907  1.30  dholland 	if (pp->p_nchar < 0 && errno == EINTR) {
    908  1.30  dholland 		goto check_again;
    909  1.30  dholland 	} else if (pp->p_nchar <= 0) {
    910   1.1       mrg 		if (errno == EINTR)
    911   1.1       mrg 		pp->p_cbuf[0] = 'q';
    912   1.1       mrg 	}
    913   1.1       mrg 	pp->p_ncount = 0;
    914  1.24  dholland 	return true;
    915   1.1       mrg }
    916   1.1       mrg 
    917   1.1       mrg /*
    918   1.1       mrg  * cleanup:
    919   1.1       mrg  *	Exit with the given value, cleaning up any droppings lying around
    920   1.1       mrg  */
    921  1.19  dholland void
    922  1.30  dholland cleanup(int exitval)
    923   1.1       mrg {
    924  1.17  dholland 	PLAYER *pp;
    925   1.1       mrg 
    926   1.1       mrg 	for (pp = Player; pp < End_player; pp++) {
    927   1.1       mrg 		cgoto(pp, HEIGHT, 0);
    928   1.1       mrg 		sendcom(pp, ENDWIN);
    929   1.1       mrg 		(void) putc(LAST_PLAYER, pp->p_output);
    930   1.1       mrg 		(void) fclose(pp->p_output);
    931   1.1       mrg 	}
    932  1.17  dholland #ifdef MONITOR
    933   1.1       mrg 	for (pp = Monitor; pp < End_monitor; pp++) {
    934   1.1       mrg 		cgoto(pp, HEIGHT, 0);
    935   1.1       mrg 		sendcom(pp, ENDWIN);
    936   1.1       mrg 		(void) putc(LAST_PLAYER, pp->p_output);
    937   1.1       mrg 		(void) fclose(pp->p_output);
    938   1.1       mrg 	}
    939  1.17  dholland #endif
    940  1.34  dholland 	(void) close(huntsock);
    941  1.17  dholland #ifdef AF_UNIX_HACK
    942  1.34  dholland 	(void) unlink(huntsockpath);
    943  1.17  dholland #endif
    944   1.1       mrg 
    945  1.30  dholland 	exit(exitval);
    946   1.1       mrg }
    947   1.1       mrg 
    948   1.1       mrg /*
    949   1.1       mrg  * send_stats:
    950   1.1       mrg  *	Print stats to requestor
    951   1.1       mrg  */
    952   1.2     lukem static void
    953  1.16  dholland send_stats(void)
    954   1.1       mrg {
    955  1.17  dholland 	IDENT *ip;
    956  1.17  dholland 	FILE *fp;
    957  1.17  dholland 	int s;
    958  1.35  dholland 	struct sockaddr_storage newaddr;
    959  1.17  dholland 	socklen_t socklen;
    960   1.1       mrg 
    961   1.1       mrg 	/*
    962   1.1       mrg 	 * Get the output stream ready
    963   1.1       mrg 	 */
    964  1.35  dholland 	socklen = sizeof(newaddr);
    965  1.35  dholland 	s = accept(statsock, (struct sockaddr *)&newaddr, &socklen);
    966   1.1       mrg 	if (s < 0) {
    967   1.1       mrg 		if (errno == EINTR)
    968   1.1       mrg 			return;
    969  1.32  dholland 		complain(LOG_WARNING, "accept");
    970   1.1       mrg 		return;
    971   1.1       mrg 	}
    972   1.1       mrg 	fp = fdopen(s, "w");
    973   1.1       mrg 	if (fp == NULL) {
    974  1.32  dholland 		complain(LOG_WARNING, "fdopen");
    975   1.1       mrg 		(void) close(s);
    976   1.1       mrg 		return;
    977   1.1       mrg 	}
    978   1.1       mrg 
    979   1.1       mrg 	/*
    980   1.1       mrg 	 * Send output to requestor
    981   1.1       mrg 	 */
    982   1.1       mrg 	fputs("Name\t\tScore\tDucked\tAbsorb\tFaced\tShot\tRobbed\tMissed\tSlimeK\n", fp);
    983   1.1       mrg 	for (ip = Scores; ip != NULL; ip = ip->i_next) {
    984   1.1       mrg 		fprintf(fp, "%s\t", ip->i_name);
    985   1.1       mrg 		if (strlen(ip->i_name) < 8)
    986   1.1       mrg 			putc('\t', fp);
    987   1.1       mrg 		fprintf(fp, "%.2f\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
    988   1.1       mrg 			ip->i_score, ip->i_ducked, ip->i_absorbed,
    989   1.1       mrg 			ip->i_faced, ip->i_shot, ip->i_robbed,
    990   1.1       mrg 			ip->i_missed, ip->i_slime);
    991   1.1       mrg 	}
    992   1.1       mrg 	fputs("\n\nName\t\tEnemy\tFriend\tDeaths\tStill\tSaved\n", fp);
    993   1.1       mrg 	for (ip = Scores; ip != NULL; ip = ip->i_next) {
    994   1.1       mrg 		if (ip->i_team == ' ') {
    995   1.1       mrg 			fprintf(fp, "%s\t", ip->i_name);
    996   1.1       mrg 			if (strlen(ip->i_name) < 8)
    997   1.1       mrg 				putc('\t', fp);
    998   1.1       mrg 		}
    999   1.1       mrg 		else {
   1000   1.1       mrg 			fprintf(fp, "%s[%c]\t", ip->i_name, ip->i_team);
   1001   1.1       mrg 			if (strlen(ip->i_name) + 3 < 8)
   1002   1.1       mrg 				putc('\t', fp);
   1003   1.1       mrg 		}
   1004   1.1       mrg 		fprintf(fp, "%d\t%d\t%d\t%d\t%d\n",
   1005   1.1       mrg 			ip->i_gkills, ip->i_bkills, ip->i_deaths,
   1006   1.1       mrg 			ip->i_stillb, ip->i_saved);
   1007   1.1       mrg 	}
   1008   1.1       mrg 
   1009   1.1       mrg 	(void) fclose(fp);
   1010   1.1       mrg }
   1011   1.1       mrg 
   1012   1.1       mrg /*
   1013   1.1       mrg  * clear_scores:
   1014   1.1       mrg  *	Clear out the scores so the next session start clean
   1015   1.1       mrg  */
   1016   1.2     lukem static void
   1017  1.16  dholland clear_scores(void)
   1018   1.1       mrg {
   1019  1.17  dholland 	IDENT *ip, *nextip;
   1020   1.1       mrg 
   1021   1.1       mrg 	for (ip = Scores; ip != NULL; ip = nextip) {
   1022   1.1       mrg 		nextip = ip->i_next;
   1023  1.15  dholland 		(void) free(ip);
   1024   1.1       mrg 	}
   1025   1.1       mrg 	Scores = NULL;
   1026   1.1       mrg }
   1027