Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: Networking /
Chapter 3 - Name-Binding Protocol (NBP) / Using NBP


Handling Names Table Entry Requests

In addition to providing services that let you register an entity name and socket address for your process, NBP lets you look up addresses of other entities based on a name, confirm that a process whose entity name and address you already have is still registered with NBP and that the address is correct, remove your process's name and address from the names table when you no longer want to make the entity available, and cancel a pending request. You use

Preparing an Entity Name

To prepare an entity name using NBPSetEntity, you allocate a buffer that is at least
99 bytes long. You can allocate a record of type EntityName for this buffer. You pass NBPSetEntity a pointer to the buffer along with the three parts of the name (object, type, and zone), and NBPSetEntity writes the entity name to the buffer in the
format that the PLookupName, PConfirmName, and PRemoveName functions require.
Figure 3-5 shows the format of the entity name record.

Figure 3-5 Entity name record format

For the PConfirmName and PRemoveName functions, you must specify explicit values for the nbpObject, nbpType, and nbpZone parameters. However, you can specify wildcards for these parameters for PLookupName.

Looking Up a Name

You can use the PLookupName function to look up the address of a particular entity whose NBP name you know. You can also use the PLookupName function to find the addresses of more than one entity whose NBP names match a partial name that includes wildcards.

If you want to retrieve the address of a particular entity, you assign to the entityPtr field of the parameter block a pointer to a fully qualified entity name that you provided using NBPSetEntity. You create a buffer to hold the name and address that PLookupName returns and set the parameter block's return buffer pointer (retBuffPtr) field to this buffer's pointer. Because the data is packed and each tuple takes a maximum of 104 bytes, to look up a particular name you need to set the return buffer size (retBuffSize) field to the buffer size of 104 bytes. Figure 3-6 shows the format of
the record for a tuple that PLookupName returns.

Figure 3-6 Tuple returned by the PLookupName function

If you want only one name and address pair returned, you set the maximum number of matches (maxToGet) field to 1. When you call the function asynchronously, you must assign to the ioCompletion field a pointer to your completion routine or set this field to NIL. For more information about executing routines synchronously or asynchro-
nously, see the chapter "Introduction to AppleTalk" in this book.

If you want to obtain the addresses of other instances of the same type of entity that are running on other nodes in the network, you can look up the addresses of these entities by specifying wildcards. In this case, you specify a type field value and wildcards for the object and zone fields.

Table 3-1 shows the wildcards that you can use to control the kind of matches that you want NBP to return.
Table 3-1 NBP wildcards
CharacterMeaning
=All possible values. You can use the equal sign (=) alone instead of specifying a name in the object or type field.
[double tilde]Any or no characters in this position. You can use the double tilde ([double tilde]) to obtain matches for object or type fields. For example, pa[double tilde]l matches pal, paul, paper ball, and so forth. You can use only one double tilde in any string. Press Option-X to type the double tilde character on a Macintosh keyboard. If you use the double tilde alone, it has the same meaning as the equal sign (=).

Any node not running AppleTalk Phase 2 drivers will not recognize this character.

*This zone. You can use the asterisk (*) in place of the name of the zone to which this node belongs.

For example, if you want to retrieve the names and addresses of all the mailboxes in the same zone as one in which your process is running, you can set the entity name object field to the equal sign (=), the type field to Mailbox, and the zone field to the asterisk (*). The PLookupName function will return the entity names and internet addresses of all mailboxes in that zone excluding your own entity's name and address.

You can specify how thorough the lookup should be by defining the number of times that NBP should broadcast the lookup packets and the time interval between these retries. To do this, you assign values to the parameter block's count and interval fields. See the discussion on how to determine these values in the section "Registering a Names Table Entry" beginning on page 3-8.

You must also create a buffer large enough to hold all of the tuples for the matches that NBP returns. (See Listing 3-3 on page 3-15.) You assign the buffer's pointer to the parameter block's retBuffPtr field and the buffer's size in bytes to the retBuffSize field. Allow 104 bytes for each match. You set the maximum number of matches for NBP to return as the value of the maxToGet field.

The PLookupName function keeps track of the number of matches it writes to the return buffer each time it receives a returned packet containing one or more matches, and it updates the number of matches returned (numGotten) field after it returns each match. Because PLookupName maintains numGotten, you can start reading the names and addresses in the buffer and storing them or displaying them for the user before the function completes execution.

A single lookup request or retry can return more than one match in a reply packet. When this happens, the PLookupName function will return as many of the matches that the packet contains as will fit in the buffer. In cases such as this, you will find that the number of tuples that PLookupName writes to the return buffer may exceed the maximum number of matches to be returned as specified by maxToGet. When this occurs you can assume that there may be additional matches that did not fit in the buffer or additional reply packets containing matches that PLookupName did not process. To receive all the matches, you should increase the size of the buffer and the maxToGet number, and call the PLookupName function again.

