<> <> <> <> DIRECTORY CrRPC USING [Call, CreateClientHandle, DestroyClientHandle, GetCARDINAL, GetFWORD, GetHWORD, GetResultsProc, Handle, PutArgsProc, PutCARD, PutCARDINAL, SetHops, SetTimeout], Endian USING [FWORD, HWORD], XNS USING [broadcastHost, broadcastNet, unknownAddress], CourierBindingProtocol, CourierBinding; CourierBindingClientImpl: CEDAR PROGRAM IMPORTS CrRPC EXPORTS CourierBinding ~ { OPEN CourierBindingProtocol; <> CARD: TYPE ~ LONG CARDINAL; FWORD: TYPE ~ Endian.FWORD; HWORD: TYPE ~ Endian.HWORD; AddressList: TYPE ~ LIST OF Address; Handle: TYPE ~ CrRPC.Handle; <> BASICTIMEOUT: CARDINAL _ 200; ROUTERDELAY: CARDINAL _ 300; RETRIES: CARDINAL _ 4; TimeoutHeuristic: PROC [hops: CARDINAL] RETURNS [CARDINAL] ~ INLINE { RETURN [BASICTIMEOUT + (ROUTERDELAY * hops)]; }; <> AddToAddressList: PROC [new: Address, list: AddressList] RETURNS [AddressList] ~ { FOR temp: AddressList _ list, temp.rest WHILE (temp # NIL) DO IF (temp.first = new) THEN RETURN [list]; ENDLOOP; RETURN [ CONS[new, list] ]; }; Bind: PUBLIC PROC [predicate: CARD, versions: Range, maxHops: CARDINAL, stubPutPred: CrRPC.PutArgsProc] RETURNS [answer: Address _ XNS.unknownAddress] ~ { answerList: AddressList _ AddToAddressList[answer, NIL]; h: Handle _ CrRPC.CreateClientHandle[ class~$EXCHANGE, remote~[net~XNS.broadcastNet, host~XNS.broadcastHost, socket~socket], timeoutMsec~BASICTIMEOUT]; <> <> <> <> { FOR hops: CARDINAL IN [0..maxHops] DO IF TRUE THEN h _ CrRPC.SetHops[h~h, low~hops, high~hops]; h _ CrRPC.SetTimeout[h, TimeoutHeuristic[hops]]; THROUGH [0..RETRIES) DO answerList _ RingPredicate[h, answerList, predicate, versions, stubPutPred]; IF (answerList.first # XNS.unknownAddress) THEN GOTO Found; ENDLOOP; ENDLOOP; EXITS Found => { answer _ answerList.first; }; -- maybe first isn't best? }; CrRPC.DestroyClientHandle[h]; }; GetRange: PROC [h: Handle] RETURNS [r: Range] ~ { r.lowVersion _ CrRPC.GetCARDINAL[h]; r.highVersion _ CrRPC.GetCARDINAL[h]; }; PutRange: PROC [h: Handle, r: Range] ~ { CrRPC.PutCARDINAL[h, r.lowVersion]; CrRPC.PutCARDINAL[h, r.highVersion]; }; GetXNSAddress: PROC [h: Handle] RETURNS [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]] ] }; }; RingPredicate: PROC [h: Handle, oldList: AddressList, predicate: CARD, versions: Range, stubPutPred: CrRPC.PutArgsProc] RETURNS [newList: AddressList] ~ { PutArgs: CrRPC.PutArgsProc ~ { CrRPC.PutCARD[h, predicate]; PutRange[h, versions]; IF (stubPutPred # NIL) THEN stubPutPred[h]; }; GetResults: CrRPC.GetResultsProc ~ { r: Range _ GetRange[h]; newList _ AddToAddressList[GetXNSAddress[h], newList]; }; newList _ oldList; CrRPC.Call[h~h, remotePgm~program, remotePgmVersion~version, remoteProc~bind, putArgs~PutArgs, getResults~GetResults ]; }; }...