|
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 - downloadIndex: ┃ T s ┃
Length: 11727 (0x2dcf) Types: TextFile Names: »search.c.orig«
└─⟦87ddcff64⟧ Bits:30001253 CPHDIST85 Tape, 1985 Autumn Conference Copenhagen └─ ⟦this⟧ »cph85dist/search/search.c.orig«
#ifndef lint static char rcsid[] = "$Header: search.c,v 2.4 85/08/06 19:20:08 matt Exp $"; #endif /* * * search * * multi-player and multi-system search and destroy. * * Original by Dave Pare 1983 * Ported & improved * by Matt Crawford 1985 * * The player process. Search tries to connect to the daemon * via either a "tcp" internet socket (to another machine) or * a "stream" local socket. It gathers data about the player * and sends it along to the daemon. * * termcap routines taken from the original "slave.c" * * Copyright (c) 1983 * * $Log: search.c,v $ * Revision 2.4 85/08/06 19:20:08 matt * Must byte-swap [htons()] a non-standard port number. * * Revision 2.3 85/07/31 23:57:30 matt * Detect the socket shutdown properly. * * Revision 2.2 85/04/11 16:41:20 matt * Damn the padding, full speed ahead! * * Revision 2.1 85/04/10 17:31:47 matt * Major de-linting and minor restructuring. * * Revision 1.6 85/02/25 14:20:03 matt * Make the select() poll be a real poll and the wait be a * longer wait. * * Revision 1.5 85/02/10 01:20:36 matt * Had to double a backslash in the advisory message. * * Revision 1.4 85/02/09 23:50:13 matt * Eliminated the dependence on the value of the mask after * select() times out. Use the return value to distinguish * a timeout!! * * Revision 1.3 84/07/08 17:04:24 matt * Added Log * * Revision 1.2 84/07/07 18:16:34 matt * Put player.speed into network byte order just before sending the * player structure (t_file) to the daemon. */ #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/file.h> #include <sgtty.h> #include <ctype.h> #include <pwd.h> #include <signal.h> #include <sys/time.h> #include <errno.h> #include <sys/socket.h> #include <sys/un.h> #ifdef INET #include <netinet/in.h> #include <netdb.h> #endif #include "defines.h" #include "structs.h" extern char *ttyname(); extern int errno; int locked = 0; /* for the signal handler - sockets made yet? */ struct sgttyb savebuf; /* for saving the term capabilities */ int line; /* the line discipline (for the tty) */ int dtabsiz; /* how many fd's does YOUR system allow? */ int fd; /* the terminal - opened from "/dev/tty" */ t_file player; /* who are we, what does our term look like */ int sock; /* socket to daemon */ main(argc, argv) int argc; char *argv[]; { void fatal(); int reset(); char *strcpy(), *strncpy(); register int cc; /* returned from all sorts of calls */ register int i; /* general purpose register */ register int sockmask; register int stdinmask; char buf[4096]; /* misc buffer for i/o */ int mask; /* masks used in select() calls */ struct sgttyb sgbuf; /* used to set modes - cbreak, etc */ struct timeval timeout; /* time outs for select calls */ int save_mask; /* don't calculate mask each time */ char *tmp; struct passwd *pwd; /* our user's /etc/passwd entry */ struct sockaddr loc_addr; /* local socket address */ #ifdef INET int to_in; /* to internet (connection) */ char hostname[32]; /* name of our host (that we're on */ char shortname[32]; /* the shortest name for this host */ struct servent *serv; /* returned by getservbyname() */ struct hostent *host; /* returned by gethostbyname() */ int port_num; /* port number if getservbyname fails */ struct sockaddr_in in_addr; /* inter-net socket address */ #endif if (!isatty(0) || !isatty(1)) { printf("search: must be played from a terminal"); exit(1); } #ifdef INET if (argc > 3) { printf("usage: search [hostname] [portnum]\n"); exit(1); } if (argc == 1) to_in = 0; else to_in = 1; if (argc == 3) port_num = atoi(argv[2]); else port_num = DEFAULT_IN_PORT; dtabsiz = getdtablesize(); if (to_in) { (void) gethostname(hostname, sizeof(hostname)); /* * find the shortest name for our local system */ host = gethostbyname(hostname); tmp = host->h_name; for (i=0; host->h_aliases[i]; i++) if (strlen(tmp) > strlen(host->h_aliases[i])) tmp = host->h_aliases[i]; (void) strcpy(shortname, tmp); /* * now find the remote host */ host = gethostbyname(argv[1]); if (host == NULL) { printf("search: no such host \"%s\"\n", argv[1]); exit(1); } /* * get the service from /etc/services (525?) */ sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); exit(1); } serv = getservbyname("search", "tcp"); if (serv == NULL || argc == 3) { if (serv == NULL) fprintf(stderr,"no entry in /etc/services\n"); fprintf(stderr,"trying port %d\n", port_num); fprintf(stderr,"use ^\\ if no game screen comes up!\n"); sleep(2); in_addr.sin_port = htons(port_num); } else in_addr.sin_port = serv->s_port; in_addr.sin_family = host->h_addrtype; bcopy(host->h_addr, &in_addr.sin_addr, host->h_length); } else { sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { perror("search, socket"); exit(1); } (void) strcpy(loc_addr.sa_data, SLOCK); } #else sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { perror("search, socket"); exit(1); } (void) strcpy(loc_addr.sa_data, SLOCK); #endif /* * make it possible to get out-of-band messages on our favorite * socket. */ fcntl(sock, F_SETOWN, getpid()); /* * open our own tty for both reading & writing - makes it * much easier to do ioctls since we only have to do them on * the one fd now. * * it has been observed that running search as root occasionally * changes /dev/tty to 622 */ fd = open("/dev/tty", O_RDWR, 0); if (fd < 0) fatal("cannot open your tty\n"); /* * save the old term characteristics, and the line discipline */ ioctl(fd, TIOCGETP, (char *)&savebuf); if (ioctl(fd, TIOCGETD, (char *)&line) == -1) fatal("cannot get line discipline\n"); /* * set all the signals - SIGURG is for out-of-band data * notification */ (void) signal(SIGINT, SIG_IGN); (void) signal(SIGTERM, SIG_IGN); (void) signal(SIGQUIT, reset); (void) signal(SIGHUP, reset); (void) signal(SIGPIPE, reset); (void) signal(SIGURG, reset); (void) signal(SIGTSTP, SIG_IGN); (void) signal(SIGSTOP, SIG_IGN); /* * now set up the player structure for transmission to the * daemon. */ i = getuid(); pwd = getpwuid(i); if (pwd == NULL) { /* stolen from "talk" */ fprintf(stderr,"You don't exist. Go away.\n"); reset(0); } #ifdef INET if (to_in) (void) sprintf(player.p_name, "%s@%s", pwd->pw_name, shortname); else #endif (void) strcpy(player.p_name, pwd->pw_name); if (termcap(&player)) fatal("terminal unsuitable for play"); /* * Set up terminal modes for game */ line = NTTYDISC; ioctl(fd, TIOCSETD, (char *)&line); ioctl(fd, TIOCGETP, (char *)&sgbuf); sgbuf.sg_flags |= CBREAK; sgbuf.sg_flags &= ~ECHO; ioctl(fd, TIOCSETP, (char *)&sgbuf); locked++; /* * now we connect to the daemon */ #ifdef INET if (to_in) { /* * and connect to the foreign machine's search daemon */ if (connect(sock, (struct sockaddr *)&in_addr, sizeof(in_addr))) { printf("search: can't connect to %s's search daemon\n", argv[1]); reset(0); } } else { /* * connect to the local search daemon thru the lock * file (usually /tmp/slock for historical reasons) */ if (connect(sock, &loc_addr, sizeof(loc_addr))) { printf("search: no local search daemon running\n"); reset(0); } } #else if (connect(sock, &loc_addr, sizeof(loc_addr))) { printf("search: no local search daemon running\n"); reset(0); } #endif locked++; /* * transmit all the info we've gathered to the daemon */ player.p_speed = htonl(player.p_speed); if (write(sock, (char *)&player, sizeof(t_file)) < sizeof(t_file)) { perror("write"); fatal("bad connect on socket"); } /* * set up all the stuff for the select loop */ sockmask = 1<<sock; stdinmask = 1<<0; save_mask = sockmask | stdinmask; timeout.tv_sec = 30L; timeout.tv_usec = 0L; locked++; /* * and loop until that out-of-band message arrives * (or some nasty error occurs) */ for (;;) { mask = save_mask; i = select(dtabsiz, &mask, NULLINT, NULLINT, &timeout); if (i < 0) { if (errno = EINTR) continue; perror("select"); } /* * nope - no data waiting. select() timed out. */ if (!i) continue; /* * data waiting on stdin (the keyboard). read it in, * and send it to the daemon. */ if (mask & stdinmask) { i = read(0, buf, sizeof(buf)); if (i <= 0) { perror("read"); break; } cc = write(sock, buf, i); if (cc < i) { perror("write"); break; } } /* * input waiting from the daemon - read it in and * write it to the screen (stdout). it's a bunch * of screen/map updates! */ if (mask & sockmask) { cc = read(sock, buf, sizeof(buf)); /* * when you get zero characters from a socket that * had input waiting, it means that the socket was * closed down (from the other side) */ if (cc == 0) reset(0); if (cc < 0) { if (errno == EINTR) continue; perror("socket read"); break; } cc = write(1, buf, cc); } } fprintf(stderr,"the daemon died!\n"); reset(0); } reset(signum) int signum; { char buf[1024]; struct timeval delay; int mask; int i; switch (locked) { /* * disconnect from our socket (getting rid of the * gunk possibly leftover) */ case 3: case 2: mask = 1 << sock; delay.tv_sec = delay.tv_usec = 0L; shutdown(sock, 1); i = select(dtabsiz, &mask, NULLINT, NULLINT, &delay); if (i > 0) { i = read(sock, buf, sizeof(buf)); write(1, buf, i); } shutdown(sock, 2); (void) close(sock); /* fall through */ /* * set the term stuff back to normal */ case 1: if (ioctl(fd, TIOCSETD, (char *)&line) == -1) perror("tiocsetd"); ioctl(fd, TIOCSETP, (char *)&savebuf); (void) close(fd); break; default: break; } exit(signum); } void /*VARARGS1*/ fatal(fmt, arg) char *fmt; int arg; { fprintf(stderr, "search: fatal error, "); fprintf(stderr, fmt, arg); (void) fputc('\n', stderr); reset(0); } static char buf[1024], *bp = buf; struct init { char *i_name; /* termcap name */ char *i_dest; /* where to put the result */ short i_size; /* sizeof associated buffer */ short i_pad; /* padding flag: 0=no, 1=P, 2=P* */ } list[] = { { "bc", player.p_BC, sizeof(player.p_BC), 0 }, { "up", player.p_UP, sizeof(player.p_UP), 0 }, { "cm", player.p_CM, sizeof(player.p_CM), 1 }, { "ce", player.p_CE, sizeof(player.p_CE), 1 }, { "cl", player.p_CL, sizeof(player.p_CL), 2 }, { NULLCH, NULLCH, 0, 0 } }; /* * Build up the termcap description needed by searchd */ int termcap(p) register t_file *p; { register char *cp; register int lines, cols; register struct init *pi = list; char *term, tbuf[BUFSIZ]; void getstring(); struct sgttyb sbuf; extern char *getenv(), *tgetstr(); ioctl(fd, TIOCGETP, (char *)&sbuf); p->p_speed = sbuf.sg_ospeed; if ((term = getenv("TERM")) != NULL && tgetent(tbuf, term) > 0) { if (cp = tgetstr("pc", &bp)) p->p_PC = *cp; cols = tgetnum("co", &bp); lines = tgetnum("li", &bp); while (pi->i_size != 0) { getstring(pi); pi++; } return(*p->p_CM == '\0' || *p->p_CL == '\0' || cols < 80 || lines < 24); } return(1); } /* * Termcap support routine */ void getstring(pi) register struct init *pi; { register char *cp = tgetstr(pi->i_name, &bp); if (cp == NULL) return; if ( pi->i_pad ) { while ( index( "0123456789.", *cp ) ) cp++; if ( pi->i_pad == 2 && *cp == '*' ) cp++; } if ( strlen(cp) >= pi->i_size ) fatal("%s string too long", pi->i_name); (void) strncpy(pi->i_dest, cp , pi->i_size); }