If the buffer is too small to accommodate all of the returned matches in a packet,
the PLookupName function returns a function result of nbpBuffOvr. In any case,
the numGotten field always indicates the actual number of tuples returned in the
buffer. (See also "PLookupName" beginning on page 3-28 for more information
about this function.)

The code in Listing 3-2 assigns values to the fields of the parameter block to be used for the PLookupName function call. The value theEntity points to a packed entity-name record that you prepared using NBPSetEntity. This is the name that will be looked
for. The value returnBufferPtr points to the buffer where PLookupName will return
any matches that it finds. The buffer must be able to hold the number of matches specified by the input value of entityCount; each match is 104 bytes long. On return, entityCount contains the number of matches that the PLookupName function found and returned in the buffer pointed to by returnBufferPtr. The PLookupName function's glue code in the MPW interface fills in the values for the ioRefNum and csCode fields.

Listing 3-2 Calling PLookupName to find matches for an entity name

FUNCTION MyLookupName (theEntity: EntityName; VAR entityCount: Integer; 
                        returnBufferPtr: Ptr): OSErr;
CONST
   kTupleSize = 104;       {sizeof(AddrBlock) + a one-byte enumerator + }
                           { sizeof(EntityName)}
VAR
   mppPB: MPPParamBlock;
BEGIN
   WITH mppPB DO
      BEGIN
         interval := $0F;                 {reasonable values for the }
         count := $03;                    { interval and retry count}
         entityPtr := @theEntity;         {pointer to the entity name to }
                                          { look for}
         retBuffPtr := returnBufferPtr;   {pointer to the buffer for the }
                                          { tuples}
         RetBuffSize := entityCount * kTupleSize; 
                                          {return buffer size}
         maxToGet := entityCount;         {the number of entities that the }
                                          { return buffer can hold}
      END;
   MyLookupName := PLookupName(@mppPB, FALSE); 
                                 {look up the entity name}
   entityCount := mppPB.numGotten; 
                                 {return the number of matches found}
END;
The tuples in the buffer are in the format used in the NBP names table, as shown in Figure 3-6 on page 3-12. Because data is packed, the object, type, and zone names in this format are of arbitrary length; you cannot use Pascal to read these tuples. You can use the NBPExtract function to read tuples from the buffer.

Extracting a Name From a List of Returned Names

After NBP returns the matches to your buffer, you need to extract the match or matches that you want to use. You can use the NBPExtract function to read a name and address pair from the return buffer that you supplied to PLookupName. Before you call NBPExtract, you need to allocate memory for two buffers: one buffer that is at least
102 bytes long to hold the name part of the tuple and another buffer that is 4 bytes long to hold the address. You pass the NBPExtract function pointers to these buffers. The NBPExtract function unpacks the name and address data and writes it to the buffers
that you supply.

You also pass NBPExtract a pointer to the buffer containing the returned tuples; this is the pointer that you assigned to the PLookupName function's retBuffPtr parameter block field. For the numInBuf parameter, you specify the number of tuples in the return buffer; this is the value that the PLookupName function returned in the numGotten parameter block field. Counting the first returned tuple as one and following in sequence to the value of numGotten, you identify which name and address pair you want to extract as the value of the whichOne parameter. You can use the NBPExtract function in a loop that varies the value of the whichOne parameter (entityCount in the following code example) from 1 to the total number of tuples in the list to extract all the names in the list.

Listing 3-3 shows an application-defined procedure, DoMyLookupName, that allocates a buffer to hold the matches that the PLookupName function returns; the MyLookupName function, shown in Listing 3-2 on page 3-13, calls the PLookupName function. The DoMyLookupName procedure calls the MyLookupName function.

If the MyLookupName function returns a result code of noErr, then the code calls the NBPExtract function to read the matches that are in the buffer and write them to
the application's buffer with an application-defined routine, MyAddToMatchList; the listing does not show the MyAddToMatchList routine. After the matches are extracted, the code disposes of the return buffer.

Listing 3-3 Creating a buffer to hold name matches found, then using NBPExtract to read the matches

PROCEDURE DoMyLookupName;
   CONST
      kTupleSize = 104;       {sizeof(AddrBlock) + a one-byte enumerator + }
                              { sizeof(EntityName)}
      kMaxMatches = 100;      {number of matches to get}
   VAR
      result:           OSErr;
      returnBufferPtr:  Ptr;
      theEntity:        EntityName;
      entityCount:      Integer;
      index:            Integer;
      entityAddress:    AddrBlock;
BEGIN
   returnBufferPtr := NewPtr(kMaxMatches * LongInt(kTupleSize));
   IF returnBufferPtr <> NIL THEN
      BEGIN
      {Create a packed entity name.}
         NBPSetEntity(@theEntity, '=', 'AFPServer', '*');
         entityCount := kMaxMatches;      {maximum number of matches we want}
         result := MyLookupName(theEntity, entityCount, returnBufferPtr);
         IF result = noErr THEN
         {Extract the matches and add them to the match list.}
            FOR index := 1 TO entityCount DO
               IF NBPExtract(returnBufferPtr, entityCount, index, theEntity,
                            entityAddress) = noErr THEN
                  AddToMatchList(theEntity, entityAddress)
            DiposPtr(returnBufferPtr);    {release the memory}
   END;
