Grapevine Package This package implements a subset of the client protocols for accessing the Grapevine registration services. The top-level facilities included are user name/password authentication, group membership determination, and resource location. The package does not include operations for updating the Grapevine data base or for transporting electronic mail. However, lower-level primitives are accessible, out of which those operations could be constructed. For information on the organization and use of the Grapevine registration services and the protocols used to access them, consult "The Grapevine Interface", by Andrew Birrell, file [Indigo]Docs>Interface.press. 1. Organization and requirements The Grapevine package is distributed as file Grapevine.dm, which contains the following binary files: GrapevineEnquire.br, GrapevineLocate.br, GrapevineNameInfo.br, and GrapevineProtocol.br. In normal use, all four modules are required. All modules of the Grapevine package may be loaded into overlays (managed by the BCPL Overlays package); such overlays will swap out when calls to Grapevine are not in progress. The initialization module GrapevineOEP.br declares Overlay Entry Points (OEPs) required by the package. The Grapevine package depends on the Pup package and all its supporting packages. The following is a complete list of the modules required on a normal Alto: Grapevine package GrapevineEnquire, GrapevineLocate, GrapevineNameInfo, GrapevineProtocol (from Grapevine.dm) Pup package PupBSPOpenClose, PupBSPProt, PupBSPStreams, PupBSPBlock, PupBSPa, PupRTPOpenClose, PupRTP, PupNetDirLookup, Pup1OpenClose, Pup1b, PupAl1a, PupRoute, PupAlEthb, PupAlEtha, Pup1Init, PupDummyGate, PupAlEthInit (from PupPackage.dm) Context package Context, ContextInit (from Context.dm) Interrupt package Interrupt, InterruptInit (from Interrupt.dm) Queue package AltoQueue Timer package AltoTimer Strings package StringUtil (from Strings.dm) ------------ Copyright Xerox Corporation 1983 Grapevine Package September 20, 1983 2 ByteBlt package AltoByteBlt File Grapevine.decl is a "get" file containing definitions needed by clients of the package. These definitions consist of various data structures and error codes, including the following: An RName is a Grapevine registered name, in the form "simpleName.registry". It has the same representation as a BCPL String. A Password is a 64-bit encryption key, straightforwardly derived from a text password. A procedure exists to convert a String to a Password. A TimeStamp consists of a net address and a standard Alto packed time. All objects in the Grapevine data base are marked with TimeStamps, which are used to determine the validity of cached information and to control the propagation of updates. An RList represents the contents of a Grapevine group (or other list maintained by Grapevine). It contains a TimeStamp and is the head of a queue of RItems, each of which contains an RName. 2. Initialization and general operation The Grapevine package must be initialized by calling: InitGrapevine(zone, testing [false]) Initializes the global state of the package. "zone" is a zone to be used for all storage allocations by the package. InitGrapevine permanently extracts only a four-word block from zone; but other operations make heavy temporary use of zone. If testing is true, the Grapevine package communicates only with servers that are running in "testing" mode. InitGrapevine may be called multiple times to change testing; the zone argument is ignored during all but the first call. The Pup package must be initialized (InitPupLevel1) before the Grapevine package may be called; and calls to Grapevine procedures must be from within the confines of a Context (as managed by the BCPL Context package). The Grapevine package caches some global state between calls. Most significantly, a BSP stream to the most recently accessed Grapevine server is usually left open; in most cases this substantially speeds up a subsequent request if it is made within the Grapevine server's connection timeout interval (currently one minute). If desired, this global state may be flushed by calling GVDestroyStream(). Procedures in the Grapevine package may be called from multiple contexts (processes). The package maintains an internal interlock so that only one Grapevine protocol interaction will be in progress at a time. Grapevine Package September 20, 1983 3 3. High-level operations These operations are sufficient for authentication, access control, and resource location. Authenticate(name, password) = code Checks "name" (an RName) and "password" (a 64-bit Password key) in the Grapevine data base, and returns a code describing the outcome (from Grapevine.decl): ecIndividual name is an individual and password is correct. ecBadPassword incorrect password. ecBadRName name does not exist or is not an individual. ecAllDown can't contact any R-Server for name's registry. MakeKey(string, key) Converts a text password pointed to by "string" to a 64-bit encryption key pointed to by "key". The result is suitable as the "password" argument of Authenticate. IsMemberClosure(group, name) = code Determines whether "name" appears anywhere in the tree that results from expanding "group"; both arguments are RNames. Returns a code describing the outcome: ecIsMember name is a member of group. ecIsNotMember name is not a member of group. ecBadRName name or group does not exist or is of wrong type. ecAllDown can't contact any R-Server for group's registry. FindServer(serverName, pollingSocket, proc, arg) Attempts to find an instance of a service identified by the specified name. If serviceName contains a ".", treats it as an RName (which must be a Grapevine group) and attempts to locate the nearest functioning instance of the service among the group's members (which must be individuals whose connect sites are valid Pup address constants). If serviceName does not contain a ".", treats it as a Name Lookup Server (NLS) name and attempts to locate the nearest functioning instance of the service without consulting Grapevine (a local broadcast is also issued). In either case, for each potential instance of the service, calls proc(port, arg), which should attempt to open a connection to the given port and return true if successful and false if not (arg may be used to communicate additional parameters and/or results). Proc should at least default and perhaps unconditionally set the port's socket field to the appropriate well-known socket number before using it, since in general the service socket is distinct from the polling socket. Note that proc will be called repeatedly until either it returns true or the list of potential instances is exhausted. If FindServer is successful, it returns zero; if unsuccessful, it returns one of ecBadRName (there is no such service) or ecAllDown (can't contact any instance of the service). The service to be located must respond to EchoMe requests on a well-known socket, the low 16 bits of which are given as Grapevine Package September 20, 1983 4 pollingSocket and the high 16 bits of which are zero (except when the Grapevine package is in testing mode). Any service (Grapevine or non-Grapevine) obeying this convention may be located, regardless of whether it is named by an RName or an NLS name. 4. Higher-level primitives These procedures may be used to perform most of the querying (as opposed to updating) operations provided by Grapevine. Calling them requires definitions from GrapevineProtocol.decl, which may be obtained from GrapevineSources.dm. IsInACL(name, member, descriptor) = code Determines membership in an access control list. "name" is the RName of a group with which the access control list is associated, "member" is the RName to be tested for membership in that list, and "descriptor" encodes one of a large collection of access control list checking options. "descriptor" is composed by adding together three constants, one from each of the following groups: The R-Name with which the access control list is actually associated: dItself the group "name" itself. dItsRegistry "name"s registry (i.e., "reg.GV"). What access control list (associated with "name") is to be checked: dMembers the membership list of the group. dOwners the owners list of the group. dFriends the friends list of the group. How the list is to be enumerated: dDirect just check for membership in the list itself. dClosure expand any names that are groups, and check for membership in those groups as well (do this recursively to as many levels as necessary). dUpArrow as for dClosure, but expand only those groups whose names contain "^"; in many cases this is considerably faster than dClosure. For example, the IsMemberClosure procedure, described earlier, is implemented as IsInACL(name, member, dItself+dMember+dClosure). IsInACL returns one of the codes described under IsMemberClosure (above). ReadRList(name, op, lvEC []) = rList or 0 Reads a list associated with "name" (an RName) as specified by "op": opReadMembers the (direct) membership of the group "name". opReadOwners the (direct) Owner list for "name". opReadFriends the (direct) Friends list for "name". If this is successful, ReadRList returns a pointer to an RList, which heads a queue of RItems each of which contains an RName. This RList is allocated from the zone that was passed to Grapevine Package September 20, 1983 5 InitGrapevine; note that an indefinite amount of storage is required, depending on the size of the list. If ReadRList is unsuccessful, it returns zero after storing into @lvEC (if specified) one of the following codes: ecBadRName name does not exist or is not a group. ecAllDown can't contact any R-Server for group's registry. DestroyRList(rList) Destroys (i.e., frees the storage occupied by) an RList returned by ReadRList. ReadRString(name, op, lvEC []) = string or 0 Reads a string associated with "name" (an RName) as specified by "op": opReadConnect the Connect site for the individual "name". opReadRemark the Remark for the group "name". If this is successful, ReadRString returns a BCPL String allocated from the zone that was passed to InitGrapevine. The caller must Free the string to that zone when done with it. 5. Lower-level primitives These are the procedures out of which the higher-level operations are composed; they may be used to compose other Grapevine operations (both queries and updates) not provided by the package. If you use these, you should read the code in GrapevineNameInfo.bcpl to understand how they are intended to be called. Calling these procedures may require definitions from GrapevineInternal.decl as well as GrapevineProtocol.decl and Grapevine.decl. Enquire(name, proc, arg) = returnCode Attempts to establish a BSP stream to a registration server that has a copy of the registry for "name" (an RName), and then calls proc(stream, name, arg). Proc should return a ReturnCode describing the outcome; any additional results may be communicated via storage pointed to by "arg". Enquire returns the ReturnCode returned by proc if proc was actually called, or a locally- manufactured ReturnCode otherwise. See GrapevineProtocol.decl and the "Grapevine Interface" document for the interpretation of ReturnCodes. Enquire's function is simply to establish contact with the correct registration server; it is proc's responsibility to perform the actual desired query, update, or whatever. That is, proc must send the protocol command over stream and interpret the result. Auxiliary procedures that facilitate this include SendWord, SendRName, ReceiveWord, ReceiveRName, and ReceiveRList. The first word of a Grapevine server's response is always a ReturnCode; and it is this ReturnCode that proc is expected to return. Additionally, if ReturnCode.code equals rcDone, proc is expected to consume any additional results that follow the ReturnCode before returning. Grapevine Package September 20, 1983 6 Proc may be called more than once, if the first call results in a ReturnCode indicating that the wrong registration server has been contacted. Also, any I/O to the BSP stream may result in a stream error, which causes control to be ripped away from proc and returned to Enquire. Consequently, proc must not acquire any resources (e.g., allocated storage) not known to the caller of Enquire, else those resources may be lost. EnquireWithStamp(stream, op, name, stamp [nullStamp]) = returnCode Sends a protocol command of the form [name, op, stamp] and returns the resulting ReturnCode. This constitutes the major protocol interaction of many Grapevine commands; it should be called only from within a "proc" passed to Enquire. 6. Revision history January 6, 1982 The third argument of IsInACL is now a "descriptor" encoding all possible combinations of ACL checking options. InitGrapevine has a "testing" option. September 20, 1983 A procedure FindServer has been added for locating servers by means of the Grapevine resource location algorithm. A few minor bugs are fixed.