XNSServerLocationImpl.mesa
Demers, December 20, 1986 1:20:53 pm PST
DIRECTORY
Basics USING [bytesPerHWord, Card16FromH, FFromCard32, FWORD, HFromCard16, HWORD],
CommBuffer USING [Overhead],
CrRPCBackdoor USING [CallMsgHdr, callMsgHdrBytes, callMsgType, courierVersionNum, MsgHdr, ReturnMsgHdr, returnMsgHdrBytes, returnMsgType, SessionHdr, sessionHdrBytes],
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, GetUnique32, GetUserBytes, Handle, Kick, SetNoErrors, SetRemoteAddress, SetUserBytes, waitForever],
XNSSocketBackdoor USING [PutCached];
XNSServerLocationImpl: CEDAR PROGRAM
IMPORTS Basics, Process, XNSRouter, XNSSocket, XNSSocketBackdoor
EXPORTS XNSServerLocation
~ {
FWORD: TYPE ~ Basics.FWORD;
HWORD: TYPE ~ Basics.HWORD;
Parameters
maxRadius: CARDINAL ~ XNSRouter.maxHops;
maxTries: ARRAY [0..maxRadius) OF CARDINAL ← [
3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6];
clicksPerResend: ARRAY [0..maxRadius) OF CARDINAL ← [
2, 4, 6, 8, 10, 12, 12, 14, 14, 16, 16, 16, 18, 18, 18];
clickMSec: CARD ~ 200;
clickTicks: Process.Ticks ← Process.MsecToTicks[clickMSec];
Expedited Courier Message Buffers
Call buffer 
CallBuffer: TYPE ~ REF CallBufferObject;
CallBufferObject: TYPE ~ MACHINE DEPENDENT RECORD [
ovh: CommBuffer.Overhead,
hdr1: XNSBuf.Hdr,
hdr2: XNSExchangeBuf.Hdr,
sessionHdr: CrRPCBackdoor.SessionHdr,
callMsgHdr: CrRPCBackdoor.CallMsgHdr
Body is empty
];
callBufferOverhead: CARDINAL ~ XNSExchangeBuf.hdrBytes + CrRPCBackdoor.sessionHdrBytes + CrRPCBackdoor.callMsgHdrBytes;
Return buffer.
ReturnBuffer: TYPE ~ REF ReturnBufferObject;
ReturnBufferObject: TYPE ~ MACHINE DEPENDENT RECORD [
ovh: CommBuffer.Overhead,
hdr1: XNSBuf.Hdr,
hdr2: XNSExchangeBuf.Hdr,
sessionHdr: CrRPCBackdoor.SessionHdr,
returnMsgHdr: CrRPCBackdoor.ReturnMsgHdr,
body: PACKED ARRAY [0..maxBodyHWords) OF HWORD
];
returnBufferOverhead: CARDINAL ~ XNSExchangeBuf.hdrBytes + CrRPCBackdoor.sessionHdrBytes + CrRPCBackdoor.returnMsgHdrBytes;
maxBodyBytes: CARDINAL ~ XNSExchangeBuf.maxBodyBytes - CrRPCBackdoor.sessionHdrBytes - CrRPCBackdoor.returnMsgHdrBytes;
maxBodyHWords: CARDINAL ~ maxBodyBytes/Basics.bytesPerHWord;
Unmarshalling
addressBytes: CARDINAL ~ BITS[XNS.Address]/BITS[BYTE];
addressHWords: CARDINAL ~ BITS[XNS.Address]/BITS[HWORD];
NumberOfXNSAddresses: PROC [b: ReturnBuffer] RETURNS [n: CARDINAL] ~ {
nB, nCheck: CARDINAL;
TRUSTED { nB ← XNSSocket.GetUserBytes[LOOPHOLE[b]] };
n ← (nB - returnBufferOverhead - Basics.bytesPerHWord) / addressBytes;
nCheck ← Basics.Card16FromH[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: BOOLFALSE;
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 ~ Basics.HFromCard16[CrRPCBackdoor.courierVersionNum];
b.sessionHdr ← [lowVersion~v, highVersion~v] };
b.callMsgHdr.msgHdr ← [msgType~CrRPCBackdoor.callMsgType];
b.callMsgHdr.callHdr ← [
tID~[0, 0],
pgmNum~Basics.FFromCard32[remotePgm],
pgmVersion~Basics.HFromCard16[remotePgmVersion],
procNum~[0, 0]];
XNSSocket.SetUserBytes[queryBuf, callBufferOverhead];
};
ProcessReply: PROC ~ {
b: ReturnBuffer ← NIL;
bestHops: CARDINALLAST[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 Basics.Card16FromH[b.sessionHdr.lowVersion] > CrRPCBackdoor.courierVersionNum
THEN RETURN;
IF Basics.Card16FromH[b.sessionHdr.highVersion] < CrRPCBackdoor.courierVersionNum
THEN RETURN;
IF b.returnMsgHdr.msgHdr.msgType # CrRPCBackdoor.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];
};
Logic of LocateServers begins here ...
IF tryLimit = 0 THEN tryLimit ← LAST[CARDINAL];
maxHops ← MIN[maxHops, maxRadius];
sH ← XNSSocket.Create[getTimeout~XNSSocket.waitForever];
exchangeID ← Basics.FFromCard32[XNSSocket.GetUnique32[]];
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[];
};
Debugging Aids
addresses: LIST OF XNS.Address ← NIL;
EachAddress: PROC [addr: XNS.Address] ~ {
addresses ← CONS[addr, addresses] };
}.