-- 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.