home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Libraries / TurboTCP 2.0.1 / TurboTCP source / CTCPAsyncCall.cp < prev    next >
Encoding:
Text File  |  1994-11-22  |  9.7 KB  |  367 lines  |  [TEXT/MPCC]

  1. /*
  2. ** CTCPAsyncCall.cp
  3. **
  4. **    TurboTCP support library
  5. **    TCP asynchronous call class
  6. **
  7. **    Copyright © 1993-94, FrostByte Design / Eric Scouten
  8. **
  9. */
  10.  
  11.  
  12. #include "CTCPAsyncCall.h"
  13.  
  14. #include "Global.h"
  15. #include "TCL.h"
  16.  
  17. #include "CTCPDriver.h"
  18. #include "CTCPStream.h"
  19.  
  20. #ifndef __MACTCP__                // for compatibility with old Univ Headers
  21. #define TCPIOCompletionUPP TCPIOCompletionProcPtr
  22. #endif
  23.  
  24.  
  25. //    —— UPP for completion procedure (corrects a bug in <TCPPB.h>) ——
  26.  
  27. #if GENERATINGCFM
  28.  
  29. enum {
  30.     TTCP_uppTCPIOCompletionProcInfo = kRegisterBased            // •• was kCStackBased in <TCPPB.h>
  31.          | REGISTER_ROUTINE_PARAMETER(1, kRegisterA0, SIZE_CODE(sizeof(struct TCPiopb*)))
  32. };
  33.  
  34. UniversalProcPtr CTCPAsyncCall::completionProcUPP = NULL;
  35.  
  36. #endif
  37.  
  38.  
  39. TCL_DEFINE_CLASS_M0(CTCPAsyncCall);
  40.  
  41.  
  42. //    —— initiate, process TCP call ——
  43.  
  44. /*______________________________________________________________________
  45. **
  46. ** DoAsyncCall (private methods)
  47. **
  48. **    Fills in the standard parameters for a TCP Device Manager call and executes the call.
  49. **
  50. **        theCsCode (short):                TCP operation code
  51. **        theParamBlockPtr (TCPiopb*):        parameter block for TCP call
  52. **
  53. **        return (OSErr):                    result code
  54. **
  55. */
  56.  
  57. OSErr CTCPAsyncCall::DoAsyncCall(short theCsCode, TCPiopb* theParamBlockPtr)
  58.  
  59. {
  60.     BlockMove(theParamBlockPtr, &itsiopb.itsParamBlock, sizeof (TCPiopb));
  61.     return DoAsyncCall(theCsCode);
  62. }
  63.  
  64. OSErr CTCPAsyncCall::DoAsyncCall(short theCsCode)        // version for use by DispatchNoCopyRcv
  65.  
  66. {
  67.     #if GENERATINGCFM                                // seems to be buggy here…
  68.         itsiopb.itsParamBlock.ioCompletion = (TCPIOCompletionUPP) completionProcUPP;
  69.     #else
  70.         itsiopb.itsParamBlock.ioCompletion = (TCPIOCompletionUPP) CompletionProc;
  71.     #endif
  72.     itsiopb.itsParamBlock.ioCRefNum = (CTCPDriver::gTCPDriver)->GetTCPRefNum();
  73.     itsiopb.itsParamBlock.csCode = theCsCode;
  74.     itsiopb.itsQueue = &((CTCPDriver::gTCPDriver)->asyncQueue);
  75.     PBControlAsync((ParmBlkPtr) &itsiopb.itsParamBlock);
  76.     return itsiopb.itsParamBlock.ioResult;
  77. }
  78.  
  79.  
  80. /*______________________________________________________________________
  81. **
  82. ** ProcessCompletion (private method)
  83. **
  84. **    Respond to completion of this TCP call and all calls following it in the completion loop.
  85. **    After running through this loop, disposes of the call object, UNLESS it was a successful
  86. **    auto-receive call.
  87. **
  88. */
  89.  
  90. void CTCPAsyncCall::ProcessCompletion()
  91.  
  92. {
  93.     Boolean    disposeWhenDone;
  94.  
  95.     
  96.     // dispatch to general completion routine or to optimized routine for no-copy-receive calls
  97.  
  98.     TRY {
  99.         if (itsiopb.itsParamBlock.csCode == TCPNoCopyRcv)
  100.             disposeWhenDone = DispatchNoCopyRcv();
  101.         else
  102.             disposeWhenDone = Dispatch();
  103.         if (disposeWhenDone) {
  104.             itsStream.ProcessAsyncCompletion(this);
  105.             delete this;
  106.         }
  107.     } CATCH {
  108.         itsStream.ProcessAsyncCompletion(this);
  109.         delete this;
  110.     } ENDTRY;
  111.  
  112. }
  113.  
  114.  
  115. /*______________________________________________________________________
  116. **
  117. ** Dispatch (private method)
  118. **
  119. **    Called by ProcessCompletion to report back to the CTCPStream object. Does not dispose
  120. **    of object. Also, does not handle TCPNoCopyRcv commands (see DispatchNoCopyRcv
  121. **    method below).
  122. **
  123. **        return (Boolean):    TRUE to dispose of call object when done
  124. **
  125. */
  126.  
  127. Boolean CTCPAsyncCall::Dispatch()
  128.  
  129. {
  130.     rdsEntry*        RDSPtr;
  131.     wdsEntry*    WDSPtr;
  132.  
  133.     if (itsiopb.itsParamBlock.ioResult) {
  134.  
  135.         // command failed, what was it?
  136.  
  137.         switch (itsiopb.itsParamBlock.csCode) {
  138.  
  139.             case TCPPassiveOpen:
  140.             case TCPActiveOpen:
  141.                 itsStream.HandleOpenFailed(itsiopb.itsParamBlock.ioResult);
  142.                 break;
  143.                 
  144.             case TCPSend:
  145.                 itsStream.HandleSendFailed((wdsEntry*) itsiopb.itsParamBlock.csParam.send.wdsPtr,
  146.                     itsiopb.itsParamBlock.csParam.open.security,
  147.                     itsiopb.itsParamBlock.csParam.open.timeToLive, itsiopb.itsParamBlock.ioResult);
  148.                 break;
  149.  
  150.             case TCPRcv:
  151.                 if (itsiopb.itsParamBlock.ioResult == connectionClosing)
  152.                     break;
  153.             
  154.             case TCPClose:
  155.                 if (itsiopb.itsParamBlock.ioResult == connectionDoesntExist)
  156.                     break;
  157.  
  158.             case TCPRcvBfrReturn:
  159.                 if (itsiopb.itsParamBlock.ioResult == invalidRDS)
  160.                     break;
  161.  
  162.             default:
  163.                 itsStream.HandleTCPError(itsiopb.itsParamBlock.ioResult, itsiopb.itsParamBlock.csCode);
  164.                 break;
  165.  
  166.         }
  167.     }
  168.     else {
  169.  
  170.         // no error, dispatch success — what type of call was this anyway?
  171.  
  172.         switch (itsiopb.itsParamBlock.csCode) {
  173.     
  174.             case TCPPassiveOpen:
  175.             case TCPActiveOpen:
  176.                 itsStream.HandleOpened();
  177.                 itsStream.StartAutoReceive();
  178.                 break;
  179.     
  180.             case TCPSend:
  181.                 WDSPtr = (wdsEntry*) itsiopb.itsParamBlock.csParam.send.wdsPtr;
  182.                 itsStream.HandleDataSent(WDSPtr, itsiopb.itsParamBlock.csParam.open.security,
  183.                     itsiopb.itsParamBlock.csParam.open.timeToLive);
  184.                 break;
  185.  
  186.             case TCPRcv:
  187.                 if (itsiopb.itsParamBlock.csParam.receive.urgentFlag)
  188.                     itsStream.RcvUrgentBegin();
  189.                 if (itsiopb.itsParamBlock.csParam.receive.markFlag)
  190.                     itsStream.RcvUrgentMark();
  191.                 itsStream.HandleDataArrived(itsiopb.itsParamBlock.csParam.receive.rcvBuff,
  192.                                         itsiopb.itsParamBlock.csParam.receive.rcvBuffLen,
  193.                                           itsStream.RcvUrgentStatus());
  194.                 break;
  195.  
  196.             case TCPClose:
  197.                 itsStream.HandleClosed();
  198.                 break;
  199.  
  200.             case TCPRcvBfrReturn:
  201.  
  202.                 // if auto-receiving, re-issue the TCPNoCopyRcv command with same paramters
  203.                 
  204.                 if ((itsiopb.itsParamBlock.csParam.open.options[36]) && (itsStream.hasSessionOpen)) {
  205.                     itsiopb.itsParamBlock.csParam.receive.rdsLength = itsiopb.itsParamBlock.csParam.open.options[36];
  206.                     DoAsyncCall(TCPNoCopyRcv);
  207.                     return FALSE;                // make sure call object stays around
  208.                 }
  209.                 else
  210.                     ForgetPtr(itsiopb.itsParamBlock.csParam.receive.rdsPtr);
  211.                 break;
  212.             
  213.         }    // switch
  214.     }        // if…else
  215.     
  216.     return TRUE;                                // always dispose of call object when done
  217.  
  218. }
  219.  
  220.  
  221. /*______________________________________________________________________
  222. **
  223. ** DispatchNoCopyRcv (private method)
  224. **
  225. **    Optimized routine to handle completion of TCPNoCopyRcv calls.
  226. **
  227. **        return (Boolean):    TRUE to dispose of call object when done
  228. **
  229. */
  230.  
  231. Boolean CTCPAsyncCall::DispatchNoCopyRcv()
  232.  
  233. {
  234.     rdsEntry*        RDSPtr;
  235.  
  236.  
  237.     // respond to error condition
  238.  
  239.     if (itsiopb.itsParamBlock.ioResult) {
  240.         if ((itsiopb.itsParamBlock.ioResult != connectionClosing)
  241.           && (itsiopb.itsParamBlock.ioResult != connectionDoesntExist))
  242.             itsStream.HandleTCPError(itsiopb.itsParamBlock.ioResult, itsiopb.itsParamBlock.csCode);
  243.         ForgetPtr(itsiopb.itsParamBlock.csParam.receive.rdsPtr);
  244.         return TRUE;                            // always dispose when call fails
  245.     }
  246.  
  247.  
  248.     // update urgent flags
  249.  
  250.     if (itsiopb.itsParamBlock.csParam.receive.urgentFlag)
  251.         itsStream.RcvUrgentBegin();
  252.     if (itsiopb.itsParamBlock.csParam.receive.markFlag)
  253.         itsStream.RcvUrgentMark();
  254.  
  255.  
  256.     // run through RDS and process each block of data
  257.  
  258.     RDSPtr = (rdsEntry*) itsiopb.itsParamBlock.csParam.receive.rdsPtr;
  259.     
  260.     while ((*RDSPtr).length) {
  261.         itsStream.HandleDataArrived((*RDSPtr).ptr, (*RDSPtr).length, itsStream.rcvUrgent);
  262.         RDSPtr++;
  263.     }
  264.  
  265.  
  266.     // return the buffers to MacTCP
  267.     
  268.     DoAsyncCall(TCPRcvBfrReturn);
  269.  
  270.  
  271.     // if auto-receiving, the call will be reissued when the BfrReturn call is completed
  272.     
  273.     return FALSE;                // keep call object around
  274.  
  275. }
  276.  
  277.  
  278. /*______________________________________________________________________
  279. **
  280. ** GetCompletionProc (private static method)
  281. **
  282. **    If running on a PowerPC, get the completion procedure resource and build a routine
  283. **    descriptor. Since the completion proc is called frequently from the Device Driver and
  284. **    MacTCP (which are emulated 68K code), we provide a 68K completion proc to avoid
  285. **    the overhead of the mode switch. Therefore, this routine builds a fat routine descriptor
  286. **    containing the 68K and PPC versions. (The 68K version is found in the code resource
  287. **    'Ttcp' 23000. It is the 68K equivalent of the completion procedure below.)
  288. **
  289. **    This routine does nothing in 68K builds (note the #ifdef/#endif that bracket the
  290. **    routine).
  291. **
  292. */
  293.  
  294. void CTCPAsyncCall::GetCompletionProc()
  295.  
  296. {
  297. #ifdef TCL_POWER_PC
  298.  
  299.     Handle    codeHandle;
  300.     Ptr        codeEntry;
  301.  
  302.     codeHandle = GetResource('Ttcp', 23000);
  303.     FailNIL(codeHandle);
  304.     DetachResource(codeHandle);
  305.     codeEntry = *codeHandle;
  306.  
  307.     completionProcUPP = NewFatRoutineDescriptor((ProcPtr) codeEntry, (ProcPtr) &CompletionProc,
  308.                                         TTCP_uppTCPIOCompletionProcInfo);
  309.     FailNIL(completionProcUPP);
  310.  
  311. #endif
  312. }
  313.  
  314.  
  315. //    —— completion procedure ——
  316.  
  317. /*______________________________________________________________________
  318. **
  319. ** CompletionProc (private static method)
  320. **
  321. **    The asynchronous completion routine. Recieves notification that any asynchronous
  322. **    TCP I/O operation has been completed. This routine is used for all TCP calls placed by
  323. **    CTCPAsyncCall::DoAsyncCall.
  324. **
  325. **    Send notification to the TCP driver object that this call has been completed. The driver
  326. **    then queues the call for processing at the next event loop.
  327. **
  328. **    The struct TurboTCPiopb includes a pointer to the CTCPDriver queue so that we don’t
  329. **    need to access application globals in this loop. This improves performance, and
  330. **    also permits us to use a 68K code resource in an otherwise PowerPC environment
  331. **    to avoid the performance hit of mode switches.
  332. **
  333. **    INTERRUPT-LEVEL ROUTINE: Cannot make memory allocations, cannot make
  334. **    synchronous TCP calls, and cannot use the profiler.
  335. **
  336. **        iopb (struct TCPiobp*):    the TCP I/O parameter block
  337. **
  338. */
  339.  
  340. #ifndef TCL_POWER_PC
  341.  
  342. #ifdef __MWERKS__
  343.     #pragma profile off
  344.     #pragma a6frames off
  345. #endif
  346.  
  347. struct TurboTCPiopb* GetTheCall();
  348. #pragma parameter __A0 GetTheCall()
  349. extern struct TurboTCPiopb* GetTheCall() = 0x2048;            // MOVEA.L A0,A0
  350.     // Silly way of working around lack of #pragma parameter for member functions.
  351.  
  352. pascal void CTCPAsyncCall::CompletionProc()
  353. {
  354.     struct TurboTCPiopb* iopb = GetTheCall();
  355.     Enqueue((QElemPtr) &(iopb->itsQElem), iopb->itsQueue);
  356.             // CTCPDriver::ProcessNetEvents will pick this up later
  357. }
  358.  
  359. #else // #ifndef TCL_POWER_PC
  360.  
  361. pascal void CTCPAsyncCall::CompletionProc(struct TurboTCPiopb* iopb)
  362. {
  363.     Enqueue((QElemPtr) &(iopb->itsQElem), iopb->itsQueue);
  364.             // CTCPDriver::ProcessNetEvents will pick this up later
  365. }
  366.  
  367. #endif // #ifndef TCL_POWER_PC