-- Transport mechanism: Name info from registration server
-- [Juniper]<DMS>MS>NameInfo.mesa
-- Andrew Birrell 11-Nov-80 13:58:05
DIRECTORY
BodyDefs USING [Connect, oldestTime, Password, Remark, RName, Timestamp],
LocateDefs USING [FindRegServer, FoundServerInfo],
NameInfoDefs USING [
AuthenticateInfo, ConnectInfo, ExpandInfo, MemberInfo, Membership, NameType,
RemarkInfo, RListHandle, StampInfo],
NameInfoSpecialDefs USING [],
ProtocolDefs USING [
CreateStream, DestroyStream, Enquire, Failed, Handle, IsLocal, MakeKey,
ReceiveBoolean, ReceiveConnect, ReceiveRC, ReceiveRemark, RegServerEnquirySocket,
ReturnCode, RSOperation, SendNow, SendPassword, SendRName, SendRSOperation],
PupDefs USING [PupAddress],
RListDefs USING [Close, Enumerate, Receive, RListHandle];
NameInfo: MONITOR
IMPORTS LocateDefs, ProtocolDefs, RListDefs
EXPORTS NameInfoDefs, NameInfoSpecialDefs =
BEGIN
-- Re-export RListDefs into NameInfoDefs --
RListHandle: PUBLIC TYPE = RECORD[l:RListDefs.RListHandle];
Enumerate: PUBLIC PROC[list: RListHandle,
work: PROC[BodyDefs.RName]RETURNS[done: BOOLEAN] ] =
{ RListDefs.Enumerate[list.l, work] };
Close: PUBLIC PROC[list: RListHandle] =
{ RListDefs.Close[list.l] };
BadResult: ERROR[info: NameInfoDefs.NameType] = CODE;
-- illegal reply from R-Server --
Expand: PUBLIC PROC[name: BodyDefs.RName,
oldStamp: BodyDefs.Timestamp ← BodyDefs.oldestTime]
RETURNS[ NameInfoDefs.ExpandInfo ] =
BEGIN
info: NameInfoDefs.NameType;
list: RListHandle;
stamp: BodyDefs.Timestamp;
[info, list, stamp] ← GetList[name, oldStamp, Expand];
SELECT info FROM
noChange => RETURN[ [noChange[]] ];
group => RETURN[ [group[list, stamp]] ];
individual => RETURN[ [individual[list, stamp]] ];
notFound => RETURN[ [notFound[]] ];
allDown => RETURN[ [allDown[]] ];
ENDCASE => ERROR BadResult[info];
END;
GetMembers: PUBLIC PROC[name: BodyDefs.RName,
oldStamp: BodyDefs.Timestamp ← BodyDefs.oldestTime]
RETURNS[ NameInfoDefs.MemberInfo ] =
{ RETURN[ GetGroupList[name, oldStamp, ReadMembers] ] };
GetOwners: PUBLIC PROC[name: BodyDefs.RName,
oldStamp: BodyDefs.Timestamp ← BodyDefs.oldestTime]
RETURNS[ NameInfoDefs.MemberInfo ] =
{ RETURN[ GetGroupList[name, oldStamp, ReadOwners] ] };
GetFriends: PUBLIC PROC[name: BodyDefs.RName,
oldStamp: BodyDefs.Timestamp ← BodyDefs.oldestTime]
RETURNS[ NameInfoDefs.MemberInfo ] =
{ RETURN[ GetGroupList[name, oldStamp, ReadFriends] ] };
GetGroupList: PUBLIC PROC[name: BodyDefs.RName,
oldStamp: BodyDefs.Timestamp,
op: ProtocolDefs.RSOperation]
RETURNS[ NameInfoDefs.MemberInfo ] =
BEGIN
info: NameInfoDefs.NameType;
list: RListHandle;
stamp: BodyDefs.Timestamp;
[info, list, stamp] ← GetList[name, oldStamp, op];
SELECT info FROM
noChange => RETURN[ [noChange[]] ];
group => RETURN[ [group[list, stamp]] ];
individual => RETURN[ [individual[]] ];
notFound => RETURN[ [notFound[]] ];
allDown => RETURN[ [allDown[]] ];
ENDCASE => ERROR BadResult[info];
END;
GetList: PROC[name: BodyDefs.RName, stamp: BodyDefs.Timestamp,
op: ProtocolDefs.RSOperation]
RETURNS[info: NameInfoDefs.NameType,
list: RListHandle, newStamp: BodyDefs.Timestamp] =
BEGIN
GetListWork: PROC[str: ProtocolDefs.Handle]
RETURNS[rc: ProtocolDefs.ReturnCode] =
BEGIN
[rc, newStamp] ← ProtocolDefs.Enquire[str, op,
name, stamp];
END;
info ← Enquire[name, GetListWork];
IF (info = individual AND op = Expand) OR info = group
THEN list ← [l: RListDefs.Receive[str !
ProtocolDefs.Failed => GOTO notQuite]];
ReleaseStream[];
EXITS notQuite => { CloseStream[]; ReleaseStream[]; info ← allDown; }
END;
GetConnect: PUBLIC PROC[name: BodyDefs.RName,
connect: BodyDefs.Connect]
RETURNS[ NameInfoDefs.ConnectInfo ] =
BEGIN
ConnectWork: PROC[str: ProtocolDefs.Handle]
RETURNS[rc: ProtocolDefs.ReturnCode] =
BEGIN
[rc,] ← ProtocolDefs.Enquire[str, ReadConnect, name];
END;
info: NameInfoDefs.NameType ← Enquire[name, ConnectWork];
IF info = individual
THEN ProtocolDefs.ReceiveConnect[str, connect !
ProtocolDefs.Failed => GOTO notQuite ];
ReleaseStream[];
SELECT info FROM
IN NameInfoDefs.ConnectInfo => RETURN[info];
ENDCASE => ERROR BadResult[info];
EXITS notQuite => { CloseStream[]; ReleaseStream[]; RETURN[allDown] }
END;
GetRemark: PUBLIC PROC[name: BodyDefs.RName,
remark: BodyDefs.Remark]
RETURNS[ NameInfoDefs.RemarkInfo ] =
BEGIN
RemarkWork: PROC[str: ProtocolDefs.Handle]
RETURNS[rc: ProtocolDefs.ReturnCode] =
BEGIN
[rc,] ← ProtocolDefs.Enquire[str, ReadRemark, name];
END;
info: NameInfoDefs.NameType = Enquire[name, RemarkWork];
IF info = group
THEN ProtocolDefs.ReceiveRemark[str, remark !
ProtocolDefs.Failed => GOTO notQuite ];
ReleaseStream[];
SELECT info FROM
IN NameInfoDefs.RemarkInfo => RETURN[info];
ENDCASE => ERROR BadResult[info];
EXITS notQuite => { CloseStream[]; ReleaseStream[]; RETURN[allDown] }
END;
CheckStamp: PUBLIC PROC[name: BodyDefs.RName,
oldStamp: BodyDefs.Timestamp ← BodyDefs.oldestTime]
RETURNS[ NameInfoDefs.StampInfo ] =
BEGIN
info: NameInfoDefs.NameType;
CheckStampWork: PROC[str: ProtocolDefs.Handle]
RETURNS[rc: ProtocolDefs.ReturnCode] =
BEGIN
[rc,] ← ProtocolDefs.Enquire[str, CheckStamp, name, oldStamp];
END;
info ← Enquire[name, CheckStampWork];
ReleaseStream[];
SELECT info FROM
IN NameInfoDefs.StampInfo => RETURN[info];
ENDCASE => ERROR BadResult[info];
END;
Authenticate: PUBLIC PROC[name: BodyDefs.RName,
password: STRING]
RETURNS[NameInfoDefs.AuthenticateInfo ] =
{ RETURN[ AuthenticateKey[name, ProtocolDefs.MakeKey[password]] ] };
AuthenticateKey: PUBLIC PROC[name: BodyDefs.RName,
key: BodyDefs.Password]
RETURNS[NameInfoDefs.AuthenticateInfo ] =
BEGIN
AuthWork: PROC[str: ProtocolDefs.Handle]
RETURNS[rc: ProtocolDefs.ReturnCode] =
BEGIN
ProtocolDefs.SendRSOperation[str, Authenticate];
ProtocolDefs.SendRName[str, name];
ProtocolDefs.SendPassword[str: str, key: [0,0,0,0], pw: key];
ProtocolDefs.SendNow[str];
rc ← ProtocolDefs.ReceiveRC[str];
END;
info: NameInfoDefs.NameType = Enquire[name, AuthWork];
ReleaseStream[];
SELECT info FROM
IN NameInfoDefs.AuthenticateInfo => RETURN[info];
ENDCASE => ERROR BadResult[info];
END;
IsMemberDirect: PUBLIC PROC[name, member: BodyDefs.RName]
RETURNS[res: NameInfoDefs.Membership] =
{ RETURN[ IsInACL[name, member, IsMemberDirect] ] };
IsOwnerDirect: PUBLIC PROC[name, owner: BodyDefs.RName]
RETURNS[res: NameInfoDefs.Membership] =
{ RETURN[ IsInACL[name, owner, IsOwnerDirect] ] };
IsFriendDirect: PUBLIC PROC[name, friend: BodyDefs.RName]
RETURNS[res: NameInfoDefs.Membership] =
{ RETURN[ IsInACL[name, friend, IsFriendDirect] ] };
IsMemberClosure: PUBLIC PROC[name, member: BodyDefs.RName]
RETURNS[res: NameInfoDefs.Membership] =
{ RETURN[ IsInACL[name, member, IsMemberClosure] ] };
IsOwnerClosure: PUBLIC PROC[name, owner: BodyDefs.RName]
RETURNS[res: NameInfoDefs.Membership] =
{ RETURN[ IsInACL[name, owner, IsOwnerClosure] ] };
IsFriendClosure: PUBLIC PROC[name, friend: BodyDefs.RName]
RETURNS[res: NameInfoDefs.Membership] =
{ RETURN[ IsInACL[name, friend, IsFriendClosure] ] };
IsInACL: PROC[name, member: BodyDefs.RName, op: ProtocolDefs.RSOperation]
RETURNS[res: NameInfoDefs.Membership] =
BEGIN
IsInACLWork: PROC[str: ProtocolDefs.Handle]
RETURNS[rc: ProtocolDefs.ReturnCode] =
BEGIN
ProtocolDefs.SendRSOperation[str, op];
ProtocolDefs.SendRName[str, name];
ProtocolDefs.SendRName[str, member];
ProtocolDefs.SendNow[str];
rc ← ProtocolDefs.ReceiveRC[str];
END;
info: NameInfoDefs.NameType = Enquire[name, IsInACLWork];
SELECT info FROM
group => res ← IF ProtocolDefs.ReceiveBoolean[str !
ProtocolDefs.Failed => GOTO notQuite]
THEN yes ELSE no;
allDown => res ← allDown;
ENDCASE => res ← notGroup;
ReleaseStream[];
EXITS notQuite => { CloseStream[]; ReleaseStream[]; res ← allDown; }
END;
-- There is a cache of one stream and one address. --
-- Access to this is under mutual exclusion, enforced by calls
-- on ClaimStream and ReleaseStream --
released: CONDITION;
free: BOOLEAN ← TRUE;
str: ProtocolDefs.Handle ← NIL; -- cached R-Server stream --
cacheAddr: PupDefs.PupAddress; -- address of cached stream --
ClaimStream: ENTRY PROC =
{ UNTIL free DO WAIT released ENDLOOP; free ← FALSE; };
ReleaseStream: ENTRY PROC = INLINE
{ free ← TRUE; NOTIFY released };
CleanUp: PUBLIC PROC =
BEGIN
ClaimStream[];
-- optimize for R-Server/M-Server internal stream --
IF NOT ProtocolDefs.IsLocal[cacheAddr] THEN CloseStream[];
ReleaseStream[];
END;
Enquire: PROC[name: BodyDefs.RName,
EnquiryWork: PROC[ProtocolDefs.Handle]
RETURNS[ProtocolDefs.ReturnCode] ]
RETURNS[info: NameInfoDefs.NameType] =
BEGIN
-- slightly subtle optimisation: If we don't have a stream, or the
-- stream we have times out, we'll need to get one to an R-Server for
-- GV. Getting one early might save us from having to call
-- FindRegServer later --
rc: ProtocolDefs.ReturnCode;
oldBad: BOOLEAN ← FALSE;
ClaimStream[];
BEGIN
IF str # NIL -- try cached stream first --
THEN BEGIN
rc ← EnquiryWork[str ! ProtocolDefs.Failed => GOTO streamGone];
EXITS streamGone => CloseStream[];
END;
IF str = NIL
THEN BEGIN
AcceptGV: INTERNAL PROC[addr: PupDefs.PupAddress]RETURNS[BOOLEAN] =
BEGIN
addr.socket ← ProtocolDefs.RegServerEnquirySocket;
IF str # NIL THEN ERROR;
str ← ProtocolDefs.CreateStream[addr !
ProtocolDefs.Failed => GOTO failed ];
cacheAddr ← addr;
RETURN[TRUE];
EXITS failed => { CloseStream[]; RETURN[FALSE] }
END;
-- don't use cached address, so that we return to a near server--
-- Note: The following call of FindRegServer doesn't call us
-- back recursively!
[] ← LocateDefs.FindRegServer["x.GV"L, AcceptGV];
IF str = NIL THEN { info ← allDown; RETURN };
rc ← EnquiryWork[str ! ProtocolDefs.Failed => GOTO notThere];
END;
IF rc.code = WrongServer
THEN oldBad ← TRUE
ELSE oldBad ← FALSE;
EXITS notThere => { CloseStream[]; oldBad ← TRUE; };
END;
IF oldBad
THEN BEGIN -- need to find the correct R-Server --
Accept: INTERNAL PROC[addr: PupDefs.PupAddress]RETURNS[BOOLEAN] =
BEGIN
ClaimStream[];
addr.socket ← ProtocolDefs.RegServerEnquirySocket;
IF str # NIL AND cacheAddr # addr THEN CloseStream[];
IF str = NIL
THEN BEGIN
str ← ProtocolDefs.CreateStream[addr !
ProtocolDefs.Failed => GOTO failed ];
cacheAddr ← addr;
END;
RETURN[TRUE];
EXITS failed => { CloseStream[]; ReleaseStream[]; RETURN[FALSE] }
END;
foundInfo: LocateDefs.FoundServerInfo;
ReleaseStream[] -- for FindRegServer --;
foundInfo ← LocateDefs.FindRegServer[name, Accept];
WITH foundInfo SELECT FROM
notFound => { info ← notFound; ClaimStream[]; RETURN };
allDown => { info ← allDown; ClaimStream[]; RETURN };
found =>
BEGIN
-- stream was claimed inside "Accept" --
rc ← EnquiryWork[str ! ProtocolDefs.Failed => GOTO down ];
EXITS down =>
{ CloseStream[]; info ← allDown; RETURN }
END;
ENDCASE => ERROR;
END;
info ← SELECT rc.code FROM
noChange => noChange,
BadPassword => badPwd,
AllDown => allDown,
done, BadRName =>
SELECT rc.type FROM
individual => individual,
group => group,
ENDCASE => notFound -- includes dead --,
ENDCASE => allDown;
END;
CloseStream: PROC =
{ IF str # NIL THEN { ProtocolDefs.DestroyStream[str]; str ← NIL } };
END.