<> <> <<>> 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]; IF n > 0 THEN { addr _ GetXNSAddress[h]; eachAddress[addr]; IF firstResponseOnly THEN ERROR StopListening[] } }; 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]; }; }.