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]<Grapevine>Docs>Interface.press.



1. Organization and requirements


The Grapevine package is distributed as file  <Alto>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 <AltoSource>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.