XNSServerLocationImpl.mesa
Demers, December 19, 1986 7:06:55 pm PST
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;
Parameters
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];
Unique Exchange ID (ought to be system-wide)
uniqueID: CARD ← BasicTime.GetClockPulses[];
GetUniqueID: ENTRY PROC RETURNS [CARD] ~ {
RETURN [uniqueID ← uniqueID.SUCC] };
Courier Messages
Version pair overhead
VersionPair: TYPE ~ MACHINE DEPENDENT RECORD [
lowVersion: HWORD,
highVersion: HWORD
];
Call buffer.
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
Body is empty
];
callBufferOverhead: CARDINAL ~ XNSExchangeBuf.hdrBytes + callHdrBytes;
Return buffer.
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;
Unmarshalling
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: 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 ~ 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: 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 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];
};
Logic of LocateServers begins here ...
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[];
};
Debugging Aids
addresses: LIST OF XNS.Address ← NIL;
EachAddress: PROC [addr: XNS.Address] ~ {
addresses ← CONS[addr, addresses] };
}.