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^] }; }. ΠSRPCCallsImpl.mesa Copyright Σ 1990 by Xerox Corporation. All rights reserved. Pier, May 24, 1990 2:38:04 pm PDT Swinehart, September 17, 1990 6:01:07 pm PDT Placing calls -- This is where this module differs most from the Courier stub from which it is derived. We define a SunRPCCall that looks similar to the CrRPC.Call and hides the differences in calling sequences between the two protocols. Since SUN RPC doesn't have any error handling mechanism, remote errors are returned as explict error codes. An error code is at the head of all returned results. If the returned error code is NIL, then the regular procedure results follow; otherwise, the error code is followed by the error explanation. Don't risk reconnects, when you don't know what happened. The following will not be called if getError raises an Error. Handle Management NewRPCConversation creates a Conversation, an SHandle, and a dummy RPC Handle, but does not actually import the interface. Instead, the interface is imported any time a call is made when the SHandle indicates that the remote server is disconnected. In addition, whenever a call fails due to timeout or other potentially correctable problems, an attempt is made to re-bind to the remote service and retry the call before giving up. But only one attempt is made. map entry is something like "13.0.208.72 baobab baobab.parc.xerox.com" A table is kept to map ports to servers, so that an old version of a server can be removed before a new one is exported. The SunPMap package does a similar job, but it distinguishes only on the basis of program and version, so doesn't support multiple instances of an interface exported from the same machine. Can't NARROW or LOOPHOLE to an opaque type Κ }˜codešœ™K™—K˜—Kšœ œ˜'K˜&K˜Kšœœ˜K˜˜.K˜K˜9K˜$K˜—šœœœ˜Kšœœ˜ Kšœ"˜"KšœB˜BšœŒ ˜Kš  œ˜Kšœœ+œ œ˜H—Kšœ œœœ˜šœ œ˜Kšœœ.œ˜X—šœ˜KšœI˜I—K˜—šœ˜Kšœœœ˜J—Kšœ-˜-K˜šœ œœ˜Kšœ(˜(K˜K˜—Kšœœ˜K˜K˜—Kšœœ˜K˜šžœœœœ,˜YKšœœ˜$Kšœ œ œ˜Kšœ3Ÿ˜HKšœ,˜,Kšœ˜šœ œœ˜KšœF™FKšœ œœ&Ÿ"˜ZKšœE˜EK˜—K˜K˜—šžœœœ˜$Kšœœ'œœ˜SKšœœ˜Kšœ.˜4KšœœŸΠctŸ‘˜(Kšœ8Ÿ˜VKšœ œœ#Ÿ˜LKšœn˜nKšœA˜AKšœx˜xK•StartOfExpansion7[x: RefTab.Ref, key: RefTab.Key, val: RefTab.Val]šœ0œ˜QK˜K˜—K™ΆK˜K˜/K˜šœœœ˜)Kšœ*™*—K˜–$[x: RefTab.Ref, key: RefTab.Key]š ž œœœœΠbkœ˜?Kšœœ2˜RKš œœ œœœœ ˜-Kšœ˜K˜—K˜K˜—K˜—…— V0£