DIRECTORY BasicTime USING[ earliestGMT, Now, Period ], Convert USING[ RopeFromInt ], GVBasics USING[ Connect, MakeKey, maxRNameLength, Password, RName ], GVNames USING[ ConnectInfo, GetConnect, SetConnect ], PrincOpsUtils USING[ HighHalf, LongCOPY ], PupDefs USING[ AnyLocalPupAddress, GetPupAddress, PupAddress, PupNameTrouble ], Rope USING[ Cat, ROPE, Fetch, Find, Flatten, Length, Text ], RPC USING[ CallFailed, EncryptionKey, ExportFailed, ImportFailed, InterfaceName, matchAllVersions, Principal, VersionRange ], RPCInternal USING[ ExportInstance, ExportTable, ImportInstance ], RPCPkt USING[ DispatcherDetails, DispatcherID, ExportHandle, Machine, noDispatcher], RPCLupine USING[ Call, Dispatcher, GetStubPkt, pktOverhead, StartCall, StubPkt]; RPCBinding: MONITOR IMPORTS BasicTime, Convert, GVBasics, GVNames, PrincOpsUtils, PupDefs, Rope, RPC, RPCLupine EXPORTS RPC, RPCInternal, RPCLupine = BEGIN LongEquivalent: PROC[a: LONG STRING, b: Rope.ROPE] RETURNS[BOOLEAN] = BEGIN IF a.length # b.Length[] THEN RETURN[FALSE] ELSE FOR i: CARDINAL IN [0..a.length) DO ac: CHAR = a[i]; bc: CHAR = b.Fetch[i]; IF ac # bc THEN BEGIN au: CHAR = IF ac IN ['a..'z] THEN 'A + (ac-'a) ELSE ac; bu: CHAR = IF bc IN ['a..'z] THEN 'A + (bc-'a) ELSE bc; IF au # bu THEN RETURN[FALSE]; END ENDLOOP; RETURN[TRUE] END; CopyRope: PROC[from: Rope.ROPE, to: LONG POINTER] = BEGIN flat: Rope.Text = Rope.Flatten[from]; text: LONG POINTER TO TEXT = LOOPHOLE[flat]; PrincOpsUtils.LongCOPY[from: LOOPHOLE[text], to: to, nwords: SIZE[StringBody[text.length]]]; END; InstanceInfo: TYPE = { ok, badName, allDown, noAddress }; LocateInstance: PROC[instance: Rope.ROPE] RETURNS[info: InstanceInfo, isRName: BOOLEAN, host: RPCPkt.Machine] = BEGIN connect: Rope.ROPE _ NIL; IF instance.Length[] > GVBasics.maxRNameLength THEN RETURN[badName,,]; isRName _ Rope.Find[instance, "."] >= 0; IF isRName THEN BEGIN info: GVNames.ConnectInfo; [info, connect] _ GVNames.GetConnect[instance]; SELECT info FROM individual => NULL; notFound, group => RETURN[badName,isRName,]; allDown => RETURN[allDown,isRName,]; ENDCASE => ERROR; END ELSE connect _ instance; IF connect.Length[] = 0 THEN info _ IF isRName THEN noAddress ELSE badName ELSE BEGIN addr: PupDefs.PupAddress; info _ ok; addr _ PupDefs.GetPupAddress[[0,0], connect ! PupDefs.PupNameTrouble => IF code = errorFromServer THEN{ info _ IF isRName THEN noAddress ELSE badName; CONTINUE } ELSE{ info _ allDown; CONTINUE } ]; host _ [net: addr.net, host: addr.host]; END; END; -- ******** Binding primitives ******** -- ExportHandle: PUBLIC TYPE = RPCPkt.ExportHandle; exportTable: PUBLIC REF RPCInternal.ExportTable _ NEW[RPCInternal.ExportTable[20] _ [used:0, entries:] ]; MakeKey: PUBLIC SAFE PROC[text: Rope.ROPE] RETURNS[ RPC.EncryptionKey ] = CHECKED BEGIN RETURN[GVBasics.MakeKey[text]] END; ExportInterface: PUBLIC PROC[user: RPC.Principal, password: RPC.EncryptionKey, interface: RPC.InterfaceName, dispatcher: RPCLupine.Dispatcher, stubProtocol: RPC.VersionRange, localOnly: BOOLEAN _ FALSE] RETURNS[ instance: ExportHandle ] = BEGIN IF interface.type = NIL THEN ERROR RPC.ExportFailed[badType]; IF interface.version # RPC.matchAllVersions AND interface.version.first > interface.version.last THEN ERROR RPC.ExportFailed[badVersion]; instance _ AddToExportTable[interface, dispatcher, stubProtocol]; IF NOT localOnly THEN BEGIN ENABLE UNWIND => [] _ UnexportInterface[instance]; prevHost: RPCPkt.Machine; prevInfo: InstanceInfo; isRName: BOOLEAN; [prevInfo, isRName, prevHost] _ LocateInstance[interface.instance]; SELECT prevInfo FROM ok => IF prevHost = myMachine THEN RETURN; badName => ERROR RPC.ExportFailed[badInstance]; allDown => ERROR RPC.ExportFailed[communications]; noAddress => NULL; ENDCASE => ERROR; IF isRName THEN BEGIN IF user.Length[] > GVBasics.maxRNameLength THEN ERROR RPC.ExportFailed[badCredentials]; SELECT GVNames.SetConnect[user, LOOPHOLE[password], interface.instance, Rope.Cat[ Convert.RopeFromInt[myMachine.net, 8, FALSE], "#", Convert.RopeFromInt[myMachine.host, 8, FALSE], "#"] ] FROM individual, noChange => NULL; group, notFound => ERROR RPC.ExportFailed[badInstance]; badPwd, notAllowed => ERROR RPC.ExportFailed[badCredentials]; allDown => ERROR RPC.ExportFailed[communications]; ENDCASE => ERROR; END ELSE ERROR RPC.ExportFailed[badInstance]; END; END; lastExportID: RPCPkt.DispatcherID _ BasicTime.Period[from: BasicTime.earliestGMT, to: BasicTime.Now[]]; -- UID on this machine AddToExportTable: ENTRY PROC[interface: RPC.InterfaceName, dispatcher: RPCLupine.Dispatcher, stubProtocol: RPC.VersionRange] RETURNS[ instance: ExportHandle ] = BEGIN myMDS: CARDINAL = PrincOpsUtils.HighHalf[LONG[LOOPHOLE[1,POINTER]]]; FOR instance IN [0..exportTable.used) DO IF exportTable[instance].id = RPCPkt.noDispatcher THEN EXIT; REPEAT FINISHED => IF exportTable.used = exportTable.length THEN RETURN WITH ERROR RPC.ExportFailed[tooMany] ELSE { instance _ exportTable.used; exportTable.used _ exportTable.used+1 } ENDLOOP; exportTable[instance] _ [lastExportID _ lastExportID+1, dispatcher, myMDS, interface, stubProtocol]; END; UnexportInterface: PUBLIC ENTRY PROC[ instance: ExportHandle ] RETURNS[ExportHandle] = { IF exportTable[instance].id # RPCPkt.noDispatcher AND instance # binderHint THEN exportTable[instance] _ [RPCPkt.noDispatcher,NIL,0,[NIL,NIL,],]; RETURN[instance] }; binderID: RPCPkt.DispatcherID = SUCC[RPCPkt.noDispatcher]; binderHint: ExportHandle = 0; binderProc: CARDINAL = 0; BinderResult: TYPE = MACHINE DEPENDENT RECORD[ stubProtocol: RPC.VersionRange, version: RPC.VersionRange, dispatcher: RPCPkt.DispatcherDetails]; BinderArgs: TYPE = MACHINE DEPENDENT RECORD[ request(0): CARDINAL, type(1): CARDINAL, -- offset in pkt, 0 => NIL -- instance(2): CARDINAL -- offset in pkt, 0 => NIL -- -- followed by the StringBody values for type, instance --]; -- Server-stub for binding calls -- Binder: RPCLupine.Dispatcher = BEGIN PktString: PROC[n: CARDINAL] RETURNS[ LONG STRING ] = { RETURN[IF n+SIZE[StringBody[0]] NOT IN [SIZE[BinderArgs]+SIZE[StringBody[0]].. callLength] THEN NIL ELSE LOOPHOLE[@pkt[n]] ] }; args: LONG POINTER TO BinderArgs = LOOPHOLE[@pkt.data]; result: LONG POINTER TO BinderResult = LOOPHOLE[@pkt.data]; SELECT args.request FROM binderProc => result^ _ LocalBind[PktString[args.type], PktString[args.instance]]; ENDCASE => NULL -- ??--; RETURN[SIZE[BinderResult]]; END; -- Server-implementation for binding calls -- LocalBind: ENTRY PROC[type, instance: LONG STRING] RETURNS[BinderResult] = BEGIN FOR i: CARDINAL IN [1..exportTable.used) DO IF exportTable[i].id # RPCPkt.noDispatcher AND( type = NIL OR LongEquivalent[type, exportTable[i].name.type] ) AND( instance = NIL OR LongEquivalent[instance, exportTable[i].name.instance] ) THEN RETURN[[exportTable[i].stubProtocol, exportTable[i].name.version, [exportTable[i].mds, exportTable[i].id, i]]]; ENDLOOP; RETURN[[,,[,RPCPkt.noDispatcher,]]] END; -- user-stub for binding calls -- RemoteBind: SAFE PROC[host: RPCPkt.Machine, type, instance: Rope.ROPE] RETURNS[BinderResult] = TRUSTED BEGIN binderInterface: REF ImportInstance = NEW[ImportInstance _ [host,[,binderID,binderHint]]]; argSize: CARDINAL = SIZE[BinderArgs]; pktSize: CARDINAL = MAX[argSize+2*SIZE[StringBody[GVBasics.maxRNameLength]], SIZE[BinderResult] ]; pktData: ARRAY [0..RPCLupine.pktOverhead+pktSize) OF WORD; pkt: RPCLupine.StubPkt = RPCLupine.GetStubPkt[@pktData]; args: POINTER TO BinderArgs = LOOPHOLE[@pkt.data]; resultLength: CARDINAL; IF type.Length[] > GVBasics.maxRNameLength OR instance.Length[] > GVBasics.maxRNameLength THEN ERROR RPC.ImportFailed[unbound]; RPCLupine.StartCall[pkt, binderInterface]; BEGIN used: CARDINAL; args^ _ [binderProc, 0, 0]; used _ SIZE[BinderArgs]; IF type # NIL THEN BEGIN args.type _ used; CopyRope[from: type, to: @pkt[used]]; used _ used + SIZE[StringBody[type.Length[]]]; END; IF instance # NIL THEN BEGIN args.instance _ used; CopyRope[from: instance, to: @pkt[used]]; used _ used + SIZE[StringBody[instance.Length[]]]; END; IF used > pktSize THEN ERROR; [resultLength,] _ RPCLupine.Call[pkt, used, pktSize]; END; RETURN[LOOPHOLE[@pkt.data, POINTER TO BinderResult]^]; END; ImportInstance: PUBLIC TYPE = RPCInternal.ImportInstance; debugRemoteBind: BOOLEAN _ FALSE; LocateImportInstance: PROC[instance: Rope.ROPE] RETURNS[host: RPCPkt.Machine] = BEGIN info: InstanceInfo; isRName: BOOLEAN; [info, isRName, host] _ LocateInstance[instance]; SELECT info FROM ok => NULL; badName => ERROR RPC.ImportFailed[badInstance]; allDown => ERROR RPC.ImportFailed[communications]; noAddress => ERROR RPC.ImportFailed[unbound]; ENDCASE => ERROR; END; ImportInterface: PUBLIC PROC[interface: RPC.InterfaceName, stubProtocol: RPC.VersionRange, localOnly: BOOLEAN _ FALSE] RETURNS[ handle: REF ImportInstance ] = BEGIN host: RPCPkt.Machine; dispatcher: RPCPkt.DispatcherDetails; IF interface.type = NIL THEN ERROR RPC.ExportFailed[badType]; IF debugRemoteBind AND NOT localOnly THEN BEGIN host _ LocateImportInstance[interface.instance]; dispatcher _ TryBinding[host, interface, stubProtocol]; END ELSE BEGIN host _ LocateImportInstance[interface.instance]; IF localOnly AND host # myMachine THEN ERROR RPC.ImportFailed[unbound] ELSE dispatcher _ TryBinding[host, interface, stubProtocol]; END; RETURN[NEW[ImportInstance _ [host,dispatcher]]] END; TryBinding: PROC[host: RPCPkt.Machine, impName: RPC.InterfaceName, stubProtocol: RPC.VersionRange] RETURNS[RPCPkt.DispatcherDetails] = CHECKED BEGIN expDetails: BinderResult; expDetails _ RemoteBind[host, impName.type, impName.instance ! RPC.CallFailed => IF why = busy THEN RETRY ELSE ERROR RPC.ImportFailed[communications] ]; IF expDetails.dispatcher.dispatcherID = RPCPkt.noDispatcher THEN ERROR RPC.ImportFailed[unbound]; IF stubProtocol # RPC.matchAllVersions AND expDetails.stubProtocol # RPC.matchAllVersions AND ( stubProtocol.first > expDetails.stubProtocol.last OR stubProtocol.last < expDetails.stubProtocol.first ) THEN ERROR RPC.ImportFailed[stubProtocol]; IF impName.version # RPC.matchAllVersions AND impName.version.first > impName.version.last THEN ERROR RPC.ImportFailed[badVersion]; IF impName.version # RPC.matchAllVersions AND expDetails.version # RPC.matchAllVersions AND ( impName.version.first > expDetails.version.last OR impName.version.last < expDetails.version.first ) THEN ERROR RPC.ImportFailed[wrongVersion]; RETURN[expDetails.dispatcher]; END; UnimportInterface: PUBLIC PROC[handle: REF ImportInstance] RETURNS[REF ImportInstance] = { RETURN[NIL] }; myMachine: RPCPkt.Machine; -- ******** Initialization ******** -- Initialize: ENTRY PROC = BEGIN BEGIN myAddr: PupDefs.PupAddress = PupDefs.AnyLocalPupAddress[[0,0]]; myMachine _ [net: myAddr.net, host: myAddr.host]; END; IF exportTable.used = 0 THEN BEGIN binderMDS: CARDINAL = PrincOpsUtils.HighHalf[LONG[LOOPHOLE[1,POINTER]]]; exportTable[binderHint] _ [binderID, Binder, binderMDS, ["Binder",NIL,[0,0]], [0,0]]; exportTable.used _ 1; END; END; Restart: ENTRY PROC = { lastExportID _ BasicTime.Period[from: BasicTime.earliestGMT, to: BasicTime.Now[]] }; Initialize[]; DO STOP; Restart[]; ENDLOOP; END. RPC: Binding primitives RPCBinding.mesa Andrew Birrell September 7, 1983 4:40 pm Last Edited by: MBrown, March 30, 1983 4:20 pm Representation of exports in the GV database: Each interface type is a group, such as "Alpine.pa" Members of the group are the interface instances. Each interface instance is an individual, such as "MontBlanc.pa" Connect-site for the individual contains the exporting host. The syntax of instances' connect-sites is (all octal): net#host#mds. Details of the exported dispatcher are kept only in the exporting machine. The importer obtains the details by an RPC call to dispatcher 1 on that machine. "Bind" makes the call, "Binder" is dispatcher 1 on every machine. "LocalBind" accepts the call. "Bind" returns RPCPkt.noDispatcher for unbound instances. Êy˜Jšœ™Jšœ™Jšœ)™)Jšœ.™.J˜šÏk ˜ Jšœ œ˜,Jšœœ˜Jšœ œ6˜DJšœœ(˜5Jšœœ˜*JšœœB˜OJšœœœ'˜Jšœ˜šœœ/˜3Jšœ˜Jšœ.œœœ˜Ešœ ˜J˜J˜———Jšœ¹™¹J˜Jšœ œ˜:J˜Jšœ œ˜J˜š œœœ œœ˜.J˜J˜J˜&J˜—š œ œœ œœ˜,Jšœ œ˜Jšœ œŸ˜0Jšœ œŸ˜3JšŸ:œ˜˜Jš œ œœœœ$˜G——Jšœ9˜;Jšœœ˜%Jšœ$˜&Jšœ/˜2šœ4˜7Jšœ4˜6—Jšœœ ˜*Jšœ'˜)Jšœ-˜0Jšœœ˜(Jšœ'˜)Jšœ*˜-šœ2˜5Jšœ2˜4—Jšœœ ˜*Jšœ˜Jšœ˜J˜—šžœœœ œ˜:Jšœœ˜Jšœœœ˜J˜—J˜J˜J˜J˜J˜JšŸ&˜&J˜šž œœœ˜Jš˜š˜Jšœ?˜?J˜1—Jšœ˜Jšœ˜šœ˜ Jš œ œœœœ˜H˜Jšœ(œ˜;—J˜Jšœ˜—Jšœ˜J˜—šžœœœ˜JšœV˜VJ˜J˜—J˜ J˜Jšœœ œ˜J˜Jšœ˜J˜—…—+v=