home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / src / turbo-tcp-20b4-cpp.hqx / TurboTCP / TurboTCP source / CTCPAsyncCall.cp < prev    next >
Encoding:
Text File  |  1994-07-03  |  9.6 KB  |  363 lines

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