/* Copyright (C) 1991, Marcus J. Ranum. All rights reserved. */ #ifndef lint static char RCSid[] = "$Header: /usr/users/mjr/hacks/umud/RCS/net.c,v 1.9 91/09/19 12:56:06 mjr Exp $"; #endif /* configure all options BEFORE including system stuff. */ #include "config.h" #ifdef NOSYSTYPES_H #include <types.h> #else #include <sys/types.h> #endif #include <errno.h> extern int errno; #include <stdio.h> #include <ctype.h> #include <varargs.h> #include <fcntl.h> #include <sys/file.h> #include <sys/time.h> #include <sys/signal.h> #include <sys/socket.h> #include <netinet/in.h> #include "mud.h" #include "vars.h" #ifndef FD_SET #define NBBY 8 #define NFDBITS (sizeof(long) * NBBY) #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) #endif /* 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 */ /* 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. */ #define IOBFL 010 /* Too many chars. Flush it. */ typedef struct { int flg; /* flags */ char *host; /* name of player's host */ 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 */ } 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 **WHOlist; /* Ordered WHO list */ static int WHOlast = -1; /* Last active iob in WHOlist */ 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 fd_set liveset; /* set of live Iobs for select() */ static struct timeval timo; /* timeout value */ 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 nxtwhoiobptr; /* used for programmed Iob traverse */ /* set up the iob tables, iob maps, sockets, the whole bit */ io_init() { int x; signal(SIGPIPE,SIG_IGN); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; timo.tv_sec = cron_quantum; timo.tv_usec = 0; /* 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 = getdtablesize(); /* initialize the Iob hash table */ iobtab = (Iob **)malloc((unsigned)(sizeof(Iob *) * iobtabsiz)); if(iobtab == (Iob **)0) return(1); WHOlist = (Iob **)malloc((unsigned)(sizeof(Iob *) * iobtabsiz)); if(WHOlist == (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); x = 1; setsockopt(serfd,SOL_SOCKET,SO_REUSEADDR,&x,sizeof(x)); 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); } /* OPEN PLAYER ACCESS FILE DESCRIPTOR AND BIND IT */ if((plyfd = socket(AF_INET,SOCK_STREAM,0)) < 0) return(1); x = 1; setsockopt(plyfd,SOL_SOCKET,SO_REUSEADDR,&x,sizeof(x)); 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); } /* VITAL! */ FD_SET(plyfd,&liveset); FD_SET(serfd,&liveset); curriob = plyfd; net_initted++; return(0); } /* disconnect an Iob (low level) */ static void iobdrop(ip) Iob *ip; { int x; Pmap *pp; Pmap *pr; if(ip == (Iob *)0) return; /* Blow it out of WHO list */ for(x = 0; x <= WHOlast; x++){ if(WHOlist[x] == ip){ if(x < WHOlast) bcopy(&WHOlist[x+1],&WHOlist[x], (WHOlast - x)*sizeof(Iob *)); else WHOlist[x] = (Iob *)0; WHOlast--; break; } } if (ip->who[0]) { plogf("DISCONNECT %s on %d from %s\n", ip->who, ip->fd, ip->host ? ip->host : "unknown"); #ifdef USE_RWHO rwhocli_userlogout(ip->who); #endif } else plogf("DISCONNECT %d from %s\n", ip->fd, ip->host ? ip->host : "unknown"); for(x = 0; x < iobtabsiz; x++) { if(iobtab[x] == ip) { iobtab[x] = (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 */ if(ip->fd == curriob) curriob--; /* mark it dead in the live Iob set */ FD_CLR(ip->fd,&liveset); /* final cleanup */ (void)shutdown(ip->fd,2); (void)close(ip->fd); if(ip->host != (char *)0) (void)free((mall_t)ip->host); (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; if(i->flg & IOBFL){ /* If we're supposed to flush */ i->flg &= ~IOBFL; return((char *)0); } else { return(op); } } if((*i->ip == '\n' || *i-> ip == '\r') && ic > 0) { *i->ip++ = '\0'; if((i->ic = --ic) < 1) i->ip = i->ibuf; if(i->flg & IOBFL){ /* If we're supposed to flush */ i->flg &= ~IOBFL; return((char *)0); } else { return(op); } } /* nothing left in buffer, but no newline */ if(--ic <= 0) { if(i->ic >= MUDBUF - 1){ /* Too Much! */ i->ip = i->ibuf; i->ic = 0; /* Are we already flushing? */ if(i->flg & IOBFL){ return((char *)0); } else { /* set up to flush until EOLN */ i->flg |= IOBFL; *(i->ibuf + (MUDBUF-1)) = '\0'; return(i->ibuf); } } /* shift down */ bcopy(op,i->ibuf,i->ic); /* resync */ i->ip = i->ibuf; /* i->ic = 0; Why is this here? -- Andrew */ return((char *)0); } if(!isprint(*i->ip)) *i->ip = ' '; i->ip++; } } /* flush a single Iob doing the select there significantly increases the system call overhead of the MUD, as opposed to doing nonblocking I/O. but that's life. */ static int iobflush(ip) Iob *ip; { static char buff_over[] = "\n<buffer overrun>\n"; fd_set wfd; struct timeval wtimo; int xx = ip->op - ip->obuf; int wr; if(ip->flg & IOBERR) return(1); FD_ZERO(&wfd); FD_SET(ip->fd,&wfd); wtimo.tv_sec = 0; wtimo.tv_usec = 800; if(select(ip->fd + 1,(fd_set *)0,&wfd,(fd_set *)0,&wtimo) != 1 || !FD_ISSET(ip->fd,&wfd)) { if(xx < MUDBUF) return(0); /* scrubba buffa */ bcopy(buff_over,ip->obuf,sizeof(buff_over)); ip->op = ip->obuf + sizeof(buff_over); return(0); } if((wr = write(ip->fd,ip->obuf,xx)) != xx) { /* partial write. god damn */ if(wr > 0) { bcopy(ip->obuf + wr,ip->obuf,xx - wr); ip->op -= wr; return(0); } if(wr < 0 && errno == EWOULDBLOCK) { if(xx >= MUDBUF) { /* scrubba buffa */ bcopy(buff_over,ip->obuf,sizeof(buff_over)); ip->op = ip->obuf + sizeof(buff_over); } return(0); } /* fukit */ ip->flg |= IOBERR; return(1); } ip->op = ip->obuf; 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); } /* flush the connected (valid) Iobs */ void io_sync() { int n; time_t now = (time_t)0; 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) { 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); } 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]); continue; } /* timeout logins */ if(!(iobtab[n]->flg & IOBOK)) { if(now == (time_t)0) time(&now); if(now - iobtab[n]->ctim > 80) iobdrop(iobtab[n]); } } } onewrt = 1; lastiob = (Iob *)0; } /* 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.\n",(char *)0); /* logf("badlogin: ",line,"\n",(char *)0); */ plogf("badlogin: %s on %d from %s\n", line, bp->fd, bp->host ? bp->host : "unknown"); return; } if(hv == -1) { plogf("killconnection: '%s' on %d from %s\n", line, bp->fd, bp->host ? bp->host : "unknown"); bp->flg |= IOBKILL; onewrt = 2; return; } bp->flg |= IOBOK; /* Stuff this Iob into the WHO list */ WHOlist[++WHOlast] = bp; /* 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 from %s\n", bp->who, bp->fd, bp->host ? bp->host : "unknown"); 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() { fd_set redy; fd_set xcpt; Iob *bp; int n; int seld; int rd; char *lp; time_t now; static char *log_connect(); char *host; if(!net_initted) return(-1); /* sleep quantum may have changed */ timo.tv_sec = cron_quantum; bcopy(&liveset,&redy,sizeof(redy)); bcopy(&liveset,&xcpt,sizeof(xcpt)); if((seld = select(curriob + 1,&redy,(fd_set *)0,&xcpt,&timo)) < 0) { if(errno != EINTR) { logf("select in loop failed: ",(char *)-1,"\n",0); return(1); } } /* yawn */ if(seld <= 0) return(0); /* start the clock */ (void)time(&now); /* new SERVER TO SERVER connection */ if(FD_ISSET(serfd,&redy)) { n = accept(serfd,(struct sockaddr *)0,(int *)0); /* xact_in() handles *everything* including closing fd */ if(n != -1) { #ifdef SO_LINGER #ifdef hpux /* * HP-UX (release 7.0 B on a 9000/330, at least) claims to default to no- * lingering and, in any case, has a different syntax for passing the * linger value to setsockopt(). Don't use it. * --- warlock */ #undef SO_LINGER #endif /* hpux */ struct linger ling; ling.l_onoff = 0; ling.l_linger = 0; setsockopt(n,SOL_SOCKET,SO_LINGER,&ling,sizeof(ling)); #endif host = log_connect(n,"server"); if(host != (char *)0) /* Toss the host in this case */ free(host); xact_in(n); } } /* new PLAYER connection */ if(FD_ISSET(plyfd,&redy)) { n = accept(plyfd,(struct sockaddr *)0,(int *)0); if(n != -1) { #ifdef SO_LINGER struct linger ling; ling.l_onoff = 0; ling.l_linger = 0; setsockopt(n,SOL_SOCKET,SO_LINGER,&ling,sizeof(ling)); #endif host = log_connect(n, "user"); if(fcntl(n,F_SETFL,FNDELAY)) { logf("cannot set NDELAY: ",(char *)-1,"\n",0); goto mainloop; } bp = (Iob *)malloc(sizeof(Iob)); if(bp == (Iob *)0) { logf("cannot alloc Iob: ",(char *)-1,"\n",0); return(-1); } bp->host = host; 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((bp->obuf = (char *)malloc(MUDBUF)) == (char *)0) return(-1); bp->op = bp->obuf; if(n > curriob) curriob = n; /* enter it into our live set */ FD_SET(n,&liveset); iobtab[n] = bp; /* I added this next little block so I could display a file before the character logs in. Ed Hand 6/26/91*/ { FILE *cfl; char cbuf[BUFSIZ]; if((cfl = fopen("NEWS/connect.txt","r")) != (FILE *)0) { while(fgets(cbuf,sizeof(cbuf),cfl) != (char *)0) iobsay(bp,cbuf,(char *)0); (void)fclose(cfl); } } iobsay(bp,"c[onnect] objectid password\n",(char *)0); } } mainloop: /* check input on existing fds. */ for(n = 0; n <= curriob; n++) { if((bp = iobtab[n]) != (Iob *)0 && FD_ISSET(n,&redy)) { rd = read(bp->fd,bp->ibuf + bp->ic,MUDBUF - bp->ic - 1); 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); } continue; } /* lastly, check exceptions in case of no input */ if(FD_ISSET(n,&xcpt)) { if(n == serfd) fatal("server service fd died!!\n",(char *)0); if(n == plyfd) fatal("player service fd died!!\n",(char *)0); /* default case */ if(bp != (Iob *)0) { bp->flg |= IOBERR | IOBKILL; onewrt = 2; } continue; } } /* e! */ return(0); } /* ARGSUSED */ cmd__netconfig(argc,argv,who,aswho) int argc; char *argv[]; char *who; char *aswho; { 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); } /* set time-out of select (to match quantum?) */ if(!strcmp(argv[1],"looptime")) { int tmpx; if(argc < 3 || (tmpx = atoi(argv[2])) <= 0) { logf(badp,(char *)0); return(1); } timo.tv_sec = tmpx; logf("loop timeout is ",argv[2]," seconds\n",(char *)0); return(0); } if(!strcmp(argv[1],"help")) { say(who,argv[0]," playport port-number\n",(char *)0); say(who,argv[0]," servport port-number\n",(char *)0); say(who,argv[0]," looptime seconds\n",(char *)0); return(0); } logf("_netconfig: I don't understand ",argv[1],"\n",(char *)0); return(0); } static cmd_WHO__format(buffer,flg,name,curtime,ltime,objname,host) char *buffer; int flg; char *name; char *objname; time_t curtime; time_t ltime; char *host; { int ct_hours, ct_mins, ct_secs, lt_hours, lt_mins, lt_secs; char oidb[MAXOID+3]; ct_hours = curtime / 3600; ct_mins = (curtime % 3600) / 60; ct_secs = curtime % 60; lt_hours = ltime / 3600; lt_mins = (ltime % 3600) / 60; lt_secs = ltime % 60; if(host == (char *)0) host = "unknown"; if(flg){ /* Wiz WHO thang */ oidb[0] = '('; strncpy(oidb+1,objname,MAXOID); strcat(oidb,")"); sprintf(buffer, "%-17.17s %3d:%02d:%02d %3d:%02d:%02d %-18.18s %-18.18s\n", name, ct_hours, ct_mins, ct_secs, lt_hours, lt_mins, lt_secs, oidb,host); } else { /* Regular WHO */ sprintf(buffer,"%-17.17s %3d:%02d:%02d %3d:%02d:%02d (%s)\n", name, ct_hours, ct_mins, ct_secs, lt_hours, lt_mins, lt_secs, objname); } } /* TCP version of WHO */ /* ARGSUSED */ cmd_WHO(argc,argv,who,aswho) int argc; char *argv[]; char *who; char *aswho; { int x; int jj; int wiz; time_t now; char xuf[180]; if(!net_initted) return(1); wiz = ut_flagged(aswho,var_wiz); (void)time(&now); say(who,"Player Name On For Idle\n",(char *)0); if(argc < 2) { for(x = 0; x <= WHOlast; x++) { cmd_WHO__format(xuf,wiz, ut_name(WHOlist[x]->who), (now - WHOlist[x]->ctim), (now - WHOlist[x]->ltim), WHOlist[x]->who, WHOlist[x]->host); say(who,xuf,(char *)0); } say(who,"There are ",itoa(WHOlast + 1,xuf), " players connected.\n",(char *)0); return(0); } for(jj = 1; jj < argc; jj++ ) { char *na; for(x = 0; x <= WHOlast; x++) { na = ut_name(WHOlist[x]->who); if(na != (char *)0 && matchstr(na,argv[jj],0) != 0) { cmd_WHO__format(xuf,wiz, ut_name(WHOlist[x]->who), (now-WHOlist[x]->ctim), (now-WHOlist[x]->ltim), WHOlist[x]->who, WHOlist[x]->host); say(who,xuf,(char *)0); } } say(who,"There are ",itoa(WHOlast + 1,xuf), " players connected.\n",(char *)0); } 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]->ctim; return(iobtab[nxtwhoiobptr++]->who); } nxtwhoiobptr++; } return((char *)0); } /* Log (via logf) the essential statistics of a new connection. */ #include <netdb.h> static char * log_connect(fd, desc) int fd; char *desc; { struct sockaddr_in sin; extern char *inet_ntoa(); char *t; char *name; int sin_len; #ifndef NO_HUGE_RESOLVER_CODE struct hostent *hp; #endif sin_len = sizeof(sin); if (getpeername(fd, (struct sockaddr *) &sin, &sin_len) < 0) { plogf("ACCEPT [%s] getpeername failed! on %d\n", desc, fd); return((char *)0); } #ifndef NO_HUGE_RESOLVER_CODE hp = gethostbyaddr((char *)&sin.sin_addr, sizeof(struct in_addr), AF_INET); if (hp != (struct hostent *)0) { plogf("ACCEPT [%s] from %s on %d\n", desc, hp->h_name, fd); if((name = (char *)malloc(strlen(hp->h_name)+1)) == (char *)0) return((char *)0); strcpy(name,hp->h_name); return(name); } #endif t = inet_ntoa(sin.sin_addr); if (t == (char *)0) { plogf("ACCEPT [%s] inet_ntoa failed! on %d\n", fd); return((char *)0); } plogf("ACCEPT [%s] from %s on %d\n", desc, t, fd); if((name = (char *)malloc(strlen(t)+1)) == (char *)0) return((char *)0); strcpy(name,t); return(name); }