DIRECTORY GVBasics USING [Connect, RName], GVLocate USING [FoundServerInfo, FoundState], GVNames USING [GetConnect, GetMembers, MemberInfo, NameType, RListHandle], GVProtocol USING [GetSocket, IsLocal], Process USING [MsecToTicks, SetTimeout ], Pup USING [Address, allHosts, allNets, nullAddress, Socket], PupBuffer USING [Buffer], PupHop USING [GetHop, Hop], PupName USING [Error, HisAddresses, NameLookup], PupSocket USING [AllocBuffer, CreateEphemeral, Destroy, Get, FreeBuffer, Kick, Send, SetNoErrors, SetUserHWords, Socket, waitForever], Rope USING [Cat, Equal, Fetch, Length, Substr]; GVLocateImpl: CEDAR MONITOR IMPORTS GVNames, GVProtocol, Process, PupHop, PupName, PupSocket, Rope EXPORTS GVLocate = BEGIN AddressInfo: TYPE = REF AddressInfoObject; AddressInfoObject: TYPE = RECORD[ preSorted: BOOLEAN, found: CARDINAL, addresses: SEQUENCE possible: CARDINAL OF AddressRec]; AddressRec: TYPE = RECORD[ addr: Pup.Address, hop: PupHop.Hop, reply: BOOLEAN]; ReplyInfo: TYPE = RECORD[ found: BOOLEAN, where: Pup.Address ]; Prod: PROC [socket: PupSocket.Socket, addrInfo: AddressInfo, accept: PROC [Pup.Address] RETURNS[BOOLEAN] ] RETURNS [info: ReplyInfo ] = { replyRecvd: BOOLEAN _ FALSE;-- "reply-waiting" flag cond: CONDITION; -- notified when reply comes in pleaseDie: BOOLEAN _ FALSE; -- for killing auxiliary processes DeathWish: ENTRY PROC RETURNS [BOOLEAN] = { RETURN[pleaseDie] }; KillSiblings: ENTRY PROC = { pleaseDie _ TRUE; PupSocket.Kick[socket] }; NoteReply: ENTRY PROC [i: CARDINAL, addr: Pup.Address] = { IF addrInfo.addresses[i].addr.host = 0 THEN { addrInfo.addresses[i].addr.host _ addr.host; addrInfo.addresses[i].addr.net _ addr.net }; addrInfo.addresses[i].reply _ TRUE; IF ~replyRecvd THEN NOTIFY cond; replyRecvd _ TRUE; }; TestReply: ENTRY PROC [i: CARDINAL] RETURNS [yes: BOOLEAN] = { yes _ addrInfo.addresses[i].reply; addrInfo.addresses[i].reply _ FALSE }; More: ENTRY PROC RETURNS[yes: BOOLEAN] = CHECKED { IF ~replyRecvd THEN WAIT cond; yes _ replyRecvd; replyRecvd _ FALSE; }; SendProd: PROCEDURE = { sent: CARDINAL _ 0; lastHop: CARDINAL = 4; --sorting limit-- FOR wantedHop: CARDINAL IN [0..lastHop) DO lastPass: BOOLEAN = (wantedHop=lastHop-1); FOR i: CARDINAL IN [0..addrInfo.found) DO IF DeathWish[] OR sent >= addrInfo.found THEN GOTO GetUsOutOfHere; IF addrInfo.preSorted OR (lastPass AND addrInfo.addresses[i].hop>=wantedHop) OR addrInfo.addresses[i].hop = wantedHop THEN { b: PupBuffer.Buffer = PupSocket.AllocBuffer[socket]; b.type _ echoMe; b.dest _ addrInfo.addresses[i].addr; b.dest.socket _ GVProtocol.GetSocket[RSPoll]; b.hWord[0] _ i; PupSocket.SetUserHWords[b, 1]; PupSocket.Send[socket, b, b.dest]; sent _ sent + 1; }; REPEAT GetUsOutOfHere => EXIT -- from outer loop! ENDLOOP; ENDLOOP; }; Slurp: PROCEDURE = { UNTIL DeathWish[] DO b: PupBuffer.Buffer = PupSocket.Get[socket]; IF b # NIL THEN { SELECT b.type FROM iAmEcho => IF b.hWord[0] < addrInfo.found THEN NoteReply[b.hWord[0], b.source]; ENDCASE => NULL; PupSocket.FreeBuffer[b]; }; ENDLOOP; }; prodder: PROCESS; slurper: PROCESS; TRUSTED { prodder _ FORK SendProd[]; slurper _ FORK Slurp[]; Process.SetTimeout[@cond, Process.MsecToTicks[1500]]; }; info.found _ FALSE; UNTIL info.found DO IF ~More[] THEN EXIT-- time-out on "cond" --; FOR i: CARDINAL IN [0..addrInfo.found) UNTIL info.found DO IF TestReply[i] THEN { info.where _ addrInfo.addresses[i].addr; IF accept[info.where] THEN info.found _ TRUE; }; ENDLOOP; ENDLOOP; KillSiblings[]; TRUSTED { JOIN prodder; JOIN slurper; }; }; GetGVRegServer: PROC RETURNS[ info: AddressInfo ] = { addressesInGVRS: CARDINAL = 10; -- we take the 10 closest socket: Pup.Socket = GVProtocol.GetSocket[RSEnquiry]; addresses: LIST OF Pup.Address; info _ NEW[AddressInfoObject[addressesInGVRS]]; info.preSorted _ TRUE; info.found _ 0; info.addresses[0] _ [ addr: [net: Pup.allNets, host: Pup.allHosts, socket: socket], hop: PupHop.GetHop[Pup.allNets], reply: FALSE ]; info.found _ 1; addresses _ PupName.HisAddresses["GrapevineRServer", socket ! PupName.Error => CONTINUE ]; UNTIL addresses = NIL DO info.addresses[info.found] _ [ addr: addresses.first, hop: PupHop.GetHop[addresses.first.net], reply: FALSE ]; info.found _ info.found + 1; IF info.found = addressesInGVRS THEN EXIT; addresses _ addresses.rest; ENDLOOP; }; GetGroupInfo: PROC [who: GVBasics.RName] RETURNS[ state: GVLocate.FoundState, info: AddressInfo _ NIL, local: GVBasics.RName _ NIL] = { mInfo: GVNames.MemberInfo = GVNames.GetMembers[who]; SELECT mInfo.type FROM notFound, individual => state _ notFound; allDown => state _ allDown; group => { m: group GVNames.MemberInfo = NARROW[mInfo, group GVNames.MemberInfo]; state _ found; info _ NEW[AddressInfoObject[m.count]]; info.preSorted _ FALSE; info.found _ 0; FOR member: GVNames.RListHandle _ m.members, member.rest UNTIL member = NIL DO cInfo: GVNames.NameType; connect: GVBasics.Connect; [cInfo, connect] _ GVNames.GetConnect[member.first]; SELECT cInfo FROM individual => BEGIN addr: Pup.Address = PupName.NameLookup[connect, GVProtocol.GetSocket[RSEnquiry] ! PupName.Error => GOTO Cant]; info.addresses[info.found] _ [ addr: addr, hop: PupHop.GetHop[addr.net], reply: FALSE ]; info.found _ info.found + 1; IF GVProtocol.IsLocal[addr] THEN local _ member.first; EXITS Cant => NULL; END; ENDCASE => NULL -- ignore others --; ENDLOOP; }; ENDCASE => ERROR; }; FindNearestServer: PUBLIC PROC [ list: GVBasics.RName, accept: PROC [Pup.Address] RETURNS [BOOL] ] RETURNS [info: GVLocate.FoundServerInfo] = { addrInfo: AddressInfo; state: GVLocate.FoundState; IF list.Equal["gv.gv", FALSE] THEN { state _ found; addrInfo _ GetGVRegServer[]; } ELSE [state, addrInfo, ] _ GetGroupInfo[list]; SELECT state FROM notFound => RETURN[[notFound[]]]; allDown => RETURN[[allDown[]]]; found => { socket: PupSocket.Socket = PupSocket.CreateEphemeral[ remote: Pup.nullAddress, getTimeout: PupSocket.waitForever ]; PupSocket.SetNoErrors[socket]; FOR i: NAT IN [0..4) DO -- re-tries for lost packets reply: ReplyInfo = Prod[socket, addrInfo, accept]; IF reply.found THEN { PupSocket.Destroy[socket]; RETURN[[found[reply.where]]]; }; REPEAT FINISHED => { PupSocket.Destroy[socket]; RETURN[[allDown[]]]; }; ENDLOOP; }; ENDCASE => ERROR; }; FindLocalServer: PUBLIC PROC [list: GVBasics.RName] RETURNS [state: GVLocate.FoundState, local: GVBasics.RName] = { [state, , local] _ GetGroupInfo[list]; IF local = NIL THEN state _ notFound; }; FindRegServer: PUBLIC PROC [ who: GVBasics.RName, accept: PROC [Pup.Address] RETURNS [BOOL] ] RETURNS [foundInfo: GVLocate.FoundServerInfo] = { sep: CHARACTER = '.; -- SN sep NA length: INT = who.Length[]; FOR i: INT DECREASING IN [0..length) DO IF who.Fetch[i] = sep THEN RETURN[FindNearestServer[Rope.Cat[who.Substr[start: i+1, len: length-i-1], ".gv"], accept]]; REPEAT FINISHED => RETURN[[notFound[]]]; ENDLOOP; }; END. <GVLocateImpl.mesa (Cedar) - Location of servers Copyright c 1985 by Xerox Corporation. All rights reserved. Andrew Birrell May 13, 1983 1:32 pm Mike Schroeder March 21, 1981 10:59 AM Hal Murray, June 3, 1986 3:46:17 pm PDT This is complicated! The parameters are a table of candidate addresses, and a socket. The prodder process sends out "echoMe" pups to the addresses; the slurper process accepts "iAmEcho" replies, and marks the table. The original process reads the marks from the table, and calls the client's "accept" procedure to see if this address is ok. This satisfies various constraints about not hogging pup buffers. The "echoMe" packets are sent out to closer addresses first; they're not sent after the client has accepted an address. Everywhere, the Monitor is not locked while doing long waits. caller promises that "i" is in range force socket number, because database doesn't have GV test-mode socket numbers Top-level contacting R-Servers. Any method is valid! Try local broadcast, and try Name Lookup Server. find a registration server for given R-Name Κ D˜codešœ/™/Kšœ Οmœ1™Kš Ÿ œžœžœžœžœžœ˜@KšŸ œžœžœžœ˜HšŸ œžœžœžœ˜:Kšœ$™$šžœ$žœ˜-Kšœ,˜,K˜,—Kšœžœ˜#Kšžœ žœžœ˜ Kšœ žœ˜Kšžœ˜—š Ÿ œžœžœžœžœžœ˜>KšœBžœ˜J—š Ÿœžœžœžœžœžœ˜2Kšžœ žœžœ˜Kšœžœ˜%Kšœ˜—šŸœž œ˜Kšœžœ˜Kšœ žœ ˜(šžœ žœžœ ž˜*Kšœ žœ˜*šžœžœžœž˜)Kšžœ žœžœžœ˜BKšžœ˜Kšžœ žœ&˜6šžœ'žœ˜/Kšœ4˜4K˜K˜$KšœN™NKšœ-˜-K˜Kšœ˜K˜"Kšœ˜——šž˜Kšœžœ ˜*—Kšžœ˜—Kšžœ˜Kšžœ˜—šŸœž œ˜šžœ ž˜Kšœ,˜,šžœžœžœ˜šžœž˜˜ Kšžœžœ!˜D——Kšžœžœ˜Kšœ˜—Kšžœ˜—Kšžœ˜—Kšœ žœ˜Kšœ žœ˜šžœ˜ Kšœ žœ ˜Kšœ žœ ˜Kšœ8˜8—Kšœ žœ˜šžœ ž˜Kšžœ žœž œ˜-š žœžœžœžœ ž˜:šžœ žœž˜K˜(Kšžœžœžœ˜-Kšœ˜—Kšžœ˜—Kšžœ˜—K˜šžœ˜ Kšžœ ˜ Kšžœ ˜—Kšžœ˜K˜K˜—šŸœžœžœ˜5Kšœžœ ˜9Kšœ5˜5Kšœ žœžœ ˜Kšœf™fKšœžœ%˜/Kšœžœ˜Kšœ˜šœ˜Kšœ=˜=Kšœ ˜ Kšœžœ˜—K˜KšœOžœ˜Zšžœ žœž˜šœ˜Kšœ˜Kšœ(˜(Kšœžœ˜—K˜Kšžœžœžœ˜*K˜Kšžœ˜—Kšœ˜K˜K˜—š Ÿ œžœžœ2žœžœ˜‡K˜4šžœ ž˜Kšœ)˜)Kšœ˜šœ ˜ Kšœžœ"˜FKšœ˜Kšœžœ˜'Kšœžœ˜Kšœ˜šžœ6žœ žœž˜NK˜K˜K˜4šžœž˜˜ Kšž˜šœ˜šœ=˜=Kšœžœ˜——˜K˜ Kšœ˜Kšœžœ˜—K˜Kšžœžœ˜6Kšžœ žœ˜Kšžœ˜——Kšžœžœ œ˜$—Kšžœ˜ —Kšžœžœ˜—Kšžœ˜K˜K˜—šŸœžœžœ˜ Kšœ˜Kšœžœžœžœ˜+Kšžœ$˜,Kšœ˜Kšœ˜Kšžœžœžœ0˜RKšžœ*˜.šžœž˜Kšœ žœ˜!Kšœ žœ˜šœ ˜ šœ5˜5Kšœ=˜=—K˜š žœžœžœžœ ˜4Kšœ2˜2šžœ žœ˜Kšœ˜Kšžœ˜ —šžœžœ˜Kšœ˜Kšžœ˜—Kšžœ˜ ——Kšžœžœ˜—Kšœ˜K˜—šŸœžœžœ˜3Kšžœ8˜?K˜&Kšžœ žœžœ˜%Kšœ˜K˜—šŸ œžœžœ˜Kšœžœžœžœ˜@Kšžœ)˜1Kšœ+™+Kšœž œ  ˜!Kšœžœ˜š žœžœž œžœ ž˜'šžœž˜KšžœV˜\—Kšžœžœžœ˜(Kšžœ˜—Kšžœ˜K˜K˜—Kšžœ˜K˜K˜—…—°(0