|
|
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 s
Length: 11988 (0x2ed4)
Types: TextFile
Names: »search.c«
└─⟦87ddcff64⟧ Bits:30001253 CPHDIST85 Tape, 1985 Autumn Conference Copenhagen
└─⟦this⟧ »cph85dist/search/search.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/General/Search/search.c«
#ifndef lint
static char rcsid[] = "$Header: search.c,v 2.5 85/08/15 13:22:30 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.5 85/08/15 13:22:30 matt
* Big blooper: getdtablesize() was called inside of #ifdef INET !
* Also, restrict dtabsiz to an int's worth of bits.
*
* 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/param.h> /* includes <sys/types.h> and <signal.h> */
#include <sys/stat.h>
#include <sys/file.h>
#include <sgtty.h>
#include <ctype.h>
#include <pwd.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);
}
dtabsiz = getdtablesize();
if (dtabsiz > NBBY * sizeof (int))
dtabsiz = NBBY * sizeof (int);
#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;
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);
}