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 / CTCPDriver.cp < prev    next >
Encoding:
Text File  |  1994-07-03  |  11.4 KB  |  512 lines

  1. /*
  2. ** CTCPDriver.cp
  3. **
  4. **    TurboTCP support library
  5. **    TCP driver interface class
  6. **
  7. **    Copyright © 1993-94, FrostByte Design / Eric Scouten
  8. **
  9. */
  10.  
  11. #include "CTCPDriver.h"
  12.  
  13. #include "CApplication.h"
  14. #include "CBartender.h"
  15. #include "CDLOGDirector.h"
  16. #include "CPtrArray.h"
  17. #include "CVoidPtrArrayIterator.h"
  18.  
  19. #include <GetMyIPAddr.h>
  20.  
  21. #include "CTCPApplication.h"
  22. #include "CTCPAsyncCall.h"
  23. #include "CTCPStream.h"
  24. #include "CTCPResolverCall.h"
  25.  
  26.  
  27. // resource definitions
  28.  
  29. #define DLOG_TCPDelayedQuit    23010
  30.  
  31.  
  32. // TCL global variables
  33.  
  34. extern CApplication*    gApplication;
  35. extern CBartender*        gBartender;
  36.  
  37.  
  38. // CTCPDriver static variables
  39.  
  40. CTCPDriver*            CTCPDriver::gTCPDriver = NULL;
  41.  
  42.  
  43. // declare special list classes used here
  44.  
  45. #ifndef TCL_NO_TEMPLATES
  46.     class CTCPStreamList : public CPtrArray<CTCPStream> {};
  47.     class CTCPResolverCallList : public CPtrArray<CTCPResolverCall> {};
  48. #else
  49.     CW_Decl_PtrArray(CTCPStream)
  50.     CW_Decl_PtrArray(CTCPResolverCall)
  51. #endif
  52.  
  53.  
  54. //______________________________________________________________________
  55. //
  56. //    All routines are private interfaces for the use of TurboTCP classes ONLY!
  57. //    They are subject to change in future versions. Be forewarned!
  58. //
  59. //______________________________________________________________________
  60.  
  61.  
  62. //    —— contructor/destructor ——
  63.  
  64. /*______________________________________________________________________
  65. **
  66. ** constructor
  67. **
  68. **    Clear the TCP driver object. Check to see if MacTCP is open. Optionally, opens TCP
  69. **    resolver.
  70. **
  71. **        doOpenResolver (Boolean):    TRUE to open TCP resolver as well
  72. **
  73. */
  74.  
  75. CTCPDriver::CTCPDriver()
  76.  
  77. {
  78.  
  79.     // clear variables
  80.     
  81.     hasMacTCP = FALSE;
  82.     hasResolver = FALSE;
  83.     myTCPRefNum = 0;
  84.     myIPAddress = 0L;
  85.     gTCPDriver = this;
  86.     activeStreamList = NULL;
  87.     activeResolverList = NULL;
  88.  
  89.     
  90.     // if on PowerPC, get completion procedure (which is 68K code)
  91.  
  92.     CTCPAsyncCall::GetCompletionProc();
  93.     
  94.     
  95.     // clear asynch processing queue
  96.     
  97.     asyncQueue.qFlags = 0;
  98.     asyncQueue.qHead = NULL;
  99.     asyncQueue.qTail = NULL;
  100.  
  101.  
  102.     // create the active TCP/DNR call lists
  103.     
  104.     activeStreamList = new CTCPStreamList;
  105.     activeResolverList = new CTCPResolverCallList;
  106.  
  107. }
  108.  
  109.  
  110. /*______________________________________________________________________
  111. **
  112. ** Dispose
  113. **
  114. **    Dispose of this object and any lingering TCP async call objects or TCP stream objects.
  115. **    It is CRITICAL that any lingering TCP streams be closed, released, and disposed;
  116. **    otherwise MacTCP is *guaranteed* to crash the machine when the next app launches.
  117. **    If the resolver is open, wait until all resolver queries have been cancelled.
  118. **
  119. **    If at least one second elapses between the start of this routine and the end, flash a
  120. **    dialog box to indicate the reason for the delay.
  121. **
  122. **    The ‘Dispose’ method is retained in TCL 2.0 because the driver object may need to
  123. **    delay its destruction.
  124. **
  125. */
  126.  
  127. void CTCPDriver::Dispose()
  128.  
  129. {
  130.     register long        i;
  131.     void*            theStreamPtr;
  132.     CTCPStream*        theStream;
  133.     unsigned long        startTickCount;
  134.     unsigned long        theTime;
  135.     CDLOGDirector*    theDialog = NULL;
  136.  
  137.  
  138.     
  139.     // cancel outstanding DNR calls & close resolver
  140.     
  141.     if (hasResolver)
  142.         CTCPResolverCall::CloseResolver();
  143.  
  144.  
  145.     // kill any lingering streams
  146.     
  147.     if (activeStreamList) {
  148.         CVoidPtrArrayIterator streams(activeStreamList, kStartAtBeginning);
  149.             
  150. //        CTCPStreamIterator streams(activeStreamList, kStartAtBeginning);
  151. //        #ifndef TCL_NO_TEMPLATES
  152. //            CPtrArrayIterator<CTCPStream> streams(activeStreamList, kStartAtBeginning);
  153. //        #else
  154. //            CPtrArrayIterator_CTCPStream streams(activeStreamList, kStartAtBeginning);
  155. //        #endif
  156.         
  157.         while (streams.Next(theStreamPtr)) {
  158.             theStream = (CTCPStream*&) theStreamPtr;
  159.             theStream->PostponeDispose();
  160.         }
  161.     }
  162.  
  163.  
  164.     // wait for TCP to be done with everything
  165.     
  166.     GetDateTime(&startTickCount);
  167.     gBartender->DisableMenuBar();                    // disable all menus
  168.     
  169.     while (!activeStreamList->IsEmpty()) {
  170.  
  171.  
  172.         // do a private event loop & toss up a dialog if it takes more than 2 seconds
  173.         
  174.         GetDateTime(&theTime);
  175.         if ((theDialog == NULL) && (theTime - startTickCount >= 2)) {
  176.             theDialog = new CDLOGDirector(DLOG_TCPDelayedQuit, gApplication);
  177.             theDialog->BeginDialog();
  178.         }
  179.  
  180.                 
  181.         // wait for TCP completions & terminations
  182.         
  183.         gApplication->Process1Event();
  184.  
  185.     }
  186.     
  187.     
  188.     // get rid of dialog box (if there was one)
  189.     
  190.     ForgetObject(theDialog);
  191.  
  192.     
  193.     // dispose all the objects
  194.     
  195.     ForgetObject(activeStreamList);
  196.     ForgetObject(activeResolverList);
  197.     delete this;
  198.  
  199. }
  200.  
  201.  
  202. //    —— event handling ——
  203.  
  204. /*______________________________________________________________________
  205. **
  206. ** ProcessOneNetEvent
  207. **
  208. **    Respond to all delayed TCP notifications, completions, disposals. This routine should be
  209. **    hooked into the application’s event loop or some very frequently called routine.
  210. **
  211. **        return (Boolean):    TRUE if there are more asynchronous events in the queue
  212. **
  213. */
  214.  
  215. Boolean CTCPDriver::ProcessOneNetEvent()
  216.  
  217. {
  218.     void*            theAsyncObject;
  219.     TurboTCPQElemPtr    theAsyncEntry;
  220.     CTCPAsyncCall*    theAsyncCall;
  221.     CTCPResolverCall*    theResolverCall;
  222.     CTCPStream*        theStream;
  223.     
  224.     
  225.     // if no events, quit now
  226.  
  227.     if (asyncQueue.qHead == NULL)
  228.         return FALSE;
  229.  
  230.  
  231.     // figure out what object caused the notification
  232.  
  233.     theAsyncEntry = (TurboTCPQElemPtr) asyncQueue.qHead;
  234.     theAsyncObject = (CCollaborator*) theAsyncEntry->qSelfLink;
  235.  
  236.  
  237.     // remove it from the queue (just in case the event processing fails)
  238.     
  239.     Dequeue((QElemPtr) theAsyncEntry, &asyncQueue);
  240.     
  241.     
  242.     // process the event
  243.  
  244.     switch (theAsyncEntry->qType) {
  245.         case asyncCall:
  246.             theAsyncCall = (CTCPAsyncCall*) theAsyncObject;
  247.             if (theAsyncCall)
  248.                 theAsyncCall ->ProcessCompletion();
  249.             break;
  250.         case resolverCall:
  251.             theResolverCall = (CTCPResolverCall*) theAsyncObject;
  252.             if (theResolverCall)
  253.                 theResolverCall->ProcessNotify();
  254.             break;
  255.         case notifyStream:
  256.             theStream = (CTCPStream*) theAsyncObject;
  257.             if (theStream)
  258.                 theStream->ProcessNotify();
  259.             break;
  260.         case disposeStream:
  261.             theStream = (CTCPStream*) theAsyncObject;
  262.             if (theStream)
  263.                 theStream->Dispose();
  264.             break;
  265.  
  266.     }    // switch
  267.  
  268.     
  269.     // tell caller whether there’s another call
  270.     
  271.     return (asyncQueue.qHead != NULL);
  272.  
  273. }
  274.  
  275.  
  276. //    —— TCP verification routines ——
  277.  
  278. /*______________________________________________________________________
  279. **
  280. ** GetIPAddr (public static method)
  281. **
  282. **    Returns the current local IP address, if available. Fails with “noTCPError” error if
  283. **    MacTCP is not installed.
  284. **
  285. **        return (ip_addr):     current IP address
  286. **
  287. */
  288.  
  289. ip_addr CTCPDriver::GetIPAddr()
  290.  
  291. {
  292.     if (!(gTCPDriver->hasMacTCP))
  293.         FailOSErr(noTCPError);
  294.     return gTCPDriver->myIPAddress;
  295. }
  296.  
  297.  
  298. /*______________________________________________________________________
  299. **
  300. ** CheckTCPDriver
  301. **
  302. **    Check to see if the MacTCP driver is present. Should be done before opening each new
  303. **    connection (built into CTCPStream). If TCP driver is present, updates the current IP address.
  304. **
  305. **        return (Boolean):    TRUE if MacTCP driver is present
  306. **
  307. */
  308.  
  309. Boolean CTCPDriver::CheckTCPDriver()
  310.  
  311. {
  312.     ParamBlockRec    theParamBlock;
  313.     unsigned char    theName[6] = "\p.IPP";        // MacTCP driver name
  314.  
  315.  
  316.     // if TCP not already confirmed, look for it
  317.     
  318.     if (!hasMacTCP) {
  319.         theParamBlock.ioParam.ioNamePtr = (StringPtr) &theName;
  320.         theParamBlock.ioParam.ioPermssn = fsCurPerm;
  321.         if ((short) PBOpenSync(&theParamBlock) == 0) {
  322.             myTCPRefNum = theParamBlock.ioParam.ioRefNum;
  323.             hasMacTCP = TRUE;
  324.         }
  325.     }
  326.  
  327.  
  328.     /*
  329.     **    If TCP driver available, get the IP address. This is done *each* time a new stream
  330.     **    is created because the address might have changed. (This could happen on a machine
  331.     **    connected by modem & SLIP, if the user hangs up the modem and re-dials the
  332.     **    SLIP server without quitting the program.)
  333.     */
  334.     
  335.     FetchIPAddr();
  336.     return hasMacTCP;
  337.  
  338. }
  339.  
  340.  
  341. /*______________________________________________________________________
  342. **
  343. ** CheckResolver
  344. **
  345. **    Check to see if the MacTCP DNR code segment is available. If it isn’t, use the OpenResolver
  346. **    call to make it available.
  347. **
  348. **        return (Boolean):    TRUE if TCP resovler is present
  349. **
  350. */
  351.  
  352. Boolean CTCPDriver::CheckResolver()
  353.  
  354. {
  355.  
  356.     TRY {
  357.         CTCPResolverCall::OpenResolver();
  358.         hasResolver = TRUE;
  359.     }
  360.     CATCH {
  361.         hasResolver = FALSE;
  362.         NO_PROPAGATE;
  363.     }
  364.     ENDTRY;
  365.     return hasResolver;
  366.  
  367. }
  368.  
  369.  
  370. /*______________________________________________________________________
  371. **
  372. ** GetTCPRefNum
  373. **
  374. **    Returns the Device Manager reference number for MacTCP, if available. Fails with
  375. **    “noTCPError” error if not available.
  376. **
  377. **        return (short):     MacTCP driver refnum
  378. **
  379. */
  380.  
  381. short CTCPDriver::GetTCPRefNum()
  382.  
  383. {
  384.     if (!(gTCPDriver->hasMacTCP))
  385.         FailOSErr(noTCPError);
  386.     return gTCPDriver->myTCPRefNum;
  387. }
  388.  
  389.  
  390. /*______________________________________________________________________
  391. **
  392. ** FetchIPAddr (protected method)
  393. **
  394. **    Retrieve the local host’s IP address. Does nothing if MacTCP is not available. Stores the
  395. **    new address in the local field myIPAddress, which can be retrieved with the
  396. **    GetIPAddr() method.
  397. **
  398. */
  399.  
  400. void CTCPDriver::FetchIPAddr()
  401.  
  402. {
  403.     struct GetAddrParamBlock theIPParamBlock;
  404.  
  405.     myIPAddress = 0L;
  406.  
  407.     if (hasMacTCP) {
  408.         theIPParamBlock.csCode = ipctlGetAddr;
  409.         theIPParamBlock.ioCRefNum = myTCPRefNum;
  410.         PBControlSync((ParmBlkPtr) &theIPParamBlock);
  411.         if (theIPParamBlock.ioResult == noErr)
  412.             myIPAddress = theIPParamBlock.ourAddress;
  413.     }
  414. }
  415.  
  416.  
  417. //    —— tracking active streams/resolvers ——
  418.  
  419. /*______________________________________________________________________
  420. **
  421. ** RegisterActiveStream
  422. **
  423. **    Add a DNR resolver call to the list of active TCP streams. The driver object uses this
  424. **    information to ensure that all resolver calls are closed and terminated before the
  425. **    application quits.
  426. **
  427. **        theStream (CTCPStream*):    the stream to register
  428. **
  429. */
  430.  
  431. void CTCPDriver::RegisterActiveStream(CTCPStream* theStream)
  432.  
  433. {
  434.     activeStreamList->Append(theStream);
  435. }
  436.  
  437.  
  438. /*______________________________________________________________________
  439. **
  440. ** RegisterActiveResolver
  441. **
  442. **    Add a DNR resolver call to the list of active TCP streams. The driver object uses this
  443. **    information to ensure that all resolver calls are closed and terminated before the
  444. **    application quits.
  445. **
  446. **        theResolver (CTCPResolverCall*):    the resolver call to register
  447. **
  448. */
  449.  
  450. void CTCPDriver::RegisterActiveResolver(CTCPResolverCall* theResolver)
  451.  
  452. {
  453.     if (CheckResolverLimit())                        // disallow 9th DNR call
  454.         FailOSErr(resolverBusy);
  455.     activeResolverList->Append(theResolver);
  456. }
  457.  
  458.  
  459. /*______________________________________________________________________
  460. **
  461. ** RemoveActiveStream
  462. **
  463. **    Remove a TCP stream from the list of active TCP streams. This message indicates that
  464. **    MacTCP is no longer dependent on the memory structure for the stream.
  465. **
  466. **        theStream (CTCPStream*):    the stream to remove
  467. **
  468. */
  469.  
  470. void CTCPDriver::RemoveActiveStream(CTCPStream* theStream)
  471.  
  472. {
  473.     if (activeStreamList)                        // just in case this is called during shutdown
  474.         activeStreamList->Remove(theStream);
  475. }
  476.  
  477.  
  478. /*______________________________________________________________________
  479. **
  480. ** RemoveActiveResolver
  481. **
  482. **    Remove a DNR resolver call from the list of active calls. This message indicates that
  483. **    the MacTCP DNR is no longer dependent on the memory structure for the call.
  484. **
  485. **        theResolver (CTCPResolverCall*):    the resolver call to remove
  486. **
  487. */
  488.  
  489. void CTCPDriver::RemoveActiveResolver(CTCPResolverCall* theResolver)
  490.  
  491. {
  492.     if (activeResolverList)                        // just in case this is called during shutdown
  493.         activeResolverList->Remove(theResolver);
  494. }
  495.  
  496.  
  497. /*______________________________________________________________________
  498. **
  499. ** CheckResolverLimit
  500. **
  501. **    Ensure that the DNR’s limit of 8 calls is not violated.
  502. **
  503. **        return (Boolean):    TRUE if too many calls have been issued
  504. **
  505. */
  506.  
  507. Boolean CTCPDriver::CheckResolverLimit()
  508.  
  509. {
  510.     return (activeResolverList->numItems) >= maxResolverCalls;
  511. }
  512.