-- RPC: Interface between stubs and runtime. -- [Ivy]RPC>RPCLupine.mesa -- Bruce Nelson 6 Oct. 1981 9:44 am PDT (Tuesday) -- Andrew Birrell 16-Mar-82 14:09:17 DIRECTORY Inline USING[ BITOR, HighHalf, LongNumber, LowHalf ], MesaRPC USING[ Conversation, EncryptionKey, InterfaceName, maxPrincipalLength, maxShortStringLength, Principal, unencrypted, VersionRange ]; RPCLupine: DEFINITIONS IMPORTS Inline = BEGIN -- Definitions copied across from MesaRPC.mesa for Lupine's benefit -- maxPrincipalLength: CARDINAL = MesaRPC.maxPrincipalLength; maxShortStringLength: CARDINAL = MesaRPC.maxShortStringLength; -- StubPkt's are allocated in user-stubs. RPCPkt's are either StubPkt's -- or packets allocated by the RPC server processes. StubPkt's and -- RPCPkt's are never seen by the vanilla ethernet -- driver. StubPktData storage must be aligned to allow the packets to be -- passed to the ethernet face, and we must correct for the fact that Pup -- checksums are at the end of the packet. To allocate a packet having -- up to "n" words of data, declare an array of n+pktOverhead words, then -- call "GetStubPkt" to obtain the aligned packet. Thus, to allocate -- space for 250 words, declare: -- space: ARRAY[1..RPCLupine.pktOverhead+250] OF WORD; -- pkt: RPCLupine.StubPkt = RPCLupine.GetStubPkt[@space]; -- Horrible! It could be much neater if the compiler supported declaring -- sequence variables in the local frame. To allocate a maximum size StubPkt, -- declare: -- space: ARRAY[1..RPCLupine.pktOverhead+RPCLupine.maxDataLength] OF WORD; -- pkt: RPCLupine.StubPkt = RPCLupine.GetStubPkt[@space]; Encapsulation: PRIVATE TYPE[7]; -- large enough for all current networks -- Header: PRIVATE TYPE[10+6+4]; -- PUP header + RPC protocol overhead + dispatcher description. -- Must be aligned to quad-word + 2 -- maxPupWords: PRIVATE CARDINAL = -- maximum value of length field of Pup packet, in words, -- as defined in [Maxc]PupSpec.press -- 266 -- Pup data -- + 10 -- Pup header -- + 1 -- Pup checksum --; encryptionBlockSize: PRIVATE CARDINAL = 4; SecurityChecksum: PRIVATE TYPE[2]; maxDataLength: CARDINAL = -- Maximum data words in RPCPkt or StubPkt -- -- The following calculation assumes that the encrypted part of a header -- is a multiple of encryptionBlockSize -- ( ( maxPupWords - 1 -- Pup checksum -- - SIZE[Header] ) / encryptionBlockSize --round down--) * encryptionBlockSize - SIZE[SecurityChecksum]; DataLength: TYPE = [0..maxDataLength]; pktOverhead: CARDINAL = pktAlign -- wastage for aligning the buffer -- + SIZE[StubPktData[0]] + encryptionBlockSize-1 -- rounding -- + SIZE[SecurityChecksum] + 1 -- Pup checksum --; pktAlign: PRIVATE WORD = 3B; -- maximum wastage for quad-word alignment -- StubPkt: TYPE = POINTER TO StubPktData; RPCPkt: TYPE = LONG StubPkt; StubPktData: TYPE = MACHINE DEPENDENT RECORD[ -- must be suitably aligned -- convHandle: PRIVATE MesaRPC.Conversation, encapsulation: PRIVATE Encapsulation, header: PRIVATE Header, -- Pup/OIS header -- data: SEQUENCE COMPUTED DataLength OF UNSPECIFIED]; GetStubPkt: PROC[ space: POINTER TO UNSPECIFIED] RETURNS[--pkt:-- StubPkt ] = INLINE -- returns pointer aligned to quad-word plus one. That -- causes Ethernet-one encapsulation to start at quad-word (honest!). -- -- i.e. space=0 => result=1, -- space=1 => result=1, -- space=2 => result=5, -- space=3 => result=5. { RETURN[ LOOPHOLE[Inline.BITOR[space+2, pktAlign],POINTER]-2 ] }; GetRPCPkt: PROC[ space: LONG POINTER TO UNSPECIFIED] RETURNS[--pkt:-- RPCPkt ] = INLINE -- returns pointer aligned to quad-word plus one. That -- causes Ethernet-one encapsulation to start at quad-word (honest!). -- -- i.e. space=0 => result=1, -- space=1 => result=1, -- space=2 => result=5, -- space=3 => result=5. -- Unfortunately, the alignment may take us across a 64K boundary! { RETURN[ LOOPHOLE[Inline.LongNumber[num[ lowbits: Inline.BITOR[Inline.LowHalf[space+2], pktAlign] - 2, highbits: Inline.HighHalf[space+2] ]]]] }; -- Binding primitives for use by stubs -- -- Exporter specifies which interface type is being exported, and which -- instance of that type, and which "version" of that type. The stub -- should default the interface type to the timestamp of the definitions -- file bcd. The interface instance defaults to a newly created UID. The -- version is client-specified, meaning which range of versions this -- exporter supports. -- Importer specifies required interface type and instance, and version -- range. The stub should default the interface type to the timestamp of -- the definitions file bcd. Interface instance defaults to "any". -- The version range defaults to "any". -- The stubProtocol in imports and exports is used to check compatability -- of stub protocol versions. ExportHandle: TYPE[SIZE[CARDINAL]]; -- index to table of dispatcher procedures -- ExportInterface: PROC[user: MesaRPC.Principal, password: MesaRPC.EncryptionKey, interface: MesaRPC.InterfaceName, dispatcher: Dispatcher, stubProtocol: MesaRPC.VersionRange, localOnly: BOOLEAN _ FALSE] RETURNS[ interfaceInstance: ExportHandle ]; -- Registers export in binding database and local dispatcher table. -- The user and password provide credentials to update the binding -- database. If localOnly=TRUE then the network binding database is -- not updated. -- -- May raise MesaRPC.ExportFailed -- UnexportInterface: PROC[ interfaceInstance: ExportHandle ] RETURNS[ExportHandle]; -- Removes export from local dispatcher table and binding database. Returns -- an ExportHandle that will fault if used. -- ImportHandle: TYPE = LONG POINTER TO ImportInstance; ImportInstance: TYPE; ImportInterface: PROC[interface: MesaRPC.InterfaceName, stubProtocol: MesaRPC.VersionRange, localOnly: BOOLEAN _ FALSE] RETURNS[ interfaceInstance: ImportHandle ]; -- Searches binding database for exporter of specified interface. -- If localOnly=TRUE then the import will succeed only if the -- exporter is on this host. -- -- May raise MesaRPC.ImportFailed -- UnimportInterface: PROC[ interfaceInstance: ImportHandle ] RETURNS[ ImportHandle ]; -- Releases local representation of binding. Returns an ImportHandle -- that will fault if used. -- -- Stubs: sending and receiving packets. -- For a user-stub making a call, the call sequence is: -- StartCall, SendPrelimPkt*, Call, ReceiveExtraPkt* -- When a Dispatcher is invoked, its call sequence is: -- ReceiveExtraPkt*, SendPrelimPkt* -- The RPC runtime assumes that within one of these sequences, the -- same stub packet is being used. All state associated with the -- call is maintained in the packet buffers. StartCall and -- StartReturn perform no communication, and raise no signals. The -- other procedures can each raise RPCSignals.CallFailed. All may -- safely be aborted, if desired. -- The RPC runtime transports arguments and results from a user-stub -- to the appropriate dispatcher. Presumably, the first argument -- packet will specify to the dispatcher which client procedure to -- call; this is of no concern to the RPC runtime. StartCall: PROC[callPkt: RPCPkt, interface: ImportHandle, localConversation: MesaRPC.Conversation _ MesaRPC.unencrypted]; -- initializes the RPCPkt to specify the call. If localConversation # -- MesaRPC.unencrypted then the call will be made securely. -- Call: PROC[pkt: RPCPkt, callLength: DataLength, maxReturnLength: DataLength, signalHandler: Dispatcher _ NIL] RETURNS[ returnLength: DataLength, lastPkt: BOOLEAN]; -- Sends the packet and waits for first return packet. The -- signalHandler gets invoked if a signal is passed back from -- the callee machine. -- -- May raise MesaRPC.CallFailed -- SendPrelimPkt: PROC[pkt: RPCPkt, length: DataLength]; -- sends the packet and waits for ack. Packet may then be re-used -- -- Used for sending non-last packets of arguments or results -- -- May raise MesaRPC.CallFailed -- ReceiveExtraPkt: PROC[prevPkt: RPCPkt] RETURNS[ length: DataLength, lastPkt: BOOLEAN]; -- Waits for next pkt. Used for receiving -- non-first packets of arguments or results. -- Assumes maxlength = maxDataLength -- -- May raise MesaRPC.CallFailed -- Dispatcher: TYPE = PROC[pkt: RPCPkt, callLength: DataLength, lastPkt: BOOLEAN, localConversation: MesaRPC.Conversation ] RETURNS[ returnLength: DataLength ]; -- "pkt" is the first argument packet. This must be passed to -- any calls of ReceiveExtraPkt or SendPrelimPkt; the stub leaves -- the last return pkt data in "pkt". "pkt" has maxlength = -- maxDataLength. -- The caller of the dispatcher will catch MesaRPC.CallFailed -- StartSignal: PROC[signalPkt: RPCPkt]; -- Called to indicate that a signal is about to be -- raised in the caller. The stub then calls: -- SendPrelimPkt*, Call, ReceiveExtraPkt* -- then RESUME's the signal with the appropriate results. -- On the caller machine, this looks a call which invokes the -- signalHandler for his call of "Call". -- If the signal gets unwound on the caller machine, the call of -- "Call" gets unwound without the stub being told (except by the -- "UNWIND" signal). The catch-phrases on the caller machine may of -- course raise another signal, which comes back to this machine as -- an invokation of the signalHandler passed to "Call"! RejectUnbound: ERROR; -- May be raised by a dispatcher to cause the remote caller to -- get CallFailed[unbound]. The dispatcher must have sent no -- result packets before raising this error. RejectProtocol: ERROR; -- May be raised by a dispatcher to cause the remote caller to -- get CallFailed[protocolError]. The dispatcher must have sent -- no result packets before raising this error. END.