<> <> <> <> DIRECTORY Arpa USING [ Address, nullAddress ], ArpaUDP USING [ Port ], Basics USING [ Card16FromH, LowHalf, HFromCard16 ], CardTab USING [ Ref, Create, Fetch, Store ], ConvertExtras USING [ ArpaAddressFromRope ], IO, RefID USING [ ID ], RefTab USING [ Create, Delete, Fetch, Ref, Store ], Rope USING [ FromRefText, ROPE ], RPC USING [ Conversation, GenerateConversation ], RuntimeError USING [ UNCAUGHT ], SunPMap USING [ ipProtocolUDP, udpPort ], SunPMapLocal USING [ SetLocal, ipProtocolUDP ], SunPMapClient USING [ GetPort ], SunRPC USING [ Create, CreateServer, Destroy, DestroyServer, Error, GetServerPort, Handle, nullPort, ReleaseReply, SendCallAndReceiveReply, Server, ServerProc, SetRemote, StartCall ], SunRPCAuth USING [ Initiate ], SunYPAgent USING [Error, Handle, Match, ObtainHandle, ReleaseHandle, Tokenize], SRPCCalls USING [ Conversation, ReportProc, SHandle, SunRPCHandleBody, TimeoutEnable ], VoiceUtilsExtras USING [ SunProtocol, SunAddrFromRope ]; SRPCCallsImpl: CEDAR MONITOR LOCKS sHandle.LOCK USING sHandle: SRPCCalls.SHandle IMPORTS Basics, CardTab, ConvertExtras, IO, RefTab, Rope, RPC, RuntimeError, SunRPC, SunPMapClient, SunPMapLocal, SunRPCAuth, SunYPAgent, VoiceUtilsExtras EXPORTS SRPCCalls ~ { OPEN IO; Handle: TYPE ~ SunRPC.Handle; ROPE: TYPE ~ Rope.ROPE; SunRPCPutArgsProc: TYPE ~ PROC [h: Handle]; SunRPCGetResultsProc: TYPE ~ PROC [h: Handle]; SunRPCGetErrorProc: TYPE ~ PROC [h: Handle]; <> <<>> <> Error: PUBLIC ERROR[errCode: ATOM, explanation: ROPE] ~ CODE; SunRPCProgramCall: PUBLIC PROC [h: Handle, remoteProc: CARD, putArgs: SunRPCPutArgsProc, getResults: SunRPCGetResultsProc, getError: SunRPCGetErrorProc] ~ { sHandle: SHandle _ SHandleFromHandle[h]; IF sHandle=NIL THEN Error[$BrokenDataStructures, "No semantics for conversation"]; sHandle.errorDetected _ FALSE; DoSunRPCProgramCall[sHandle, remoteProc, putArgs, getResults, getError]; }; DoSunRPCProgramCall: ENTRY PROC [sHandle: SHandle, remoteProc: CARD, putArgs: SunRPCPutArgsProc, getResults: SunRPCGetResultsProc, getError: SunRPCGetErrorProc] ~ { ENABLE { SunRPC.Error => { errorDetected: BOOL _ sHandle.errorDetected; sHandle.connected _ FALSE; sHandle.errorDetected _ TRUE; SELECT code FROM $unreachable, $timeout, $wrongProgram, $wrongProgramVersion, $wrongProc => IF sHandle.enabled AND ~errorDetected THEN { IF sHandle.reportProc#NIL THEN sHandle.reportProc[sHandle, code, "Automatic reconnect will be attempted."]; RETRY; } ELSE Error[code, "Recovery from original error failed."]; ENDCASE => { sHandle.enabled _ FALSE; Error[code, "Cannot recover automatically."]; }; }; UNWIND => NULL; Error => NULL; -- Just in case; RuntimeError.UNCAUGHT => { sHandle.connected _ FALSE; sHandle.errorDetected _ TRUE; sHandle.enabled _ FALSE; <> Error[$UnknownError, NIL]; }; }; h: Handle; IF ~sHandle.connected THEN IF sHandle.enabled THEN { ec: ATOM; ex: ROPE; [ec, ex] _ ImportInterface[sHandle]; IF ec#NIL THEN Error[ec, ex]; } ELSE Error[$disconnected, "Not connected from server"]; h _ sHandle.handle; SunRPC.StartCall[h~h, c~SunRPCAuth.Initiate[], pgm~sHandle.rpcProgram, version~sHandle.rpcVersion, proc~remoteProc]; putArgs[sHandle.handle]; [] _ SunRPC.SendCallAndReceiveReply[h~h, timeoutMsec~sHandle.timeoutInMs, retries~sHandle.retries]; getError[h]; <> getResults[h]; SunRPC.ReleaseReply[h]; }; <> <<>> <> Conversation: TYPE ~ SRPCCalls.Conversation; SHandle: TYPE ~ SRPCCalls.SHandle; SHandleBody: TYPE ~ SRPCCalls.SunRPCHandleBody; TimeoutEnable: TYPE ~ SRPCCalls.TimeoutEnable; ID: TYPE ~ RefID.ID; conversationToSHandleMap: RefTab.Ref _ RefTab.Create[]; handleToSHandleMap: RefTab.Ref _ RefTab.Create[]; NewRPCConversation: PUBLIC PROC [ serverName: Rope.ROPE, rpcProgram: CARD, rpcVersion: CARD, clientData: REF, reportProc: SRPCCalls.ReportProc _ NIL, timeoutEnable: TimeoutEnable, timeoutInMs: INT, retries: INT] RETURNS [conversation: Conversation] ~ { sHandle: SHandle; conversation _ RPC.GenerateConversation[]; sHandle _ NEW[SHandleBody _ [serverName: serverName, rpcProgram: rpcProgram, rpcVersion: rpcVersion, timeoutEnable: timeoutEnable, timeoutInMs: timeoutInMs, retries: retries, clientData: clientData, conversation: conversation, reportProc: reportProc, handle: SunRPC.Create[]]]; []_conversationToSHandleMap.Store[conversation, sHandle]; []_handleToSHandleMap.Store[sHandle.handle, sHandle]; -- Dummy handle until really imported }; ReleaseConversation: PUBLIC PROC [conversation: Conversation] ~ { sHandle: SHandle; IF conversation = NIL THEN RETURN; sHandle _ GetSHandle[conversation]; IF sHandle = NIL THEN RETURN; []_conversationToSHandleMap.Delete[conversation]; IF sHandle.handle#NIL THEN { []_handleToSHandleMap.Delete[sHandle.handle]; SunRPC.Destroy[sHandle.handle]; }; sHandle.connected _ FALSE; sHandle.conversation _ NIL; -- Break any sHandle.handle _ NIL; -- loops sHandle.clientData _ NIL; }; GetSHandle: PUBLIC PROC[conversation: Conversation] RETURNS [sHandle: SHandle] ~ { RETURN[NARROW[conversationToSHandleMap.Fetch[conversation].val]]; }; SHandleFromHandle: PROC[handle: Handle] RETURNS [sHandle: SHandle] ~ { RETURN[NARROW[handleToSHandleMap.Fetch[handle].val]]; }; ImportInterface: INTERNAL PROC[sHandle: SHandle] RETURNS[errCode: ATOM _ NIL, expl: ROPE _ NIL] ~ { ENABLE { SunRPC.Error => { errCode _ code; SELECT code FROM $unreachable, $timeout => NULL; ENDCASE => sHandle.enabled _ FALSE; CONTINUE; }; RuntimeError.UNCAUGHT => { errCode _ $UnknownError; sHandle.enabled _ FALSE; CONTINUE; }; }; server: Rope.ROPE _ sHandle.serverName; addr: Arpa.Address _ Arpa.nullAddress; handle, oldHandle: Handle; sHandle.connected _ FALSE; oldHandle _ sHandle.handle; IF VoiceUtilsExtras.SunProtocol[server] THEN { uPort: ArpaUDP.Port; [addr, uPort] _ VoiceUtilsExtras.SunAddrFromRope[server]; handle _ SunRPC.Create[addr, uPort]; } ELSE IF server#NIL THEN { port: CARD; addr _ SunYPNameToAddress[server]; handle _ SunRPC.Create[addr, Basics.HFromCard16[SunPMap.udpPort]]; port _ SunPMapClient.GetPort[handle, SunRPCAuth.Initiate[], sHandle.rpcProgram, sHandle.rpcVersion, SunPMap.ipProtocolUDP ! SunRPC.Error => { errCode _ code; expl _ IO.PutFR["Can't contact remote server: %g.", IO.rope[server]];}]; IF errCode#NIL THEN RETURN; IF port = 0 THEN RETURN [$CantConnect, IO.PutFR["ThParty not exported on server: %g.", IO.rope[server]]]; handle _ SunRPC.SetRemote[handle, addr, Basics.HFromCard16[Basics.LowHalf[port]]]; }; IF addr = Arpa.nullAddress THEN RETURN[$CantOpenSchema, IO.PutFR["Unknown server: %g.", IO.rope[server]]]; []_handleToSHandleMap.Store[handle, sHandle]; sHandle.handle _ handle; IF oldHandle#NIL THEN { []_handleToSHandleMap.Delete[oldHandle]; SunRPC.Destroy[oldHandle]; }; sHandle.connected _ TRUE; }; 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 _ ConvertExtras.ArpaAddressFromRope[Rope.FromRefText[addrText]]; }; }; ExportSunRPCInterface: PUBLIC PROC [ previousPort: CARD_0, server: SunRPC.ServerProc, rpcPgm: CARD, rpcPgmVersion: CARD] RETURNS [uniquePort: CARD] ~ { ENABLE SunRPC.Error => Error[code, "export failed"]; ok: BOOL; -- Do something with this!! theServer: SunRPC.Server _ GetServer[previousPort]; -- in case server already running IF theServer#NIL THEN SunRPC.DestroyServer[theServer]; -- remove old server theServer _ SunRPC.CreateServer[pgm~rpcPgm, serverProc~server, version~rpcPgmVersion, port: SunRPC.nullPort ]; uniquePort _ Basics.Card16FromH[SunRPC.GetServerPort[theServer]]; ok _ SunPMapLocal.SetLocal[program~rpcPgm, version~rpcPgmVersion, protocol~SunPMapLocal.ipProtocolUDP, port~uniquePort]; [] _ sunServerTable.Store[key: uniquePort, val: NEW[SunRPC.Server _ theServer] ]; }; <> sunServerTable: CardTab.Ref _ CardTab.Create[]; WrapOpaqueType: TYPE = REF SunRPC.Server; <> GetServer: PROC [port: CARD] RETURNS [SunRPC.Server] = INLINE { wrapper: WrapOpaqueType _ NARROW[CardTab.Fetch[x: sunServerTable, key: port].val]; RETURN[IF wrapper=NIL THEN NIL ELSE wrapper^] }; }.