🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: vmsnet.sources
Article #105

XSCOPE/VMS 1.0, part 02/08

#105
From: Patrick L. Mahan - TGV Window Wa...
Date: Fri, 04 Sep 1992 05:34
1744 lines
50234 bytes
Submitted-by: mahan@tgv.com (Patrick L. Mahan - TGV Window Washer)
Posting-number: Volume 3, Issue 154
Archive-name: xscope/part02


-+-+-+-+-+-+-+-+ START OF PART 2 -+-+-+-+-+-+-+-+
X    `09if ((!caddr) `7C`7C (!*caddr)) return 0;
X    `09if (strchr(caddr, '.')) return 0;
X    `09for ( a = caddr; *a; a++)
X    `09`09if((*a < '0') `7C`7C (*a > '9')) return 0;
X    `09if (a == caddr) return 0;
X#ifdef DNDEBUG
X    `09fprintf(stderr, "isEtherAddr: %s is an ethernet address\n",caddr);
X#endif
X    `09return 1;
X    `09`09
X`7D
X
X`0C
X/*
X * isDnetAddr
X * Boolean routine to determine if a passed client node name
X * is a valid DECnet address.
X */
Xint
XisDnetAddr (caddr)
X    `09char *caddr;
X`7B
X    `09if (strchr(caddr, '.')) return 1;
X    `09return 0;
X`7D
X
X`0C
X/*
X * issueNetCmdRead
X * Reading from the Network Command Mailbox willbe done on the mbxChannel, b
Vut
X * will be treated as a read in the NET: channel, since it is the channel th
Vat the
X * upper layer sees.
X */
Xint
XissueNetCmdRead (chan)
X`09unsigned short chan;
X`7B
X    `09int status;
X
X    `09if (!ChanTableInfo`5B(mbxChannel>>4)`5D->readAstPend)
X    `09`7B
X#ifdef DNDEBUG
X    `09`09fprintf(stderr, "issueNetCmdRead: read pending on channel %d from
V chan %d\n", mbxChannel, chan);
X#endif
X    `09`09ChanTableInfo`5B(mbxChannel>>4)`5D->readAstPend = 1;
X        `09status = SYS$QIO (0, mbxChannel, IO$_READVBLK, &netiosb, &netCmdA
Vst, NET_CMD,
X                                &nb, mbxMsgLen, 0, 0, 0, 0);
X    `09`09if (VMSFAIL(status)) LIB$SIGNAL(status);
X    `09`7D
X    `09return status;
X`7D
X
X`0C
X/*
X * issueRead (chan)
X * Routine to setup a read AST on the passed channel.  In our emulation
X * we must check the channel's buffers to see if any remaining data is left
X * to be read.  In the case that there is some remainder, the routine will`2
V0
X * "fake" an AST event by shoving interrupt information in the stack.  Other
Vwise
X * the routine sets up the AST normally with the buffer being the base of th
Ve`20
X * vm area setup.
X */
Xint
XissueRead (chan)
X`09unsigned short chan;
X`7B
X`09astParam ap;
X`09int shiftChan = chan>>4;
X`09char *vmbase = ChanTableInfo`5BshiftChan`5D->base;
X`09char *vmdelta = ChanTableInfo`5BshiftChan`5D->delta;
X`09int vmlen = ChanTableInfo`5BshiftChan`5D->len;
X`09int remainder = (vmbase + vmlen) - vmdelta;
X    `09int status;
X/*`20
X * Insert a fake result in the stack if there is unread data in our channel'
Vs buffer.`20
X * Then return without setting up the read attention AST QIO.
X */
X`09if (remainder > 0)
X`09`7B
X`09`09stack`5BstackIndex`5D.channel = chan;
X`09`09stack`5BstackIndex`5D.type = NET_RD;
X`09`09stackIndex++;
X`09`09ChanTableInfo`5B(chan>>4)`5D->readAstPend = 0;
X`09`09ChanTableInfo`5B(chan>>4)`5D->readAstDone = 1;
X#ifdef DNDEBUG
X`09`09fprintf(stderr, "issueRead: (puesdoread) to channel %d remainder %d\n"
V, chan, remainder);
X#endif
X`09`09return SS$_NORMAL;
X`09`7D
X        ChanTableInfo`5BshiftChan`5D->base = vmbase;
X        ChanTableInfo`5BshiftChan`5D->delta = vmdelta = vmbase;
X        ChanTableInfo`5BshiftChan`5D->len = vmlen = 0;
X
X`09ap.ast.type = NET_RD;
X`09ap.ast.chan = chan;
X
X#ifdef DNDEBUG
X    `09fprintf(stderr, "issueRead: read pending on channel %d\n", chan);
X#endif
X`09ChanTableInfo`5BshiftChan`5D->readAstDone = 0;
X`09ChanTableInfo`5BshiftChan`5D->readAstPend = 1;
X        status = SYS$QIO (0, chan, IO$_READVBLK, &ChanTableInfo`5BshiftChan`
V5D->read_iosb,`20
X`09`09`09&readAst, ap.astid, vmbase, MAX_QIO, 0, 0, 0, 0);
X    `09if (VMSFAIL(status)) LIB$SIGNAL(status);
X`7D
X
X`0C
X/*
X * linkInit
X * Routine to intercept the network message and parse it into a node name.
X */
Xvoid
XlinkInit ()
X`7B
X`09int i = nb.mbxMsg`5B0`5D + 1;
X`09int start = i + 1;
X
X`09info_cnt = nb.mbxMsg`5Bi`5D;
X`09ncb = &nb.mbxMsg`5Bstart`5D;
X`7D
X
X`0C
X/*
X * linkTerm
X * Routine to terminate a link (low level - socket_close is high level) give
Vn
X * a channel spec or the network message block's unit number.
X */
Xvoid
XlinkTerm(sChan)
X`09unsigned short sChan;
X`7B
X`09int status;
X`09unsigned short channel;
X`09unsigned short next;
X`09int currChannel;
X`09int i;
X
X    `09next = 0;
X`09if (sChan)
X    `09`7B
X    `09`09if (!ChanTableInfo`5BsChan`5D) return;
X    `09`09if (((sChan<<4) == netChannel) && (lisChannel)) netChannel = lisCh
Vannel;
X        `09if (ChanTableInfo`5BsChan`5D->chanDassgn) return;
X`09`09next = sChan;
X`09`09goto bash;
X`09`7D
X`09for (i = 0; i < (FD_SETSIZE/NFDBITS); i++)
X`09`7B
X`09`09currChannel = (int) allChannels->bits`5Bi`5D;
X`09`09while (currChannel)
X`09`09`7B
X`09`09`09next = (ffs(currChannel) - 1) + (i * NFDBITS);
X`09`09`09if (ChanTableInfo`5Bnext`5D->unit == nb.unit) goto bash;
X`09`09`09currChannel &= `7E(1 << next);
X`09`09`7D
X`09`7D
Xbash:
X`09if ((!next) `7C`7C (next > FD_SETSIZE))
X    `09`09return;
X`09else
X`09`7B
X`09`09channel = next<<4;
X#ifdef DNDEBUG
X`09`09fprintf(stderr, "linkTerm: terminating link to %d\n",channel);
X#endif
X`09`09status = SYS$DASSGN (channel);
X`09`09if (VMSFAIL(status)) LIB$SIGNAL(status);
X        `09ChanTableInfo`5Bnext`5D->chanDassgn = 1;
X`09`7D
X`7D
X
X`0C
X/*
X * nameFromPort
X * A hack to translate the passed port number to a DECnet OBJECT name. Its u
Vgly
X * but hey, who asked you?
X */
Xstruct dsc$descriptor
X*nameFromPort (sa)
X`09struct sockaddr *sa;
X`7B
X`09union
X`09`7B
X`09`09unsigned short port;
X`09`09char t`5B2`5D;
X`09`7D temp;
X    `09int i = 0;
X
X`09temp.t`5B0`5D = sa->sa_data`5B1`5D;
X`09temp.t`5B1`5D = sa->sa_data`5B0`5D;
X    `09for (i = 0; i < Number(transTable); i++)
X    `09`7B
X    `09`09if (transTable`5Bi`5D.port == temp.port)
X    `09`09`7B
X    `09`09`09if (transTable`5Bi`5D.port = X11_PORT)
X`09`09`09`09x11_dsc.dsc$a_pointer`5B3`5D = 0x30;
X    `09`09`09return transTable`5Bi`5D.object;
X        `09`7D
X    `09`7D
X/*
X * Of course - the obligatory special case: used when someone tries to`20
X * access a X11 "reserved" port 6001-9 (beyond 6009, I don't care!)
X */
X`09if ((temp.port > X11_PORT) && (temp.port < X11_PORT + 10))
X`09`7B
X`09`09x11_dsc.dsc$a_pointer`5B3`5D = ((temp.port - X11_PORT) + 0x30);
X`09`09return &x11_dsc;
X`09`7D`20
X`09fprintf (stderr, "nameFromPort: unrecognized port request: %d\n");
X`09return NULL;
X`7D
X
X`0C
X/*
X * NCPpredicate
X * Routine that is passed to qsort.
X */
Xstatic int
XNCPpredicate (c1, c2)
X    `09NCPstruct *c1;
X    `09NCPstruct *c2;
X`7B
X    `09return (memcmp (c1->nodebuf, c2->nodebuf, MAX(strlen(c1->nodebuf), st
Vrlen(c2->nodebuf))));
X`7D
X
X`0C
X/*
X * NCPinit()
X * Routine to load the NCP table of node/addresses from its data base using
V the Network
X * File Block (NFB$) defined constants for node and address matching of the
V on-line`20
X * data base.
X */
Xint
XNCPinit()
X`7B
X    `09int`09i;
X    `09int`09j;
X    `09int`09add;
X    `09int`09retLen = 0;
X    `09int`09status;
X    `09int`09seg = MAXDNETNODES + 1;
X`09unsigned short netNCPChan;
X    `09struct io_stat_blk iosb;
X    `09char `09*delta;
X    `09struct nfbdef nfb = `7B NFB$C_FC_SHOW, 0, NFB$C_DB_NDI, NFB$C_OP_EQL,
X    `09`09`09      NFB$C_WILDCARD, NFB$C_WILDCARD, 0, 0, 0,
X    `09`09`09      NFB$C_NDI_NNA, NFB$C_NDI_TAD, NFB$C_ENDOFLIST `7D;
X    `09struct dsc$descriptor nfbDes = `7Bsizeof(nfb), 0, 0, &nfb`7D;
X    `09char *keyArea = DNETALLOC(NFB$C_CTX_SIZE);
X    `09struct dsc$descriptor kaDes = `7BNFB$C_CTX_SIZE, 0, 0, keyArea`7D;
X    `09char *bufArea = DNETALLOC(BUF_QUO);
X    `09struct dsc$descriptor bufDes = `7BBUF_QUO, 0, 0, bufArea`7D;
X    `09struct nfbdef1 *prm;
X    `09struct nfbdef2 *val;
X
X    `09i = 0;
X/*
X * Assign a temporary channel to _NET: to return NCP db info
X */
X`09status = SYS$ASSIGN (&net_device, &netNCPChan, 0, 0);
X`09if (VMSFAIL(status)) LIB$SIGNAL(status);
X    `09LIB$MOVC5 (&zero, NULL, "\0", &kaDes, keyArea);
X        status = SYS$QIOW (0, netChannel, IO$_ACPCONTROL, &iosb, 0, 0,`20
X    `09`09&nfbDes, &kaDes, &retLen, &bufDes, 0, 0);
X    `09if (!VMSFAIL(status)) status = iosb.status;
X    `09if ((VMSFAIL(status)) && (status != SS$_ENDOFFILE)) LIB$SIGNAL(status
V);
X/*
X * Main loop for calling ACPCONTROL on the _NET: device, returning database
V information.
X */
X    `09while (status != SS$_ENDOFFILE)
X    `09`7B
X        `09delta = bufArea;
X    `09`09if (seg > MAXDNETNODES)`09`09/* add memory in puesdo realloc mode
V */
X    `09`09`7B
X    `09`09`09NCPstruct *tmp = (NCPstruct *)`20
X    `09`09`09`09DNETALLOC((i+MAXDNETNODES)*sizeof(NCPstruct));
X    `09`09`09if(!tmp) exit(SS$_INSFMEM);
X    `09`09`09if (pNCP)
X    `09`09`09`7B
X   `09`09`09`09bcopy ((char *) pNCP, (char *) tmp, sizeof(NCPstruct) * i);
X   `09`09`09`09DNETFREE(pNCP);
X    `09`09`09`7D
X   `09`09`09pNCP = tmp;
X    `09`09`09seg = 0;
X    `09`09`7D
X/*
X * Loop through the NFB records that the NETACP passed back to this routine.
X */
X    `09`09for (j = 0; nfb.fldid`5Bj`5D != NFB$C_ENDOFLIST; ++j)
X    `09`09`7B
X    `09`09`09add = 0;
X    `09`09`09prm = (struct nfbdef1 *) &nfb.fldid`5Bj`5D;
X    `09`09`09val = (struct nfbdef2 *) delta;
X    `09`09`09switch (prm->overlay.fields.typ)
X    `09`09`09`7B
X    `09`09`09case NFB$C_TYP_BIT:
X    `09`09`09case NFB$C_TYP_LNG:
X`09`09`09`09pNCP`5Bi`5D.area = (short) (val->overlay.lngValue / 1024);
X`09`09`09`09pNCP`5Bi`5D.node = (short) (val->overlay.lngValue % 1024);
X    `09`09`09`09add = sizeof(long);
X    `09`09`09`09break;
X    `09`09`09case NFB$C_TYP_STR:
X    `09`09    `09`09pNCP`5Bi`5D.nodebuf = DNETALLOC (NODNAMSIZ);
X    `09`09`09`09bcopy (&val->overlay.string.strText, pNCP`5Bi`5D.nodebuf,
X    `09`09`09`09`09val->overlay.string.strCount);
X    `09`09`09`09pNCP`5Bi`5D.nodebuf`5Bval->overlay.string.strCount`5D = 0x0;
X    `09`09`09`09add = val->overlay.string.strCount + sizeof(short);
X    `09`09`09`09break;
X    `09`09`09default:
X    `09`09`09`09fprintf(stderr, "NCPinit: unrecognized %d\n",val->overlay.ln
VgValue);
X    `09`09`09`09add = sizeof(long);
X    `09`09`09`7D
X    `09`09`09delta += add;
X    `09`09`7D
X#ifdef NCPDEBUG
X       `09`09fprintf(stderr, "NCPinit: %d.%d: %s\n",pNCP`5Bi`5D.area, pNCP`5
VBi`5D.node, pNCP`5Bi`5D.nodebuf);
X#endif /* NCPDEBUG */
X    `09`09i++;
X    `09`09seg++;
X        `09status = SYS$QIOW (0, netNCPChan, IO$_ACPCONTROL, &iosb, 0, 0,`20
X    `09`09`09&nfbDes, &kaDes, &retLen, &bufDes, 0, 0);
X    `09`09if (!VMSFAIL(status)) status = iosb.status;
X    `09`09if ((VMSFAIL(status)) && (status != SS$_ENDOFFILE)) LIB$SIGNAL(sta
Vtus);
X`09`7D
X/*
X * Hopefully we have some nodes here to sort...
X */
X    `09if (i)
X    `09`7B
X    `09`09NCPtot = i;
X    `09`09qsort ((char *) pNCP, NCPtot, sizeof(NCPstruct), NCPpredicate);
X    `09`09SYS$DASSGN (netNCPChan);
X#ifdef NCPDEBUG
X    `09`09fprintf(stderr, "NCPinit: %d nodes found\n", NCPtot);
X#endif
X    `09`7D
X    `09else
X    `09`09fprintf(stderr, "NCPinit: no nodes found!\n");
X`7D
X
X`0C
X/*
X * NCPfind
X * Ah, the luscious jewel of the Nile, itself!  This baby looks up a given n
Vode id
X * in the NCP table (built in NCPinit()).  The id can be in one of three for
Vms:
X * 1) DECnet Node Name - Phase IV has a max of 6 characters
X * 2) DECnet Node Address - up to the max of 63.1023
X * 3) Unknown Node Address - this sucker comes from the active ethernet addr
Vess.
X *    It is composed of all numbers (illegal for a node name spec).  The rtn
V can
X *    translate this address to become a DECnet Node Address type above.  Th
Ve fact
X *    that a node comes in as a hybrid active ethernet address name portends
V that
X *    the node is not known by NCP.
X * The routine returns a binary value of the address in the sockaddr passed
V area and
X * the resolved node name/address in "client".
X */
Xint
XNCPfind (sChan, psock, client)
X    `09unsigned short sChan;
X    `09char`09*psock;
X    `09char `09*client;
X`7B
X    `09int `09status;
X    `09int `09i;
X    `09short `09node;
X    `09short`09area;
X    `09int`09result;
X    `09int`09last;
X    `09int`09strt;
X    `09char `09*b1;
X    `09char `09*b2;
X    `09char `09*aoff;
X    `09static NCPstruct dum = `7BNULL, 0, 0`7D;
X    `09NCPstruct *pNCPf;
X    `09struct sht
X    `09`7B
X    `09`09union
X    `09`09`7B
X    `09`09`09struct chs
X    `09`09`09`7B
X    `09`09`09`09char c1;
X    `09`09`09`09char c2;
X    `09`09`09`7Dc;
X    `09`09`09short s1;
X    `09`09`7Do;
X    `09`7Ds;
X
X    `09if (!pNCP) NCPinit();
X    `09if (sChan)
X    `09`7B
X    `09`09aoff = (char *) (psock + sizeof(long));
X    `09`09if (ChanTableInfo`5BsChan`5D)
X    `09`09`7B
X    `09`09`09if (ChanTableInfo`5BsChan`5D->node + ChanTableInfo`5BsChan`5D->
Varea)
X    `09`09`09`7B
X        `09`09`09if (ChanTableInfo`5BsChan`5D->nodename)
X    `09`09`09`09`7B
X   `09`09     `09`09`09bcopy (ChanTableInfo`5BsChan`5D->nodename, client,`20
X    `09`09`09`09`09`09strlen(ChanTableInfo`5BsChan`5D->nodename)+1);
X    `09`09`09`09`09client`5Bstrlen(ChanTableInfo`5BsChan`5D->nodename)`5D =
V 0x0;
X    `09`09`09`09`7D
X   `09 `09`09`09else
X   `09 `09`09`09`09sprintf (client, "%d.%d", ChanTableInfo`5BsChan`5D->area,
V`20
X    `09`09`09`09`09`09ChanTableInfo`5Bi`5D->node);
X        `09`09`09bcopy ((char *) &ChanTableInfo`5BsChan`5D->area, aoff, size
Vof(short));
X   `09 `09`09`09bcopy ((char *) &ChanTableInfo`5BsChan`5D->node,`20
X    `09`09`09`09`09(char *) (aoff + sizeof(short)), sizeof(short));
X    `09`09`09`09return 0;
X    `09        `09`7D
X        `09`7D
X    `09`7D
X    `09else
X    `09`09aoff = psock;
X    `09if ((!client) `7C`7C (!*client)) fprintf(stderr, "NCPaddr: error no c
Vlient spec in call\n");
X`09upper(client);
X    `09if (strchr(client, ':')) *((char *) strchr(client, ':')) = '\0';
X    `09if (isEtherAddr(client)) `09/* it's an active ethernet hybrid address
V */
X    `09`7B
X    `09`09result = atoi(client);
X    `09`09DNETFREE(client);
X    `09`09client = DNETALLOC(NODNAMSIZ);
X    `09`09sprintf(client, "%d.%d", result/1024, result % 1024);
X    `09`7D
X    `09if (isDnetAddr(client)) `09/* it's a DECnet address (eg., "1.22") */
X    `09`7B
X    `09`09b1 = client;
X    `09`09b2 = strchr (client, '.');
X    `09`09*b2++ = 0x0;
X    `09`09area = (short) atoi(b1);
X    `09`09node = (short) atoi(b2);
X`09`09sprintf (client, "%d.%d", area, node);
X    `09`09for (i = 0; i < NCPtot; i++)
X    `09`09`7B
X    `09`09`09if ((pNCP`5Bi`5D.area == area) && (pNCP`5Bi`5D.node == node)) b
Vreak;
X        `09`7D
X    `09`7D
X    `09else `09`09`09`09/* it's a node name (eg., "NCD999") */
X    `09`7B
X    `09`09dum.nodebuf = client;
X    `09`09i = -1;
X    `09`09if((pNCPf = (NCPstruct *) bsearch (&dum, pNCP, NCPtot,`20
X    `09`09`09sizeof(NCPstruct), NCPpredicate)))
X    `09`09`09i = (pNCPf - pNCP);
X    `09`7D
X/*
X * We should now have either a valid index into the NCP table or a indicatio
Vn that
X * the node name/address is not currently known by this host node.
X */
X`09if ((i > -1) && (i < NCPtot))
X    `09`7B
X    `09`09if (pNCP`5Bi`5D.nodebuf)
X        `09`09bcopy (pNCP`5Bi`5D.nodebuf, client, strlen(pNCP`5Bi`5D.nodebuf
V)+1);
X    `09`09else
X    `09`09`09sprintf (client, "%d.%d", pNCP`5Bi`5D.area, pNCP`5Bi`5D.node);
X    `09`09bcopy ((char *) &pNCP`5Bi`5D.area, aoff, sizeof(short));
X    `09`09bcopy ((char *) &pNCP`5Bi`5D.node, (char *) (aoff + sizeof(short))
V, sizeof(short));
X    `09`09if (sChan && ChanTableInfo`5BsChan`5D)
X    `09`09`7B
X    `09`09`09if (!ChanTableInfo`5BsChan`5D->nodename)`20
X    `09`09`09`09ChanTableInfo`5BsChan`5D->nodename = DNETALLOC(NODNAMSIZ);
X    `09`09`09bcopy (client, ChanTableInfo`5BsChan`5D->nodename, strlen(clien
Vt) + 1);
X    `09`09`09ChanTableInfo`5BsChan`5D->nodename`5Bstrlen(client)`5D = 0x0;
X    `09`09`09ChanTableInfo`5BsChan`5D->node = pNCP`5Bi`5D.node;
X    `09`09`09ChanTableInfo`5BsChan`5D->area = pNCP`5Bi`5D.area;
X    `09`09`7D
X    `09`09return 0;
X    `09`7D
X    `09else
X    `09`7B
X    `09`09fprintf(stderr, "NCPfind: %s not found in node lookup\n",client);
X    `09`09return -1;
X    `09`7D
X`7D
X
X`0C
X/*
X * netCmdAst
X * AST routine the fires for incoming network messages.
X */
Xvoid
XnetCmdAst (type)
X`09int type;
X`7B
X`09int i;
X`09int start;
X
X    `09ChanTableInfo`5B(mbxChannel>>4)`5D->readAstPend = 0;
X`09stack`5BstackIndex`5D.channel = netChannel;
X`09stack`5BstackIndex`5D.type = NET_CMD;
X`09stackIndex++;
X`09WAKE_UP_DAMMIT;
X`7D
X
X`0C
Xvoid
XnotUsed()
X`7B
X`09fprintf (stderr, "Unused message %d detected\n", nb.netCmd);
X`7D
X
X`0C
X/*
X * processNetCmd
X * Routine to process a network message.
X */
Xint
XprocessNetCmd (pChan)
X    `09unsigned short *pChan;
X`7B
X    `09unsigned short sChan = ((*pChan)>>4);
X/*
X * Note that the current netChannel could have disappeared during the interi
Vm (as
X * with an xscope connect()ed link with the X11 server), so that issuing the
V netcmd read
X * using that channel would be invalid on the next network directive.  There
Vfore, there
X * must be a provision for testing the passed channel information.
X */
X    `09if (!ChanTableInfo`5BsChan`5D)
X    `09`7B
X    `09`09if (lisChannel)`20
X    `09`09`09*pChan = lisChannel;
X    `09`09else
X    `09`09`09fprintf(stderr, "processNetCmd: error on invalid netChannel %d\
Vn", *pChan);
X    `09`7D
X/* Reissue on the passed or updated channel */
X`09issueNetCmdRead (*pChan);
X#ifdef DNDEBUG
X    `09fprintf(stderr, "processNetCmd: netiosb: %d status: %d\n", netiosb.ms
Vg_len, netiosb.status);
X#endif
X
X`09switch (nb.netCmd)
X`09`7B
X`09`09case MSG$_CONNECT    :`09
X#ifdef DNDEBUG
X    `09`09`09`09`09fprintf(stderr, "Link init\n");
X#endif
X    `09`09`09`09`09linkInit (); return 1; break;
X                case MSG$_ABORT      :
X                case MSG$_DISCON     :
X                case MSG$_EXIT       :
X                case MSG$_PATHLOST   :
X                case MSG$_PROTOCOL   :
X                case MSG$_THIRDPARTY :
X                case MSG$_TIMEOUT    :`09
X#ifdef DNDEBUG
X    `09`09`09`09`09fprintf(stderr, "processNetCmd: linkTerm\n");
X#endif
X`09`09`09`09`09linkTerm ((unsigned short) 0); break;
X                case MSG$_NETSHUT    :`09fprintf (stderr, "DECnet shutdown d
Vetected - exiting\n");`20
X`09`09`09`09`09exit(1);
X                case MSG$_CONFIRM    : `20
X#ifdef DNDEBUG
X    `09`09`09`09`09fprintf(stderr, "Connection confirmed\n");`20
X#endif
X    `09`09`09`09`09break;
X                case MSG$_INTMSG     :  break;
X                case MSG$_REJECT     :  break;
X                default              :`09notUsed(); break;
X`09`7D
X`09return 0;
X`7D
X
X`0C
X/* readAst (ap)
X * AST routine to update the stack, increment the channel's length variable,
X * and wake up the server.
X */
Xint
XreadAst (ap)
X`09struct astblk ap;
X`7B
X    `09unsigned short sChan = ap.chan>>4;
X
X    `09if (ChanTableInfo`5BsChan`5D)
X    `09`7B
X    `09`09stack`5BstackIndex`5D.channel = ap.chan;
X    `09`09stack`5BstackIndex`5D.type = ap.type;
X`09`09stackIndex++;
X`09`09ChanTableInfo`5BsChan`5D->len = ChanTableInfo`5BsChan`5D->read_iosb.ms
Vg_len;
X`09`09ChanTableInfo`5BsChan`5D->readAstPend = 0;
X`09`09ChanTableInfo`5BsChan`5D->readAstDone = 1;
X    `09`09WAKE_UP_DAMMIT;
X    `09`7D
X`7D
X
X`0C
X/*
X * timeoutAst
X * Routine that fires after the select() timer expires.
X */
Xvoid
XtimeoutAst()
X`7B
X`09timerExpired = 1;
X`09WAKE_UP_DAMMIT;
X`7D
X
X`0C
X/*
X * upper
X * Routine to convert a NUL terminated string to uppercase.
X */
Xvoid
Xupper (s)
X        char    *s;
X`7B
X        int     i;
X        char    *tp;
X
X        for (i = 0, tp = s; i < strlen(s); i++, tp++)
X                if (islower(*tp)) *tp = toupper(*tp);
X`7D
X
X`0C
X/*
X * EMULATION ROUTINES
X */
X
X`0C
X/*
X * accept():
X * Module to emulate the "acceptance" of a connection over a "listen()"ing c
Vhannel.
X * In the current paradigm, only one listening channel is supported (called
V "lisChannel");
X * even though the actual network command(s) arrive over the channel assigne
Vd to the`20
X * network command mailbox (w/ the NET: device; called "mbxChannel").  The "
Vchan" being
X * passed to this and all other socket emulation routines dealing with netwo
Vrk issues (i.e.,
X * the only non-client channel) is the listening channel established in sock
Vet().  All
X * references to the Net Command Mailbox channel are internal to this librar
Vy, and`20
X * are opaque to the upper layer program.
X */
Xunsigned short
Xaccept (chan, psock, psock_l)
X`09unsigned short chan;
X`09struct sockaddr *psock;
X`09long psock_l;
X`7B
X        int status;
X`09int dvi_unit;
X`09unsigned short channel;
X`09unsigned short sChan;
X`09struct io_stat_blk iosb;
X`09struct dsc$descriptor_s ncbd;
X`09struct`20
X`09`7B
X`09`09short buf_len;
X`09`09short code;
X`09`09int *ret_code;
X`09`09int ret_len;
X`09`09int term;
X`09`7D dviitm = `7B 4, DVI$_UNIT, &dvi_unit, 0, 0`7D;
X
X#ifdef DNDEBUG
X    `09fprintf(stderr, "accept: start - passed chan %d\n", chan);
X#endif /* DNDEBUG */
X`09if (!ncb)`20
X`09`7B
X`09`09fprintf (stderr, "accept: no ncb received!\n");
X`09`09return -1;
X`09`7D
X`09ncb`5Binfo_cnt`5D = '\0';
X        ncbd.dsc$w_length = info_cnt;
X        ncbd.dsc$a_pointer = ncb;
X        ncbd.dsc$b_dtype = DSC$K_DTYPE_T;
X        ncbd.dsc$b_class = DSC$K_CLASS_S;
X
X    `09if (!mbx_created)
X    `09`7B
X    `09`09fprintf(stderr, "accept: error - mailbox not created yet\n");
X    `09`09exit();
X    `09`7D
X        status = SYS$ASSIGN (&net_device, &channel, 0, &netcmd_mbx);
X`09if (VMSFAIL(status)) LIB$SIGNAL(status);
X`09status = SYS$GETDVI (0, channel, 0, &dviitm, &iosb, 0, 0, 0);
X`09if (VMSFAIL(status)) LIB$SIGNAL(status);
X    `09sChan = channel>>4;
X`09clearChanTable ((sChan));
X`09ChanTableInfo`5B(sChan)`5D->unit = dvi_unit;
X`09ChanTableInfo`5B(sChan)`5D->nodename = DNETALLOC (NODNAMSIZ);
X`09bcopy ((char *) ncb, ChanTableInfo`5B(sChan)`5D->nodename, info_cnt);
X    `09ChanTableInfo`5B(sChan)`5D->user = (strchr(ChanTableInfo`5B(sChan)`5D
V->nodename, '=') + 1);
X    `09*((char *) strchr(ChanTableInfo`5B(sChan)`5D->nodename,':') + 2) = '\
V0';
X    `09*((char *) strchr(ChanTableInfo`5B(sChan)`5D->user,'/')) = '\0';
X`09FD_SET(channel, allChannels);
X#ifdef DNDEBUG
X`09fprintf(stderr, "accept: from Node: %s User: %s on channel %d\n",
X    `09`09ChanTableInfo`5B(sChan)`5D->nodename, ChanTableInfo`5B(sChan)`5D->
Vuser, channel);
X#endif
X        status = SYS$QIOW (0, channel, IO$_ACCESS, &iosb, 0, 0, 0, &ncbd, 0,
V 0, 0, 0);
X`09if(!VMSFAIL(status) && !VMSFAIL(iosb.status))
X`09`7B
X`09`09ncb = NULL;
X`09        return channel;
X`09`7D
X`09if (VMSFAIL(status)) LIB$SIGNAL (status);
X`09if (VMSFAIL(iosb.status)) LIB$SIGNAL(iosb.status);
X`09return -1;
X`7D
X
X`0C
X/*
X * B routines: bcmp, bcopy, bzero
X * These routines are declared here in function form to provide
X * a global linker resolution for references in upper level code.
X */
Xint
Xbcmp (s1, s2, l)
X`09char *s1;
X`09char *s2;
X`09int l;
X`7B
X`09return (BCMP(s1, s2, l));
X`7D
X
X`0C
Xvoid *
Xbcopy (s, d, l)
X`09char *s;
X`09char *d;
X`09int l;
X`7B
X`09return BCOPY(s, d, l);
X`7D
X
X`0C
X/*
X * bind():
X * bind the NET channel to the correct object name.
X */
Xint
Xbind (chan, sa, sa_len)
X`09unsigned short chan;
X`09struct sockaddr *sa;
X`09unsigned int sa_len;
X`7B
X`09int status;
X`09struct io_stat_blk iosb;
X`09struct dsc$descriptor_s nfbd;
X`09struct dsc$descriptor_s *object_name;
X
X#ifdef DNDEBUG
X    `09fprintf(stderr, "bind: start - passed chan %d\n", chan);
X#endif /* DNDEBUG */
X        nfbd.dsc$w_length = sizeof(nfb);
X        nfbd.dsc$a_pointer = &nfb;
X        nfbd.dsc$b_dtype = DSC$K_DTYPE_T;
X        nfbd.dsc$b_class = DSC$K_CLASS_S;
X/*
X * Bind to the declare channel in the ChanTableInfo struct.
X */
X`09object_name = nameFromPort (sa);
X`09status = SYS$QIOW (0, chan, IO$_ACPCONTROL, &iosb, 0, 0, &nfbd, object_na
Vme, 0, 0, 0, 0);
X`09if (VMSFAIL(status) `7C`7C VMSFAIL(iosb.status)) return -1;
X#ifdef DNDEBUG
X    `09fprintf(stderr, "bind: on channel %d to %s\n", chan, object_name->dsc
V$a_pointer);
X#endif
X`09return 0;
X`7D
X
X`0C
Xint
Xbzero (buf, size)
X`09char *buf;
X`09int size;
X`7B
X`09return (BZERO(buf, size));
X`7D
X
X`0C
X#ifdef NOTDEF
X/*
X * connect():
X * supports connecting to a "socket" given the network channel (from socket(
V))
X */
Xint
Xconnect (chan, name, namelen)
X`09unsigned short chan;
X`09struct sockaddr *name;
X`09unsigned int namelen;
X`7B
X`09int`09`09status;
X`09unsigned short`09objlen;
X`09char *pncb;
X`09struct dsc$descriptor ncb_desc;
X`09static struct io_stat_blk iosb;
X`09struct dsc$descriptor_s *objdsc;
X    `09static char *objstr = NULL;
X    `09char hname`5B32`5D;
X    `09int l = 0;
X
X#ifdef DNDEBUG
X    `09fprintf(stderr, "connect: start - passed chan %d\n", chan);
X#endif /* DNDEBUG */
X    `09if (!objstr) objstr = DNETALLOC(NCBSIZE);
X        if (!(pncb = initNCB(name, &objlen, TASKOBJECT, NULL)))`20
X    `09`7B
X    `09`09char *a = objstr;
X    `09`09short *area = &name->sa_data`5B2`5D;
X    `09`09short *node = &name->sa_data`5B4`5D;
X
X       `09`09objdsc = nameFromPort (name);
X    `09`09BCOPY(TASKOBJECT, a, strlen(TASKOBJECT));
X    `09`09a += strlen(TASKOBJECT);
X    `09`09BCOPY(objdsc->dsc$a_pointer, a, strlen(objdsc->dsc$a_pointer));
X    `09`09a+= strlen(objdsc->dsc$a_pointer);
X    `09`09*a = 0x0;
X    `09`09sprintf (hname, "%d.%d::", *area, *node);
X    `09`09pncb = initNCB(name, &objlen, objstr, hname);
X    `09`7D
X    `09ncb_desc.dsc$w_length = objlen;
X        ncb_desc.dsc$a_pointer = pncb;
X        ncb_desc.dsc$b_dtype = DSC$K_DTYPE_T;
X        ncb_desc.dsc$b_class = DSC$K_CLASS_S;
X
X        status = SYS$QIOW (0, chan, IO$_ACCESS, &iosb, 0, 0, 0, &ncb_desc, 0
V, 0, 0, 0);
X        if (!VMSFAIL(status)) status = iosb.status;
X        if (!VMSFAIL(status))
X`09`7B
X#ifdef DNDEBUG
X`09`09fprintf(stderr, "connect: Connection to %s on channel %d\n", pncb, cha
Vn);
X#endif
X    `09`09DNETFREE (pncb);
X                return 0;
X`09`7D
X        else
X                LIB$SIGNAL (status);
X`09DNETFREE (pncb);
X`09return -1;
X`7D
X#endif /* NOTDEF */
X
X`0C
X/*
X * connect():
X * supports connecting to a "socket" given the network channel (from socket(
V))
X */
Xint
Xconnect (chan, name, namelen)
X        unsigned short chan;
X        struct sockaddr *name;
X        unsigned int namelen;
X`7B
X        int             status;
X        unsigned short  objlen;
X        char *pncb;
X        struct dsc$descriptor ncb_desc;
X        static struct io_stat_blk iosb;
X        struct dsc$descriptor_s *objdsc;
X        char *objstr = DNETALLOC(NCBSIZE);
X        char *hname;
X        int l = 0;
X        char *a;
X        short *port = &name->sa_data`5B0`5D;
X        short *area = &name->sa_data`5B2`5D;
X        short *node = &name->sa_data`5B4`5D;
X
X#ifdef DNDEBUG
X        fprintf(stderr, "connect: start - passed chan %d port %d addr %d.%d\
Vn",
X                chan, *port, *area, *node);
X#endif /* DNDEBUG */
X        BCOPY (TASKOBJECT, objstr, strlen(TASKOBJECT));
X        hname = NULL;
X        if ((objdsc = nameFromPort (name)))
X        `7B
X                hname = DNETALLOC(32);
X                a = objstr + strlen(TASKOBJECT);
X                BCOPY(objdsc->dsc$a_pointer, a, strlen(objdsc->dsc$a_pointer
V));
X                a+= strlen(objdsc->dsc$a_pointer);
X                *a = 0x0;
X                sprintf (hname, "%d.%d::", *area, *node);
X        `7D
X        pncb = initNCB(name, &objlen, objstr, hname);
X        if (hname) DNETFREE(hname);
X        ncb_desc.dsc$w_length = objlen;
X        ncb_desc.dsc$a_pointer = pncb;
X        ncb_desc.dsc$b_dtype = DSC$K_DTYPE_T;
X        ncb_desc.dsc$b_class = DSC$K_CLASS_S;
X
X        status = SYS$QIOW (0, chan, IO$_ACCESS, &iosb, 0, 0, 0, &ncb_desc, 0
V, 0, 0, 0);
X        if (!VMSFAIL(status)) status = iosb.status;
X        if (!VMSFAIL(status))
X        `7B
X#ifdef DNDEBUG
X                fprintf(stderr, "connect: Connection to %s on channel %d\n",
V pncb, chan);
X#endif
X                DNETFREE (pncb);
X                return 0;
X        `7D
X        else
X                LIB$SIGNAL (status);
X        DNETFREE (pncb);
X        return -1;
X`7D
X
X`0C
X/*
X * ffs
X * Emulates the find first set function for UNIX.
X */
Xint
Xffs (lw)
X`09int lw;
X`7B
X`09int fp;
X`09int sp = 0;
X`09int status;
X`09int sz = sizeof(lw)*BITSPERBYTE;
X
X`09status = lib$ffs(&sp, &sz, &lw, &fp);
X`09if (VMSFAIL(status))
X`09`7B
X`09`09LIB$SIGNAL(status);
X`09`09exit();
X`09`7D
X`09return ++fp;
X`7D
X
X`0C
X/*
X * getdtablesize
X * Routine to return the given size of the file descriptor table (channel ta
Vble).
X */
Xint
Xgetdtablesize()
X`7B
X`09return FD_SETSIZE;  /* *** should be CHANNELCNT in SYSGEN */
X`7D
X
X`0C
X/*
X * gethostbyaddr
X * Socket library emulation routine to return the host name given a (DECnet)
X * network address.
X */
Xstruct hostent *
Xgethostbyaddr (addr, length, family)
X`09unsigned char *addr;
X`09unsigned int length;
X`09unsigned int family;
X`7B
X`09static struct hostent *t = NULL;
X
X#ifdef DNDEBUG
X    `09fprintf(stderr, "gethostbyaddr: start\n");
X#endif /* DNDEBUG */
X    `09if (!t)
X    `09`7B
X    `09`09t = DNETALLOC (sizeof(struct hostent));
X    `09`09t->h_name = DNETALLOC(NODNAMSIZ);
X`09`09t->h_aliases = NULL;
X    `09`09t->h_addrtype = AF_DECnet;`20
X`09`09t->h_length = sizeof(long);
X`09`09t->h_addr_list = DNETALLOC (sizeof(long));
X`09`09t->h_addr_list`5B0`5D = DNETALLOC (sizeof(long));
X`09`09t->h_cputype = DNETALLOC (strlen(CPUTYPE)+1);
X`09`09t->h_opsys = DNETALLOC (strlen(OPSYS)+1);
X`09`09bcopy (CPUTYPE, t->h_cputype, strlen(CPUTYPE));
X`09`09bcopy (OPSYS, t->h_opsys, strlen(OPSYS));
X    `09`7D
X#ifdef DNDEBUG
X    `09fprintf (stderr, "gethostbyaddr: DECnet address %d.%d\n",`20
X    `09`09(short) *addr, (short) (*(addr+sizeof(short))));
X#endif
X    `09sprintf (t->h_name, "%d.%d", (short) *addr, (short) *(addr+sizeof(sho
Vrt)));
X    `09if (NCPfind (0, t->h_addr_list`5B0`5D, t->h_name) < 0)
X    `09`7B
X    `09`09h_errno = HOST_NOT_FOUND;
X    `09`09return 0;
X    `09`7D
X`09return t;
X`7D
X
X`0C
X/*
X * gethostbyname
X * Routine to return the network address of a given node name.
X */
Xstruct hostent *
Xgethostbyname (name)
X`09char *name;
X`7B
X`09static struct hostent *t = NULL;
X
X#ifdef DNDEBUG
X    `09fprintf(stderr, "gethostbyname: start\n");
X#endif /* DNDEBUG */
X    `09if (!t)
X    `09`7B
X    `09`09t = DNETALLOC (sizeof(struct hostent));
X    `09`09t->h_name = DNETALLOC(NODNAMSIZ);
X`09`09t->h_aliases = NULL;
X`09`09t->h_addrtype = AF_DECnet;
X`09`09t->h_length = sizeof(long);
X`09`09t->h_addr_list = DNETALLOC (sizeof(long));
X`09`09t->h_addr_list`5B0`5D = DNETALLOC (sizeof(long));
X`09`09t->h_cputype = DNETALLOC (strlen(CPUTYPE)+1);
X`09`09t->h_opsys = DNETALLOC (strlen(OPSYS)+1);
X`09`09bcopy (CPUTYPE, t->h_cputype, strlen(CPUTYPE));
X`09`09bcopy (OPSYS, t->h_opsys, strlen(OPSYS));
X    `09`7D
X`09bcopy (name, t->h_name, strlen(name)+1);
X    `09if (NCPfind (0, t->h_addr_list`5B0`5D, t->h_name) < 0)
X    `09`7B
X    `09`09h_errno = HOST_NOT_FOUND;
X    `09`09return 0;
X    `09`7D
X`09return t;
X`7D
X
X`0C
X/*
X * gethostname
X * Routine to return the host node name.
X */
Xint
Xgethostname (hname, l)
X    `09char *hname;
X    `09int l;
X`7B
X        short retlen = 0;
X
X        unsigned short iosb`5B4`5D;
X        struct
X            `7B
X            unsigned short id_buflen;
X            unsigned short id_itmcod;
X            int *id_scsid;
X            unsigned short *id_retlen;
X            int listend;
X            `7D itmlst = `7Bl, SYI$_NODENAME, hname, &retlen, 0`7D;
X
X#ifdef DNDEBUG
X    `09fprintf(stderr, "gethostname: start\n");
X#endif /* DNDEBUG */
X        SYS$GETSYIW (0, 0, 0, &itmlst, iosb, 0, 0);
X        hname`5Bretlen`5D = '\0';
X`09return 0;
X`7D
X
X`0C
X/*
X * getpeername
X * Routine to return the node address (DECnet) associated with a given chann
Vel.
X */
Xint
Xgetpeername (chan, psock, psock_l)
X`09unsigned short chan;
X`09struct sockaddr *psock;
X`09long *psock_l;
X`7B
X    `09unsigned short sChan = chan>>4;
X
X#ifdef DNDEBUG
X    `09fprintf(stderr, "getpeername: start\n");
X#endif /* DNDEBUG */
X`09psock->sa_family = AF_DECnet;
X    `09if (!ChanTableInfo`5BsChan`5D) return -1;
X    `09*psock_l = sizeof(long);
X`09return NCPfind (sChan, psock, ChanTableInfo`5BsChan`5D->nodename);
X`7D
X
X`0C
X/*
X * gettimeofday
X * Routine to return the time in secs and millisecs
X */
Xint
Xgettimeofday (timev)
X`09struct timeval *timev;
X`7B
X`09static timeb_t t;
X
X#ifdef DNDEBUG
X    `09fprintf(stderr, "gettimeofday: start\n");
X#endif /* DNDEBUG */
X`09ftime (&t);
X`09timev->tv_sec = t.time;
X`09timev->tv_usec = t.millitm * 1000;
X
X`09return 0;
X`7D
X
X`0C
Xint
Xhtonl (i)
X`09int i;
X`7B
X        int t1;
X`09int t2;
X
X        t2 = i;`20
X        ((char *)&t1)`5B0`5D = ((char *)&t2)`5B3`5D;
X`09((char *)&t1)`5B1`5D = ((char *)&t2)`5B2`5D;
X        ((char *)&t1)`5B2`5D = ((char *)&t2)`5B1`5D;
X`09((char *)&t1)`5B3`5D = ((char *)&t2)`5B0`5D;
X
X`09return t1;
X`7D
X
X`0C
Xunsigned short
Xhtons (i)
X`09unsigned short i;
X`7B
X        unsigned short t1;
X`09unsigned short t2;
X
X        t2 = i;
X        ((char *)&t1)`5B0`5D = ((char *)&t2)`5B1`5D;
X`09((char *)&t1)`5B1`5D = ((char *)&t2)`5B0`5D;
X
X        return t1;
X`7D
X
X`0C
X/*
X * inet_addr
X * Routine to translate the network address into a longword value.
X */
Xint
Xinet_addr (address)
X`09char *address;
X`7B
X`09char`09*a;
X`09char`09*b`5B4`5D;
X    `09char `09*tmpvm;
X`09int`09i;
X`09int`09j = 0;
X`09int`09out;
X
X#ifdef DNDEBUG
X    `09fprintf(stderr, "inet_addr: start\n");
X#endif /* DNDEBUG */
X    `09if(isalpha(*address)) return -1;
X`09b`5Bj++`5D = address;
X    `09tmpvm = DNETALLOC(strlen(address));
X    `09bcopy (address, tmpvm, strlen(address));
X`09for (i = 0, a = tmpvm; i < strlen(address); i++, a++)
X`09`7B
X`09`09if ((*a == '.') `7C`7C (*a = ':'))
X`09`09`7B
X`09`09`09*a = '\0';
X`09`09`09b`5Bj++`5D = a + 1;
X`09`09`7D
X`09`7D
X/* *** Needs to read all network address types (?) */
X`09a = (char *) &out;
X`09for (i = 0; i < j; i++, a++)
X`09`09*a = (char) atoi(b`5Bi`5D);
X`09DNETFREE(tmpvm);
X`09return (htonl(out));
X`7D
X
X`0C
X/*
X * listen():
X * Module to emulate a "listen" placed on the passed channel.  In the case o
Vf
X * DECnet, we'll interpret this to mean issue a read to the network command
X * mailbox associated with the NET: device.  Right now I don't really have a
X * use for the back log queue length, but we'll keep it around anyhow.
X */
Xint
Xlisten (chan, bl)
X`09unsigned short chan;
X`09unsigned int bl;
X`7B
X`09int`09status;
X
X#ifdef DNDEBUG
X    `09fprintf(stderr, "listen: start - passed chan %d\n", chan);
X#endif /* DNDEBUG */
X    `09lisChannel = netChannel;
X`09ChanTableInfo`5B(chan>>4)`5D->backLogQueueLength = bl; /* *** */
X`09if (!ChanTableInfo`5B(chan>>4)`5D->readAstPend)
X`09`7B
X`09`09DISABLE_ASTS;`09`09/* don't forget this or we're toast! */
X`09`09status = issueNetCmdRead (chan);
X`09`09ChanTableInfo`5B(chan>>4)`5D->readAstPend = 1;
X`09`09if (VMSFAIL(status))
X`09`09`7B
X`09`09`09LIB$SIGNAL (status);
X`09`09`09exit(0);
X`09`09`7D
X`09`7D
X`09return 0;
X`7D
X
X`0C
X/*
X *
X * SELECT for DECnet
X * Note:
X *`09readfds should contain the fd for the _NET: device for new connections.
X * `09writefds will be returned from outstanding write AST notification.
X *
X * Return:
X * `09int value specifying the number of channels ready.
X *
X */
Xint
Xselect (width, readfds, writefds, exceptfds, timeout)
X`09int width;
X`09fd_set *readfds;
X`09fd_set *writefds;
X`09fd_set *exceptfds;
X`09struct timeval *timeout;
X`7B
X`09int i;
X`09int j;
X`09int k;
X`09int lw;
X`09char *plw;
X`09int delta`5B2`5D;
X`09int totset;
X`09int fd_group;
X`09int numBytes = width/NBBY;
X`09int status;
X    `09int bit;
X    `09int pos;
X`09fd_set readMask;
X`09fd_set writeMask;
X`09fd_set exceptMask;
X
X`09stackIndex = 0;
X`09timerExpired = 0;
X`09totset = 0;
X
X#ifdef DNDEBUG
X    `09fprintf(stderr, "select: start\n");
X#endif /* DNDEBUG */
X/*
X * Optimized channel listening setup loop.
X */
X`09for (fd_group = 0, i = 0, j = 0; j < width; ++fd_group)
X`09`7B
X`09`09if (readfds->bits`5Bfd_group`5D)
X`09`09`7B
X    `09`09`09pos = -1;
X`09`09`09while( _FFS(pos+1, ((NBLW-1)-pos), &readfds->bits`5Bfd_group`5D, &p
Vos))
X    `09`09`09`7B
X    `09`09`09`09bit = j + pos;
X    `09`09`09`09if (!ChanTableInfo`5Bbit`5D)
X    `09`09`09`09`7B
X    `09`09`09`09`09errno = EBADF;
X    `09`09`09`09`09return -1;
X    `09`09`09`09`7D
X    `09`09`09`09if (!ChanTableInfo`5Bbit`5D->readAstPend)`20
X    `09`09`09`09`09status = issueRead ((bit<<4));
X`09`09`09`7D
X`09`09`7D
X`09`09else
X`09`09`09j += NBLW;
X`09`7D
X`09LIB$MOVC5(&zero, NULL, "\0", &numBytes, (char *) &readMask);
X`09if (writefds) LIB$MOVC5(&zero, NULL, "\0", &numBytes, (char *) &writeMask
V);
X/*
X`09This is a future enhancement, currently omitted for time considerations:
X`09if (exceptfds) LIB$MOVC5(&zero, NULL, "\0", &numBytes, (char *) &exceptMa
Vsk);
X*/
X`09if (!stackIndex)
X`09`7B
X`09`09int sec = 0;
X`09`09int usec = 0;
X
X`09`09if (timeout)
X`09`09`7B
X`09`09`09sec = timeout->tv_sec;
X`09`09`09usec = timeout->tv_usec;
X`09`09`7D
X`09`09if ((timeout) && (!(sec + usec)))
X`09`09`09timerExpired = 1;
X`09`09else
X`09`09`7B
X/*
X * Here's the juicy part of select().  Check for a timeout value to be setup
V. Then
X * enable ASTs, check for any I/O completion, and disable ASTs.
X */
X`09`09`09if (timeout)
X`09`09`09`7B
X`09`09`09`09delta`5B0`5D = (sec * -10000000) + (usec * -10);
X`09`09`09`09delta`5B1`5D = -1;
X`09`09`09`09SYS$SETIMR ( 0, delta, timeoutAst, timeout, 0);
X`09`09`09`7D
X`09`09`09ENABLE_ASTS;
X`09`09`09HIBERNATE;
X`09`09`09DISABLE_ASTS;
X`09`09`09if ((!timerExpired) && (timeout))
X`09`09`09`7B
X`09`09`09`09status = SYS$CANTIM (timeout, 0);
X`09`09`09`09if (VMSFAIL(status)) LIB$SIGNAL(status);
X`09`09`09`7D
X`09`09`7D
X`09`7D
X`09if (!stackIndex && !timerExpired)
X`09`09fprintf (stderr, "select: error - stackIndex 0 timerExpired 0\n");
X/*
X * Now check the ast stack for completions.  Mark any channel's with I/O pen
Vding
X * on the internal fd masks.
X */
X`09if ((timerExpired) && (!stackIndex))
X`09`7B
X`09`09for (i = 0, lw = 0, fd_group = 0; lw < width; lw+=NBLW, fd_group++)
X`09`09`7B
X`09`09`09if (readfds)
X`09`09`09`09readfds->bits`5Bfd_group`5D = 0;
X`09`09`09if (writefds)
X`09`09`09`09writefds->bits`5Bfd_group`5D = 0;
X`09`09`09if (exceptfds)
X`09`09`09`09exceptfds->bits`5Bfd_group`5D = 0;
X`09`09`7D
X`09`7D
X`09else
X`09`7B
X#ifdef DNDEBUG
X`09`09fprintf(stderr, "select: stackIndex %d\n", stackIndex);
X#endif
X`09`09for (i = 0; i < stackIndex; i++)
X`09`09`7B
X/*
X *`09Note, read_iosb.status = SS$_LINKABORT, when the line dies!`20
X */
X`09`09`09if ((stack`5Bi`5D.type == NET_CMD) `7C`7C (ChanTableInfo`5B(stack`5
VBi`5D.channel>>4)`5D))
X`09`09`09`7B
X`09`09`09switch (stack`5Bi`5D.type)
X`09`09`09`7B
X`09`09`09case NET_CMD :
X`09`09`09`7B
X`09`09`09`09if (processNetCmd(&stack`5Bi`5D.channel))
X`09`09`09`09`7B
X`09`09`09`09`09FD_SET(stack`5Bi`5D.channel, &readMask);
X`09`09`09`09`09totset++;
X`09`09`09`09`7D
X`09`09`09`09break;
X`09`09`09`7D
X`09`09`09case NET_RD :
X`09`09`09`7B
X`09`09`09`09if (readfds)
X`09`09`09`09`7B
X`09`09`09`09`09if (FD_ISSET(stack`5Bi`5D.channel, readfds))
X`09`09`09`09`09`7B
X`09`09`09`09`09`09FD_SET(stack`5Bi`5D.channel, &readMask);
X`09`09`09`09`09`09totset++;
X`09`09`09`09`09`7D
X`09`09`09`09`7D
X`09`09`09`7D
X`09`09`09case NET_WRT :`20
X`09`09`09`7B
X`09`09`09`09if (writefds)
X`09`09`09`09`7B
X`09`09`09`09`09if (FD_ISSET(stack`5Bi`5D.channel, writefds))
X`09`09`09`09`09`7B
X`09`09`09`09`09`09FD_SET(stack`5Bi`5D.channel, &writeMask);
X`09`09`09`09`09`09totset++;
X`09`09`09`09`09`7D
X`09`09`09`09`7D
X`09`09`09`7D
X/*
X *`09`09`09case NET_CMD :`20
X *`09`09`09`7B
X *`09`09`09`09if (exceptfds)
X *`09`09`09`09`7B
X *`09`09`09`09`09if (FD_ISSET(stack`5Bi`5D.channel, exceptfds))
X *`09`09`09`09`09`7B
X *`09`09`09`09`09`09FD_SET(stack`5Bi`5D.channel, &exceptMask);
X *`09`09`09`09`09`09totset++;
X *`09`09`09`09`09`7D
X *`09`09`09`09`7D
X *`09`09`09`7D
X */
X`09`09`09`7D /* switch */
X`09`09`09`7D /* LINKABORT if */
X`09`09`09else
X`09`09`09`7B
X`09`09`09`09errno = EBADF;
X`09`09`09`09totset = -1;
X`09`09`09`09break;
X`09`09`09`7D
X`09`09`7D
X/*
X * Now "and" the two tables together to create the returned fd table(s).
X */
X`09`09for (lw = 0, fd_group = 0; lw < width; lw+=NBLW, ++fd_group)
X`09`09`7B
X`09`09`09if (readfds)
X`09`09`09`09readfds->bits`5Bfd_group`5D &= readMask.bits`5Bfd_group`5D;
X`09`09`09if (writefds)
X`09`09`09`09writefds->bits`5Bfd_group`5D &= writeMask.bits`5Bfd_group`5D;
X`09`09`09if (exceptfds)
X`09`09`09`09exceptfds->bits`5Bfd_group`5D &= exceptMask.bits`5Bfd_group`5D;
X`09`09`7D
X`09`7D
X#ifdef DNDEBUG
X    `09fprintf(stderr, "select: returning %d\n", totset);
X#endif
X`09return totset;
X`7D
X
X`0C
X/*
X * setsockopt
X * Stub routine for emulation purposes right now.
X */
Xint
Xsetsockopt (chan, level, optname, optval, optlen)
X`09unsigned short chan;
X`09unsigned long level;
X`09unsigned long optname;
X`09char *optval;
X`09unsigned long optlen;
X`7B
X#ifdef DNDEBUG
X    `09fprintf(stderr, "setsockopt: start - passed chan %d\n", chan);
X#endif /* DNDEBUG */
X`09ChanTableInfo`5B(chan>>4)`5D->o`5Boptname`5D.option = optval;
X`09ChanTableInfo`5B(chan>>4)`5D->o`5Boptname`5D.optionlen = optlen;
X`09return 0;
X`7D
X
X`0C
X/*
X * socket():
X * Two channels are created as a result of this call,
X * 1) mbxChannel - the network command mailbox throught which all low level`
V20
X *`09`09   connection information and management crap flows
X * 2) netChannel - the channel to the NET device, used by a server to est. a
V`20
X *`09`09   DECnet object; used by a client to connect and perform I/O on
X *`09`09   the aforementioned object.
X * Note: only netChannel is "seen" by the calling layer program.
X */
Xunsigned short
Xsocket (addrfam, type, proto)
X`09unsigned long addrfam;
X`09unsigned long type;
X`09unsigned long proto;
X`7B
X`09int status;
X
X#ifdef DNDEBUG
X    `09fprintf(stderr, "socket: start\n");
X#endif /* DNDEBUG */
X    `09connectNet ();
X`09if (!ChanTableInfo`5B(netChannel>>4)`5D) clearChanTable((netChannel>>4));
X`09if (!ChanTableInfo`5B(mbxChannel>>4)`5D) clearChanTable((mbxChannel>>4));
X`09return netChannel;
X`7D
X
X`0C
X/*
X * socket_close
X * Emulation routine for closing channels.
X */
Xint
Xsocket_close (chan)
X        unsigned short chan;
X`7B
X`09unsigned short shiftChan = chan>>4;
X
X#ifdef DNDEBUG
X`09fprintf(stderr, "socket_close: linkTerm %d\n", chan);
X#endif
X`09linkTerm (shiftChan);
X`09clearChanTable (shiftChan);
X`09return 0;
X`7D
X
X`0C
X/*
X * socket_ioctl
X * Emualtion routine for stubbing purposes only.
X */
Xint
Xsocket_ioctl (chan, request, argp)
X`09unsigned short chan;
X`09unsigned int request;
X`09char *argp;
X`7B
X#ifdef DNDEBUG
X    `09fprintf(stderr, "socket_ioctl: start - passed chan %d\n", chan);
X#endif /* DNDEBUG */
X`09if (chan > FD_SETSIZE)
X`09`09return -1;
X`09ChanTableInfo`5B(chan>>4)`5D->type = request;
X`7D
X
X`0C
X/*
X * socket_perror
X * Emulation for the same.  Relatively weak right now in that it ignores err
Vno
X * values.
X */
Xvoid
Xsocket_perror (s)
X`09char *s;
X`7B
X#ifdef DNDEBUG
X    `09fprintf(stderr, "socket_perror: start\n");
X#endif /* DNDEBUG */
X`09fprintf(stdout, "%s", s);
X`7D
X
X`0C
X/*
X * socket_read (chan, target, length)
X * Routine to emulate the a streamed read on a socket.  Currently the read
X * supports ONLY nonblocking I/O.  That is, the read will complete is there
X * is ANYTHING in the channel buffer not depending on the passed "length" fi
Veld.
X * With blocking I/O, the read will wait until the length field request has
X * been statisfied.
X */
Xint
Xsocket_read (chan, target, l)
X        unsigned short   chan;
X        char    *target;
X        int     l;
X`7B
X`09int`09shiftChan = chan>>4;
X`09char *vmbase = ChanTableInfo`5BshiftChan`5D->base;
X`09char *vmdelta = ChanTableInfo`5BshiftChan`5D->delta;
X`09int vmlen = ChanTableInfo`5BshiftChan`5D->len;
X        int     remainder;
X        char    *savtarget;
X        int     movetot;
X`09int`09pass;
X`09int`09status;
X`09struct io_stat_blk iosb;
X
X#ifdef DNDEBUG
X    `09fprintf(stderr, "socket_read: start - passed chan %d\n", chan);
X#endif /* DNDEBUG */
X`09if (!ChanTableInfo`5BshiftChan`5D) return -1;
X        if (!l) return l;
X
X        savtarget = target;
X        movetot = 0;
X/* Check the size of the channel's read buffer `09`09`09*/
X        remainder = (vmbase + vmlen) - vmdelta;
X/*
X * If this routine was called after an AST read notification from select() a
Vnd the
X * read in buffer size was 0, return 0 now so that a QIO is *not* performed.
V  In the
X * case of a calling program that does *not* use select/AST's, readAstDone w
Vill remain 0.
X */
X    `09if (ChanTableInfo`5BshiftChan`5D->readAstDone)
X    `09`7B
X    `09`09ChanTableInfo`5BshiftChan`5D->readAstDone = 0;
X    `09`09if(!remainder) return 0;
X    `09`7D
X/*
X * See if the VM area exists and, if so, is there anything in there?  If yes
V again,
X * move it, update VM pointers, and return. (Non blocking I/O).
X */
X        if (remainder)
X        `7B
X`09`09pass = MIN(remainder, l);
X                bcopy (vmdelta, target, pass);
X                movetot += pass;
X                savtarget += pass;
X                vmdelta += pass;
X`09`09ChanTableInfo`5BshiftChan`5D->base = vmbase;
X`09`09ChanTableInfo`5BshiftChan`5D->delta = vmdelta;
X`09`09ChanTableInfo`5BshiftChan`5D->len = vmlen;
X`09`09return movetot;
X        `7D
X/*
X * VM memory area is empty, so fill it up and update the pointers.
X */
X`09if (!remainder)
X`09`7B
X                status = SYS$QIOW (0, chan, IO$_READVBLK, &iosb, 0, 0, vmbas
Ve,
X                        MAX_QIO, 0, 0, 0, 0);
X                if (!(status & STS$M_SUCCESS) `7C`7C !(iosb.status & STS$M_S
VUCCESS))
X                        return -1;
X`09`09vmdelta = vmbase;
X                vmlen = iosb.msg_len;
X#ifdef DNDEBUG
X    `09`09fprintf(stderr,"socket_read: iosb.len %d on channel %d\n",iosb.msg
V_len, chan);
X#endif
X`09`09if (vmlen < l) fprintf(stderr, "socket_read: returned < request %d/%d\
Vn", vmlen, l);
X        `7D
X`09pass = MIN(vmlen, l);
X        bcopy (vmdelta, savtarget, pass);
X        movetot += pass;
X        vmdelta += pass;
X`09ChanTableInfo`5BshiftChan`5D->base = vmbase;
X`09ChanTableInfo`5BshiftChan`5D->delta = vmdelta;
X`09ChanTableInfo`5BshiftChan`5D->len = vmlen;
X`09return movetot;
X`7D
X
X`0C
X/*
X * socket_write
X * Emulation routine for writes to a given channel.  Note that I tried IO$M_
VNOW
X * but it had the effect of causing an error (overflow I believe). `20
X * Does buffering occur?  Is it detrimental to the works since I don't check
V for
X * write completion?
X */
Xint
Xsocket_write (chan, buffer, l)   /* Issue writes, (IO$_WRITEVBLK), over the
V logical link.*/
X        unsigned short`09chan;
X        char            *buffer;
X        int             l;
X`7B
X`09int status;
X`09struct io_stat_blk iosb;
X`09
X#ifdef DNDEBUG
X    `09fprintf(stderr, "socket_write: start - passed chan %d\n", chan);
X#endif /* DNDEBUG */
X        status = SYS$QIOW (0, chan, IO$_WRITEVBLK, &iosb, 0, 0, buffer,
X                        l, 0, 0, 0, 0);
X        if (VMSFAIL(status))`20
X`09`7B
X`09`09LIB$SIGNAL(status);
X`09`09return -1;
X`09`7D
X        if (VMSFAIL(iosb.status))`20
X`09`7B
X`09`09LIB$SIGNAL(iosb.status);
X`09`09return -1;
X`09`7D
X#ifdef DNDEBUG
X`09fprintf(stderr, "socket_write: wrote %d/%d to channel %d\n",iosb.msg_len,
V l, chan);
X#endif
X`09return iosb.msg_len;
X`7D
X
X`0C
X/*
X * socket_writev
X * Emulation routine for the ugly iov style socket writing.
X */
Xint
Xsocket_writev( d, iov, iovcnt)
X        int d;
X        struct iovec *iov;
X        int iovcnt;
X`7B
X        int     totbytes;
+-+-+-+-+-+-+-+-  END  OF PART 2 +-+-+-+-+-+-+-+-
--
Patrick L. Mahan

--- TGV Window Washer ------------------------------- Mahan@TGV.COM ---------

Waking a person unnecessarily should not be considered  - Lazarus Long
a capital crime.  For a first offense, that is            From the Notebooks of
							  Lazarus Long
Technical Details
Message-ID: <8045405@MVB.SAIC.COM>
Path: arc1-ca.pugleaf.net!sparky!uunet!usc!news.service.uci.edu!unogate!mvb.saic.com!vmsnet-sources

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!sparky!uunet!usc!news.service.uci.edu!unogate!mvb.saic.com!vmsnet-sources
From: mahan@tgv.com (Patrick L. Mahan - TGV Window Washer)
Newsgroups: vmsnet.sources
Subject: XSCOPE/VMS 1.0, part 02/08
Message-ID: <8045405@MVB.SAIC.COM>
Date: Fri, 04 Sep 1992 05:34:15 GMT
Reply-To: mahan@tgv.com
Organization: TGV Incorporated (Tech Support) in Santa Cruz, CA
Lines: 1745
Approved: Mark.Berryman@Mvb.Saic.Com