|
|
1.1 root 1: /*
2: * Hunt
3: * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
4: * San Francisco, California
5: *
6: * Copyright (c) 1985 Regents of the University of California.
7: * All rights reserved. The Berkeley software License Agreement
8: * specifies the terms and conditions for redistribution.
9: */
10:
11: # include <errno.h>
12: # include <curses.h>
13: # include "hunt.h"
14: # include <signal.h>
15: # include <ctype.h>
16: # include <sys/stat.h>
17:
18: FLAG Last_player = FALSE;
19: # ifdef MONITOR
20: FLAG Am_monitor = FALSE;
21: # endif MONITOR
22: FLAG Query_driver = FALSE;
23:
24: char Buf[BUFSIZ];
25:
26: int Master_pid;
27: int Socket;
28: # ifdef INTERNET
29: char *Sock_host;
30: # endif INTERNET
31:
32: SOCKET Daemon;
33: # ifdef INTERNET
34: # define DAEMON_SIZE (sizeof Daemon)
35: # else INTERNET
36: # define DAEMON_SIZE (sizeof Daemon - 1)
37: # endif INTERNET
38:
39: char map_key[256]; /* what to map keys to */
40:
41: static char name[NAMELEN];
42:
43: extern int cur_row, cur_col, _putchar();
44: extern char *tgoto();
45:
46: /*
47: * main:
48: * Main program for local process
49: */
50: main(ac, av)
51: int ac;
52: char **av;
53: {
54: char *term;
55: extern int errno;
56: extern int Otto_mode;
57: int dumpit(), intr(), sigterm(), sigemt(), tstp();
58:
59: for (ac--, av++; ac > 0 && av[0][0] == '-'; ac--, av++) {
60: switch (av[0][1]) {
61:
62: case 'l': /* rsh compatibility */
63: case 'n':
64: if (ac <= 1)
65: goto usage;
66: ac--, av++;
67: (void) strcpy(name, av[0]);
68: break;
69: case 'o':
70: # ifndef OTTO
71: fputs("The -o flag is reserved for future use.\n",
72: stderr);
73: goto usage;
74: # else OTTO
75: Otto_mode = TRUE;
76: break;
77: # endif OTTO
78: # ifdef MONITOR
79: case 'm':
80: Am_monitor = TRUE;
81: break;
82: # endif MONITOR
83: # ifdef INTERNET
84: case 'q': /* query whether hunt is running */
85: Query_driver = TRUE;
86: break;
87: case 'h':
88: if (ac <= 1)
89: goto usage;
90: ac--, av++;
91: Sock_host = av[0];
92: break;
93: # endif INTERNET
94: default:
95: usage:
96: # ifdef INTERNET
97: # ifdef MONITOR
98: # define USAGE "usage: hunt [-q] [-n name] [-h host] [-m]\n"
99: # else MONITOR
100: # define USAGE "usage: hunt [-q] [-n name] [-h host]\n"
101: # endif MONITOR
102: # else INTERNET
103: # ifdef MONITOR
104: # define USAGE "usage: hunt [-n name] [-m]\n"
105: # else MONITOR
106: # define USAGE "usage: hunt [-n name]\n"
107: # endif MONITOR
108: # endif INTERNET
109: fputs(USAGE, stderr);
110: # undef USAGE
111: exit(1);
112: }
113: }
114: # ifdef INTERNET
115: if (ac > 1)
116: goto usage;
117: else if (ac > 0)
118: Sock_host = av[0];
119: # else INTERNET
120: if (ac > 0)
121: goto usage;
122: # endif INTERNET
123:
124: # ifdef INTERNET
125: if (Query_driver) {
126: find_driver(FALSE);
127: if (Daemon.sin_port != 0) {
128: struct hostent *hp;
129:
130: hp = gethostbyaddr(&Daemon.sin_addr,
131: sizeof Daemon.sin_addr, AF_INET);
132: fprintf(stderr, "HUNT!! found on %s\n", hp != NULL
133: ? hp->h_name : inet_ntoa(Daemon.sin_addr));
134: }
135: exit(Daemon.sin_port == 0);
136: }
137: # endif INTERNET
138: # ifdef OTTO
139: if (Otto_mode)
140: (void) strcpy(name, "otto");
141: else
142: # endif OTTO
143: env_init();
144:
145: (void) fflush(stdout);
146: if (!isatty(0) || (term = getenv("TERM")) == NULL) {
147: fprintf(stderr, "no terminal type\n");
148: exit(1);
149: }
150: _tty_ch = 0;
151: gettmode();
152: setterm(term);
153: noecho();
154: cbreak();
155: _puts(TI);
156: _puts(VS);
157: clear_screen();
158: (void) signal(SIGINT, intr);
159: (void) signal(SIGTERM, sigterm);
160: (void) signal(SIGEMT, sigemt);
161: (void) signal(SIGQUIT, dumpit);
162: (void) signal(SIGPIPE, SIG_IGN);
163: (void) signal(SIGTSTP, tstp);
164:
165: do {
166: # ifdef INTERNET
167: find_driver(TRUE);
168:
169: do {
170: int msg;
171:
172: # ifndef OLDIPC
173: Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0);
174: # else OLDIPC
175: Socket = socket(SOCK_STREAM, 0, 0, 0);
176: # endif OLDIPC
177: if (Socket < 0) {
178: perror("socket");
179: exit(1);
180: }
181: # ifndef OLDIPC
182: msg = 1;
183: if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK,
184: &msg, sizeof msg) < 0)
185: perror("setsockopt loopback");
186: # endif OLDIPC
187: errno = 0;
188: if (connect(Socket, (struct sockaddr *) &Daemon,
189: DAEMON_SIZE) < 0) {
190: if (errno != ECONNREFUSED) {
191: perror("connect");
192: leave(1, "connect");
193: }
194: }
195: else
196: break;
197: sleep(1);
198: } while (close(Socket) == 0);
199: # else INTERNET
200: /*
201: * set up a socket
202: */
203:
204: if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0) {
205: perror("socket");
206: exit(1);
207: }
208:
209: /*
210: * attempt to connect the socket to a name; if it fails that
211: * usually means that the driver isn't running, so we start
212: * up the driver.
213: */
214:
215: Daemon.sun_family = SOCK_FAMILY;
216: (void) strcpy(Daemon.sun_path, Sock_name);
217: if (connect(Socket, &Daemon, DAEMON_SIZE) < 0) {
218: if (errno != ENOENT) {
219: perror("connect");
220: leave(1, "connect2");
221: }
222: start_driver();
223:
224: do {
225: (void) close(Socket);
226: if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0) {
227: perror("socket");
228: exit(1);
229: }
230: sleep(2);
231: } while (connect(Socket, &Daemon, DAEMON_SIZE) < 0);
232: }
233: # endif INTERNET
234:
235: do_connect(name);
236: playit();
237: } while (!quit());
238: leave(0, NULL);
239: /* NOTREACHED */
240: }
241:
242: # ifdef INTERNET
243: # ifdef BROADCAST
244: broadcast_vec(s, vector)
245: int s; /* socket */
246: struct sockaddr **vector;
247: {
248: char if_buf[BUFSIZ];
249: struct ifconf ifc;
250: struct ifreq *ifr;
251: int n;
252: int vec_cnt;
253:
254: *vector = NULL;
255: ifc.ifc_len = sizeof if_buf;
256: ifc.ifc_buf = if_buf;
257: if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0)
258: return 0;
259: vec_cnt = 0;
260: n = ifc.ifc_len / sizeof (struct ifreq);
261: *vector = (struct sockaddr *) malloc(n * sizeof (struct sockaddr));
262: for (ifr = ifc.ifc_req; n > 0; n--, ifr++)
263: if (ioctl(s, SIOCGIFBRDADDR, ifr) >= 0)
264: bcopy(&ifr->ifr_addr, &(*vector)[vec_cnt++],
265: sizeof (struct sockaddr));
266: return vec_cnt;
267: }
268: # endif BROADCAST
269:
270: find_driver(do_startup)
271: FLAG do_startup;
272: {
273: int msg;
274: static SOCKET test;
275: int test_socket;
276: int namelen;
277: char local_name[80];
278: static initial = TRUE;
279: static struct in_addr local_address;
280: register struct hostent *hp;
281: int (*oldsigalrm)(), sigalrm();
282: extern int errno;
283: # ifdef BROADCAST
284: static int brdc;
285: static SOCKET *brdv;
286: int i;
287: # endif BROADCAST
288:
289: if (Sock_host != NULL) {
290: if (!initial)
291: return; /* Daemon address already valid */
292: initial = FALSE;
293: if ((hp = gethostbyname(Sock_host)) == NULL) {
294: leave(1, "Unknown host");
295: /* NOTREACHED */
296: }
297: Daemon.sin_family = SOCK_FAMILY;
298: Daemon.sin_port = htons(Sock_port);
299: Daemon.sin_addr = *((struct in_addr *) hp->h_addr);
300: if (!Query_driver)
301: return;
302: }
303:
304:
305: if (initial) { /* do one time initialization */
306: # ifndef BROADCAST
307: sethostent(1); /* don't bother to close host file */
308: # endif BROADCAST
309: if (gethostname(local_name, sizeof local_name) < 0) {
310: leave(1, "Sorry, I have no name.");
311: /* NOTREACHED */
312: }
313: if ((hp = gethostbyname(local_name)) == NULL) {
314: leave(1, "Can't find myself.");
315: /* NOTREACHED */
316: }
317: local_address = * ((struct in_addr *) hp->h_addr);
318:
319: test.sin_family = SOCK_FAMILY;
320: test.sin_addr = local_address;
321: test.sin_port = htons(Test_port);
322: }
323:
324: # ifndef OLDIPC
325: test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0);
326: # else OLDIPC
327: test_socket = socket(SOCK_DGRAM, 0, 0, 0);
328: # endif OLCIPC
329: if (test_socket < 0) {
330: perror("socket");
331: leave(1, "socket system call failed");
332: /* NOTREACHED */
333: }
334:
335: msg = 1;
336: if (Query_driver && Sock_host != NULL) {
337: test.sin_family = SOCK_FAMILY;
338: test.sin_addr = Daemon.sin_addr;
339: test.sin_port = htons(Test_port);
340: # ifndef OLDIPC
341: (void) sendto(test_socket, (char *) &msg, sizeof msg, 0,
342: (struct sockaddr *) &test, DAEMON_SIZE);
343: # else OLDIPC
344: (void) send(test_socket, (struct sockaddr *) &test,
345: (char *) &msg, sizeof msg);
346: # endif OLDIPC
347: goto get_response;
348: }
349:
350: if (!initial) {
351: /* favor host of previous session by broadcasting to it first */
352: test.sin_addr = Daemon.sin_addr;
353: test.sin_port = htons(Test_port);
354: (void) sendto(test_socket, (char *) &msg, sizeof msg, 0,
355: (struct sockaddr *) &test, DAEMON_SIZE);
356: }
357:
358:
359: # ifdef BROADCAST
360: if (initial)
361: brdc = broadcast_vec(test_socket, &brdv);
362:
363: if (brdc <= 0) {
364: Daemon.sin_family = SOCK_FAMILY;
365: Daemon.sin_addr = local_address;
366: Daemon.sin_port = htons(Sock_port);
367: initial = FALSE;
368: return;
369: }
370:
371: if (setsockopt(test_socket, SOL_SOCKET, SO_BROADCAST,
372: (int) &msg, sizeof msg) < 0) {
373: perror("setsockopt broadcast");
374: leave(1, "setsockopt broadcast");
375: /* NOTREACHED */
376: }
377:
378: /* send broadcast packets on all interfaces */
379: for (i = 0; i < brdc; i++) {
380: bcopy(&brdv[i], &test, sizeof (SOCKET));
381: test.sin_port = htons(Test_port);
382: if (sendto(test_socket, (char *) &msg, sizeof msg, 0,
383: (struct sockaddr *) &test, DAEMON_SIZE) < 0) {
384: perror("sendto");
385: leave(1, "sendto");
386: /* NOTREACHED */
387: }
388: }
389: # else BROADCAST
390: /* loop thru all hosts on local net and send msg to them. */
391: sethostent(0); /* rewind host file */
392: while (hp = gethostent()) {
393: if (inet_netof(test.sin_addr)
394: == inet_netof(* ((struct in_addr *) hp->h_addr))) {
395: test.sin_addr = * ((struct in_addr *) hp->h_addr);
396: # ifndef OLDIPC
397: (void) sendto(test_socket, (char *) &msg, sizeof msg, 0,
398: (struct sockaddr *) &test, DAEMON_SIZE);
399: # else OLDIPC
400: (void) send(test_socket, (struct sockaddr *) &test,
401: (char *) &msg, sizeof msg);
402: # endif OLDIPC
403: }
404: }
405: # endif BROADCAST
406:
407: get_response:
408: namelen = DAEMON_SIZE;
409: oldsigalrm = signal(SIGALRM, sigalrm);
410: errno = 0;
411: (void) alarm(1);
412: # ifndef OLDIPC
413: if (recvfrom(test_socket, (char *) &msg, sizeof msg, 0,
414: (struct sockaddr *) &Daemon, &namelen) < 0)
415: # else OLDIPC
416: if (receive(test_socket, (struct sockaddr *) &Daemon, &msg,
417: sizeof msg) < 0)
418: # endif OLDIPC
419: {
420: if (errno != EINTR) {
421: perror("recvfrom");
422: leave(1, "recvfrom");
423: /* NOTREACHED */
424: }
425: (void) alarm(0);
426: (void) signal(SIGALRM, oldsigalrm);
427: Daemon.sin_family = SOCK_FAMILY;
428: Daemon.sin_port = htons(Sock_port);
429: Daemon.sin_addr = local_address;
430: if (!do_startup)
431: Daemon.sin_port = 0;
432: else
433: start_driver();
434: }
435: else {
436: (void) alarm(0);
437: (void) signal(SIGALRM, oldsigalrm);
438: Daemon.sin_port = htons(Sock_port);
439: }
440: (void) close(test_socket);
441: initial = FALSE;
442: }
443: # endif INTERNET
444:
445: start_driver()
446: {
447: register int procid;
448:
449: # ifdef MONITOR
450: if (Am_monitor) {
451: leave(1, "No one playing.");
452: /* NOTREACHED */
453: }
454: # endif MONITOR
455:
456: # ifdef INTERNET
457: if (Sock_host != NULL) {
458: sleep(3);
459: return 0;
460: }
461: # endif INTERNET
462:
463: mvcur(cur_row, cur_col, 23, 0);
464: cur_row = 23;
465: cur_col = 0;
466: put_str("Starting...");
467: fflush(stdout);
468: procid = vfork();
469: if (procid == -1) {
470: perror("fork");
471: leave(1, "fork failed.");
472: }
473: if (procid == 0) {
474: (void) signal(SIGINT, SIG_IGN);
475: (void) close(Socket);
476: execl(Driver, "HUNT", NULL);
477: /* only get here if exec failed */
478: kill(getppid(), SIGEMT); /* tell mom */
479: _exit(1);
480: }
481: mvcur(cur_row, cur_col, 23, 0);
482: cur_row = 23;
483: cur_col = 0;
484: put_str("Connecting...");
485: fflush(stdout);
486: return 0;
487: }
488:
489: /*
490: * bad_con:
491: * We had a bad connection. For the moment we assume that this
492: * means the game is full.
493: */
494: bad_con()
495: {
496: leave(1, "The game is full. Sorry.");
497: /* NOTREACHED */
498: }
499:
500: /*
501: * dumpit:
502: * Handle a core dump signal by not dumping core, just leaving,
503: * so we end up with a core dump from the driver
504: */
505: dumpit()
506: {
507: (void) kill(Master_pid, SIGQUIT);
508: (void) chdir("coredump");
509: abort();
510: }
511:
512: /*
513: * sigterm:
514: * Handle a terminate signal
515: */
516: sigterm()
517: {
518: leave(0, NULL);
519: /* NOTREACHED */
520: }
521:
522:
523: /*
524: * sigemt:
525: * Handle a emt signal - shouldn't happen on vaxes(?)
526: */
527: sigemt()
528: {
529: leave(1, "Unable to start driver. Try again.");
530: /* NOTREACHED */
531: }
532:
533: # ifdef INTERNET
534: /*
535: * sigalrm:
536: * Handle an alarm signal
537: */
538: sigalrm()
539: {
540: return;
541: }
542: # endif INTERNET
543:
544: /*
545: * rmnl:
546: * Remove a '\n' at the end of a string if there is one
547: */
548: rmnl(s)
549: char *s;
550: {
551: register char *cp;
552: char *rindex();
553:
554: cp = rindex(s, '\n');
555: if (cp != NULL)
556: *cp = '\0';
557: }
558:
559: /*
560: * intr:
561: * Handle a interrupt signal
562: */
563: intr()
564: {
565: register int ch;
566: register int explained;
567: register int y, x;
568:
569: (void) signal(SIGINT, SIG_IGN);
570: y = cur_row;
571: x = cur_col;
572: mvcur(cur_row, cur_col, 23, 0);
573: cur_row = 23;
574: cur_col = 0;
575: put_str("Really quit? ");
576: clear_eol();
577: fflush(stdout);
578: explained = FALSE;
579: for (;;) {
580: ch = getchar();
581: if (isupper(ch))
582: ch = tolower(ch);
583: if (ch == 'y') {
584: (void) write(Socket, "q", 1);
585: (void) close(Socket);
586: leave(0, NULL);
587: }
588: else if (ch == 'n') {
589: (void) signal(SIGINT, intr);
590: mvcur(cur_row, cur_col, y, x);
591: cur_row = y;
592: cur_col = x;
593: fflush(stdout);
594: return;
595: }
596: if (!explained) {
597: put_str("(Y or N) ");
598: fflush(stdout);
599: explained = TRUE;
600: }
601: (void) putchar(CTRL(G));
602: (void) fflush(stdout);
603: }
604: }
605:
606: /*
607: * leave:
608: * Leave the game somewhat gracefully, restoring all current
609: * tty stats.
610: */
611: leave(eval, mesg)
612: int eval;
613: char *mesg;
614: {
615: mvcur(cur_row, cur_col, 23, 0);
616: if (mesg == NULL)
617: clear_eol();
618: else {
619: put_str(mesg);
620: clear_eol();
621: putchar('\n');
622: fflush(stdout); /* flush in case VE changes pages */
623: }
624: resetty();
625: _puts(VE);
626: _puts(TE);
627: exit(eval);
628: }
629:
630: /*
631: * tstp:
632: * Handle stop and start signals
633: */
634: tstp()
635: {
636: static struct sgttyb tty;
637: int y, x;
638:
639: tty = _tty;
640: y = cur_row;
641: x = cur_col;
642: mvcur(cur_row, cur_col, 23, 0);
643: cur_row = 23;
644: cur_col = 0;
645: _puts(VE);
646: _puts(TE);
647: (void) fflush(stdout);
648: resetty();
649: (void) kill(getpid(), SIGSTOP);
650: (void) signal(SIGTSTP, tstp);
651: _tty = tty;
652: (void) stty(_tty_ch, &_tty);
653: _puts(TI);
654: _puts(VS);
655: cur_row = y;
656: cur_col = x;
657: _puts(tgoto(CM, cur_row, cur_col));
658: redraw_screen();
659: fflush(stdout);
660: }
661:
662: env_init()
663: {
664: register int i;
665: char *envp, *envname, *s, *index();
666:
667: for (i = 0; i < 256; i++)
668: map_key[i] = (char) i;
669:
670: envname = NULL;
671: if ((envp = getenv("HUNT")) != NULL) {
672: while ((s = index(envp, '=')) != NULL) {
673: if (strncmp(envp, "name=", s - envp + 1) == 0) {
674: envname = s + 1;
675: if ((s = index(envp, ',')) == NULL) {
676: *envp = '\0';
677: break;
678: }
679: *s = '\0';
680: envp = s + 1;
681: } /* must be last option */
682: else if (strncmp(envp, "mapkey=", s - envp + 1) == 0) {
683: for (s = s + 1; *s != '\0'; s += 2) {
684: map_key[(unsigned int) *s] = *(s + 1);
685: if (*(s + 1) == '\0') {
686: break;
687: }
688: }
689: *envp = '\0';
690: break;
691: } else {
692: *s = '\0';
693: printf("unknown option %s\n", envp);
694: if ((s = index(envp, ',')) == NULL) {
695: *envp = '\0';
696: break;
697: }
698: envp = s + 1;
699: }
700: }
701: if (*envp != '\0')
702: if (envname == NULL)
703: envname = envp;
704: else
705: printf("unknown option %s\n", envp);
706: }
707: if (envname != NULL) {
708: (void) strcpy(name, envname);
709: printf("Entering as '%s'\n", envname);
710: }
711: else if (name[0] == '\0') {
712: printf("Enter your code name: ");
713: if (fgets(name, sizeof name, stdin) == NULL)
714: exit(1);
715: }
716: rmnl(name);
717: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.