home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 May / macformat-024.iso / Shareware City / Developers / TurboTCP 2.1 / TurboTCP core / CTCPResolverCall.cp < prev    next >
Encoding:
Text File  |  1995-01-06  |  21.6 KB  |  772 lines  |  [TEXT/MMCC]

  1. //
  2. // CTCPResolverCall.cp
  3. //
  4. //    TurboTCP library
  5. //    TCP resolver call class
  6. //
  7. //    Copyright © 1993-95, FrostByte Design / Eric Scouten
  8. //    Some portions adapted from file “dnr.c” Copyright © 1988 by Apple Computer. All rights reserved.
  9. //
  10.  
  11. #include "CTCPResolverCall.h"
  12.  
  13. #include <Folders.h>
  14. #include <GestaltEqu.h>
  15. #include <Traps.h>
  16.  
  17.  
  18. //***********************************************************
  19. //
  20. // Procedure code numbers for DNR code segment
  21. //
  22.  
  23. #define OPENRESOLVER    1L
  24. #define CLOSERESOLVER    2L
  25. #define STRTOADDR        3L
  26. #define ADDRTOSTR        4L
  27. #define ENUMCACHE        5L
  28. #define ADDRTONAME    6L
  29. #define HINFO            7L
  30. #define MXINFO            8L
  31.  
  32.  
  33. //***********************************************************
  34. //
  35. // Class variables
  36. //
  37.  
  38. Handle            CTCPResolverCall::macDNRcode = nil;
  39. UniversalProcPtr    CTCPResolverCall::macDNRentry = nil;
  40. #if TurboTCP_CFM
  41.     ResultUPP        CTCPResolverCall::StrToAddrUPP = NewResultProc(CTCPResolverCall::PostponeStrToAddr);
  42.     ResultUPP        CTCPResolverCall::AddrToNameUPP = NewResultProc(CTCPResolverCall::PostponeAddrToName);
  43.     Result2UPP    CTCPResolverCall::HInfoUPP = NewResult2Proc(CTCPResolverCall::PostponeHInfo);
  44.     Result2UPP    CTCPResolverCall::MXInfoUPP = NewResult2Proc(CTCPResolverCall::PostponeMXInfo);
  45. #endif
  46.  
  47.  
  48. //***********************************************************
  49. //
  50. // Interfaces to TCP DNR (adapted from latest <dnr.c>)
  51. //
  52. //
  53.  
  54. // NOTE: The dnr.c file created for Universal Headers contained an error. All of the selectors
  55. // are treated by the DNR as long values, not short. This has been corrected in TurboTCP.
  56.  
  57. extern "C" {
  58.     typedef OSErr (*OpenResolverProcPtr)(long selector, char* fileName);
  59.     typedef OSErr (*CloseResolverProcPtr)(long selector);
  60.     typedef OSErr (*StrToAddrProcPtr)(long selector, char* hostName, struct hostInfo* rtnStruct,
  61.                                     long resultProc, char* userData);
  62.     typedef OSErr (*AddrToStrProcPtr)(long selector, long address, char* hostName);
  63.     typedef OSErr (*AddrToNameProcPtr)(long selector, unsigned long addr, struct hostInfo* rtnStruct,
  64.                                     long resultProc, char* userData);
  65.     typedef OSErr (*HInfoProcPtr)(long selector, char* hostName, struct returnRec* returnRecPtr,
  66.                                     long resultProc, char* userData);
  67.     typedef OSErr (*MXInfoProcPtr)(long selector, char* hostName, struct returnRec* returnRecPtr,
  68.                                     long resultProc, char* userData);
  69. }
  70.  
  71. #if TurboTCP_CFM
  72.  
  73.     enum {
  74.         uppOpenResolverProcInfo = kCStackBased
  75.              | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  76.              | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  77.              | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char*)))
  78.     };
  79.     enum {
  80.         uppCloseResolverProcInfo = kCStackBased
  81.              | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  82.              | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  83.     };
  84.     enum {
  85.         uppStrToAddrProcInfo = kCStackBased
  86.              | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  87.              | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  88.              | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char*)))
  89.              | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(struct hostInfo*)))
  90.              | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(long)))
  91.              | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char*)))
  92.     };
  93.     enum {
  94.         uppAddrToStrProcInfo = kCStackBased
  95.              | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  96.              | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  97.              | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(unsigned long)))
  98.              | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(char*)))
  99.     };
  100.     enum {
  101.         uppAddrToNameProcInfo = kCStackBased
  102.              | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  103.              | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  104.              | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(unsigned long)))
  105.              | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(struct hostInfo*)))
  106.              | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(long)))
  107.              | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char*)))
  108.     
  109.     };
  110.     enum {
  111.         uppHInfoProcInfo = kCStackBased
  112.              | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  113.              | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  114.              | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char*)))
  115.              | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(struct returnRec*)))
  116.              | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(long)))
  117.              | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char*)))
  118.     
  119.     };
  120.     enum {
  121.         uppMXInfoProcInfo = kCStackBased
  122.              | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  123.              | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  124.              | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char*)))
  125.              | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(struct returnRec*)))
  126.              | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(long)))
  127.              | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char*)))
  128.     
  129.     };
  130.     
  131.     typedef UniversalProcPtr OpenResolverUPP;
  132.     typedef UniversalProcPtr CloseResolverUPP;
  133.     typedef UniversalProcPtr StrToAddrUPP;
  134.     typedef UniversalProcPtr AddrToStrUPP;
  135.     typedef UniversalProcPtr AddrToNameUPP;
  136.     typedef UniversalProcPtr HInfoUPP;
  137.     typedef UniversalProcPtr MXInfoUPP;
  138.     
  139.     #define    CallOpenResolverProc(userRoutine, selector, filename)    \
  140.             CallUniversalProc(userRoutine, uppOpenResolverProcInfo, selector, filename)
  141.     #define    CallCloseResolverProc(userRoutine, selector)    \
  142.             CallUniversalProc(userRoutine, uppCloseResolverProcInfo, selector)
  143.     #define    CallStrToAddrProc(userRoutine, selector, hostName, rtnStruct, resultProc, userData)    \
  144.             CallUniversalProc(userRoutine, uppStrToAddrProcInfo, selector, hostName, rtnStruct, resultProc, userData)
  145.     #define    CallAddrToStrProc(userRoutine, selector, address, hostName)    \
  146.             CallUniversalProc(userRoutine, uppAddrToStrProcInfo, selector, address, hostName)
  147.     #define    CallAddrToNameProc(userRoutine, selector, addr, rtnStruct, resultProc, userData)    \
  148.             CallUniversalProc(userRoutine, uppAddrToNameProcInfo, selector, addr, rtnStruct, resultProc, userData)
  149.     #define    CallHInfoProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)    \
  150.             CallUniversalProc(userRoutine, uppHInfoProcInfo, selector, hostName, returnRecPtr, resultProc, userData)
  151.     #define    CallMXInfoProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)    \
  152.             CallUniversalProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)
  153.  
  154. #else // #if TurboTCP_CFM
  155.  
  156.     typedef OpenResolverProcPtr OpenResolverUPP;
  157.     typedef CloseResolverProcPtr CloseResolverUPP;
  158.     typedef StrToAddrProcPtr StrToAddrUPP;
  159.     typedef AddrToStrProcPtr AddrToStrUPP;
  160.     typedef AddrToNameProcPtr AddrToNameUPP;
  161.     typedef HInfoProcPtr HInfoUPP;
  162.     typedef MXInfoProcPtr MXInfoUPP;
  163.     
  164.     #define    CallOpenResolverProc(userRoutine, selector, filename)    \
  165.             (*((OpenResolverProcPtr) userRoutine))(selector, filename)
  166.     #define    CallCloseResolverProc(userRoutine, selector)    \
  167.             (*((CloseResolverProcPtr) userRoutine))(selector)
  168.     #define    CallStrToAddrProc(userRoutine, selector, hostName, rtnStruct, resultProc, userData)    \
  169.             (*((StrToAddrProcPtr) userRoutine))(selector, hostName, rtnStruct, resultProc, userData)
  170.     #define    CallAddrToStrProc(userRoutine, selector, address, hostName)    \
  171.             (*((AddrToStrProcPtr) userRoutine))(selector, address, hostName)
  172.     #define    CallAddrToNameProc(userRoutine, selector, addr, rtnStruct, resultProc, userData)    \
  173.             (*((AddrToNameProcPtr) userRoutine))(selector, addr, rtnStruct, resultProc, userData)
  174.     #define    CallHInfoProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)    \
  175.             (*((HInfoProcPtr) userRoutine))(selector, hostName, returnRecPtr, resultProc, userData)
  176.     #define    CallMXInfoProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)    \
  177.             (*((MXInfoProcPtr) userRoutine))(selector, hostName, returnRecPtr, resultProc, userData)
  178.  
  179. #endif // #if TurboTCP_CFM … else
  180.  
  181.  
  182. //***********************************************************
  183.  
  184. CTCPResolverCall::CTCPResolverCall
  185.     (CTCPEndpoint& theEndpoint)            // the endpoint that is attached to this resolver
  186.     
  187. : itsEndpoint(&theEndpoint), qEntry(this)
  188.  
  189. {
  190.     inUse = false;
  191.     disposeOnCompletion = false;
  192.     pendingNotify = notifNone;
  193.     qEntry.qType = resolverCall;
  194. }
  195.  
  196.  
  197. //***********************************************************
  198.  
  199. void CTCPResolverCall::Dispose()
  200.  
  201.     // Get rid of the resolver object. If a resolver operation is in progress, will dispose of
  202.     // itself when the current resolver operation is completed. Use Dispose() instead of
  203.     // the destructor since the object may need to remain around for a while.
  204.  
  205. {
  206.     if (inUse)
  207.         disposeOnCompletion = true;
  208.     else
  209.         delete this;
  210. }
  211.  
  212.  
  213. // -- request resolver calls --
  214.  
  215. //***********************************************************
  216.  
  217. void CTCPResolverCall::DoStrToAddr
  218.     (char* theHostName)                // whose IP address do we need?
  219.  
  220.     // Get the IP address of a host named by a DNS or dotted decimal string.
  221.     // Completion is handled by HandleStrToAddr.
  222.  
  223. {
  224.     OSErr theResult;
  225.     
  226.     if (inUse)
  227.         ThrowOSErr_(resolverInUse);
  228.     if (!(CTCPDriver::gTCPDriver)->CheckResolver())
  229.         ThrowOSErr_(noResolverErr);
  230.     
  231.     inUse = true;
  232.     (CTCPDriver::gTCPDriver)->RegisterActiveResolver(this);
  233.     ::BlockMoveData(theHostName, &hostName, 255);
  234.  
  235.     #if TurboTCP_CFM                        // seems to be buggy here…
  236.         theResult = CallStrToAddrProc(macDNRentry, STRTOADDR, (char*) &hostName, &theHostInfo,
  237.                                 (long) StrToAddrUPP, (char*) this);
  238.     #else
  239.         theResult = CallStrToAddrProc(macDNRentry, STRTOADDR, (char*) &hostName, &theHostInfo,
  240.                                 (long) &PostponeStrToAddr, (char*) this);
  241.     #endif
  242.  
  243.  
  244.     // if call was completed immediately (with error or not), process it immediately
  245.     
  246.     if (theResult != cacheFault) {
  247.         inUse = false;
  248.         (CTCPDriver::gTCPDriver)->RemoveActiveResolver(this);
  249.         HandleStrToAddr();
  250.     }
  251. }
  252.  
  253.  
  254. //***********************************************************
  255.  
  256. void CTCPResolverCall::DoAddrToStr    // static method
  257.     (ip_addr    theIPaddr,                // the address to convert
  258.     char*    theString)                // buffer for the completed string (min. 16 chars)
  259.  
  260.     // Convert an IP address to dotted decimal notation. This call can be used while the
  261.     // resolver object is otherwise in use, and is completed immediately.
  262.  
  263. {
  264.     if (!(CTCPDriver::gTCPDriver)->CheckResolver())
  265.         ThrowOSErr_(noResolverErr);
  266.     CallAddrToStrProc(macDNRentry, ADDRTOSTR, theIPaddr, theString);
  267. }
  268.  
  269.  
  270. //***********************************************************
  271.  
  272. void CTCPResolverCall::DoAddrToName
  273.     (ip_addr theIPaddr)                    // the IP address to query
  274.  
  275.     // Get the canonical name of a host as specified by IP address. Completion is handled by
  276.     // HandleAddrToName method.
  277.  
  278. {
  279.     OSErr theResult;
  280.     
  281.     if (inUse)
  282.         ThrowOSErr_(resolverInUse);
  283.     if (!(CTCPDriver::gTCPDriver)->CheckResolver())
  284.         ThrowOSErr_(noResolverErr);
  285.     
  286.     inUse = true;
  287.     (CTCPDriver::gTCPDriver)->RegisterActiveResolver(this);
  288.  
  289.     #if TurboTCP_CFM                            // seems to be buggy here…
  290.         theResult = CallAddrToNameProc(macDNRentry, ADDRTONAME, theIPaddr, &theHostInfo,
  291.                                     (long) AddrToNameUPP, (char*) this);
  292.     #else
  293.         theResult = CallAddrToNameProc(macDNRentry, ADDRTONAME, theIPaddr, &theHostInfo,
  294.                                     (long) &PostponeAddrToName, (char*) this);
  295.     #endif
  296.  
  297.  
  298.     // if call was completed immediately (with error or not), process it immediately
  299.     
  300.     if (theResult != cacheFault) {
  301.         inUse = false;
  302.         (CTCPDriver::gTCPDriver)->RemoveActiveResolver(this);
  303.         HandleAddrToName();
  304.     }
  305. }
  306.  
  307.  
  308. //***********************************************************
  309.  
  310. void CTCPResolverCall::DoHInfo
  311.     (char* theHostName)            // who we askin’ ‘bout anyway?
  312.  
  313.     // Get the CPU type and operating system type of a remote host. Completion is handled by
  314.     // HandleHInfo.
  315.  
  316. {
  317.     OSErr theResult;
  318.     
  319.     if (inUse)
  320.         ThrowOSErr_(resolverInUse);
  321.     if (!(CTCPDriver::gTCPDriver)->CheckResolver())
  322.         ThrowOSErr_(noResolverErr);
  323.     
  324.     inUse = true;
  325.     (CTCPDriver::gTCPDriver)->RegisterActiveResolver(this);
  326.     ::BlockMoveData(theHostName, &hostName, 255);
  327.  
  328.     #if TurbTCP_CFM                            // seems to be buggy here…
  329.         theResult = CallHInfoProc(macDNRentry, HINFO, (char*) &hostName, &theHMXInfo,
  330.                                 (long) HInfoUPP, (char*) this);
  331.     #else
  332.         theResult = CallHInfoProc(macDNRentry, HINFO, (char*) &hostName, &theHMXInfo,
  333.                                 (long) &PostponeHInfo, (char*) this);
  334.     #endif
  335.  
  336.  
  337.     // if call was completed immediately (with error or not), process it immediately
  338.     
  339.     if (theResult != cacheFault) {
  340.         inUse = false;
  341.         (CTCPDriver::gTCPDriver)->RemoveActiveResolver(this);
  342.         HandleHInfo();
  343.     }
  344. }
  345.  
  346.  
  347. //***********************************************************
  348.  
  349. void CTCPResolverCall::DoMXInfo
  350.     (char* theHostName)        // who we askin’ ‘bout anyway?
  351.  
  352.     // Get the mailbox exchange (MX) info of a remote host. Completion is handled by
  353.     // HandleMXInfo.
  354.  
  355. {
  356.     OSErr theResult;
  357.     
  358.     if (inUse)
  359.         ThrowOSErr_(resolverInUse);
  360.     if (!(CTCPDriver::gTCPDriver)->CheckResolver())
  361.         ThrowOSErr_(noResolverErr);
  362.     
  363.     inUse = true;
  364.     (CTCPDriver::gTCPDriver)->RegisterActiveResolver(this);
  365.     ::BlockMoveData(theHostName, &hostName, 255);
  366.     #if TurboTCP_CFM                            // seems to be buggy here…
  367.         theResult = CallMXInfoProc(macDNRentry, MXINFO, (char*) &hostName, &theHMXInfo,
  368.                                 (long) MXInfoUPP, (char*) this);
  369.     #else
  370.         theResult = CallMXInfoProc(macDNRentry, MXINFO, (char*) &hostName, &theHMXInfo,
  371.                                 (long) &PostponeMXInfo, (char*) this);
  372.     #endif
  373.  
  374.  
  375.     // if call was completed immediately (with error or not), process it immediately
  376.     
  377.     if (theResult != cacheFault) {
  378.         inUse = false;
  379.         (CTCPDriver::gTCPDriver)->RemoveActiveResolver(this);
  380.         HandleMXInfo();
  381.     }
  382. }
  383.  
  384.  
  385. // -- respond to completion of resolver calls --
  386.  
  387. //***********************************************************
  388.  
  389. void CTCPResolverCall::ProcessNotify()                // private method
  390.  
  391.     // Handles any notifications passed to the resolver. This routine is free of interrupt-level
  392.     // constraints.
  393.  
  394. {
  395.     // free this resolver object for future use
  396.     
  397.     (CTCPDriver::gTCPDriver)->RemoveActiveResolver(this);
  398.     inUse = false;    
  399.     
  400.  
  401.     // dispatch notification to appropriate routine
  402.     
  403.     switch (pendingNotify) {
  404.         case notifStrToAddr:
  405.             HandleStrToAddr();
  406.             break;
  407.             
  408.         case notifAddrToName:
  409.             HandleAddrToName();
  410.             break;
  411.             
  412.         case notifHInfo:
  413.             HandleHInfo();
  414.             break;
  415.             
  416.         case notifMXInfo:
  417.             HandleMXInfo();
  418.     }
  419.     
  420.     
  421.     // if someone attempted to dispose this earlier, do it now
  422.     
  423.     if (disposeOnCompletion)
  424.         delete this;
  425.     
  426. }
  427.  
  428.  
  429. // -- open/close TCP resolver --
  430.  
  431. //***********************************************************
  432.  
  433. void CTCPResolverCall::OpenResolver()                // private static method
  434.  
  435.     // Find the MacTCP DNR code resource and read it. Save the location of the resolver resource
  436.     // for later use.
  437.  
  438. {
  439.     short    vRefNum;
  440.     short    refnum;
  441.     long        dirID;
  442.     short    fRef;
  443.     OSErr    rc;
  444.     
  445.     
  446.     // is the resolver already there?
  447.     
  448.     if (macDNRentry)
  449.         return;
  450.  
  451.  
  452.     // open the MacTCP driver to get DNR resources
  453.  
  454.     Try_ {
  455.         refnum = OpenTheDNR();
  456.     }
  457.     Catch_(err) {
  458.         DontThrowSame_;                    // ignore failures since the resource may
  459.                                         // have been installed in the System file
  460.                                         // (if running on a Mac 512Ke)
  461.     }
  462.     EndCatch_;
  463.  
  464.  
  465.     // load the DNR resource package
  466.     
  467.     macDNRcode = ::GetIndResource('dnrp', 1);
  468.     ThrowIfNil_(macDNRcode);
  469.     ::DetachResource(macDNRcode);
  470.  
  471.     if (refnum != -1)
  472.         ::CloseResFile(refnum);
  473.  
  474.         
  475.     // lock the DNR resource since it cannot be relocated while opened
  476.  
  477.     ::MoveHHi(macDNRcode);
  478.     ::HLock(macDNRcode);
  479.     macDNRentry = (UniversalProcPtr) *macDNRcode;
  480.  
  481.  
  482.     // check for “hosts” file in System Folder (BRB)
  483.  
  484.     GetSystemFolder(&vRefNum, &dirID);
  485.     rc = ::HOpen(vRefNum, dirID, "\pHosts", fsRdPerm, &fRef);
  486.     switch (rc) {
  487.         case noErr:
  488.             ::FSClose(fRef);
  489.             break;
  490.             
  491.         case fnfErr:
  492.             if ((rc = ::HCreate(vRefNum, dirID, "\pHosts", 'ttxt', 'TEXT')) != noErr)
  493.                 #if TurboTCP_TCL
  494.                     ErrorAlert(rc, SpecifyMsg(1001, 1));
  495.                 #else
  496.                     (void) 0;                        //! TEMPORARY: punt
  497.                 #endif
  498.             break;
  499.             
  500.         default:
  501.             break;
  502.     }
  503.  
  504.  
  505.     // ask the DNR resource to open the resolver
  506.  
  507.     rc = CallOpenResolverProc(macDNRentry, OPENRESOLVER, nil);
  508.                                             // send it a null hosts file name
  509.     if (rc != noErr) {
  510.         ::HUnlock(macDNRcode);                    // problem with open resolver, flush DNR resource
  511.         ::DisposeHandle(macDNRcode);
  512.         macDNRcode = nil;
  513.         macDNRentry = nil;
  514.         ThrowOSErr_(rc);                        // signal failure of DNR
  515.     }
  516.  
  517. }
  518.  
  519.  
  520. //***********************************************************
  521.  
  522. void CTCPResolverCall::CloseResolver()                // private static method
  523.  
  524.     // Shut down the DNR code resource. Does nothing if the resolver was never loaded.
  525.  
  526. {
  527.  
  528.     // ensure that we had a resolver to begin with
  529.     
  530.     if (macDNRentry == nil)
  531.         return;
  532.  
  533.  
  534.     // call CloseResolver function in DNR
  535.  
  536.     CallCloseResolverProc(macDNRentry, CLOSERESOLVER);
  537.  
  538.  
  539.     // release the DNR code resource
  540.  
  541.     ::HUnlock(macDNRcode);
  542.     ::DisposeHandle(macDNRcode);
  543.     macDNRcode = nil;
  544.     macDNRentry = nil;
  545.  
  546. }
  547.  
  548.  
  549. //***********************************************************
  550.  
  551. short CTCPResolverCall::OpenTheDNR()                // private static method
  552.  
  553.     // Search in several places for the MacTCP DNR code resource. Tries the Control Panels
  554.     // folder and the System folder.
  555.     
  556.     // Returns the reference number to resource file.
  557.  
  558. {
  559.     short    refnum;
  560.     short    vRefNum;
  561.     long        dirID;
  562.     
  563.     
  564.     // first search Control Panels for MacTCP 1.1.x
  565.  
  566.     GetCPanelFolder(&vRefNum, &dirID);
  567.     refnum = SearchFolderForDNRP('cdev', 'ztcp', vRefNum, dirID);
  568.     if (refnum != -1)
  569.         return refnum;
  570.     
  571.     
  572.     // next search System Folder for MacTCP 1.0.x
  573.  
  574.     GetSystemFolder(&vRefNum, &dirID);
  575.     refnum = SearchFolderForDNRP('cdev', 'mtcp', vRefNum, dirID);
  576.     if (refnum != -1)
  577.         return refnum;
  578.  
  579.  
  580.     // finally, search Control Panels for MacTCP 1.0.x
  581.  
  582.     GetCPanelFolder(&vRefNum, &dirID);
  583.     refnum = SearchFolderForDNRP('cdev', 'mtcp', vRefNum, dirID);
  584.     if (refnum != -1)
  585.         return refnum;
  586.     
  587.     return -1;
  588.  
  589. }
  590.  
  591.  
  592. //***********************************************************
  593.  
  594. short CTCPResolverCall::SearchFolderForDNRP    // private static method
  595.     (long    targetType,                    // file type that we’re looking for
  596.     long        targetCreator,                    // file creator
  597.     short    vRefNum,                        // volume ID
  598.     long        dirID)                        // directory ID
  599.  
  600.     // Search a folder for files that might contain the 'dnrp' resource.
  601.     // Returns the refnum of the file if found, -1 if not found.
  602.  
  603. {
  604.     HParamBlockRec    fi;
  605.     Str255            filename;
  606.     short            refnum;
  607.     
  608.     
  609.     // initialize our search mechanism
  610.     
  611.     fi.fileParam.ioCompletion = nil;
  612.     fi.fileParam.ioNamePtr = filename;
  613.     fi.fileParam.ioVRefNum = vRefNum;
  614.     fi.fileParam.ioDirID = dirID;
  615.     fi.fileParam.ioFDirIndex = 1;
  616.     
  617.     
  618.     // keep looking till we run out of files
  619.     
  620.     while (::PBHGetFInfoSync(&fi) == noErr) {
  621.     
  622.         // scan the folder for files that match our type & creator
  623.  
  624.         if (fi.fileParam.ioFlFndrInfo.fdType == targetType &&
  625.             fi.fileParam.ioFlFndrInfo.fdCreator == targetCreator) {
  626.  
  627.             // type/creator match, look for the resource
  628.             
  629.             refnum = ::HOpenResFile(vRefNum, dirID, filename, fsRdPerm);
  630.             if (::GetIndResource('dnrp', 1) == nil)
  631.                 ::CloseResFile(refnum);
  632.             else
  633.                 return refnum;
  634.         }
  635.  
  636.         // no match or no resource, try next file in folder
  637.  
  638.         fi.fileParam.ioFDirIndex++;
  639.         fi.fileParam.ioDirID = dirID;                // PBHGetFInfo() clobbers ioDirID
  640.     }
  641.     
  642.     return -1;                                // nothing found
  643.  
  644. }    
  645.  
  646.  
  647. //***********************************************************
  648.  
  649. void CTCPResolverCall::GetSystemFolder    // private static method
  650.     (short*    vRefNumP,                // returns volume ID
  651.     long*    dirIDP)                    // returns directory ID
  652.  
  653.     // Get the ID of the current system folder.
  654.  
  655. {
  656.     SysEnvRec    info;
  657.     long            wdProcID;
  658.     
  659.     ::SysEnvirons(1, &info);
  660.     if (GetWDInfo(info.sysVRefNum, vRefNumP, dirIDP, &wdProcID) != noErr) {
  661.         *vRefNumP = 0;
  662.         *dirIDP = 0;
  663.     }
  664. }
  665.  
  666.  
  667. //***********************************************************
  668.  
  669. void CTCPResolverCall::GetCPanelFolder
  670.     (short*    vRefNumP,                // returns volume ID
  671.     long*    dirIDP)                    // returns directory ID
  672.  
  673.     // Fetch the ID of the current “Control Panels” folder.
  674.  
  675. {
  676.     Boolean    hasFolderMgr = false;
  677.     long        feature;
  678.     
  679.     
  680.     // see if we have the Folder Manager available
  681.      
  682.      #if TurboTCP_TCL
  683.     if (TrapAvailable(_Gestalt))                    // PowerPlant guarantees system 7 & thus Gestalt
  684.     #endif
  685.         if (::Gestalt(gestaltFindFolderAttr, &feature) == noErr)
  686.             hasFolderMgr = true;
  687.  
  688.  
  689.     // if folder manager, use it; else return system folder
  690.         
  691.     if (!hasFolderMgr) {
  692.         GetSystemFolder(vRefNumP, dirIDP);
  693.         return;
  694.     }
  695.     else {
  696.         if (::FindFolder(kOnSystemDisk, kControlPanelFolderType,
  697.                     kDontCreateFolder, vRefNumP, dirIDP) != noErr) {
  698.             *vRefNumP = 0;
  699.             *dirIDP = 0;
  700.         }
  701.     }
  702.  
  703. }
  704.  
  705.  
  706. // -- interrupt-level methods: delay processing for non-interrupt status --
  707.  
  708. #ifndef __MWERKS__
  709.     //#pragma options(!profile)
  710. #else
  711.     #pragma profile off
  712. #endif
  713.  
  714.  
  715. //***********************************************************
  716.  
  717. void CTCPResolverCall::PostponeNotify        // private static method
  718.     (short theNotifType)                    // which resolver call was completed
  719.  
  720.     // Respond to notification that a DNR call was completed. Delays processing of notification
  721.     // until the next net-event call. This method merely logs the kind of notification and adds this
  722.     // resolver to the list of resolvers to be processed next time through the event loop.
  723.  
  724. {
  725.     pendingNotify = theNotifType;
  726.     ::Enqueue((QElemPtr) &qEntry, &((CTCPDriver::gTCPDriver)->asyncQueue));
  727. }
  728.  
  729.  
  730. //***********************************************************
  731. //
  732. // Completion routines
  733. //
  734. //    These methods respond to notification that various MacTCP DNS commands have
  735. //    been completed. They merely call PostponeNotify and defer the processing until later.
  736. //
  737.  
  738. pascal void CTCPResolverCall::PostponeStrToAddr    // private static method
  739.     (struct hostInfo*    hostInfoPtr,                // pointer to the DNR data structure (ignored)
  740.     char*            userDataPtr)                // user data pointer
  741. {
  742.     if (userDataPtr)
  743.         ((CTCPResolverCall*) userDataPtr)->PostponeNotify(notifStrToAddr);
  744. }
  745.  
  746.  
  747. pascal void CTCPResolverCall::PostponeAddrToName    // private static method
  748.     (struct hostInfo*    hostInfoPtr,                // pointer to the DNR data structure (ignored)
  749.     char*            userDataPtr)                // user data pointer
  750. {
  751.     if (userDataPtr)
  752.         ((CTCPResolverCall*) userDataPtr)->PostponeNotify(notifAddrToName);
  753. }
  754.  
  755.  
  756. pascal void CTCPResolverCall::PostponeHInfo            // private static method
  757.     (struct returnRec*    returnRecPtr,                // pointer to the DNR data structure (ignored)
  758.     char*            userDataPtr)                // user data pointer
  759. {
  760.     if (userDataPtr)
  761.         ((CTCPResolverCall*) userDataPtr)->PostponeNotify(notifHInfo);
  762. }
  763.  
  764.  
  765. pascal void CTCPResolverCall::PostponeMXInfo        // private static method
  766.     (struct returnRec*    returnRecPtr,                // pointer to the DNR data structure (ignored)
  767.     char*            userDataPtr)                // user data pointer
  768. {
  769.     if (userDataPtr)
  770.         ((CTCPResolverCall*) userDataPtr)->PostponeNotify(notifMXInfo);
  771. }
  772.