Article View: vmsnet.sources
Article #105XSCOPE/VMS 1.0, part 02/08
From: Patrick L. Mahan - TGV Window Wa...
Date: Fri, 04 Sep 1992 05:34
Date: Fri, 04 Sep 1992 05:34
1744 lines
50234 bytes
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-sourcesShow 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