|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T h
Length: 19315 (0x4b73) Types: TextFile Names: »hunt.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Hunt/hunt.c«
/* * Hunt * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold * San Francisco, California * * Copyright (c) 1985 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ # include <errno.h> # include <curses.h> # include "hunt.h" # include <signal.h> # include <ctype.h> # include <sys/stat.h> # ifndef HPUX # include <sys/time.h> # else # include <time.h> # endif # ifdef TERMINFO # include <term.h> # define CM cursor_address # else /* * Some old versions of curses don't have these defined */ # ifndef cbreak # define cbreak() crmode() # endif # ifndef baudrate # define baudrate() (_tty.sg_ospeed) # endif # endif /* * these numbers are contrived to allow 3 users on a VAX 11/750 * i.e. an spin loop of 10000 iterations in 30 milliseconds. */ # define LOOP_COUNT 10000 # define FUDGE_FACTOR 30 FLAG Last_player = FALSE; # ifdef MONITOR FLAG Am_monitor = FALSE; # endif MONITOR char Buf[BUFSIZ]; int Socket; # ifdef INTERNET char *Sock_host; char *use_port; FLAG Query_driver = FALSE; char *Send_message = NULL; # endif INTERNET SOCKET Daemon; # ifdef INTERNET # define DAEMON_SIZE (sizeof Daemon) # else INTERNET # define DAEMON_SIZE (sizeof Daemon - 1) # endif INTERNET char map_key[256]; /* what to map keys to */ FLAG no_beep; static char name[NAMELEN]; static char team = ' '; extern int cur_row, cur_col, _putchar(); extern char *tgoto(); /* * main: * Main program for local process */ main(ac, av) int ac; char **av; { char *term; int c; extern int errno; extern int Otto_mode; extern int optind; extern char *optarg; long enter_status; int intr(), sigterm(), sigemt(), tstp(); long env_init(), quit(); enter_status = env_init((long) Q_CLOAK); while ((c = getopt(ac, av, "bcfh:l:mn:op:qst:w:")) != EOF) { switch (c) { case 'l': /* rsh compatibility */ case 'n': (void) strncpy(name, optarg, NAMELEN); break; case 't': team = *optarg; if (!isdigit(team)) { fprintf(stderr, "Team names must be numeric\n"); team = ' '; } break; case 'o': # ifndef OTTO fputs("The -o flag is reserved for future use.\n", stderr); goto usage; # else OTTO Otto_mode = TRUE; break; # endif OTTO # ifdef MONITOR case 'm': Am_monitor = TRUE; break; # endif MONITOR # ifdef INTERNET case 'q': /* query whether hunt is running */ Query_driver = TRUE; break; case 'w': Send_message = optarg; break; case 'h': Sock_host = optarg; break; case 'p': use_port = optarg; Test_port = atoi(use_port); break; # endif INTERNET case 'c': enter_status = Q_CLOAK; break; # ifdef FLY case 'f': enter_status = Q_FLY; break; # endif FLY case 's': enter_status = Q_SCAN; break; case 'b': no_beep = !no_beep; break; default: usage: # ifdef INTERNET # ifdef MONITOR # define USAGE "usage:\thunt [-qmcsf] [-n name] [-t team]\n\t[-p port] [-w message] [host]\n" # else MONITOR # define USAGE "usage:\thunt [-qcsf] [-n name] [-t team]\n\t[-p port] [-w message] [host]\n" # endif MONITOR # else INTERNET # ifdef MONITOR # define USAGE "usage:\thunt [-mcsf] [-n name] [-t team]\n" # else MONITOR # define USAGE "usage:\thunt [-csf] [-n name] [-t team]\n" # endif MONITOR # endif INTERNET fputs(USAGE, stderr); # undef USAGE exit(1); } } # ifdef INTERNET if (optind + 1 < ac) goto usage; else if (optind + 1 == ac) Sock_host = av[ac - 1]; # else INTERNET if (optind > ac) goto usage; # endif INTERNET # ifdef INTERNET if (Query_driver) { find_driver(FALSE); if (Daemon.sin_port != 0) { struct hostent *hp; int num_players; hp = gethostbyaddr((char *) &Daemon.sin_addr, sizeof Daemon.sin_addr, AF_INET); num_players = ntohs(Daemon.sin_port); printf("%d player%s hunting on %s!\n", num_players, (num_players == 1) ? "" : "s", hp != NULL ? hp->h_name : inet_ntoa(Daemon.sin_addr)); } exit(Daemon.sin_port); } # endif INTERNET # ifdef OTTO if (Otto_mode) (void) strncpy(name, "otto", NAMELEN); else # endif OTTO fill_in_blanks(); (void) fflush(stdout); if (!isatty(0) || (term = getenv("TERM")) == NULL) { fprintf(stderr, "no terminal type\n"); exit(1); } # ifdef TERMINFO initscr(); noecho(); cbreak(); # else _tty_ch = 0; gettmode(); setterm(term); noecho(); cbreak(); _puts(TI); _puts(VS); # endif clear_the_screen(); (void) signal(SIGINT, intr); (void) signal(SIGTERM, sigterm); (void) signal(SIGEMT, sigemt); (void) signal(SIGPIPE, SIG_IGN); #ifdef SIGTSTP (void) signal(SIGTSTP, tstp); #endif for (;;) { { register int loop; struct timeval start, stop; int elapsed_time; (void) gettimeofday(&start, (struct timezone *) NULL); for (loop = 0; loop < LOOP_COUNT; loop++) continue; (void) gettimeofday(&stop, (struct timezone *) NULL); elapsed_time = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec; if (elapsed_time > LOOP_COUNT * FUDGE_FACTOR) leave(1, "Response time too slow"); } # ifdef INTERNET find_driver(TRUE); if (Daemon.sin_port == 0) leave(1, "Game not found, try again"); do { int option; Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0); if (Socket < 0) { perror("socket"); exit(1); } option = 1; if (setsockopt(Socket, SOL_SOCKET, SO_USELOOPBACK, &option, sizeof option) < 0) perror("setsockopt loopback"); errno = 0; if (connect(Socket, (struct sockaddr *) &Daemon, DAEMON_SIZE) < 0) { if (errno != ECONNREFUSED) { perror("connect"); leave(1, "connect"); } } else break; sleep(1); } while (close(Socket) == 0); # else INTERNET /* * set up a socket */ if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0) { perror("socket"); exit(1); } /* * attempt to connect the socket to a name; if it fails that * usually means that the driver isn't running, so we start * up the driver. */ Daemon.sun_family = SOCK_FAMILY; (void) strcpy(Daemon.sun_path, Sock_name); if (connect(Socket, &Daemon, DAEMON_SIZE) < 0) { if (errno != ENOENT) { perror("connect"); leave(1, "connect2"); } start_driver(); do { (void) close(Socket); if ((Socket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0) { perror("socket"); exit(1); } sleep(2); } while (connect(Socket, &Daemon, DAEMON_SIZE) < 0); } # endif INTERNET do_connect(name, team, enter_status); # ifdef INTERNET if (Send_message != NULL) { do_message(); if (enter_status == Q_MESSAGE) break; Send_message = NULL; continue; } # endif playit(); if ((enter_status = quit(enter_status)) == Q_QUIT) break; } leave(0, (char *) NULL); /* NOTREACHED */ } # ifdef INTERNET # ifdef BROADCAST broadcast_vec(s, vector) int s; /* socket */ struct sockaddr **vector; { char if_buf[BUFSIZ]; struct ifconf ifc; struct ifreq *ifr; unsigned int n; int vec_cnt; *vector = NULL; ifc.ifc_len = sizeof if_buf; ifc.ifc_buf = if_buf; if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0) return 0; vec_cnt = 0; n = ifc.ifc_len / sizeof (struct ifreq); *vector = (struct sockaddr *) malloc(n * sizeof (struct sockaddr)); for (ifr = ifc.ifc_req; n != 0; n--, ifr++) if (ioctl(s, SIOCGIFBRDADDR, ifr) >= 0) bcopy(&ifr->ifr_addr, &(*vector)[vec_cnt++], sizeof (struct sockaddr)); return vec_cnt; } # endif BROADCAST find_driver(do_startup) FLAG do_startup; { int option; short msg; short port_num; static SOCKET test; int test_socket; int namelen; char local_name[256]; static initial = TRUE; static struct in_addr local_address; register struct hostent *hp; int (*oldsigalrm)(), sigalrm(); extern int errno; # ifdef BROADCAST static int brdc; static SOCKET *brdv; int i; # endif BROADCAST if (Sock_host != NULL) { if (!initial) return; /* Daemon address already valid */ initial = FALSE; if ((hp = gethostbyname(Sock_host)) == NULL) { leave(1, "Unknown host"); /* NOTREACHED */ } Daemon.sin_family = SOCK_FAMILY; Daemon.sin_addr = *((struct in_addr *) hp->h_addr); test.sin_family = SOCK_FAMILY; test.sin_addr = Daemon.sin_addr; test.sin_port = htons(Test_port); } if (initial) { /* do one time initialization */ # ifndef BROADCAST sethostent(1); /* don't bother to close host file */ # endif BROADCAST if (gethostname(local_name, sizeof local_name) < 0) { leave(1, "Sorry, I have no name."); /* NOTREACHED */ } if ((hp = gethostbyname(local_name)) == NULL) { leave(1, "Can't find myself."); /* NOTREACHED */ } local_address = * ((struct in_addr *) hp->h_addr); test.sin_family = SOCK_FAMILY; test.sin_addr = local_address; test.sin_port = htons(Test_port); } test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0); if (test_socket < 0) { perror("socket"); leave(1, "socket system call failed"); /* NOTREACHED */ } if (Sock_host != NULL) { test_one_host: test.sin_family = SOCK_FAMILY; test.sin_addr = Daemon.sin_addr; test.sin_port = htons(Test_port); if (Am_monitor) msg = htons(C_MONITOR); else if (Query_driver) msg = htons(C_MESSAGE); else msg = htons(C_PLAYER); (void) sendto(test_socket, (char *) &msg, sizeof msg, 0, (struct sockaddr *) &test, DAEMON_SIZE); goto get_response; } if (!initial) { /* favor host of previous session by broadcasting to it first */ test.sin_addr = Daemon.sin_addr; test.sin_port = htons(Test_port); msg = htons(0); /* Must be playing! */ (void) sendto(test_socket, (char *) &msg, sizeof msg, 0, (struct sockaddr *) &test, DAEMON_SIZE); } # ifdef BROADCAST if (initial) brdc = broadcast_vec(test_socket, &brdv); if (brdc <= 0) { Daemon.sin_family = SOCK_FAMILY; Daemon.sin_addr = local_address; initial = FALSE; goto test_one_host; } # ifdef SO_BROADCAST option = 1; if (setsockopt(test_socket, SOL_SOCKET, SO_BROADCAST, (int) &option, sizeof option) < 0) { perror("setsockopt broadcast"); leave(1, "setsockopt broadcast"); /* NOTREACHED */ } # endif /* send broadcast packets on all interfaces */ if (Am_monitor) msg = htons(C_MONITOR); else if (Query_driver) msg = htons(C_MESSAGE); else msg = htons(C_PLAYER); for (i = 0; i < brdc; i++) { bcopy(&brdv[i], &test, sizeof (SOCKET)); test.sin_port = htons(Test_port); if (sendto(test_socket, (char *) &msg, sizeof msg, 0, (struct sockaddr *) &test, DAEMON_SIZE) < 0) { perror("sendto"); leave(1, "sendto"); /* NOTREACHED */ } } # else BROADCAST /* loop thru all hosts on local net and send msg to them. */ if (Am_monitor) msg = htons(C_MONITOR); else if (Query_driver) msg = htons(C_MESSAGE); else msg = htons(C_PLAYER); sethostent(0); /* rewind host file */ while (hp = gethostent()) { if (inet_netof(test.sin_addr) == inet_netof(* ((struct in_addr *) hp->h_addr))) { test.sin_addr = * ((struct in_addr *) hp->h_addr); (void) sendto(test_socket, (char *) &msg, sizeof msg, 0, (struct sockaddr *) &test, DAEMON_SIZE); } } # endif BROADCAST get_response: namelen = DAEMON_SIZE; oldsigalrm = signal(SIGALRM, sigalrm); errno = 0; (void) alarm(1); if (recvfrom(test_socket, (char *) &port_num, sizeof port_num, 0, (struct sockaddr *) &Daemon, &namelen) < 0) { if (errno != EINTR) { perror("recvfrom"); leave(1, "recvfrom"); /* NOTREACHED */ } (void) alarm(0); (void) signal(SIGALRM, oldsigalrm); Daemon.sin_family = SOCK_FAMILY; Daemon.sin_addr = local_address; if (!do_startup) Daemon.sin_port = 0; else { start_driver(); sleep(2); find_driver(FALSE); /* try again */ } } else { (void) alarm(0); (void) signal(SIGALRM, oldsigalrm); /* * Note that we do *not* convert from network to host * order since the port number *should* be in network order */ Daemon.sin_port = port_num; } (void) close(test_socket); initial = FALSE; } # endif INTERNET start_driver() { register int procid; # ifdef MONITOR if (Am_monitor) { leave(1, "No one playing."); /* NOTREACHED */ } # endif MONITOR # ifdef INTERNET if (Sock_host != NULL) { sleep(3); return 0; } # endif INTERNET mvcur(cur_row, cur_col, 23, 0); cur_row = 23; cur_col = 0; put_str("Starting..."); fflush(stdout); # ifndef BSD procid = fork(); # else procid = vfork(); # endif if (procid == -1) { perror("fork"); leave(1, "fork failed."); } if (procid == 0) { (void) signal(SIGINT, SIG_IGN); # ifndef INTERNET (void) close(Socket); # endif if (use_port == NULL) execl(Driver, "HUNT", (char *) NULL); else execl(Driver, "HUNT", "-p", use_port, (char *) NULL); /* only get here if exec failed */ kill(getppid(), SIGEMT); /* tell mom */ _exit(1); } mvcur(cur_row, cur_col, 23, 0); cur_row = 23; cur_col = 0; put_str("Connecting..."); fflush(stdout); return 0; } /* * bad_con: * We had a bad connection. For the moment we assume that this * means the game is full. */ bad_con() { leave(1, "The game is full. Sorry."); /* NOTREACHED */ } /* * bad_ver: * version number mismatch. */ bad_ver() { leave(1, "Version number mismatch. No go."); /* NOTREACHED */ } /* * sigterm: * Handle a terminate signal */ sigterm() { leave(0, (char *) NULL); /* NOTREACHED */ } /* * sigemt: * Handle a emt signal - shouldn't happen on vaxes(?) */ sigemt() { leave(1, "Unable to start driver. Try again."); /* NOTREACHED */ } # ifdef INTERNET /* * sigalrm: * Handle an alarm signal */ sigalrm() { return; } # endif INTERNET /* * rmnl: * Remove a '\n' at the end of a string if there is one */ rmnl(s) char *s; { register char *cp; char *rindex(); cp = rindex(s, '\n'); if (cp != NULL) *cp = '\0'; } /* * intr: * Handle a interrupt signal */ intr() { register int ch; register int explained; register int y, x; (void) signal(SIGINT, SIG_IGN); y = cur_row; x = cur_col; mvcur(cur_row, cur_col, 23, 0); cur_row = 23; cur_col = 0; put_str("Really quit? "); clear_eol(); fflush(stdout); explained = FALSE; for (;;) { ch = getchar(); if (isupper(ch)) ch = tolower(ch); if (ch == 'y') { (void) write(Socket, "q", 1); (void) close(Socket); leave(0, (char *) NULL); } else if (ch == 'n') { (void) signal(SIGINT, intr); mvcur(cur_row, cur_col, y, x); cur_row = y; cur_col = x; fflush(stdout); return; } if (!explained) { put_str("(Yes or No) "); fflush(stdout); explained = TRUE; } (void) putchar(CTRL(G)); (void) fflush(stdout); } } /* * leave: * Leave the game somewhat gracefully, restoring all current * tty stats. */ leave(eval, mesg) int eval; char *mesg; { if (baudrate() != 0) { mvcur(cur_row, cur_col, 23, 0); fflush(stdout); /* flush in case VE changes pages */ # ifdef TERMINFO putp(cursor_normal); putp(exit_ca_mode); reset_shell_mode(); # else resetty(); _puts(VE); _puts(TE); # endif } if (mesg != NULL) puts(mesg); exit(eval); } #ifdef SIGTSTP /* * tstp: * Handle stop and start signals */ tstp() { # ifndef TERMINFO static struct sgttyb tty; # endif int y, x; y = cur_row; x = cur_col; mvcur(cur_row, cur_col, 23, 0); cur_row = 23; cur_col = 0; # ifdef TERMINFO putp(cursor_normal); putp(exit_ca_mode); reset_shell_mode(); # else tty = _tty; _puts(VE); _puts(TE); (void) fflush(stdout); resetty(); # endif (void) kill(getpid(), SIGSTOP); (void) signal(SIGTSTP, tstp); # ifdef TERMINFO reset_prog_mode(); putp(enter_ca_mode); putp(cursor_visible); # else _tty = tty; (void) stty(_tty_ch, &_tty); _puts(TI); _puts(VS); # endif cur_row = y; cur_col = x; # ifdef TERMINFO putp(tgoto(CM, cur_row, cur_col)); # else _puts(tgoto(CM, cur_row, cur_col)); # endif redraw_screen(); fflush(stdout); } #endif long env_init(enter_status) long enter_status; { register int i; char *envp, *envname, *s, *index(), *strpbrk(); for (i = 0; i < 256; i++) map_key[i] = (char) i; envname = NULL; if ((envp = getenv("HUNT")) != NULL) { while ((s = strpbrk(envp, "=,")) != NULL) { if (strncmp(envp, "cloak,", s - envp + 1) == 0) { enter_status = Q_CLOAK; envp = s + 1; } else if (strncmp(envp, "scan,", s - envp + 1) == 0) { enter_status = Q_SCAN; envp = s + 1; } else if (strncmp(envp, "fly,", s - envp + 1) == 0) { enter_status = Q_FLY; envp = s + 1; } else if (strncmp(envp, "nobeep,", s - envp + 1) == 0) { no_beep = TRUE; envp = s + 1; } else if (strncmp(envp, "name=", s - envp + 1) == 0) { envname = s + 1; if ((s = index(envp, ',')) == NULL) { *envp = '\0'; strncpy(name, envname, NAMELEN); break; } *s = '\0'; strncpy(name, envname, NAMELEN); envp = s + 1; } else if (strncmp(envp, "port=", s - envp + 1) == 0) { use_port = s + 1; Test_port = atoi(use_port); if ((s = index(envp, ',')) == NULL) { *envp = '\0'; break; } *s = '\0'; envp = s + 1; } else if (strncmp(envp, "host=", s - envp + 1) == 0) { Sock_host = s + 1; if ((s = index(envp, ',')) == NULL) { *envp = '\0'; break; } *s = '\0'; envp = s + 1; } # ifdef INTERNET else if (strncmp(envp, "message=", s - envp + 1) == 0) { Send_message = s + 1; if ((s = index(envp, ',')) == NULL) { *envp = '\0'; break; } *s = '\0'; envp = s + 1; } # endif else if (strncmp(envp, "team=", s - envp + 1) == 0) { team = *(s + 1); if (!isdigit(team)) team = ' '; if ((s = index(envp, ',')) == NULL) { *envp = '\0'; break; } *s = '\0'; envp = s + 1; } /* must be last option */ else if (strncmp(envp, "mapkey=", s - envp + 1) == 0) { for (s = s + 1; *s != '\0'; s += 2) { map_key[(unsigned int) *s] = *(s + 1); if (*(s + 1) == '\0') { break; } } *envp = '\0'; break; } else { *s = '\0'; printf("unknown option %s\n", envp); if ((s = index(envp, ',')) == NULL) { *envp = '\0'; break; } envp = s + 1; } } if (*envp != '\0') if (envname == NULL) strncpy(name, envp, NAMELEN); else printf("unknown option %s\n", envp); } return enter_status; } fill_in_blanks() { register int i; register char *cp; again: if (name[0] != '\0') { printf("Entering as '%s'", name); if (team != ' ') printf(" on team %c.\n", team); else putchar('\n'); } else { printf("Enter your code name: "); if (fgets(name, NAMELEN, stdin) == NULL) exit(1); } rmnl(name); if (name[0] == '\0') { name[0] = '\0'; printf("You have to have a code name!\n"); goto again; } for (cp = name; *cp != '\0'; cp++) if (!isprint(*cp)) { name[0] = '\0'; printf("Illegal character in your code name.\n"); goto again; } if (team == ' ') { printf("Enter your team (0-9 or nothing): "); i = getchar(); if (isdigit(i)) team = i; while (i != '\n' && i != EOF) i = getchar(); } } #if defined(BSD) #if BSD < 43 char * strpbrk(s, brk) register char *s, *brk; { register char *p; register c; while (c = *s) { for (p = brk; *p; p++) if (c == *p) return (s); s++; } return (0); } #endif #endif