Important: The information in this document is obsolete and should not be used for new development.
Writing a Requester ATP Application
You use thePSendRequest
function or thePNSendRequest
function 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
OpenDriver
function to open the .MPP driver. Even if you suspect that the .MPP and the .ATP drivers are open, you should call
theOpenDriver
function for the .MPP driver to ensure that this is the case. CallingOpenDrive
r for a driver that is already open will not produce harmful repercussions. See the chapter "Device Manager" in Inside Macintosh: Devices for information on
theOpenDriver
function. 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
PSendRequest
function. To specify a particular socket to be used to send the request, use thePNSendRequest
function; in this case, you must callPOpenATPSocket
to 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
reqTID
parameter; 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
theatpFlags
parameter is set. ATP sets this bit to inform you that it has assigned
a transaction ID and that thereqTID
field is now valid.- If you opened a socket to be used for the
PNSendRequest
call, close the socket usingPCloseATPSkt
. See"PCloseATPSkt" on page 6-31 for information on how to use this function. If you use thePSendRequest
function, ATP allocates a socket and opens and closes it for you.
PSendRequest
function. The code uses theBuildBDS
function 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 theOpenDriver
function 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 theBuildBDS
function for this purpose. You passBuildBDS
a 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.BuildBDS
returns as its function result the number of elements that it creates; you pass this number and a pointer to the buffer data structure to thePSendRequest
orPNSendRequest
function that you call to issue the request. The memory that you allocate for the buffer must be nonrelocatable until thePSendResponse
call completes execution. AfterPSendResponse
returns, 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 thePSendRequest
function or thePNSendRequest
function 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
addrBlock
parameter the AppleTalk internet address of the socket whose client responder application you are sending the request to.- Specify in the
reqLength
field the size in bytes of the request and in thereqPointer
field 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
timeOutVa
l andretryCount
parameters 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 theatpFlags
parameter 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.
userData
parameter,
and ATP will pass this to the responder application in theuserData
parameter of itsPGetRequest
call. 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: thetimeOutVal
field and theretryCount
field. ThetimeOutVal
value determines
in seconds how long ATP waits before resending the original request packet; theretryCount
value 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
retryCount
parameter 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 aPSendRequest
call, you can use either thePKillSendReq
function or thePRelTCB
function. To cancel aPNSendRequest
call, you can use thePKillSendReq
function 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 theTRelTime
parameter to one
of the following values:
TRelTime Setting of
release timer000 30 seconds 001 1 minute 010 4 minutes 100 8 minutes