(linenum→info "unix/slp.c:2238")

bsd-games/2.17/hunt/huntd/driver.c

    1: /*      $NetBSD: driver.c,v 1.10 2004/01/27 20:30:29 jsm Exp $       */
    2: /*
    3:  * Copyright (c) 1983-2003, Regents of the University of California.
    4:  * All rights reserved.
    5:  * 
    6:  * Redistribution and use in source and binary forms, with or without 
    7:  * modification, are permitted provided that the following conditions are 
    8:  * met:
    9:  * 
   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 
   18:  *   permission.
   19:  * 
   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.
   31:  */
   32: 
   33: #include <sys/cdefs.h>
   34: #ifndef lint
   35: __RCSID("$NetBSD: driver.c,v 1.10 2004/01/27 20:30:29 jsm Exp $");
   36: #endif /* not lint */
   37: 
   38: # include       <sys/ioctl.h>
   39: # include       <sys/stat.h>
   40: # include       <sys/time.h>
   41: # include       <err.h>
   42: # include       <errno.h>
   43: # include       <signal.h>
   44: # include       <stdlib.h>
   45: # include       <time.h>
   46: # include       <unistd.h>
   47: # include       "hunt.h"
   48: 
   49: # ifndef pdp11
   50: # define        RN     (((Seed = Seed * 11109 + 13849) >> 16) & 0xffff)
   51: # else
   52: # define        RN     ((Seed = Seed * 11109 + 13849) & 0x7fff)
   53: # endif
   54: 
   55: int     Seed = 0;
   56: 
   57: 
   58: SOCKET  Daemon;
   59: char    *First_arg;                /* pointer to argv[0] */
   60: char    *Last_arg;         /* pointer to end of argv/environ */
   61: # ifdef INTERNET
   62: int     Test_socket;                /* test socket to answer datagrams */
   63: FLAG    inetd_spawned;             /* invoked via inetd */
   64: FLAG    standard_port = TRUE;      /* true if listening on standard port */
   65: u_short sock_port;              /* port # of tcp listen socket */
   66: u_short stat_port;              /* port # of statistics tcp socket */
   67: # define        DAEMON_SIZE    (sizeof Daemon)
   68: # else
   69: # define        DAEMON_SIZE    (sizeof Daemon - 1)
   70: # endif
   71: 
   72: static  void     clear_scores(void);
   73: static  int      havechar(PLAYER *, int);
   74: static  void     init(void);
   75:         int    main(int, char *[], char *[]);
   76: static  void     makeboots(void);
   77: static  void     send_stats(void);
   78: static  void     zap(PLAYER *, FLAG, int);
   79: 
   80: 
   81: /*
   82:  * main:
   83:  *      The main program.
   84:  */
   85: int
   86: main(ac, av, ep)
   87:         int    ac;
   88:         char   **av, **ep;
   89: {
   90:         PLAYER *pp;
   91: # ifdef INTERNET
   92:         u_short        msg;
   93:         short  port_num, reply;
   94:         int    namelen;
   95:         SOCKET test;
   96: # endif
   97:         static FLAG    first = TRUE;
   98:         static FLAG    server = FALSE;
   99:         int            c, i;
  100:         const int      linger = 90 * 1000;
  101: 
  102:         First_arg = av[0];
  103:         if (ep == NULL || *ep == NULL)
  104:                 ep = av + ac;
  105:         while (*ep)
  106:                 ep++;
  107:         Last_arg = ep[-1] + strlen(ep[-1]);
  108: 
  109:         while ((c = getopt(ac, av, "sp:")) != -1) {
  110:                 switch (c) {
  111:                   case 's':
  112:                         server = TRUE;
  113:                         break;
  114: # ifdef INTERNET
  115:                   case 'p':
  116:                         standard_port = FALSE;
  117:                         Test_port = atoi(optarg);
  118:                         break;
  119: # endif
  120:                   default:
  121: erred:
  122:                         fprintf(stderr, "Usage: %s [-s] [-p port]\n", av[0]);
  123:                         exit(1);
  124:                 }
  125:         }
  126:         if (optind < ac)
  127:                 goto erred;
  128: 
  129:         init();
  130: 
  131: 
  132: again:
  133:         do {
  134:                 errno = 0;
  135:                 while (poll(fdset, 3+MAXPL+MAXMON, INFTIM) < 0)
  136:                 {
  137:                         if (errno != EINTR)
  138: # ifdef LOG
  139:                                 syslog(LOG_WARNING, "select: %m");
  140: # else
  141:                                 warn("select");
  142: # endif
  143:                         errno = 0;
  144:                 }
  145: # ifdef INTERNET
  146:                 if (fdset[2].revents & POLLIN) {
  147:                         namelen = DAEMON_SIZE;
  148:                         port_num = htons(sock_port);
  149:                         (void) recvfrom(Test_socket, (char *) &msg, sizeof msg,
  150:                                 0, (struct sockaddr *) &test, &namelen);
  151:                         switch (ntohs(msg)) {
  152:                           case C_MESSAGE:
  153:                                 if (Nplayer <= 0)
  154:                                         break;
  155:                                 reply = htons((u_short) Nplayer);
  156:                                 (void) sendto(Test_socket, (char *) &reply,
  157:                                         sizeof reply, 0,
  158:                                         (struct sockaddr *) &test, DAEMON_SIZE);
  159:                                 break;
  160:                           case C_SCORES:
  161:                                 reply = htons(stat_port);
  162:                                 (void) sendto(Test_socket, (char *) &reply,
  163:                                         sizeof reply, 0,
  164:                                         (struct sockaddr *) &test, DAEMON_SIZE);
  165:                                 break;
  166:                           case C_PLAYER:
  167:                           case C_MONITOR:
  168:                                 if (msg == C_MONITOR && Nplayer <= 0)
  169:                                         break;
  170:                                 reply = htons(sock_port);
  171:                                 (void) sendto(Test_socket, (char *) &reply,
  172:                                         sizeof reply, 0,
  173:                                         (struct sockaddr *) &test, DAEMON_SIZE);
  174:                                 break;
  175:                         }
  176:                 }
  177: # endif
  178:                 {
  179:                         for (pp = Player, i = 0; pp < End_player; pp++, i++)
  180:                                 if (havechar(pp, i + 3)) {
  181:                                         execute(pp);
  182:                                         pp->p_nexec++;
  183:                                 }
  184: # ifdef MONITOR
  185:                         for (pp = Monitor, i = 0; pp < End_monitor; pp++, i++)
  186:                                 if (havechar(pp, i + MAXPL + 3)) {
  187:                                         mon_execute(pp);
  188:                                         pp->p_nexec++;
  189:                                 }
  190: # endif
  191:                         moveshots();
  192:                         for (pp = Player, i = 0; pp < End_player; )
  193:                                 if (pp->p_death[0] != '\0')
  194:                                         zap(pp, TRUE, i + 3);
  195:                                 else
  196:                                         pp++, i++;
  197: # ifdef MONITOR
  198:                         for (pp = Monitor, i = 0; pp < End_monitor; )
  199:                                 if (pp->p_death[0] != '\0')
  200:                                         zap(pp, FALSE, i + MAXPL + 3);
  201:                                 else
  202:                                         pp++, i++;
  203: # endif
  204:                 }
  205:                 if (fdset[0].revents & POLLIN)
  206:                         if (answer()) {
  207: # ifdef INTERNET
  208:                                 if (first && standard_port)
  209:                                         faketalk();
  210: # endif
  211:                                 first = FALSE;
  212:                         }
  213:                 if (fdset[1].revents & POLLIN)
  214:                         send_stats();
  215:                 for (pp = Player, i = 0; pp < End_player; pp++, i++) {
  216:                         if (fdset[i + 3].revents & POLLIN)
  217:                                 sendcom(pp, READY, pp->p_nexec);
  218:                         pp->p_nexec = 0;
  219:                         (void) fflush(pp->p_output);
  220:                 }
  221: # ifdef MONITOR
  222:                 for (pp = Monitor, i = 0; pp < End_monitor; pp++, i++) {
  223:                         if (fdset[i + MAXPL + 3].revents & POLLIN)
  224:                                 sendcom(pp, READY, pp->p_nexec);
  225:                         pp->p_nexec = 0;
  226:                         (void) fflush(pp->p_output);
  227:                 }
  228: # endif
  229:         } while (Nplayer > 0);
  230: 
  231:         if (poll(fdset, 3+MAXPL+MAXMON, linger) > 0) {
  232:                 goto again;
  233:         }
  234:         if (server) {
  235:                 clear_scores();
  236:                 makemaze();
  237:                 clearwalls();
  238: # ifdef BOOTS
  239:                 makeboots();
  240: # endif
  241:                 first = TRUE;
  242:                 goto again;
  243:         }
  244: 
  245: # ifdef MONITOR
  246:         for (pp = Monitor, i = 0; pp < End_monitor; i++)
  247:                 zap(pp, FALSE, i + MAXPL + 3);
  248: # endif
  249:         cleanup(0);
  250:         /* NOTREACHED */
  251:         return(0);
  252: }
  253: 
  254: /*
  255:  * init:
  256:  *      Initialize the global parameters.
  257:  */
  258: static void
  259: init()
  260: {
  261:         int    i;
  262: # ifdef INTERNET
  263:         SOCKET test_port;
  264:         int    msg;
  265:         int    len;
  266: # endif
  267: 
  268: # ifndef DEBUG
  269:         switch (fork()) {
  270:           case -1:
  271:                 err(1, "fork");
  272:           case 0:
  273:                 break; /* child */
  274:           default:
  275:                 exit(0); /* parent */
  276:         }
  277:         if (setsid() == -1)
  278:                 err(1, "setsid");
  279:         (void) signal(SIGHUP, SIG_IGN);
  280:         (void) signal(SIGINT, SIG_IGN);
  281:         (void) signal(SIGQUIT, SIG_IGN);
  282:         (void) signal(SIGTERM, cleanup);
  283: # endif
  284: 
  285:         (void) chdir("/var/tmp");      /* just in case it core dumps */
  286:         (void) umask(0);               /* No privacy at all! */
  287:         (void) signal(SIGPIPE, SIG_IGN);
  288: 
  289: # ifdef LOG
  290: # ifdef SYSLOG_43
  291:         openlog("huntd", LOG_PID, LOG_DAEMON);
  292: # endif
  293: # ifdef SYSLOG_42
  294:         openlog("huntd", LOG_PID);
  295: # endif
  296: # endif
  297: 
  298:         /*
  299:          * Initialize statistics socket
  300:          */
  301: # ifdef INTERNET
  302:         Daemon.sin_family = SOCK_FAMILY;
  303:         Daemon.sin_addr.s_addr = INADDR_ANY;
  304:         Daemon.sin_port = 0;
  305: # else
  306:         Daemon.sun_family = SOCK_FAMILY;
  307:         (void) strcpy(Daemon.sun_path, Stat_name);
  308: # endif
  309: 
  310:         Status = socket(SOCK_FAMILY, SOCK_STREAM, 0);
  311:         if (bind(Status, (struct sockaddr *) &Daemon, DAEMON_SIZE) < 0) {
  312:                 if (errno == EADDRINUSE)
  313:                         exit(0);
  314:                 else {
  315: # ifdef LOG
  316:                         syslog(LOG_ERR, "bind: %m");
  317: # else
  318:                         warn("bind");
  319: # endif
  320:                         cleanup(1);
  321:                 }
  322:         }
  323:         (void) listen(Status, 5);
  324: 
  325: # ifdef INTERNET
  326:         len = sizeof (SOCKET);
  327:         if (getsockname(Status, (struct sockaddr *) &Daemon, &len) < 0)  {
  328: # ifdef LOG
  329:                 syslog(LOG_ERR, "getsockname: %m");
  330: # else
  331:                 warn("getsockname");
  332: # endif
  333:                 exit(1);
  334:         }
  335:         stat_port = ntohs(Daemon.sin_port);
  336: # endif
  337: 
  338:         /*
  339:          * Initialize main socket
  340:          */
  341: # ifdef INTERNET
  342:         Daemon.sin_family = SOCK_FAMILY;
  343:         Daemon.sin_addr.s_addr = INADDR_ANY;
  344:         Daemon.sin_port = 0;
  345: # else
  346:         Daemon.sun_family = SOCK_FAMILY;
  347:         (void) strcpy(Daemon.sun_path, Sock_name);
  348: # endif
  349: 
  350:         Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0);
  351: # if defined(INTERNET)
  352:         msg = 1;
  353: #ifdef SO_USELOOPBACK
  354:         if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK, &msg, sizeof msg)<0)
  355: # ifdef LOG
  356:                 syslog(LOG_WARNING, "setsockopt loopback %m");
  357: # else
  358:                 warn("setsockopt loopback");
  359: # endif
  360: #endif
  361: # endif
  362:         if (bind(Socket, (struct sockaddr *) &Daemon, DAEMON_SIZE) < 0) {
  363:                 if (errno == EADDRINUSE)
  364:                         exit(0);
  365:                 else {
  366: # ifdef LOG
  367:                         syslog(LOG_ERR, "bind: %m");
  368: # else
  369:                         warn("bind");
  370: # endif
  371:                         cleanup(1);
  372:                 }
  373:         }
  374:         (void) listen(Socket, 5);
  375: 
  376: # ifdef INTERNET
  377:         len = sizeof (SOCKET);
  378:         if (getsockname(Socket, (struct sockaddr *) &Daemon, &len) < 0)  {
  379: # ifdef LOG
  380:                 syslog(LOG_ERR, "getsockname: %m");
  381: # else
  382:                 warn("getsockname");
  383: # endif
  384:                 exit(1);
  385:         }
  386:         sock_port = ntohs(Daemon.sin_port);
  387: # endif
  388: 
  389:         /*
  390:          * Initialize minimal select mask
  391:          */
  392:         fdset[0].fd = Socket;
  393:         fdset[0].events = POLLIN;
  394:         fdset[1].fd = Status;
  395:         fdset[1].events = POLLIN;
  396: 
  397: # ifdef INTERNET
  398:         len = sizeof (SOCKET);
  399:         if (getsockname(0, (struct sockaddr *) &test_port, &len) >= 0
  400:         && test_port.sin_family == AF_INET) {
  401:                 inetd_spawned = TRUE;
  402:                 Test_socket = 0;
  403:                 if (test_port.sin_port != htons((u_short) Test_port)) {
  404:                         standard_port = FALSE;
  405:                         Test_port = ntohs(test_port.sin_port);
  406:                 }
  407:         } else {
  408:                 test_port = Daemon;
  409:                 test_port.sin_port = htons((u_short) Test_port);
  410: 
  411:                 Test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0);
  412:                 if (bind(Test_socket, (struct sockaddr *) &test_port,
  413:                     DAEMON_SIZE) < 0) {
  414: # ifdef LOG
  415:                         syslog(LOG_ERR, "bind: %m");
  416: # else
  417:                         warn("bind");
  418: # endif
  419:                         exit(1);
  420:                 }
  421:                 (void) listen(Test_socket, 5);
  422:         }
  423: 
  424:         fdset[2].fd = Test_socket;
  425:         fdset[2].events = POLLIN;
  426: # else
  427:         fdset[2].fd = -1;
  428: # endif
  429: 
  430:         Seed = getpid() + time((time_t *) NULL);
  431:         makemaze();
  432: # ifdef BOOTS
  433:         makeboots();
  434: # endif
  435: 
  436:         for (i = 0; i < NASCII; i++)
  437:                 See_over[i] = TRUE;
  438:         See_over[DOOR] = FALSE;
  439:         See_over[WALL1] = FALSE;
  440:         See_over[WALL2] = FALSE;
  441:         See_over[WALL3] = FALSE;
  442: # ifdef REFLECT
  443:         See_over[WALL4] = FALSE;
  444:         See_over[WALL5] = FALSE;
  445: # endif
  446: 
  447: }
  448: 
  449: # ifdef BOOTS
  450: /*
  451:  * makeboots:
  452:  *      Put the boots in the maze
  453:  */
  454: static void
  455: makeboots()
  456: {
  457:         int    x, y;
  458:         PLAYER *pp;
  459: 
  460:         do {
  461:                 x = rand_num(WIDTH - 1) + 1;
  462:                 y = rand_num(HEIGHT - 1) + 1;
  463:         } while (Maze[y][x] != SPACE);
  464:         Maze[y][x] = BOOT_PAIR;
  465:         for (pp = Boot; pp < &Boot[NBOOTS]; pp++)
  466:                 pp->p_flying = -1;
  467: }
  468: # endif
  469: 
  470: 
  471: /*
  472:  * checkdam:
  473:  *      Check the damage to the given player, and see if s/he is killed
  474:  */
  475: void
  476: checkdam(ouch, gotcha, credit, amt, shot_type)
  477:         PLAYER *ouch, *gotcha;
  478:         IDENT  *credit;
  479:         int    amt;
  480:         char   shot_type;
  481: {
  482:         const char     *cp;
  483: 
  484:         if (ouch->p_death[0] != '\0')
  485:                 return;
  486: # ifdef BOOTS
  487:         if (shot_type == SLIME)
  488:                 switch (ouch->p_nboots) {
  489:                   default:
  490:                         break;
  491:                   case 1:
  492:                         amt = (amt + 1) / 2;
  493:                         break;
  494:                   case 2:
  495:                         if (gotcha != NULL)
  496:                                 message(gotcha, "He has boots on!");
  497:                         return;
  498:                 }
  499: # endif
  500:         ouch->p_damage += amt;
  501:         if (ouch->p_damage <= ouch->p_damcap) {
  502:                 (void) sprintf(Buf, "%2d", ouch->p_damage);
  503:                 cgoto(ouch, STAT_DAM_ROW, STAT_VALUE_COL);
  504:                 outstr(ouch, Buf, 2);
  505:                 return;
  506:         }
  507: 
  508:         /* Someone DIED */
  509:         switch (shot_type) {
  510:           default:
  511:                 cp = "Killed";
  512:                 break;
  513: # ifdef FLY
  514:           case FALL:
  515:                 cp = "Killed on impact";
  516:                 break;
  517: # endif
  518:           case KNIFE:
  519:                 cp = "Stabbed to death";
  520:                 ouch->p_ammo = 0;             /* No exploding */
  521:                 break;
  522:           case SHOT:
  523:                 cp = "Shot to death";
  524:                 break;
  525: