Important: The information in this document is obsolete and should not be used for new development.
Using Mappers
This section begins by describing how the general provider functions that govern a provider's mode of operation apply to mapper providers. It goes on to discuss information you need to know in order to use mapper functions: how you format names and addresses specified in parameters to mapper functions and how you handle processing when calling mapper functions asynchronously. This section concludes with a discussion of different techniques you can use when using the mapper to search for a name pattern.Setting Modes of Operation for Mappers
Like all Open Transport providers, mappers can use different modes of operation. A mapper can execute synchronously or asynchronously. You set the mapper's default mode of execution by using the appropriate function to open it; for example, you can create a mapper that executes asynchronously by calling theOTAsyncOpenMapper
function. After opening the mapper, you can change its mode of execution by calling theOTSetSynchronous
orOTSetAsynchronous
functions. To determine how mapper functions execute, you call theOTIsSynchronous
function.Mappers use one asynchronous event and four completion events. Table 6-1 lists the event codes that the mapper provider can pass to your application and explains the meaning of the
cookie
parameter to the notifier for each function. For more detailed information, see the descriptions of the mapper functions in "Functions".Table 6-1 Completion events for asynchronous mapper functions
The only way to cancel an asynchronous mapper function is to call the
OTCloseProvider
function, passing the mapper reference for which the function was executed. TheOTCloseProvider
function is described in the chapter "Providers" in this book.By default, mappers do not block and do not acknowledge sends. You can change a mapper's blocking status by using the
OTSetBlocking
function. Mapper providers are not affected by their send-acknowledgment status. However, a mapper provider's blocking status might affect the behavior of mapper functions. For example, if a mapper is blocking, heavy network traffic might cause mapper functions to wait before sending or receiving data. If a mapper is nonblocking and you are doing a lot of name lookups, theOTLookupName
function might return with thekOTFlowErr
result. In this case, you can try executing the function later.Specifying Name and Address Information
Several mapper functions require that you specify a name or address. This might be a name to register or to look up. Specifying a name or address means that you have to create a buffer that contains the information and then create aTNetbuf
structure that specifies the size and location of this buffer. The format that you use to store a name or an address is specific to the name-registration protocol that underlies the mapper and is exactly the same as the name and address formats that you can use to bind an endpoint. For information about name and address formats, please consult the documentation provided for the protocol you are using.If the protocol supports it, you can specify a name pattern rather than a name when calling the
OTLookupName
function. Different protocols might use different wildcard characters to define name patterns. Please consult the documentation provided for your protocol to determine valid wildcard characters and how you use these to specify name patterns.Searching for Names
You use theOTLookupName
function to search for a registered name or for a list of names if your protocol supports name pattern matching. You use thereq
parameter to specify the name or name pattern to search for. When the function returns, it uses thereply
parameter to pass back the matching name or names.The
req
parameter is a pointer to aTLookupRequest
structure containing the name or name pattern to be found and additional information that the mapper can use in conducting the search. You use themaxcnt
field to specify the number of names you expect to be returned. If you are looking for a specific name, set this field to 1. If you are looking for a name pattern, you can use this field to indicate the number of matches you expect theOTLookupName
function to return. You use thetimeout
field to specify the amount of time (in milliseconds) available for this search. If a match is not found within the specified time, the function returns with thekOTNoDataErr
. If the number you specify for themaxcnt
field is larger than the number of names that match the given pattern, the mapper provider uses the value given in thetimeout
field to determine when to stop the search.The
reply
parameter is a pointer to aTLookupReply
structure that contains two fields. Thenames
field describes the size and location of the buffer in which the replies are placed when the function returns; therspcount
field specifies the number of matching entries found. Figure 6-1 shows how the contents of a reply buffer containing two entries are stored. The section "Code Sample: Using OTLookupName" provides and describes a sample program that uses theOTLookupName
function. See especially, Listing 6-3.Figure 6-1 Format of entries in
OTLookupName
reply buffer
The first two bytes of each entry specify the length of the address; the second two bytes specify the length of the name. The address is stored next and then the name, padded to a four byte boundary.
Retrieving Entries in Asynchronous Mode
If you call theOTLookupName
function asynchronously, you can use an alternate method for retrieving matching entries. In asynchronous mode, this function sends two event codes: it sends theT_LKUPNAMERESULT
code each time it stores a name in the reply buffer, and it sends theT_LKUPNAMECOMPLETE
code when it has stored the last name in the reply buffer--that is, when the function as a whole completes execution. Each time theT_LKUPNAMERESULT
event is passed to your notification function, you can do the following:
This method saves you the trouble of guessing how large a reply buffer to allocate. It might also save you some memory if you are expecting many matches to be returned and are interested in only some of them.
- Copy the name and address information from the reply buffer to some other location.
- From inside the notifier function, set the
reply->names.len
field or thereply->rspcount
field to 0.When you set either of these fields to 0, Open Transport automatically sets the other field to 0. It's important, however, that you reset these values from within the notifier or the results might be unpredictable. You can also do it from code bracketed by the
OTEnterNotifier
andOTLeaveNotifier
functions. For more information, see "OTEnterNotifier".
- Repeat the first two steps until the event passed to your notifier function is
T_LKUPNAMECOMPLETE
.
- Note
- The
T_LKUPNAMECOMPLETE
event might have stored a name in the buffer. Be sure to check for this possibility.Code Sample: Using OTLookupName
This section discusses the program OTLookupNameTest, which demonstrates how you open an NBP mapper provider, issue an NBP lookup request, and print out the resulting information. Listing 6-1 shows the preprocessor directives and the main function of the program.Listing 6-1 The main function to OTLookupNameTest
#ifndef qDebug /* variable set for OT debugging macros */ #define qDebug1 #endif #include <OpenTransport.h> #include <OpenTptAppleTalk.h> #include <OTDebug.h> /* Need OTDebugBreak & OTAssert macros */ #include <stdio.h> /* OTDebugStr is not defined in OT header files, but it is exported by the libraries, so we define the prototype here. */ extern pascal void OTDebugStr(const char* str); static UInt32 gLastPrinted = 0; /* Global var to track printing */ void main(void) { OSStatus err; char requestAddress[] = "=:AFPServer@*"; printf("Hello World!\n"); err = InitOpenTransport(); if (err == noErr) { err = LookupAndPrint(requestAddress); CloseOpenTransport(); } if (err == noErr) { printf("Success.\n"); } else { printf("Failed with error %d.\n", err); } printf("Done. Press command-Q to Quit.\n"); }The main function initializes Open Transport, calls the user-defined functionLookupAndPrint
(passing a value for the requested address), and then closes Open Transport.The
LookupAndPrint
function is the key function to the OTLookupNameTest program. However, because it calls Open Transport functions synchronously, it also uses a notifier to yield time to other processes. Listing 6-2 shows the notifier, which callsprintf
periodically in response to akOTSyncIdle
event. (Theprintf
function callsWaitNextEvent
, thus our synchronous calls to Open Transport will yield time to other processes. A real world application would probably use threads to do this.Listing 6-2 Notifier that yields time to other processes
static pascal void YieldingNotifier(EndpointRef ep, OTEventCode code, OTResult result, void* cookie) { #pragma unused(ep) #pragma unused(result) #pragma unused(cookie) switch (code) { case kOTSyncIdleEvent: if (TickCount() > gLastPrinted + 10) { printf("."); fflush(stdout); gLastPrinted = TickCount(); } break; default: /* do nothing */ break; } }For more information on using threads to yield time, see "Using Synchronous Processing With Threads".Listing 6-3 shows the
LookupAndPrint
function. This function takes one parameter, a pointer to an NBP address. This address must have the form<name>:<type>@<zone>
The function begins by opening an NBP mapper provider and switching it into synchronous/blocking mode. It uses
kOTSyncIdle
events (and the notifier shown in Listing 6-2) to yield time to other processes. Then it issues an NBP lookup request, using theOTLookUpName
function . When the request completes, the function calls the user-definedPrintAddress
andPrintName
functions to display the results.Listing 6-3 The LookupAndPrint function
static OSStatus LookupAndPrint(char *requestAddress) { OSStatus err; OSStatus junk; MapperRef nbpMapper; TLookupRequest lookupRequest; TLookupReply lookupReply; UInt8 *responseBuffer; TLookupBuffer*currentLookupReplyBuffer; UInt32 nameIndex; err = noErr; nbpMapper = kOTInvalidMapperRef; /* for error checking */ /* Create the responseBuffer. */ responseBuffer = OTAllocMem(kResponseBufferSize); if (responseBuffer == nil) err = kENOMEMErr; /* Create an NBP mapper and set it to up for threaded processing. */ if (err == noErr) nbpMapper = OTOpenMapper(OTCreateConfiguration(kNBPName), 0, &err); if (err == noErr) { junk = OTSetSynchronous(nbpMapper); OTAssert("LookupAndPrint: Could not set synchronous mode on mapper", junk == noErr); junk = OTSetBlocking(nbpMapper); OTAssert("LookupAndPrint: Could not set blocking mode on mapper", junk == noErr); junk = OTUseSyncIdleEvents(nbpMapper, true); OTAssert("LookupAndPrint: Could not enable sync idle events on mapper", junk == noErr); junk = OTInstallNotifier(nbpMapper, YieldingNotifier, nil); OTAssert("LookupAndPrint: Could not install notifier for mapper", junk == noErr); } /* Call OTLookupName synchronously. */ if (err == noErr) { /* Set up the TLookupRequest structure. */ OTMemzero(&lookupRequest, sizeof(lookupRequest)); lookupRequest.name.buf = (UInt8 *) requestAddress; lookupRequest.name.len = OTStrLength(requestAddress); lookupRequest.timeout = 1000;// 1 second in milliseconds lookupRequest.maxcnt = kResponseBufferSize / kNBPEntityBufferSize; /* Set up the TLookupReply structure. */ OTMemzero(&lookupReply, sizeof(lookupReply)); lookupReply.names.buf = responseBuffer; lookupReply.names.maxlen = kResponseBufferSize; /* Now do the lookup. */ err = OTLookupName(nbpMapper, &lookupRequest, &lookupReply); } /* Print out the contents of the responseBuffer. */ if (err == noErr) { printf("\n"); /* Start by pointing to the beginning of the response buffer. */ currentLookupReplyBuffer = (TLookupBuffer *) responseBuffer; /* For each response in the buffer... */ for (nameIndex = 0; nameIndex < lookupReply.rspcount; nameIndex++) { /*... print the name and address and... */ printf("%3d ", nameIndex); PrintAddress( (DDPAddress *) ¤tLookupReplyBuffer->fAddressBuffer[0]); PrintName( (char *)¤tLookupReplyBuffer-> fAddressBuffer[currentLookupReplyBuffer-> fAddressLength], currentLookupReplyBuffer->fNameLength); printf("\n"); /*... use OTNextLookupBuffer to get from the current buffer to the next. */ currentLookupReplyBuffer = OTNextLookupBuffer(currentLookupReplyBuffer); } } /* Clean up. */ if (responseBuffer != nil) { OTFreeMem(responseBuffer); } if (nbpMapper != kOTInvalidMapperRef) { junk = OTCloseProvider(nbpMapper); OTAssert("LookupAndPrint: Failed closing mapper", junk == noErr); } return err; }The functionLookupAndPrint
calls two functions, PrintName and PrintAddress, to print names and addresses; Listing 6-4 shows the two functions.Listing 6-4 Printing names and addresses
static void PrintName(const char *name, UInt32 length) { char nameForPrinting[256]; OTMemzero(nameForPrinting, 256); OTMemcpy(nameForPrinting, name, length); printf(""%s"", nameForPrinting); } static void PrintAddress( DDPAddress *addr ) { OTAssert( "PrintAddress: Expected a DDPNBPADdress", addr->fAddressType == AF_ATALK_DDP ); printf("Net = $%04x, Node = $%02x, Socket = $%02x ", addr->fNetwork, addr->fNodeID, addr->fSocket); }
Subtopics
- Setting Modes of Operation for Mappers
- Specifying Name and Address Information
- Searching for Names
- Retrieving Entries in Asynchronous Mode
- Code Sample: Using OTLookupName