Types
Address: TYPE ~ Arpa.Address;
Handle: TYPE ~ SunRPC.Handle;
Conversation: TYPE ~ SunRPCAuth.Conversation;
MapEntry: TYPE ~ SunPMap.MapEntry;
Map
Item: TYPE ~ REF ItemObject;
ItemObject:
TYPE ~
RECORD [
next: Item,
entry: MapEntry
];
Headers: TYPE ~ REF HeadersObject;
HeadersObject: TYPE ~ ARRAY [0 .. tableSize) OF Item;
headers: Headers ¬ NEW[HeadersObject];
Hash:
PROC [program, version:
CARD]
RETURNS [
CARD] ~ {
RETURN [(3*program + version) MOD tableSize];
};
Procedures
Null:
PUBLIC SunPMap.NullProc
-- [h: Handle, c: Conversation] -- ~ {
NULL;
};
Set:
PUBLIC SunPMap.SetProc
-- [h: Handle, c: Conversation, program, version, protocol, port: CARD32] RETURNS [success: BOOL] -- ~ {
RETURN [SetLocal[program, version, protocol, port]];
};
SetLocal:
PUBLIC
ENTRY
PROC [program, version, protocol, port:
CARD32]
RETURNS [success:
BOOL] ~ {
index: CARD ¬ Hash[program, version];
FOR item: Item ¬ headers[index], item.next
WHILE item #
NIL
DO
IF (item.entry.program = program)
AND (item.entry.version = version)
AND (item.entry.protocol = protocol)
AND (item.entry.port = port)
THEN RETURN [FALSE];
ENDLOOP;
headers[index] ¬ NEW[ItemObject ¬ [headers[index], [program, version, protocol, port]]];
RETURN [TRUE];
};
Unset:
PUBLIC SunPMap.UnsetProc
-- [h: Handle, c: Conversation, program, version: CARD32] RETURNS [success: BOOL] -- ~ {
RETURN [UnsetLocal[program, version]];
};
UnsetLocal:
PUBLIC
ENTRY
PROC [program, version:
CARD32]
RETURNS [success:
BOOL] ~ {
prev, p: Item;
index: CARD ¬ Hash[program, version];
success ¬ FALSE;
prev ¬ NIL; p ¬ headers[index];
DO
IF p = NIL THEN RETURN;
IF (p.entry.program = program)
AND (p.entry.version = version)
THEN {
success ¬ TRUE;
IF prev = NIL THEN headers[index] ¬ p.next ELSE prev.next ¬ p.next;
}
p ¬ p.next;
ENDLOOP;
};
GetPort:
PUBLIC SunPMap.GetPortProc
-- [h: Handle, c: Conversation, program, version, protocol: CARD32] RETURNS [port: CARD32] -- ~ {
RETURN [GetPortLocal[program, version, protocol]];
};
GetPortLocal:
PUBLIC
ENTRY
PROC [program, version, protocol:
CARD32]
RETURNS [port:
CARD32] ~ {
index: CARD ¬ Hash[program, version];
FOR item: Item ¬ headers[index], item.next
WHILE item #
NIL
DO
IF (item.entry.program = program)
AND (item.entry.version = version)
AND (item.entry.protocol = protocol)
THEN RETURN [item.entry.port];
ENDLOOP;
RETURN [0];
};
Dump:
PUBLIC SunPMap.DumpProc
-- [h: Handle, c: Conversation, eachMapEntry: PROC[MapEntry]] -- ~ {
DumpLocal[eachMapEntry];
};
DumpLocal:
PUBLIC
PROC [eachMapEntry:
PROC[MapEntry]] ~ {
It's okay to do this without holding the monitor lock because REF operations are atomic ...
FOR i:
CARDINAL
IN [0 .. tableSize)
DO
FOR p: Item ¬ headers[i], p.next
WHILE p #
NIL
DO
eachMapEntry[p.entry];
ENDLOOP;
ENDLOOP;
};
Callit:
PUBLIC SunPMap.CallitProc
-- [h: Handle, c: Conversation, program, version, proc: CARD32, args: REF TEXT] RETURNS [port: CARD32, result: REF TEXT] -- ~ {
gotError: BOOL ¬ FALSE;
[port, result] ¬ CallitLocal[program, version, proc, args, longTimeout, 0
! SunRPC.Error => { gotError ¬ TRUE; CONTINUE }];
IF gotError THEN ERROR SunRPC.Error[$abortWithoutReturn];
};
CallitLocal:
PUBLIC
PROC [program, version, proc:
CARD32, args:
REF
TEXT, timeout:
CARD, retries:
CARD]
RETURNS [port:
CARD32, result:
REF
TEXT] ~ {
hLocal: Handle ¬ NIL;
conversation: Conversation ¬ NIL;
CleanUp:
PROC ~ {
IF hLocal # NIL
THEN { SunRPC.Destroy[hLocal]; hLocal ¬ NIL };
IF conversation # NIL
THEN { SunRPCAuth.Terminate[conversation]; conversation ¬ NIL };
};
{
ENABLE
UNWIND => CleanUp[];
bytes: CARDINAL;
port ¬ GetPortLocal[program, version, SunPMap.ipProtocolUDP];
IF port = 0 THEN ERROR SunRPC.Error[$serviceNotRegistered];
hLocal ¬ SunRPCOnUDP.Create[remoteAddress~Arpa.MyAddress[], remotePort~Basics.HFromCard16[port]];
conversation ¬ SunRPCAuth.Initiate[];
SunRPC.StartCall[hLocal, conversation, program, version, proc];
SunRPC.PutBlock[hLocal, args, 0, args.length];
[] ¬ SunRPC.SendCallAndReceiveReply[hLocal, timeout, retries];
bytes ¬ SunRPC.BytesRemaining[hLocal];
result ¬ RefText.New[bytes];
SunRPC.GetBlock[hLocal, result, 0, bytes];
};
CleanUp[];
};
}...