|
|
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 t
Length: 7531 (0x1d6b)
Types: TextFile
Names: »talk.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/General/War/talk.c«
#ifdef SCCS
static char *sccsid = "@(#)talk.c 1.1 4/5/85";
static char *cpyrid = "@(#)Copyright (C) 1985 by D Bell";
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <utmp.h>
#include "war.h"
#define NAMELEN (sizeof(ud.ut_name)) /* length of name field */
#define LINELEN (sizeof(ud.ut_line)) /* length of line field */
#define DEVLEN (sizeof(dev) - 1) /* length of device string */
#define FULLEN (LINELEN + DEVLEN + 1) /* length of full tty name */
#define INFO 20 /* number of messages */
char utmp[] = "/etc/utmp"; /* logged in user file */
char dev[] = "/dev/"; /* prefix for tty names */
int sd; /* descriptor for socket */
int serverflag; /* nonzero if we are the server */
struct sockaddr addr; /* name of our socket */
int infocount; /* number of queued messages */
struct info info[INFO]; /* messages queued for sending */
/*
* Set the socket address used for connecting to the other player.
* We find the other player by his user name (and his tty name if necessary).
* The address is generated using the device numbers of our two terminals.
* Exits if an error is detected. If successful, saves the socket address
* and remembers whether we are to be the server or the client.
*/
findplayer(user, tty)
register char *user; /* other player's user name */
register char *tty; /* other player's tty name, or NULL */
{
register FILE *fd; /* file pointer */
register char *shortname; /* short tty name */
register int count; /* times user is logged in */
int sawme; /* true if saw myself */
int dev1; /* device of first tty */
int dev2; /* device of second tty */
struct stat sb; /* file status */
struct utmp ud; /* utmp entry */
char fullname[FULLEN]; /* full tty name */
if (fstat(STDERR, &sb)) { /* we aren't on a tty */
perror("stderr");
exit(1);
}
if ((sb.st_mode & S_IFMT) != S_IFCHR) {
fprintf(stderr, "stderr: not a character device\n");
exit(1);
}
dev1 = sb.st_rdev;
fd = fopen(utmp, "r");
if (fd == NULL) {
perror(utmp);
exit(1);
}
strcpy(fullname, dev);
shortname = &fullname[DEVLEN];
shortname[LINELEN] = '\0';
count = 0;
sawme = 0;
while (fread(&ud, sizeof(ud), 1, fd)) {
if (ud.ut_name[0] == '\0') continue;
if (strncmp(user, ud.ut_name, NAMELEN)) continue;
strncpy(shortname, ud.ut_line, LINELEN);
if (stat(fullname, &sb) < 0) continue;
if ((sb.st_mode & S_IFMT) != S_IFCHR) continue;
if (sb.st_rdev == dev1) { /* see if this is myself */
sawme = 1;
continue;
}
dev2 = sb.st_rdev;
count++;
if ((tty == NULL) || strcmp(tty, shortname)) continue;
count = 1; /* found user on tty */
break;
}
fclose(fd);
if (count <= 0) {
if (sawme)
fprintf(stderr, "you are not logged in elsewhere\n");
else
fprintf(stderr, "%s is not logged in\n", user);
exit(1);
}
if (tty && strcmp(tty, shortname)) {
fprintf(stderr, "%s is not logged in on %s\n", user, tty);
exit(1);
}
if (count > 1) {
fprintf(stderr, "%s is logged in more than once\n", user);
exit(1);
}
if (dev1 > dev2) { /* order the devices */
count = dev1;
dev1 = dev2;
dev2 = count;
serverflag = 1;
}
sprintf(addr.sa_data, "WAR.%d.%d", dev1, dev2);
}
/*
* Initialize to talk to the other player.
*/
talkinit()
{
if (chdir(GAMEDIR)) { /* go to right place */
perror(GAMEDIR);
exit(1);
}
dpymove(-1, 1);
dpystr("Waiting for other player...");
dpyhome();
dpyupdate();
if (serverflag) { /* we are the server */
serverinit();
dpymove(-1, 1);
dpyclrwindow();
sendboard();
} else { /* we are the client */
clientinit();
dpymove(-1, 1);
dpyclrwindow();
readinfo();
sendboard();
}
beep();
playing = 1;
newstat = 1;
}
/*
* Here if we are the server process, to create the binding.
* Wait for a connection from the client.
*/
serverinit()
{
register int s; /* socket descriptor */
int dummylen; /* dummy length */
struct sockaddr dummyaddr; /* name of our socket */
s = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC); /* create socket */
if (s < 0) {
perror("socket");
exit(1);
}
unlink(addr.sa_data); /* remove binding name */
if (bind(s, &addr, sizeof(addr)) < 0) { /* declare ourself */
perror("bind");
exit(1);
}
if (listen(s, 1) < 0) { /* allow one connection */
perror("listen");
exit(1);
}
dummylen = sizeof(dummyaddr);
sd = accept(s, &dummyaddr, &dummylen);
if (sd < 0) {
perror("accept");
exit(1);
}
close(s);
}
/*
* Here if we are the client process, to connect to the binded address.
* We just continuously try to connect to the address.
*/
clientinit()
{
sd = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC); /* create socket */
if (sd < 0) {
perror("socket");
exit(1);
}
while (connect(sd, &addr, sizeof(addr)) < 0) {
if ((errno != ECONNREFUSED) && (errno != ENOENT)) {
perror("connect");
exit(1);
}
sleep(1);
}
}
/*
* Send the initial board layout
*/
sendboard()
{
register struct cell *cc; /* current cell within row */
register struct object *obj; /* object at this location */
for (cc = homecell; cc; cc = cc->c_next) {
obj = cc->c_obj;
if ((obj == NULL) || (obj->o_side != myside)) continue;
sendinfo('p', cc->c_row, cc->c_col, obj->o_id);
}
sendinfo('r', 0, 0, 0);
}
/*
* Send an information message to the other player.
* Successive message are buffered up and sent together in one write.
* All pending messages are flushed when an 'r' message type is used.
*/
sendinfo(type, row, col, id)
register int type; /* message type */
unsigned int row;
unsigned int col;
{
register struct info *ip; /* pointer to current info block */
if ((row >= ROWS) || (col >= COLS)) panic("badsend");
ip = &info[infocount++];
ip->i_type = type;
ip->i_row = row;
ip->i_col = col;
ip->i_id = id;
if ((type != 'r') && (infocount < INFO))
return; /* wait till later */
type = (infocount * sizeof(struct info));
if (write(sd, info, type) != type) {
dpyclose();
fprintf(stderr, "other player quit\n");
exit(0);
}
infocount = 0;
}
/*
* Read and process commands from the other player until we are released
* with a ready command. We transform incoming id's and row numbers.
*/
readinfo()
{
register int row; /* row of interest */
register int col; /* column of interest */
register int id; /* id of object */
register struct cell *cc; /* current cell */
register struct object *obj; /* current object */
struct info info; /* command being read */
while (1) {
id = read(sd, &info, sizeof(info));
if (id <= 0) {
dpyclose();
fprintf(stderr, "other player quit\n");
exit(0);
}
if (id != sizeof(info)) panic("short read from socket");
id = info.i_id ^ 1; /* toggle id */
row = (ROWS - 1) - info.i_row; /* and row number */
col = info.i_col;
if ((row >= ROWS) || (col >= COLS)) panic("bad coordinates");
cc = &board[row][col];
obj = cc->c_obj;
switch (info.i_type) {
case 'b': /* wall got blasted */
if ((obj == NULL) || ((obj->o_flags & F_WALL) == 0))
panic("blasting non-wall");
removeobject(row, col);
break;
case 'h': /* man got hit */
if ((obj == NULL) || (obj->o_side != myside))
panic("missed me");
hitobject(cc->c_row, cc->c_col);
break;
case 'p': /* object got placed or moved */
if (obj) panic("nested objects");
obj = findid(id);
if (obj->o_side == myside) panic("read my own object");
placeobject(obj, row, col);
break;
case 'r': /* ready for other player */
return;
default:
panic("bad command read from opponent\n");
}
}
}