DIRECTORY
CrRPC USING [Call, CreateClientHandle, DestroyClientHandle, Error, GetCARDINAL, GetFWORD, GetHWORD, GetResultsProc, Handle, PutArgsProc, SetHops, SetTimeout],
Endian USING [FWORD, HWORD],
XNS USING [Address, broadcastHost, broadcastNet, Socket],
XNSServerLocation USING [EachAddressProc];
XNSServerLocationImpl:
CEDAR
PROGRAM
IMPORTS CrRPC
EXPORTS XNSServerLocation
~ {
FWORD: TYPE ~ Endian.FWORD;
HWORD: TYPE ~ Endian.HWORD;
maxPermissibleRadius: CARDINAL ~ 6; -- broadcasting to the entire Internet would be antisocial
GetXNSAddress:
PROC [h: CrRPC.Handle]
RETURNS [
XNS.Address] ~ {
xNet: FWORD;
xHost: MACHINE DEPENDENT RECORD [a, b, c: HWORD];
xSocket: HWORD;
xNet ← CrRPC.GetFWORD[h];
xHost.a ← CrRPC.GetHWORD[h];
xHost.b ← CrRPC.GetHWORD[h];
xHost.c ← CrRPC.GetHWORD[h];
xSocket ← CrRPC.GetHWORD[h];
TRUSTED {
RETURN [
[net~LOOPHOLE[xNet], host~LOOPHOLE[xHost], socket~LOOPHOLE[xSocket]] ] };
};
StopListening: ERROR ~ CODE;
LocateServers:
PUBLIC
PROC [
socket:
XNS.Socket,
-- destination socket for broadcast
maxHops:
CARDINAL,
-- radius of broadcast
remotePgm:
CARD,
remotePgmVersion:
CARDINAL,
eachAddress: XNSServerLocation.EachAddressProc,
-- called with address of each responding server
firstResponseOnly:
BOOL ←
TRUE
] ~ {
h: CrRPC.Handle;
PutArgs: CrRPC.PutArgsProc ~ { NULL };
GetResults: CrRPC.GetResultsProc ~ {
n: CARDINAL;
addr: XNS.Address;
n ← CrRPC.GetCARDINAL[h];
THROUGH [0..n)
DO
addr ← GetXNSAddress[h];
eachAddress[addr];
IF firstResponseOnly THEN ERROR StopListening[];
ENDLOOP;
};
maxHops ← MIN[maxHops, maxPermissibleRadius];
h ← CrRPC.CreateClientHandle[
class~$EXCHANGE,
remote~[net~XNS.broadcastNet, host~XNS.broadcastHost, socket~socket]];
BEGIN
ENABLE StopListening => CONTINUE;
FOR hops:
CARDINAL
IN [0..maxHops]
DO
h ← CrRPC.SetHops[h~h, low~hops, high~hops];
h ← CrRPC.SetTimeout[h, 200 + 300 * hops];
THROUGH [0..4)
DO
CrRPC.Call[
h~h, remotePgm~remotePgm, remotePgmVersion~remotePgmVersion, remoteProc~0,
putArgs~PutArgs, getResults~GetResults
! CrRPC.Error => CONTINUE];
ENDLOOP;
ENDLOOP;
END;
CrRPC.DestroyClientHandle[h];
};
}.