/*
Copyright (C) 1991, Marcus J. Ranum. All rights reserved.
VMS port by Andrew Molitor (with many thanks!)
*/
#ifndef lint
static char RCSid[] = "$Header: /usr/users/mjr/hacks/umud/RCS/net_vms.c,v 1.1 91/06/17 14:37:36 mjr Exp $";
#endif
/* configure all options BEFORE including system stuff. */
#include "config.h"
#include "multinet_root:[multinet.include.sys]types.h"
#include "multinet_root:[multinet.include]netdb.h"
#include "multinet_root:[multinet.include.sys]socket.h"
#include "multinet_root:[multinet.include.netinet]in.h"
#include "multinet_root:[multinet.include.vms]inetiodef.h"
#include <ctype.h>
#include <varargs.h>
#include <ssdef.h>
#include <libdtdef.h>
#include "mud.h"
#include "vars.h"
/*
For the VMS version, we use event flags to synchronize most everything.
Writes we don't care about. All reads set flag 32 on completion, server fd
connects set flag 33, player connects set flag 34. We use 35 for the timer.
*/
/*
#define VMSNET_DEBUG
*/
/*
as always the network code comprises the lioness' share of the MUD.
this module supports connection maintenance and buffering for
berkeley-style tcp/ip sockets. each connection has a pair of
buffers allocated, and once it has been authenticated as a given
player's connection, an entry into a player-name hash table is
made for faster access.
the manner in which buffers are shutdown is bizarre, but it is
all handled in io_sync() to prevent writes into buffers that have
been freed. this way buffers *WILL* hang around 'till the end of
the play/run.
*/
/* you can change PHSIZ, but don't mess with PHMAG */
#define PHSIZ 31 /* width of internal name hash table */
/*
When we queue up a write, we stuff this in a queue, and wait
for it to complete.
*/
typedef struct obuff {
struct obuff *bck,*fwd;
short int iosb[4];
char buffer[MUDBUF];
} obuff;
/* This is the queue of buffers $qio'd for output */
static obuff *outQ = (obuff *)0;
/* Iob flags */
#define IOBOK 001 /* OK/logged in player connection */
#define IOBKILL 002 /* kill this IOB at sync time - it's dead */
#define IOBERR 004 /* ignore this IOB - it is f***ed up. */
typedef struct {
int flg; /* flags */
time_t ltim; /* last input time */
time_t ctim; /* connect time */
char who[MAXOID]; /* player object ID */
int fd; /* file desc */
char *obuf; /* malloced output buffer */
char *op; /* output buf ptr */
char *ibuf; /* malloced input buffer */
char *ip; /* input buf ptr */
int ic; /* input byte cnt */
obuff *outputbuff; /* The structure. */
short int iosb[4]; /* For read $qios */
int opcnt; /* Number of oputstanding ops */
} Iob;
/*
player-name to Iob resolution map
an entry is made in this when the player is authenticated by the
login(), and is subsequently used to quickly map names to Iobs.
the mapping is destroyed when the iob is dropped by iobdrop().
don't mess with this code - it's icky.
*/
typedef struct pmap {
Iob *iob;
struct pmap *n;
} Pmap;
static Pmap *pmaptab[PHSIZ];
static Iob **iobtab; /* active Iob table */
static Iob *lastiob = (Iob *)0;
static int onewrt = 0; /* optimization */
static int iobtabsiz; /* top bound of Iob table */
static int curriob; /* highest Iob in use */
static short int seriosb[4];
static short int plyiosb[4];
static Iob *orphans = (Iob *)0;
static long timo[2];
static int serfd; /* inter server service port */
static int plyfd; /* main player service port */
struct sockaddr_in addr; /* address of newly connected */
static int sport = NET_SRVPRT; /* service port # */
static int pport = NET_PLYPRT; /* play port # */
static int net_initted = 0;
static int timosec; /* Seconds per tick */
static int nxtwhoiobptr; /* used for programmed Iob traverse */
static void dec_opcnt();
/*
set up the iob tables, iob maps, sockets, the whole bit
*/
io_init()
{
int x;
int op;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
timosec = cron_quantum;
op = LIB$K_DELTA_SECONDS;
lib$cvt_to_internal_time(&op,&timosec,timo);
/*
if you ain't got dtablesize(), fudge this with whatever
your systems max file descriptor value is. erring on the
high side will waste a little memory is all.
*/
iobtabsiz = 128;
sys$clref(32L);
sys$clref(33L);
sys$clref(34L);
sys$setef(35L); /* SET this to get the timer going. */
/* initialize the Iob hash table */
iobtab = (Iob **)malloc((unsigned)(sizeof(Iob *) * iobtabsiz));
if(iobtab == (Iob **)0)
return(1);
/* zero iob table */
for(x = 0; x < iobtabsiz; x++)
iobtab[x] = (Iob *)0;
/* zero player to Iob hash table */
for(x = 0; x < PHSIZ; x++)
pmaptab[x] = (Pmap *)0;
/* OPEN INTER SERVER FILE DESCRIPTOR AND BIND IT */
if((serfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
return(1);
addr.sin_port = htons(sport);
if(bind(serfd,(struct sockaddr *)&addr,sizeof(addr))) {
logf("cannot bind socket: ",(char *)-1,"\n",0);
return(1);
}
if(listen(serfd,5) == -1) {
logf("cannot listen at socket: ",(char *)-1,"\n",0);
return(1);
}
/* Queue up a wait for connects type thing. */
sys$qio(33L,serfd,IO$_ACCEPT_WAIT,seriosb,0,0,0,0,0,0,0,0);
/* OPEN PLAYER ACCESS FILE DESCRIPTOR AND BIND IT */
if((plyfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
return(1);
addr.sin_port = htons(pport);
if(bind(plyfd,(struct sockaddr *)&addr,sizeof(addr))) {
logf("cannot bind socket: ",(char *)-1,"\n",0);
return(1);
}
if(listen(plyfd,5) == -1) {
logf("cannot listen at socket: ",(char *)-1,"\n",0);
return(1);
}
/* Queue up a wait for connects type thing. */
sys$qio(34L,plyfd,IO$_ACCEPT_WAIT,plyiosb,0,0,0,0,0,0,0,0);
/*
In VMS, the iotab is ONLY for existing connects. curriob is
the high-water mark, this indicates an empty table.
*/
curriob = -1;
net_initted++;
return(0);
}
/*
disconnect an Iob (low level)
*/
static void
iobdrop(ip)
Iob *ip;
{
int x,y;
Pmap *pp;
Pmap *pr;
if(ip == (Iob *)0)
return;
#ifdef VMSNET_DEBUG
printf("Dropping Iob on fd %d.\n",ip->fd);
#endif
if (ip->who[0]) {
plogf("DISCONNECT %s on %d\n", ip->who, ip->fd);
#ifdef USE_RWHO
rwhocli_userlogout(ip->who);
#endif
} else
plogf("DISCONNECT %d\n", ip->fd);
for(y = 0; y < iobtabsiz; y++) {
if(iobtab[y] == ip) {
iobtab[y] = (Iob *)0;
break;
}
}
/* unlink player map hash. this is somewhat convoluted. */
for(x = 0; x < PHSIZ; x++) {
pp = pmaptab[x];
while(pp != (Pmap *)0) {
if(pp->iob == ip && pp == pmaptab[x]) {
pr = pp;
pmaptab[x] = pp->n;
free((mall_t)pr);
break;
} else {
if(pp->n != (Pmap *)0 && pp->n->iob == ip) {
pr = pp->n;
pp->n = pp->n->n;
free((mall_t)pr);
break;
}
}
pp = pp->n;
}
}
/* adjust top iob in use count */
/* y had BETTER not have been messed with */
if(y == curriob)
curriob--;
/* final cleanup */
(void)shutdown(ip->fd,2);
(void)close(ip->fd);
if(ip->opcnt > 0){
/* Stuff it on the orphaned Iob list for io_sync() to handle */
ip->ip = (char *) orphans;
orphans = ip;
return;
}
(void)free((mall_t)ip->ibuf);
(void)free((mall_t)ip->obuf);
/*
this is done to cause a coredump in case someone's code is
so stupid as to write into an Iob that has been closed down
*/
ip->ibuf = ip->obuf = (char *)0;
(void)free((mall_t)ip);
}
/*
tokenize out a single line of text (destructive)
this function handles a buffer of player input, returning a sequence of
lines - it may move data around in the buffer, and may alter the content
of the buffer as it does so. this handles cases where a line may be
broken into two packets by the network - it re-assembles them efficiently.
*/
static char *
iobgl(i)
Iob *i;
{
char *op;
int ic;
while(i->ic > 0 && (*i->ip == '\n' || *i->ip == '\r')) {
*i->ip++ = '\0';
i->ic--;
}
if((ic = i->ic) <= 0) {
i->ip = i->ibuf;
i->ic = 0;
return((char *)0);
}
op = i->ip;
while(1) {
if(*i->ip == '\r' && *(i->ip + 1) == '\n' && ic > 1) {
*i->ip++ = '\0';
*i->ip++ = '\0';
if((i->ic = ic - 2) < 1)
i->ip = i->ibuf;
return(op);
}
if((*i->ip == '\n' || *i-> ip == '\r') && ic > 0) {
*i->ip++ = '\0';
if((i->ic = --ic) < 1)
i->ip = i->ibuf;
return(op);
}
/* nothing left in buffer, but no newline */
if(--ic <= 0) {
if(i->ic >= MUDBUF - 1)
return((char *)0);
/* shift down */
bcopy(op,i->ibuf,i->ic);
/* resync */
i->ip = i->ibuf;
i->ic = 0;
return((char *)0);
}
i->ip++;
}
}
/*
flush a single Iob
*/
static int
iobflush(ip)
Iob *ip;
{
int xx = ip->op - ip->obuf;
int wr;
if(ip->flg & IOBERR)
return(1);
/* Too much pending. Flush it. */
if(ip->opcnt > 16){
sys$qio(0,ip->fd,IO$_WRITEVBLK,0,0,0,"<Output Flushed>",16,
0,0,0,0);
ip->op = ip->obuf;
return(0);
}
/* Queue this up. */
#ifdef VMSNET_DEBUG
printf("Queueing %d bytes on fd %d.\n",xx,ip->fd);
#endif
sys$qio(0,ip->fd,IO$_WRITEVBLK,(ip->outputbuff)->iosb,dec_opcnt,ip,
ip->obuf,xx,0,0,0,0);
ip->opcnt++;
if(outQ == (obuff *)0){ /* Empty queue */
(ip->outputbuff)->fwd = (ip->outputbuff)->bck = (obuff *)0;
outQ = ip->outputbuff;
} else {
(ip->outputbuff)->fwd = outQ;
(ip->outputbuff)->bck = outQ->bck;
(outQ->bck)->fwd = ip->outputbuff;
outQ->bck = ip->outputbuff;
}
/* Get a new obuffer. */
if(getnewobuff(ip) == -1){
ip->flg |= IOBERR;
return(1);
}
return(0);
}
/* VARARGS1 */
void
say(who,va_alist)
char *who;
va_dcl
{
Pmap *p;
char *s;
va_list ap;
if(who == (char *)0 || who[0] == '\0' || !net_initted)
return;
for(p = pmaptab[objid_hash(who,PHSIZ)];p != (Pmap *)0; p = p->n) {
/* wrong guy */
if((p->iob->flg & IOBERR) || strcmp(p->iob->who,who))
continue;
if(lastiob != p->iob) {
lastiob = p->iob;
onewrt++;
}
va_start(ap);
while((s = va_arg(ap,char *)) != (char *)0) {
while(*s) {
if((p->iob->op - p->iob->obuf) > MUDBUF - 1) {
if(iobflush(p->iob))
goto dropthru;
} else {
*p->iob->op++ = *s++;
}
}
}
dropthru:
va_end(ap);
}
}
#ifdef CONNONLY
int
playerconn(who)
char *who;
{
Pmap *p;
if(who == (char *)0 || who[0] == '\0' || !net_initted)
return(0);
for(p = pmaptab[objid_hash(who,PHSIZ)];p != (Pmap *)0; p = p->n) {
if((p->iob->flg & IOBERR) || strcmp(p->iob->who,who))
/* wrong guy */
continue;
else
return(1);
}
return(0);
}
#endif
void
io_logoff(who)
char *who;
{
Pmap *p;
if(who == (char *)0 || who[0] == '\0' || !net_initted)
return;
p = pmaptab[objid_hash(who,PHSIZ)];
while(p != (Pmap *)0) {
if(strcmp(p->iob->who,who)) {
p = p->n;
continue;
}
p->iob->flg |= IOBKILL;
onewrt = 2;
p = p->n;
}
}
/* VARARGS1 */
void
iobsay(ip,va_alist)
Iob *ip;
va_dcl
{
char *s;
va_list ap;
if(ip->flg & IOBERR)
return;
if(lastiob != ip) {
lastiob = ip;
onewrt++;
}
va_start(ap);
while((s = va_arg(ap,char *)) != (char *)0) {
while(*s) {
if((ip->op - ip->obuf) > MUDBUF - 1) {
if(iobflush(ip))
return;
} else {
*ip->op++ = *s++;
}
}
}
va_end(ap);
}
/*
This trots down the list of orphaned Iob's, checking to see
if any have all outstanbding ops on them completed, and freeing those.
*/
static void
purge_orphans()
{
Iob *bp,*tmp;
for(bp = orphans; bp != (Iob *) 0; bp = (Iob *) bp->ip) {
if(bp->opcnt <= 0 && bp == orphans){
orphans = (char *) bp->ip;
free((mall_t) bp->ibuf);
free((mall_t) bp->obuf);
bp->ibuf = bp->obuf = (char *)0;
free((mall_t)bp);
bp = orphans;
} else {
#ifdef VMSNET_DEBUG
printf("Orphaned Iob on fd %d has pending ops.\n",bp->fd);
#endif
if(bp->ip != (char *)0 && ((Iob *)bp->ip)->opcnt <= 0){
tmp = (Iob *) bp->ip;
bp->ip = ((Iob *)bp->ip)->ip;
free((mall_t) tmp->ibuf);
free((mall_t) tmp->obuf);
tmp->ibuf = tmp->obuf = (char *)0;
free((mall_t) tmp);
}
}
}
}
/*
flush the connected (valid) Iobs
*/
void
io_sync()
{
int n;
Iob *bp;
#ifdef VMSNET_DEBUG
printf("Syncing..\n");
#endif
if(!onewrt || !net_initted)
return;
/* WARNING!!! the calls to goodbye() actually may make more
Iob writes as a result of a player hangup! Do NOT do much
in goodbye!() or madness may result. */
if(onewrt == 1 && lastiob != (Iob *)0) {
#ifdef VMSNET_DEBUG
printf("Only one Iob to flush.\n");
#endif
if(iobflush(lastiob)) {
if(lastiob->flg & IOBOK)
goodbye(lastiob->who);
iobdrop(lastiob);
return;
}
if(lastiob->flg & IOBERR || lastiob->flg & IOBKILL) {
if(lastiob->flg & IOBOK)
goodbye(lastiob->who);
iobdrop(lastiob);
}
purge_orphans();
return;
}
for(n = 0; n < iobtabsiz; n++) {
if(iobtab[n] != (Iob *)0) {
if(iobtab[n]->op > iobtab[n]->obuf) {
if(iobflush(iobtab[n])) {
if(iobtab[n]->flg & IOBOK)
goodbye(iobtab[n]->who);
iobdrop(iobtab[n]);
}
continue;
}
if(iobtab[n]->flg & IOBKILL || iobtab[n]->flg & IOBERR) {
if(iobtab[n]->flg & IOBOK)
goodbye(iobtab[n]->who);
iobdrop(iobtab[n]);
}
}
}
onewrt = 1;
lastiob = (Iob *)0;
purge_orphans();
}
/*
wrapper around the player authentication routine. said routine will
return a 1 if the login is valid, a 0 if it is not. if the login is
OK, we then fiddle some Iob values and make a hash-table map entry.
if login() returns -1, then we are to close the connection.
*/
static void
io_dologin(bp,line)
Iob *bp;
char *line;
{
Pmap *pm;
int hv;
hv = login(line,bp->who);
if(hv == 0) {
iobsay(bp,"Either that object does not exist, or the password was incorrect, butthead.\n",(char *)0);
logf("badlogin: ",line,"\n",(char *)0);
return;
}
if(hv == -1) {
bp->flg |= IOBKILL;
onewrt = 2;
return;
}
bp->flg |= IOBOK;
/* now add a pointer to the character's name in the Iob hash */
pm = (Pmap *)malloc(sizeof(Pmap));
if(pm == (Pmap *)0)
fatal("out of memory building new connection\n",(char *)0);
pm->iob = bp;
pm->n = pmaptab[(hv = objid_hash(bp->who,PHSIZ))];
pmaptab[hv] = pm;
plogf("CONNECT %s on %d\n", bp->who, bp->fd);
welcome(bp->who);
#ifdef USE_RWHO
rwhocli_userlogin(bp->who,ut_name(bp->who),bp->ctim);
#endif
}
/*
main I/O loop - listens for new connections, accepts them, validates
them, reads input, and dispatches it.
*/
io_loop()
{
Iob *bp;
int n;
int seld;
int rd;
char *lp;
time_t now;
int x;
int eflags;
#ifdef VMSNET_DEBUG
printf("Waiting...");
#endif
if(!net_initted)
return(1);
/* Set up a timer. */
sys$readef(35L,&eflags);
/* If the last timer has expired, or tick interval changed */
if(eflags & 8 || cron_quantum != timosec){
/* Has our tick interval changed? */
if(cron_quantum != timosec){
int op = LIB$K_DELTA_SECONDS;
timosec = cron_quantum;
lib$cvt_to_internal_time(&op,&timosec,timo);
}
#ifdef VMSNET_DEBUG
printf("Setting timer for %d seconds.\n",timosec);
#endif
sys$cantim(1);
sys$setimr(35L,timo,0,1,0);
}
sys$wflor(32L,15L); /* Wait on event flags 32, through 35. */
sys$readef(32L,&eflags); /* Read this event flag group. */
#ifdef VMSNET_DEBUG
printf("Event! flags are: %x\n",eflags);
#endif
if(eflags & 7 == 0) /* None of the good flags are set. yawn. */
return(0);
/* start the clock */
(void)time(&now);
/* new SERVER TO SERVER connection */
if(eflags & 2){ /* 33 is masked 0x0002 in this group. */
n = accept(serfd,(struct sockaddr *)0,(int *)0);
#ifdef VMSNET_DEBUG
printf("New server connect on fd %d.\n",n);
#endif
if(n == -1) {
logf("aiee! connect on server port dropped\n",0);
close(n);
} else {
/* deal with it */
xact_in(n); /* This even closes the channel */
}
/* Queue another one */
sys$qio(33L,serfd,IO$_ACCEPT_WAIT,seriosb,0,0,0,0,0,0,0,0);
}
/* new PLAYER connection */
if(eflags & 4){ /* 34 is masked 0x0004 in this group */
n = accept(plyfd,(struct sockaddr *)0,(int *)0);
#ifdef VMSNET_DEBUG
printf("New player connect on fd %d.\n",n);
#endif
if(n != -1) {
/* Queue another one */
sys$qio(34L,plyfd,IO$_ACCEPT_WAIT,plyiosb,
0,0,0,0,0,0,0,0);
bp = (Iob *)malloc(sizeof(Iob));
if(bp == (Iob *)0) {
logf("cannot alloc Iob: ",(char *)-1,"\n",0);
return(-1);
}
bp->flg = 0;
bp->who[0] = '\0';
bp->fd = n;
bp->ctim = now;
if((bp->ibuf = (char *)malloc(MUDBUF)) == (char *)0)
return(-1);
bp->ip = bp->ibuf;
bp->ic = 0;
if(getnewobuff(bp) == -1)
return(-1);
bp->op = bp->obuf;
bp->opcnt = 0;
/* queue up a read on the new socket */
#ifdef VMSNET_DEBUG
printf("Queueing initial read.\n");
#endif
sys$qio(32L,bp->fd,IO$_READVBLK,bp->iosb,
dec_opcnt,bp,
bp->ibuf + bp->ic,MUDBUF - bp->ic - 1,
0,0,0,0);
/* Put it in the iobtable */
for(x=0; x < iobtabsiz; x++){
if(iobtab[x] == (Iob *)0)
break;
}
if(x == iobtabsiz || iobtab[x] != (Iob *)0){
iobsay(bp,"No space!\n",(char *)0);
iobdrop(bp);
} else {
iobtab[x] = bp;
if(x > curriob){
curriob = x;
}
}
iobsay(bp,"c[onnect] objectid password\n",(char *)0);
}
}
mainloop:
/* check input on existing fds. */
/* Clear the event flag NOW. It's safe to do it here. */
sys$clref(32L);
for(n = 0; n <= curriob; n++) {
if((bp = iobtab[n]) != (Iob *)0 && bp->iosb[0] == SS$_NORMAL) {
rd = bp->iosb[1];
#ifdef VMSNET_DEBUG
printf("Read %d bytes on fd %d\n",rd,bp->fd);
#endif
if(rd <= 0) {
bp->flg |= IOBERR | IOBKILL;
onewrt = 2;
continue;
}
/* increment count of bytes in buffer */
bp->ic += rd;
/* adjust last active time */
bp->ltim = now;
/* process input based on state of connection */
while((lp = iobgl(bp)) != (char *)0) {
if(bp->flg & IOBOK)
run(bp->who,bp->who,lp,0,(char **)0,1);
else
io_dologin(bp,lp);
}
bp->opcnt++;
/* queue up another read */
sys$qio(32L,bp->fd,IO$_READVBLK,bp->iosb,
dec_opcnt,bp,
bp->ibuf + bp->ic,MUDBUF - bp->ic - 1,
0,0,0,0);
continue;
}
/* lastly, check exceptions in case of no input */
if((bp = iobtab[n]) != (Iob *)0 && bp->iosb[0] != 0
&& bp->iosb[0] != SS$_NORMAL) {
#ifdef VMSNET_DEBUG
printf("Error %x on fd %d.\n",bp->iosb[0],bp->fd);
#endif
/* default case */
if(bp != (Iob *)0) {
bp->flg |= IOBERR | IOBKILL;
onewrt = 2;
}
continue;
}
}
/* e! */
return(0);
}
/* ARGSUSED */
cmd__netconfig(argc,argv,who)
int argc;
char *argv[];
char *who;
{
static char *nactm = "network layer is already active.\n";
static char *badp = "invalid port number.\n";
/* configure service port */
if(!strcmp(argv[1],"playport")) {
int tmpx;
if(net_initted) {
logf(nactm,(char *)0);
return(1);
}
if(argc < 3 || (tmpx = atoi(argv[2])) <= 0) {
logf(badp,(char *)0);
return(1);
}
pport = tmpx;
logf("player port is #",argv[2],"\n",(char *)0);
return(0);
}
/* configure service port */
if(!strcmp(argv[1],"servport")) {
int tmpx;
if(net_initted) {
logf(nactm,(char *)0);
return(1);
}
if(argc < 3 || (tmpx = atoi(argv[2])) <= 0) {
logf(badp,(char *)0);
return(1);
}
sport = tmpx;
logf("server port is #",argv[2],"\n",(char *)0);
return(0);
}
logf("_netconfig: I don't understand ",argv[1],"\n",(char *)0);
return(0);
}
/* ARGSUSED */
cmd_WHO(argc,argv,who,aswho)
int argc;
char *argv[];
char *who;
char *aswho;
{
int x;
int jj;
time_t now;
char xuf[180];
extern char *sprintf();
if(!net_initted)
return(1);
(void)time(&now);
say(who,"Player Name On For Idle\n",(char *)0);
if(argc < 2) {
for(x = 0; x < iobtabsiz; x++) {
if(iobtab[x] != (Iob *)0 && (iobtab[x]->flg & IOBOK) &&
iobtab[x]->who[0] != '\0') {
sprintf(xuf,"%-21.21s %3d:%02d.%02d %3d:%02d.%02d (%s)\n",
ut_name(iobtab[x]->who),
(int)((now - iobtab[x]->ctim) / 3600),
(int)((now - iobtab[x]->ctim) / 60),
(int)((now - iobtab[x]->ctim) % 60),
(int)((now - iobtab[x]->ltim) / 3600),
(int)((now - iobtab[x]->ltim) / 60),
(int)((now - iobtab[x]->ltim) % 60),
iobtab[x]->who);
say(who,xuf,(char *)0);
}
}
return(0);
}
for(jj = 1; jj < argc; jj++ ) {
char *na;
for(x = 0; x < iobtabsiz; x++) {
if(iobtab[x] != (Iob *)0 && (iobtab[x]->flg & IOBOK) &&
iobtab[x]->who[0] != '\0') {
na = ut_name(iobtab[x]->who);
if(na != (char *)0 && matchstr(na,argv[jj],0) != 0) {
sprintf(xuf,"%-21.21s %3d:%02d.%02d %3d:%02d.%02d (%s)\n",
na,
(int)((now - iobtab[x]->ctim) / 3600),
(int)((now - iobtab[x]->ctim) / 60),
(int)((now - iobtab[x]->ctim) % 60),
(int)((now - iobtab[x]->ltim) / 3600),
(int)((now - iobtab[x]->ltim) / 60),
(int)((now - iobtab[x]->ltim) % 60),
iobtab[x]->who);
say(who,xuf,(char *)0);
}
}
}
}
return(0);
}
/*
This is called when any queued operation on a socket completes.
It merely decrements the count of outstanding operations on the socket, so we
can tell when the socket is recycleable.
*/
void dec_opcnt(bp)
Iob *bp;
{
bp->opcnt--;
}
/*
Get a new obuff for an Iob, and hook it up.
*/
int getnewobuff(ip)
Iob *ip;
{
obuff *skip;
int found;
/* Scan down the list of queued obuffs for one that's done. */
skip = outQ;
found = 0;
if(skip != (obuff *)0){
do {
if(skip->iosb[0] != 0){ /* Hah! It's *done* */
found = 1;
break;
}
skip = skip->fwd;
} while(skip != outQ);
}
if(!found){ /* Nothing free, malloc one */
#ifdef VMSNET_DEBUG
printf("No free obuff's, mallocing one\n");
#endif
if( (ip->outputbuff = (obuff *) malloc(sizeof(obuff)))
== (obuff *)0){
return(-1);
}
} else {
/* skip points at something we can rip out of the queue */
if(skip->fwd == skip->bck){
outQ = (obuff *)0;
} else {
(skip->bck)->fwd = skip->fwd;
(skip->fwd)->bck = skip->bck;
if(outQ == skip)
outQ = skip->fwd;
}
ip->outputbuff = skip;
}
ip->op = ip->obuf = (ip->outputbuff)->buffer;
#ifdef VMSNET_DEBUG
printf("Got new obuff for Iob on fd %d.\n",ip->fd);
#endif
return(0);
}
/* reset pointer to live Iobs for programmed traverse */
void
io_rstnxtwho()
{
nxtwhoiobptr = 0;
}
/* programmed traverse of object-IDs of logged-in players */
char
*io_nxtwho(timp)
time_t *timp;
{
if(nxtwhoiobptr > curriob || !net_initted)
return((char *)0);
while(nxtwhoiobptr <= curriob) {
if(iobtab[nxtwhoiobptr] != (Iob *)0 &&
(iobtab[nxtwhoiobptr]->flg & IOBOK) &&
(iobtab[nxtwhoiobptr]->flg & (IOBKILL|IOBERR)) == 0 &&
iobtab[nxtwhoiobptr]->who[0] != '\0') {
if(timp != (time_t *)0)
*timp = iobtab[nxtwhoiobptr]->ltim;
return(iobtab[nxtwhoiobptr++]->who);
}
nxtwhoiobptr++;
}
return((char *)0);
}