END;

Confirming a Name

If you know the name and address of an entity, and you only want to confirm that the tuple is still registered with NBP and that the address hasn't been changed, you should call the PConfirmName function instead of calling PLookupName.

The PConfirmName function is faster than PLookupName because NBP can send a request packet directly to the node based on the address that you supply rather than having to broadcast lookup packets throughout the network to locate the names table entry based on the entity name alone.

The code in Listing 3-4 sets up the parameter block to be used for the PConfirmName function and calls PConfirmName to verify that the name and address still exist, and that the address is unchanged. If the application is using a different socket, PConfirmName returns a function result of nbpConfDiff and gives the new
socket number in the parameter block's newSocket field.

Listing 3-4 Confirming an existing NBP name and address

FUNCTION MyConfirmName (theEntity: EntityName; entityAddress: AddrBlock;
                        VAR socket: Integer): OSErr;
VAR
   mppPB: MPPParamBlock;
BEGIN
   WITH mppPB DO
      BEGIN
         interval := $0F;              {reasonable values for the interval }
         count := $03;                 { and retry count}
         entityPtr := @theEntity;      {entity name to look for}
         confirmAddr := entityAddress; {entity's network address}
      END;
   MyConfirmName := PConfirmName(@mppPB, FALSE);
   socket := mppPB.newSocket;          {return the socket number, which is }
                                       { the new socket number if }
                                       { PConfirmName's result is }
                                       { nbpConfDiff}
END;

Removing an Entry From the Names Table

After you close the socket that your process uses or when you no longer want to make the process available throughout the network, you remove the names table entry from the node on which it resides using the PRemoveName function.

There are two ways to remove a names table entry:

The PRemoveName function removes the entry from the node's names table unless the name is no longer registered, in which case, PRemoveName returns a function result of nbpNotFound. An entity name may not be included in the node's names table if, for example, the request to register the name had been canceled by the PKillNBP function before the PRegisterName function used to register the name was executed.

The code in Listing 3-5 shows how to remove a names table entry using PRemoveName. The PRemoveName function's glue code fills in the ioRefNum and csCode values. The code in Listing 3-5 provides the pointer to the names table entry record that was used to register the name; it assigns this value to the entityPtr field of the parameter block used for the PRemoveName function call. (The code in Listing 3-1 on page 3-10 created the names table entry record.) If the application-defined MyRemoveName function returns a function result of noErr, the code disposes of the memory block pointed to by ntePtr.

Listing 3-5 Removing an NBP names table entry

FUNCTION MyRemoveName (ntePtr: Ptr): OSErr;
VAR
   mppPB: MPPParamBlock;
   result: OSErr;
BEGIN
   mppPB.entityPtr := Ptr(ORD4(ntePtr) + 9);
                     {the entity name is at offset 9 in the NTE}
   result := PRemoveName(@mppPB, FALSE);{remove the name}
   IF (result = noErr) THEN
      DisposPtr(ntePtr); {release the memory}
   MyRemoveName := result;
END;

Canceling a Request

You can use the PKillNBP function to cancel a request to register, look up, or confirm
a names table entry if the function was called asynchronously and it has not already been executed.

When you call PRegisterName, PLookupName, or PConfirmName, NBP calls the Device Manager, which places your request in the .MPP driver queue with other requests waiting to be executed. To queue the request, the Device Manager places
a pointer to the function's parameter block in the .MPP driver queue. You assign this pointer to the PKillNPB parameter block's queue element (nKillQEl) field.

If the function request that you want to cancel is not in the queue, PKillNBP returns
a function result of cbNotFound. If PKillNBP cancels the function, it returns a
function result of noErr, and the function that it canceled returns a function result
of reqAborted.

The code in Listing 3-6 on page 3-18 shows how to cancel a PRegisterName, PLookupName, or PConfirmName function call. The application-defined MyKillNBP function takes as an input parameter a pointer to the parameter block that was used
to make the PLookupName, PRegisterName, or PConfirmName function call to be canceled. The code assigns this pointer to the nKillQEl field of the parameter block to be passed to the PKillNBP function. The ioRefNum and csCode field values are filled in by the PKillNBP function's glue code in the MPW interface.

Listing 3-6 Canceling a request to look up a name

FUNCTION MyKillNBP (requestPBPtr: MPPPBptr): OSErr;
   VAR
   mppPB: MPPParamBlock;
BEGIN
   mppPB.nKillQEl := Ptr(requestPBPtr);
   MyKillNBP := PKillNBP(@mppPB, FALSE);
END;

Previous Book Contents Book Index Next

© Apple Computer, Inc.
7 JUL 1996