Important: The information in this document is obsolete and should not be used for new development.
Writing a Requester ATP Application
You use thePSendRequestfunction or thePNSendRequestfunction to send an ATP request to another socket.Before you can use ATP, you must first open the .MPP driver, which in turn opens the .ATP driver. Use the Device Manager's
OpenDriverfunction to open the .MPP driver. Even if you suspect that the .MPP and the .ATP drivers are open, you should call
theOpenDriverfunction for the .MPP driver to ensure that this is the case. CallingOpenDriver for a driver that is already open will not produce harmful repercussions. See the chapter "Device Manager" in Inside Macintosh: Devices for information on
theOpenDriverfunction. Do not close the .MPP driver when you are finished using ATP because other applications dependent on it or on the .ATP driver require that it
remain open.To send an ATP request, follow these steps:
The code in Listing 6-1 shows how to open a socket and issue a call to the
- Create a buffer data structure (BDS) to hold the data that you expect to receive in response to your request. For information on how to do this, see "Creating a Buffer Data Structure" on page 6-12.
- To allow ATP to assign the socket to be used to send the request, use the
PSendRequestfunction. To specify a particular socket to be used to send the request, use thePNSendRequestfunction; in this case, you must callPOpenATPSocketto first open the socket (see "POpenATPSkt" on page 6-30 for information about this function). For information on the parameters required for these functions, see "Specifying the Parameters for the Send Request Function" on page 6-12.- You can get the transaction ID that ATP assigns to a request from the
reqTIDparameter; you need this ID to cancel a request. However, before you check this
field, make sure that the valid transaction ID (atpTIDValidvalue) bit (bit 1) of
theatpFlagsparameter is set. ATP sets this bit to inform you that it has assigned
a transaction ID and that thereqTIDfield is now valid.- If you opened a socket to be used for the
PNSendRequestcall, close the socket usingPCloseATPSkt. See"PCloseATPSkt" on page 6-31 for information on how to use this function. If you use thePSendRequestfunction, ATP allocates a socket and opens and closes it for you.
PSendRequestfunction. The code uses theBuildBDSfunction to create a buffer data structure to
hold the response data it expects in response. This segment of code assumes that the application has already called theOpenDriverfunction to open the .MPP and
.ATP drivers.Listing 6-1 Opening a socket and sending an ATP request
CONST kMaxPacketSize = 578; {maximum packet size we can receive} kNRespBuffs = 8; {you allow eight response buffers} kOurRespBufSize = kMaxPacketSize * kNRespBuffs; {response buffer size} VAR err: OSErr; reqLength: Integer; nBufs: Integer; ref: Integer; targetAddr: AddrBlock; gAtpPBPtr: ATPPBPtr; gReqBufPtr: Ptr; gRespBufPtr: Ptr; gSRespBdsPtr: BDSPtr; BEGIN gAtpPBPtr := ATPPBPtr(NewPtr(SizeOf(ATPParamBlock))); gReqBufPtr := NewPtr(kMaxPacketSize); gRespBufPtr := NewPtr(kOurRespBufSize); gSRespBdsPtr := BDSPtr(NewPtr(SizeOf (BDSType))); err := OpenDriver('MPP',ref); if err <> noErr THEN DoErr(err); WITH gAtpPBPtr^ DO BEGIN atpSocket := 0; {dynamically allocate a socket} addrBlock.aNet := 0; {accept requests from anyone} addrBlock.aNode := 0; addrBlock.aSocket := 0; END; err := POpenATPSkt(gAtpPBPtr,false);{socket is returned in } { gAtpPBPtr^.atpSocket} IF err <> noErr THEN DoErr(err); IF gAtpPBPtr^.ioResult <> noErr THEN DoErr(err); MyPrepareRequestData(gReqBufPtr,@reqLength); {user routine that prepares the } { request data to be sent} MyLocateTargetAddress(@targetAddr); {user routine that locates the } { target machine} {Set up your BDS structure.} nBufs := BuildBDS(gRespBufPtr,Ptr(gSRespBdsPtr),kOurRespBufSize); WITH gAtpPBPtr^ DO BEGIN atpFlags := atpXOvalue; {issue an exactly-once transaction} addrBlock.aNet := targetAddr.aNet; {set up the target machine} addrBlock.aNode := targetAddr.aNode; addrBlock.aSocket := targetAddr.aSocket; reqLength := reqLength; {size of your request data} reqPointer := gReqBufPtr; {pointer to actual request data} numOfBuffs := nBufs; {number of responses expected} bdsPointer := Ptr(gSRespBdsPtr); {your BDS pointer} timeOutVal := 3; {timeout interval} retryCount := 5; {number of retries} END; err := PSendRequest(gAtpPBPtr,false); IF err <> noErr THEN DoErr(err); MyProcessResponses(gAtpPBPtr^.bdsPointer,gAtpPBPtr^.numOfResps); {user routine to process the } { response data returned} {Clean up after you are done.} DisposePtr(Ptr(gAtpPBPtr)); DisposePtr(gReqBufPtr); DisposePtr(gRespBufPtr); DisposePtr(Ptr(gSRespBdsPtr)); END.Creating a Buffer Data Structure
Response data can comprise up to eight packets. ATP uses the organization of the buffer data structure (BDS) to manage these packets and ensure their complete delivery. The BDS must be an array of up to eight elements. You can create the buffer data structure yourself, or you can use theBuildBDSfunction for this purpose. You passBuildBDSa pointer to a buffer and the length of the buffer, and it creates up to eight elements, one for each packet, depending on the size of the buffer that you supply.BuildBDSreturns as its function result the number of elements that it creates; you pass this number and a pointer to the buffer data structure to thePSendRequestorPNSendRequestfunction that you call to issue the request. The memory that you allocate for the buffer must be nonrelocatable until thePSendResponsecall completes execution. AfterPSendResponsereturns, you should release this memory if you do not intend to reuse it.Specifying the Parameters for the Send Request Function
When you call either thePSendRequestfunction or thePNSendRequestfunction to send an ATP request, you must do these tasks:
You can send up to 4 bytes of additional information in the
- Specify as the value of the
addrBlockparameter the AppleTalk internet address of the socket whose client responder application you are sending the request to.- Specify in the
reqLengthfield the size in bytes of the request and in thereqPointerfield a pointer to the request data. The buffer that you use to store the request belongs to ATP until thePSendRequest(orPNSendRequest) function completes execution, after which you can either reuse the memory or release it.- Set the
timeOutVal andretryCountparameters appropriately for your network. See the following section, "Setting the Timeout and Retry Count Parameters." If this is an exactly-once request, set bit 5 (atpXOvalue) of theatpFlagsparameter to ensure that the responder application receives a specific request only once. For additional information about exactly-once transactions, see "At-Least-Once and Exactly-Once Transactions" on page 6-7.
userDataparameter,
and ATP will pass this to the responder application in theuserDataparameter of itsPGetRequestcall. To make this parameter meaningful, both the requester and the responder applications should agree on the use of these additional data bytes that are separate from the request or response data sent in an ATP transaction.Setting the Timeout and Retry Count Parameters
When a transaction does not complete on the first transmission, ATP retries it a number of times. You can control ATP's retry behavior by setting these two parameters: thetimeOutValfield and theretryCountfield. ThetimeOutValvalue determines
in seconds how long ATP waits before resending the original request packet; theretryCountvalue determines how many times ATP retries to send the request.ATP optimizes how it performs retries based on the response bitmap; ATP on the requester side resends the request with the header bitmap indicating to the ATP driver on the responder side which packets it should resend. (See the "The Bitmap/Sequence Number" on page 6-6 for more information.) ATP makes this request to resend until it receives all of the packets or it exhausts the number of retry attempts that you specify. If ATP exhausts all of the retry attempts before the requester side receives all of the packets, ATP returns an error.
To choose the correct timeout value and retry count combination, you should consider the speed and complexity of your network--for example, take into account the degree of traffic congestion and whether your network contains multiple routers. You can use the AppleTalk Echo Protocol (AEP) echo socket to test the network performance and adjust the values accordingly. For more information about using the AEP echo socket to test network performance, see the chapter "Datagram Delivery Protocol (DDP)" in this book. You can store various pairs of values in a preferences resource file so that you can easily change them to adapt to the speed of the network.
If you want ATP to retry indefinitely to send the request, you can set the
retryCountparameter to 255. In this case, ATP will send the request repeatedly until either the ATP responder end satisfies the request and sends back a response or you cancel the request. To cancel aPSendRequestcall, you can use either thePKillSendReqfunction or thePRelTCBfunction. To cancel aPNSendRequestcall, you can use thePKillSendReqfunction only.Setting the Release Timer Value
For exactly-once transactions, the ATP responder code saves the response packets until the ATP code on the requester side indicates that it has received all of them. When this is the case, the ATP code on the requester side sends a transaction release packet to tell the ATP code on the responder side to release the response packets. Because this packet could be dropped or lost during transmission, ATP uses a release timer to discard the retained packets after a specified amount of time and to release the memory used to
store them.If the nodes at both ends of the ATP connection are running AppleTalk Phase 2
drivers, you can control the release timer value that determines when ATP releases
the response packets by setting the 3 lower bits of theTRelTimeparameter to one
of the following values:
TRelTime Setting of
release timer000 30 seconds 001 1 minute 010 4 minutes 100 8 minutes