DIRECTORY BasicTime USING [GetClockPulses], CommBuffer USING [Overhead], CrRPCFriends USING [CallHdr, callMsgType, courierVersionNum, MsgHdr, ReturnHdr, returnMsgType], Endian USING [bytesPerHWord, CardFromH, FFromCard, FWORD, HFromCard, HWORD], Process USING [Abort, CheckForAbort, MsecToTicks, Pause, Ticks], XNS USING [Address, broadcastHost, broadcastNet, Net, Socket], XNSBuf USING [Buffer, Hdr], XNSExchangeBuf USING [Hdr, hdrBytes, maxBodyBytes], XNSExchangeTypes USING [clearinghouseServiceType, ExchangeID], XNSRouter USING [Enumerate, GetHops, maxHops, RoutingTableEntry], XNSServerLocation USING [EachAddressProc], XNSSocket USING [AllocBuffer, Create, Destroy, FreeBuffer, Get, GetUserBytes, Handle, Kick, SetNoErrors, SetRemoteAddress, SetUserBytes, waitForever], XNSSocketBackdoor USING [PutCached]; XNSServerLocationImpl: CEDAR MONITOR -- MONITOR only for GetUniqueExchangeID -- IMPORTS BasicTime, Endian, Process, XNSRouter, XNSSocket, XNSSocketBackdoor EXPORTS XNSServerLocation ~ { FWORD: TYPE ~ Endian.FWORD; HWORD: TYPE ~ Endian.HWORD; bytesPerWord: CARDINAL ~ Endian.bytesPerHWord; maxRadius: CARDINAL ~ XNSRouter.maxHops; maxTries: ARRAY [0..maxRadius) OF CARDINAL _ [ 3, 4, 4, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6]; clicksPerResend: ARRAY [0..maxRadius) OF CARDINAL _ [ 2, 4, 6, 8, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12]; clickMSec: CARD ~ 200; clickTicks: Process.Ticks _ Process.MsecToTicks[clickMSec]; uniqueID: CARD _ BasicTime.GetClockPulses[]; GetUniqueID: ENTRY PROC RETURNS [CARD] ~ { RETURN [uniqueID _ uniqueID.SUCC] }; VersionPair: TYPE ~ MACHINE DEPENDENT RECORD [ lowVersion: HWORD, highVersion: HWORD ]; CallHdr: TYPE ~ MACHINE DEPENDENT RECORD [ versionPair: VersionPair, msgHdr: CrRPCFriends.MsgHdr, callHdr: CrRPCFriends.CallHdr ]; callHdrBytes: CARDINAL ~ SIZE[CallHdr]*bytesPerWord; -- Should use BYTES CallBuffer: TYPE ~ REF CallBufferObject; CallBufferObject: TYPE ~ MACHINE DEPENDENT RECORD [ ovh: CommBuffer.Overhead, hdr1: XNSBuf.Hdr, hdr2: XNSExchangeBuf.Hdr, hdr3: CallHdr ]; callBufferOverhead: CARDINAL ~ XNSExchangeBuf.hdrBytes + callHdrBytes; ReturnHdr: TYPE ~ MACHINE DEPENDENT RECORD [ versionPair: VersionPair, msgHdr: CrRPCFriends.MsgHdr, returnHdr: CrRPCFriends.ReturnHdr ]; returnHdrBytes: CARDINAL ~ SIZE[ReturnHdr]*bytesPerWord; -- BYTES[...] ? ReturnBuffer: TYPE ~ REF ReturnBufferObject; ReturnBufferObject: TYPE ~ MACHINE DEPENDENT RECORD [ ovh: CommBuffer.Overhead, hdr1: XNSBuf.Hdr, hdr2: XNSExchangeBuf.Hdr, hdr3: ReturnHdr, body: PACKED ARRAY [0..maxBodyHWords) OF HWORD ]; returnBufferOverhead: CARDINAL ~ XNSExchangeBuf.hdrBytes + returnHdrBytes; maxBodyBytes: CARDINAL ~ XNSExchangeBuf.maxBodyBytes - returnHdrBytes; maxBodyHWords: CARDINAL ~ maxBodyBytes/Endian.bytesPerHWord; addressHWords: CARDINAL ~ SIZE[XNS.Address]; -- Should use BYTES[...] / bytesPerWord addressBytes: CARDINAL ~ SIZE[XNS.Address]*bytesPerWord; -- Should use BYTES[...] NumberOfXNSAddresses: PROC [b: ReturnBuffer] RETURNS [n: CARDINAL] ~ { nB, nCheck: CARDINAL; TRUSTED { nB _ XNSSocket.GetUserBytes[LOOPHOLE[b]] }; n _ (nB - returnBufferOverhead - Endian.bytesPerHWord) / addressBytes; nCheck _ Endian.CardFromH[b.body[0]]; IF nCheck # n THEN n _ 0; }; GetXNSAddress: PROC [b: ReturnBuffer, i: CARDINAL] RETURNS [XNS.Address] ~ { temp: ARRAY [0..addressHWords) OF HWORD; j, delta: CARDINAL; delta _ i*addressHWords + 1; FOR j IN [0..addressHWords) DO temp[j] _ b.body[j+delta] ENDLOOP; RETURN[ LOOPHOLE[temp] ]; }; StopBroadcast: PUBLIC ERROR ~ CODE; LocateServers: PUBLIC PROC [ remotePgm: CARD, remotePgmVersion: CARDINAL, eachAddress: XNSServerLocation.EachAddressProc, socket: XNS.Socket, net: XNS.Net, maxHops: CARDINAL, tryLimit: CARDINAL ] ~ { broadcaster: PROCESS; broadcasterDone: BOOL _ FALSE; exchangeID: XNSExchangeTypes.ExchangeID; sH: XNSSocket.Handle _ NIL; queryBuf: XNSBuf.Buffer _ NIL; replyBuf: XNSBuf.Buffer _ NIL; CleanUp: PROC ~ { XNSSocket.SetNoErrors[sH]; TRUSTED { Process.Abort[broadcaster]; JOIN broadcaster }; IF queryBuf # NIL THEN { XNSSocket.FreeBuffer[queryBuf]; queryBuf _ NIL }; IF replyBuf # NIL THEN { XNSSocket.FreeBuffer[replyBuf]; replyBuf _ NIL }; XNSSocket.Destroy[sH]; }; DirectedBroadcaster: PROC ~ { triesLeft: CARDINAL; clicksLeft: CARDINAL; hops: CARDINAL; hops _ XNSRouter.GetHops[net]; IF hops < maxRadius THEN { triesLeft _ MIN[maxTries[hops], tryLimit]; clicksLeft _ 0; XNSSocket.SetRemoteAddress[sH, [net, XNS.broadcastHost, socket]]; DO ENABLE ABORTED => EXIT; IF clicksLeft = 0 THEN { IF triesLeft = 0 THEN EXIT; XNSSocketBackdoor.PutCached[queryBuf]; triesLeft _ triesLeft.PRED; clicksLeft _ clicksPerResend[hops] } ELSE { clicksLeft _ clicksLeft.PRED }; Process.Pause[clickTicks]; ENDLOOP; }; broadcasterDone _ TRUE; XNSSocket.Kick[sH]; }; Broadcaster: PROC ~ { triesLeft: ARRAY [0..maxRadius) OF CARDINAL; clicksLeft: ARRAY [0..maxRadius) OF CARDINAL; tries, clicks: CARDINAL; done: BOOL; EachNet: PROC [net: XNS.Net, rte: XNSRouter.RoutingTableEntry] ~ { Process.CheckForAbort[]; XNSSocket.SetRemoteAddress[sH, [net, XNS.broadcastHost, socket]]; XNSSocketBackdoor.PutCached[queryBuf] }; FOR hops: CARDINAL IN [0..maxHops) DO triesLeft[hops] _ MIN[maxTries[hops], tryLimit]; clicksLeft[hops] _ hops; ENDLOOP; done _ FALSE; WHILE NOT done DO ENABLE ABORTED => EXIT; done _ TRUE; FOR hops: CARDINAL IN [0..maxHops) DO IF (clicks _ clicksLeft[hops]) > 0 THEN { clicksLeft[hops] _ clicks.PRED; done _ FALSE } ELSE { IF (tries _ triesLeft[hops]) > 0 THEN { XNSRouter.Enumerate[low~hops, high~hops, proc~EachNet]; done _ FALSE; clicksLeft[hops] _ clicksPerResend[hops]; triesLeft[hops] _ tries.PRED }; }; ENDLOOP; Process.Pause[clickTicks]; ENDLOOP; broadcasterDone _ TRUE; XNSSocket.Kick[sH]; }; CreateQuery: PROC ~ { b: CallBuffer; TRUSTED { b _ LOOPHOLE[queryBuf _ XNSSocket.AllocBuffer[sH]] }; b.hdr1.type _ exchange; b.hdr2.id _ exchangeID; b.hdr2.type _ XNSExchangeTypes.clearinghouseServiceType; -- BOGUS NAME  it really means "Expedited Courier" { v: HWORD ~ Endian.HFromCard[CrRPCFriends.courierVersionNum]; b.hdr3.versionPair _ [lowVersion~v, highVersion~v] }; b.hdr3.msgHdr _ [msgType~Endian.HFromCard[CrRPCFriends.callMsgType]]; b.hdr3.callHdr _ [ tID~Endian.HFromCard[0], pgmNum~Endian.FFromCard[remotePgm], pgmVersion~Endian.HFromCard[remotePgmVersion], procNum~Endian.HFromCard[0]]; XNSSocket.SetUserBytes[queryBuf, callBufferOverhead]; }; ProcessReply: PROC ~ { b: ReturnBuffer _ NIL; bestHops: CARDINAL _ LAST[CARDINAL]; bestAddress: XNS.Address; IF XNSSocket.GetUserBytes[replyBuf] <= returnBufferOverhead THEN RETURN; IF replyBuf.hdr1.type # exchange THEN RETURN; TRUSTED { b _ LOOPHOLE[replyBuf] }; IF b.hdr2.id # exchangeID THEN RETURN; IF b.hdr2.type # XNSExchangeTypes.clearinghouseServiceType THEN RETURN; IF Endian.CardFromH[b.hdr3.versionPair.lowVersion] > CrRPCFriends.courierVersionNum THEN RETURN; IF Endian.CardFromH[b.hdr3.versionPair.highVersion] < CrRPCFriends.courierVersionNum THEN RETURN; IF Endian.CardFromH[b.hdr3.msgHdr.msgType] # CrRPCFriends.returnMsgType THEN RETURN; FOR i: CARDINAL IN [0..NumberOfXNSAddresses[b]) DO addr: XNS.Address ~ GetXNSAddress[b, i]; hops: CARDINAL ~ XNSRouter.GetHops[addr.net]; IF hops < bestHops THEN { bestHops _ hops; bestAddress _ addr }; ENDLOOP; IF bestHops < LAST[CARDINAL] THEN eachAddress[bestAddress]; }; IF tryLimit = 0 THEN tryLimit _ LAST[CARDINAL]; maxHops _ MIN[maxHops, maxRadius]; sH _ XNSSocket.Create[getTimeout~XNSSocket.waitForever]; exchangeID _ Endian.FFromCard[GetUniqueID[]]; CreateQuery[]; IF net = XNS.broadcastNet THEN TRUSTED { broadcaster _ FORK Broadcaster[] } ELSE TRUSTED { broadcaster _ FORK DirectedBroadcaster[] }; WHILE NOT broadcasterDone DO ENABLE { UNWIND => CleanUp[]; StopBroadcast => EXIT; }; replyBuf _ XNSSocket.Get[sH]; IF replyBuf # NIL THEN { ProcessReply[]; XNSSocket.FreeBuffer[replyBuf]; replyBuf _ NIL }; ENDLOOP; CleanUp[]; }; addresses: LIST OF XNS.Address _ NIL; EachAddress: PROC [addr: XNS.Address] ~ { addresses _ CONS[addr, addresses] }; }. XNSServerLocationImpl.mesa Demers, December 19, 1986 7:06:55 pm PST Parameters Unique Exchange ID (ought to be system-wide) Courier Messages Version pair overhead Call buffer. Body is empty Return buffer. Unmarshalling Logic of LocateServers begins here ... Debugging Aids Κ Ψ˜code™K™(J™—šΟk ˜ Kšœ œ˜!Kšœ œ ˜Kšœ œM˜_Kšœœ'œ œ˜LKšœœ3˜@Kšœœ5˜>Kšœœ˜Kšœœ˜3Kšœœ(˜>Kšœ œ2˜AKšœœ˜*Kšœ œ‡˜–Kšœœ ˜$K˜—šΟnœœœΟc*˜OKšœD˜KKšœ˜Kšœ˜K˜Kšœœ œ˜Kšœœ œ˜K˜Kšœœ˜.head™ Kšœ œ˜(Kšœ œœœ2˜\Kšœœœœ=˜nKšœ œ˜Kšœ;˜;—™,Kšœ œ˜,š ž œœœœœ˜*Kšœœ˜$——™™š œ œœ œœ˜.Kšœ œ˜Kšœ ˜K˜K˜——™ š œ œœ œœ˜*Kšœ˜K˜K˜K˜—šœœœŸ˜HK˜—Kšœ œœ˜(š œœœ œœ˜3Kšœ˜K˜K˜J˜ J™ K˜K˜—šœœ*˜FK˜——™šœœ œœ˜,Kšœ˜K˜K˜!K˜—šœœœŸ˜HK˜—Kšœœœ˜,š œœœ œœ˜5Kšœ˜K˜K˜Jšœ˜Jš œœœœœ˜/K˜K˜—Kšœœ,˜JKšœœ0˜FKšœœ%˜<——K˜™ Kšœœœœ Ÿ'˜TKšœœœœŸ˜QK˜šžœœœœ˜FKšœ œ˜Kšœœ˜5KšœF˜FKšœ%˜%Kšœ œ˜K˜K˜—š ž œœœœœ ˜LKšœœœœ˜(Kšœ œ˜Kšœ˜Kšœœœœ˜AJšœœ ˜K˜K˜——Kšž œœœœ˜#K˜šž œœœœœ:œœœ œ˜ΗKšœ œ˜Kšœœœ˜K˜(Kšœœ˜Kšœœ˜Kšœœ˜K˜šžœœ˜K˜Jšœ œ˜:Kšœ œœ.œ˜JKšœ œœ.œ˜JK˜K˜—K˜šžœœ˜Kšœ œ˜Kšœ œ˜Kšœœ˜K˜šœœ˜Kšœ œ˜*Kšœ˜Kšœ%œ˜Aš˜Kšœœœ˜šœ˜šœ˜Kšœœœ˜Kšœ&˜&Kšœœ˜K˜$—šœ˜Kšœœ˜——K˜Kšœ˜—K˜—Kšœœ˜K˜K˜K˜—šž œœ˜Kšœ œœœ˜,Kšœ œœœ˜-Kšœœ˜Kšœœ˜ šžœœœ+˜BKšœ˜Kšœ%œ˜AKšœ(˜(—šœœœ˜%Kšœœ˜0Kšœ˜Kšœ˜—Kšœœ˜ šœœ˜Kšœœœ˜Kšœœ˜ šœœœ˜%šœ ˜"šœ˜Kšœœ˜Kšœœ˜—šœ˜šœœ˜'K˜7Kšœœ˜ K˜)Kšœœ˜—K˜——Kšœ˜—K˜Kšœ˜—Kšœœ˜K˜K˜—K˜šž œœ˜Kšœ˜Kšœœ)˜?K˜K˜Kšœ9Ÿ3˜lšœœ4˜>K˜5—KšœE˜EKšœœ˜œKšœ5˜5K˜K˜—šž œœ˜Kšœœ˜Kšœ œœœ˜$Kšœ œ ˜Kšœ:œœ˜HKšœœœ˜-Kšœœ ˜#Kšœœœ˜&Kšœ9œœ˜GKšœRœœ˜`KšœSœœ˜aKšœFœœ˜Ušœœœ˜2Kšœœ˜(Kšœœ˜-Kšœœ)˜@Kšœ˜—Kšœ œœœ˜;K˜—K˜K™&K˜Kšœœ œœ˜/Kšœ œ˜"Kšœ˜K˜8K˜-K˜šœœ ˜Kšœœœ˜1Kšœœœ˜:—šœœ˜šœ˜Kšœ˜Kšœœ˜K˜—K˜šœ œœ˜Kšœ˜Kšœ+œ˜1—Kšœ˜—Kšœ ˜ K˜K˜—™Kš œ œœœ œ˜%šž œœœ ˜)Kšœ œ˜$——K˜—J˜—…—B*2