-- MesaRPC.mesa is the Mesa-compatible public interface to the RPC runtime.
-- RPC.mesa defines the Cedar-compatible interface.

-- File [Ivy]<Birrell>RPC>MesaRPC.mesa

-- Andrew Birrell	 3-Dec-81 10:12:00
-- BZM			29-Oct-81 11:45:47


DIRECTORY
BodyDefs	USING[ maxRNameLength, Password ];

MesaRPC: DEFINITIONS =

  BEGIN


-- Short string types. Used only by Lupine clients.

  maxShortStringLength: CARDINAL = 64;
  -- Maximum length of ShortSTRING values. --

  ShortSTRING: TYPE = STRING;


-- Types for Import/Export calls --

  InterfaceName: TYPE = RECORD [
	type:     LONG ShortSTRING ← NIL, -- e.g. "AlpineAccess.Alpine" --
	instance: LONG ShortSTRING ← NIL, -- e.g. "MontBlanc.Alpine" --
	version:  VersionRange ← matchAllVersions];

  defaultInterfaceName: InterfaceName = [];

  VersionRange: TYPE = MACHINE DEPENDENT RECORD[first, last: CARDINAL];
    -- client-defined, closed interval --

  matchAllVersions: VersionRange = [1,0];
    -- importer: use any version;  exporter: no versioning implied --



-- Parameter storage zones.  Used only by Lupine clients, not the runtime.

  Zones: TYPE = RECORD [
	heap: UNCOUNTED ZONE ← NIL,
	mds:  MDSZone ← NIL ];

  standardZones: Zones = [];
  
-- Encryption and Authentication facilities --

  maxPrincipalLength: CARDINAL = MIN[maxShortStringLength,
				     BodyDefs.maxRNameLength];
    -- Limit on length of strings used for Principal --

  Principal:	TYPE = LONG ShortSTRING;
  -- Name of authentication principal --

  EncryptionKey: TYPE = BodyDefs.Password;
    -- DES key --

  MakeKey: PROC[text: LONG STRING] RETURNS[EncryptionKey];

  Conversation:	TYPE = LONG POINTER TO ConversationObject;

  ConversationObject: PRIVATE TYPE;

  SecurityLevel: TYPE = MACHINE DEPENDENT {
        none(0),	-- unauthenticated, insecure; used for "unencrypted"
        authOnly(1),	-- authenticated, but unencrypted calls
        ECB(2),		-- authenticated, encrypt with ECB mode of DES
        CBC(3),		-- authenticated, encrypt with CBC mode of DES
        CBCCheck(4)	-- authenticated, encrypt with CBC mode of DES + checksum
        };
  
  ConversationLevel: TYPE = SecurityLevel[authOnly..CBCCheck];

  unencrypted:	Conversation = NIL;
    -- Dummy conversation; may be passed to RPC runtime.
    --   GetConversationID[unencrypted] = ERROR;
    --   GetCaller[unencrypted] = NIL;
    --   GetLevel[unencrypted] = none; --

  GenerateConversation: PROC RETURNS[Conversation];
    -- Returns a handle for a previously unused Conversation.  This
    -- conversation is only for local use, it must not be passed to
    -- the RPC runtime.
    --   GetConversationID[GenerateConversation[]] = unique ID;
    --   GetCaller[GenerateConversation[]] = NIL;
    --   GetLevel[GenerateConversation[]] = "none"; --

  StartConversation: PROC[caller: Principal, key: EncryptionKey,
			  callee: Principal,
			  level: ConversationLevel]
		  RETURNS[conversation: Conversation];
    -- Obtains authenticator for conversation, registers it with runtime,
    -- and allocates ConversationID --

  EndConversation: PROC[conversation: Conversation];
    -- Terminates use of this conversation --
 
  GetCaller:	PROC[conversation: Conversation]
	     RETURNS[caller: Principal];
    -- Returns the caller name for a current call.  The result
    -- string has lifetime at least equal to the duration of the
    -- call.  Result is NIL if conversation's security level is "none" (including
    -- conversation = "unencrypted"). --

  GetLevel:	PROC[conversation: Conversation]
	     RETURNS[level: SecurityLevel];

  ConversationID: TYPE[3];
    -- UID allocated by initiator host --

  GetConversationID: PROC[conversation: Conversation]
	     RETURNS[id: ConversationID];
    -- Returns permanently unique ID of this conversation --



-- Public signals --

  AuthenticateFailure: TYPE = {
  	communications,	-- couldn't contact authentication server(s) --
	badCaller,	-- invalid caller name --
	badKey,		-- incorrect caller password --
	badCallee	-- invalid callee name --
	};

  ExportFailure: TYPE = {
	communications, -- couldn't access binding database --
	badType,	-- unacceptable interface type name --
	badInstance,	-- unacceptable interface instance name --
	badVersion,	-- statically silly version range --
	tooMany,	-- too many exports for local tables --
	badCredentials	-- not allowed to change the database --
	};

  ImportFailure: TYPE = {
	communications, -- couldn't access binding database --
	badType,	-- unacceptable interface type name --
	badInstance,	-- unacceptable interface instance name --
	badVersion,	-- statically silly version range --
	wrongVersion,	-- exported version not in req'd range --
	unbound,	-- this instance not exported --
	stubProtocol	-- exporter protocol incompatible with importer --
	};

  CallFailure:	TYPE = {
	timeout,	-- no acknowledgement within reasonable time --
	unbound,	-- server no longer exports the interface --
	busy,		-- server says it's too busy --
	runtimeProtocol,-- user/server runtimes don't understand each other --
	stubProtocol	-- user/server stubs don't understand each other --
	};

  AuthenticateFailed: ERROR[why: AuthenticateFailure];
    -- Raised by StartConversation --

  ExportFailed: ERROR[why: ExportFailure];
    -- Raised by ExportInterface --

  ImportFailed: ERROR[why: ImportFailure];
    -- Raised by ImportInterface --

  CallFailed:   SIGNAL[why: CallFailure];
    -- Raised by any remote call; only why=timeout is resumable --


END.