1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33: #include <sys/cdefs.h>
34: #ifndef lint
35: __RCSID("$NetBSD: hunt.c,v 1.23 2004/11/05 21:30:32 dsl Exp $");
36: #endif
37:
38: # include <sys/param.h>
39: # include <sys/stat.h>
40: # include <sys/time.h>
41: # include <sys/poll.h>
42: # include <ctype.h>
43: # include <err.h>
44: # include <errno.h>
45: # include <curses.h>
46: # include <signal.h>
47: # include <stdlib.h>
48: # include <string.h>
49: # if !defined(USE_CURSES) && defined(BSD_RELEASE) && BSD_RELEASE >= 44
50: # include <termios.h>
51: static struct termios saved_tty;
52: # endif
53: # include <unistd.h>
54: # include <ifaddrs.h>
55:
56: # include "hunt.h"
57:
58:
59:
60:
61: # if !defined(cbreak) && (!defined(BSD_RELEASE) || BSD_RELEASE < 44)
62: # define cbreak() crmode()
63: # endif
64:
65: # if !defined(USE_CURSES) || !defined(TERMINFO)
66: # define beep() (void) putchar(CTRL('G'))
67: # endif
68: # if !defined(USE_CURSES)
69: # undef refresh
70: # define refresh() (void) fflush(stdout);
71: # endif
72: # ifdef USE_CURSES
73: # define clear_eol() clrtoeol()
74: # define put_ch addch
75: # define put_str addstr
76: # endif
77:
78: #ifndef MAXHOSTNAMELEN
79: #define MAXHOSTNAMELEN 256
80: #endif
81:
82: FLAG Last_player = FALSE;
83: # ifdef MONITOR
84: FLAG Am_monitor = FALSE;
85: # endif
86:
87: char Buf[BUFSIZ];
88:
89: int Socket;
90: # ifdef INTERNET
91: char *Sock_host;
92: char *use_port;
93: FLAG Query_driver = FALSE;
94: char *Send_message = NULL;
95: FLAG Show_scores = FALSE;
96: # endif
97:
98: SOCKET Daemon;
99: # ifdef INTERNET
100: # define DAEMON_SIZE (sizeof Daemon)
101: # else
102: # define DAEMON_SIZE (sizeof Daemon - 1)
103: # endif
104:
105: char map_key[256];
106: FLAG no_beep;
107:
108: static char name[NAMELEN];
109: static char team = ' ';
110:
111: static int in_visual;
112:
113: extern int cur_row, cur_col;
114:
115: void dump_scores(SOCKET);
116: long env_init(long);
117: void fill_in_blanks(void);
118: void leave(int, const char *) __attribute__((__noreturn__));
119: void leavex(int, const char *) __attribute__((__noreturn__));
120: void fincurs(void);
121: int main(int, char *[]);
122: # ifdef INTERNET
123: SOCKET *list_drivers(void);
124: # endif
125:
126: extern int Otto_mode;
127:
128:
129:
130:
131: int
132: main(ac, av)
133: int ac;
134: char **av;
135: {
136: char *term;
137: int c;
138: long enter_status;
139:
140:
141: setregid(getgid(), getgid());
142:
143: enter_status = env_init((long) Q_CLOAK);
144: while ((c = getopt(ac, av, "Sbcfh:l:mn:op:qst:w:")) != -1) {
145: switch (c) {
146: case 'l':
147: case 'n':
148: (void) strncpy(name, optarg, NAMELEN);
149: break;
150: case 't':
151: team = *optarg;
152: if (!isdigit((unsigned char)team)) {
153: warnx("Team names must be numeric");
154: team = ' ';
155: }
156: break;
157: case 'o':
158: # ifndef OTTO
159: warnx("The -o flag is reserved for future use.");
160: goto usage;
161: # else
162: Otto_mode = TRUE;
163: break;
164: # endif
165: case 'm':
166: # ifdef MONITOR
167: Am_monitor = TRUE;
168: # else
169: warnx("The monitor was not compiled in.");
170: # endif
171: break;
172: # ifdef INTERNET
173: case 'S':
174: Show_scores = TRUE;
175: break;
176: case 'q':
177: Query_driver = TRUE;
178: break;
179: case 'w':
180: Send_message = optarg;
181: break;
182: case 'h':
183: Sock_host = optarg;
184: break;
185: case 'p':
186: use_port = optarg;
187: Test_port = atoi(use_port);
188: break;
189: # else
190: case 'S':
191: case 'q':
192: case 'w':
193: case 'h':
194: case 'p':
195: wanrx("Need TCP/IP for S, q, w, h, and p options.");
196: break;
197: # endif
198: case 'c':
199: enter_status = Q_CLOAK;
200: break;
201: case 'f':
202: # ifdef FLY
203: enter_status = Q_FLY;
204: # else
205: warnx("The flying code was not compiled in.");
206: # endif
207: break;
208: case 's':
209: enter_status = Q_SCAN;
210: break;
211: case 'b':
212: no_beep = !no_beep;
213: break;
214: default:
215: usage:
216: fputs(
217: "usage:\thunt [-qmcsfS] [-n name] [-t team] [-p port] [-w message] [host]\n",
218: stderr);
219: exit(1);
220: }
221: }
222: # ifdef INTERNET
223: if (optind + 1 < ac)
224: goto usage;
225: else if (optind + 1 == ac)
226: Sock_host = av[ac - 1];
227: # else
228: if (optind > ac)
229: goto usage;
230: # endif
231:
232: # ifdef INTERNET
233: if (Show_scores) {
234: SOCKET *hosts;
235:
236: for (hosts = list_drivers(); hosts->sin_port != 0; hosts += 1)
237: dump_scores(*hosts);
238: exit(0);
239: }
240: if (Query_driver) {
241: SOCKET *hosts;
242:
243: for (hosts = list_drivers(); hosts->sin_port != 0; hosts += 1) {
244: struct hostent *hp;
245: int num_players;
246:
247: hp = gethostbyaddr((char *) &hosts->sin_addr,
248: sizeof hosts->sin_addr, AF_INET);
249: num_players = ntohs(hosts->sin_port);
250: printf("%d player%s hunting on %s!\n",
251: num_players, (num_players == 1) ? "" : "s",
252: hp != NULL ? hp->h_name :
253: inet_ntoa(hosts->sin_addr));
254: }
255: exit(0);
256: }
257: # endif
258: # ifdef OTTO
259: if (Otto_mode)
260: (void) strncpy(name, "otto", NAMELEN);
261: else
262: # endif
263: fill_in_blanks();
264:
265: (void) fflush(stdout);
266: if (!isatty(0) || (term = getenv("TERM")) == NULL)
267: errx(1, "no terminal type");
268: # ifdef USE_CURSES
269: initscr();
270: (void) noecho();
271: (void) cbreak();
272: # else
273: # if !defined(BSD_RELEASE) || BSD_RELEASE < 44
274: _tty_ch = 0;
275: # endif
276: gettmode();
277: (void) setterm(term);
278: (void) noecho();
279: (void) cbreak();
280: # if defined(BSD_RELEASE) && BSD_RELEASE >= 44
281: tcgetattr(0, &saved_tty);
282: # endif
283: _puts(TI);
284: _puts(VS);
285: # endif
286: in_visual = TRUE;
287: if (LINES < SCREEN_HEIGHT || COLS < SCREEN_WIDTH)
288: leavex(1, "Need a larger window");
289: clear_the_screen();
290: (void) signal(SIGINT, intr);
291: (void) signal(SIGTERM, sigterm);
292: (void) signal(SIGUSR1, sigusr1);
293: (void) signal(SIGPIPE, SIG_IGN);
294: #if !defined(USE_CURSES) && defined(SIGTSTP)
295: (void) signal(SIGTSTP, tstp);
296: #endif
297:
298: for (;;) {
299: # ifdef INTERNET
300: find_driver(TRUE);
301:
302: if (Daemon.sin_port == 0)
303: leavex(1, "Game not found, try again");
304:
305: jump_in:
306: do {
307: int option;
308:
309: Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0);
310: if (Socket < 0)
311: err(1, "socket");
312: option = 1;
313: #ifdef SO_USELOOPBACK
314: if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK,
315: &option, sizeof option) < 0)
316: warn("setsockopt loopback");
317: #endif
318: errno = 0;
319: if (connect(Socket, (struct sockaddr *) &Daemon,
320: DAEMON_SIZE) < 0) {
321: if (errno != ECONNREFUSED) {
322: leave(1, "connect");
323: }
324: }
325: else
326: break;
327: sleep(1);
328: } while (close(Socket) == 0);
329: # else
330:
331:
332:
333:
334: if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0)
335: err(1, "socket");
336:
337:
338:
339:
340:
341:
342:
343: Daemon.sun_family = SOCK_FAMILY;
344: (void) strcpy(Daemon.sun_path, Sock_name);
345: if (connect(Socket, &Daemon, DAEMON_SIZE) < 0) {
346: if (errno != ENOENT) {
347: leavex(1, "connect2");
348: }
349: start_driver();
350:
351: do {
352: (void) close(Socket);
353: if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM,
354: 0)) < 0)
355: err(1, "socket");
356: sleep(2);
357: } while (connect(Socket, &Daemon, DAEMON_SIZE) < 0);
358: }
359: # endif
360:
361: do_connect(name, team, enter_status);
362: # ifdef INTERNET
363: if (Send_message != NULL) {
364: do_message();
365: if (enter_status == Q_MESSAGE)
366: break;
367: Send_message = NULL;
368:
369: goto jump_in;
370: }
371: # endif
372: playit();
373: if ((enter_status = quit(enter_status)) == Q_QUIT)
374: break;
375: }
376: leavex(0, (char *) NULL);
377:
378: return(0);
379: }
380:
381: # ifdef INTERNET
382: # ifdef BROADCAST
383: int
384: broadcast_vec(s, vector)
385: int s;
386: struct sockaddr **vector;
387: {
388: int vec_cnt;
389: struct ifaddrs *ifp, *ip;
390:
391: *vector = NULL;
392: if (getifaddrs(&ifp) < 0)
393: return 0;
394:
395: vec_cnt = 0;
396: for (ip = ifp; ip; ip = ip->ifa_next)
397: if ((ip->ifa_addr->sa_family == AF_INET) &&
398: (ip->ifa_flags & IFF_BROADCAST))
399: vec_cnt++;
400:
401: *vector = (struct sockaddr *)
402: malloc(vec_cnt * sizeof(struct sockaddr_in));
403: if (*vector == NULL)
404: leave(1, "Out of memory!");
405:
406: vec_cnt = 0;
407: for (ip = ifp; ip; ip = ip->ifa_next)
408: if ((ip->ifa_addr->sa_family == AF_INET) &&
409: (ip->ifa_flags & IFF_BROADCAST))
410: memcpy(&(*vector)[vec_cnt++], ip->ifa_broadaddr,
411: sizeof(struct sockaddr_in));
412:
413: freeifaddrs(ifp);
414: return vec_cnt;
415: }
416: # endif
417:
418: SOCKET *
419: list_drivers()
420: {
421: int option;
422: u_short msg;
423: u_short port_num;
424: static SOCKET test;
425: int test_socket;
426: int namelen;
427: char local_name[MAXHOSTNAMELEN + 1];
428: static int initial = TRUE;
429: static struct in_addr local_address;
430: struct hostent *hp;
431: # ifdef BROADCAST
432: static int brdc;
433: static SOCKET *brdv;
434: # else
435: u_long local_net;
436: # endif
437: int i;
438: static SOCKET *listv;
439: static unsigned int listmax;
440: unsigned int listc;
441: struct pollfd set[1];
442:
443: if (initial) {
444: # ifndef BROADCAST
445: sethostent(1);
446: # endif
447: if (gethostname(local_name, sizeof local_name) < 0) {
448: leavex(1, "Sorry, I have no name.");
449:
450: }
451: local_name[sizeof(local_name) - 1] = '\0';
452: if ((hp = gethostbyname(local_name)) == NULL) {
453: leavex(1, "Can't find myself.");
454:
455: }
456: local_address = * ((struct in_addr *) hp->h_addr);
457:
458: listmax = 20;
459: listv = (SOCKET *) malloc(listmax * sizeof (SOCKET));
460: if (listv == NULL)
461: leave(1, "Out of memory!");
462: } else if (Sock_host != NULL)
463: return listv;
464:
465: test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0);
466: if (test_socket < 0) {
467: leave(1, "socket system call failed");
468:
469: }
470: test.sin_family = SOCK_FAMILY;
471: test.sin_port = htons(Test_port);
472: listc = 0;
473:
474: if (Sock_host != NULL) {
475: if ((hp = gethostbyname(Sock_host)) == NULL) {
476: leavex(1, "Unknown host");
477:
478: }
479: test.sin_addr = *((struct in_addr *) hp->h_addr);
480: goto test_one_host;
481: }
482:
483: if (!initial) {
484:
485: test.sin_addr = Daemon.sin_addr;
486: msg = htons(C_PLAYER);
487: (void) sendto(test_socket, (char *) &msg, sizeof msg, 0,
488: (struct sockaddr *) &test, DAEMON_SIZE);
489: }
490:
491: # ifdef BROADCAST
492: if (initial)
493: brdc = broadcast_vec(test_socket, (void *) &brdv);
494:
495: # ifdef SO_BROADCAST
496:
497: option = 1;
498: if (setsockopt(test_socket, SOL_SOCKET, SO_BROADCAST,
499: &option, sizeof option) < 0) {
500: leave(1, "setsockopt broadcast");
501:
502: }
503: # endif
504:
505:
506: msg = htons(C_TESTMSG());
507: for (i = 0; i < brdc; i++) {
508: test.sin_addr = brdv[i].sin_addr;
509: if (sendto(test_socket, (char *) &msg, sizeof msg, 0,
510: (struct sockaddr *) &test, DAEMON_SIZE) < 0) {
511: leave(1, "sendto");
512:
513: }
514: }
515: test.sin_addr = local_address;
516: if (sendto(test_socket, (char *) &msg, sizeof msg, 0,
517: (struct sockaddr *) &test, DAEMON_SIZE) < 0) {
518: leave(1, "sendto");
519:
520: }
521: # else
522:
523: msg = htons(C_TESTMSG());
524: local_net = inet_netof(local_address);
525: sethostent(0);
526: while (hp = gethostent()) {
527: if (local_net == inet_netof(* ((struct in_addr *) hp->h_addr))){
528: test.sin_addr = * ((struct in_addr *) hp->h_addr);
529: (void) sendto(test_socket, (char *) &msg, sizeof msg, 0,