home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-01-05 | 9.0 KB | 325 lines | [TEXT/MMCC] |
- //
- // CTCPAsyncCall.cp
- //
- // TurboTCP library
- // TCP asynchronous call class
- //
- // Copyright © 1993-95, FrostByte Design / Eric Scouten
- //
-
- #include "CTCPAsyncCall.h"
-
- #include "CTCPDriver.h"
- #include "CTCPStream.h"
-
- #if !TurboTCP_UH2
- #define TCPIOCompletionUPP TCPIOCompletionProc
- #endif
-
-
- //***********************************************************
- //
- // UPP for completion procedure (corrects a bug in <TCPPB.h>)
- //
-
- #if TurboTCP_CFM
- enum {
- TTCP_uppTCPIOCompletionProcInfo = kRegisterBased // •• was kCStackBased in <TCPPB.h>
- | REGISTER_ROUTINE_PARAMETER(1, kRegisterA0, SIZE_CODE(sizeof(struct TCPiopb*)))
- };
- UniversalProcPtr CTCPAsyncCall::completionProcUPP = nil;
- #endif
-
-
- // –– initiate, process TCP call ––
-
- //***********************************************************
-
- OSErr CTCPAsyncCall::DoAsyncCall // private method
- (short theCsCode, // TCP operation code
- TCPiopb* theParamBlockPtr) // parameter block for TCP call
-
- // Fills in the standard parameters for a TCP Device Manager call and executes the call.
- // Returns the result code.
-
- {
- ::BlockMoveData(theParamBlockPtr, &itsiopb.itsParamBlock, sizeof (TCPiopb));
- return DoAsyncCall(theCsCode);
- }
-
- OSErr CTCPAsyncCall::DoAsyncCall // private version for use by DispatchNoCopyRcv
- (short theCsCode) // TCP operation code
-
- {
- #if GENERATINGCFM // seems to be buggy here…
- itsiopb.itsParamBlock.ioCompletion = (TCPIOCompletionUPP) completionProcUPP;
- #else
- itsiopb.itsParamBlock.ioCompletion = (TCPIOCompletionUPP) CompletionProc;
- #endif
- itsiopb.itsParamBlock.ioCRefNum = (CTCPDriver::gTCPDriver)->GetTCPRefNum();
- itsiopb.itsParamBlock.csCode = theCsCode;
- itsiopb.itsQueue = &((CTCPDriver::gTCPDriver)->asyncQueue);
- ::PBControlAsync((ParmBlkPtr) &itsiopb.itsParamBlock);
- return itsiopb.itsParamBlock.ioResult;
- }
-
-
- //***********************************************************
-
- void CTCPAsyncCall::ProcessCompletion()
-
- // Respond to completion of this TCP call and all calls following it in the completion loop.
- // After running through this loop, disposes of the call object, UNLESS it was a successful
- // auto-receive call.
-
- {
- Boolean disposeWhenDone;
-
-
- // dispatch to general completion routine or to optimized routine for no-copy-receive calls
-
- Try_ {
- if (itsiopb.itsParamBlock.csCode == TCPNoCopyRcv)
- disposeWhenDone = DispatchNoCopyRcv();
- else
- disposeWhenDone = Dispatch();
- if (disposeWhenDone) {
- itsStream.ProcessAsyncCompletion(this);
- delete this;
- }
- }
- Catch_(err) {
- itsStream.ProcessAsyncCompletion(this);
- delete this;
- DontThrowSame_;
- }
- EndCatch_;
-
- }
-
- //***********************************************************
-
- Boolean CTCPAsyncCall::Dispatch() // private method
-
- // Called by ProcessCompletion to report back to the CTCPStream object. Does not dispose
- // of object. Also, does not handle TCPNoCopyRcv commands (see DispatchNoCopyRcv
- // method below). Returns true if the call object should be disposed when done.
-
- {
- wdsEntry* WDSPtr;
-
- if (itsiopb.itsParamBlock.ioResult) {
-
- // command failed, what was it?
-
- switch (itsiopb.itsParamBlock.csCode) {
-
- case TCPPassiveOpen:
- case TCPActiveOpen:
- itsStream.HandleOpenFailed(itsiopb.itsParamBlock.ioResult);
- break;
-
- case TCPSend:
- itsStream.HandleSendFailed((wdsEntry*) itsiopb.itsParamBlock.csParam.send.wdsPtr,
- itsiopb.itsParamBlock.csParam.open.security,
- itsiopb.itsParamBlock.csParam.open.timeToLive, itsiopb.itsParamBlock.ioResult);
- break;
-
- case TCPRcv:
- if (itsiopb.itsParamBlock.ioResult == connectionClosing)
- break;
-
- case TCPClose:
- if (itsiopb.itsParamBlock.ioResult == connectionDoesntExist)
- break;
-
- case TCPRcvBfrReturn:
- if (itsiopb.itsParamBlock.ioResult == invalidRDS)
- break;
-
- default:
- itsStream.HandleTCPError(itsiopb.itsParamBlock.ioResult, itsiopb.itsParamBlock.csCode);
- break;
-
- }
- }
- else {
-
- // no error, dispatch success — what type of call was this anyway?
-
- switch (itsiopb.itsParamBlock.csCode) {
-
- case TCPPassiveOpen:
- case TCPActiveOpen:
- itsStream.HandleOpened();
- itsStream.StartAutoReceive();
- break;
-
- case TCPSend:
- WDSPtr = (wdsEntry*) itsiopb.itsParamBlock.csParam.send.wdsPtr;
- itsStream.HandleDataSent(WDSPtr, itsiopb.itsParamBlock.csParam.open.security,
- itsiopb.itsParamBlock.csParam.open.timeToLive);
- break;
-
- case TCPRcv:
- if (itsiopb.itsParamBlock.csParam.receive.urgentFlag)
- itsStream.RcvUrgentBegin();
- if (itsiopb.itsParamBlock.csParam.receive.markFlag)
- itsStream.RcvUrgentMark();
- itsStream.HandleDataArrived(itsiopb.itsParamBlock.csParam.receive.rcvBuff,
- itsiopb.itsParamBlock.csParam.receive.rcvBuffLen,
- itsStream.RcvUrgentStatus());
- break;
-
- case TCPClose:
- itsStream.HandleClosed();
- break;
-
- case TCPRcvBfrReturn:
-
- // if auto-receiving, re-issue the TCPNoCopyRcv command with same paramters
-
- if ((itsiopb.itsParamBlock.csParam.open.options[36]) && (itsStream.hasSessionOpen)) {
- itsiopb.itsParamBlock.csParam.receive.rdsLength = itsiopb.itsParamBlock.csParam.open.options[36];
- DoAsyncCall(TCPNoCopyRcv);
- return false; // make sure call object stays around
- }
- else
- ::DisposePtr(itsiopb.itsParamBlock.csParam.receive.rdsPtr);
- break;
-
- } // switch
- } // if…else
-
- return true; // always dispose of call object when done
-
- }
-
-
- //***********************************************************
-
- Boolean CTCPAsyncCall::DispatchNoCopyRcv() // private method
-
- // Optimized routine to handle completion of TCPNoCopyRcv calls.
- // Returns true if the call object should be disposed when done.
-
- {
- rdsEntry* RDSPtr;
-
-
- // respond to error condition
-
- if (itsiopb.itsParamBlock.ioResult) {
- if ((itsiopb.itsParamBlock.ioResult != connectionClosing)
- && (itsiopb.itsParamBlock.ioResult != connectionDoesntExist))
- itsStream.HandleTCPError(itsiopb.itsParamBlock.ioResult, itsiopb.itsParamBlock.csCode);
- ::DisposePtr(itsiopb.itsParamBlock.csParam.receive.rdsPtr);
- return true; // always dispose when call fails
- }
-
-
- // update urgent flags
-
- if (itsiopb.itsParamBlock.csParam.receive.urgentFlag)
- itsStream.RcvUrgentBegin();
- if (itsiopb.itsParamBlock.csParam.receive.markFlag)
- itsStream.RcvUrgentMark();
-
-
- // run through RDS and process each block of data
-
- RDSPtr = (rdsEntry*) itsiopb.itsParamBlock.csParam.receive.rdsPtr;
-
- while ((*RDSPtr).length) {
- itsStream.HandleDataArrived((*RDSPtr).ptr, (*RDSPtr).length, itsStream.rcvUrgent);
- RDSPtr++;
- }
-
-
- // return the buffers to MacTCP
-
- DoAsyncCall(TCPRcvBfrReturn);
-
-
- // if auto-receiving, the call will be reissued when the BfrReturn call is completed
-
- return false; // keep call object around
-
- }
-
- //***********************************************************
-
- void CTCPAsyncCall::GetCompletionProc() // private static method
-
- // If running on a PowerPC, get the completion procedure resource and build a routine
- // descriptor. Since the completion proc is called frequently from the Device Driver and
- // MacTCP (which are emulated 68K code), we provide a 68K completion proc to avoid
- // the overhead of the mode switch. Therefore, this routine builds a fat routine descriptor
- // containing the 68K and PPC versions. (The 68K version is found in the code resource
- // 'Ttcp' 23000. It is the 68K equivalent of the completion procedure below.)
-
- // This routine does nothing in 68K builds (note the #ifdef/#endif that bracket the
- // routine).
-
- {
- #if TurboTCP_PPC
-
- Handle codeHandle;
- Ptr codeEntry;
-
- codeHandle = ::GetResource('Ttcp', 23000);
- ThrowIfNil_(codeHandle);
- ::DetachResource(codeHandle);
- codeEntry = *codeHandle;
-
- completionProcUPP = ::NewFatRoutineDescriptor((ProcPtr) codeEntry, (ProcPtr) &CompletionProc,
- TTCP_uppTCPIOCompletionProcInfo);
- ThrowIfNil_(completionProcUPP);
-
- #endif
- }
-
-
- //***********************************************************
- //
- // A few silly changes to make our completion routines work.
- //
-
- #if TurboTCP_68K
-
- #ifdef __MWERKS__
- #pragma profile off
- #pragma a6frames off
- #endif
-
- struct TurboTCPiopb* GetTheCall();
- #pragma parameter __A0 GetTheCall()
- extern struct TurboTCPiopb* GetTheCall() = 0x2048; // MOVEA.L A0,A0
-
-
- //***********************************************************
-
- pascal void CTCPAsyncCall::CompletionProc()
-
- // The asynchronous completion routine. Recieves notification that any asynchronous
- // TCP I/O operation has been completed. This routine is used for all TCP calls placed by
- // CTCPAsyncCall::DoAsyncCall.
-
- // Send notification to the TCP driver object that this call has been completed. The driver
- // then queues the call for processing at the next event loop.
-
- // The struct TurboTCPiopb includes a pointer to the CTCPDriver queue so that we don’t
- // need to access application globals in this loop. This improves performance, and
- // also permits us to use a 68K code resource in an otherwise PowerPC environment
- // to avoid the performance hit of mode switches.
-
- // *** Runs at interrupt level. ***
-
- {
- struct TurboTCPiopb* iopb = GetTheCall();
- ::Enqueue((QElemPtr) &(iopb->itsQElem), iopb->itsQueue);
- // CTCPDriver::ProcessNetEvents will pick this up later
- }
-
- #endif // TurboTCP_68K
-