-- RPC: layout of packets

-- [Ivy]<Birrell>RPC>RPCPkt.mesa

-- Andrew Birrell March 11, 1983 3:44 pm

DIRECTORY
BufferDefs USING[ PupBuffer ],
PupTypes USING[ PupHostID, PupNetID, PupSocketID ],
PSB   USING[ PsbIndex ],
RPCLupine USING[ DataLength, Dispatcher, RPCPkt ],
RPCPrivate USING[ rpcSocket ];

RPCPkt: DEFINITIONS
SHARES RPCLupine =

BEGIN


-- ******** Layout of stub-packets ******** --

Header: TYPE = MACHINE DEPENDENT RECORD[
length (0:0..14): [0..77777B],
oddByte (0:15..15): { no(0), yes(1) },
type (1):  PktType,
destPSB (2):  PSB.PsbIndex,-- field has 6 extra bits
srcePSB (3):  PSB.PsbIndex,-- field has 6 extra bits
destHost (4):  Machine,
destSoc (5):  PupTypes.PupSocketID,
srceHost (7):  Machine,
srceSoc (8):  PupTypes.PupSocketID,
-- end of standard Pup header --
conv (10):  PktConversationID,
-- For secure conversations, the remainder of the packet must be encrypted --
pktID (12):  PktID,
call (16): SELECT OVERLAID * FROM
calling => [dispatcher (16): DispatcherDetails],
 responding => [outcome (16): Outcome,
   fill  (17): ARRAY[SIZE[Outcome]..
    SIZE[DispatcherDetails])
      OF WORD
   ],
ENDCASE ];

PktType: TYPE = MACHINE DEPENDENT RECORD[ -- "type" word of a Pup --
transport (0:0..7): [0..255], -- should be zero before sending --
subType (0:8..10): { rpc(3B), (7B) },
eom (0:11..11): { end(0), notEnd(1) },
ack (0:12..12): { dontAck(0), pleaseAck(1) },
class (0:13..15): { call(0), data(1), ack(2), rfa(4), (7) } ];

-- Mapping from Pup pkt types to RPC pkt types:
-- 140B = [end, dontAck, call ]
-- 141B = [end, dontAck, data ]
-- 142B = [, dontAck, ack ] (also 162B)
-- 143B = unused (also 163B)
-- 144B = [, dontAck, rfa ] (also 164B)
-- 150B = [end, pleaseAck, call ]
-- 151B = [end, pleaseAck, data ]
-- 152B = [, pleaseAck, ack ] (also 172B)
-- 153B = unused (also 173B)
-- 154B = [, pleaseAck, rfa ] (also 174B)
-- 160B = [notEnd, dontAck, call ]
-- 161B = [notEnd, dontAck, data ]
-- 170B = [notEnd, pleaseAck, call ]
-- 171B = [notEnd, pleaseAck, data ]

pktLengthOverhead: RPCLupine.DataLength = SIZE[Header] + 1--checksum--;
-- Difference between RPCLupine.DataLength and transmitted Pup length
-- for unencrypted packets --

Machine: TYPE = MACHINE DEPENDENT RECORD[
-- Unambiguous name of a host
net: PupTypes.PupNetID,
host: PupTypes.PupHostID ];

HostConversationID: TYPE = MACHINE DEPENDENT RECORD[
-- Host-relative ID of a conversation; unique for all time --
ls(0): CARDINAL,
ms(1): [0..77777B] ];

ConversationID: TYPE = RECORD[
-- Absolute ID of a conversation; unique for all hosts and all time --
originator: Machine,
count: HostConversationID];

PktConversationID: TYPE = MACHINE DEPENDENT RECORD[
-- Same as ConversationID, but abbreviated for within a packet --
-- Assumes originator is always caller or callee --
ls(0): CARDINAL,
originator(1:0..0): { caller, callee },
ms(1:1..15): [0..77777B] ];

ConnectionID: TYPE = MACHINE DEPENDENT RECORD[
-- Uniquely identifies an independent sequence of calls --
conv(0): PktConversationID,
caller(2): Machine,
activity(3): PSB.PsbIndex ];

CallCount: TYPE = LONG CARDINAL
-- [ConnectionID,CallCount] uniquely identifies call for all hosts and time --;

PktID: TYPE = MACHINE DEPENDENT RECORD[
-- [ConversationID,PktID] uniquely identifies pkt for all hosts and time --
activity(0): PSB.PsbIndex,-- field has 6 extra bits--
callSeq(1): CallCount,
pktSeq(3): CARDINAL ];

Outcome: TYPE = MACHINE DEPENDENT { -- possible responses to call or signal --
result(0), -- normal --
unbound(1), -- dispatcher not known --
signal(2), -- signal propagation --
unwind(3), -- signal is unwinding --
protocol(4), -- stub protocol error detected --
(LAST[CARDINAL]) -- room for expansion? --
};

DispatcherDetails: TYPE = MACHINE DEPENDENT RECORD[
mds: CARDINAL, -- top half of dispatcher's MDS base address --
dispatcherID: DispatcherID, -- exporter-relative UID of interface instance --
dispatcherHint: ExportHandle -- hint to exporter host's export table -- ];

DispatcherID: TYPE = LONG CARDINAL;
noDispatcher: DispatcherID = 0;
ExportHandle: TYPE = CARDINAL;

SetupResponse: PROC[header: LONG POINTER TO Header] = INLINE
BEGIN
header.destHost ← header.srceHost;
header.destSoc ← RPCPrivate.rpcSocket;
header.destPSB ← header.srcePSB;
header.outcome ← result;
END;



-- ******** Single-packet communication: exported by RPCPktIO ******** --

PktExchangeState: TYPE = { receiving, sending, call, endCall, authReq };

PktExchange: PROC[inPkt: RPCLupine.RPCPkt, length: RPCLupine.DataLength,
   maxlength: RPCLupine.DataLength,
state: PktExchangeState,
   signalHandler: RPCLupine.Dispatcher ← NIL]
RETURNS[newPkt: BOOLEAN, newLength: RPCLupine.DataLength];
-- Reliable transmission of given packet, and receipt of next packet;
-- "newLength" is data length of incoming packet, if any. --

IdleReceive: PROC[pkt: RPCLupine.RPCPkt, maxlength: CARDINAL];
-- Returns when new packet arrives; "maxlength" is number of words in the
-- pkt buffer starting from pkt.header (total, including all overheads) --

EnqueueAgain: PROC[b: BufferDefs.PupBuffer];
-- Dispatches packet to appropriate process; used by idler processes to requeue pkt that
-- had incorrect destPSB.

END.