📄 hunt.c
字号:
/* * Hunt * Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold * San Francisco, California */# include <errno.h># if !defined(USE_CURSES) && defined(BSD_RELEASE) && BSD_RELEASE >= 44# include <termios.h>static struct termios saved_tty;# endif# include <curses.h># include <string.h># include "hunt.h"# include <signal.h># include <ctype.h># include <sys/stat.h># include <sys/time.h>/* * Some old versions of curses don't have these defined */# if !defined(cbreak) && (!defined(BSD_RELEASE) || BSD_RELEASE < 44)# define cbreak() crmode()# endif# if !defined(USE_CURSES) || !defined(TERMINFO)# define beep() (void) putchar(CTRL('G'))# endif# if !defined(USE_CURSES)# undef refresh# define refresh() (void) fflush(stdout);# endif# ifdef USE_CURSES# define clear_eol() clrtoeol()# define put_ch addch# define put_str addstr# endif#if !defined(BSD_RELEASE) || BSD_RELEASE < 44extern int _putchar();#endifFLAG Last_player = FALSE;# ifdef MONITORFLAG Am_monitor = FALSE;# endifchar Buf[BUFSIZ];int Socket;# ifdef INTERNETchar *Sock_host;char *use_port;FLAG Query_driver = FALSE;char *Send_message = NULL;FLAG Show_scores = FALSE;# endifSOCKET Daemon;# ifdef INTERNET# define DAEMON_SIZE (sizeof Daemon)# else# define DAEMON_SIZE (sizeof Daemon - 1)# endifchar map_key[256]; /* what to map keys to */FLAG no_beep;static char name[NAMELEN];static char team = ' ';static int in_visual;extern int cur_row, cur_col;extern char *tgoto();# ifdef INTERNETextern SOCKET *list_drivers();# endif/* * 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; SIGNAL_TYPE intr(), sigterm(), sigemt(), tstp(); long env_init(), quit(); enter_status = env_init((long) Q_CLOAK); while ((c = getopt(ac, av, "Sbcfh: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_mode = TRUE; break;# endif case 'm':# ifdef MONITOR Am_monitor = TRUE;# else fputs("The monitor was not compiled in.\n", stderr);# endif break;# ifdef INTERNET case 'S': Show_scores = TRUE; break; 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;# else case 'S': case 'q': case 'w': case 'h': case 'p': fputs("Need TCP/IP for S, q, w, h, and p options.\n", stderr); break;# endif case 'c': enter_status = Q_CLOAK; break; case 'f':# ifdef FLY enter_status = Q_FLY;# else fputs("The flying code was not compiled in.\n", stderr);# endif break; case 's': enter_status = Q_SCAN; break; case 'b': no_beep = !no_beep; break; default: usage: fputs("usage:\thunt [-qmcsfS] [-n name] [-t team] [-p port] [-w message] [host]\n", stderr); exit(1); } }# ifdef INTERNET if (optind + 1 < ac) goto usage; else if (optind + 1 == ac) Sock_host = av[ac - 1];# else if (optind > ac) goto usage;# endif# ifdef INTERNET if (Show_scores) { SOCKET *hosts; for (hosts = list_drivers(); hosts->sin_port != 0; hosts += 1) dump_scores(*hosts); exit(0); } if (Query_driver) { SOCKET *hosts; for (hosts = list_drivers(); hosts->sin_port != 0; hosts += 1) { struct hostent *hp; int num_players; hp = gethostbyaddr((char *) &hosts->sin_addr, sizeof hosts->sin_addr, AF_INET); num_players = ntohs(hosts->sin_port); printf("%d player%s hunting on %s!\n", num_players, (num_players == 1) ? "" : "s", hp != NULL ? hp->h_name : inet_ntoa(hosts->sin_addr)); } exit(0); }# endif# ifdef OTTO if (Otto_mode) (void) strncpy(name, "otto", NAMELEN); else# endif fill_in_blanks(); (void) fflush(stdout); if (!isatty(0) || (term = getenv("TERM")) == NULL) { fprintf(stderr, "no terminal type\n"); exit(1); }# ifdef USE_CURSES initscr(); (void) noecho(); (void) cbreak();# else /* !USE_CURSES */# if !defined(BSD_RELEASE) || BSD_RELEASE < 44 _tty_ch = 0;# endif gettmode(); (void) setterm(term); (void) noecho(); (void) cbreak();# if defined(BSD_RELEASE) && BSD_RELEASE >= 44 tcgetattr(0, &saved_tty);# endif _puts(TI); _puts(VS);# endif /* !USE_CURSES */ in_visual = TRUE; if (LINES < SCREEN_HEIGHT || COLS < SCREEN_WIDTH) leave(1, "Need a larger window"); clear_the_screen(); (void) signal(SIGINT, intr); (void) signal(SIGTERM, sigterm); (void) signal(SIGEMT, sigemt); (void) signal(SIGPIPE, SIG_IGN);#if !defined(USE_CURSES) && defined(SIGTSTP) (void) signal(SIGTSTP, tstp);#endif for (;;) {# ifdef INTERNET find_driver(TRUE); if (Daemon.sin_port == 0) leave(1, "Game not found, try again"); jump_in: 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 do_connect(name, team, enter_status);# ifdef INTERNET if (Send_message != NULL) { do_message(); if (enter_status == Q_MESSAGE) break; Send_message = NULL; /* don't continue as that will call find_driver */ goto jump_in; }# endif playit(); if ((enter_status = quit(enter_status)) == Q_QUIT) break; } leave(0, (char *) NULL); /* NOTREACHED */}# ifdef INTERNET# ifdef BROADCASTbroadcast_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) memcpy(&(*vector)[vec_cnt++], &ifr->ifr_addr, sizeof (struct sockaddr)); return vec_cnt;}# endifSOCKET *list_drivers(){ int option; u_short msg; u_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; extern int errno;# ifdef BROADCAST static int brdc; static SOCKET *brdv;# else u_long local_net;# endif int i; static SOCKET *listv; static unsigned int listmax; unsigned int listc; int mask; struct timeval wait; if (initial) { /* do one time initialization */# ifndef BROADCAST sethostent(1); /* don't bother to close host file */# endif 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); listmax = 20; listv = (SOCKET *) malloc(listmax * sizeof (SOCKET)); } else if (Sock_host != NULL) return listv; /* address already valid */ test_socket = socket(SOCK_FAMILY, SOCK_DGRAM, 0); if (test_socket < 0) { perror("socket"); leave(1, "socket system call failed"); /* NOTREACHED */ } test.sin_family = SOCK_FAMILY; test.sin_port = htons(Test_port); listc = 0; if (Sock_host != NULL) { /* explicit host given */ if ((hp = gethostbyname(Sock_host)) == NULL) { leave(1, "Unknown host"); /* NOTREACHED */ } test.sin_addr = *((struct in_addr *) hp->h_addr); goto test_one_host; } if (!initial) { /* favor host of previous session by broadcasting to it first */ test.sin_addr = Daemon.sin_addr; msg = htons(C_PLAYER); /* 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, (struct sockaddr **) &brdv); if (brdc <= 0) { initial = FALSE; test.sin_addr = local_address; goto test_one_host; }# ifdef SO_BROADCAST /* Sun's will broadcast even though this option can't be set */ option = 1; if (setsockopt(test_socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof option) < 0) { perror("setsockopt broadcast"); leave(1, "setsockopt broadcast"); /* NOTREACHED */ }# endif /* send broadcast packets on all interfaces */ msg = htons(C_TESTMSG()); for (i = 0; i < brdc; i++) { test.sin_addr = brdv[i].sin_addr; 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. */ msg = htons(C_TESTMSG()); local_net = inet_netof(local_address); sethostent(0); /* rewind host file */ while (hp = gethostent()) { if (local_net == 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); } }# endifget_response: namelen = DAEMON_SIZE; errno = 0; wait.tv_sec = 1; wait.tv_usec = 0; for (;;) { if (listc + 1 >= listmax) { listmax += 20; listv = (SOCKET *) realloc((char *) listv, listmax * sizeof(SOCKET)); } mask = 1 << test_socket; if (select(test_socket + 1, &mask, NULL, NULL, &wait) == 1 && recvfrom(test_socket, (char *) &port_num, sizeof port_num, 0, (struct sockaddr *) &listv[listc], &namelen) > 0) { /* * Note that we do *not* convert from network to host * order since the port number *should* be in network * order: */ for (i = 0; i < listc; i += 1) if (listv[listc].sin_addr.s_addr == listv[i].sin_addr.s_addr) break; if (i == listc) listv[listc++].sin_port = port_num; continue; } if (errno != 0 && errno != EINTR) { perror("select/recvfrom"); leave(1, "select/recvfrom"); /* NOTREACHED */ } /* terminate list with local address */ listv[listc].sin_family = SOCK_FAMILY; listv[listc].sin_addr = local_address; listv[listc].sin_port = htons(0); (void) close(test_socket); initial = FALSE; return listv; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -