<<>> <> <> <> <> <> <<>> <> <<>> DIRECTORY Arpa USING [Address, nullAddress], Atom USING [GetPName, MakeAtom], Basics USING [HFromCard16, LowHalf], Convert USING [ArpaAddressFromRope], IO USING [rope, PutFR1], LoganBerry, LoganBerryClass USING [Class, ClassObject, Register], LoganBerrySunRPC, LoganBerrySunRPCClient, RefID USING [Seal, Unseal], Rope USING [Concat, Find, FromRefText, Length, Replace, ROPE, Substr], SunPMap USING [ipProtocolUDP, udpPort], SunPMapClient USING [GetPort], SunRPC USING [Error, Handle], SunRPCOnUDP USING [Create, SetRemote], SunRPCAuth USING [Initiate], SunYPAgent USING [Error, Handle, Match, ObtainHandle, ReleaseHandle, Tokenize]; LoganBerrySunStubImpl: CEDAR MONITOR LOCKS dbinfo USING dbinfo: OpenDBInfo <<-- Operations are monitored to avoid concurrent callers using the same RPC handle.>> IMPORTS Atom, Basics, Convert, IO, LoganBerry, LoganBerryClass, LoganBerrySunRPCClient, RefID, Rope, SunPMapClient, SunRPC, SunRPCAuth, SunRPCOnUDP, SunYPAgent <> ~ BEGIN ROPE: TYPE = Rope.ROPE; Conv: TYPE ~ LoganBerry.Conv; OpenDB: TYPE ~ LoganBerry.OpenDB; AttributeType: TYPE ~ LoganBerry.AttributeType; AttributeValue: TYPE ~ LoganBerry.AttributeValue; Entry: TYPE ~ LoganBerry.Entry; EntryProc: TYPE ~ LoganBerry.EntryProc; Cursor: TYPE ~ LoganBerry.Cursor; CursorDirection: TYPE ~ LoganBerry.CursorDirection; LogID: TYPE ~ LoganBerry.LogID; activityLog: LogID ~ LoganBerry.activityLog; SchemaInfo: TYPE ~ LoganBerry.SchemaInfo; nilconv: INT = 0; OpenDBInfo: TYPE = REF OpenDBRecord; OpenDBRecord: TYPE = MONITORED RECORD [ h: SunRPC.Handle ¬ NIL, db: CARD32 ]; CursorInfo: TYPE = REF CursorRecord; CursorRecord: TYPE = RECORD[ dbinfo: OpenDBInfo, cursor: CARD32 ]; <> <> CheckName: PROC [dbName: ROPE] RETURNS [accept: BOOLEAN, server: ROPE, nameOnServer: ROPE] ~ { fullPathName: ROPE; serverIndex: INT; sunName: BOOL ¬ TRUE; fullPathName ¬ dbName; accept ¬ FALSE; serverIndex ¬ Rope.Find[s1: fullPathName, s2: "-SUN", case: FALSE]; IF serverIndex = -1 THEN { sunName ¬ FALSE; serverIndex ¬ Rope.Find[s1: fullPathName, s2: "-ARPA", case: FALSE]}; IF serverIndex > -1 THEN { -- found either -sun or -arpa suffix newlength: INT; fullServerName: ROPE; serverNameLength: INT ¬ serverIndex - 1; accept ¬ TRUE; server ¬ Rope.Substr[base: fullPathName, start: 1, len: serverNameLength]; IF sunName THEN fullServerName ¬ Rope.Concat[base: server, rest: "-SUN"] ELSE fullServerName ¬ Rope.Concat[base: server, rest: "-ARPA"]; <> newlength ¬ Rope.Length[fullServerName] ; nameOnServer ¬ NIL; nameOnServer ¬ Rope.Replace[base: fullPathName, start: 1, len: newlength, with: NIL]; newlength ¬ Rope.Length[nameOnServer]; nameOnServer ¬ Rope.Substr[base: nameOnServer, start: 1, len: newlength]; }; }; ypMap: ROPE ¬ "hosts.byname"; SunYPNameToAddress: PROC [name: ROPE] RETURNS [addr: Arpa.Address ¬ Arpa.nullAddress] ~ { ENABLE SunYPAgent.Error => CONTINUE; mapEntry: REF TEXT ¬ NIL; h: SunYPAgent.Handle ¬ SunYPAgent.ObtainHandle[]; -- use default domain mapEntry ¬ SunYPAgent.Match[h, ypMap, name]; SunYPAgent.ReleaseHandle[h]; IF mapEntry # NIL THEN { <> addrText: REF TEXT ¬ SunYPAgent.Tokenize[mapEntry][0]; -- address is at front of mapEntry addr ¬ Convert.ArpaAddressFromRope[Rope.FromRefText[addrText]]; }; }; <> Open: PROC [conv: Conv ¬ NIL, dbName: ROPE] RETURNS [db: OpenDB] ~ { ENABLE { SunRPC.Error => PostSunError[code]; LoganBerrySunRPCClient.Error => ERROR LoganBerry.Error[Atom.MakeAtom[ec], explanation]; }; accept: BOOLEAN; server, nameOnServer: ROPE; dbinfo: OpenDBInfo; addr: Arpa.Address; port: CARD; [accept, server, nameOnServer] ¬ CheckName[dbName]; IF NOT accept THEN RETURN[LoganBerry.nullDB]; dbinfo ¬ NEW[OpenDBRecord]; addr ¬ SunYPNameToAddress[server]; IF ( addr = Arpa.nullAddress ) THEN ERROR LoganBerry.Error[$CantOpenSchema, IO.PutFR1["Unknown server: %g.", IO.rope[server]]]; dbinfo.h ¬ SunRPCOnUDP.Create[addr, Basics.HFromCard16[SunPMap.udpPort]]; port ¬ SunPMapClient.GetPort[dbinfo.h, SunRPCAuth.Initiate[], 390905, 1, SunPMap.ipProtocolUDP ! SunRPC.Error => ERROR LoganBerry.Error[$CantOpenSchema, IO.PutFR1["Can't contact remote server: %g.", IO.rope[server]]]]; IF port = 0 THEN ERROR LoganBerry.Error[$CantOpenSchema, IO.PutFR1["LoganBerry not exported on server: %g.", IO.rope[server]]]; dbinfo.h ¬ SunRPCOnUDP.SetRemote[dbinfo.h, addr, Basics.HFromCard16[Basics.LowHalf[port]]]; dbinfo.db ¬ LoganBerrySunRPCClient.Open[dbinfo.h, nilconv, nameOnServer]; RETURN[RefID.Seal[dbinfo]]; }; ReadEntry: PROC [conv: Conv ¬ NIL, db: OpenDB, key: AttributeType, value: AttributeValue] RETURNS [entry: Entry, others: BOOLEAN] ~ { ENABLE { SunRPC.Error => PostSunError[code]; LoganBerrySunRPCClient.Error => ERROR LoganBerry.Error[Atom.MakeAtom[ec], explanation]; }; dbinfo: OpenDBInfo ¬ GetInfo[db]; [entry, others] ¬ ReadEntryI[dbinfo, key, value]; RETURN[entry, others]; }; ReadEntryI: PUBLIC ENTRY PROC [dbinfo: OpenDBInfo, key: AttributeType, value: AttributeValue] RETURNS [entry: Entry, others: BOOLEAN] ~ { ENABLE UNWIND => NULL; srEntry: LoganBerrySunRPC.Entry; [srEntry, others] ¬ LoganBerrySunRPCClient.ReadEntry[dbinfo.h, nilconv, dbinfo.db, Atom.GetPName[key], value]; entry ¬ SrToEntry[srEntry]; }; EnumerateEntries: PROC [db: OpenDB, key: AttributeType, start: AttributeValue ¬ NIL, end: AttributeValue ¬ NIL, proc: EntryProc] RETURNS [] ~ { entry: Entry; c: Cursor ¬ GenerateEntries[NIL, db, key, start, end]; entry ¬ NextEntry[NIL, c]; WHILE entry # NIL DO IF NOT proc[entry] THEN EXIT; entry ¬ NextEntry[NIL, c]; ENDLOOP; EndGenerate[NIL, c]; }; GenerateEntries: PROC [conv: Conv ¬ NIL, db: OpenDB, key: AttributeType, start: AttributeValue ¬ NIL, end: AttributeValue ¬ NIL] RETURNS [cursor: Cursor] ~ { ENABLE { SunRPC.Error => PostSunError[code]; LoganBerrySunRPCClient.Error => ERROR LoganBerry.Error[Atom.MakeAtom[ec], explanation]; }; cinfo: CursorInfo; dbinfo: OpenDBInfo ¬ GetInfo[db]; cinfo ¬ GenerateEntriesI[dbinfo, key, start, end]; RETURN[RefID.Seal[cinfo]]; }; GenerateEntriesI: PUBLIC ENTRY PROC [dbinfo: OpenDBInfo, key: AttributeType, start: AttributeValue ¬ NIL, end: AttributeValue ¬ NIL] RETURNS [cinfo: CursorInfo] ~ { ENABLE UNWIND => NULL; cinfo ¬ NEW[CursorRecord]; cinfo.dbinfo ¬ dbinfo; cinfo.cursor ¬ LoganBerrySunRPCClient.GenerateEntries[dbinfo.h, nilconv, dbinfo.db, Atom.GetPName[key], start, end]; }; NextEntry: PROC [conv: Conv ¬ NIL, cursor: Cursor, dir: CursorDirection ¬ increasing] RETURNS [entry: Entry] ~ { ENABLE { SunRPC.Error => PostSunError[code]; LoganBerrySunRPCClient.Error => ERROR LoganBerry.Error[Atom.MakeAtom[ec], explanation]; }; cinfo: CursorInfo ¬ GetCursorInfo[cursor]; entry ¬ NextEntryI[cinfo.dbinfo, cinfo, dir]; RETURN[entry]; }; NextEntryI: PUBLIC ENTRY PROC [dbinfo: OpenDBInfo, cinfo: CursorInfo, dir: CursorDirection ¬ increasing] RETURNS [entry: Entry] ~ { ENABLE UNWIND => NULL; srEntry: LoganBerrySunRPC.Entry; srEntry ¬ LoganBerrySunRPCClient.NextEntry[cinfo.dbinfo.h, nilconv, cinfo.cursor, IF dir=increasing THEN increasing ELSE decreasing]; entry ¬ SrToEntry[srEntry]; }; EndGenerate: PROC [conv: Conv ¬ NIL, cursor: Cursor] RETURNS [] ~ { ENABLE { SunRPC.Error => PostSunError[code]; LoganBerrySunRPCClient.Error => ERROR LoganBerry.Error[Atom.MakeAtom[ec], explanation]; }; cinfo: CursorInfo ¬ GetCursorInfo[cursor]; EndGenerateI[cinfo.dbinfo, cinfo]; }; EndGenerateI: PUBLIC ENTRY PROC [dbinfo: OpenDBInfo, cinfo: CursorInfo] RETURNS [] ~ { ENABLE UNWIND => NULL; LoganBerrySunRPCClient.EndGenerate[cinfo.dbinfo.h, nilconv, cinfo.cursor]; }; WriteEntry: PROC [conv: Conv ¬ NIL, db: OpenDB, entry: Entry, log: LogID ¬ activityLog, replace: BOOLEAN ¬ FALSE] RETURNS [] ~ { ENABLE { SunRPC.Error => PostSunError[code]; LoganBerrySunRPCClient.Error => ERROR LoganBerry.Error[Atom.MakeAtom[ec], explanation]; }; dbinfo: OpenDBInfo ¬ GetInfo[db]; WriteEntryI[dbinfo, entry, log, replace]; }; WriteEntryI: PUBLIC ENTRY PROC [dbinfo: OpenDBInfo, entry: Entry, log: LogID ¬ activityLog, replace: BOOLEAN ¬ FALSE] RETURNS [] ~ { ENABLE UNWIND => NULL; LoganBerrySunRPCClient.WriteEntry[dbinfo.h, nilconv, dbinfo.db, EntryToSr[entry], log, replace]; }; DeleteEntry: PROC [conv: Conv ¬ NIL, db: OpenDB, key: AttributeType, value: AttributeValue] RETURNS [deleted: Entry] ~ { ENABLE { SunRPC.Error => PostSunError[code]; LoganBerrySunRPCClient.Error => ERROR LoganBerry.Error[Atom.MakeAtom[ec], explanation]; }; dbinfo: OpenDBInfo ¬ GetInfo[db]; deleted ¬ DeleteEntryI[dbinfo, key, value]; RETURN[deleted]; }; DeleteEntryI: PUBLIC ENTRY PROC [dbinfo: OpenDBInfo, key: AttributeType, value: AttributeValue] RETURNS [deleted: Entry] ~ { ENABLE UNWIND => NULL; srEntry: LoganBerrySunRPC.Entry; srEntry ¬ LoganBerrySunRPCClient.ReadEntry[dbinfo.h, nilconv, dbinfo.db, Atom.GetPName[key], value].entry; LoganBerrySunRPCClient.DeleteEntry[dbinfo.h, nilconv, dbinfo.db, Atom.GetPName[key], value]; deleted ¬ SrToEntry[srEntry]; }; Close: PROC [conv: Conv ¬ NIL, db: OpenDB] RETURNS [] ~ { ENABLE { SunRPC.Error => PostSunError[code]; LoganBerrySunRPCClient.Error => ERROR LoganBerry.Error[Atom.MakeAtom[ec], explanation]; }; dbinfo: OpenDBInfo ¬ GetInfo[db]; CloseI[dbinfo]; }; CloseI: PUBLIC ENTRY PROC [dbinfo: OpenDBInfo] RETURNS [] ~ { ENABLE UNWIND => NULL; LoganBerrySunRPCClient.Close[dbinfo.h, nilconv, dbinfo.db]; }; BuildIndices: PROC [conv: Conv ¬ NIL, db: OpenDB] RETURNS [] ~ { ENABLE { SunRPC.Error => PostSunError[code]; LoganBerrySunRPCClient.Error => ERROR LoganBerry.Error[Atom.MakeAtom[ec], explanation]; }; dbinfo: OpenDBInfo ¬ GetInfo[db]; BuildIndicesI[dbinfo]; }; BuildIndicesI: PUBLIC ENTRY PROC [dbinfo: OpenDBInfo] RETURNS [] ~ { ENABLE UNWIND => NULL; LoganBerrySunRPCClient.BuildIndices[dbinfo.h, nilconv, dbinfo.db]; }; CompactLogs: PROC [conv: Conv ¬ NIL, db: OpenDB] RETURNS [] ~ { ENABLE { SunRPC.Error => PostSunError[code]; LoganBerrySunRPCClient.Error => ERROR LoganBerry.Error[Atom.MakeAtom[ec], explanation]; }; dbinfo: OpenDBInfo ¬ GetInfo[db]; CompactLogsI[dbinfo]; }; CompactLogsI: PUBLIC ENTRY PROC [dbinfo: OpenDBInfo] RETURNS [] ~ { ENABLE UNWIND => NULL; LoganBerrySunRPCClient.CompactLogs[dbinfo.h, nilconv, dbinfo.db]; }; Describe: PROC [conv: Conv ¬ NIL, db: OpenDB] RETURNS [info: SchemaInfo] ~ { ENABLE { SunRPC.Error => PostSunError[code]; LoganBerrySunRPCClient.Error => ERROR LoganBerry.Error[Atom.MakeAtom[ec], explanation]; }; dbinfo: OpenDBInfo ¬ GetInfo[db]; info ¬ DescribeI[dbinfo]; RETURN[info]; }; DescribeI: PUBLIC ENTRY PROC [dbinfo: OpenDBInfo] RETURNS [info: SchemaInfo] ~ { ENABLE UNWIND => NULL; srInfo: LoganBerrySunRPC.SchemaInfo; srInfo ¬ LoganBerrySunRPCClient.Describe[dbinfo.h, nilconv, dbinfo.db]; info ¬ SrToSchemaInfo[srInfo]; }; IsLocal: PROC [db: LoganBerry.OpenDB] RETURNS [local: BOOL ¬ TRUE] = { RETURN[FALSE]; }; PostSunError: PROC [code: ATOM] RETURNS [] ~ { <> ERROR LoganBerry.Error[$CallFailed, IO.PutFR1["SUN RPC stub problem - %g.", IO.rope[SELECT code FROM $timeout, $unreachable => "server unreachable", $protocolError => "protocol error", $wrongRPCVersion, $wrongProgram, $wrongProgramVersion, $wrongProc => "using wrong program, version, or procedure", ENDCASE => "unknown error" ]]]; }; <> GetInfo: PROC [db: OpenDB] RETURNS [OpenDBInfo] ~ INLINE { <> ref: REF = RefID.Unseal[db]; IF ref = NIL THEN ERROR LoganBerry.Error[$BadDBHandle, "NIL OpenDB handle."]; WITH ref SELECT FROM dbinfo: OpenDBInfo => { RETURN[dbinfo]; }; ENDCASE => ERROR LoganBerry.Error[$BadDBHandle, "Invalid OpenDB handle."]; }; GetCursorInfo: PROC [cursor: Cursor] RETURNS [CursorInfo] ~ INLINE { <> ref: REF = RefID.Unseal[cursor]; IF ref = NIL THEN ERROR LoganBerry.Error[$BadCursor, "NIL cursor."]; WITH ref SELECT FROM cinfo: CursorInfo => { RETURN[cinfo]; }; ENDCASE => ERROR LoganBerry.Error[$BadCursor, "Invalid cursor."]; }; <> SrToEntry: PROC [srEntry: LoganBerrySunRPC.Entry] RETURNS [entry: LoganBerry.Entry] ~ { entry ¬ NIL; FOR i: CARDINAL DECREASING IN [0..srEntry.length) DO attr: LoganBerry.Attribute ¬ [Atom.MakeAtom[srEntry[i].type], srEntry[i].value]; entry ¬ CONS[attr, entry]; ENDLOOP; }; EntryToSr: PROC [entry: LoganBerry.Entry] RETURNS [srEntry: LoganBerrySunRPC.Entry] ~ { count: CARDINAL ¬ 0; FOR e: Entry ¬ entry, e.rest WHILE e # NIL DO count ¬ count + 1; ENDLOOP; srEntry ¬ NEW[LoganBerrySunRPC.EntryObject[count]]; count ¬ 0; FOR e: Entry ¬ entry, e.rest WHILE e # NIL DO srEntry[count].type ¬ Atom.GetPName[e.first.type]; srEntry[count].value ¬ e.first.value; count ¬ count + 1; ENDLOOP; }; SrToSchemaInfo: PROC [srInfo: LoganBerrySunRPC.SchemaInfo] RETURNS [info: LoganBerry.SchemaInfo] ~ { SrToLogList: PROC [srLogs: LoganBerrySunRPC.LogList] RETURNS [logs: LIST OF LoganBerry.LogInfo] ~ { logs ¬ NIL; FOR i: CARDINAL DECREASING IN [0..srLogs.length) DO loginfo: LoganBerry.LogInfo ¬ NEW[LoganBerry.LogInfoRec ¬ [srLogs[i].id, srLogs[i].file]]; logs ¬ CONS[loginfo, logs]; ENDLOOP; }; SrToIndexList: PROC [srIndices: LoganBerrySunRPC.IndexList] RETURNS [indices: LIST OF LoganBerry.IndexInfo] ~ { indices ¬ NIL; FOR i: CARDINAL DECREASING IN [0..srIndices.length) DO indexinfo: LoganBerry.IndexInfo ¬ NEW[LoganBerry.IndexInfoRec ¬ [Atom.MakeAtom[srIndices[i].key], srIndices[i].file, Atom.MakeAtom[srIndices[i].order]]]; indices ¬ CONS[indexinfo, indices]; ENDLOOP; }; info ¬ NEW[LoganBerry.SchemaInfoRec ¬ [srInfo.dbName, SrToLogList[srInfo.logs], SrToIndexList[srInfo.indices]]]; }; <> class: LoganBerryClass.Class; Init: PROC ~ { LoganBerryClass.Register[name: class.name, class: class]; }; class ¬ NEW[LoganBerryClass.ClassObject ¬ [ name: $SunRPCStub, open: Open, describe: Describe, readEntry: ReadEntry, enumerateEntries: EnumerateEntries, generateEntries: GenerateEntries, nextEntry: NextEntry, endGenerate: EndGenerate, writeEntry: WriteEntry, deleteEntry: DeleteEntry, close: Close, buildIndices: BuildIndices, compactLogs: CompactLogs, isLocal: IsLocal, classData: NIL ]]; Init[]; END. <<>>