-- Transport Mechanism - Location of server by client -- -- [Juniper]<DMS>MS>Locate.mesa -- Andrew Birrell 18-Mar-81 17:55:30 -- DIRECTORY BodyDefs USING [Connect, maxRNameLength, RName], LocateDefs USING [FoundServerInfo, FoundState], NameInfoDefs USING [Close, Enumerate, GetConnect, GetMembers, MemberInfo, NameType, RListHandle], ProtocolDefs USING [Connect, Init, IsLocal, maxConnectLength, RegServerEnquirySocket, RegServerPollingSocket], PupDefs USING [EnumeratePupAddresses, GetFreePupBuffer, GetPupAddress, PupAddress, PupBuffer, PupNameTrouble, PupRouterSendThis, PupSocket, PupSocketDestroy, PupSocketID, PupSocketMake, ReturnFreePupBuffer, SecondsToTocks, SetPupContentsWords], PupTypes USING [fillInSocketID, PupSocketID], Storage USING[ Node, Free ], String USING [AppendString, EquivalentString]; Locate: MONITOR IMPORTS NameInfoDefs, ProtocolDefs, PupDefs, Storage, String EXPORTS LocateDefs = BEGIN ReplyInfo: TYPE = RECORD[ found: BOOLEAN, where: PupDefs.PupAddress ]; AcceptReplies: PROCEDURE[ socket: PupDefs.PupSocket, sent: CARDINAL, accept: PROCEDURE[PupDefs.PupAddress]RETURNS[BOOLEAN] ] RETURNS[ info: ReplyInfo ] = BEGIN bestHops: CARDINAL ← LAST[CARDINAL]; info.found ← FALSE; UNTIL info.found OR sent = 0 -- we may finish early or late, but it will be near enough-- DO BEGIN b: PupDefs.PupBuffer = socket.get[]; IF b = NIL THEN EXIT ELSE BEGIN sent ← sent-1; SELECT b.pupType FROM iAmEcho => BEGIN info.where ← b.source; IF accept[info.where] THEN info.found ← TRUE END; ENDCASE; PupDefs.ReturnFreePupBuffer[b]; END; END; ENDLOOP; END; SendEnquiry: PROCEDURE[addr: PupDefs.PupAddress, from: PupDefs.PupAddress] = BEGIN b: PupDefs.PupBuffer; b ← PupDefs.GetFreePupBuffer[]; b.source ← from; b.pupType ← echoMe; b.dest ← addr; -- force socket number, because database may not have GV test-mode socket numbers -- b.dest.socket ← ProtocolDefs.RegServerPollingSocket; PupDefs.SetPupContentsWords[b, 0]; PupDefs.PupRouterSendThis[b]; END; EnquiryInfo: TYPE = RECORD[ outcome:{ done, down, badName }, local: BOOLEAN, sent: CARDINAL]; gvName: STRING = "gv.gv"; -- NA for registration servers-- NoGVRS: SIGNAL = CODE; -- debugging; may be resumed -- GetGVRegServer: PROCEDURE[ from: PupDefs.PupAddress ] RETURNS[ info: EnquiryInfo ] = BEGIN Work: PROCEDURE[addr: PupDefs.PupAddress] RETURNS[ BOOLEAN ] = BEGIN -- don't trust socket number given by NLS (?) -- addr.socket ← ProtocolDefs.RegServerEnquirySocket; SendEnquiry[addr, from]; info.sent ← info.sent+1; RETURN[FALSE] END; GVRS: STRING = "GrapevineRServer"L; info ← [done, FALSE, 0]; -- hack to allow test servers anywhere on my net -- [] ← Work[ [net:[0], host:[0], socket: ProtocolDefs.RegServerEnquirySocket ] ]; -- end hack -- BEGIN ENABLE PupDefs.PupNameTrouble => IF code = errorFromServer THEN BEGIN SIGNAL NoGVRS[]; GOTO bad END ELSE GOTO down; [] ← PupDefs.EnumeratePupAddresses[GVRS, Work ]; EXITS down => info.outcome ← down; bad => info.outcome ← badName; END; END; GetGroupInfo: PROC[ who, local: BodyDefs.RName, from: PupDefs.PupAddress] RETURNS[ info: EnquiryInfo ] = BEGIN mInfo: NameInfoDefs.MemberInfo = NameInfoDefs.GetMembers[who]; WITH m: mInfo SELECT FROM notFound => info ← [badName,FALSE,0]; allDown => info ← [down,FALSE,0]; individual => info ← [badName,FALSE,0]; group => BEGIN apparent: CARDINAL ← 0; actual: CARDINAL ← 0; Count: PROC[member:BodyDefs.RName]RETURNS[done:BOOLEAN] = { apparent ← apparent + 1; done ← FALSE }; addresses: DESCRIPTOR FOR ARRAY OF PupDefs.PupAddress; Access: PROC[member:BodyDefs.RName]RETURNS[done:BOOLEAN] = BEGIN cInfo: NameInfoDefs.NameType; connect: ProtocolDefs.Connect = [ProtocolDefs.maxConnectLength]; done ← FALSE; cInfo ← NameInfoDefs.GetConnect[member, connect]; SELECT cInfo FROM individual => BEGIN PupDefs.GetPupAddress[@(addresses[actual]), connect ! PupDefs.PupNameTrouble => GOTO cant]; actual ← actual + 1; EXITS cant => NULL; END; ENDCASE => NULL -- ignore others --; END; NameInfoDefs.Enumerate[m.members, Count]; addresses ← DESCRIPTOR[Storage.Node[apparent* SIZE[PupDefs.PupAddress]], apparent]; NameInfoDefs.Enumerate[m.members, Access]; NameInfoDefs.Close[m.members]; info ← [done,FALSE,0]; FOR i: CARDINAL IN [0..actual) DO IF local = NIL THEN { SendEnquiry[addresses[i], from]; info.sent ← info.sent+1 } ELSE BEGIN IF ProtocolDefs.IsLocal[addresses[i]] THEN BEGIN info.local ← TRUE; local.length ← 0; String.AppendString[local, who]; END; END; ENDLOOP; Storage.Free[BASE[addresses]]; END; ENDCASE => ERROR; END; FindRegServer: PUBLIC PROCEDURE[ who: BodyDefs.RName, accept: PROCEDURE[PupDefs.PupAddress]RETURNS[BOOLEAN] ] RETURNS[ foundInfo: LocateDefs.FoundServerInfo ] = BEGIN -- find a registration server for given R-Name -- sep: CHARACTER = '.; -- SN sep NA -- rPtr: CARDINAL; NA: BodyDefs.RName = [BodyDefs.maxRNameLength]; -- parse to find registry name -- rPtr ← who.length; DO IF rPtr = 0 THEN RETURN[ [notFound[]] ]; rPtr←rPtr-1; IF who[rPtr] = sep THEN EXIT; ENDLOOP; NA.length ← 0; FOR rPtr←rPtr+1, rPtr+1 WHILE rPtr # who.length DO NA[NA.length] ← who[rPtr]; NA.length←NA.length+1 ENDLOOP; String.AppendString[NA, ".GV"L]; foundInfo ← FindNearestServer[NA, accept]; END; --FindRegServer-- FindNearestServer: PUBLIC PROCEDURE[list: BodyDefs.RName, accept: PROCEDURE[PupDefs.PupAddress]RETURNS[BOOLEAN] ] RETURNS[info: LocateDefs.FoundServerInfo] = BEGIN socket: PupDefs.PupSocket = PupDefs.PupSocketMake[ local: PupTypes.fillInSocketID, remote:, ticks: PupDefs.SecondsToTocks[1] ]; from: PupDefs.PupAddress = socket.getLocalAddress[]; THROUGH [1..3] -- re-tries for lost packets -- DO BEGIN sendInfo: EnquiryInfo = IF String.EquivalentString[list, gvName] THEN GetGVRegServer[from] ELSE GetGroupInfo[list,NIL,from]; SELECT sendInfo.outcome FROM badName => { info ← [notFound[]]; EXIT }; down => { info ← [allDown[]]; EXIT }; done => BEGIN reply: ReplyInfo = AcceptReplies[socket, sendInfo.sent, accept]; IF reply.found THEN { info ← [found[reply.where]]; EXIT } ELSE NULL --continue round loop-- END; ENDCASE => ERROR; END; REPEAT FINISHED => info ← [allDown[]] ENDLOOP; PupDefs.PupSocketDestroy[socket]; END --FindNearestServer--; FindLocalServer: PUBLIC PROCEDURE[list, local: BodyDefs.RName] RETURNS[ LocateDefs.FoundState ] = BEGIN sendInfo: EnquiryInfo = GetGroupInfo[list, local, ]; SELECT sendInfo.outcome FROM badName => RETURN[ notFound ]; down => RETURN[ allDown ]; done => RETURN[ IF sendInfo.local THEN found ELSE notFound ]; ENDCASE => ERROR; END; AcceptFirst: PUBLIC PROCEDURE[PupDefs.PupAddress]RETURNS[BOOLEAN] = BEGIN RETURN[TRUE] END; ProtocolDefs.Init[]; END.