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 [AuthenticateFailure, CallFailed, CallFailure, EncryptionKey, ExportFailed, ExportFailure, ImportFailed, ImportFailure, InterfaceName, matchAllVersions, Principal, VersionRange], RPCInternal USING [ExportInstance, ExportTable, ImportInstance], RPCInternalExtras, 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, RPCInternalExtras, RPCLupine = { AuthenticateFailed: PUBLIC SAFE ERROR[why: RPC.AuthenticateFailure] = CODE; CallFailed: PUBLIC SAFE SIGNAL[why: RPC.CallFailure] = CODE; ExportFailed: PUBLIC SAFE ERROR[why: RPC.ExportFailure] = CODE; ImportFailed: PUBLIC SAFE ERROR[why: RPC.ImportFailure] = CODE; LongEquivalent: PROC [a: LONG STRING, b: Rope.ROPE] RETURNS [BOOL] = { 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 { 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]; }; ENDLOOP; RETURN[TRUE] }; CopyRope: PROC [from: Rope.ROPE, to: LONG POINTER] = { 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]]]; }; InstanceInfo: TYPE = { ok, badName, allDown, noAddress }; LocateInstance: PROC [instance: Rope.ROPE] RETURNS [info: InstanceInfo, isRName: BOOL, host: RPCPkt.Machine] = { connect: Rope.ROPE _ NIL; IF instance.Length[] > GVBasics.maxRNameLength THEN RETURN[badName,,]; isRName _ Rope.Find[instance, "."] >= 0; IF isRName THEN { info: GVNames.ConnectInfo; [info, connect] _ GVNames.GetConnect[instance]; SELECT info FROM individual => NULL; notFound, group => RETURN[badName,isRName,]; allDown => RETURN[allDown,isRName,]; ENDCASE => ERROR; } ELSE connect _ instance; IF connect.Length[] = 0 THEN info _ IF isRName THEN noAddress ELSE badName ELSE { 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]; }; }; 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 { RETURN[GVBasics.MakeKey[text]] }; ExportInterface: PUBLIC PROC [user: RPC.Principal, password: RPC.EncryptionKey, interface: RPC.InterfaceName, dispatcher: RPCLupine.Dispatcher, stubProtocol: RPC.VersionRange, localOnly: BOOL _ FALSE] RETURNS [ instance: ExportHandle ] = { 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 ~localOnly AND interface.instance # NIL THEN { ENABLE UNWIND => [] _ UnexportInterface[instance]; prevHost: RPCPkt.Machine; prevInfo: InstanceInfo; isRName: BOOL; [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 { 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; } ELSE ERROR RPC.ExportFailed[badInstance]; }; }; lastExportID: RPCPkt.DispatcherID _ BasicTime.Period[from: BasicTime.earliestGMT, to: BasicTime.Now[]]; AddToExportTable: PUBLIC ENTRY PROC [interface: RPC.InterfaceName, dispatcher: RPCLupine.Dispatcher, stubProtocol: RPC.VersionRange] RETURNS [ instance: ExportHandle ] = { 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]; }; 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 = { 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]]; }; -- Server-implementation for binding calls -- LocalBind: ENTRY PROC [type, instance: LONG STRING] RETURNS [BinderResult] = { 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 exportTable[i].name.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,]]] }; RemoteBind: SAFE PROC [host: RPCPkt.Machine, type, instance: Rope.ROPE] RETURNS [BinderResult] = TRUSTED { 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]; { used: CARDINAL; args^ _ [binderProc, 0, 0]; used _ SIZE[BinderArgs]; IF type # NIL THEN { args.type _ used; CopyRope[from: type, to: @pkt[used]]; used _ used + SIZE[StringBody[type.Length[]]]; }; IF instance # NIL THEN { args.instance _ used; CopyRope[from: instance, to: @pkt[used]]; used _ used + SIZE[StringBody[instance.Length[]]]; }; IF used > pktSize THEN ERROR; [resultLength,] _ RPCLupine.Call[pkt, used, pktSize]; }; RETURN[LOOPHOLE[@pkt.data, POINTER TO BinderResult]^]; }; ImportInstance: PUBLIC TYPE = RPCInternal.ImportInstance; debugRemoteBind: BOOL _ FALSE; LocateImportInstance: PROC [instance: Rope.ROPE] RETURNS [host: RPCPkt.Machine] = { info: InstanceInfo; isRName: BOOL; [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; }; ImportInterface: PUBLIC PROC [interface: RPC.InterfaceName, stubProtocol: RPC.VersionRange, localOnly: BOOL _ FALSE] RETURNS [ handle: REF ImportInstance ] = { host: RPCPkt.Machine; dispatcher: RPCPkt.DispatcherDetails; IF interface.type = NIL THEN ERROR RPC.ExportFailed[badType]; IF debugRemoteBind AND NOT localOnly THEN { host _ LocateImportInstance[interface.instance]; dispatcher _ TryBinding[host, interface, stubProtocol]; } ELSE { host _ LocateImportInstance[interface.instance]; IF localOnly AND host # myMachine THEN ERROR RPC.ImportFailed[unbound] ELSE dispatcher _ TryBinding[host, interface, stubProtocol]; }; RETURN[NEW[ImportInstance _ [host,dispatcher]]] }; TryBinding: PROC [host: RPCPkt.Machine, impName: RPC.InterfaceName, stubProtocol: RPC.VersionRange] RETURNS [RPCPkt.DispatcherDetails] = CHECKED { 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]; }; UnimportInterface: PUBLIC PROC [handle: REF ImportInstance] RETURNS [REF ImportInstance] = { RETURN[NIL]; }; myMachine: RPCPkt.Machine; -- ******** Initialization ******** -- Initialize: ENTRY PROC = { { myAddr: PupDefs.PupAddress = PupDefs.AnyLocalPupAddress[[0,0]]; myMachine _ [net: myAddr.net, host: myAddr.host]; }; IF exportTable.used = 0 THEN { binderMDS: CARDINAL = PrincOpsUtils.HighHalf[LONG[LOOPHOLE[1,POINTER]]]; exportTable[binderHint] _ [binderID, Binder, binderMDS, ["Binder",NIL,[0,0]], [0,0]]; exportTable.used _ 1; }; }; Restart: ENTRY PROC = { lastExportID _ BasicTime.Period[from: BasicTime.earliestGMT, to: BasicTime.Now[]]; }; Initialize[]; DO STOP; Restart[]; ENDLOOP; }. vRPCBinding.mesa - Binding primitives (& signals) Copyright c 1985 by Xerox Corporation. All rights reserved. Bob Hagmann August 7, 1985 10:40:13 am PDT Russ Atkinson (RRA) October 29, 1985 8:59:12 am PST Hal Murray, January 22, 1986 4:37:00 pm PST Signals (formerly in RPCSignals) ******** Binding primitives ******** 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. UID on this machine 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. user-stub for binding calls Bob Hagmann August 7, 1985 10:40:13 am PDT changes to: AddToExportTable, RPCBinding, ExportHandle, DIRECTORY Κ˜codešœ0™0Kšœ Οmœ1™˜Kš žœ žœžœžœžœ$˜G——Kšžœ9˜;Kšžœžœ˜%Kšžœ$˜&Kšžœ/˜2šžœ4˜7Kšžœ4˜6—Kšžœžœ ˜*Kšžœ'˜)Kšžœ-˜0Kšžœžœ˜(Kšžœ'˜)Kšžœ*˜-šžœ2˜5Kšžœ2˜4—Kšžœžœ ˜*Kšžœ˜Kšœ˜K˜—šŸœžœžœ žœžœžœžœ˜\Kšžœžœ˜ Kšœ˜K˜—K˜K˜Kš &˜&K˜šŸ œžœžœ˜šœ˜Kšœ?˜?K˜1Kšœ˜—šžœžœ˜Kš œ žœžœžœžœ˜HKšœBžœ˜UK˜Kšœ˜—Kšœ˜K˜—šŸœžœžœ˜KšœR˜RKšœ˜K˜K˜—K˜ K˜Kšžœžœ žœ˜K˜Kšœ˜™*Kšœ Οr5™A—K™K™K™—…—,*>’