Important: The information in this document is obsolete and should not be used for new development.
Creating and Using a Connection Listener
A connection listener is a special sort of ADSP connection end that cannot receive or transmit data streams or attention messages. The sole function of a connection listener
is to wait passively to receive an open-connection request and to inform its client, the connection server, when it receives one. The connection server can then accept or deny the open-connection request. If it accepts the request, the connection server selects a socket to use as a connection end, establishes a connection end on that socket, and sends an acknowledgment and connection request back to the requesting connection end. The connection server can use the same socket as it used for the connection listener, or it
can select a different socket as the connection end.Use the following procedure to establish a connection listener and to use that connection listener to open a connection with a remote connection end:
Listing 5-2 illustrates the use of ADSP to establish and use a connection listener. It opens the .MPP and .DSP drivers and allocates memory for the CCB. Then it uses the
- Use the Device Manager's
OpenDriverfunction to open the .MPP driver and then use theOpenDriverfunction to open the .DSP driver. TheOpenDriverfunction returns the reference number for the .DSP driver. You must supply this reference number each time you call the .DSP driver.- Allocate nonrelocatable memory for a connection control block, which is described
in "Connections, Connection Ends, and Connection States" on page 5-6. The CCB
is 242 bytes. A connection listener does not need send and receive queues or an attention-message buffer. The memory that you allocate becomes the property of ADSP when you call thedspCLInitroutine to establish a connection listener. You cannot write any data to this memory except by calling ADSP, and you must ensure that the memory remains locked until you call thedspRemoveroutine to eliminate the connection end.- Call the
dspCLInitroutine to establish a connection listener. You must provide a pointer to the CCB.If there is a specific socket that you want to use for the connection listener, you can specify the socket number in the
localSocketparameter. If you want ADSP to assign the socket for you, specify 0 for thelocalSocketparameter. ADSP returns the socket number when thedspCLInitroutine completes execution.- If you wish, you can use the NBP routines to add the name and address of your connection listener to the node's names table. See the chapter "Name-Binding Protocol (NBP)" in this book for information on NBP.
- Use the
dspCLListenroutine to cause the connection listener to wait for an open-
connection request. Because thedspCLListenroutine does not complete execution until it receives a connection request, you should call this routine asynchronously.
You can specify a value for thefilterAddressparameter to restrict the network number, node ID, or socket number from which you will accept an open-connection request.When the
dspCLListenroutine receives an open-connection request that meets
the restrictions of thefilterAddressparameter, it returns anoErrresult code
(if you executed the routine asynchronously, it places anoErrresult code in theioResultparameter) and places values in the parameter block for theremoteCID,remoteAddress,sendSeq,sendWindow, andattnSendSeqparameters.- If you want to open the connection, call the
dspInitroutine to establish a connection end. You can use any available socket on the node for the connection end, including the socket that you used for the connection listener. Because a single socket can have more than one CCB connected with it, the socket can function simultaneously as a connection end and a connection listener.You can check the address of the remote socket to determine if it meets your criteria for a connection end. Although the
filterAddressparameter to thedspCLListenroutine provides some screening of socket addresses, it cannot check for network number ranges, for example, or for a specific set of socket numbers. If for some reason you want to deny the connection request, call thedspDenyroutine, specifying the CCB of the connection listener in theccbRefNumparameter. Because thedspCLListenroutine completes execution when it receives an open-connection request, you must return to step 5 to wait for another connection request.- Call the
dspOpenroutine to open the connection. Specify the valueocAcceptfor theocModeparameter and specify in theccbRefNumparameter the reference number
of the CCB for the connection end that you want to use. When you call thedspOpenroutine, you must provide the values returned by thedspCLListenroutine for
theremoteCID,remoteAddress,sendSeq,sendWindow, andattnSendSeqparameters.You can poll the state field in the CCB to determine when the connection is open. Alternatively, you can check the result code for the
dspOpenroutine when the routine completes execution. If the routine returns thenoErrresult code, then the connection is open.- You can now send and receive data and attention messages over the connection, as described in "Opening and Maintaining an ADSP Connection" beginning on page 5-13. When you are ready to close the connection, you can use the
dspCloseordspRemoveroutine, both of which are also described in the section "Creating and Using a Connection Control Block."- When you are finished using the connection listener, you can use the
dspCLRemoveroutine to eliminate it. Once you have called thedspCLRemoveroutine, you can release the memory you allocated for the connection listener's CCB.
dspCLInitroutine to establish a connection listener, uses NBP to register the name of the connection end on the internet, and uses thedspCLListenroutine to wait for a connection request. When the routine receives a connection request, it calls thedspOpenroutine to complete the connection.Listing 5-2 Using ADSP to establish and use a connection listener
VAR dspCCBPtr: TPCCB; myDSPPBPtr: DSPPBPtr; myMPPPBPtr: MPPPBPtr; myNTEName: NamesTableEntry; drvrRefNum: Integer; mppRefNum: Integer; connRefNum: Integer; myErr: OSErr; BEGIN myErr := OpenDriver('.MPP', mppRefNum); {open .MPP driver} IF myErr <> noErr THEN DoErr(myErr); {check and handle error} myErr := OpenDriver('.DSP', drvrRefNum); {open .DSP driver} IF myErr <> noErr THEN DoErr(myErr); {check and handle error} {Allocate memory for data buffers.} dspCCBPtr := TPCCB(NewPtr(SizeOf(TRCCB))); myDSPPBPtr := DSPPBPtr(NewPtr(SizeOf(DSPParamBlock))); myMPPPBPtr := MPPPBPtr(NewPtr(SizeOf(MPPParamBlock))); WITH myDSPPBPtr^ DO {set up dspCLInit parameters} BEGIN ioCRefNum := drvrRefNum; {ADSP driver ref num} csCode := dspCLInit; ccbPtr := dspCCBPtr; {pointer to CCB} localSocket := 0; {local socket number} END; myErr := PBControl(ParmBlkPtr(myDSPPBPtr), FALSE); {establish a connection listener} IF myErr <> noErr THEN DoErr(myErr); {check and handle error} connRefNum := myDSPPBPtr^.ccbRefNum; {save CCB ref num for later} NBPSetNTE(@myNTEName, 'The Object', 'The Type', '*', myDSPPBPtr^.localSocket); {set up NBP names table entry} WITH myMPPPBPtr^ DO {set up PRegisterName parameters} BEGIN interval := 7; {retransmit every 7*8=56 ticks } count := 3; { and retry 3 times} entityPtr := @myNTEname; {name to register} verifyFlag := 1; {verify this name} END; myErr := PRegisterName(myMPPPBPtr, FALSE); {register this name} IF myErr <> noErr THEN DoErr(myErr); {check and handle error} WITH myDSPPBPtr^ DO {set up dspCLListen parameters} BEGIN ioCRefNum := drvrRefNum; {ADSP driver ref num} csCode := dspCLListen; ccbRefNum := connRefNum; {connection ref num} filterAddress := AddrBlock(0); {connect with anybody} END; myErr := PBControl(ParmBlkPtr(myDSPPBPtr), TRUE); {listen for connection requests} WHILE myDSPPBPtr^.ioResult = 1 DO BEGIN {Return control to user while waiting for a connection } { request.} GoDoSomething; END; IF myErr <> noErr THEN DoErr(myErr); {check and handle error} WITH myDSPPBPtr^ DO {set up dspInit parameters} BEGIN ioCRefNum := drvrRefNum; {ADSP driver ref num} csCode := dspInit; ccbPtr := @dspCCB; {pointer to CCB} userRoutine := @myConnectionEvtUserRoutine; sendQSize := qSize; {size of send queue} sendQueue := dspSendQPtr; {send-queue buffer} recvQSize := qSize; {size of receive queue} recvQueue := dspRecvQPtr; {receive-queue buffer} attnPtr := dspAttnBufPtr; {receive-attention buffer} localSocket := 0; {let ADSP assign socket} END; dspCCB.myA5 := SetCurrentA5; {save A5 for the user routine} {Establish a connection end.} myErr := PBControl(ParmBlkPtr(myDSPPBPtr), FALSE); IF myErr <> noErr THEN DoErr(myErr); {check and handle error} connRefNum := myDSPPBPtr^.ccbRefNum; {save CCB ref num for later} {You received a connection request: now open a connection. } { The dspCLListen call has returned values into the } { remoteCID, remoteAddress, sendSeq, sendWindow, } { and attnSendSeq fields of the parameter block.} WITH myDSPPBPtr^ DO {set up dspOpen parameters} BEGIN ioCRefNum := drvrRefNum; {ADSP driver ref num} csCode := dspOpen; ccbRefNum := connRefNum; {connection ref num} ocMode := ocAccept; {open connection mode} ocInterval := 0; {use default retry interval} ocMaximum := 0; {use default retry maximum} END; myErr := PBControl(ParmBlkPtr(myDSPPBPtr), FALSE); {open a connection} IF myErr <> noErr THEN DoErr(myErr) {check and handle error} END; {MyCLADSP}