/* srvutl.c */ #define SRVUTLMASTER 1 /* * Includes */ #include #include #include "vtcpip.h" #include "dfault.h" #include "evtdef.h" #include "hstdef.h" #include "prodef.h" #include "prodat.h" #include "tcpdat.h" #include "srvutl.h" #include "svdrvr.h" #include "mapskt.h" #include "jobmon.h" #include "bytprc.h" #include "cticks.h" #include "suspnd.h" /* * debug - * * bit 0 (0x01) enable printing of internal events * bit 3 (0x08) enable ntsleep() printing * bit 4 (0x10) enable transq() printing */ int debug = 0; /* * size of timer queue */ #define NTIMES 30 /* * timer queue of events which will be placed * into the event queue when the time is up. */ static struct { int eclass, /* event queue data */ event, idata, next; /* next item in list */ long when; /* when timer is to go off */ } Stq[NTIMES]; static int Stfirst, Stfree; /* pointers for timer queue */ /* * Compute elapsed time */ long elapsed(ltm) long ltm; { long el; el = cticks(NULL)-ltm; if(el < 0) el += WRAPTIME; return(el); } /* * ntsleep * * sleep, while demuxing packets, so we don't miss anything */ int ntsleep(n) int n; { int i,nmux,redir,sknum; long start,t,el; struct socket *skt; char *pc; redir = 0; start = cticks(NULL); t = n*TICKSPERSEC; do { /* * demux all packets */ nmux = demux(1); /* * if there were packets in the incoming packet buffer, * then more might have arrived while we were processing * them. This gives absolute priority to packets coming * in from the network. */ if(nmux) continue; /* * Check for any ICMP redirect events. */ if(IREDIR==ntgtevent(ICMPCLASS,&i,&i)) redir = 1; /* * Check each socket to see if action is necessary. * This now sends all Ack packets, due to p->lasttime * being set to 0L. Waiting for nmux==0 for sending * ACKs makes sure that the network has a much higher * priority and reduces the number of unnecessary ACKs. */ for(sknum=0; sknumstate>SLISTEN) { if(skt->out.lasttime==0L) { #ifdef DEBUGOPTION if(debug&0x08) { printf("ntsleep:lasttime==0L sknum = %d\n", sknum); } #endif /* * takes care of all ACKs */ transq(skt); } else if((skt->out.rdptr!=skt->out.wtptr) || (skt->state>SEST)) { /* * if a retransmission * timeout occurs, * exponential back-off. * This number returns * toward the correct value * by the RTT measurement * code in ackcheck. */ el = elapsed(skt->out.lasttime); if(el > skt->rto) { #ifdef DEBUGOPTION if(debug&0x08) { printf("ntsleep:timeout sknum = %d\n", sknum); } #endif if(skt->rtorto<<=1; transq(skt); } } el = elapsed(skt->out.lasttime); if(el>POKEINTERVAL && skt->state==SEST) { #ifdef DEBUGOPTION if(debug&0x08) { printf("ntsleep:pokeinterval sknum = %d\n", sknum); } #endif transq(skt); } /* * check to see if ICMP redirection * occurred and needs servicing. * If it needs servicing, try to get * the new hardware address for the * new gateway. If getdlayer fails, * we assume an ARP was sent, another * ICMP redirect will occur, this * routine will reactivate, and then * the hardware address will be * available in the cache. Check all * ports to see if they match the * redirected address. */ if(redir && comparen(skt->tcpout.i.ipdest, nnsaveicmp,4)) { #ifdef DEBUGOPTION if(debug&0x08) { printf("ntsleep:icmp redirect sknum = %d\n", sknum); } #endif pc = getdlayer(nnnewicmp); if(pc!= NULL) movebytes(skt->tcpout.d.dest, pc,DADDLEN); } } } /* * reset flag for next demux */ redir = 0; /* * suspend on long waits */ if(n) { suspnd(60); } } while(elapsed(start) < t); /* * will demux once, even for sleep(0) */ return(nmux); } /* * enqueue * * Queue up data coming in from the network. * QUEUESIZE is the size limitation of the advertised window. */ int enqueue(skt,buffer,nbytes) register struct socket *skt; register char *buffer; int nbytes; { int i; i = inroom(skt); if(i<=0 || nbytes==0) /* * no room at the inn */ return(0); if(nbytes>i) nbytes = i; /* * room at end */ i = skt->in.wtptr - skt->in.where; i = QUEUESIZE - i; if(iin.wtptr,buffer,i); movebytes(skt->in.where,(char *)(buffer+i),nbytes-i); skt->in.wtptr = skt->in.where + nbytes - i; } else { movebytes(skt->in.wtptr,buffer,nbytes); if(i==nbytes) { skt->in.wtptr = skt->in.where; } else { skt->in.wtptr += nbytes; } } /* * more stuff here */ return(nbytes); } /* * dequeue * * This copies data out of the outgoing queue buffer * and then deallocates it from the queue. * * returns number of bytes copied from the queue */ int dequeue(skt,buffer,nbytes) register struct socket *skt; register char *buffer; int nbytes; { int i,qbytes; qbytes = outqlen(skt); if(qbytes==0) return(0); if(qbytesout.rdptr - skt->out.where; i = QUEUESIZE - i; if(iout.rdptr,i); movebytes((char *)(buffer+i),skt->out.where,nbytes-i); skt->out.rdptr = skt->out.where + nbytes - i; } else { movebytes(buffer,skt->out.rdptr,nbytes); if(i==nbytes) { skt->out.rdptr = skt->out.where; } else { skt->out.rdptr += nbytes; } } return(nbytes); } /* * rmqueue * * does queue deallocation * rmqueue of QUEUESIZE or greater bytes will empty the queue */ int rmqueue(skt,nbytes) register struct socket *skt; int nbytes; { int i,qbytes; qbytes = outqlen(skt); if(qbytes==0) return(0); if(qbytesout.rdptr - skt->out.where; i = QUEUESIZE - i; if(i<=nbytes) { skt->out.rdptr = skt->out.where + nbytes - i; } else { skt->out.rdptr += nbytes; } return(nbytes); } /* * transq * * Transmit the entire queue (window) to the other host without expecting * any sort of acknowledgement. */ int transq(skt) register struct socket *skt; { register unsigned int i,j,n; char *tqrdptr; unsigned int bytes,qbytes; long saveseq; if(skt==NULL) { /* * NULL port for trans */ ntposterr(406); return(-1); } /* * find out how many bytes the other side * will allow us to send (window) */ qbytes = outqlen(skt); bytes = skt->out.size; if(qbytestcpout.t.ack = longswap(skt->in.nxt); /* * is push indicator on? */ if(skt->out.push) { skt->tcpout.t.flags |= TPUSH; } else { skt->tcpout.t.flags &= ~TPUSH; } /* * is urgent flag set? */ if(skt->out.urgent) { skt->tcpout.t.flags |= TURG; } else { skt->tcpout.t.flags &= ~TURG; } /* * if no data to send . . . */ if((bytes<=0) || skt->state!=SEST) { /* * just a retransmission or ACK */ #ifdef DEBUGOPTION if(debug&0x10) { printf("transq: ack\n"); } #endif tcpsend(skt,0); return(0); } /* * we have data to send, get the correct sequence #'s * To be really real, we should check wraparound * sequence # in the loop. */ saveseq = skt->out.nxt; /* * in a loop, transmit the entire queue of data */ tqrdptr = skt->out.rdptr; for(i=0; isendsize) { n = skt->sendsize; if(i+n>bytes) n = bytes-i; j = tqrdptr - skt->out.where; j = QUEUESIZE - j; if(jtcpout.x.data,tqrdptr,j); movebytes((skt->tcpout.x.data+j),skt->out.where,n-j); tqrdptr = skt->out.where + n - j; } else { movebytes(skt->tcpout.x.data,tqrdptr,n); if(j==n) { tqrdptr = skt->out.where; } else { tqrdptr += n; } } #ifdef DEBUGOPTION if(debug&0x10) { printf("transq: seq = %ld, cnt = %d\n", skt->out.nxt,n); } #endif /* * Load urgent data pointer */ if(skt->tcpout.t.flags & TURG) { skt->tcpout.t.urgent = intswap(n); } else { skt->tcpout.t.urgent = 0; } /* * send it */ tcpsend(skt,n); skt->out.nxt += n; } #ifdef DEBUGOPTION if(debug&0x10) { printf("transq: done\n"); } #endif /* * get back first seq # */ skt->out.nxt = saveseq; return(0); } /* * comparen * * Take n bytes and return identical (true=1) or not identical (false=0) */ int comparen(s1,s2,n) register char *s1,*s2; register int n; { while (n--) if(*s1++!=*s2++) return(0); return(1); } /* * ntposterr * place an error into the event q * Takes the error number and puts it into the error structure */ void ntposterr(num) int num; { if(ntptevent(ERRCLASS,num,-1)) /* * only if we lost an event */ ntptuev(ERRCLASS,501,-1); } /* * ntgtevent * * Retrieves the next event (and clears it) which matches bits in * the given mask. Returns the event number or -1 on no event present. * Also returns the exact class and the associated integer in reference * parameters. * * The way the queue works: * There is always a dummy record pointed to by nnelast. * When data is put into the queue, it goes into nnelast, * then nnelast looks around for another empty one to obtain. * It looks at nnefree first, then bumps one from nnefirst if necessary. * When data is retrieved, it is searched from nnefirst to nnelast. * Any freed record is appended to nnefree. */ int ntgtevent(mask,retclass,retdat) int mask; int *retclass,*retdat; { int i,j; i = nnefirst; j = 0; while(i!=nnelast) { if(mask&nnq[i].eclass) { if(i==nnefirst) { /* * step nnefirst */ nnefirst = nnq[nnefirst].next; } else { /* * bypass record i */ nnq[j].next = nnq[i].next; } nnq[i].next = nnefree; /* * install in free list */ nnefree = i; #ifdef DEBUGOPTION if(debug&0x01) { printf("event: class=%d, event=%d, data=%d\r\n", nnq[i].eclass, nnq[i].event, nnq[i].idata); } #endif *retdat = nnq[i].idata; *retclass = nnq[i].eclass; return(nnq[i].event); } j = i; i = nnq[i].next; } return(0); } /* * ntptevent * * add an event to the queue. * Will probably get the memory for the entry from the free list. * Returns 0 if there was room, 1 if an event was lost. */ extern char *nterrstring(); int ntptevent(class,event,dat) int class,event,dat; { int i,jobnum; /* * The ERRCLASS and MSGCLASS events are sent to a user * if a valid socket number is specified. */ if(class&(ERRCLASS|MSGCLASS) && dat>=0) { jobnum = sktlist[dat].jobnum; sv_xmit(jobnum,class,event,dat); } i = nnelast; /* * put data in */ nnq[i].eclass = class; nnq[i].event = event; nnq[i].idata = dat; /* * there is a spot in free list */ if(nnefree>=0) { nnq[i].next = nnelast = nnefree; /* * remove from free list */ nnefree = nnq[nnefree].next; return(0); } else { nnq[i].next = nnelast = nnefirst; /* * lose oldest event */ nnefirst = nnq[nnefirst].next; return(1); } } /* * ntptuev * * put a unique event into the queue * First searches the queue for like events */ int ntptuev(class,event,dat) int class,event,dat; { int i; i = nnefirst; while(i!=nnelast) { if(nnq[i].idata==dat && nnq[i].event==event && nnq[i].eclass==class) return(0); i = nnq[i].next; } return(ntptevent(class,event,dat)); } /* * nterrstring * * returns the string associated with a particular error number * * error number is formatted %4d at the beginning of the string */ static char *errs[] = { " 0 Error unknown", /* * addsess() messages */ " 10 Require machine name/address", " 11 Querying the Domain Name Server", " 12 No name server, cannot resolve IP address", " 13 Internal Sdomain() allocation error", " 14 Trying to open TCP connection", " 15 Could not open the connection", " 16 Domain lookup failed", " 17 Domain lookup successful", /**/ " 100 Network jammed, probable break in wire", " 101 Could not initialize hardware level network driver", " 102 ERROR: The conflicting machine is using the same IP number", " 103 RARP request failed, an IP number is required", " 300 Bad IP checksum", " 301 IP packet not for me", " 302 IP packet with options received", " 303 IP: unknown higher layer protocol", " 304 IP: fragmented packet received, frags not supported", " 400 TCP: bad checksum", " 401 ACK invalid for TCP syn sent", " 403 TCP in unknown state", " 404 Invalid port for TCPsend", " 405 TCP connection reset by other host", " 406 Null port specified for ackandtrans", " 407 Packet received for invalid port -- reset sent", " 500 No internal TCP ports available", " 501 Warning: Event queue filled, probably non-fatal", " 504 Local host or gateway not responding", " 505 Memory allocation error, cannot open port", " 506 Not allowed to connect to broadcast address", " 507 Reset received: syn sent, host is refusing connection", " 600 ICMP: Echo reply", " 603 ICMP: Destination unreachable", " 604 ICMP: Source Quench", " 605 ICMP: Redirect, another gateway is more efficient", " 608 ICMP: Echo requested (ping requested)", " 611 ICMP: Time Exceeded on Packet", " 612 ICMP: Parameter problem in IP", " 613 ICMP: Timestamp request", " 614 ICMP: Timestamp reply", " 615 ICMP: Information request", " 616 ICMP: Information reply", " 699 ICMP: Checksum error", " 700 Bad UDP checksum", " 800 Domain: Name request to server failed", " 801 Domain: Using default domain", " 802 Domain: name does not exist", " 803 Domain: UDP name server did not resolve the name", " 804 Domain: name server failed, unknown reason", " 805 Host machine not in configuration file", " 806 Missing IP number, requires domain lookup", " 900 Session: Cannot find or open configuration file", " 901 Session: Cannot allocate memory for processing", " 902 Session: Invalid keyword in configuration file", " 903 Session: Element too long (>200), maybe missing quote", " 904 Session: Probable missing quote marks, place field on one line", " 905 Session: 'name' field required before other machine entries", " 906 Session: Syntax error, invalid IP number", " 907 Session: Syntax error, Subnet mask invalid", " 908 Session: Syntax error, IP address for this machine is invalid", " 909 Session: Syntax error, Invalid services request", ""}; static char errspace[80]; /* room for user-defined errors */ char *nterrstring(errno) int errno; { int i; char s[10]; if(errno<0) return(errspace); sprintf(s,"%4d",errno); i = 0; do { if(!strncmp(errs[i],s,4)) /* * pointer to error message */ return(errs[i]); i++; /* * until NULL found */ } while(*errs[i]); /* * error unknown */ sprintf(errs[0],"%4d",errno); errs[0][4] = ' '; return(errs[0]); } /* * skvalid * * Verify that the socket number is valid * and map the port for access */ struct socket *skvalid(sknum) int sknum; { if(sknum<0 || sknum>=GSCKTS || !sktlist[sknum].region) return(-1); return((struct socket *) mapskt(sknum)); } /* * skqlen * * Returns the number of bytes waiting to be * written to the network from socket sknum. * <0 if error. */ int skqlen(sknum) int sknum; { register struct socket *skt; /* * check validity */ skt = (struct socket *) skvalid(sknum); if(skt==-1) return(-2); return(outqlen(skt)); } int outqlen(skt) register struct socket *skt; { register int diff; diff = skt->out.wtptr - skt->out.rdptr; if(diff>=0) { return(diff); } else { return(diff+QUEUESIZE); } } /* * skroom * * Returns the number of bytes left in * the incoming queue for socket sknum. * <0 if error. */ int skroom(sknum) int sknum; { register struct socket *skt; /* * check validity */ skt = (struct socket *) skvalid(sknum); if(skt==-1) return(-2); if(skt->state!=SEST) return(-1); return(inroom(skt)); } int inroom(skt) register struct socket *skt; { register int diff; diff = skt->in.wtptr - skt->in.rdptr; if(diff>=0) { return(QUEUESIZE-1-diff); } else { return(-1-diff); } } /* * ntstip * * Set a new ip number. This goes through and * changes all sorts of ip numbers. * * This routine assumes that there are currently NO open tcp connections. */ VOID ntstip(st) register char *st; { /* * Change all dependent locations relating to * the IP number, don't worry about open connections, * they must be closed by higher layer. */ /* * main ip number */ movebytes(nnipnum,st,4); /* * arp */ movebytes(arp.spa,nnipnum,4); /* * ip source */ movebytes(ipblank.i.ipsource,nnipnum,4); /* * udp source */ movebytes(ulist.tcps.source,nnipnum,4); /* * more udp source */ movebytes(ulist.udpout.i.ipsource,nnipnum,4); } /* * ntgtip * * Sets *st* to the current ip number */ VOID ntgtip(st) register char *st; { movebytes(st,nnipnum,4); } /* * ntstmask * * Set the network mask. */ VOID ntstmask(st) register char *st; { movebytes(nnmask,st,4); } /* * ntgtmask * * Get the network mask. */ VOID ntgtmask(st) register char *st; { movebytes(st,nnmask,4); } /* * ntlisten * * Listen to a TCP port number and make the connection automatically when * the SYN packet comes in. The TCP layer will notify the higher layers * with a CONOPEN event. * * example usage : ntlisten ( sknum ) * * Returns<0 if error * * Note: Most parameters have been initialized * by makesocket() for TCP connections, all others * are zero. */ int ntlisten(sknum) int sknum; { register struct socket *skt; skt = (struct socket *) skvalid(sknum); if(skt == -1) return(-1); if(skt->sktport) { /* * Use specified port number */ skt->in.port = sktlist[sknum].inport = skt->sktport; skt->tcpout.t.source = intswap(skt->sktport); } /* * Set socket state */ skt->state = SLISTEN; /* * return the socket port number */ return(skt->sktport = skt->in.port); } /* * ntxopen * * Open a network socket for the user to *machine* using port *service*. * The rest of the parameters are self-explanatory. * * Note: Most parameters have been initialized * by makesocket() for TCP connections, all others * are zero. */ int ntxopen(sknum,machine,service,rto,mtu,mseg,mwin) int sknum; char *machine; unsigned int service,rto,mtu,mseg,mwin; { register struct socket *skt; int i; unsigned int seg; char destip[4]; char *pc,*hiset; /* * make a copy of the ip number that we are trying for */ movebytes(destip,machine,4); /* * check the IP number and don't allow broadcast addresses */ if((destip[3]&0xFF)==0xFF || !destip[3]) { printf("%d.%d.%d.%d\n", destip[0] & 0xFF, destip[1] & 0xFF, destip[2] & 0xFF, destip[3] & 0xFF); ntposterr(506); return(-4); } /* * get the hardware address for that host, or use the one * for the gateway all handled by 'ntdlayer' by ARPs. */ pc = ntdlayer(destip); /* * cannot connect to local machine */ if(pc==NULL) { ntposterr(504); return(-2); } /* * set up socket structure after call to ntdlayer */ skt = (struct socket *) mapskt(sknum); /* * copy the ip number that we are trying for */ movebytes(skt->tcpout.i.ipdest,destip,4); movebytes(skt->tcps.dest,destip,4); /* * load ether address */ movebytes(skt->tcpout.d.dest,pc,DADDLEN); /* * starting retrans timeout */ if(rto>MINRTO) skt->rto = rto; /* * largest packet space we have */ if(mtusendsize = mtu; /* * buffer size is the limit */ if(mwincredit = mwin; /* * don't bother to ARP */ i = cachelook(nnipnum,0,0); /* * if it is not -1, we are in trouble */ if(i >= 0) { hiset = (char *)arpc[i].hrd; pc = nterrstring(-1); sprintf(pc, "Conflict with Ethernet hardware address: %02x-%02x-%02x-%02x-%02x-%02x", hiset[0] & 0xFF, hiset[1] & 0xFF, hiset[2] & 0xFF, hiset[3] & 0xFF, hiset[4] & 0xFF, hiset[5] & 0xFF); ntposterr(-1); ntposterr(102); ntclose(sknum); return(-3); } /* * try to make the connection, we will get an event notification * later if it connects. Timeouts must be done at a higher layer. */ /* * Set flags and state */ skt->tcpout.t.flags = TSYN; skt->state = SSYNS; /* * set service port */ skt->tcpout.t.dest = intswap(service); skt->out.port = sktlist[sknum].outport = service; movebytes(sktlist[sknum].remoteip,destip,4); /* * allow from port to be forced */ i = skt->skfport; if(i) { skt->tcpout.t.source = intswap(i); skt->in.port = sktlist[sknum].inport = i; } /* * install maximum segment size other than default maximum */ seg = intswap(mseg); movebytes((char *)&skt->tcpout.x.options[2],(char *)&seg,2); tcpsend(skt,4); skt->tcpout.t.hlen = 20<<2; skt->out.nxt += 1; return(sknum); } /* * nt2open * * Send out repeat SYN on a connection which is not open yet. * This checks to make sure if it is actually needed. * Timing is handled at a higher layer. * * Returns 1 if the state is still at SYNS other wise 0 * if connection is proceeding. */ int nt2open(sknum) int sknum; { register struct socket *skt; /* * check validity */ skt = (struct socket *) skvalid(sknum); if(skt == -1) return(-1); if(skt->state != SSYNS) return(0); /* * The connection has not proceeded to further states, * try retransmission */ skt->out.nxt--; skt->tcpout.t.hlen = 24<<2; tcpsend(skt,4); skt->tcpout.t.hlen = 20<<2; skt->out.nxt++; return(1); } /* * ntabort * * Abort clients and their connections */ VOID ntabort() { int j; register int i; register struct socket *skt; for(i=0; istate!=SCLOSED) { sv_xmit(j,ABORTCLASS,CLIENT,i); ntclose(i); } } } } /* * ntclose * * Start the closing process on socket sknum. */ int ntclose(sknum) int sknum; { register struct socket *skt; skt = (struct socket *) skvalid(sknum); if(skt == -1) return(-1); switch (skt->state) { case SLISTEN: case SSYNS: skt->state = SCLOSED; break; case SSYNR: case SEST: skt->tcpout.t.flags = TFIN|TACK; tcpsend(skt,0); skt->state = SFW1; break; case SCWAIT: skt->tcpout.t.flags = TFIN|TACK; tcpsend(skt,0); skt->state = SLAST; break; case STWAIT: if(elapsed(skt->out.lasttime) > WAITTIME) skt->state = SCLOSED; break; case SLAST: if(elapsed(skt->out.lasttime) > LASTTIME) skt->state = SCLOSED; break; default: break; } return(0); } /* * ntinit () * * Handles all the initialization to bring up the network connection. * Assumes that the configuration file has already been read up. * (called from Snetinit () ) * * Returns 0 on successful initialization. */ int ntinit() { int ret; /* * Initializes all buffers and hardware for data link layer. * Machine/board dependent. */ ret = dlinit(); if(ret) { printf("Board initialization failed!. Error code=%d\n", ret); ntposterr(101); return(ret); } /* * initialize the template packets needed for transmission */ protinit(); return(0); } /* * ntshut () * * Shut down the hardware. This tries to close any active * connections and then turn off the hardware ( via dlshut ) */ VOID ntshut() { int sknum; for(sknum=0; sknummpp; if(!m || m->mstat < HAVEIP) return(-1); /* * First setup retransmit time */ i = m->retrans; if(i < 2*TICKSPERSEC) i = 2*TICKSPERSEC; /* * do the open call */ j = ntxopen(sknum,m->hostip,tport,i,m->mtu,m->maxseg,m->window); if(j >= 0) { Stmrset(CONCLASS,CONFAIL,sknum,m->conto); Stmrset(SCLASS,RETRYCON,sknum,i/TICKSPERSEC); } return(j); } /* * Stask * * A higher level version of net sleep -- manages the timer queue. * Always call this in your main loop. */ static long recent = 0L; VOID Stask() { long t; int i; /* * Check the timer queue to see if something should be posted * First check for timer wraparound */ t = cticks(NULL); if(t=0) { Stq[i].when -= WRAPTIME; i = Stq[i].next; } } recent = t; /* * Q is not empty and timer is going off */ while (Stfirst >= 0 && t > Stq[Stfirst].when) { i = Stfirst; ntptevent(Stq[i].eclass,Stq[i].event,Stq[i].idata); /* * remove from q */ Stfirst = Stq[Stfirst].next; Stq[i].next = Stfree; /* * add to free list */ Stfree = i; } } /* * Stmrset * * Set an async timer which is checked in Stask -- when time elapses * sticks an event in the network event queue * * class, event, dat is what gets posted when howlong times out. */ int Stmrset(class,event,dat,howlong) int class,event,dat,howlong; { int i,j,jlast,retval; long gooff; retval = 0; gooff = cticks(NULL)+howlong*TICKSPERSEC; /* * queue is full, post first event */ if(Stfree < 0) { Stfree = Stfirst; Stfirst = Stq[Stfirst].next; Stq[Stfree].next = -1; ntptevent( Stq[Stfree].eclass, Stq[Stfree].event, Stq[Stfree].idata); retval = -1; } /* * event to occur at that time */ Stq[Stfree].idata = dat; Stq[Stfree].event = event; Stq[Stfree].eclass = class; Stq[Stfree].when = gooff; /* * remove from free list */ i = Stfree; Stfree = Stq[i].next; if(Stfirst < 0) { /* * if no queue yet anchor active q */ Stfirst = i; Stq[i].next = -1; } else /* * goes first on list at beginning of list */ if(gooff < Stq[Stfirst].when) { Stq[i].next = Stfirst; Stfirst = i; } else { /* * goes in middle * search q from beginning */ j = jlast = Stfirst; while (gooff >= Stq[j].when&&j >= 0) { jlast = j; j = Stq[j].next; } /* * insert in q */ Stq[i].next = j; Stq[jlast].next = i; } return(retval); } /* * Stmrunset * * Remove all timer events from the queue * that match the class/event/dat. */ int Stmrunset(class,event,dat) int class,event,dat; { int i,ilast,retval; retval = ilast = -1; i = Stfirst; /* * search list */ while (i >= 0 ) { if(Stq[i].idata == dat && Stq[i].eclass == class && Stq[i].event == event) { /* * found at least one */ retval = 0; if(i == Stfirst) { /* * first one matches * attach to free list */ Stfirst = Stq[i].next; Stq[i].next = Stfree; Stfree = i; i = Stfirst; /* * start list over */ continue; } else { /* * remove this entry * attach to free list */ Stq[ilast].next = Stq[i].next; Stq[i].next = Stfree; Stfree = i; i = ilast; } } ilast = i; i = Stq[i].next; } return(retval); } /* * Sgetevent * * Gets events from the network and filters those for session related */ int Sgetevent(mask,retclass,retdat) int mask; register int *retclass,*retdat; { int retval; /* * session event */ if(retval = ntgtevent(SCLASS,retclass,retdat)) { switch (retval) { case UDPTO: /* name server not responding */ domto(*retdat); break; case RETRYCON: /* * connection open yet? */ if(0 < nt2open(*retdat)) /* * 5 is a kludge */ Stmrset(SCLASS,RETRYCON,*retdat,5); break; default: break; } } /* * allow messages */ mdemux(1); /* * allow job monitor */ jdemux(1); /* * allow net */ ntsleep(0); /* * allow timers */ Stask(); if(!(retval = ntgtevent(mask,retclass,retdat))) return(0); /* * kill this timer */ if((retval==CONOPEN) && (*retclass==CONCLASS)) Stmrunset(CONCLASS,CONFAIL,*retdat); if((*retdat==997) && (retval==UDPDATA) && (*retclass==USERCLASS)) { udpdom(); } else { /* * let higher layer have it */ return(retval); } return(0); } /* * jbminit * * Initialize the job monitor handler */ VOID jbminit() { /* * Initialize the job monitor handler */ jobmon(0,4); } /* * jdemux * * Find the job termination messages in the buffer, queue up all classes. * * The 'all' parameter tells jdemux whether it should attempt to empty * the termination message buffer or return after the first useful message * is queued. * * returns the number of messages queued */ int jdemux(all) register int all; { register int nmuxed; register int i,j; nmuxed = 0; /* * while all flag is on */ do { /* * Check for job terminations */ if((j = jbabrt()) != 0) { nmuxed++; for(i=0; iclass,pkt->event,pkt->data); nmuxed++; } } while(all); return(nmuxed); }