DIRECTORY PrincOpsUtils USING[ BITOR, Enter, Exit, HighHalf, LowHalf, MakeLongPointer ], RPC USING[ Conversation, EncryptionKey, InterfaceName, maxPrincipalLength, maxShortStringLength, Principal, unencrypted, VersionRange ], VM USING [AddressForPageNumber, PageCount, PageNumber, PageNumberForAddress, PagesForWords]; RPCLupine: DEFINITIONS IMPORTS PrincOpsUtils, VM = BEGIN PacketBufferLock: MONITORLOCK; -- Definitions copied across from RPC.mesa for Lupine's benefit maxPrincipalLength: CARDINAL = RPC.maxPrincipalLength; maxShortStringLength: CARDINAL = RPC.maxShortStringLength; Encapsulation: PRIVATE TYPE[7]; -- large enough for all current networks Header: PRIVATE TYPE[10+6+4]; maxPupWords: PRIVATE CARDINAL = 266 -- Pup data -- + 10 -- Pup header -- + 1 -- Pup checksum --; encryptionBlockSize: PRIVATE CARDINAL = 4; SecurityChecksum: PRIVATE TYPE[2]; maxDataLength: CARDINAL = ( ( 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 RPC.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 { RETURN[ LOOPHOLE[PrincOpsUtils.BITOR[LOOPHOLE[space, WORD]+2, pktAlign],POINTER]-2 ] }; GetPkt: PROC[ space: LONG POINTER TO UNSPECIFIED] RETURNS[--pkt:-- RPCLupine.RPCPkt ] = INLINE {RETURN[ LOOPHOLE[space+1]]}; GetRPCPkt: PROC[ space: LONG POINTER TO UNSPECIFIED] RETURNS[--pkt:-- RPCPkt ] = INLINE { RETURN[ PrincOpsUtils.MakeLongPointer[ low: LOOPHOLE[PrincOpsUtils.BITOR[LOOPHOLE[PrincOpsUtils.LowHalf[space+2], WORD], pktAlign] - 2], high: PrincOpsUtils.HighHalf[space+2] ]] }; -- Binding primitives for use by stubs -- ExportHandle: TYPE[SIZE[CARDINAL]]; -- index to table of dispatcher procedures ExportInterface: PROC[user: RPC.Principal, password: RPC.EncryptionKey, interface: RPC.InterfaceName, dispatcher: Dispatcher, stubProtocol: RPC.VersionRange, localOnly: BOOLEAN _ FALSE] RETURNS[ interfaceInstance: ExportHandle ]; UnexportInterface: PROC[ interfaceInstance: ExportHandle ] RETURNS[ExportHandle]; ImportHandle: TYPE = REF ImportInstance; ImportInstance: TYPE; ImportInterface: PROC[interface: RPC.InterfaceName, stubProtocol: RPC.VersionRange, localOnly: BOOLEAN _ FALSE] RETURNS[ interfaceInstance: ImportHandle ]; UnimportInterface: PROC[ interfaceInstance: ImportHandle ] RETURNS[ ImportHandle ]; StartCall: PROC[callPkt: RPCPkt, interface: ImportHandle, localConversation: RPC.Conversation _ RPC.unencrypted]; Call: PROC[pkt: RPCPkt, callLength: DataLength, maxReturnLength: DataLength, signalHandler: Dispatcher _ NIL] RETURNS[ returnLength: DataLength, lastPkt: BOOLEAN]; SendPrelimPkt: PROC[pkt: RPCPkt, length: DataLength]; ReceiveExtraPkt: PROC[prevPkt: RPCPkt] RETURNS[ length: DataLength, lastPkt: BOOLEAN]; Dispatcher: TYPE = PROC[pkt: RPCPkt, callLength: DataLength, lastPkt: BOOLEAN, localConversation: RPC.Conversation ] RETURNS[ returnLength: DataLength ]; StartSignal: PROC[signalPkt: RPCPkt]; RejectUnbound: ERROR; RejectProtocol: ERROR; MaxPacketBufferListSize: INT = 7; -- Maximum size kept in the cache MaxPacketBufferIntervalInRec: INT = 10; PacketBufferCacheListRec: TYPE = RECORD [ prev: REF PacketBufferCacheListRec, next: REF PacketBufferCacheListRec _ NIL, putIndex: CARDINAL _ 1, intervalStarts: ARRAY [1..MaxPacketBufferIntervalInRec] OF VM.PageNumber _ ALL[0] ]; PacketBufferCacheList: ARRAY [1..MaxPacketBufferListSize] OF REF PacketBufferCacheListRec ; AllocInline: PROC [nWords: CARDINAL] RETURNS [address: LONG POINTER TO WORD] = INLINE { IF PrincOpsUtils.Enter[@PacketBufferLock] THEN { nPages: VM.PageCount = MAX[1, VM.PagesForWords[nWords]]; IF nPages <= MaxPacketBufferListSize THEN { putIndex: INT _ PacketBufferCacheList[nPages].putIndex; IF putIndex > 1 THEN { putIndex_ putIndex - 1; address _ VM.AddressForPageNumber[PacketBufferCacheList[nPages].intervalStarts[putIndex]]; PacketBufferCacheList[nPages].putIndex _ putIndex; PrincOpsUtils.Exit[@PacketBufferLock]; RETURN; }; }; PrincOpsUtils.Exit[@PacketBufferLock]; }; RETURN[Alloc[nWords]]; }; DeAllocInline: PROC [address: LONG POINTER TO WORD, nWords: CARDINAL] = INLINE { nPages: VM.PageCount = MAX[1, VM.PagesForWords[nWords]]; IF PrincOpsUtils.Enter[@PacketBufferLock] AND LOOPHOLE[address, INT] # 0 THEN { IF nPages <= MaxPacketBufferListSize THEN { putIndex: INT _ PacketBufferCacheList[nPages].putIndex; IF putIndex <= MaxPacketBufferIntervalInRec THEN { PacketBufferCacheList[nPages].intervalStarts[putIndex] _ VM.PageNumberForAddress[address]; PacketBufferCacheList[nPages].putIndex _ putIndex + 1; PrincOpsUtils.Exit[@PacketBufferLock]; RETURN; }; }; PrincOpsUtils.Exit[@PacketBufferLock]; }; DeAlloc[address, nWords]; }; Alloc: PROC [nWords: CARDINAL] RETURNS [address: LONG POINTER TO WORD] ; DeAlloc: PROC [address: LONG POINTER TO WORD, nWords: CARDINAL]; END. ”RPCLupine.mesa RPC: Interface between stubs and runtime. Copyright c 1985 by Xerox Corporation. All rights reserved. Last Edited by: Bruce Nelson 6 Oct. 1981 9:44 am PDT (Tuesday) Birrell, September 7, 1983 3:28 pm Bob Hagmann February 11, 1985 9:39:39 am PST Packet Buffer Monitor Lock 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]; PUP header + RPC protocol overhead + dispatcher description. Must be aligned to quad-word + 2 -- maximum value of length field of Pup packet, in words, as defined in [Maxc]PupSpec.press -- Maximum data words in RPCPkt or StubPkt. The following calculation assumes that the encrypted part of a header is a multiple of encryptionBlockSize -- 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. returns long pointer aligned to quad-word plus one, given a quad-word aligned long pointer 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! 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. 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 RPC.ExportFailed -- Removes export from local dispatcher table and binding database. Returns an ExportHandle that will fault if used. -- 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 RPC.ImportFailed -- 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. initializes the RPCPkt to specify the call. If localConversation # RPC.unencrypted then the call will be made securely. 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 RPC.CallFailed -- 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 RPC.CallFailed Waits for next pkt. Used for receiving non-first packets of arguments or results. Assumes maxlength = maxDataLength. May raise RPC.CallFailed -- "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 RPC.CallFailed -- 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"! 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. 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. Packet Buffer Data Types, Data Structures, Allocation and Deallocation routines. Bob Hagmann February 11, 1985 9:39:17 am PST changes to: GetRPCPkt, DIRECTORY, RPCLupine, RejectProtocol, GetStubPkt Κ a˜Iheadšœ™šœ)™)Icodešœ Οmœ1™<—šœ™Jšœ/™/J™"L™,L™—šΟk ˜ Jšœžœžœ4˜NJšžœžœ˜ˆJšžœžœT˜\J˜—šœ ž ˜Jšžœžœ˜—J˜Jšž˜J˜šœ™Jšœž œ˜J™—J˜JšΟc?˜?J˜Jšœžœ˜6Jšœžœ˜:J˜J˜J˜šœ²™²J™Jšœ3™3Jšœ8™8—J™šœ›™›J™JšœG™GJšœ8™8—J˜šœžœžœ˜JšŸ(˜(J˜—šœ žœžœ ˜Jšœ=Ÿ%™bJ˜—šœ žœžœ˜Jšœ6Ÿ*™`JšœŸ˜JšœŸ˜JšœŸœ˜J˜—Jšœžœžœ˜*J˜Jšœžœžœ˜"J˜šœžœ˜JšœoŸ(™—˜JšœŸ˜Jšœžœ ˜JšœŸœ˜%—J˜Jšœžœ˜J˜—Jšœ žœ˜&J˜šœ žœ Ÿ%˜FJšœžœ˜JšœŸ˜&Jšœžœ˜JšœŸœ˜J˜—šœ žœžœ˜JšŸ*˜*J˜—Jšœ žœžœžœ ˜'J˜Jšœ žœžœ ˜J˜š œ žœžœž œžœ˜-JšŸ˜Jšœ žœ˜%Jšœžœ˜%Jšœžœ Ÿ˜,Jš œžœžœ žœž œ˜3J˜—š Οn œžœ žœžœž œ˜0JšžœŸœ ž˜#Jšœ4ŸC™wJšœ™Jšœ™Jšœ™Jšœ™Jš œžœžœžœžœžœžœ˜YJ˜—š  œžœ žœžœžœž œ˜1š žœŸœžœžœžœ ˜JJšœZ™Z——J˜š   œžœ žœžœžœž œ˜4JšžœŸœ ž˜"šœ4ŸCœ™}Jšœ™Jšœ™Jšœ™Jšœ™—Jšœ?™?šœžœ ˜(Jš œžœžœžœ!žœ˜a˜%J˜J˜J˜J˜J˜J˜———JšŸ)˜)J˜Jšœκ™κJ˜Jšœς™ςJ˜Jšœa™aJ˜šœžœžœžœ˜#JšŸ*˜*J˜—š œžœ2˜GJ˜J˜J˜Jšœ žœžœ˜Jšžœ$˜+JšœΓŸ,™οJ˜—š œžœ#˜:Jšžœ˜JšœHŸ,™tJ˜—Jšœžœžœ˜(J˜Jšœžœ˜J˜š œžœ˜3J˜Jšœ žœžœ˜Jšžœ$˜+Jšœ{Ÿ9™΄J˜—š œžœ#˜:Jšžœ˜JšœBŸ™^J˜J˜J˜—Jšœ%™%J˜šœ4™4Jšœ1™1—šœ3™3Jšœ ™ —J˜JšœΧ™ΧJ˜Jšœπ™πJ˜š  œžœ˜ J˜J˜7JšœCŸ5™xJ˜—š œžœ%˜/J˜Jšœžœ˜ šžœ˜"Jšœ žœ˜—Jšœ8™8Jšœ:Ÿ1™kJ˜—š  œžœ"˜5Jšœ•™•J˜—š œžœ˜&šžœ˜Jšœ žœ˜—JšœRŸA™“J˜—š  œžœžœ ˜$Jšœ!žœ˜)J˜%Jšžœ˜$JšœΕŸ;™€J˜—š  œžœ˜%šœ[™[Jšœ&™&—JšœΝ™ΝJ˜—šœžœ˜Jšœ ™ —J˜šœžœ˜Jšœ¦™¦J˜—šœP™PJ˜JšœžœŸ!˜DJšœžœ˜'šœžœžœ˜)Jšœžœ˜#Jšœžœžœ˜)Jšœ žœ˜Jš œžœ#žœžœžœ˜QJ˜—Jšœžœžœžœ˜[J˜š  œžœ žœžœ žœžœžœžœžœ˜Wšžœ(žœ˜0Jšœžœ žœžœ˜8šžœ#žœ˜+Jšœ žœ*˜7šžœžœ˜Jšœ˜Jšœ žœN˜ZJšœ2˜2Jšœ&˜&Jšžœ˜J˜—J˜—Jšœ&˜&J˜—Jšžœ˜J˜J˜—š  œžœ žœžœžœžœ žœžœ˜PJšœžœ žœžœ˜8š žœ(žœžœ žœžœ˜Ošžœ#žœ˜+Jšœ žœ*˜7šžœ*žœ˜2Jšœ9žœ˜ZJšœ6˜6Jšœ&˜&Jšžœ˜J˜—J˜—Jšœ&˜&J˜—Jšœ˜J˜—J˜š œžœ žœžœ žœžœžœžœ˜HJ˜—š œžœ žœžœžœžœžœ˜@J˜J˜—J˜˜J˜——J˜Jšžœ˜L™L™™,Lšœ Οr;™G—L™L™—…—n7c