]> git.saurik.com Git - apple/mdnsresponder.git/commitdiff
mDNSResponder-98.tar.gz v98
authorApple <opensource@apple.com>
Fri, 28 Jan 2005 06:07:55 +0000 (06:07 +0000)
committerApple <opensource@apple.com>
Fri, 28 Jan 2005 06:07:55 +0000 (06:07 +0000)
107 files changed:
Clients/DNSServiceBrowser.m
Clients/ExplorerPlugin/About.cpp
Clients/ExplorerPlugin/About.h
Clients/ExplorerPlugin/ExplorerBarWindow.cpp
Clients/ExplorerPlugin/ExplorerBarWindow.h
Clients/ExplorerPlugin/ExplorerPlugin.cpp
Clients/ExplorerPlugin/ExplorerPlugin.h
Clients/ExplorerPlugin/ExplorerPlugin.rc
Clients/ExplorerPlugin/ExplorerPlugin.vcproj
Clients/ExplorerPlugin/ExplorerPluginLocRes.rc [new file with mode: 0755]
Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj [new file with mode: 0755]
Clients/ExplorerPlugin/ExplorerPluginRes.rc [new file with mode: 0755]
Clients/ExplorerPlugin/ExplorerPluginRes.vcproj [new file with mode: 0755]
Clients/ExplorerPlugin/Resource.h
Clients/ExplorerPlugin/res/globe.bmp [new file with mode: 0755]
Clients/ExplorerPlugin/resource_dll.h [new file with mode: 0755]
Clients/ExplorerPlugin/resource_loc_res.h [new file with mode: 0755]
Clients/ExplorerPlugin/resource_res.h [new file with mode: 0755]
Clients/PrinterSetupWizard/FirstPage.cpp
Clients/PrinterSetupWizard/FourthPage.cpp
Clients/PrinterSetupWizard/FourthPage.h
Clients/PrinterSetupWizard/PrinterSetupWizard.rc
Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj
Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp
Clients/PrinterSetupWizard/PrinterSetupWizardApp.h
Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc [new file with mode: 0755]
Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj [new file with mode: 0755]
Clients/PrinterSetupWizard/PrinterSetupWizardRes.rc [new file with mode: 0755]
Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj [new file with mode: 0755]
Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp
Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h
Clients/PrinterSetupWizard/SecondPage.cpp
Clients/PrinterSetupWizard/SecondPage.h
Clients/PrinterSetupWizard/ThirdPage.cpp
Clients/PrinterSetupWizard/ThirdPage.h
Clients/PrinterSetupWizard/UtilTypes.h
Clients/PrinterSetupWizard/res/PrinterSetupWizardLocRes.rc2 [new file with mode: 0755]
Clients/PrinterSetupWizard/res/PrinterSetupWizardRes.rc2 [new file with mode: 0755]
Clients/PrinterSetupWizard/resource.h
Clients/PrinterSetupWizard/resource_exe.h [new file with mode: 0755]
Clients/PrinterSetupWizard/resource_loc_res.h [new file with mode: 0755]
Clients/PrinterSetupWizard/resource_res.h [new file with mode: 0755]
Clients/dns-sd.c
Makefile
mDNSCore/DNSCommon.c
mDNSCore/DNSCommon.h
mDNSCore/DNSDigest.c
mDNSCore/mDNS.c
mDNSCore/mDNSDebug.h
mDNSCore/mDNSEmbeddedAPI.h
mDNSCore/uDNS.c
mDNSCore/uDNS.h
mDNSMacOS9/Mac OS Test Responder.c
mDNSMacOS9/Mac OS Test Searcher.c
mDNSMacOS9/SubTypeTester.c
mDNSMacOS9/mDNSLibrary.c
mDNSMacOS9/mDNSLibraryResources.r
mDNSMacOS9/mDNSMacOS9.c
mDNSMacOSX/LaunchDaemonInfo.plist [new file with mode: 0644]
mDNSMacOSX/daemon.c
mDNSMacOSX/mDNSMacOSX.c
mDNSMacOSX/mDNSMacOSX.h
mDNSMacOSX/mDNSResponder.order [new file with mode: 0644]
mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj
mDNSPosix/Client.c
mDNSPosix/Identify.c
mDNSPosix/Makefile
mDNSPosix/NetMonitor.c
mDNSPosix/PosixDaemon.c
mDNSPosix/ProxyResponder.c
mDNSPosix/Responder.c
mDNSPosix/dnsextd.c
mDNSPosix/mDNSPosix.c
mDNSPosix/mDNSUNP.h
mDNSShared/PlatformCommon.c
mDNSShared/PlatformCommon.h
mDNSShared/dns_sd.h
mDNSShared/dnssd_clientshim.c
mDNSShared/dnssd_clientstub.c
mDNSShared/dnssd_ipc.c
mDNSShared/dnssd_ipc.h
mDNSShared/mDNSDebug.c
mDNSShared/uds_daemon.c
mDNSShared/uds_daemon.h
mDNSVxWorks/mDNSVxWorks.c
mDNSWindows/DLL.NET/dnssd_NET.h
mDNSWindows/DLL.NET/dnssd_NET.rc
mDNSWindows/DLL.NET/dnssd_NET.vcproj
mDNSWindows/DLL/dll.rc
mDNSWindows/DLL/dnssd.vcproj
mDNSWindows/DNSServices/DNSServices.c
mDNSWindows/Java/makefile
mDNSWindows/NSPTool/NSPTool.rc
mDNSWindows/NSPTool/NSPTool.vcproj
mDNSWindows/SystemService/Service.c
mDNSWindows/SystemService/Service.rc
mDNSWindows/SystemService/Service.vcproj
mDNSWindows/WinVersRes.h
mDNSWindows/dDNS.c [new file with mode: 0755]
mDNSWindows/dDNS.h [new file with mode: 0755]
mDNSWindows/isocode.h [new file with mode: 0755]
mDNSWindows/loclibrary.c [new file with mode: 0755]
mDNSWindows/loclibrary.h [new file with mode: 0755]
mDNSWindows/mDNSWin32.c
mDNSWindows/mDNSWin32.h
mDNSWindows/mdnsNSP/mdnsNSP.rc
mDNSWindows/mdnsNSP/mdnsNSP.vcproj

index 30db5a831e2a325c4945fc620774b53fdcf67abe..da427802b04539fa1cf4807622c6a3a95765db51 100755 (executable)
@@ -23,6 +23,9 @@
     Change History (most recent first):
 
 $Log: DNSServiceBrowser.m,v $
+Revision 1.30  2005/01/27 17:46:16  cheshire
+Added comment
+
 Revision 1.29  2004/06/04 20:58:36  cheshire
 Move DNSServiceBrowser from mDNSMacOSX directory to Clients directory
 
@@ -780,7 +783,7 @@ static void QueryRecordReply( DNSServiceRef DNSServiceRef, DNSServiceFlags flags
 /* Remove service from runloop, deallocate service and associated resources */
 {
        if ( fSocketRef != nil) {
-               CFSocketInvalidate( fSocketRef);
+               CFSocketInvalidate( fSocketRef);                // Note: Also closes the underlying socket
                CFRelease( fSocketRef);
        }
 
index 37d3281afb4b178ea21b66c62b6223773bac7889..783a9ced70ef3744c5cd08ac1fa78fcb50f7ddd0 100644 (file)
@@ -4,6 +4,7 @@
 #include "stdafx.h"
 #include "ExplorerPlugin.h"
 #include "About.h"
+#include <DebugServices.h>
 
 
 // CAbout dialog
@@ -34,6 +35,23 @@ END_MESSAGE_MAP()
 
 
 // CAbout message handlers
+BOOL
+CAbout::OnInitDialog()
+{
+       BOOL b = CDialog::OnInitDialog();
+
+       CStatic * control = (CStatic*) GetDlgItem( IDC_ABOUT_BACKGROUND );
+       check( control );
+
+       if ( control )
+       {
+               control->SetBitmap( ::LoadBitmap( GetNonLocalizedResources(), MAKEINTRESOURCE( IDB_ABOUT ) ) );
+       }
+
+       return b;
+}
+
+
 HBRUSH CAbout::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
 { 
        switch (nCtlColor)
index f4d0d7e228309637728ea9eb347876e2035b6476..f25270d69d90fd92eeca7989516e0c159c5f7f01 100644 (file)
@@ -19,6 +19,7 @@ public:
 protected:
        virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
        virtual HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
+       virtual BOOL    OnInitDialog();
        DECLARE_MESSAGE_MAP()
 public:
        CStatic m_componentCtrl;
index beb0b35bf7831c5ae44e328fe44e389ca2013f3f..ea9cdc34c4ec76323f9803a231ec98597364e51d 100644 (file)
     Change History (most recent first):
     
 $Log: ExplorerBarWindow.cpp,v $
+Revision 1.15  2005/01/27 22:38:27  shersche
+add About item to tree list
+
+Revision 1.14  2005/01/25 17:55:39  shersche
+<rdar://problem/3911084> Get bitmaps from non-localizable resource module
+Bug #: 3911084
+
+Revision 1.13  2005/01/06 21:13:09  shersche
+<rdar://problem/3796779> Handle kDNSServiceErr_Firewall return codes
+Bug #: 3796779
+
 Revision 1.12  2004/10/26 00:56:03  cheshire
 Use "#if 0" instead of commenting out code
 
@@ -93,6 +104,7 @@ Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within
 #include       "Resource.h"
 
 #include       "ExplorerBarWindow.h"
+#include       "ExplorerPlugin.h"
 
 // MFC Debugging
 
@@ -122,6 +134,7 @@ static char THIS_FILE[] = __FILE__;
 
 #define        kTXTRecordKeyPath                               "path"
 
+
 #if 0
 #pragma mark == Prototypes ==
 #endif
@@ -195,7 +208,9 @@ int ExplorerBarWindow::OnCreate( LPCREATESTRUCT inCreateStruct )
        mTree.Create( WS_TABSTOP | WS_VISIBLE | WS_CHILD | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_HASLINES | TVS_NOHSCROLL , rect, this, 
                IDC_EXPLORER_TREE );
        
-       
+       s.LoadString( IDS_ABOUT );
+       m_about = mTree.InsertItem( s, 0, 0 );
+
        ServiceHandlerEntry *           e;
        
        // Web Site Handler
@@ -212,7 +227,7 @@ int ExplorerBarWindow::OnCreate( LPCREATESTRUCT inCreateStruct )
        mServiceHandlers.Add( e );
        
        s.LoadString( IDS_WEB_SITES );
-       e->treeItem = mTree.InsertItem( s, 0, 0 );
+       e->treeItem = mTree.InsertItem( s, 1, 1 );
        mTree.Expand( e->treeItem, TVE_EXPAND );
        
        err = DNSServiceBrowse( &e->ref, 0, 0, e->type, NULL, BrowseCallBack, e );
@@ -237,7 +252,7 @@ int ExplorerBarWindow::OnCreate( LPCREATESTRUCT inCreateStruct )
        mServiceHandlers.Add( e );
        
        s.LoadString( IDS_FTP_SITES );
-       e->treeItem = mTree.InsertItem( s, 0, 0 );
+       e->treeItem = mTree.InsertItem( s, 1, 1 );
        mTree.Expand( e->treeItem, TVE_EXPAND );
        
        err = DNSServiceBrowse( &e->ref, 0, 0, e->type, NULL, BrowseCallBack, e );
@@ -248,20 +263,32 @@ int       ExplorerBarWindow::OnCreate( LPCREATESTRUCT inCreateStruct )
 
        m_serviceRefs.push_back(e->ref); 
 
-       m_imageList.Create(16, 16, ILC_COLORDDB, 1, 0);
-       bitmap.LoadBitmap(IDB_LOGO);
-       m_imageList.Add(&bitmap, (CBitmap*) NULL);
+       m_imageList.Create( 16, 16, ILC_COLORDDB, 2, 0);
+       bitmap.Attach( ::LoadBitmap( GetNonLocalizedResources(), MAKEINTRESOURCE( IDB_GLOBE ) ) );
+       m_imageList.Add( &bitmap, (CBitmap*) NULL );
+       bitmap.Detach();
+       bitmap.Attach( ::LoadBitmap( GetNonLocalizedResources(), MAKEINTRESOURCE( IDB_LOGO ) ) );
+       m_imageList.Add( &bitmap, (CBitmap*) NULL );
 
        mTree.SetImageList(&m_imageList, TVSIL_NORMAL);
        
 exit:
 
        // Cannot talk to the mDNSResponder service. Show the error message and exit (with kNoErr so they can see it).
-       if ( err != kNoErr )
+       if ( err )
        {
-               s.LoadString( IDS_MDNSRESPONDER_NOT_AVAILABLE );
+               if ( err == kDNSServiceErr_Firewall )
+               {
+                       s.LoadString( IDS_FIREWALL );
+               }
+               else
+               {
+                       s.LoadString( IDS_MDNSRESPONDER_NOT_AVAILABLE );
+               }
+               
                mTree.DeleteAllItems();
                mTree.InsertItem( s, 0, 0, TVI_ROOT, TVI_LAST );
+               
                err = kNoErr;
        }
 
@@ -331,11 +358,25 @@ void      ExplorerBarWindow::OnDoubleClick( NMHDR *inNMHDR, LRESULT *outResult )
        item = mTree.GetSelectedItem();
        require( item, exit );
        
-       service = reinterpret_cast < ServiceInfo * > ( mTree.GetItemData( item ) );
-       require_quiet( service, exit );
+       // Tell Internet Explorer to go to the URL if it's about item
        
-       err = StartResolve( service );
-       require_noerr( err, exit );
+       if ( item == m_about )
+       {
+               CString url;
+
+               check( mOwner );
+
+               url.LoadString( IDS_ABOUT_URL );
+               mOwner->GoToURL( url );
+       }
+       else
+       {
+               service = reinterpret_cast < ServiceInfo * > ( mTree.GetItemData( item ) );
+               require_quiet( service, exit );
+               
+               err = StartResolve( service );
+               require_noerr( err, exit );
+       }
 
 exit:
        *outResult = 0;
@@ -512,7 +553,7 @@ LONG        ExplorerBarWindow::OnServiceAdd( ServiceInfo * service )
                
                afterItem = ( index > 0 ) ? handler->array[ index - 1 ]->item : TVI_FIRST;
                handler->array.InsertAt( index, service );
-               service->item = mTree.InsertItem( service->displayName, handler->treeItem, afterItem );
+               service->item = mTree.InsertItem( service->displayName, 1, 1, handler->treeItem, afterItem );
                mTree.SetItemData( service->item, (DWORD_PTR) service );
                
                // Make sure the item is visible if this is the first time a service was added.
index afa4e999509379559450b1499a2c25464894a14f..34a33453d5f2e061738493477e9dd34daeb9f886 100644 (file)
@@ -23,6 +23,9 @@
     Change History (most recent first):
     
 $Log: ExplorerBarWindow.h,v $
+Revision 1.6  2005/01/27 22:27:03  shersche
+Add m_about member for "About Rendezvous" tree item
+
 Revision 1.5  2004/07/26 05:47:31  shersche
 use TXTRecord APIs, fix bug in locating service to be removed
 
@@ -295,6 +298,7 @@ class       ExplorerBarWindow : public CWnd
 
                typedef std::list< DNSServiceRef >  ServiceRefList;
                
+               HTREEITEM               m_about;
                ServiceRefList  m_serviceRefs;
                CImageList              m_imageList;
 };
index 5de124db0c86d288a1325f826b44e7d3ea70cc7c..464051abba8c31fc53b5f0c9123297b9aaee3921 100644 (file)
     Change History (most recent first):
     
 $Log: ExplorerPlugin.cpp,v $
+Revision 1.6  2005/01/25 17:56:45  shersche
+<rdar://problem/3911084> Load resource DLLs, get icons and bitmaps from resource DLLs
+Bug #: 3911084
+
 Revision 1.5  2004/09/15 10:33:54  shersche
 <rdar://problem/3721611> Install XP toolbar button (8 bit mask) if running on XP platform, otherwise install 1 bit mask toolbar button
 Bug #: 3721611
@@ -65,6 +69,8 @@ Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within
 #include       "ClassFactory.h"
 #include       "Resource.h"
 
+#include       "loclibrary.h"
+
 // MFC Debugging
 
 #ifdef _DEBUG
@@ -96,6 +102,24 @@ DEBUG_LOCAL void            MFCDLLThreadDetach( HINSTANCE inInstance );
 DEBUG_LOCAL OSStatus   RegisterServer( HINSTANCE inInstance, CLSID inCLSID, LPCTSTR inName );
 DEBUG_LOCAL OSStatus   RegisterCOMCategory( CLSID inCLSID, CATID inCategoryID, BOOL inRegister );
 
+// Stash away pointers to our resource DLLs
+
+static HINSTANCE g_nonLocalizedResources       = NULL;
+static CString  g_nonLocalizedResourcesName;
+static HINSTANCE g_localizedResources          = NULL;
+
+HINSTANCE
+GetNonLocalizedResources()
+{
+       return g_nonLocalizedResources;
+}
+
+HINSTANCE
+GetLocalizedResources()
+{
+       return g_localizedResources;
+}
+
 #if 0
 #pragma mark == Globals ==
 #endif
@@ -266,10 +290,12 @@ exit:
 
 DEBUG_LOCAL OSStatus   MFCDLLProcessAttach( HINSTANCE inInstance )
 {
+       wchar_t                                 resource[MAX_PATH];
        OSStatus                                err;
        _AFX_THREAD_STATE *             threadState;
        AFX_MODULE_STATE *              previousModuleState;
        BOOL                                    ok;
+       int                                             res;
        CWinApp *                               app;
        
        app = NULL;
@@ -286,6 +312,34 @@ DEBUG_LOCAL OSStatus       MFCDLLProcessAttach( HINSTANCE inInstance )
        app = AfxGetApp();
        require_action( ok, exit, err = kNotInitializedErr );
        
+       // Before we load the resources, let's load the error string
+
+       // errorMessage.LoadString( IDS_REINSTALL );
+       // errorCaption.LoadString( IDS_REINSTALL_CAPTION );
+
+       // Load Resources
+
+       res = PathForResource( inInstance, L"ExplorerPluginResources.dll", resource, MAX_PATH );
+
+       err = translate_errno( res != 0, kUnknownErr, kUnknownErr );
+       require_noerr( err, exit );
+
+       g_nonLocalizedResources = LoadLibrary( resource );
+       translate_errno( g_nonLocalizedResources, GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
+       g_nonLocalizedResourcesName = resource;
+
+       res = PathForResource( inInstance, L"ExplorerPluginLocalized.dll", resource, MAX_PATH );
+       err = translate_errno( res != 0, kUnknownErr, kUnknownErr );
+       require_noerr( err, exit );
+
+       g_localizedResources = LoadLibrary( resource );
+       translate_errno( g_localizedResources, GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
+       AfxSetResourceHandle( g_localizedResources );
+
        ok = app->InitInstance();
        require_action( ok, exit, err = kUnknownErr );
        
@@ -478,21 +532,21 @@ DEBUG_LOCAL OSStatus      RegisterServer( HINSTANCE inInstance, CLSID inCLSID, LPCTST
                 ( versionInfo.dwMajorVersion == 5 ) &&
             ( versionInfo.dwMinorVersion >= 1 ) )
        {
-               wsprintf( data, L"%s,%d", moduleName, IDI_BUTTON_XP );
+               wsprintf( data, L"%s,%d", (LPCTSTR) g_nonLocalizedResourcesName, IDI_BUTTON_XP );
                size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
                RegSetValueEx( key, L"Icon", 0, REG_SZ, (LPBYTE) data, size);
 
-               wsprintf( data, L"%s,%d", moduleName, IDI_BUTTON_XP );
+               wsprintf( data, L"%s,%d", (LPCTSTR) g_nonLocalizedResourcesName, IDI_BUTTON_XP );
                size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
                RegSetValueEx( key, L"HotIcon", 0, REG_SZ, (LPBYTE) data, size);
        }
        else
        {
-               wsprintf( data, L"%s,%d", moduleName, IDI_BUTTON_2K );
+               wsprintf( data, L"%s,%d", (LPCTSTR) g_nonLocalizedResourcesName, IDI_BUTTON_2K );
                size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
                RegSetValueEx( key, L"Icon", 0, REG_SZ, (LPBYTE) data, size);
 
-               wsprintf( data, L"%s,%d", moduleName, IDI_BUTTON_2K );
+               wsprintf( data, L"%s,%d", (LPCTSTR) g_nonLocalizedResourcesName, IDI_BUTTON_2K );
                size = (DWORD)( ( lstrlen( data ) + 1 ) * sizeof( TCHAR ) );
                RegSetValueEx( key, L"HotIcon", 0, REG_SZ, (LPBYTE) data, size);
        }
index 0acca3f9c48a749a298b85907825dd347089e42d..40a709a51315b4e8a41dfd13bfc452b05cfcd116 100644 (file)
@@ -23,6 +23,9 @@
     Change History (most recent first):
     
 $Log: ExplorerPlugin.h,v $
+Revision 1.3  2005/01/25 18:35:38  shersche
+Declare APIs for obtaining handles to resource modules
+
 Revision 1.2  2004/07/13 21:24:21  rpantos
 Fix for <rdar://problem/3701120>.
 
@@ -44,3 +47,6 @@ DEFINE_GUID(CLSID_ExplorerBar,
 
 extern HINSTANCE               gInstance;
 extern int                             gDLLRefCount;
+extern HINSTANCE               GetNonLocalizedResources();
+extern HINSTANCE               GetLocalizedResources();
+
index 7879e58c05935141937b21519c6e63400ce8835c..88dfeaf07faf7474739d474d47be151c562d21e9 100644 (file)
-// Microsoft Visual C++ generated resource script.
-//
-#include "Resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.h"
-#include "WinVersRes.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE 
-BEGIN
-    "Resource.h\0"
-END
-
-2 TEXTINCLUDE 
-BEGIN
-    "#include ""afxres.h""\r\n"
-    "#include ""WinVersRes.h""\r\n"
-    "\0"
-END
-
-3 TEXTINCLUDE 
-BEGIN
-    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
-    "#define _AFX_NO_OLE_RESOURCES\r\n"
-    "#define _AFX_NO_TRACKER_RESOURCES\r\n"
-    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
-    "\r\n"
-    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
-    "LANGUAGE 9, 1\r\n"
-    "#pragma code_page(1252)\r\n"
-    "#include ""afxres.rc""     // Standard components\r\n"
-    "#endif\r\n"
-    "\0"
-END
-
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION MASTER_PROD_VERS
- PRODUCTVERSION MASTER_PROD_VERS
- FILEFLAGSMASK 0x3fL
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x2L
- FILESUBTYPE 0x0L
-BEGIN
-    BLOCK "StringFileInfo"
-    BEGIN
-        BLOCK "040904b0"
-        BEGIN
-            VALUE "CompanyName", "Apple Computer, Inc."
-            VALUE "FileDescription", "DNSServices Explorer Bar"
-            VALUE "FileVersion", MASTER_PROD_VERS_STR
-            VALUE "InternalName", "ExplorerPlugin.dll"
-            VALUE "LegalCopyright", "Copyright (C) 2003-2004 Apple Computer, Inc."
-            VALUE "OriginalFilename", "ExplorerPlugin.dll"
-            VALUE "ProductName", MASTER_PROD_NAME
-            VALUE "ProductVersion", MASTER_PROD_VERS_STR
-        END
-    END
-    BLOCK "VarFileInfo"
-    BEGIN
-        VALUE "Translation", 0x409, 1200
-    END
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Dialog
-//
-
-IDD_LOGIN DIALOGEX 0, 0, 180, 89
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
-CAPTION "Login"
-FONT 8, "MS Shell Dlg", 0, 0, 0x0
-BEGIN
-    LTEXT           "Enter a username and password. Leave blank to use the default username and/or password.",
-                    IDC_STATIC,8,8,156,16,NOT WS_GROUP
-    RTEXT           "Username:",IDC_STATIC,10,34,36,8,NOT WS_GROUP
-    EDITTEXT        IDC_LOGIN_USERNAME_TEXT,50,32,118,12,ES_AUTOHSCROLL
-    RTEXT           "Password:",IDC_STATIC,10,50,36,8,NOT WS_GROUP
-    EDITTEXT        IDC_LOGIN_PASSWORD_TEXT,50,48,118,12,ES_PASSWORD | 
-                    ES_AUTOHSCROLL
-    DEFPUSHBUTTON   "OK",IDOK,129,70,44,14
-    PUSHBUTTON      "Cancel",IDCANCEL,77,70,44,14
-END
-
-IDD_ABOUT DIALOGEX 0, 0, 219, 87
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR
-CAPTION "About Rendezvous"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
-    CONTROL         119,IDC_STATIC,"Static",SS_BITMAP | SS_REALSIZEIMAGE,0,0,
-                    220,86
-    CONTROL         MASTER_PROD_VERS_STR3,IDC_COMPONENT,"Static",
-                    SS_SIMPLE | WS_GROUP,92,10,122,8
-    LTEXT           "Copyright (c) 2004 Apple Computer, Inc. All rights reserved. Apple and the Apple logo are trademarks of Apple Computer, Inc., registered in the U.S. and other countries.",
-                    IDC_LEGAL,92,31,123,50,0,WS_EX_RTLREADING
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// DESIGNINFO
-//
-
-#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO 
-BEGIN
-    IDD_LOGIN, DIALOG
-    BEGIN
-        BOTTOMMARGIN, 62
-    END
-
-    IDD_ABOUT, DIALOG
-    BEGIN
-        BOTTOMMARGIN, 132
-    END
-END
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Bitmap
-//
-
-IDB_LOGO                BITMAP                  "res\\logo.bmp"
-IDB_ABOUT               BITMAP                  "res\\about.bmp"
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDI_BUTTON_2K           ICON                    "res\\button-2k.ico"
-IDI_BUTTON_XP           ICON                    "res\\button-xp.ico"
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Menu
-//
-
-IDR_CONTEXT_MENU MENU 
-BEGIN
-    POPUP "ContextMenu"
-    BEGIN
-        MENUITEM "About Rendezvous...",         ID_Menu
-        MENUITEM SEPARATOR
-    END
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// String Table
-//
-
-STRINGTABLE 
-BEGIN
-    IDS_NAME                "Rendezvous"
-    IDS_WEB_SITES           "Web Sites"
-    IDS_FTP_SITES           "FTP Sites"
-    IDS_PRINTERS            "Printers"
-    IDS_MDNSRESPONDER_NOT_AVAILABLE "Rendezvous Service Not Available"
-END
-
-#endif    // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-#define _AFX_NO_SPLITTER_RESOURCES
-#define _AFX_NO_OLE_RESOURCES
-#define _AFX_NO_TRACKER_RESOURCES
-#define _AFX_NO_PROPERTY_RESOURCES
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-LANGUAGE 9, 1
-#pragma code_page(1252)
-#include "afxres.rc"     // Standard components
-#endif
-
-/////////////////////////////////////////////////////////////////////////////
-#endif    // not APSTUDIO_INVOKED
-
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource_dll.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+#include "WinVersRes.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+    "resource_dll.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+    "#include ""afxres.h""\r\n"\r
+    "#include ""WinVersRes.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
+    "#define _AFX_NO_OLE_RESOURCES\r\n"\r
+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
+    "\r\n"\r
+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
+    "LANGUAGE 9, 1\r\n"\r
+    "#pragma code_page(1252)\r\n"\r
+    "#include ""afxres.rc""     // Standard components\r\n"\r
+    "#endif\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION MASTER_PROD_VERS\r
+ PRODUCTVERSION MASTER_PROD_VERS\r
+ FILEFLAGSMASK 0x3fL\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x2L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+        BLOCK "040904b0"\r
+        BEGIN\r
+            VALUE "CompanyName", "Apple Computer, Inc."\r
+            VALUE "FileDescription", "DNSServices Explorer Bar"\r
+            VALUE "FileVersion", MASTER_PROD_VERS_STR\r
+            VALUE "InternalName", "ExplorerPlugin.dll"\r
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
+            VALUE "OriginalFilename", "ExplorerPlugin.dll"\r
+            VALUE "ProductName", MASTER_PROD_NAME\r
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+        VALUE "Translation", 0x409, 1200\r
+    END\r
+END\r
+\r
+#endif    // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+#define _AFX_NO_SPLITTER_RESOURCES\r
+#define _AFX_NO_OLE_RESOURCES\r
+#define _AFX_NO_TRACKER_RESOURCES\r
+#define _AFX_NO_PROPERTY_RESOURCES\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 9, 1\r
+#pragma code_page(1252)\r
+#include "afxres.rc"     // Standard components\r
+#endif\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
+\r
index 62f37fc248e74b312de8fcc8ae28aab4e6dc37fb..87f3f8eab0ec8ed018dcc842b838eff4ea644ec4 100644 (file)
-<?xml version="1.0" encoding = "Windows-1252"?>
-<VisualStudioProject
-       ProjectType="Visual C++"
-       Version="7.00"
-       Name="ExplorerPlugin"
-       ProjectGUID="{BB8AC1B5-6587-4163-BDC6-788B157705CA}"
-       SccProjectName=""
-       SccLocalPath="">
-       <Platforms>
-               <Platform
-                       Name="Win32"/>
-       </Platforms>
-       <Configurations>
-               <Configuration
-                       Name="Debug|Win32"
-                       OutputDirectory=".\Debug"
-                       IntermediateDirectory=".\Debug"
-                       ConfigurationType="2"
-                       UseOfMFC="1"
-                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
-                       CharacterSet="1">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="0"
-                               AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"
-                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"
-                               StringPooling="TRUE"
-                               BasicRuntimeChecks="3"
-                               RuntimeLibrary="1"
-                               ForceConformanceInForLoopScope="TRUE"
-                               UsePrecompiledHeader="0"
-                               PrecompiledHeaderFile=""
-                               AssemblerListingLocation=".\Debug/"
-                               ObjectFile=".\Debug/"
-                               ProgramDataBaseFileName=".\Debug/"
-                               BrowseInformation="1"
-                               WarningLevel="4"
-                               WarnAsError="FALSE"
-                               SuppressStartupBanner="TRUE"
-                               Detect64BitPortabilityProblems="TRUE"
-                               DebugInformationFormat="3"
-                               CallingConvention="2"
-                               CompileAs="0"/>
-                       <Tool
-                               Name="VCCustomBuildTool"
-                               Description="Registering"
-                               CommandLine="regsvr32.exe /s /c $(OutDir)/ExplorerPlugin.dll
-"
-                               Outputs="$(OUTDIR)\Register.out"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "
-                               AdditionalDependencies="../../mDNSWindows/DLL/Debug/dnssd.lib uafxcwd.lib ws2_32.lib"
-                               OutputFile="$(OutDir)/ExplorerPlugin.dll"
-                               LinkIncremental="1"
-                               SuppressStartupBanner="TRUE"
-                               IgnoreDefaultLibraryNames="uafxcwd.lib"
-                               ModuleDefinitionFile="./$(ProjectName).def"
-                               GenerateDebugInformation="TRUE"
-                               ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
-                               SubSystem="2"
-                               ImportLibrary="$(OutDir)/$(ProjectName).lib"/>
-                       <Tool
-                               Name="VCMIDLTool"
-                               PreprocessorDefinitions="_DEBUG"
-                               MkTypLibCompatible="TRUE"
-                               SuppressStartupBanner="TRUE"
-                               TargetEnvironment="1"
-                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               PreprocessorDefinitions="_DEBUG"
-                               Culture="1033"
-                               AdditionalIncludeDirectories="../../mDNSWindows"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-               </Configuration>
-               <Configuration
-                       Name="Release|Win32"
-                       OutputDirectory=".\Release"
-                       IntermediateDirectory=".\Release"
-                       ConfigurationType="2"
-                       UseOfMFC="1"
-                       ATLMinimizesCRunTimeLibraryUsage="FALSE"
-                       CharacterSet="1">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="2"
-                               GlobalOptimizations="TRUE"
-                               InlineFunctionExpansion="2"
-                               FavorSizeOrSpeed="2"
-                               OmitFramePointers="TRUE"
-                               AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"
-                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"
-                               StringPooling="TRUE"
-                               RuntimeLibrary="0"
-                               BufferSecurityCheck="FALSE"
-                               EnableFunctionLevelLinking="FALSE"
-                               ForceConformanceInForLoopScope="TRUE"
-                               UsePrecompiledHeader="0"
-                               PrecompiledHeaderFile=""
-                               AssemblerListingLocation=".\Release/"
-                               ObjectFile=".\Release/"
-                               ProgramDataBaseFileName=".\Release/"
-                               BrowseInformation="1"
-                               WarningLevel="4"
-                               WarnAsError="FALSE"
-                               SuppressStartupBanner="TRUE"
-                               Detect64BitPortabilityProblems="TRUE"
-                               CompileAs="0"/>
-                       <Tool
-                               Name="VCCustomBuildTool"
-                               Description="Registering"
-                               CommandLine="regsvr32.exe /s /c $(OutDir)/$(ProjectName).dll
-"
-                               Outputs="$(OUTDIR)\Register.out"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "
-                               AdditionalDependencies="../../mDNSWindows/DLL/Release/dnssd.lib ws2_32.lib uafxcw.lib"
-                               OutputFile="$(OutDir)/$(ProjectName).dll"
-                               LinkIncremental="1"
-                               SuppressStartupBanner="TRUE"
-                               IgnoreDefaultLibraryNames="uafxcw.lib"
-                               ModuleDefinitionFile="./$(ProjectName).def"
-                               ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"
-                               SubSystem="2"
-                               OptimizeReferences="0"
-                               EnableCOMDATFolding="0"
-                               ImportLibrary="$(OutDir)/$(ProjectName).lib"/>
-                       <Tool
-                               Name="VCMIDLTool"
-                               PreprocessorDefinitions="NDEBUG"
-                               MkTypLibCompatible="TRUE"
-                               SuppressStartupBanner="TRUE"
-                               TargetEnvironment="1"
-                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               PreprocessorDefinitions="NDEBUG"
-                               Culture="1033"
-                               AdditionalIncludeDirectories="../../mDNSWindows"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-               </Configuration>
-       </Configurations>
-       <Files>
-               <Filter
-                       Name="Support"
-                       Filter="">
-                       <File
-                               RelativePath="..\..\mDNSWindows\CommonServices.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSWindows\DebugServices.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSWindows\DebugServices.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSWindows\WinServices.cpp">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSWindows\WinServices.h">
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Source Files"
-                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
-                       <File
-                               RelativePath="About.cpp">
-                       </File>
-                       <File
-                               RelativePath="ClassFactory.cpp">
-                       </File>
-                       <File
-                               RelativePath="ExplorerBar.cpp">
-                       </File>
-                       <File
-                               RelativePath="ExplorerBarWindow.cpp">
-                       </File>
-                       <File
-                               RelativePath="ExplorerPlugin.cpp">
-                       </File>
-                       <File
-                               RelativePath="ExplorerPlugin.def">
-                       </File>
-                       <File
-                               RelativePath="LoginDialog.cpp">
-                       </File>
-                       <File
-                               RelativePath="StdAfx.cpp">
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Header Files"
-                       Filter="h;hpp;hxx;hm;inl;inc">
-                       <File
-                               RelativePath=".\About.h">
-                       </File>
-                       <File
-                               RelativePath="ClassFactory.h">
-                       </File>
-                       <File
-                               RelativePath="ExplorerBar.h">
-                       </File>
-                       <File
-                               RelativePath="ExplorerBarWindow.h">
-                       </File>
-                       <File
-                               RelativePath="ExplorerPlugin.h">
-                       </File>
-                       <File
-                               RelativePath="LoginDialog.h">
-                       </File>
-                       <File
-                               RelativePath="Resource.h">
-                       </File>
-                       <File
-                               RelativePath="StdAfx.h">
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Resource Files"
-                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest">
-                       <File
-                               RelativePath="ExplorerPlugin.rc">
-                       </File>
-                       <File
-                               RelativePath="Web.ico">
-                       </File>
-                       <File
-                               RelativePath=".\about.bmp">
-                       </File>
-                       <File
-                               RelativePath=".\res\about.bmp">
-                       </File>
-                       <File
-                               RelativePath=".\res\cold.ico">
-                       </File>
-                       <File
-                               RelativePath=".\cold.ico">
-                       </File>
-                       <File
-                               RelativePath=".\hot.ico">
-                       </File>
-                       <File
-                               RelativePath=".\res\hot.ico">
-                       </File>
-                       <File
-                               RelativePath=".\logo.bmp">
-                       </File>
-                       <File
-                               RelativePath=".\res\logo.bmp">
-                       </File>
-               </Filter>
-       </Files>
-       <Globals>
-               <Global
-                       Name="RESOURCE_FILE"
-                       Value="ExplorerPlugin.rc"/>
-       </Globals>
-</VisualStudioProject>
+<?xml version="1.0" encoding = "Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.00"\r
+       Name="ExplorerPlugin"\r
+       ProjectGUID="{BB8AC1B5-6587-4163-BDC6-788B157705CA}"\r
+       SccProjectName=""\r
+       SccLocalPath="">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory=".\Debug"\r
+                       IntermediateDirectory=".\Debug"\r
+                       ConfigurationType="2"\r
+                       UseOfMFC="1"\r
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"\r
+                       CharacterSet="1">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0501"\r
+                               StringPooling="TRUE"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               ForceConformanceInForLoopScope="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               PrecompiledHeaderFile=""\r
+                               AssemblerListingLocation=".\Debug/"\r
+                               ObjectFile=".\Debug/"\r
+                               ProgramDataBaseFileName=".\Debug/"\r
+                               BrowseInformation="1"\r
+                               WarningLevel="4"\r
+                               WarnAsError="FALSE"\r
+                               SuppressStartupBanner="TRUE"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="3"\r
+                               CallingConvention="2"\r
+                               CompileAs="0"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                               Description="Registering"\r
+                               CommandLine="regsvr32.exe /s /c $(OutDir)/ExplorerPlugin.dll\r
+"\r
+                               Outputs="$(OUTDIR)\Register.out"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
+                               AdditionalDependencies="../../mDNSWindows/DLL/Debug/dnssd.lib uafxcwd.lib ws2_32.lib"\r
+                               OutputFile="$(OutDir)/ExplorerPlugin.dll"\r
+                               LinkIncremental="1"\r
+                               SuppressStartupBanner="TRUE"\r
+                               IgnoreDefaultLibraryNames="uafxcwd.lib"\r
+                               ModuleDefinitionFile="./$(ProjectName).def"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/$(ProjectName).lib"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               MkTypLibCompatible="TRUE"\r
+                               SuppressStartupBanner="TRUE"\r
+                               TargetEnvironment="1"\r
+                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories="../../mDNSWindows"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory=".\Release\Root\Program Files\bin"\r
+                       IntermediateDirectory=".\Release"\r
+                       ConfigurationType="2"\r
+                       UseOfMFC="1"\r
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"\r
+                       CharacterSet="1">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="2"\r
+                               GlobalOptimizations="TRUE"\r
+                               InlineFunctionExpansion="2"\r
+                               FavorSizeOrSpeed="2"\r
+                               OmitFramePointers="TRUE"\r
+                               AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501"\r
+                               StringPooling="TRUE"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="FALSE"\r
+                               EnableFunctionLevelLinking="FALSE"\r
+                               ForceConformanceInForLoopScope="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               PrecompiledHeaderFile=""\r
+                               AssemblerListingLocation=".\Release/"\r
+                               ObjectFile=".\Release/"\r
+                               ProgramDataBaseFileName=".\Release/"\r
+                               BrowseInformation="1"\r
+                               WarningLevel="4"\r
+                               WarnAsError="FALSE"\r
+                               SuppressStartupBanner="TRUE"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               CompileAs="0"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                               Description="Registering"\r
+                               CommandLine="regsvr32.exe /s /c $(OutDir)/$(ProjectName).dll\r
+"\r
+                               Outputs="$(OUTDIR)\Register.out"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
+                               AdditionalDependencies="../../mDNSWindows/DLL/Release/dnssd.lib ws2_32.lib uafxcw.lib"\r
+                               OutputFile="$(OutDir)/$(ProjectName).dll"\r
+                               LinkIncremental="1"\r
+                               SuppressStartupBanner="TRUE"\r
+                               IgnoreDefaultLibraryNames="uafxcw.lib"\r
+                               ModuleDefinitionFile="./$(ProjectName).def"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="0"\r
+                               EnableCOMDATFolding="0"\r
+                               ImportLibrary="$(IntDir)/$(ProjectName).lib"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               MkTypLibCompatible="TRUE"\r
+                               SuppressStartupBanner="TRUE"\r
+                               TargetEnvironment="1"\r
+                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories="../../mDNSWindows"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <Files>\r
+               <Filter\r
+                       Name="Support"\r
+                       Filter="">\r
+                       <File\r
+                               RelativePath="..\..\mDNSWindows\CommonServices.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSWindows\DebugServices.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSWindows\DebugServices.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSWindows\WinServices.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSWindows\WinServices.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSWindows\isocode.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSWindows\loclibrary.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSWindows\loclibrary.h">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">\r
+                       <File\r
+                               RelativePath="About.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ClassFactory.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ExplorerBar.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ExplorerBarWindow.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ExplorerPlugin.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ExplorerPlugin.def">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="LoginDialog.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="StdAfx.cpp">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc">\r
+                       <File\r
+                               RelativePath=".\About.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ClassFactory.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ExplorerBar.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ExplorerBarWindow.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ExplorerPlugin.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="LoginDialog.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="Resource.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="StdAfx.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="resource_dll.h">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest">\r
+                       <File\r
+                               RelativePath="ExplorerPlugin.rc">\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+               <Global\r
+                       Name="RESOURCE_FILE"\r
+                       Value="ExplorerPlugin.rc"/>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc b/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc
new file mode 100755 (executable)
index 0000000..731a01a
--- /dev/null
@@ -0,0 +1,212 @@
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource_loc_res.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+#include "WinVersRes.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+    "resource_loc_res.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+    "#include ""afxres.h""\r\n"\r
+    "#include ""WinVersRes.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
+    "#define _AFX_NO_OLE_RESOURCES\r\n"\r
+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
+    "\r\n"\r
+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
+    "LANGUAGE 9, 1\r\n"\r
+    "#pragma code_page(1252)\r\n"\r
+    "#include ""afxres.rc""     // Standard components\r\n"\r
+    "#endif\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION MASTER_PROD_VERS\r
+ PRODUCTVERSION MASTER_PROD_VERS\r
+ FILEFLAGSMASK 0x3fL\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x2L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+        BLOCK "040904b0"\r
+        BEGIN\r
+            VALUE "CompanyName", "Apple Computer, Inc."\r
+            VALUE "FileDescription", "DNS-SD Explorer Bar Resource Module"\r
+            VALUE "FileVersion", MASTER_PROD_VERS_STR\r
+            VALUE "InternalName", "ExplorerPluginLocalized.dll"\r
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
+            VALUE "OriginalFilename", "ExplorerPluginLocalized.dll"\r
+            VALUE "ProductName", MASTER_PROD_NAME\r
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+        VALUE "Translation", 0x409, 1200\r
+    END\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Dialog\r
+//\r
+\r
+IDD_LOGIN DIALOGEX 0, 0, 180, 89\r
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION\r
+CAPTION "Login"\r
+FONT 8, "MS Shell Dlg", 0, 0, 0x0\r
+BEGIN\r
+    LTEXT           "Enter a username and password. Leave blank to use the default username and/or password.",\r
+                    IDC_STATIC,8,8,156,16,NOT WS_GROUP\r
+    RTEXT           "Username:",IDC_STATIC,10,34,36,8,NOT WS_GROUP\r
+    EDITTEXT        IDC_LOGIN_USERNAME_TEXT,50,32,118,12,ES_AUTOHSCROLL\r
+    RTEXT           "Password:",IDC_STATIC,10,50,36,8,NOT WS_GROUP\r
+    EDITTEXT        IDC_LOGIN_PASSWORD_TEXT,50,48,118,12,ES_PASSWORD | \r
+                    ES_AUTOHSCROLL\r
+    DEFPUSHBUTTON   "OK",IDOK,129,70,44,14\r
+    PUSHBUTTON      "Cancel",IDCANCEL,77,70,44,14\r
+END\r
+\r
+IDD_ABOUT DIALOGEX 0, 0, 219, 87\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\r
+EXSTYLE WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR\r
+CAPTION "About Rendezvous"\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+    CONTROL         "",IDC_ABOUT_BACKGROUND,"Static",SS_BITMAP | SS_REALSIZEIMAGE,0,0,\r
+                    220,86\r
+    CONTROL         MASTER_PROD_VERS_STR3,IDC_COMPONENT,"Static",\r
+                    SS_SIMPLE | WS_GROUP,92,10,122,8\r
+    LTEXT           "Copyright (c) 2004-2005 Apple Computer, Inc. All rights reserved. Apple and the Apple logo are trademarks of Apple Computer, Inc., registered in the U.S. and other countries.",\r
+                    IDC_LEGAL,92,31,123,50,0,WS_EX_RTLREADING\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// DESIGNINFO\r
+//\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+GUIDELINES DESIGNINFO \r
+BEGIN\r
+    IDD_LOGIN, DIALOG\r
+    BEGIN\r
+        BOTTOMMARGIN, 62\r
+    END\r
+\r
+    IDD_ABOUT, DIALOG\r
+    BEGIN\r
+        BOTTOMMARGIN, 132\r
+    END\r
+END\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Menu\r
+//\r
+\r
+IDR_CONTEXT_MENU MENU \r
+BEGIN\r
+    POPUP "ContextMenu"\r
+    BEGIN\r
+        MENUITEM "About Rendezvous...",         ID_Menu\r
+        MENUITEM SEPARATOR\r
+    END\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// String Table\r
+//\r
+\r
+STRINGTABLE \r
+BEGIN\r
+    IDS_ABOUT               "About Rendezvous"\r
+    IDS_ABOUT_URL           "http://www.apple.com/macosx/features/rendezvous"\r
+    IDS_NAME                "Rendezvous"\r
+    IDS_WEB_SITES           "Web Sites"\r
+    IDS_FTP_SITES           "FTP Sites"\r
+    IDS_PRINTERS            "Printers"\r
+    IDS_MDNSRESPONDER_NOT_AVAILABLE "Rendezvous Service Not Available"\r
+    IDS_FIREWALL            "Check firewall settings"\r
+END\r
+\r
+#endif    // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+#define _AFX_NO_SPLITTER_RESOURCES\r
+#define _AFX_NO_OLE_RESOURCES\r
+#define _AFX_NO_TRACKER_RESOURCES\r
+#define _AFX_NO_PROPERTY_RESOURCES\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 9, 1\r
+#pragma code_page(1252)\r
+#include "afxres.rc"     // Standard components\r
+#endif\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
+\r
diff --git a/Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj b/Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj
new file mode 100755 (executable)
index 0000000..5aa578d
--- /dev/null
@@ -0,0 +1,178 @@
+<?xml version="1.0" encoding = "Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.00"\r
+       Name="ExplorerPluginLocRes"\r
+       ProjectGUID="{BB8AC1B5-6587-4163-BDC6-788B157705CA}"\r
+       SccProjectName=""\r
+       SccLocalPath="">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory=".\Debug\ExplorerPlugin.dll.Resources\en.lproj"\r
+                       IntermediateDirectory=".\Debug"\r
+                       ConfigurationType="2"\r
+                       UseOfMFC="1"\r
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"\r
+                       CharacterSet="1">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..\mDNSWindows"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"\r
+                               StringPooling="TRUE"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               ForceConformanceInForLoopScope="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               PrecompiledHeaderFile=""\r
+                               AssemblerListingLocation=".\Debug/"\r
+                               ObjectFile=".\Debug/"\r
+                               ProgramDataBaseFileName=".\Debug/"\r
+                               BrowseInformation="1"\r
+                               WarningLevel="4"\r
+                               WarnAsError="FALSE"\r
+                               SuppressStartupBanner="TRUE"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="3"\r
+                               CallingConvention="2"\r
+                               CompileAs="0"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
+                               AdditionalDependencies=""\r
+                               OutputFile="$(OutDir)/ExplorerPluginLocalized.dll"\r
+                               LinkIncremental="1"\r
+                               SuppressStartupBanner="TRUE"\r
+                               IgnoreDefaultLibraryNames=""\r
+                               ModuleDefinitionFile=""\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"\r
+                               SubSystem="2"\r
+                               ResourceOnlyDLL="TRUE"\r
+                               ImportLibrary="$(OutDir)/$(ProjectName).lib"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               MkTypLibCompatible="TRUE"\r
+                               SuppressStartupBanner="TRUE"\r
+                               TargetEnvironment="1"\r
+                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories="../../mDNSWindows"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory=".\Release\Root\Program Files\bin\ExplorerPlugin.dll.Resources\en.lproj"\r
+                       IntermediateDirectory=".\Release"\r
+                       ConfigurationType="2"\r
+                       UseOfMFC="1"\r
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"\r
+                       CharacterSet="1">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="2"\r
+                               GlobalOptimizations="TRUE"\r
+                               InlineFunctionExpansion="2"\r
+                               FavorSizeOrSpeed="2"\r
+                               OmitFramePointers="TRUE"\r
+                               AdditionalIncludeDirectories="..\..\mDNSWindows"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"\r
+                               StringPooling="TRUE"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="FALSE"\r
+                               EnableFunctionLevelLinking="FALSE"\r
+                               ForceConformanceInForLoopScope="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               PrecompiledHeaderFile=""\r
+                               AssemblerListingLocation=".\Release/"\r
+                               ObjectFile=".\Release/"\r
+                               ProgramDataBaseFileName=".\Release/"\r
+                               BrowseInformation="1"\r
+                               WarningLevel="4"\r
+                               WarnAsError="FALSE"\r
+                               SuppressStartupBanner="TRUE"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               CompileAs="0"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
+                               AdditionalDependencies=""\r
+                               OutputFile="$(OutDir)/ExplorerPluginLocalized.dll"\r
+                               LinkIncremental="1"\r
+                               SuppressStartupBanner="TRUE"\r
+                               IgnoreDefaultLibraryNames=""\r
+                               ModuleDefinitionFile=""\r
+                               ProgramDatabaseFile=""\r
+                               SubSystem="2"\r
+                               OptimizeReferences="0"\r
+                               EnableCOMDATFolding="0"\r
+                               ResourceOnlyDLL="TRUE"\r
+                               ImportLibrary="$(IntDir)/$(ProjectName).lib"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               MkTypLibCompatible="TRUE"\r
+                               SuppressStartupBanner="TRUE"\r
+                               TargetEnvironment="1"\r
+                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories="../../mDNSWindows"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc">\r
+                       <File\r
+                               RelativePath="resource_loc_res.h">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest">\r
+                       <File\r
+                               RelativePath="ExplorerPluginLocRes.rc">\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+               <Global\r
+                       Name="RESOURCE_FILE"\r
+                       Value="ExplorerPluginLocRes.rc"/>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/Clients/ExplorerPlugin/ExplorerPluginRes.rc b/Clients/ExplorerPlugin/ExplorerPluginRes.rc
new file mode 100755 (executable)
index 0000000..fb9199d
--- /dev/null
@@ -0,0 +1,141 @@
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource_res.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+#include "WinVersRes.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+    "resource_res.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+    "#include ""afxres.h""\r\n"\r
+    "#include ""WinVersRes.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
+    "#define _AFX_NO_OLE_RESOURCES\r\n"\r
+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
+    "\r\n"\r
+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
+    "LANGUAGE 9, 1\r\n"\r
+    "#pragma code_page(1252)\r\n"\r
+    "#include ""afxres.rc""     // Standard components\r\n"\r
+    "#endif\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION MASTER_PROD_VERS\r
+ PRODUCTVERSION MASTER_PROD_VERS\r
+ FILEFLAGSMASK 0x3fL\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x2L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+        BLOCK "040904b0"\r
+        BEGIN\r
+            VALUE "CompanyName", "Apple Computer, Inc."\r
+            VALUE "FileDescription", "DNS-SD Explorer Bar Resource Module"\r
+            VALUE "FileVersion", MASTER_PROD_VERS_STR\r
+            VALUE "InternalName", "ExplorerPluginResources.dll"\r
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
+            VALUE "OriginalFilename", "ExplorerPluginResources.dll"\r
+            VALUE "ProductName", MASTER_PROD_NAME\r
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+        VALUE "Translation", 0x409, 1200\r
+    END\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Bitmap\r
+//\r
+\r
+IDB_LOGO                BITMAP                  "res\\logo.bmp"\r
+IDB_ABOUT               BITMAP                  "res\\about.bmp"\r
+IDB_GLOBE                                      BITMAP                                          "res\\globe.bmp"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Icon\r
+//\r
+\r
+// Icon with lowest ID value placed first to ensure application icon\r
+// remains consistent on all systems.\r
+IDI_BUTTON_2K           ICON                    "res\\button-2k.ico"\r
+IDI_BUTTON_XP           ICON                    "res\\button-xp.ico"\r
+#endif    // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+#define _AFX_NO_SPLITTER_RESOURCES\r
+#define _AFX_NO_OLE_RESOURCES\r
+#define _AFX_NO_TRACKER_RESOURCES\r
+#define _AFX_NO_PROPERTY_RESOURCES\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 9, 1\r
+#pragma code_page(1252)\r
+#include "afxres.rc"     // Standard components\r
+#endif\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
+\r
diff --git a/Clients/ExplorerPlugin/ExplorerPluginRes.vcproj b/Clients/ExplorerPlugin/ExplorerPluginRes.vcproj
new file mode 100755 (executable)
index 0000000..31627b1
--- /dev/null
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding = "Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.00"\r
+       Name="ExplorerPluginRes"\r
+       ProjectGUID="{BB8AC1B5-6587-4163-BDC6-788B157705CA}"\r
+       SccProjectName=""\r
+       SccLocalPath="">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory=".\Debug\ExplorerPlugin.dll.Resources"\r
+                       IntermediateDirectory=".\Debug"\r
+                       ConfigurationType="2"\r
+                       UseOfMFC="1"\r
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"\r
+                       CharacterSet="1">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..\mDNSWindows"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"\r
+                               StringPooling="TRUE"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               ForceConformanceInForLoopScope="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               PrecompiledHeaderFile=""\r
+                               AssemblerListingLocation=".\Debug/"\r
+                               ObjectFile=".\Debug/"\r
+                               ProgramDataBaseFileName=".\Debug/"\r
+                               BrowseInformation="1"\r
+                               WarningLevel="4"\r
+                               WarnAsError="FALSE"\r
+                               SuppressStartupBanner="TRUE"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="3"\r
+                               CallingConvention="2"\r
+                               CompileAs="0"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
+                               OutputFile="$(OutDir)\ExplorerPluginResources.dll"\r
+                               LinkIncremental="1"\r
+                               SuppressStartupBanner="TRUE"\r
+                               IgnoreDefaultLibraryNames=""\r
+                               ModuleDefinitionFile=""\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"\r
+                               SubSystem="2"\r
+                               ResourceOnlyDLL="TRUE"\r
+                               ImportLibrary="$(OutDir)/$(ProjectName).lib"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               MkTypLibCompatible="TRUE"\r
+                               SuppressStartupBanner="TRUE"\r
+                               TargetEnvironment="1"\r
+                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories="../../mDNSWindows"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory=".\Release\Root\Program Files\bin\ExplorerPlugin.dll.Resources"\r
+                       IntermediateDirectory=".\Release"\r
+                       ConfigurationType="2"\r
+                       UseOfMFC="1"\r
+                       ATLMinimizesCRunTimeLibraryUsage="FALSE"\r
+                       CharacterSet="1">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="2"\r
+                               GlobalOptimizations="TRUE"\r
+                               InlineFunctionExpansion="2"\r
+                               FavorSizeOrSpeed="2"\r
+                               OmitFramePointers="TRUE"\r
+                               AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"\r
+                               StringPooling="TRUE"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="FALSE"\r
+                               EnableFunctionLevelLinking="FALSE"\r
+                               ForceConformanceInForLoopScope="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               PrecompiledHeaderFile=""\r
+                               AssemblerListingLocation=".\Release/"\r
+                               ObjectFile=".\Release/"\r
+                               ProgramDataBaseFileName=".\Release/"\r
+                               BrowseInformation="1"\r
+                               WarningLevel="4"\r
+                               WarnAsError="FALSE"\r
+                               SuppressStartupBanner="TRUE"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               CompileAs="0"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
+                               OutputFile="$(OutDir)\ExplorerPluginResources.dll"\r
+                               LinkIncremental="1"\r
+                               SuppressStartupBanner="TRUE"\r
+                               IgnoreDefaultLibraryNames=""\r
+                               ModuleDefinitionFile=""\r
+                               ProgramDatabaseFile=""\r
+                               SubSystem="2"\r
+                               OptimizeReferences="0"\r
+                               EnableCOMDATFolding="0"\r
+                               ResourceOnlyDLL="TRUE"\r
+                               ImportLibrary="$(IntDir)/$(ProjectName).lib"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               MkTypLibCompatible="TRUE"\r
+                               SuppressStartupBanner="TRUE"\r
+                               TargetEnvironment="1"\r
+                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories="../../mDNSWindows"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc">\r
+                       <File\r
+                               RelativePath="resource_res.h">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest">\r
+                       <File\r
+                               RelativePath="ExplorerPluginRes.rc">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="Web.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\about.bmp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\about.bmp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\button-2k.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\button-xp.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\res\cold.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\hot.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\logo.bmp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\logo.bmp">\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+               <Global\r
+                       Name="RESOURCE_FILE"\r
+                       Value="ExplorerPluginRes.rc"/>\r
+       </Globals>\r
+</VisualStudioProject>\r
index 2e56708a486cd13bd41b5ebd6f0b59c0679b4629..e6a7b320cab093509e0401cb6c6e5a900a770d83 100644 (file)
@@ -1,32 +1,37 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by ExplorerPlugin.rc
-//
-#define IDS_NAME                        106
-#define IDS_WEB_SITES                   107
-#define IDS_FTP_SITES                   108
-#define IDS_PRINTERS                    109
-#define IDS_MDNSRESPONDER_NOT_AVAILABLE 110
-#define IDB_LOGO                        115
-#define IDI_BUTTON_2K                   115
-#define IDD_ABOUT                       118
-#define IDI_BUTTON_XP                   118
-#define IDB_ABOUT                       119
-#define IDR_CONTEXT_MENU                120
-#define IDD_LOGIN                       145
-#define IDC_COMPONENT                   1001
-#define IDC_LEGAL                       1002
-#define IDC_LOGIN_USERNAME_TEXT         1182
-#define IDC_LOGIN_PASSWORD_TEXT         1183
-#define ID_Menu                         40001
+/*
+ * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
 
-// Next default values for new objects
-// 
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        119
-#define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1001
-#define _APS_NEXT_SYMED_VALUE           101
-#endif
-#endif
+    Change History (most recent first):
+    
+ */
+
+// Include the core resources
+
+#include "resource_dll.h"
+
+// Include the non-localizable resources
+
+#include "resource_res.h"
+
+// Include the localizable resources
+
+#include "resource_loc_res.h"
diff --git a/Clients/ExplorerPlugin/res/globe.bmp b/Clients/ExplorerPlugin/res/globe.bmp
new file mode 100755 (executable)
index 0000000..7e4949d
Binary files /dev/null and b/Clients/ExplorerPlugin/res/globe.bmp differ
diff --git a/Clients/ExplorerPlugin/resource_dll.h b/Clients/ExplorerPlugin/resource_dll.h
new file mode 100755 (executable)
index 0000000..628228d
--- /dev/null
@@ -0,0 +1,26 @@
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Visual C++ generated include file.\r
+// Used by ExplorerPlugin.rc\r
+//\r
+#define IDS_NAME                        106\r
+#define IDS_WEB_SITES                   107\r
+#define IDS_FTP_SITES                   108\r
+#define IDS_PRINTERS                    109\r
+#define IDS_MDNSRESPONDER_NOT_AVAILABLE 110\r
+#define IDS_FIREWALL                    111\r
+#define IDC_COMPONENT                   1001\r
+#define IDC_LEGAL                       1002\r
+#define IDC_LOGIN_USERNAME_TEXT         1182\r
+#define IDC_LOGIN_PASSWORD_TEXT         1183\r
+#define ID_Menu                         40001\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE        119\r
+#define _APS_NEXT_COMMAND_VALUE         40001\r
+#define _APS_NEXT_CONTROL_VALUE         1001\r
+#define _APS_NEXT_SYMED_VALUE           101\r
+#endif\r
+#endif\r
diff --git a/Clients/ExplorerPlugin/resource_loc_res.h b/Clients/ExplorerPlugin/resource_loc_res.h
new file mode 100755 (executable)
index 0000000..baf2213
--- /dev/null
@@ -0,0 +1,32 @@
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Visual C++ generated include file.\r
+// Used by ExplorerPluginLocRes.rc\r
+//\r
+#define IDS_NAME                        106\r
+#define IDS_WEB_SITES                   107\r
+#define IDS_FTP_SITES                   108\r
+#define IDS_PRINTERS                    109\r
+#define IDS_MDNSRESPONDER_NOT_AVAILABLE 110\r
+#define IDS_FIREWALL                    111\r
+#define IDD_ABOUT                       118\r
+#define IDR_CONTEXT_MENU                120\r
+#define IDD_LOGIN                       145\r
+#define IDC_ABOUT_BACKGROUND                           146\r
+#define IDS_ABOUT                       147\r
+#define IDS_ABOUT_URL                   148\r
+#define IDC_COMPONENT                   1001\r
+#define IDC_LEGAL                       1002\r
+#define IDC_LOGIN_USERNAME_TEXT         1182\r
+#define IDC_LOGIN_PASSWORD_TEXT         1183\r
+#define ID_Menu                         40001\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE        119\r
+#define _APS_NEXT_COMMAND_VALUE         40001\r
+#define _APS_NEXT_CONTROL_VALUE         1001\r
+#define _APS_NEXT_SYMED_VALUE           101\r
+#endif\r
+#endif\r
diff --git a/Clients/ExplorerPlugin/resource_res.h b/Clients/ExplorerPlugin/resource_res.h
new file mode 100755 (executable)
index 0000000..b0217b3
--- /dev/null
@@ -0,0 +1,31 @@
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Visual C++ generated include file.\r
+// Used by ExplorerPluginRes.rc\r
+//\r
+#define IDS_NAME                        106\r
+#define IDS_WEB_SITES                   107\r
+#define IDS_FTP_SITES                   108\r
+#define IDS_PRINTERS                    109\r
+#define IDS_MDNSRESPONDER_NOT_AVAILABLE 110\r
+#define IDS_FIREWALL                    111\r
+#define IDB_LOGO                        115\r
+#define IDI_BUTTON_2K                   115\r
+#define IDI_BUTTON_XP                   118\r
+#define IDB_ABOUT                       119\r
+#define IDB_GLOBE                       149\r
+#define IDC_COMPONENT                   1001\r
+#define IDC_LEGAL                       1002\r
+#define IDC_LOGIN_USERNAME_TEXT         1182\r
+#define IDC_LOGIN_PASSWORD_TEXT         1183\r
+#define ID_Menu                         40001\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE        119\r
+#define _APS_NEXT_COMMAND_VALUE         40001\r
+#define _APS_NEXT_CONTROL_VALUE         1001\r
+#define _APS_NEXT_SYMED_VALUE           101\r
+#endif\r
+#endif\r
index c71faf5e4fefec4129b8a2c1d77079ebdd7687c8..530b26cf8520670fda0a3d7863f136f8c2e9adbf 100644 (file)
     Change History (most recent first):
     
 $Log: FirstPage.cpp,v $
+Revision 1.3  2005/01/25 08:58:08  shersche
+<rdar://problem/3911084> Load icons at run-time from resource DLLs
+Bug #: 3911084
+
 Revision 1.2  2004/07/13 20:15:04  shersche
 <rdar://problem/3726363> Load large font name from resource
 Bug #: 3726363
@@ -37,6 +41,8 @@ First checked in
 #include "PrinterSetupWizardApp.h"
 #include "FirstPage.h"
 
+#include <DebugServices.h>
+
 
 // CFirstPage dialog
 
@@ -71,6 +77,18 @@ void CFirstPage::DoDataExchange(CDataExchange* pDX)
 BOOL
 CFirstPage::OnSetActive()
 {
+       static bool firstTime = true;
+
+       if ( firstTime )
+       {
+               CStatic * image = (CStatic*) GetDlgItem( IDC_INFO );
+               check( image );
+
+               image->SetIcon( LoadIcon( GetNonLocalizedResources(), MAKEINTRESOURCE( IDI_INFO ) ) );
+
+               firstTime = false;
+       }
+
        CPropertySheet* psheet = (CPropertySheet*) GetParent();   
    
        psheet->SetWizardButtons(PSWIZB_NEXT);
index c4ccc52a96ee1175d7a3e78e8a79cf154c7c16f5..8c330df1ae3beb39f04d2800dc442e2f87be2d30 100644 (file)
@@ -23,6 +23,9 @@
     Change History (most recent first):
     
 $Log: FourthPage.cpp,v $
+Revision 1.5  2005/01/06 08:17:08  shersche
+Display the selected protocol ("Raw", "LPR", "IPP") rather than the port name
+
 Revision 1.4  2004/07/13 20:15:04  shersche
 <rdar://problem/3726363> Load large font name from resource
 Bug #: 3726363
@@ -77,7 +80,7 @@ void CFourthPage::DoDataExchange(CDataExchange* pDX)
        DDX_Control(pDX, IDC_PRINTER_NAME, m_printerNameCtrl);
        DDX_Control(pDX, IDC_PRINTER_MANUFACTURER, m_printerManufacturerCtrl);
        DDX_Control(pDX, IDC_PRINTER_MODEL, m_printerModelCtrl);
-       DDX_Control(pDX, IDC_PRINTER_PORT, m_printerPortCtrl);
+       DDX_Control(pDX, IDC_PRINTER_PROTOCOL, m_printerProtocolCtrl);
        DDX_Control(pDX, IDC_PRINTER_DEFAULT, m_printerDefault);
 }
 
@@ -124,7 +127,10 @@ CFourthPage::OnSetActive()
        m_printerNameCtrl.SetWindowText( printer->actualName );
        m_printerManufacturerCtrl.SetWindowText ( printer->manufacturer );
        m_printerModelCtrl.SetWindowText ( printer->model );
-       m_printerPortCtrl.SetWindowText ( printer->portName );
+
+       Service * service = printer->services.front();
+       require_quiet( service, exit );
+       m_printerProtocolCtrl.SetWindowText ( service->protocol );
 
        if (printer->deflt)
        {
index 78bbf52b1a5b2ce860f67b223d93e996b597bf1b..b488e20ef6fd231332d17b03161c5a04d5a6adaa 100644 (file)
@@ -23,6 +23,9 @@
     Change History (most recent first):
     
 $Log: FourthPage.h,v $
+Revision 1.2  2005/01/06 08:17:08  shersche
+Display the selected protocol ("Raw", "LPR", "IPP") rather than the port name
+
 Revision 1.1  2004/06/18 04:36:57  rpantos
 First checked in
 
@@ -66,6 +69,6 @@ private:
        CStatic m_printerNameCtrl;
        CStatic m_printerManufacturerCtrl;
        CStatic m_printerModelCtrl;
-       CStatic m_printerPortCtrl;
+       CStatic m_printerProtocolCtrl;
        CStatic m_printerDefault;
 };
index f099a44283887d90d3fe2cfdeaf714c29cbd20ee..4899ef780749ad280065b87ca7750e8bad254a3c 100644 (file)
@@ -1,6 +1,6 @@
 // Microsoft Visual C++ generated resource script.\r
 //\r
-#include "resource.h"\r
+#include "resource_exe.h"\r
 \r
 #define APSTUDIO_READONLY_SYMBOLS\r
 /////////////////////////////////////////////////////////////////////////////\r
@@ -30,7 +30,7 @@ LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
 \r
 1 TEXTINCLUDE \r
 BEGIN\r
-    "resource.h\0"\r
+    "resource_exe.h\0"\r
 END\r
 \r
 2 TEXTINCLUDE \r
@@ -79,131 +79,6 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 // Icon with lowest ID value placed first to ensure application icon\r
 // remains consistent on all systems.\r
 IDR_MAINFRAME           ICON                    "res\\Print.ico"\r
-IDI_INFO                ICON                    "res\\Info.ico"\r
-IDI_PRINTER             ICON                    "res\\NetworkPrinter.ico"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Bitmap\r
-//\r
-\r
-IDB_WATERMARK           BITMAP                  "res\\watermark.bmp"\r
-IDB_BANNER_ICON         BITMAP                  "res\\banner_icon.bmp"\r
-IDB_ABOUT               BITMAP                  "res\\about.bmp"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Dialog\r
-//\r
-\r
-IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55\r
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | \r
-    WS_SYSMENU\r
-CAPTION "About Printer Setup Wizard"\r
-FONT 8, "MS Shell Dlg", 0, 0, 0x1\r
-BEGIN\r
-    ICON            IDR_MAINFRAME,IDC_STATIC,11,17,20,20\r
-    LTEXT           "Printer Setup Wizard Version 1.0",IDC_STATIC,40,10,119,\r
-                    8,SS_NOPREFIX\r
-    LTEXT           "Copyright (C) 2002",IDC_STATIC,40,25,119,8\r
-    DEFPUSHBUTTON   "OK",IDOK,178,7,50,16,WS_GROUP\r
-END\r
-\r
-IDD_PRINTERSETUPWIZARD_DIALOG DIALOGEX 0, 0, 320, 200\r
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | \r
-    WS_CAPTION | WS_SYSMENU\r
-EXSTYLE WS_EX_APPWINDOW\r
-CAPTION "Printer Setup Wizard"\r
-FONT 8, "MS Shell Dlg", 0, 0, 0x1\r
-BEGIN\r
-    DEFPUSHBUTTON   "OK",IDOK,263,7,50,16\r
-    PUSHBUTTON      "Cancel",IDCANCEL,263,25,50,16\r
-    PUSHBUTTON      "Start Wizard",IDC_BUTTON1,100,86,109,35\r
-END\r
-\r
-IDD_SECOND_PAGE DIALOGEX 0, 0, 290, 154\r
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION\r
-CAPTION "Rendezvous Printer Wizard"\r
-FONT 8, "MS Shell Dlg", 0, 0, 0x0\r
-BEGIN\r
-    LTEXT           "Shared Printers:",IDC_STATIC,3,0,171,8\r
-    CONTROL         "",IDC_BROWSE_LIST,"SysTreeView32",TVS_DISABLEDRAGDROP | \r
-                    TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | WS_BORDER | \r
-                    WS_TABSTOP,2,11,286,142\r
-END\r
-\r
-IDD_FIRST_PAGE DIALOGEX 0, 0, 290, 199\r
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION\r
-CAPTION "Rendezvous Printer Wizard"\r
-FONT 8, "MS Shell Dlg", 0, 0, 0x0\r
-BEGIN\r
-    LTEXT           "Welcome to the Rendezvous Printer Setup Wizard",IDC_GREETING,\r
-                    114,7,171,46\r
-    LTEXT           "Click next to continue.",IDC_STATIC,115,188,143,8\r
-    LTEXT           "This wizard helps you connect to a shared printer using Rendezvous.  Make sure your printer is turned on and connected to your network.",\r
-                    IDC_STATIC,146,60,139,62\r
-    ICON            IDI_INFO,IDC_STATIC,118,60,21,20,SS_REALSIZEIMAGE,\r
-                    WS_EX_TRANSPARENT\r
-END\r
-\r
-IDD_THIRD_PAGE DIALOGEX 0, 0, 290, 154\r
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | \r
-    WS_SYSMENU\r
-CAPTION "Rendezvous Printer Wizard"\r
-FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
-BEGIN\r
-    CONTROL         "",IDC_PRINTER_MODEL,"SysListView32",LVS_REPORT | \r
-                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | \r
-                    LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,110,58,178,76\r
-    CONTROL         "",IDC_PRINTER_MANUFACTURER,"SysListView32",LVS_REPORT | \r
-                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | \r
-                    LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,58,105,76\r
-    ICON            IDI_PRINTER,IDC_PRINTER_IMAGE,1,0,21,20,SS_REALSIZEIMAGE\r
-    LTEXT           "",IDC_PRINTER_NAME,40,5,173,8\r
-    LTEXT           "The Rendezvous Printer Wizard has auto-selected the following printer settings.  Click 'Next' to continue installing this printer.",\r
-                    IDC_PRINTER_SELECTION_TEXT,40,23,243,26\r
-    CONTROL         "Use this printer as the default printer",\r
-                    IDC_DEFAULT_PRINTER,"Button",BS_AUTOCHECKBOX | \r
-                    WS_TABSTOP,3,142,224,10\r
-    PUSHBUTTON      "Have Disk...",IDC_HAVE_DISK,238,140,50,14\r
-END\r
-\r
-IDD_FOURTH_PAGE DIALOGEX 0, 0, 290, 199\r
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION\r
-CAPTION "Rendezvous Printer Wizard"\r
-FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
-BEGIN\r
-    LTEXT           "Completing the Rendezvous Printer Wizard",IDC_GOODBYE,\r
-                    116,7,171,27\r
-    LTEXT           "You have successfully completed the Rendezvous Printer Wizard.  The printer has the following settings:",\r
-                    IDC_STATIC,116,42,158,31\r
-    LTEXT           "Name:",IDC_STATIC,116,78,22,8\r
-    LTEXT           "Manufacturer:",IDC_STATIC,116,91,47,8\r
-    LTEXT           "Model:",IDC_STATIC,116,104,22,8\r
-    LTEXT           "Port:",IDC_STATIC,116,117,17,8\r
-    LTEXT           "Default:",IDC_STATIC,116,130,27,8\r
-    LTEXT           "",IDC_PRINTER_NAME,172,79,113,8\r
-    LTEXT           "",IDC_PRINTER_MANUFACTURER,172,91,113,8\r
-    LTEXT           "",IDC_PRINTER_MODEL,172,103,113,8\r
-    LTEXT           "",IDC_PRINTER_PORT,172,116,113,8\r
-    LTEXT           "",IDC_PRINTER_DEFAULT,172,130,113,8\r
-    LTEXT           "To close this wizard, click Finish.",IDC_STATIC,116,187,\r
-                    103,8\r
-END\r
-\r
-IDD_DIALOG1 DIALOGEX 0, 0, 265, 130\r
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | \r
-    WS_SYSMENU\r
-CAPTION "Dialog"\r
-FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
-BEGIN\r
-    CONTROL         138,IDC_STATIC,"Static",SS_BITMAP | SS_REALSIZEIMAGE,0,0,\r
-                    265,131\r
-    LTEXT           "Static",IDC_STATIC,77,12,19,8\r
-    LTEXT           "Static",IDC_STATIC,71,46,19,8\r
-    LTEXT           "Static",IDC_STATIC,71,89,19,8\r
-END\r
-\r
 \r
 /////////////////////////////////////////////////////////////////////////////\r
 //\r
@@ -231,7 +106,7 @@ BEGIN
             VALUE "FileDescription", "Rendezvous Printer Wizard"\r
             VALUE "FileVersion", MASTER_PROD_VERS_STR\r
             VALUE "InternalName", "RendezvousPrinterWizard.exe"\r
-            VALUE "LegalCopyright", "Copyright (C) 2003-2004 Apple Computer, Inc."\r
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
             VALUE "OriginalFilename", "RendezvousPrinterWizard.exe"\r
             VALUE "ProductName", MASTER_PROD_NAME\r
             VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
@@ -244,34 +119,6 @@ BEGIN
 END\r
 \r
 \r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// DESIGNINFO\r
-//\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-GUIDELINES DESIGNINFO \r
-BEGIN\r
-    IDD_SECOND_PAGE, DIALOG\r
-    BEGIN\r
-        BOTTOMMARGIN, 153\r
-    END\r
-\r
-    IDD_FIRST_PAGE, DIALOG\r
-    BEGIN\r
-        RIGHTMARGIN, 285\r
-        BOTTOMMARGIN, 196\r
-    END\r
-\r
-    IDD_FOURTH_PAGE, DIALOG\r
-    BEGIN\r
-        RIGHTMARGIN, 285\r
-        BOTTOMMARGIN, 197\r
-    END\r
-END\r
-#endif    // APSTUDIO_INVOKED\r
-\r
-\r
 /////////////////////////////////////////////////////////////////////////////\r
 //\r
 // RT_MANIFEST\r
@@ -286,37 +133,8 @@ IDR_MANIFEST            RT_MANIFEST             "res\\PrinterSetupWizard.manifes
 \r
 STRINGTABLE \r
 BEGIN\r
-    IDS_ABOUTBOX            "&About Printer Setup Wizard..."\r
-    IDS_GOODBYE             "Completing the Rendezvous Printer Setup Wizard."\r
-    IDS_GREETING            "Welcome to the Rendezvous Printer Setup Wizard"\r
-    IDS_BROWSE_TITLE        "Browse for Rendezvous Printers"\r
-    IDS_BROWSE_SUBTITLE     "Select the printer you want to use from the list below."\r
-    IDS_CAPTION             "Rendezvous Printer Wizard"\r
-    IDS_GOODBYE_GOOD1       "You have successfully completed the Rendezvous Printer Wizard.  The printer has the following settings:"\r
-    IDS_SEARCHING           "Searching for printers..."\r
-    IDS_GOODBYTE_GOOD2      "To close this wizard, click Finish."\r
-    IDS_INSTALL_TITLE       "Install Rendezvous Printer"\r
-    IDS_INSTALL_SUBTITLE    "The manufacturer and model determine which printer software to use."\r
-END\r
-\r
-STRINGTABLE \r
-BEGIN\r
-    IDS_ERROR_SELECTING_PRINTER_TEXT \r
-                            "There was an error selecting this printer."\r
-    IDS_ERROR_SELECTING_PRINTER_CAPTION "Error"\r
-    IDS_INSTALL_ERROR_CAPTION "Error"\r
-    IDS_INSTALL_ERROR_MESSAGE \r
-                            "You do not have sufficient access to your computer to connect to the selected printer."\r
-    IDS_MANUFACTURER_HEADING "Manufacturer"\r
-    IDS_MODEL_HEADING       "Model"\r
-    IDS_NO_RENDEZVOUS_PRINTERS "No Rendezvous Printers are available"\r
-    IDS_NO_MDNSRESPONDER_SERVICE_TEXT "Rendezvous Service is not available"\r
-    IDS_NO_MDNSRESPONDER_SERVICE_CAPTION "Error"\r
-    IDS_PRINTER_MATCH_GOOD  "The Rendezvous Printer Wizard has auto-selected the following printer settings.  Click 'Next' to continue installing this printer."\r
-    IDS_PRINTER_MATCH_BAD   "The Rendezvous Printer Wizard cannot find a driver for this printer.  Manually select from the list, or click 'Have Disk' if your printer came with an installation disk. "\r
-    IDS_YES                 "Yes"\r
-    IDS_NO                  "No"\r
-    IDS_LARGE_FONT          "MS Sans Serif"\r
+    IDS_REINSTALL    "Rendezvous Printer Wizard cannot run because some of its required files are missing.  Please reinstall Rendezvous Printer Wizard."\r
+       IDS_REINSTALL_CAPTION "Rendezvous Printer Wizard"\r
 END\r
 \r
 #endif    // English (U.S.) resources\r
index 280c398d88228e7f9152d05c6290fce85a8d7efd..c26dc3e937ed827f876d16155ba060ca8e2d7a65 100644 (file)
-<?xml version="1.0" encoding = "windows-1251"?>
-<VisualStudioProject
-       ProjectType="Visual C++"
-       Version="7.00"
-       Name="PrinterSetupWizard"
-       ProjectGUID="{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}"
-       Keyword="MFCProj">
-       <Platforms>
-               <Platform
-                       Name="Win32"/>
-       </Platforms>
-       <Configurations>
-               <Configuration
-                       Name="Debug|Win32"
-                       OutputDirectory="Debug"
-                       IntermediateDirectory="Debug"
-                       ConfigurationType="1"
-                       UseOfMFC="1"
-                       CharacterSet="2">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="0"
-                               AdditionalIncludeDirectories=".;../../mDNSWindows;../../mDNSShared;C:\WINDDK\2600.1106\inc;C:\WINDDK\2600.1106\inc\wxp"
-                               PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUGS;DEBUG=1;WINVER=0x0400;UNICODE;_UNICODE"
-                               StringPooling="TRUE"
-                               MinimalRebuild="TRUE"
-                               BasicRuntimeChecks="3"
-                               RuntimeLibrary="1"
-                               BufferSecurityCheck="TRUE"
-                               TreatWChar_tAsBuiltInType="TRUE"
-                               UsePrecompiledHeader="0"
-                               WarningLevel="4"
-                               Detect64BitPortabilityProblems="TRUE"
-                               DebugInformationFormat="4"
-                               CallingConvention="0"
-                               DisableSpecificWarnings="4702"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalDependencies="../../mDNSWindows/DLL/Debug/dnssd.lib ws2_32.lib iphlpapi.lib winspool.lib"
-                               OutputFile="$(OutDir)/RendezvousPrinterWizard.exe"
-                               LinkIncremental="2"
-                               GenerateDebugInformation="TRUE"
-                               SubSystem="2"
-                               EntryPointSymbol="wWinMainCRTStartup"
-                               TargetMachine="1"/>
-                       <Tool
-                               Name="VCMIDLTool"
-                               PreprocessorDefinitions="_DEBUG"
-                               MkTypLibCompatible="FALSE"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               PreprocessorDefinitions="_DEBUG"
-                               Culture="1033"
-                               AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-               </Configuration>
-               <Configuration
-                       Name="Release|Win32"
-                       OutputDirectory="Release"
-                       IntermediateDirectory="Release"
-                       ConfigurationType="1"
-                       UseOfMFC="1"
-                       CharacterSet="2">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="2"
-                               InlineFunctionExpansion="1"
-                               OmitFramePointers="TRUE"
-                               AdditionalIncludeDirectories=".;../../mDNSWindows;../../mDNSShared;C:\WINDDK\2600.1106\inc;C:\WINDDK\2600.1106\inc\wxp"
-                               PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;WINVER=0x0400;UNICODE;_UNICODE"
-                               StringPooling="TRUE"
-                               MinimalRebuild="FALSE"
-                               RuntimeLibrary="0"
-                               EnableFunctionLevelLinking="TRUE"
-                               TreatWChar_tAsBuiltInType="TRUE"
-                               UsePrecompiledHeader="0"
-                               WarningLevel="4"
-                               Detect64BitPortabilityProblems="TRUE"
-                               DebugInformationFormat="3"
-                               DisableSpecificWarnings="4702"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalDependencies="../../mDNSWindows/DLL/Release/dnssd.lib ws2_32.lib iphlpapi.lib winspool.lib"
-                               OutputFile="$(OutDir)/RendezvousPrinterWizard.exe"
-                               LinkIncremental="1"
-                               GenerateDebugInformation="TRUE"
-                               SubSystem="2"
-                               OptimizeReferences="0"
-                               EnableCOMDATFolding="0"
-                               EntryPointSymbol="wWinMainCRTStartup"
-                               TargetMachine="1"/>
-                       <Tool
-                               Name="VCMIDLTool"
-                               PreprocessorDefinitions="NDEBUG"
-                               MkTypLibCompatible="FALSE"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               PreprocessorDefinitions="NDEBUG"
-                               Culture="1033"
-                               AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-               </Configuration>
-       </Configurations>
-       <Files>
-               <Filter
-                       Name="Source Files"
-                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
-                       <File
-                               RelativePath=".\About.cpp">
-                       </File>
-                       <File
-                               RelativePath="FirstPage.cpp">
-                       </File>
-                       <File
-                               RelativePath=".\FourthPage.cpp">
-                       </File>
-                       <File
-                               RelativePath="PrinterSetupWizardApp.cpp">
-                       </File>
-                       <File
-                               RelativePath="PrinterSetupWizardSheet.cpp">
-                       </File>
-                       <File
-                               RelativePath="SecondPage.cpp">
-                       </File>
-                       <File
-                               RelativePath=".\StdioFileEx.cpp">
-                       </File>
-                       <File
-                               RelativePath="ThirdPage.cpp">
-                       </File>
-                       <File
-                               RelativePath="stdafx.cpp">
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Header Files"
-                       Filter="h;hpp;hxx;hm;inl;inc">
-                       <File
-                               RelativePath=".\About.h">
-                       </File>
-                       <File
-                               RelativePath="FirstPage.h">
-                       </File>
-                       <File
-                               RelativePath=".\FourthPage.h">
-                       </File>
-                       <File
-                               RelativePath="PrinterSetupWizardApp.h">
-                       </File>
-                       <File
-                               RelativePath="PrinterSetupWizardSheet.h">
-                       </File>
-                       <File
-                               RelativePath="Resource.h">
-                       </File>
-                       <File
-                               RelativePath="SecondPage.h">
-                       </File>
-                       <File
-                               RelativePath=".\StdioFileEx.h">
-                       </File>
-                       <File
-                               RelativePath="ThirdPage.h">
-                       </File>
-                       <File
-                               RelativePath=".\UtilTypes.h">
-                       </File>
-                       <File
-                               RelativePath="stdafx.h">
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Resource Files"
-                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest">
-                       <File
-                               RelativePath=".\res\Info.ico">
-                       </File>
-                       <File
-                               RelativePath=".\res\NetworkPrinter.ico">
-                       </File>
-                       <File
-                               RelativePath=".\res\Print.ico">
-                       </File>
-                       <File
-                               RelativePath=".\res\Printer.bmp">
-                       </File>
-                       <File
-                               RelativePath=".\res\Printer.ico">
-                       </File>
-                       <File
-                               RelativePath=".\res\Printer2.ico">
-                       </File>
-                       <File
-                               RelativePath="res\PrinterSetupWizard.ico">
-                       </File>
-                       <File
-                               RelativePath="res\PrinterSetupWizard.manifest">
-                       </File>
-                       <File
-                               RelativePath="PrinterSetupWizard.rc">
-                       </File>
-                       <File
-                               RelativePath="res\PrinterSetupWizard.rc2">
-                       </File>
-                       <File
-                               RelativePath=".\res\about.bmp">
-                       </File>
-                       <File
-                               RelativePath="res\banner_icon.bmp">
-                       </File>
-                       <File
-                               RelativePath="res\watermark.bmp">
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Support"
-                       Filter="">
-                       <File
-                               RelativePath="..\..\mDNSWindows\CommonServices.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSWindows\DebugServices.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSWindows\DebugServices.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSWindows\WinServices.cpp">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSWindows\WinServices.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSShared\dns_sd.h">
-                       </File>
-               </Filter>
-               <File
-                       RelativePath="ReadMe.txt">
-               </File>
-       </Files>
-       <Globals>
-               <Global
-                       Name="RESOURCE_FILE"
-                       Value="PrinterSetupWizard.rc"/>
-       </Globals>
-</VisualStudioProject>
+<?xml version="1.0" encoding = "windows-1251"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.00"\r
+       Name="PrinterSetupWizard"\r
+       ProjectGUID="{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}"\r
+       Keyword="MFCProj">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory=".\Debug"\r
+                       IntermediateDirectory=".\Debug"\r
+                       ConfigurationType="1"\r
+                       UseOfMFC="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".;../../mDNSWindows;../../mDNSShared;C:\WINDDK\2600.1106\inc;C:\WINDDK\2600.1106\inc\wxp"\r
+                               PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUGS;DEBUG=1;WINVER=0x0501;UNICODE;_UNICODE"\r
+                               StringPooling="TRUE"\r
+                               MinimalRebuild="TRUE"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               BufferSecurityCheck="TRUE"\r
+                               TreatWChar_tAsBuiltInType="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="4"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="4"\r
+                               CallingConvention="0"\r
+                               DisableSpecificWarnings="4702"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="../../mDNSWindows/DLL/Debug/dnssd.lib ws2_32.lib iphlpapi.lib winspool.lib"\r
+                               OutputFile="$(OutDir)/RendezvousPrinterWizard.exe"\r
+                               LinkIncremental="2"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
+                               SubSystem="2"\r
+                               EntryPointSymbol="wWinMainCRTStartup"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               MkTypLibCompatible="FALSE"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory=".\Release\Root\Program Files"\r
+                       IntermediateDirectory=".\Release"\r
+                       ConfigurationType="1"\r
+                       UseOfMFC="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="2"\r
+                               InlineFunctionExpansion="1"\r
+                               OmitFramePointers="TRUE"\r
+                               AdditionalIncludeDirectories=".;../../mDNSWindows;../../mDNSShared;C:\WINDDK\2600.1106\inc;C:\WINDDK\2600.1106\inc\wxp"\r
+                               PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;WINVER=0x0501;UNICODE;_UNICODE"\r
+                               StringPooling="TRUE"\r
+                               MinimalRebuild="FALSE"\r
+                               RuntimeLibrary="0"\r
+                               EnableFunctionLevelLinking="TRUE"\r
+                               TreatWChar_tAsBuiltInType="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="4"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="3"\r
+                               DisableSpecificWarnings="4702"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="../../mDNSWindows/DLL/Release/dnssd.lib ws2_32.lib iphlpapi.lib winspool.lib"\r
+                               OutputFile="$(OutDir)/RendezvousPrinterWizard.exe"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="0"\r
+                               EnableCOMDATFolding="0"\r
+                               EntryPointSymbol="wWinMainCRTStartup"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               MkTypLibCompatible="FALSE"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">\r
+                       <File\r
+                               RelativePath=".\About.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="FirstPage.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\FourthPage.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="PrinterSetupWizardApp.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="PrinterSetupWizardSheet.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="SecondPage.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\StdioFileEx.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ThirdPage.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="stdafx.cpp">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc">\r
+                       <File\r
+                               RelativePath=".\About.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="FirstPage.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\FourthPage.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="PrinterSetupWizardApp.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="PrinterSetupWizardSheet.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="SecondPage.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\StdioFileEx.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ThirdPage.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\UtilTypes.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="resource.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="resource_exe.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="stdafx.h">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest">\r
+                       <File\r
+                               RelativePath="res\Info.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\NetworkPrinter.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\Print.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\PrinterSetupWizard.manifest">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="PrinterSetupWizard.rc">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\about.bmp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\banner_icon.bmp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\watermark.bmp">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Support"\r
+                       Filter="">\r
+                       <File\r
+                               RelativePath="..\..\mDNSWindows\CommonServices.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSWindows\DebugServices.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSWindows\DebugServices.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSWindows\WinServices.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSWindows\WinServices.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSShared\dns_sd.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSWindows\isocode.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSWindows\loclibrary.c">\r
+                               <FileConfiguration\r
+                                       Name="Debug|Win32">\r
+                                       <Tool\r
+                                               Name="VCCLCompilerTool"\r
+                                               DisableSpecificWarnings="4201"/>\r
+                               </FileConfiguration>\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSWindows\loclibrary.h">\r
+                       </File>\r
+               </Filter>\r
+               <File\r
+                       RelativePath="ReadMe.txt">\r
+               </File>\r
+       </Files>\r
+       <Globals>\r
+               <Global\r
+                       Name="RESOURCE_FILE"\r
+                       Value="PrinterSetupWizard.rc"/>\r
+       </Globals>\r
+</VisualStudioProject>\r
index 295b4a906e8f47efdcb1fcf87b148e5ef55b5869..37b62289a04a0b988822cbc082b6b151a0e6b64a 100644 (file)
     Change History (most recent first):
     
 $Log: PrinterSetupWizardApp.cpp,v $
+Revision 1.5  2005/01/25 18:30:02  shersche
+Fix call to PathForResource() by passing in NULL as first parameter.
+
+Revision 1.4  2005/01/25 08:54:41  shersche
+<rdar://problem/3911084> Load resource DLLs at startup.
+Bug #: 3911084
+
 Revision 1.3  2004/07/13 21:24:23  rpantos
 Fix for <rdar://problem/3701120>.
 
@@ -40,11 +47,31 @@ First checked in
 #include "PrinterSetupWizardApp.h"
 #include "PrinterSetupWizardSheet.h"
 #include "DebugServices.h"
+#include "loclibrary.h"
 
 #ifdef _DEBUG
 #define new DEBUG_NEW
 #endif
 
+// Stash away pointers to our resource DLLs
+
+static HINSTANCE g_nonLocalizedResources       = NULL;
+static HINSTANCE g_localizedResources          = NULL;
+
+
+HINSTANCE
+GetNonLocalizedResources()
+{
+       return g_nonLocalizedResources;
+}
+
+
+HINSTANCE
+GetLocalizedResources()
+{
+       return g_localizedResources;
+}
+
 
 // CPrinterSetupWizardApp
 
@@ -71,12 +98,42 @@ CPrinterSetupWizardApp theApp;
 
 BOOL CPrinterSetupWizardApp::InitInstance()
 {
+       CString         errorMessage;
+       CString         errorCaption;
+       wchar_t         resource[MAX_PATH];
+       int                     res;
+       OSStatus        err = kNoErr;
+
        //
        // initialize the debugging framework
        //
        debug_initialize( kDebugOutputTypeWindowsDebugger, "PrinterSetupWizard", NULL );
        debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelTrace );
 
+       // Before we load the resources, let's load the error string
+
+       errorMessage.LoadString( IDS_REINSTALL );
+       errorCaption.LoadString( IDS_REINSTALL_CAPTION );
+
+       // Load Resources
+
+       res = PathForResource( NULL, L"RendezvousPrinterWizard.dll", resource, MAX_PATH );
+       err = translate_errno( res != 0, kUnknownErr, kUnknownErr );
+       require_noerr( err, exit );
+
+       g_nonLocalizedResources = LoadLibrary( resource );
+       translate_errno( g_nonLocalizedResources, GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
+       res = PathForResource( NULL, L"RendezvousPrinterWizardLocalized.dll", resource, MAX_PATH );
+       err = translate_errno( res != 0, kUnknownErr, kUnknownErr );
+       require_noerr( err, exit );
+
+       g_localizedResources = LoadLibrary( resource );
+       translate_errno( g_localizedResources, GetLastError(), kUnknownErr );
+       require_noerr( err, exit );\r
+               \r
+       AfxSetResourceHandle( g_localizedResources );\r
 
        // InitCommonControls() is required on Windows XP if an application
        // manifest specifies use of ComCtl32.dll version 6 or later to enable
@@ -87,28 +144,47 @@ BOOL CPrinterSetupWizardApp::InitInstance()
 
        AfxEnableControlContainer();
 
-       CPrinterSetupWizardSheet dlg(IDS_CAPTION);
+       {
+               CPrinterSetupWizardSheet dlg(IDS_CAPTION);
 
-       m_pMainWnd = &dlg;
+               m_pMainWnd = &dlg;
 
-       try
-       {
-               INT_PTR nResponse = dlg.DoModal();
-       
-               if (nResponse == IDOK)
+               try
                {
-                       // TODO: Place code here to handle when the dialog is
-                       //  dismissed with OK
+                       INT_PTR nResponse = dlg.DoModal();
+               
+                       if (nResponse == IDOK)
+                       {
+                               // TODO: Place code here to handle when the dialog is
+                               //  dismissed with OK
+                       }
+                       else if (nResponse == IDCANCEL)
+                       {
+                               // TODO: Place code here to handle when the dialog is
+                               //  dismissed with Cancel
+                       }
                }
-               else if (nResponse == IDCANCEL)
+               catch (CPrinterSetupWizardSheet::WizardException & exc)
                {
-                       // TODO: Place code here to handle when the dialog is
-                       //  dismissed with Cancel
+                       MessageBox(NULL, exc.text, exc.caption, MB_OK|MB_ICONEXCLAMATION);
                }
        }
-       catch (CPrinterSetupWizardSheet::WizardException & exc)
+
+exit:
+
+       if ( err )
+       {
+               MessageBox( NULL, errorMessage, errorCaption, MB_ICONERROR | MB_OK );
+       }
+
+       if ( g_nonLocalizedResources )
+       {
+               FreeLibrary( g_nonLocalizedResources );
+       }
+
+       if ( g_localizedResources )
        {
-               MessageBox(NULL, exc.text, exc.caption, MB_OK|MB_ICONEXCLAMATION);
+               FreeLibrary( g_localizedResources );
        }
 
        // Since the dialog has been closed, return FALSE so that we exit the
index aa3f23327bbb626bba28c3b27dacc889c9386db6..871de5d447c170c46def80a1420c4eb0d776b172 100644 (file)
     Change History (most recent first):
     
 $Log: PrinterSetupWizardApp.h,v $
+Revision 1.2  2005/01/25 08:52:55  shersche
+<rdar://problem/3911084> Add APIs to return localizable and non-localizable resource DLL handles
+Bug #: 3911084
+
 Revision 1.1  2004/06/18 04:36:57  rpantos
 First checked in
 
@@ -57,4 +61,6 @@ public:
 };
 
 
-extern CPrinterSetupWizardApp theApp;
+extern CPrinterSetupWizardApp  theApp;
+extern HINSTANCE                               GetNonLocalizedResources();
+extern HINSTANCE                               GetLocalizedResources();
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc
new file mode 100755 (executable)
index 0000000..521b2ef
--- /dev/null
@@ -0,0 +1,303 @@
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource_loc_res.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+#include "WinVersRes.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Russian resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT\r
+#pragma code_page(1251)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+    "resource_loc_res.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+    "#include ""afxres.h""\r\n"\r
+    "#include ""WinVersRes.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
+    "#define _AFX_NO_OLE_RESOURCES\r\n"\r
+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
+    "\r\n"\r
+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
+    "LANGUAGE 9, 1\r\n"\r
+    "#pragma code_page(1252)\r\n"\r
+    "#include ""res\\PrinterSetupWizardLocRes.rc2""  // non-Microsoft Visual C++ edited resources\r\n"\r
+    "#include ""afxres.rc""         // Standard components\r\n"\r
+    "#endif\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+#endif    // Russian resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Dialog\r
+//\r
+\r
+IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55\r
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | \r
+    WS_SYSMENU\r
+CAPTION "About Printer Setup Wizard"\r
+FONT 8, "MS Shell Dlg", 0, 0, 0x1\r
+BEGIN\r
+    ICON            128,IDC_STATIC,11,17,20,20\r
+    LTEXT           "Printer Setup Wizard Version 1.0",IDC_STATIC,40,10,119,\r
+                    8,SS_NOPREFIX\r
+    LTEXT           "Copyright (C) 2002",IDC_STATIC,40,25,119,8\r
+    DEFPUSHBUTTON   "OK",IDOK,178,7,50,16,WS_GROUP\r
+END\r
+\r
+IDD_PRINTERSETUPWIZARD_DIALOG DIALOGEX 0, 0, 320, 200\r
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | \r
+    WS_CAPTION | WS_SYSMENU\r
+EXSTYLE WS_EX_APPWINDOW\r
+CAPTION "Printer Setup Wizard"\r
+FONT 8, "MS Shell Dlg", 0, 0, 0x1\r
+BEGIN\r
+    DEFPUSHBUTTON   "OK",IDOK,263,7,50,16\r
+    PUSHBUTTON      "Cancel",IDCANCEL,263,25,50,16\r
+    PUSHBUTTON      "Start Wizard",IDC_BUTTON1,100,86,109,35\r
+END\r
+\r
+IDD_SECOND_PAGE DIALOGEX 0, 0, 290, 154\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION\r
+CAPTION "Rendezvous Printer Wizard"\r
+FONT 8, "MS Shell Dlg", 0, 0, 0x0\r
+BEGIN\r
+    LTEXT           "Shared printers:",IDC_STATIC,3,0,171,8\r
+    CONTROL         "",IDC_BROWSE_LIST,"SysTreeView32",TVS_DISABLEDRAGDROP | \r
+                    TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | WS_BORDER | \r
+                    WS_TABSTOP,2,11,286,101\r
+    LTEXT           "Description:",IDC_DESCRIPTION_LABEL,13,128,39,8\r
+    LTEXT           "Location:",IDC_LOCATION_LABEL,13,139,30,8\r
+    GROUPBOX        "Printer information",IDC_PRINTER_INFORMATION,2,116,286,\r
+                    37\r
+    LTEXT           "",IDC_DESCRIPTION_FIELD,57,128,226,8\r
+    LTEXT           "",IDC_LOCATION_FIELD,57,139,226,8\r
+END\r
+\r
+IDD_FIRST_PAGE DIALOGEX 0, 0, 290, 199\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION\r
+CAPTION "Rendezvous Printer Wizard"\r
+FONT 8, "MS Shell Dlg", 0, 0, 0x0\r
+BEGIN\r
+    LTEXT           "Welcome to the Rendezvous Printer Setup Wizard",\r
+                    IDC_GREETING,114,7,171,46\r
+    LTEXT           "Click next to continue.",IDC_STATIC,115,188,143,8\r
+    LTEXT           "This wizard helps you connect to a shared printer using Rendezvous.  Make sure your printer is turned on and connected to your network.",\r
+                    IDC_STATIC,146,60,139,62\r
+    ICON            "",IDC_INFO,118,60,20,20,SS_REALSIZEIMAGE\r
+END\r
+\r
+IDD_THIRD_PAGE DIALOGEX 0, 0, 290, 154\r
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | \r
+    WS_SYSMENU\r
+CAPTION "Rendezvous Printer Wizard"\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+    CONTROL         "",IDC_PRINTER_MODEL,"SysListView32",LVS_REPORT | \r
+                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | \r
+                    LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,110,58,178,76\r
+    CONTROL         "",IDC_PRINTER_MANUFACTURER,"SysListView32",LVS_REPORT | \r
+                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | \r
+                    LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,58,105,76\r
+    ICON            1017,1,0,0,20,27\r
+    LTEXT           "",IDC_PRINTER_NAME,40,5,173,8\r
+    LTEXT           "The Rendezvous Printer Wizard has auto-selected the following printer settings.  Click 'Next' to continue installing this printer.",\r
+                    IDC_PRINTER_SELECTION_TEXT,40,23,243,26\r
+    CONTROL         "Use this printer as the default printer",\r
+                    IDC_DEFAULT_PRINTER,"Button",BS_AUTOCHECKBOX | \r
+                    WS_TABSTOP,3,142,224,10\r
+    PUSHBUTTON      "Have Disk...",IDC_HAVE_DISK,238,140,50,14\r
+END\r
+\r
+IDD_FOURTH_PAGE DIALOGEX 0, 0, 290, 199\r
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION\r
+CAPTION "Rendezvous Printer Wizard"\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+    LTEXT           "Completing the Rendezvous Printer Wizard",IDC_GOODBYE,\r
+                    116,7,171,27\r
+    LTEXT           "You have successfully completed the Rendezvous Printer Wizard.  The printer has the following settings:",\r
+                    IDC_STATIC,116,42,158,31\r
+    LTEXT           "Name:",IDC_STATIC,116,78,22,8\r
+    LTEXT           "Manufacturer:",IDC_STATIC,116,91,47,8\r
+    LTEXT           "Model:",IDC_STATIC,116,104,22,8\r
+    LTEXT           "Protocol:",IDC_STATIC,116,117,38,8\r
+    LTEXT           "Default:",IDC_STATIC,116,130,27,8\r
+    LTEXT           "",IDC_PRINTER_NAME,172,78,113,8\r
+    LTEXT           "",IDC_PRINTER_MANUFACTURER,172,91,113,8\r
+    LTEXT           "",IDC_PRINTER_MODEL,172,104,113,8\r
+    LTEXT           "",IDC_PRINTER_PROTOCOL,172,117,113,8\r
+    LTEXT           "",IDC_PRINTER_DEFAULT,172,130,113,8\r
+    LTEXT           "To close this wizard, click Finish.",IDC_STATIC,116,187,\r
+                    103,8\r
+END\r
+\r
+IDD_DIALOG1 DIALOGEX 0, 0, 265, 130\r
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | \r
+    WS_SYSMENU\r
+CAPTION "Dialog"\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+    CONTROL         138,IDC_STATIC,"Static",SS_BITMAP | SS_REALSIZEIMAGE,0,0,\r
+                    265,131\r
+    LTEXT           "Static",IDC_STATIC,77,12,19,8\r
+    LTEXT           "Static",IDC_STATIC,71,46,19,8\r
+    LTEXT           "Static",IDC_STATIC,71,89,19,8\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION MASTER_PROD_VERS\r
+ PRODUCTVERSION MASTER_PROD_VERS\r
+ FILEFLAGSMASK 0x3fL\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x1L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+        BLOCK "040904e4"\r
+        BEGIN\r
+            VALUE "CompanyName", "Apple Computer, Inc."\r
+            VALUE "FileDescription", "Rendezvous Printer Wizard Resource Module"\r
+            VALUE "FileVersion", MASTER_PROD_VERS_STR\r
+            VALUE "InternalName", "RendezvousPrinterWizardLocalized.dll"\r
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
+            VALUE "OriginalFilename", "RendezvousPrinterWizardLocalized.dll"\r
+            VALUE "ProductName", MASTER_PROD_NAME\r
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+        VALUE "Translation", 0x409, 1252\r
+    END\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// String Table\r
+//\r
+\r
+STRINGTABLE \r
+BEGIN\r
+    IDS_ABOUTBOX            "&About Printer Setup Wizard..."\r
+    IDS_GOODBYE             "Completing the Rendezvous Printer Setup Wizard."\r
+    IDS_GREETING            "Welcome to the Rendezvous Printer Setup Wizard"\r
+    IDS_BROWSE_TITLE        "Browse for Rendezvous Printers"\r
+    IDS_BROWSE_SUBTITLE     "Select the printer you want to use from the list below."\r
+    IDS_CAPTION             "Rendezvous Printer Wizard"\r
+    IDS_GOODBYE_GOOD1       "You have successfully completed the Rendezvous Printer Wizard.  The printer has the following settings:"\r
+    IDS_SEARCHING           "Searching for printers..."\r
+    IDS_GOODBYTE_GOOD2      "To close this wizard, click Finish."\r
+    IDS_INSTALL_TITLE       "Install Rendezvous Printer"\r
+    IDS_INSTALL_SUBTITLE    "The manufacturer and model determine which printer software to use."\r
+END\r
+\r
+STRINGTABLE \r
+BEGIN\r
+    IDS_ERROR_SELECTING_PRINTER_TEXT \r
+                            "There was an error selecting this printer."\r
+    IDS_ERROR_SELECTING_PRINTER_CAPTION "Error"\r
+    IDS_INSTALL_ERROR_CAPTION "Error"\r
+    IDS_INSTALL_ERROR_MESSAGE \r
+                            "You do not have sufficient access to your computer to connect to the selected printer."\r
+    IDS_MANUFACTURER_HEADING "Manufacturer"\r
+    IDS_MODEL_HEADING       "Model"\r
+    IDS_NO_RENDEZVOUS_PRINTERS "No Rendezvous Printers are available"\r
+    IDS_NO_MDNSRESPONDER_SERVICE_TEXT "Rendezvous Service is not available."\r
+    IDS_NO_MDNSRESPONDER_SERVICE_CAPTION "Error"\r
+    IDS_PRINTER_MATCH_GOOD  "The Rendezvous Printer Wizard has auto-selected the following printer settings.  Click 'Next' to continue installing this printer."\r
+    IDS_PRINTER_MATCH_BAD   "The Rendezvous Printer Wizard cannot find a driver for this printer.  Manually select from the list, or click 'Have Disk' if your printer came with an installation disk. "\r
+    IDS_YES                 "Yes"\r
+    IDS_NO                  "No"\r
+    IDS_LARGE_FONT          "MS Sans Serif"\r
+    IDS_FIREWALL            "Please check firewall setting to ensure the Rendezvous Printer Wizard operates correctly."\r
+    IDS_ERROR_CAPTION       "Error"\r
+END\r
+\r
+STRINGTABLE \r
+BEGIN\r
+    IDS_FIREWALL_CAPTION    "Firewall Detected"\r
+END\r
+\r
+#endif    // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+#define _AFX_NO_SPLITTER_RESOURCES\r
+#define _AFX_NO_OLE_RESOURCES\r
+#define _AFX_NO_TRACKER_RESOURCES\r
+#define _AFX_NO_PROPERTY_RESOURCES\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 9, 1\r
+#pragma code_page(1252)\r
+#include "res\PrinterSetupWizardLocRes.rc2"  // non-Microsoft Visual C++ edited resources\r
+#include "afxres.rc"         // Standard components\r
+#endif\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
+\r
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj
new file mode 100755 (executable)
index 0000000..e7d0271
--- /dev/null
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding = "windows-1251"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.00"\r
+       Name="PrinterSetupWizardLocRes"\r
+       ProjectGUID="{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}"\r
+       Keyword="MFCProj">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory=".\Debug\RendezvousPrinterWizard.exe.Resources\en.lproj"\r
+                       IntermediateDirectory=".\Debug"\r
+                       ConfigurationType="2"\r
+                       UseOfMFC="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..\mDNSWindows"\r
+                               PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUGS;DEBUG=1;WINVER=0x0400;UNICODE;_UNICODE"\r
+                               StringPooling="TRUE"\r
+                               MinimalRebuild="TRUE"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               BufferSecurityCheck="TRUE"\r
+                               TreatWChar_tAsBuiltInType="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="4"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="4"\r
+                               CallingConvention="0"\r
+                               DisableSpecificWarnings="4702"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(OutDir)/RendezvousPrinterWizardLocalized.dll"\r
+                               LinkIncremental="2"\r
+                               GenerateDebugInformation="TRUE"\r
+                               SubSystem="2"\r
+                               EntryPointSymbol=""\r
+                               ResourceOnlyDLL="TRUE"\r
+                               ImportLibrary="$(OutDir)/Localized.lib"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               MkTypLibCompatible="FALSE"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory=".\Release\Root\Program Files\RendezvousPrinterWizard.exe.Resources\en.lproj"\r
+                       IntermediateDirectory=".\Release"\r
+                       ConfigurationType="2"\r
+                       UseOfMFC="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="2"\r
+                               InlineFunctionExpansion="1"\r
+                               OmitFramePointers="TRUE"\r
+                               AdditionalIncludeDirectories="..\..\mDNSWindows"\r
+                               PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;WINVER=0x0400;UNICODE;_UNICODE"\r
+                               StringPooling="TRUE"\r
+                               MinimalRebuild="FALSE"\r
+                               RuntimeLibrary="0"\r
+                               EnableFunctionLevelLinking="TRUE"\r
+                               TreatWChar_tAsBuiltInType="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="4"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="3"\r
+                               DisableSpecificWarnings="4702"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(OutDir)/RendezvousPrinterWizardLocalized.dll"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="FALSE"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="0"\r
+                               EnableCOMDATFolding="0"\r
+                               EntryPointSymbol=""\r
+                               ResourceOnlyDLL="TRUE"\r
+                               ImportLibrary="$(IntDir)/$(TargetName).lib"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               MkTypLibCompatible="FALSE"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc">\r
+                       <File\r
+                               RelativePath="resource_loc_dll.h">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest">\r
+                       <File\r
+                               RelativePath="PrinterSetupWizardLocRes.rc">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\PrinterSetupWizardLocRes.rc2">\r
+                       </File>\r
+               </Filter>\r
+               <File\r
+                       RelativePath="ReadMe.txt">\r
+               </File>\r
+       </Files>\r
+       <Globals>\r
+               <Global\r
+                       Name="RESOURCE_FILE"\r
+                       Value="PrinterSetupWizardLocRes.rc"/>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardRes.rc b/Clients/PrinterSetupWizard/PrinterSetupWizardRes.rc
new file mode 100755 (executable)
index 0000000..9a38621
--- /dev/null
@@ -0,0 +1,173 @@
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource_res.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+#include "WinVersRes.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// Russian resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT\r
+#pragma code_page(1251)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+    "resource_res.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+    "#include ""afxres.h""\r\n"\r
+    "#include ""WinVersRes.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
+    "#define _AFX_NO_OLE_RESOURCES\r\n"\r
+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
+    "\r\n"\r
+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
+    "LANGUAGE 9, 1\r\n"\r
+    "#pragma code_page(1252)\r\n"\r
+    "#include ""res\\PrinterSetupWizardRes.rc2""  // non-Microsoft Visual C++ edited resources\r\n"\r
+    "#include ""afxres.rc""         // Standard components\r\n"\r
+    "#endif\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+#endif    // Russian resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Icon\r
+//\r
+\r
+// Icon with lowest ID value placed first to ensure application icon\r
+// remains consistent on all systems.\r
+IDR_MAINFRAME           ICON                    "res\\Print.ico"\r
+IDI_INFO                ICON                    "res\\Info.ico"\r
+IDI_PRINTER             ICON                    "res\\NetworkPrinter.ico"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Bitmap\r
+//\r
+\r
+IDB_WATERMARK           BITMAP                  "res\\watermark.bmp"\r
+IDB_BANNER_ICON         BITMAP                  "res\\banner_icon.bmp"\r
+IDB_ABOUT               BITMAP                  "res\\about.bmp"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Dialog\r
+//\r
+\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION MASTER_PROD_VERS\r
+ PRODUCTVERSION MASTER_PROD_VERS\r
+ FILEFLAGSMASK 0x3fL\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x1L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+        BLOCK "040904e4"\r
+        BEGIN\r
+            VALUE "CompanyName", "Apple Computer, Inc."\r
+            VALUE "FileDescription", "Rendezvous Printer Wizard Resource Module"\r
+            VALUE "FileVersion", MASTER_PROD_VERS_STR\r
+            VALUE "InternalName", "RendezvousPrinterWizardLocalized.dll"\r
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
+            VALUE "OriginalFilename", "RendezvousPrinterWizardLocalized.dll"\r
+            VALUE "ProductName", MASTER_PROD_NAME\r
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+        VALUE "Translation", 0x409, 1252\r
+    END\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// DESIGNINFO\r
+//\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+\r
+#endif    // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+#define _AFX_NO_SPLITTER_RESOURCES\r
+#define _AFX_NO_OLE_RESOURCES\r
+#define _AFX_NO_TRACKER_RESOURCES\r
+#define _AFX_NO_PROPERTY_RESOURCES\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 9, 1\r
+#pragma code_page(1252)\r
+#include "res\PrinterSetupWizardRes.rc2"  // non-Microsoft Visual C++ edited resources\r
+#include "afxres.rc"         // Standard components\r
+#endif\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
+\r
diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj b/Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj
new file mode 100755 (executable)
index 0000000..f3591f0
--- /dev/null
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding = "windows-1251"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.00"\r
+       Name="PrinterSetupWizardRes"\r
+       ProjectGUID="{B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}"\r
+       Keyword="MFCProj">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory=".\Debug\RendezvousPrinterWizard.exe.Resources"\r
+                       IntermediateDirectory=".\Debug"\r
+                       ConfigurationType="2"\r
+                       UseOfMFC="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..\mDNSWindows"\r
+                               PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUGS;DEBUG=1;WINVER=0x0400;UNICODE;_UNICODE"\r
+                               StringPooling="TRUE"\r
+                               MinimalRebuild="TRUE"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               BufferSecurityCheck="TRUE"\r
+                               TreatWChar_tAsBuiltInType="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="4"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="4"\r
+                               CallingConvention="0"\r
+                               DisableSpecificWarnings="4702"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(OutDir)/RendezvousPrinterWizard.dll"\r
+                               LinkIncremental="2"\r
+                               GenerateDebugInformation="TRUE"\r
+                               SubSystem="2"\r
+                               EntryPointSymbol=""\r
+                               ResourceOnlyDLL="TRUE"\r
+                               ImportLibrary="$(OutDir)/Localized.lib"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               MkTypLibCompatible="FALSE"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory=".\Release\Root\Program Files\RendezvousPrinterWizard.exe.Resources"\r
+                       IntermediateDirectory=".\Release"\r
+                       ConfigurationType="2"\r
+                       UseOfMFC="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="2"\r
+                               InlineFunctionExpansion="1"\r
+                               OmitFramePointers="TRUE"\r
+                               AdditionalIncludeDirectories="..\..\mDNSWindows"\r
+                               PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;WINVER=0x0400;UNICODE;_UNICODE"\r
+                               StringPooling="TRUE"\r
+                               MinimalRebuild="FALSE"\r
+                               RuntimeLibrary="0"\r
+                               EnableFunctionLevelLinking="TRUE"\r
+                               TreatWChar_tAsBuiltInType="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="4"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="3"\r
+                               DisableSpecificWarnings="4702"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(OutDir)/RendezvousPrinterWizard.dll"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="FALSE"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="0"\r
+                               EnableCOMDATFolding="0"\r
+                               EntryPointSymbol=""\r
+                               ResourceOnlyDLL="TRUE"\r
+                               ImportLibrary="$(IntDir)/$(TargetName).lib"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               MkTypLibCompatible="FALSE"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories="$(IntDir);../../mDNSWindows"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc">\r
+                       <File\r
+                               RelativePath="resource_dll.h">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest">\r
+                       <File\r
+                               RelativePath=".\res\Info.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\res\NetworkPrinter.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\res\Print.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\res\Printer.bmp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\res\Printer.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\res\Printer2.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\PrinterSetupWizard.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="PrinterSetupWizardRes.rc">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\PrinterSetupWizardRes.rc2">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\res\about.bmp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\banner_icon.bmp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\watermark.bmp">\r
+                       </File>\r
+               </Filter>\r
+               <File\r
+                       RelativePath="ReadMe.txt">\r
+               </File>\r
+       </Files>\r
+       <Globals>\r
+               <Global\r
+                       Name="RESOURCE_FILE"\r
+                       Value="PrinterSetupWizardRes.rc"/>\r
+       </Globals>\r
+</VisualStudioProject>\r
index 02b2952ca0cbee95180ab6fc655c3854419703bd..6b026e1fad0e695d788184f255693bbe5136c943 100644 (file)
     Change History (most recent first):
     
 $Log: PrinterSetupWizardSheet.cpp,v $
+Revision 1.22  2005/01/25 18:49:43  shersche
+Get icon resources from resource DLL
+
+Revision 1.21  2005/01/10 01:09:32  shersche
+Use the "note" key to populate pLocation field when setting up printer
+
+Revision 1.20  2005/01/03 19:05:01  shersche
+Store pointer to instance of wizard sheet so that print driver install thread sends a window message to the correct window
+
+Revision 1.19  2004/12/31 07:23:53  shersche
+Don't modify the button setting in SetSelectedPrinter()
+
+Revision 1.18  2004/12/29 18:53:38  shersche
+<rdar://problem/3725106>
+<rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
+Bug #: 3725106, 3737413
+
 Revision 1.17  2004/10/12 18:02:53  shersche
 <rdar://problem/3764873> Escape '/', '@', '"' characters in printui command.
 Bug #: 3764873
@@ -110,26 +127,23 @@ First checked in
 
 // Private Messages
 
-#define WM_SERVICE_EVENT                               ( WM_USER + 0x100 )
-#define WM_PROCESS_EVENT                               ( WM_USER + 0x101 )
-
-// Service Types
-
-#define        kPDLDataStreamServiceType               "_pdl-datastream._tcp"
-#define kLPRServiceType                                        "_printer._tcp"
-#define kIPPServiceType                                        "_ipp._tcp"
+#define WM_PROCESS_EVENT       ( WM_USER + 0x100 )
 
 
 // CPrinterSetupWizardSheet
+CPrinterSetupWizardSheet * CPrinterSetupWizardSheet::m_self;
 
 IMPLEMENT_DYNAMIC(CPrinterSetupWizardSheet, CPropertySheet)
 CPrinterSetupWizardSheet::CPrinterSetupWizardSheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage)
        :CPropertySheet(nIDCaption, pParentWnd, iSelectPage),
-       m_selectedPrinter(NULL)
+       m_selectedPrinter(NULL),
+       m_driverThreadExitCode( 0 ),
+       m_driverThreadFinished( false )
 {
        m_arrow         =       LoadCursor(0, IDC_ARROW);
        m_wait          =       LoadCursor(0, IDC_APPSTARTING);
        m_active        =       m_arrow;
+       m_self          =       this;
        
        Init();
 }
@@ -137,131 +151,136 @@ CPrinterSetupWizardSheet::CPrinterSetupWizardSheet(UINT nIDCaption, CWnd* pParen
 
 CPrinterSetupWizardSheet::~CPrinterSetupWizardSheet()
 {
-       //
-       // rdar://problem/3701837 memory leaks
-       //
-       // Clean up the ServiceRef and printer list on exit
-       //
-       if (m_pdlBrowser != NULL)
-       {
-               DNSServiceRefDeallocate(m_pdlBrowser);
-               m_pdlBrowser = NULL;
-       }
-
-       while (m_printerList.size() > 0)
-       {
-               Printer * printer = m_printerList.front();
-
-               m_printerList.pop_front();
-
-               delete printer;
-       }
-
-       if (m_selectedPrinter != NULL)
+       if ( m_selectedPrinter != NULL )
        {
                delete m_selectedPrinter;
+               m_selectedPrinter = NULL;
        }
-}
 
-
-// ------------------------------------------------------
-// InstallEventHandler
-//
-// Installs an event handler for DNSService events.  
-//     
-int
-CPrinterSetupWizardSheet::InstallEventHandler(EventHandler * handler)
-{
-       PrinterList::iterator iter;
-       
-       m_eventHandlerList.push_back(handler);
-
-       iter = m_printerList.begin();
-
-       while (iter != m_printerList.end())
-       {
-               Printer * printer = *iter++;
-
-               handler->OnAddPrinter(printer, iter != m_printerList.end());
-       }
-       
-       return kNoErr;
+       m_self = NULL;
 }
 
 
 // ------------------------------------------------------
-// RemoveEventHandler
+// SetSelectedPrinter
 //
-// Removes an event handler for DNSService events.  
+// Manages setting a printer as the printer to install.  Stops
+// any pending resolves.  
 //     
-int
-CPrinterSetupWizardSheet::RemoveEventHandler(EventHandler * handler)
+void
+CPrinterSetupWizardSheet::SetSelectedPrinter(Printer * printer)
 {
-       m_eventHandlerList.remove(handler);
+       check( !printer || ( printer != m_selectedPrinter ) );
 
-       return kNoErr;
+       m_selectedPrinter = printer;
 }
 
 
-
 // ------------------------------------------------------
-// SetSelectedPrinter
+// InstallPrinter
 //
-// Manages setting a printer as the printer to install.  Stops
-// any pending resolves.  
+// Installs a printer with Windows.
+//
+// NOTE: this works one of two ways, depending on whether
+// there are drivers already installed for this printer.
+// If there are, then we can just create a port with XcvData,
+// and then call AddPrinter.  If not, we use the printui.dll
+// to install the printer. Actually installing drivers that
+// are not currently installed is painful, and it's much
+// easier and less error prone to just let printui.dll do
+// the hard work for us.
 //     
+
 OSStatus
-CPrinterSetupWizardSheet::SetSelectedPrinter(Printer * printer)
+CPrinterSetupWizardSheet::InstallPrinter(Printer * printer)
 {
-       OSStatus err;
+       Service *       service;
+       BOOL            ok;
+       OSStatus        err;
+
+       service = printer->services.front();
+       check( service );
 
        //
-       // we only want one resolve going on at a time, so we check
-       // state of the m_selectedPrinter
+       // if the driver isn't installed, then install it
        //
-       if (m_selectedPrinter != NULL)
+       if ( !printer->driverInstalled )
        {
+               DWORD           dwResult;
+               HANDLE          hThread;
+               unsigned        threadID;
+
+               m_driverThreadFinished = false;
+       
+               //
+               // create the thread
+               //
+               hThread = (HANDLE) _beginthreadex_compat( NULL, 0, InstallDriverThread, printer, 0, &threadID );
+               err = translate_errno( hThread, (OSStatus) GetLastError(), kUnknownErr );
+               require_noerr( err, exit );
+                       
                //
-               // if we're currently resolving, then stop the resolve
+               // go modal
                //
-               if (m_selectedPrinter->serviceRef)
+               while (!m_driverThreadFinished)
                {
-                       err = StopResolve(m_selectedPrinter);
-                       require_noerr(err, exit);
+                       MSG msg;
+       
+                       GetMessage( &msg, m_hWnd, 0, 0 );
+                       TranslateMessage(&msg);
+                       DispatchMessage(&msg);
                }
+       
+               //
+               // Wait until child process exits.
+               //
+               dwResult = WaitForSingleObject( hThread, INFINITE );
+               err = translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr );
+               require_noerr( err, exit );
 
-               delete m_selectedPrinter;
-               m_selectedPrinter = NULL;
-       }
+               //
+               // check the return value of thread
+               //
+               require_noerr( m_driverThreadExitCode, exit );
 
-       check( m_selectedPrinter == NULL );
+               //
+               // now we know that the driver was successfully installed
+               //
+               printer->driverInstalled = true;
+       }
 
-       try
+       if ( service->type == kPDLServiceType )
        {
-               m_selectedPrinter = new Printer;
+               err = InstallPrinterPDLAndLPR( printer, service, PROTOCOL_RAWTCP_TYPE );
+               require_noerr( err, exit );
        }
-       catch (...)
+       else if ( service->type == kLPRServiceType )
        {
-               m_selectedPrinter = NULL;
+               err = InstallPrinterPDLAndLPR( printer, service, PROTOCOL_LPR_TYPE );
+               require_noerr( err, exit );
+       }
+       else if ( service->type == kIPPServiceType )
+       {
+               err = InstallPrinterIPP( printer, service );
+               require_noerr( err, exit );
+       }
+       else
+       {
+               err = kUnknownErr;
+               require_noerr( err, exit );
        }
 
-       require_action( m_selectedPrinter, exit, err = E_OUTOFMEMORY );
-
-       m_selectedPrinter->window               =       printer->window;
-       m_selectedPrinter->serviceRef   =       NULL;
-       m_selectedPrinter->item                 =       NULL;
-       m_selectedPrinter->ifi                  =       printer->ifi;
-       m_selectedPrinter->name                 =       printer->name;
-       m_selectedPrinter->displayName  =       printer->displayName;
-       m_selectedPrinter->actualName   =       printer->actualName;
-       m_selectedPrinter->type                 =       printer->type;
-       m_selectedPrinter->domain               =       printer->domain;
-       m_selectedPrinter->installed    =       printer->installed;
-       m_selectedPrinter->deflt                =       printer->deflt;
-       m_selectedPrinter->refs                 =       1;
-                       
-       err = StartResolve(m_selectedPrinter);
-       require_noerr(err, exit);
+       printer->installed = true;
+
+       //
+       // if the user specified a default printer, set it
+       //
+       if (printer->deflt)
+       {
+               ok = SetDefaultPrinter( printer->actualName );
+               err = translate_errno( ok, errno_compat(), err = kUnknownErr );
+               require_noerr( err, exit );
+       }
 
 exit:
 
@@ -269,23 +288,8 @@ exit:
 }
 
 
-// ------------------------------------------------------
-// InstallPrinter
-//
-// Installs a printer with Windows.
-//
-// NOTE: this works one of two ways, depending on whether
-// there are drivers already installed for this printer.
-// If there are, then we can just create a port with XcvData,
-// and then call AddPrinter.  If not, we use the printui.dll
-// to install the printer. Actually installing drivers that
-// are not currently installed is painful, and it's much
-// easier and less error prone to just let printui.dll do
-// the hard work for us.
-//     
-
 OSStatus
-CPrinterSetupWizardSheet::InstallPrinter(Printer * printer)
+CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * service, DWORD protocol )
 {
        PRINTER_DEFAULTS        printerDefaults =       { NULL,  NULL, SERVER_ACCESS_ADMINISTER };
        DWORD                           dwStatus;
@@ -293,14 +297,19 @@ CPrinterSetupWizardSheet::InstallPrinter(Printer * printer)
        PBYTE                           pOutputData             =       NULL;
        DWORD                           cbOutputNeeded  =       0;
        PORT_DATA_1                     portData;
+       PRINTER_INFO_2          pInfo;
        HANDLE                          hXcv                    =       NULL;
        HANDLE                          hPrinter                =       NULL;
+       Queue                   *       q;
        BOOL                            ok;
        OSStatus                        err;
 
        check(printer != NULL);
        check(printer->installed == false);
 
+       q = service->queues.front();
+       check( q );
+
        ok = OpenPrinter(L",XcvMonitor Standard TCP/IP Port", &hXcv, &printerDefaults);
        err = translate_errno( ok, errno_compat(), kUnknownErr );
        require_noerr( err, exit );
@@ -325,98 +334,49 @@ CPrinterSetupWizardSheet::InstallPrinter(Printer * printer)
        ZeroMemory(&portData, sizeof(PORT_DATA_1));
        wcscpy(portData.sztPortName, printer->portName);
        
-       portData.dwPortNumber   =       printer->portNumber;
+       portData.dwPortNumber   =       service->portNumber;
        portData.dwVersion              =       1;
        
-       portData.dwProtocol     = PROTOCOL_RAWTCP_TYPE;
+       portData.dwProtocol     = protocol;
        portData.cbSize         = sizeof PORT_DATA_1;
        portData.dwReserved     = 0L;
        
-       wcscpy(portData.sztQueue, printer->hostname);
-       wcscpy(portData.sztIPAddress, printer->hostname); 
-       wcscpy(portData.sztHostAddress, printer->hostname);
+       wcscpy(portData.sztQueue, q->name);
+       wcscpy(portData.sztIPAddress, service->hostname); 
+       wcscpy(portData.sztHostAddress, service->hostname);
                
        ok = XcvData(hXcv, L"AddPort", (PBYTE) &portData, sizeof(PORT_DATA_1), pOutputData, cbInputData,  &cbOutputNeeded, &dwStatus);
        err = translate_errno( ok, errno_compat(), kUnknownErr );
        require_noerr( err, exit );
-       
-       if (printer->driverInstalled)
-       {
-               PRINTER_INFO_2 pInfo;
-       
-               ZeroMemory(&pInfo, sizeof(pInfo));
-                       
-               pInfo.pPrinterName                      =       printer->actualName.GetBuffer();
-               pInfo.pServerName                       =       NULL;
-               pInfo.pShareName                        =       NULL;
-               pInfo.pPortName                         =       printer->portName.GetBuffer();
-               pInfo.pDriverName                       =       printer->model.GetBuffer();
-               pInfo.pComment                          =       printer->model.GetBuffer();
-               pInfo.pLocation                         =       L"";
-               pInfo.pDevMode                          =       NULL;
-               pInfo.pDevMode                          =       NULL;
-               pInfo.pSepFile                          =       L"";
-               pInfo.pPrintProcessor           =       L"winprint";
-               pInfo.pDatatype                         =       L"RAW";
-               pInfo.pParameters                       =       L"";
-               pInfo.pSecurityDescriptor       =       NULL;
-               pInfo.Attributes                        =       PRINTER_ATTRIBUTE_QUEUED;
-               pInfo.Priority                          =       0;
-               pInfo.DefaultPriority           =       0;
-               pInfo.StartTime                         =       0;
-               pInfo.UntilTime                         =       0;
-       
-               hPrinter = AddPrinter(NULL, 2, (LPBYTE) &pInfo);
-               err = translate_errno( hPrinter, errno_compat(), kUnknownErr );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               DWORD           dwResult;
-               HANDLE          hThread;
-               unsigned        threadID;
-                       
-       
-               m_processFinished = false;
-       
-               //
-               // create the thread
-               //
-               hThread = (HANDLE) _beginthreadex_compat( NULL, 0, InstallPrinterThread, printer, 0, &threadID );
-               err = translate_errno( hThread, (OSStatus) GetLastError(), kUnknownErr );
-               require_noerr( err, exit );
-                       
-               //
-               // go modal
-               //
-               while (!m_processFinished)
-               {
-                       MSG msg;
-       
-                       GetMessage( &msg, m_hWnd, 0, 0 );
-                       TranslateMessage(&msg);
-                       DispatchMessage(&msg);
-               }
-       
-               //
-               // Wait until child process exits.
-               //
-               dwResult = WaitForSingleObject( hThread, INFINITE );
-               err = translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr );
-               require_noerr( err, exit );
-       }
-
-       printer->installed = true;
 
        //
-       // if the user specified a default printer, set it
+       // add the printer
        //
-       if (printer->deflt)
-       {
-               ok = SetDefaultPrinter(printer->actualName);
-               err = translate_errno( ok, errno_compat(), err = kUnknownErr );
-               require_noerr( err, exit );
-       }
+       ZeroMemory(&pInfo, sizeof(pInfo));
+               
+       pInfo.pPrinterName                      =       printer->actualName.GetBuffer();
+       pInfo.pServerName                       =       NULL;
+       pInfo.pShareName                        =       NULL;
+       pInfo.pPortName                         =       printer->portName.GetBuffer();
+       pInfo.pDriverName                       =       printer->model.GetBuffer();
+       pInfo.pComment                          =       printer->model.GetBuffer();
+       pInfo.pLocation                         =       service->location.GetBuffer();
+       pInfo.pDevMode                          =       NULL;
+       pInfo.pDevMode                          =       NULL;
+       pInfo.pSepFile                          =       L"";
+       pInfo.pPrintProcessor           =       L"winprint";
+       pInfo.pDatatype                         =       L"RAW";
+       pInfo.pParameters                       =       L"";
+       pInfo.pSecurityDescriptor       =       NULL;
+       pInfo.Attributes                        =       PRINTER_ATTRIBUTE_QUEUED;
+       pInfo.Priority                          =       0;
+       pInfo.DefaultPriority           =       0;
+       pInfo.StartTime                         =       0;
+       pInfo.UntilTime                         =       0;
+
+       hPrinter = AddPrinter(NULL, 2, (LPBYTE) &pInfo);
+       err = translate_errno( hPrinter, errno_compat(), kUnknownErr );
+       require_noerr( err, exit );
 
 exit:
 
@@ -439,10 +399,46 @@ exit:
 }
 
 
+OSStatus
+CPrinterSetupWizardSheet::InstallPrinterIPP(Printer * printer, Service * service)
+{
+       DEBUG_UNUSED( service );
+
+       HANDLE                  hPrinter = NULL;
+       PRINTER_INFO_2  pInfo;
+       OSStatus                err;
+       
+       //
+       // add the printer
+       //
+       ZeroMemory(&pInfo, sizeof(PRINTER_INFO_2));
+       
+       pInfo.pPrinterName              = printer->actualName.GetBuffer();
+       pInfo.pPortName                 = printer->portName.GetBuffer();
+       pInfo.pDriverName               = printer->model.GetBuffer();
+       pInfo.pPrintProcessor   = L"winprint";
+       pInfo.pLocation                 = service->location.GetBuffer();
+       pInfo.Attributes                = PRINTER_ATTRIBUTE_NETWORK | PRINTER_ATTRIBUTE_LOCAL;
+       
+       hPrinter = AddPrinter(NULL, 2, (LPBYTE)&pInfo);
+       err = translate_errno( hPrinter, errno_compat(), kUnknownErr );
+       require_noerr( err, exit );
+
+exit:
+
+       if ( hPrinter != NULL )
+       {
+               ClosePrinter(hPrinter);
+       }
+
+       return err;
+}
+
+
 BEGIN_MESSAGE_MAP(CPrinterSetupWizardSheet, CPropertySheet)
-ON_MESSAGE( WM_SERVICE_EVENT, OnServiceEvent )
 ON_MESSAGE( WM_PROCESS_EVENT, OnProcessEvent )
 ON_WM_SETCURSOR()
+ON_WM_TIMER()
 END_MESSAGE_MAP()
 
 
@@ -468,40 +464,11 @@ BOOL CPrinterSetupWizardSheet::OnCommand(WPARAM wParam, LPARAM lParam)
 // ------------------------------------------------------
 // OnInitDialog
 //
-// Initializes this Dialog object.  We start the browse here,
-// so that printers show up instantly when the user clicks
-// the next button.  
+// Initializes this Dialog object.
 //     
 BOOL CPrinterSetupWizardSheet::OnInitDialog()
 {
-       OSStatus err;
-
        CPropertySheet::OnInitDialog();
-       
-       //
-       // setup the DNS-SD browsing
-       //
-       err = DNSServiceBrowse( &m_pdlBrowser, 0, 0, kPDLDataStreamServiceType, NULL, OnBrowse, this );
-       require_noerr( err, exit );
-
-       m_serviceRefList.push_back(m_pdlBrowser);
-
-       err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(m_pdlBrowser), m_hWnd, WM_SERVICE_EVENT, FD_READ|FD_CLOSE);
-       require_noerr( err, exit );
-
-       LoadPrinterNames();
-
-exit:
-
-       if (err != kNoErr)
-       {
-               WizardException exc;
-
-               exc.text.LoadString(IDS_NO_MDNSRESPONDER_SERVICE_TEXT);
-               exc.caption.LoadString(IDS_NO_MDNSRESPONDER_SERVICE_CAPTION);
-
-               throw(exc);
-       }
 
        return TRUE;
 }
@@ -583,456 +550,28 @@ void CPrinterSetupWizardSheet::Init(void)
        m_psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
        m_psh.pszbmHeader = MAKEINTRESOURCE(IDB_BANNER_ICON);
 
-       m_psh.hInstance = AfxGetInstanceHandle();
+       m_psh.hInstance = GetNonLocalizedResources();
 
        SetWizardMode();
 }
 
 
-LONG
-CPrinterSetupWizardSheet::OnServiceEvent(WPARAM inWParam, LPARAM inLParam)
-{
-       if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam)))
-    {
-               dlog( kDebugLevelError, "OnServiceEvent: window error\n" );
-    }
-    else
-    {
-               SOCKET sock = (SOCKET) inWParam;
-
-               // iterate thru list
-               ServiceRefList::iterator begin = m_serviceRefList.begin();
-               ServiceRefList::iterator end   = m_serviceRefList.end();
-
-               while (begin != end)
-               {
-                       DNSServiceRef ref = *begin++;
-
-                       check(ref != NULL);
-
-                       if ((SOCKET) DNSServiceRefSockFD(ref) == sock)
-                       {
-                               DNSServiceProcessResult(ref);
-                               break;
-                       }
-               }
-       }
-
-       return ( 0 );
-}
-
-
 LONG
 CPrinterSetupWizardSheet::OnProcessEvent(WPARAM inWParam, LPARAM inLParam)
 {
-       DEBUG_UNUSED(inWParam);
        DEBUG_UNUSED(inLParam);
 
-       m_processFinished = true;
+       m_driverThreadExitCode  =       (DWORD) inWParam;
+       m_driverThreadFinished  =       true;
 
        return 0;
 }
 
 
-void DNSSD_API
-CPrinterSetupWizardSheet::OnBrowse(
-                                                               DNSServiceRef                   inRef,
-                                                               DNSServiceFlags                 inFlags,
-                                                               uint32_t                                inInterfaceIndex,
-                                                               DNSServiceErrorType     inErrorCode,
-                                                               const char *                    inName, 
-                                                               const char *                    inType, 
-                                                               const char *                    inDomain,       
-                                                               void *                                  inContext )
-{
-       DEBUG_UNUSED(inRef);
-
-       CPrinterSetupWizardSheet        *       self;
-       Printer                                         *       printer;
-       EventHandlerList::iterator              it;
-       DWORD                                                   printerNameCount;
-       bool                                                    moreComing = (bool) (inFlags & kDNSServiceFlagsMoreComing);
-
-       require_noerr( inErrorCode, exit );
-       
-       self = reinterpret_cast <CPrinterSetupWizardSheet*>( inContext );
-       require_quiet( self, exit );
-
-       printer = self->LookUp(inName);
-
-       if (inFlags & kDNSServiceFlagsAdd)
-       {
-               OSStatus err;
-
-               if (printer != NULL)
-               {
-                       printer->refs++;
-               }
-               else
-               {
-                       try
-                       {
-                               printer = new Printer;
-                       }
-                       catch (...)
-                       {
-                               printer = NULL;
-                       }
-
-                       require_action( printer, exit, err = E_OUTOFMEMORY );
-
-                       printer->window         =       self;
-                       printer->ifi            =       inInterfaceIndex;
-                       printer->name           =       inName;
-                       err = UTF8StringToStringObject(inName, printer->displayName);
-                       check_noerr( err );
-                       printer->actualName     =       printer->displayName;
-
-                       //
-                       // Compare this name against printers that are already installed
-                       // to avoid name clashes.  Rename as necessary
-                       // to come up with a unique name.
-                       //
-                       printerNameCount = 2;
-
-                       for (;;)
-                       {
-                               PrinterNameMap::iterator it;
-
-                               it = self->m_printerNames.find(printer->actualName);
-
-                               if (it != self->m_printerNames.end())
-                               {
-                                       printer->actualName.Format(L"%s (%d)", printer->displayName, printerNameCount);
-                               }
-                               else
-                               {
-                                       break;
-                               }
-
-                               printerNameCount++;
-                       }
-
-                       printer->type           =       inType;
-                       printer->domain         =       inDomain;
-                       printer->installed      =       false;
-                       printer->deflt          =       false;
-                       printer->refs           =       1;
-                       
-                       self->m_printerList.push_back( printer );
-
-                       //
-                       // now invoke event handlers for AddPrinter event
-                       //
-                       for (it = self->m_eventHandlerList.begin(); it != self->m_eventHandlerList.end(); it++)
-                       {
-                               EventHandler * handler = *it;
-
-                               handler->OnAddPrinter(printer, moreComing);
-                       }
-               }
-       }
-       else
-       {
-               if ((printer != NULL) && (--printer->refs == 0))
-               {
-                       //
-                       // now invoke event handlers for RemovePrinter event
-                       //
-                       for (it = self->m_eventHandlerList.begin(); it != self->m_eventHandlerList.end(); it++)
-                       {
-                               EventHandler * handler = *it;
-
-                               handler->OnRemovePrinter(printer, moreComing);
-                       }
-
-                       self->m_printerList.remove(printer);
-
-                       //
-                       // check to see if we've selected this printer
-                       //
-                       if (self->m_selectedPrinter == printer)
-                       {
-                               //
-                               // this guy is being removed while we're resolving it...so let's 
-                               // stop the resolve
-                               //
-                               if (printer->serviceRef != NULL)
-                               {
-                                       self->StopResolve(printer);
-                               }
-
-                               self->m_selectedPrinter = NULL;
-                       }
-
-                       delete printer;
-               }
-       }
-
-exit:
-
-       return;
-}
-
-
-void DNSSD_API
-CPrinterSetupWizardSheet::OnResolve(
-                                                               DNSServiceRef                   inRef,
-                                                               DNSServiceFlags                 inFlags,
-                                                               uint32_t                                inInterfaceIndex,
-                                                               DNSServiceErrorType             inErrorCode,
-                                                               const char *                    inFullName,     
-                                                               const char *                    inHostName, 
-                                                               uint16_t                                inPort,
-                                                               uint16_t                                inTXTSize,
-                                                               const char *                    inTXT,
-                                                               void *                                  inContext )
-{
-       DEBUG_UNUSED(inFullName);
-       DEBUG_UNUSED(inInterfaceIndex);
-       DEBUG_UNUSED(inFlags);
-       DEBUG_UNUSED(inRef);
-
-       Printer                                         *       printer;
-       CPrinterSetupWizardSheet        *       self;
-       EventHandlerList::iterator              it1;
-       EventHandlerList::iterator              it2;
-       int                                                             idx;
-       OSStatus                                                err;
-
-       require_noerr( inErrorCode, exit );
-
-       printer = reinterpret_cast<Printer*>( inContext );
-       require_quiet( printer, exit);
-
-       self = printer->window;
-       require_quiet( self, exit );
-
-       err = self->StopResolve(printer);
-       require_noerr(err, exit);
-       
-       //
-       // hold on to the hostname...
-       //
-       err = UTF8StringToStringObject( inHostName, printer->hostname );
-       require_noerr( err, exit );
-
-       //
-       // <rdar://problem/3739200> remove the trailing dot on hostname
-       //
-       idx = printer->hostname.ReverseFind('.');
-
-       if ((idx > 1) && ((printer->hostname.GetLength() - 1) == idx))
-       {
-               printer->hostname.Delete(idx, 1);
-       }
-
-       //
-       // hold on to the port
-       //
-       printer->portNumber = ntohs(inPort);
-
-       //
-       // parse the text record.  we create a stringlist of text record
-       // entries that can be interrogated later
-       //
-       while (inTXTSize)
-       {
-               char buf[256];
-
-               unsigned char num = *inTXT;
-               check( (int) num < inTXTSize );
-
-               memset(buf, 0, sizeof(buf));
-               memcpy(buf, inTXT + 1, num);
-               
-               inTXTSize -= (num + 1);
-               inTXT += (num + 1);
-
-               CString elem;
-
-               err = UTF8StringToStringObject( buf, elem );
-               require_noerr( err, exit );
-
-               int curPos = 0;
-
-               CString key = elem.Tokenize(L"=", curPos);
-               CString val = elem.Tokenize(L"=", curPos);
-
-               key.MakeLower();
-
-               if ((key == L"usb_mfg") || (key == L"usb_manufacturer"))
-               {
-                       printer->usb_MFG = val;
-               }
-               else if ((key == L"usb_mdl") || (key == L"usb_model"))
-               {
-                       printer->usb_MDL = val;
-               }
-               else if (key == L"description")
-               {
-                       printer->description = val;
-               }
-               else if (key == L"product")
-               {
-                       printer->product = val;
-               }
-       }
-
-       //
-       // now invoke event handlers for Resolve event
-       //
-       it1 = self->m_eventHandlerList.begin();
-       it2 = self->m_eventHandlerList.end();
-
-       while (it1 != it2)
-       {
-               EventHandler * handler = *it1++;
-
-               handler->OnResolvePrinter(printer);
-       }
-
-exit:
-
-       return;
-}
-
-
-OSStatus
-CPrinterSetupWizardSheet::LoadPrinterNames()
-{
-       PBYTE           buffer  =       NULL;
-       OSStatus        err             = 0;
-
-       //
-       // rdar://problem/3701926 - Printer can't be installed twice
-       //
-       // First thing we want to do is make sure the printer isn't already installed.
-       // If the printer name is found, we'll try and rename it until we
-       // find a unique name
-       //
-       DWORD dwNeeded = 0, dwNumPrinters = 0;
-
-       BOOL ok = EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &dwNeeded, &dwNumPrinters);
-       err = translate_errno( ok, errno_compat(), kUnknownErr );
-
-       if ((err == ERROR_INSUFFICIENT_BUFFER) && (dwNeeded > 0))
-       {
-               try
-               {
-                       buffer = new unsigned char[dwNeeded];
-               }
-               catch (...)
-               {
-                       buffer = NULL;
-               }
-       
-               require_action( buffer, exit, kNoMemoryErr );
-               ok = EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, buffer, dwNeeded, &dwNeeded, &dwNumPrinters);
-               err = translate_errno( ok, errno_compat(), kUnknownErr );
-               require_noerr( err, exit );
-
-               for (DWORD index = 0; index < dwNumPrinters; index++)
-               {
-                       PRINTER_INFO_4 * lppi4 = (PRINTER_INFO_4*) (buffer + index * sizeof(PRINTER_INFO_4));
-
-                       m_printerNames[lppi4->pPrinterName] = lppi4->pPrinterName;
-               }
-       }
-
-exit:
-
-       if (buffer != NULL)
-       {
-               delete [] buffer;
-       }
-
-       return err;
-}
-
-
-OSStatus
-CPrinterSetupWizardSheet::StartResolve(Printer * printer)
-{
-       OSStatus err;
-
-       check( printer );
-
-       err = DNSServiceResolve( &printer->serviceRef, 0, 0, printer->name.c_str(), printer->type.c_str(), printer->domain.c_str(), (DNSServiceResolveReply) OnResolve, printer );
-       require_noerr( err, exit);
-
-       m_serviceRefList.push_back(printer->serviceRef);
-
-       err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(printer->serviceRef), m_hWnd, WM_SERVICE_EVENT, FD_READ|FD_CLOSE);
-       require_noerr( err, exit );
-
-       //
-       // set the cursor to arrow+hourglass
-       //
-       m_active = m_wait;
-       SetCursor(m_active);
-
-exit:
-
-       return err;
-}
-
-
-OSStatus
-CPrinterSetupWizardSheet::StopResolve(Printer * printer)
-{
-       OSStatus err;
-
-       check( printer );
-       check( printer->serviceRef );
-
-       m_serviceRefList.remove( printer->serviceRef );
-
-       err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(printer->serviceRef), m_hWnd, 0, 0);
-       check(err == 0);        
-
-       DNSServiceRefDeallocate( printer->serviceRef );
-
-       printer->serviceRef = NULL;
-       
-       //
-       // set the cursor back to normal
-       //
-       m_active = m_arrow;
-       SetCursor(m_active);
-
-       return kNoErr;
-}
-
-
-Printer*
-CPrinterSetupWizardSheet::LookUp(const char * inName)
-{
-       PrinterList::iterator it1 = m_printerList.begin();
-       PrinterList::iterator it2 = m_printerList.end();
-
-       while (it1 != it2)
-       {
-               Printer * printer = *it1++;
-
-               if (printer->name == inName)
-               {
-                       return printer;
-               }
-       }
-
-       return NULL;
-}
-
-
 unsigned WINAPI
-CPrinterSetupWizardSheet::InstallPrinterThread( LPVOID inParam )
-{
-       check( inParam );
-               
+CPrinterSetupWizardSheet::InstallDriverThread( LPVOID inParam )
+{      
        Printer                 *       printer = (Printer*) inParam;
-       CString                         actualName;
-       CString                         command;
        DWORD                           exitCode = 0;
        DWORD                           dwResult;
        OSStatus                        err;
@@ -1040,46 +579,57 @@ CPrinterSetupWizardSheet::InstallPrinterThread( LPVOID inParam )
        PROCESS_INFORMATION pi;
        BOOL                            ok;
 
-       ZeroMemory( &si, sizeof(si) );
-       si.cb = sizeof(si);
-       ZeroMemory( &pi, sizeof(pi) );
+       check( printer );
+       check( m_self );
 
        //
-       // <rdar://problem/3764873> Escape '\', '@', '"' characters which seem to cause problems for printui
+       // because we're calling endthreadex(), C++ objects won't be cleaned up
+       // correctly.  we'll nest the CString 'command' inside a block so
+       // that it's destructor will be invoked.
        //
+       {
+               CString command;
 
-       actualName = printer->actualName;
+               ZeroMemory( &si, sizeof(si) );
+               si.cb = sizeof(si);
+               ZeroMemory( &pi, sizeof(pi) );
 
-       actualName.Replace(L"\\", L"\\\\");
-       actualName.Replace(L"@", L"\\@");
-       actualName.Replace(L"\"", L"\\\"");
-       
-       command.Format(L"rundll32.exe printui.dll,PrintUIEntry /if /b \"%s\" /f \"%s\" /r \"%s\" /m \"%s\"", (LPCTSTR) actualName, (LPCTSTR) printer->infFileName, (LPCTSTR) printer->portName, (LPCTSTR) printer->model);
+               command.Format(L"rundll32.exe printui.dll,PrintUIEntry /ia /m \"%s\" /f \"%s\"", (LPCTSTR) printer->model, (LPCTSTR) printer->infFileName );
 
-       ok = CreateProcess(NULL, command.GetBuffer(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
-       err = translate_errno( ok, errno_compat(), kUnknownErr );
-       require_noerr( err, exit );
+               ok = CreateProcess(NULL, command.GetBuffer(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
+               err = translate_errno( ok, errno_compat(), kUnknownErr );
+               require_noerr( err, exit );
 
-       dwResult = WaitForSingleObject( pi.hProcess, INFINITE );
-       translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr );
-       require_noerr( err, exit );
+               dwResult = WaitForSingleObject( pi.hProcess, INFINITE );
+               translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr );
+               require_noerr( err, exit );
 
-       ok = GetExitCodeProcess( pi.hProcess, &exitCode );
-       err = translate_errno( ok, errno_compat(), kUnknownErr );
-       require_noerr( err, exit );
+               ok = GetExitCodeProcess( pi.hProcess, &exitCode );
+               err = translate_errno( ok, errno_compat(), kUnknownErr );
+               require_noerr( err, exit );
+       }
+
+exit:
 
        //
        // Close process and thread handles. 
        //
-       CloseHandle( pi.hProcess );
-       CloseHandle( pi.hThread );
+       if ( pi.hProcess )
+       {
+               CloseHandle( pi.hProcess );
+       }
 
-exit:
+       if ( pi.hThread )
+       {
+               CloseHandle( pi.hThread );
+       }
 
        //
        // alert the main thread
        //
-       printer->window->PostMessage( WM_PROCESS_EVENT, err, exitCode );
+       m_self->PostMessage( WM_PROCESS_EVENT, err, exitCode );
+
+       _endthreadex_compat( 0 );
 
        return 0;
 }
index e1077aae623be6bcf72c226cb6de89212be144a1..be4bd6ae5a89eb8e20bd4e3dc54fe5e3b6343889 100644 (file)
     Change History (most recent first):
     
 $Log: PrinterSetupWizardSheet.h,v $
+Revision 1.6  2005/01/03 19:05:01  shersche
+Store pointer to instance of wizard sheet so that print driver install thread sends a window message to the correct window
+
+Revision 1.5  2004/12/29 18:53:38  shersche
+<rdar://problem/3725106>
+<rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
+Bug #: 3725106, 3737413
+
 Revision 1.4  2004/07/13 21:24:23  rpantos
 Fix for <rdar://problem/3701120>.
 
@@ -71,14 +79,8 @@ public:
 
        CPrinterSetupWizardSheet(UINT nIDCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0);
        virtual ~CPrinterSetupWizardSheet();
-       
-       int
-       InstallEventHandler(EventHandler * handler);
 
-       int
-       RemoveEventHandler(EventHandler * handler);
-
-       OSStatus
+       void
        SetSelectedPrinter(Printer * printer);
 
        Printer*
@@ -90,12 +92,6 @@ public:
        HCURSOR
        GetCursor();
 
-       //
-       // handles socket events for DNSService operations
-       //
-       virtual LONG
-       OnServiceEvent(WPARAM inWParam, LPARAM inLParam);
-
        //
        // handles end of process event
        //
@@ -117,6 +113,10 @@ public:
        afx_msg void
        OnOK();
 
+       HCURSOR                                 m_active;
+       HCURSOR                                 m_arrow;
+       HCURSOR                                 m_wait;
+
 protected:
        DECLARE_MESSAGE_MAP()
        CFirstPage              m_pgFirst;
@@ -124,72 +124,30 @@ protected:
        CThirdPage              m_pgThird;
        CFourthPage             m_pgFourth;
 
-       static void DNSSD_API
-       OnBrowse(
-               DNSServiceRef                   inRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType     inErrorCode,
-               const char *                    inName, 
-               const char *                    inType, 
-               const char *                    inDomain,       
-               void *                                  inContext );
-
-       static void DNSSD_API
-       OnResolve(
-               DNSServiceRef                   inRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inErrorCode,
-               const char *                    inFullName,     
-               const char *                    inHostName, 
-               uint16_t                                inPort,
-               uint16_t                                inTXTSize,
-               const char *                    inTXT,
-               void *                                  inContext );
+       void
+       OnServiceResolved(
+               Service                         *       service);
 
        void Init(void);
 
 private:
 
        OSStatus
-       LoadPrinterNames();
+       InstallPrinter(Printer * printer);
 
        OSStatus
-       StartResolve(Printer * printer);
+       InstallPrinterPDLAndLPR(Printer * printer, Service * service, DWORD protocol);
 
        OSStatus
-       StopResolve(Printer * printer);
-
-       Printer*
-       LookUp(const char * inName);
-
-       OSStatus
-       InstallPrinter(Printer * printer);
+       InstallPrinterIPP(Printer * printer, Service * service);
 
        static unsigned WINAPI
-       InstallPrinterThread( LPVOID inParam );
-
-
-       typedef std::list<Printer*>                     PrinterList;
-       typedef std::list<EventHandler*>        EventHandlerList;
-       typedef std::list<DNSServiceRef>        ServiceRefList;
-       typedef std::map<CString,CString>       PrinterNameMap;
-
-       Printer *       m_selectedPrinter;
-       
-       PrinterNameMap                  m_printerNames;
-       PrinterList                             m_printerList;
-       EventHandlerList                m_eventHandlerList;
-       ServiceRefList                  m_serviceRefList;
-
-       bool                                    m_processFinished;
+       InstallDriverThread( LPVOID inParam );
 
-       HCURSOR                                 m_active;
-       HCURSOR                                 m_arrow;
-       HCURSOR                                 m_wait;
-
-       DNSServiceRef                   m_pdlBrowser;
+       static CPrinterSetupWizardSheet *       m_self;
+       Printer                                                 *       m_selectedPrinter;
+       bool                                                            m_driverThreadFinished;
+       DWORD                                                           m_driverThreadExitCode;
 };
 
 
@@ -205,3 +163,10 @@ CPrinterSetupWizardSheet::GetCursor()
 {
        return m_active;
 }
+
+
+// Service Types
+
+#define        kPDLServiceType         "_pdl-datastream._tcp."
+#define kLPRServiceType                "_printer._tcp."
+#define kIPPServiceType                "_ipp._tcp."
index abf4fa0f327a1480be486c386161841c51cd2ffa..9e3720a6777c62577a024b5e740652171d2152c0 100644 (file)
     Change History (most recent first):
     
 $Log: SecondPage.cpp,v $
+Revision 1.10  2005/01/20 19:54:38  shersche
+Fix parse error when text record is NULL
+
+Revision 1.9  2005/01/06 08:13:50  shersche
+Don't use moreComing flag to determine number of text record, disregard queue name if qtotal isn't defined, don't disregard queue name if "rp" is the only key specified
+
+Revision 1.8  2005/01/04 21:09:14  shersche
+Fix problems in parsing text records. Fix problems in remove event handling. Ensure that the same service can't be resolved more than once.
+
+Revision 1.7  2004/12/31 07:25:27  shersche
+Tidy up printer management, and fix memory leaks when hitting 'Cancel'
+
+Revision 1.6  2004/12/30 01:24:02  shersche
+<rdar://problem/3906182> Remove references to description key
+Bug #: 3906182
+
+Revision 1.5  2004/12/30 01:02:47  shersche
+<rdar://problem/3734478> Add Printer information box that displays description and location information when printer name is selected
+Bug #: 3734478
+
+Revision 1.4  2004/12/29 18:53:38  shersche
+<rdar://problem/3725106>
+<rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
+Bug #: 3725106, 3737413
+
 Revision 1.3  2004/09/13 21:26:15  shersche
 <rdar://problem/3796483> Use the moreComing flag to determine whether drawing should take place in OnAddPrinter and OnRemovePrinter callbacks
 Bug #: 3796483
@@ -43,16 +68,23 @@ First checked in
 #include "PrinterSetupWizardSheet.h"
 #include "SecondPage.h"
 #include "DebugServices.h"
+#include "WinServices.h"
+#include <winspool.h>
 
 // local variable is initialize but not referenced
 #pragma warning(disable:4189)
 
+#define WM_SERVICE_EVENT       ( WM_USER + 0x101 )
 
 // CSecondPage dialog
 
 IMPLEMENT_DYNAMIC(CSecondPage, CPropertyPage)
 CSecondPage::CSecondPage()
-       : CPropertyPage(CSecondPage::IDD)
+       : CPropertyPage(CSecondPage::IDD),
+       m_pdlBrowser( NULL ),
+       m_lprBrowser( NULL ),
+       m_ippBrowser( NULL ),
+       m_selected( NULL )
 {
        m_psp.dwFlags &= ~(PSP_HASHELP);
        m_psp.dwFlags |= PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE;
@@ -64,10 +96,67 @@ CSecondPage::CSecondPage()
        m_emptyListItem         =       NULL;
        m_initialized           =       false;
        m_waiting                       =       false;
+
+       LoadPrinterNames();
 }
 
+
 CSecondPage::~CSecondPage()
 {
+       StopBrowse();
+}
+
+
+OSStatus
+CSecondPage::LoadPrinterNames()
+{
+       PBYTE           buffer  =       NULL;
+       OSStatus        err             = 0;
+
+       //
+       // rdar://problem/3701926 - Printer can't be installed twice
+       //
+       // First thing we want to do is make sure the printer isn't already installed.
+       // If the printer name is found, we'll try and rename it until we
+       // find a unique name
+       //
+       DWORD dwNeeded = 0, dwNumPrinters = 0;
+
+       BOOL ok = EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &dwNeeded, &dwNumPrinters);
+       err = translate_errno( ok, errno_compat(), kUnknownErr );
+
+       if ((err == ERROR_INSUFFICIENT_BUFFER) && (dwNeeded > 0))
+       {
+               try
+               {
+                       buffer = new unsigned char[dwNeeded];
+               }
+               catch (...)
+               {
+                       buffer = NULL;
+               }
+       
+               require_action( buffer, exit, kNoMemoryErr );
+               ok = EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, buffer, dwNeeded, &dwNeeded, &dwNumPrinters);
+               err = translate_errno( ok, errno_compat(), kUnknownErr );
+               require_noerr( err, exit );
+
+               for (DWORD index = 0; index < dwNumPrinters; index++)
+               {
+                       PRINTER_INFO_4 * lppi4 = (PRINTER_INFO_4*) (buffer + index * sizeof(PRINTER_INFO_4));
+
+                       m_printerNames[lppi4->pPrinterName] = lppi4->pPrinterName;
+               }
+       }
+
+exit:
+
+       if (buffer != NULL)
+       {
+               delete [] buffer;
+       }
+
+       return err;
 }
 
 
@@ -85,23 +174,7 @@ CSecondPage::InitBrowseList()
        //
        text.LoadString(IDS_NO_RENDEZVOUS_PRINTERS);
 
-       m_emptyListItem = m_browseList.InsertItem( text, 0, 0, NULL, TVI_FIRST );
-
-       //
-       // this will remove everything else in the list...we might be navigating
-       // back to this window, and the browse list might have changed since
-       // we last displayed it.
-       //
-       if ( m_emptyListItem )
-       {
-               HTREEITEM item = m_browseList.GetNextVisibleItem( m_emptyListItem );
-  
-               while ( item )
-               {
-                       m_browseList.DeleteItem( item );
-                       item = m_browseList.GetNextVisibleItem( m_emptyListItem );
-               }
-       }
+       LoadTextAndDisableWindow( text );
 
        //
        // disable the next button until there's a printer to select
@@ -109,9 +182,9 @@ CSecondPage::InitBrowseList()
        psheet->SetWizardButtons(PSWIZB_BACK);
 
        //
-       // disable the window until there's a printer to select
+       // disable the printer information box
        //
-       m_browseList.EnableWindow( FALSE );
+       SetPrinterInformationState( FALSE );
 
 exit:
 
@@ -119,222 +192,1002 @@ exit:
 }
 
 
-void CSecondPage::DoDataExchange(CDataExchange* pDX)
+OSStatus
+CSecondPage::StartOperation( DNSServiceRef ref )
 {
-       CPropertyPage::DoDataExchange(pDX);
-       DDX_Control(pDX, IDC_BROWSE_LIST, m_browseList);
+       OSStatus err;
+
+       err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(ref), m_hWnd, WM_SERVICE_EVENT, FD_READ|FD_CLOSE);
+       require_noerr( err, exit );
+
+       m_serviceRefList.push_back( ref );
+
+exit:
+
+       return err;
 }
 
 
-afx_msg BOOL
-CSecondPage::OnSetCursor(CWnd * pWnd, UINT nHitTest, UINT message)
+OSStatus
+CSecondPage::StopOperation( DNSServiceRef & ref )
 {
-       DEBUG_UNUSED(pWnd);
-       DEBUG_UNUSED(nHitTest);
-       DEBUG_UNUSED(message);
+       OSStatus err = kNoErr;
 
-       CPrinterSetupWizardSheet        *       psheet;
+       if ( ref )
+       {
+               m_serviceRefList.remove( ref );
 
-       psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
-       require_quiet( psheet, exit );
+               if ( IsWindow( m_hWnd ) )
+               {
+                       err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD( ref ), m_hWnd, 0, 0 );
+                       require_noerr( err, exit );
+               }
 
-       SetCursor(psheet->GetCursor());
+               DNSServiceRefDeallocate( ref );
+               ref = NULL;
+       }
 
 exit:
 
-       return TRUE;
+       return err;
 }
 
 
-BOOL
-CSecondPage::OnSetActive()
+Printer*
+CSecondPage::Lookup(const char * inName)
 {
-       CString                                                 noPrinters;
-       CPrinterSetupWizardSheet        *       psheet;
+       check( IsWindow( m_hWnd ) );
+       check( inName );
+
+       HTREEITEM item = m_browseList.GetChildItem( TVI_ROOT );\r
+       while ( item )\r
+       {\r
+               Printer *       printer;\r
+               DWORD_PTR       data;\r
+\r
+               data = m_browseList.GetItemData( item );\r
+               printer = reinterpret_cast<Printer*>(data);\r
+\r
+               if ( printer && ( printer->name == inName ) )
+               {
+                       return printer;
+               }
+\r
+               item = m_browseList.GetNextItem( item, TVGN_NEXT );
+       }
 
-       psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
-       require_quiet( psheet, exit );
-  
-       //
-       // initialize the browse list...this will remove everything currently
-       // in it, and add the no rendezvous printers item
-       //
-       InitBrowseList();
+       return NULL;
+}
+
+
+OSStatus
+CSecondPage::StartBrowse()
+{
+       OSStatus err;
 
        //
-       // this will invoke OnAddPrinter for all the printers that we have
-       // browsed
+       // setup the DNS-SD browsing
        //
-       psheet->InstallEventHandler(this);
+       err = DNSServiceBrowse( &m_pdlBrowser, 0, 0, kPDLServiceType, NULL, OnBrowse, this );
+       require_noerr( err, exit );
+
+       err = StartOperation( m_pdlBrowser );
+       require_noerr( err, exit );
+
+       err = DNSServiceBrowse( &m_lprBrowser, 0, 0, kLPRServiceType, NULL, OnBrowse, this );
+       require_noerr( err, exit );
+
+       err = StartOperation( m_lprBrowser );
+       require_noerr( err, exit );
+
+       err = DNSServiceBrowse( &m_ippBrowser, 0, 0, kIPPServiceType, NULL, OnBrowse, this );
+       require_noerr( err, exit );
+
+       err = StartOperation( m_ippBrowser );
+       require_noerr( err, exit );
 
 exit:
 
-       return CPropertyPage::OnSetActive();
+       return err;
 }
 
 
-BOOL
-CSecondPage::OnKillActive()
+OSStatus
+CSecondPage::StopBrowse()
 {
-       CPrinterSetupWizardSheet * psheet;
+       OSStatus err;
 
-       psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
-       require_quiet( psheet, exit );
+       err = StopOperation( m_pdlBrowser );
+       require_noerr( err, exit );
 
-       //
-       // we don't want our event handlers called when we don't have
-       // anywhere to put the data
-       //
-       psheet->RemoveEventHandler(this);
+       err = StopOperation( m_lprBrowser );
+       require_noerr( err, exit );
+
+       err = StopOperation( m_ippBrowser );
+       require_noerr( err, exit );
+
+       while ( m_printers.size() > 0 )
+       {
+               Printer * printer = m_printers.front();
+
+               m_printers.pop_front();
+
+               if ( printer->resolving )
+               {
+                       StopResolve( printer );
+               }
+
+               delete printer;
+       }
 
 exit:
 
-       return CPropertyPage::OnKillActive();
+       return err;
 }
 
 
-BEGIN_MESSAGE_MAP(CSecondPage, CPropertyPage)
-       ON_NOTIFY(TVN_SELCHANGED, IDC_BROWSE_LIST, OnTvnSelchangedBrowseList)
-       ON_WM_SETCURSOR()
-END_MESSAGE_MAP()
+OSStatus
+CSecondPage::StartResolve( Printer * printer )
+{
+       CPrinterSetupWizardSheet        *       psheet;
+       OSStatus                                                err = kNoErr;
+       Services::iterator                              it;
+
+       psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+       require_quiet( psheet, exit );
 
+       check( printer );
 
-// Printer::EventHandler implementation
-void
-CSecondPage::OnAddPrinter(
-                                               Printer *       printer,
-                                               bool                    moreComing)
+       for ( it = printer->services.begin(); it != printer->services.end(); it++ )
+       {
+               if ( (*it)->serviceRef == NULL )
+               {
+                       err = StartResolve( *it );
+                       require_noerr( err, exit );
+               }
+       }
+
+exit:
+
+       return err;
+}
+
+
+OSStatus
+CSecondPage::StartResolve( Service * service )
 {
-       check( IsWindow( m_hWnd ) );
+       CPrinterSetupWizardSheet        *       psheet;
+       OSStatus                                                err = kNoErr;
 
-       m_browseList.SetRedraw(FALSE);
+       psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+       require_quiet( psheet, exit );
 
-       printer->item = m_browseList.InsertItem(printer->displayName);
+       check( service->serviceRef == NULL );
 
-       m_browseList.SetItemData( printer->item, (DWORD_PTR) printer );
-       
-       m_browseList.SortChildren(TVI_ROOT);
+       //
+       // clean out any queues that were collected during a previous
+       // resolve
+       //
 
+       service->EmptyQueues();
+
+       //
+       // now start the new resolve
        //
-       // if the searching item is still in the list
-       // get rid of it
+
+       err = DNSServiceResolve( &service->serviceRef, 0, 0, service->printer->name.c_str(), service->type.c_str(), service->domain.c_str(), (DNSServiceResolveReply) OnResolve, service );
+       require_noerr( err, exit );
+
+       err = StartOperation( service->serviceRef );
+       require_noerr( err, exit );
+
        //
-       // note that order is important here.  Insert the printer
-       // item before removing the placeholder so we always have
-       // an item in the list to avoid experiencing the bug
-       // in Microsoft's implementation of CTreeCtrl
+       // If we're not currently resolving, then disable the next button
+       // and set the cursor to hourglass
        //
-       if (m_emptyListItem != NULL)
-       {
-               m_browseList.DeleteItem(m_emptyListItem);
-               m_emptyListItem = NULL;
-               m_browseList.EnableWindow(TRUE);
-       }
 
-       if (!moreComing)
+       if ( !service->printer->resolving )
        {
-               m_browseList.SetRedraw(TRUE);
-               m_browseList.Invalidate();
+               psheet->SetWizardButtons( PSWIZB_BACK );
+
+               psheet->m_active = psheet->m_wait;
+               SetCursor(psheet->m_active);
        }
+
+       service->printer->resolving++;
+
+exit:
+
+       return err;
 }
 
 
-void
-CSecondPage::OnRemovePrinter(
-                                               Printer *       printer,
-                                               bool                    moreComing)
+OSStatus
+CSecondPage::StopResolve(Printer * printer)
 {
-       check( IsWindow( m_hWnd ) );
+       OSStatus err = kNoErr;
 
-       m_browseList.SetRedraw(FALSE);
+       check( printer );
 
-       //
-       // check to make sure if we're the only item in the control...i.e.
-       // the list size is 1.
-       //
-       if (m_browseList.GetCount() > 1)
-       {
-               //
-               // if we're not the only thing in the list, then
-               // simply remove it from the list
-               //
-               m_browseList.DeleteItem( printer->item );
-       }
-       else
-       {
-               //
-               // if we're the only thing in the list, then redisplay
-               // it with the no rendezvous printers message
-               //
-               InitBrowseList();
-       }
+       Services::iterator it;
 
-       if (!moreComing)
+       for ( it = printer->services.begin(); it != printer->services.end(); it++ )
        {
-               m_browseList.SetRedraw(TRUE);
-               m_browseList.Invalidate();
+               if ( (*it)->serviceRef )
+               {
+                       err = StopResolve( *it );
+                       require_noerr( err, exit );
+               }
        }
+
+exit:
+
+       return err;
 }
 
 
-void
-CSecondPage::OnResolvePrinter(
-                                               Printer * printer)
+OSStatus
+CSecondPage::StopResolve( Service * service )
 {
-       DEBUG_UNUSED(printer);
+       OSStatus err;
 
-       check( IsWindow( m_hWnd ) );
+       check( service->serviceRef );
 
-       CPrinterSetupWizardSheet * psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
-       require_quiet( psheet, exit );
-   
-       //
-       // setup the sheet to enable the next button if we've successfully
-       // resolved
-       //
-       psheet->SetWizardButtons( PSWIZB_BACK|PSWIZB_NEXT );
+       err = StopOperation( service->serviceRef );
+       require_noerr( err, exit );
+
+       service->printer->resolving--;
 
 exit:
 
-       return;
+       return err;
 }
 
 
-void CSecondPage::OnTvnSelchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult)
+void CSecondPage::DoDataExchange(CDataExchange* pDX)
 {
-       LPNMTREEVIEW                                    pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
-       CPrinterSetupWizardSheet        *       psheet;
-       int                                                             err = 0;
+       CPropertyPage::DoDataExchange(pDX);
+       DDX_Control(pDX, IDC_BROWSE_LIST, m_browseList);
+       DDX_Control(pDX, IDC_PRINTER_INFORMATION, m_printerInformation);\r
+       DDX_Control(pDX, IDC_DESCRIPTION_LABEL, m_descriptionLabel);\r
+       DDX_Control(pDX, IDC_DESCRIPTION_FIELD, m_descriptionField);\r
+       DDX_Control(pDX, IDC_LOCATION_LABEL, m_locationLabel);\r
+       DDX_Control(pDX, IDC_LOCATION_FIELD, m_locationField);\r
+}
 
-       HTREEITEM item = m_browseList.GetSelectedItem();
-       require_quiet( item, exit );
+
+afx_msg BOOL
+CSecondPage::OnSetCursor(CWnd * pWnd, UINT nHitTest, UINT message)
+{
+       DEBUG_UNUSED(pWnd);
+       DEBUG_UNUSED(nHitTest);
+       DEBUG_UNUSED(message);
+
+       CPrinterSetupWizardSheet * psheet;
 
        psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
-       require_action( psheet, exit, err = kUnknownErr );      
+       require_quiet( psheet, exit );
 
-       Printer * printer;
+       SetCursor(psheet->GetCursor());
 
-       printer = reinterpret_cast<Printer*>(m_browseList.GetItemData( item ) );
-       require_quiet( printer, exit );
+exit:
+
+       return TRUE;
+}
+
+
+BOOL
+CSecondPage::OnSetActive()
+{
+       CPrinterSetupWizardSheet        *       psheet;
+       Printer                                         *       printer;
+       OSStatus                                                err = kNoErr;
+
+       psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+       require_action( psheet, exit, err = kUnknownErr );
+
+       if ( ( printer = psheet->GetSelectedPrinter() ) != NULL )
+       {
+               psheet->SetSelectedPrinter( NULL );
+               delete printer;
+       }
 
        //
-       // this call will trigger a resolve.  When the resolve is complete,
-       // our OnResolve will be called.
+       // initialize the browse list...this will remove everything currently
+       // in it, and add the no rendezvous printers item
        //
-       err = psheet->SetSelectedPrinter(printer);
-       require_noerr( err, exit );
+       InitBrowseList();
 
        //
-       // setup the sheet to disable the next button until we've successfully
-       // resolved this printer
+       // start browing
        //
-       psheet->SetWizardButtons( PSWIZB_BACK );
+       err = StartBrowse();
+       require_noerr( err, exit );
 
 exit:
 
-       if (err != 0)
+       if ( err != kNoErr )
        {
-               CString text;
+               if ( err == kDNSServiceErr_Firewall )
+               {
+                       CString text, caption;
+
+                       text.LoadString( IDS_FIREWALL );
+                       caption.LoadString( IDS_FIREWALL_CAPTION );
+
+                       MessageBox(text, caption, MB_OK|MB_ICONEXCLAMATION);
+               }
+               else
+               {
+                       CPrinterSetupWizardSheet::WizardException exc;
+                       
+                       exc.text.LoadString( IDS_NO_MDNSRESPONDER_SERVICE_TEXT );
+                       exc.caption.LoadString( IDS_ERROR_CAPTION );
+                       
+                       throw(exc);
+               }
+       }
+
+       return CPropertyPage::OnSetActive();
+}
+
+
+BOOL
+CSecondPage::OnKillActive()
+{
+       OSStatus err = kNoErr;
+
+       if ( m_selected )
+       {
+               CPrinterSetupWizardSheet * psheet;
+
+               psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+               require_quiet( psheet, exit );
+
+               psheet->SetSelectedPrinter( m_selected );
+               m_printers.remove( m_selected );
+               m_selected = NULL;
+       }
+
+       err = StopBrowse();
+       require_noerr( err, exit );
+
+exit:
+
+       return CPropertyPage::OnKillActive();
+}
+
+
+void DNSSD_API
+CSecondPage::OnBrowse(
+                               DNSServiceRef                   inRef,
+                               DNSServiceFlags                 inFlags,
+                               uint32_t                                inInterfaceIndex,
+                               DNSServiceErrorType     inErrorCode,
+                               const char *                    inName, 
+                               const char *                    inType, 
+                               const char *                    inDomain,       
+                               void *                                  inContext )
+{
+       DEBUG_UNUSED(inRef);
+
+       CSecondPage     *       self;
+       bool                    moreComing = (bool) (inFlags & kDNSServiceFlagsMoreComing);
+
+       require_noerr( inErrorCode, exit );
+       
+       self = reinterpret_cast <CSecondPage*>( inContext );
+       require_quiet( self, exit );
+
+       if ( inFlags & kDNSServiceFlagsAdd )
+       {
+               self->OnAddPrinter( inInterfaceIndex, inName, inType, inDomain, moreComing );
+       }
+       else
+       {
+               self->OnRemovePrinter( inName, inType, inDomain, moreComing );
+       }
+
+exit:
+       
+       return;
+}
+
+
+void DNSSD_API
+CSecondPage::OnResolve(
+                               DNSServiceRef                   inRef,
+                               DNSServiceFlags                 inFlags,
+                               uint32_t                                inInterfaceIndex,
+                               DNSServiceErrorType             inErrorCode,
+                               const char *                    inFullName,     
+                               const char *                    inHostName, 
+                               uint16_t                                inPort,
+                               uint16_t                                inTXTSize,
+                               const char *                    inTXT,
+                               void *                                  inContext )
+{
+       DEBUG_UNUSED(inFullName);
+       DEBUG_UNUSED(inInterfaceIndex);
+       DEBUG_UNUSED(inFlags);
+       DEBUG_UNUSED(inRef);
+
+       CSecondPage     *       self;
+       Service         *       service;
+       Queue           *       q;
+       bool                    qtotalDefined = false;
+       uint32_t                qpriority = kDefaultPriority;
+       CString                 qname;
+       int                             idx;
+       OSStatus                err;
+
+       require_noerr( inErrorCode, exit );
+
+       service = reinterpret_cast<Service*>( inContext );
+       require_quiet( service, exit);
+
+       check( service->refs != 0 );
+
+       self = service->printer->window;
+       require_quiet( self, exit );
+
+       err = self->StopOperation( service->serviceRef );
+       require_noerr( err, exit );
+       
+       //
+       // hold on to the hostname...
+       //
+       err = UTF8StringToStringObject( inHostName, service->hostname );
+       require_noerr( err, exit );
+
+       //
+       // <rdar://problem/3739200> remove the trailing dot on hostname
+       //
+       idx = service->hostname.ReverseFind('.');
+
+       if ((idx > 1) && ((service->hostname.GetLength() - 1) == idx))
+       {
+               service->hostname.Delete(idx, 1);
+       }
+
+       //
+       // hold on to the port
+       //
+       service->portNumber = ntohs(inPort);
+
+       //
+       // parse the text record.
+       //
+
+       err = self->ParseTextRecord( service, inTXTSize, inTXT, qtotalDefined, qname, qpriority );
+       require_noerr( err, exit );
+
+       if ( service->qtotal == 1 )
+       {       
+               //
+               // create a new queue
+               //
+               try
+               {
+                       q = new Queue;
+               }
+               catch (...)
+               {
+                       q = NULL;
+               }
+
+               require_action( q, exit, err = E_OUTOFMEMORY );
+
+               if ( qtotalDefined )
+               {
+                       q->name = qname;
+               }
+
+               q->priority = qpriority;
+               
+               service->queues.push_back( q );
+
+               //
+               // we've completely resolved this service
+               //
+
+               self->OnResolveService( service );
+       }
+       else
+       {
+               //
+               // if qtotal is more than 1, then we need to get additional
+               // text records.  if not, then this service is considered
+               // resolved
+               //
+
+               err = DNSServiceQueryRecord(&service->serviceRef, 0, inInterfaceIndex, inFullName, kDNSServiceType_TXT, kDNSServiceClass_IN, OnQuery, (void*) service );
+               require_noerr( err, exit );
+
+               err = self->StartOperation( service->serviceRef );
+               require_noerr( err, exit );
+       }
+
+exit:
+
+       return;
+}
+
+
+void DNSSD_API
+CSecondPage::OnQuery(
+                               DNSServiceRef           inRef, 
+                               DNSServiceFlags         inFlags, 
+                               uint32_t                        inInterfaceIndex, 
+                               DNSServiceErrorType inErrorCode,
+                               const char              *       inFullName, 
+                               uint16_t                        inRRType, 
+                               uint16_t                        inRRClass, 
+                               uint16_t                        inRDLen, 
+                               const void              *       inRData, 
+                               uint32_t                        inTTL, 
+                               void                    *       inContext)
+{
+       DEBUG_UNUSED( inTTL );
+       DEBUG_UNUSED( inRRClass );
+       DEBUG_UNUSED( inRRType );
+       DEBUG_UNUSED( inFullName );
+       DEBUG_UNUSED( inInterfaceIndex );
+       DEBUG_UNUSED( inRef );
+
+       Service         *       service = NULL;
+       Queue           *       q;
+       CSecondPage     *       self;
+       bool                    qtotalDefined = false;
+       bool                    moreComing = (bool) (inFlags & kDNSServiceFlagsMoreComing);
+       OSStatus                err = kNoErr;
+
+       require_noerr( inErrorCode, exit );
+
+       service = reinterpret_cast<Service*>( inContext );
+       require_quiet( service, exit);
+
+       self = service->printer->window;
+       require_quiet( self, exit );
+
+       if ( ( inFlags & kDNSServiceFlagsAdd ) && ( inRDLen > 0 ) && ( inRData != NULL ) )
+       {
+               const char * inTXT = ( const char * ) inRData;
+
+               //
+               // create a new queue
+               //
+               try
+               {
+                       q = new Queue;
+               }
+               catch (...)
+               {
+                       q = NULL;
+               }
+
+               require_action( q, exit, err = E_OUTOFMEMORY );
+
+               err = service->printer->window->ParseTextRecord( service, inRDLen, inTXT, qtotalDefined, q->name, q->priority );
+               require_noerr( err, exit );
+
+               if ( !qtotalDefined )
+               {
+                       q->name = L"";
+               }
+
+               //
+               // add this queue
+               //
+
+               service->queues.push_back( q );
+
+               if ( service->queues.size() == service->qtotal )
+               {
+                       //
+                       // else if moreComing is not set, then we're going
+                       // to assume that we're done
+                       //
+
+                       self->StopOperation( service->serviceRef );
+
+                       //
+                       // sort the queues
+                       //
+
+                       service->queues.sort( OrderQueueFunc );
+
+                       //
+                       // we've completely resolved this service
+                       //
+
+                       self->OnResolveService( service );
+               }
+       }
+
+exit:
+
+       if ( err && service && ( service->serviceRef != NULL ) )
+       {
+               service->printer->window->StopOperation( service->serviceRef );
+       }
+
+       return;
+}
+
+
+BEGIN_MESSAGE_MAP(CSecondPage, CPropertyPage)
+       ON_MESSAGE( WM_SERVICE_EVENT, OnServiceEvent )
+       ON_NOTIFY(TVN_SELCHANGED, IDC_BROWSE_LIST, OnTvnSelchangedBrowseList)
+       ON_WM_SETCURSOR()
+END_MESSAGE_MAP()
+
+
+// Printer::EventHandler implementation
+OSStatus
+CSecondPage::OnAddPrinter(
+                               uint32_t                inInterfaceIndex,
+                               const char *    inName, 
+                               const char *    inType, 
+                               const char *    inDomain,
+                               bool                    moreComing)
+{
+       Printer                                         *       printer;
+       Service                                         *       service;
+       CPrinterSetupWizardSheet        *       psheet;
+       DWORD                                                   printerNameCount;
+       bool                                                    newPrinter = false;
+       OSStatus                                                err = kNoErr;
+
+       check( IsWindow( m_hWnd ) );
+
+       m_browseList.SetRedraw(FALSE);
+
+       psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+       require_quiet( psheet, exit );
+
+       printer = Lookup( inName );
+
+       if (printer == NULL)
+       {
+               try
+               {
+                       printer = new Printer;
+               }
+               catch (...)
+               {
+                       printer = NULL;
+               }
+
+               require_action( printer, exit, err = E_OUTOFMEMORY );
+
+               printer->window         =       this;
+               printer->name           =       inName;
+               
+               err = UTF8StringToStringObject(inName, printer->displayName);
+               check_noerr( err );
+               printer->actualName     =       printer->displayName;
+               printer->installed      =       false;
+               printer->deflt          =       false;
+               printer->resolving      =       0;
+
+               //
+               // Compare this name against printers that are already installed
+               // to avoid name clashes.  Rename as necessary
+               // to come up with a unique name.
+               //
+               printerNameCount = 2;
+
+               for (;;)
+               {
+                       PrinterNameMap::iterator it;
+
+                       it = m_printerNames.find(printer->actualName);
+
+                       if (it != m_printerNames.end())
+                       {
+                               printer->actualName.Format(L"%s (%d)", printer->displayName, printerNameCount);
+                       }
+                       else
+                       {
+                               break;
+                       }
+
+                       printerNameCount++;
+               }
+
+               newPrinter = true;
+       }
+
+       check( printer );
+
+       service = printer->LookupService( inType );
+
+       if ( service != NULL )
+       {
+               service->refs++;
+       }
+       else
+       {
+               try
+               {
+                       service = new Service;
+               }
+               catch (...)
+               {
+                       service = NULL;
+               }
+
+               require_action( service, exit, err = E_OUTOFMEMORY );
+               
+               service->printer        =       printer;
+               service->ifi            =       inInterfaceIndex;
+               service->type           =       inType;
+               service->domain         =       inDomain;
+               service->qtotal         =       1;
+               service->refs           =       1;
+               service->serviceRef     =       NULL;
+
+               printer->services.push_back( service );
+
+               //
+               // if the printer is selected, then we'll want to start a
+               // resolve on this guy
+               //
+
+               if ( m_selected == printer )
+               {
+                       StartResolve( service );
+               }
+       }
+       
+       if ( newPrinter )
+       {
+               printer->item = m_browseList.InsertItem(printer->displayName);
+
+               m_browseList.SetItemData( printer->item, (DWORD_PTR) printer );
+
+               m_printers.push_back( printer );
+               
+               m_browseList.SortChildren(TVI_ROOT);
+               
+               if ( printer->name == m_selectedName )
+               {
+                       m_browseList.SelectItem( printer->item );
+               }
+
+               //
+               // if the searching item is still in the list
+               // get rid of it
+               //
+               // note that order is important here.  Insert the printer
+               // item before removing the placeholder so we always have
+               // an item in the list to avoid experiencing the bug
+               // in Microsoft's implementation of CTreeCtrl
+               //
+               if (m_emptyListItem != NULL)
+               {
+                       m_browseList.DeleteItem(m_emptyListItem);
+                       m_emptyListItem = NULL;
+                       m_browseList.EnableWindow(TRUE);
+               }
+       }
+
+exit:
+
+       if (!moreComing)
+       {
+               m_browseList.SetRedraw(TRUE);
+               m_browseList.Invalidate();
+       }
+
+       return err;
+}
+
+
+OSStatus
+CSecondPage::OnRemovePrinter(
+                               const char *    inName, 
+                               const char *    inType, 
+                               const char *    inDomain,
+                               bool                    moreComing)
+{
+       DEBUG_UNUSED( inDomain );
+       DEBUG_UNUSED( inType );
+
+       Printer *       printer;
+       OSStatus        err = kNoErr;
+
+       check( IsWindow( m_hWnd ) );
+
+       m_browseList.SetRedraw(FALSE);
+
+       printer = Lookup( inName );
+
+       if ( printer )
+       {
+               Service * service;
+
+               service = printer->LookupService( inType );
+
+               if ( service && ( --service->refs == 0 ) )
+               {
+                       if ( service->serviceRef != NULL )
+                       {
+                               err = StopResolve( service );
+                               require_noerr( err, exit );
+                       }
+
+                       printer->services.remove( service );
+
+                       delete service;
+               }
+
+               if ( printer->services.size() == 0 )
+               {
+                       //
+                       // check to make sure if we're the only item in the control...i.e.
+                       // the list size is 1.
+                       //
+                       if (m_browseList.GetCount() > 1)
+                       {
+                               //
+                               // if we're not the only thing in the list, then
+                               // simply remove it from the list
+                               //
+                               m_browseList.DeleteItem( printer->item );
+                       }
+                       else
+                       {
+                               //
+                               // if we're the only thing in the list, then redisplay
+                               // it with the no rendezvous printers message
+                               //
+                               InitBrowseList();
+                       }
+
+                       m_printers.remove( printer );
+
+                       if ( m_selected == printer )
+                       {
+                               m_selected              = NULL;
+                               m_selectedName  = "";
+                       }
+
+                       delete printer;
+               }
+       }
+
+exit:
+
+       if (!moreComing)
+       {
+               m_browseList.SetRedraw(TRUE);
+               m_browseList.Invalidate();
+       }
+
+       return err;
+}
+
+
+void
+CSecondPage::OnResolveService( Service * service )
+{
+       CPrinterSetupWizardSheet * psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+       require_quiet( psheet, exit );
+       
+       check( service );
+
+       if ( !--service->printer->resolving )
+       {
+               //
+               // sort the services now.  we want the service that
+               // has the highest priority queue to be first in
+               // the list.
+               //
+
+               service->printer->services.sort( OrderServiceFunc );
+
+               //
+               // and set it to selected
+               //
+
+               m_selected              = service->printer;
+               m_selectedName  = service->printer->name;
+
+               //
+               // and update the printer information box
+               //
+               SetPrinterInformationState( TRUE );
+
+               m_descriptionField.SetWindowText( service->description );
+               m_locationField.SetWindowText( service->location );
+
+               psheet->SetWizardButtons( PSWIZB_BACK|PSWIZB_NEXT );
+
+               //
+               // reset the cursor
+               //
+
+               psheet->m_active = psheet->m_arrow;
+               SetCursor(psheet->m_active);
+       }
+
+exit:
+
+       return;
+}
+
+
+LONG
+CSecondPage::OnServiceEvent(WPARAM inWParam, LPARAM inLParam)
+{
+       if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam)))
+    {
+               dlog( kDebugLevelError, "OnServiceEvent: window error\n" );
+    }
+    else
+    {
+               SOCKET sock = (SOCKET) inWParam;
+
+               // iterate thru list
+               ServiceRefList::iterator begin = m_serviceRefList.begin();
+               ServiceRefList::iterator end   = m_serviceRefList.end();
+
+               while (begin != end)
+               {
+                       DNSServiceRef ref = *begin++;
+
+                       check(ref != NULL);
+
+                       if ((SOCKET) DNSServiceRefSockFD(ref) == sock)
+                       {
+                               DNSServiceProcessResult(ref);
+                               break;
+                       }
+               }
+       }
+
+       return ( 0 );
+}
+
+
+void CSecondPage::OnTvnSelchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult)
+{
+       LPNMTREEVIEW                                    pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
+       CPrinterSetupWizardSheet        *       psheet;
+       int                                                             err = 0;
+
+       HTREEITEM item = m_browseList.GetSelectedItem();
+       require_quiet( item, exit );
+
+       psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
+       require_action( psheet, exit, err = kUnknownErr );      
+
+       Printer * printer;
+
+       printer = reinterpret_cast<Printer*>(m_browseList.GetItemData( item ) );
+       require_quiet( printer, exit );
+
+       //
+       // this call will trigger a resolve.  When the resolve is complete,
+       // our OnResolve will be called.
+       //
+       err = StartResolve( printer );
+       require_noerr( err, exit );
+
+       //
+       // And clear out the printer information box
+       //
+       SetPrinterInformationState( FALSE );
+       m_descriptionField.SetWindowText(L"");
+       m_locationField.SetWindowText(L"");
+
+exit:
+
+       if (err != 0)
+       {
+               CString text;
                CString caption;
 
                text.LoadString(IDS_ERROR_SELECTING_PRINTER_TEXT);
@@ -345,3 +1198,174 @@ exit:
 
        *pResult = 0;
 }
+
+
+bool
+CSecondPage::OrderServiceFunc( const Service * a, const Service * b )
+{
+       Queue * q1, * q2;
+
+       q1 = (a->queues.size() > 0) ? a->queues.front() : NULL;
+
+       q2 = (b->queues.size() > 0) ? b->queues.front() : NULL;
+
+       if ( !q1 && !q2 )
+       {
+               return true;
+       }
+       else if ( q1 && !q2 )
+       {
+               return true;
+       }
+       else if ( !q1 && q2 )
+       {
+               return false;
+       }
+       else if ( q1->priority < q2->priority )
+       {
+               return true;
+       }
+       else if ( q1->priority > q2->priority )
+       {
+               return false;
+       }
+       else if ( ( a->type == kPDLServiceType ) || ( ( a->type == kLPRServiceType ) && ( b->type == kIPPServiceType ) ) )
+       {
+               return true;
+       }
+       else
+       {
+               return false;
+       }
+}
+
+
+bool
+CSecondPage::OrderQueueFunc( const Queue * q1, const Queue * q2 )
+{
+       return ( q1->priority <= q2->priority ) ? true : false;
+}
+
+
+void
+CSecondPage::LoadTextAndDisableWindow( CString & text )
+{
+       m_emptyListItem = m_browseList.InsertItem( text, 0, 0, NULL, TVI_FIRST );
+       m_browseList.SelectItem( NULL );
+
+       //
+       // this will remove everything else in the list...we might be navigating
+       // back to this window, and the browse list might have changed since
+       // we last displayed it.
+       //
+       if ( m_emptyListItem )
+       {
+               HTREEITEM item = m_browseList.GetNextVisibleItem( m_emptyListItem );
+  
+               while ( item )
+               {
+                       m_browseList.DeleteItem( item );
+                       item = m_browseList.GetNextVisibleItem( m_emptyListItem );
+               }
+       }
+
+       m_browseList.EnableWindow( FALSE );
+}
+
+
+void
+CSecondPage::SetPrinterInformationState( BOOL state )
+{
+       m_printerInformation.EnableWindow( state );\r
+       m_descriptionLabel.EnableWindow( state );\r
+       m_descriptionField.EnableWindow( state );\r
+       m_locationLabel.EnableWindow( state );\r
+       m_locationField.EnableWindow( state );\r
+}\r
+\r
+\r
+OSStatus
+CSecondPage::ParseTextRecord( Service * service, uint16_t inTXTSize, const char * inTXT, bool & qtotalDefined, CString & qname, uint32_t & qpriority )
+{
+       bool            rpOnly = true;
+       OSStatus        err = kNoErr;
+       
+       while (inTXTSize)
+       {
+               char buf[256];
+
+               unsigned char num = *inTXT;
+               check( (int) num < inTXTSize );
+
+               if ( num )
+               {
+                       memset(buf, 0, sizeof(buf));
+                       memcpy(buf, inTXT + 1, num);
+
+                       CString elem;
+
+                       err = UTF8StringToStringObject( buf, elem );
+                       require_noerr( err, exit );
+
+                       int curPos = 0;
+
+                       CString key = elem.Tokenize(L"=", curPos);
+                       CString val = elem.Tokenize(L"=", curPos);
+
+                       key.MakeLower();
+
+                       if ( key == L"rp" )
+                       {
+                               qname = val;
+                       }
+                       else
+                       {
+                               rpOnly = false;
+
+                               if ((key == L"usb_mfg") || (key == L"usb_manufacturer"))
+                               {
+                                       service->usb_MFG = val;
+                               }
+                               else if ((key == L"usb_mdl") || (key == L"usb_model"))
+                               {
+                                       service->usb_MDL = val;
+                               }
+                               else if (key == L"ty")
+                               {
+                                       service->description = val;
+                               }
+                               else if (key == L"product")
+                               {
+                                       service->product = val;
+                               }
+                               else if (key == L"note")
+                               {
+                                       service->location = val;
+                               }
+                               else if (key == L"qtotal")
+                               {
+                                       service->qtotal = (unsigned short) _ttoi((LPCTSTR) val);
+                                       qtotalDefined = true;
+                               }
+                               else if (key == L"priority")
+                               {
+                                       qpriority = _ttoi((LPCTSTR) val);
+                               }
+                       }
+               }
+
+               inTXTSize -= (num + 1);
+               inTXT += (num + 1);
+       }
+
+exit:
+
+       if ( rpOnly )
+       {
+               qtotalDefined = true;
+       }
+
+       return err;
+}
+
+
index 45c55c96d0f91e10ce4d0cee904b32cc91ff332c..9d9c4fb77ca165543eff25ea39d62a747bad82a9 100644 (file)
     Change History (most recent first):
     
 $Log: SecondPage.h,v $
+Revision 1.6  2005/01/04 21:09:14  shersche
+Fix problems in parsing text records. Fix problems in remove event handling. Ensure that the same service can't be resolved more than once.
+
+Revision 1.5  2004/12/31 07:25:27  shersche
+Tidy up printer management, and fix memory leaks when hitting 'Cancel'
+
+Revision 1.4  2004/12/30 01:02:46  shersche
+<rdar://problem/3734478> Add Printer information box that displays description and location information when printer name is selected
+Bug #: 3734478
+
+Revision 1.3  2004/12/29 18:53:38  shersche
+<rdar://problem/3725106>
+<rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
+Bug #: 3725106, 3737413
+
 Revision 1.2  2004/09/13 21:23:42  shersche
 <rdar://problem/3796483> Add moreComing argument to OnAddPrinter and OnRemovePrinter callbacks
 Bug #: 3796483
@@ -47,7 +62,7 @@ using namespace PrinterSetupWizard;
 
 // CSecondPage dialog
 
-class CSecondPage : public CPropertyPage, public EventHandler
+class CSecondPage : public CPropertyPage
 {
        DECLARE_DYNAMIC(CSecondPage)
 
@@ -58,19 +73,43 @@ public:
 // Dialog Data
        enum { IDD = IDD_SECOND_PAGE };
 
-       virtual void
-       OnAddPrinter(
-                       Printer *       printer,
-                       bool                    moreComing);
-
-       virtual void
-       OnRemovePrinter(
-                       Printer *       printer,
-                       bool                    moreComing);
-
-       virtual void
-       OnResolvePrinter(
-                       Printer * printer);
+       static void DNSSD_API
+       OnBrowse(
+               DNSServiceRef                   inRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType     inErrorCode,
+               const char *                    inName, 
+               const char *                    inType, 
+               const char *                    inDomain,       
+               void *                                  inContext );
+
+       static void DNSSD_API
+       OnResolve(
+               DNSServiceRef                   inRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inErrorCode,
+               const char *                    inFullName,     
+               const char *                    inHostName, 
+               uint16_t                                inPort,
+               uint16_t                                inTXTSize,
+               const char *                    inTXT,
+               void *                                  inContext );
+
+       static void DNSSD_API
+       OnQuery(
+               DNSServiceRef                   inRef, 
+               DNSServiceFlags                 inFlags, 
+               uint32_t                                inInterfaceIndex, 
+               DNSServiceErrorType             inErrorCode,
+               const char                      *       inFullName, 
+               uint16_t                                inRRType, 
+               uint16_t                                inRRClass, 
+               uint16_t                                inRDLen, 
+               const void                      *       inRData, 
+               uint32_t                                inTTL, 
+               void                            *       inContext);
 
 protected:
 
@@ -91,5 +130,94 @@ public:
        bool                    m_initialized;
        bool                    m_waiting;
        
-       afx_msg void OnTvnSelchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult);
+       LONG                    OnServiceEvent(WPARAM inWParam, LPARAM inLParam);
+       afx_msg void    OnTvnSelchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult);
+
+private:
+
+       OSStatus
+       LoadPrinterNames();
+
+       Printer*
+       Lookup( const char * name );
+
+       OSStatus
+       StartOperation( DNSServiceRef ref );
+
+       OSStatus
+       StopOperation( DNSServiceRef & ref );
+
+       OSStatus
+       StartBrowse();
+
+       OSStatus
+       StopBrowse();
+
+       OSStatus
+       StartResolve( Printer * printer );
+
+       OSStatus
+       StartResolve( Service * service );
+
+       OSStatus
+       StopResolve( Printer * printer );
+
+       OSStatus
+       StopResolve( Service * service );
+
+       OSStatus
+       OnAddPrinter(
+                       uint32_t                inInterfaceIndex,
+                       const char *    inName, 
+                       const char *    inType, 
+                       const char *    inDomain,
+                       bool                    moreComing);
+
+       OSStatus
+       OnRemovePrinter(
+                       const char *    inName, 
+                       const char *    inType, 
+                       const char *    inDomain,
+                       bool                    moreComing);
+
+       void
+       OnResolveService( Service * service );
+
+       static bool
+       OrderServiceFunc( const Service * a, const Service * b );
+
+       static bool
+       OrderQueueFunc( const Queue * q1, const Queue * q2 );
+
+       void
+       LoadTextAndDisableWindow( CString & text );
+       
+       void
+       SetPrinterInformationState( BOOL state );
+
+       OSStatus
+       ParseTextRecord( Service * service, uint16_t inTXTSize, const char * inTXT, bool & qtotalDefined, CString & qname, uint32_t & qpriority );
+
+       typedef std::map<CString,CString>       PrinterNameMap;
+       typedef std::list<DNSServiceRef>        ServiceRefList;
+       typedef std::list<Printer*>                     Printers;
+
+       
+       PrinterNameMap  m_printerNames;
+       Printers                m_printers;
+       ServiceRefList  m_serviceRefList;
+       DNSServiceRef   m_pdlBrowser;
+       DNSServiceRef   m_lprBrowser;
+       DNSServiceRef   m_ippBrowser;
+
+       Printer         *       m_selected;
+       std::string             m_selectedName;
+\r
+private:\r
+\r
+       CStatic m_printerInformation;\r
+       CStatic m_descriptionLabel;\r
+       CStatic m_descriptionField;\r
+       CStatic m_locationLabel;\r
+       CStatic m_locationField;\r
 };
index 6828f3ce64c256c029d6fffd79948f7aab031355..76978cdd4bf3ebbe8364c986f5049f87e1f9a17b 100644 (file)
     Change History (most recent first):
     
 $Log: ThirdPage.cpp,v $
+Revision 1.14  2005/01/25 08:55:54  shersche
+<rdar://problem/3911084> Load icons at run-time from resource DLL
+Bug #: 3911084
+
+Revision 1.13  2005/01/06 08:15:45  shersche
+Append queue name to end of LPR port name, correctly build port name when queue name is absent
+
+Revision 1.12  2005/01/05 01:06:12  shersche
+<rdar://problem/3841218> Strip the first substring off the product key if an initial match can't be found with the whole product key.
+Bug #: 3841218
+
+Revision 1.11  2004/12/29 18:53:38  shersche
+<rdar://problem/3725106>
+<rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
+Bug #: 3725106, 3737413
+
 Revision 1.10  2004/10/11 22:55:34  shersche
 <rdar://problem/3827624> Use the IP port number when deriving the printer port name.
 Bug #: 3827624
@@ -106,7 +122,8 @@ enum PrinterParsingState
 IMPLEMENT_DYNAMIC(CThirdPage, CPropertyPage)
 CThirdPage::CThirdPage()
        : CPropertyPage(CThirdPage::IDD),
-               m_initialized(false)
+               m_initialized(false),
+               m_printerImage( NULL )
 {
        m_psp.dwFlags &= ~(PSP_HASHELP);
        m_psp.dwFlags |= PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE;
@@ -153,7 +170,7 @@ CThirdPage::~CThirdPage()
 //
 // ----------------------------------------------------
 void
-CThirdPage::SelectMatch(Printer * printer, Manufacturer * manufacturer, Model * model)
+CThirdPage::SelectMatch(Printer * printer, Service * service, Manufacturer * manufacturer, Model * model)
 {
        LVFINDINFO      info;
        int                     nIndex;
@@ -197,7 +214,7 @@ CThirdPage::SelectMatch(Printer * printer, Manufacturer * manufacturer, Model *
                m_modelListCtrl.SetFocus();
        }
 
-       CopyPrinterSettings( printer, manufacturer, model );
+       CopyPrinterSettings( printer, service, manufacturer, model );
 }
 
 
@@ -209,13 +226,50 @@ CThirdPage::SelectMatch(Printer * printer, Manufacturer * manufacturer, Model *
 // --------------------------------------------------------
 
 void
-CThirdPage::CopyPrinterSettings( Printer * printer, Manufacturer * manufacturer, Model * model )
+CThirdPage::CopyPrinterSettings( Printer * printer, Service * service, Manufacturer * manufacturer, Model * model )
 {
        printer->manufacturer           =       manufacturer->name;
        printer->model                          =       model->name;
        printer->driverInstalled        =       model->driverInstalled;
        printer->infFileName            =       model->infFileName;
-       printer->portName.Format(L"IP_%s.%d", static_cast<LPCTSTR>(printer->hostname), printer->portNumber);
+
+       if ( service->type == kPDLServiceType )
+       {
+               printer->portName.Format(L"IP_%s.%d", static_cast<LPCTSTR>(service->hostname), service->portNumber);
+               service->protocol = L"Raw";
+       }
+       else if ( service->type == kLPRServiceType )
+       {
+               Queue * q = service->queues.front();
+               check( q );
+
+               if ( q->name.GetLength() > 0 )
+               {
+                       printer->portName.Format(L"LPR_%s.%d.%s", static_cast<LPCTSTR>(service->hostname), service->portNumber, static_cast<LPCTSTR>(q->name) );
+               }
+               else
+               {
+                       printer->portName.Format(L"LPR_%s.%d", static_cast<LPCTSTR>(service->hostname), service->portNumber);
+               }
+
+               service->protocol = L"LPR";
+       }
+       else if ( service->type == kIPPServiceType )
+       {
+               Queue * q = service->queues.front();
+               check( q );
+
+               if ( q->name.GetLength() > 0 )
+               {
+                       printer->portName.Format(L"http://%s:%d/printers/%s", static_cast<LPCTSTR>(service->hostname), service->portNumber, static_cast<LPCTSTR>(q->name) );
+               }
+               else
+               {
+                       printer->portName.Format(L"http://%s:%d/", static_cast<LPCTSTR>(service->hostname), service->portNumber );
+               }
+
+               service->protocol = L"IPP";
+       }
 }
 
 
@@ -321,6 +375,7 @@ CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CSt
                                                //
                                                // get rid of all delimiters
                                                //
+                                               key.Trim();
                                                val.Remove('"');
        
                                                //
@@ -484,7 +539,24 @@ CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CSt
                                        CString name            = s.Tokenize(L"=",curPos);
                                        CString description = s.Tokenize(L"=",curPos);
                                        
-                                       name.Remove('"');
+                                       if (name.Find('%') == 0)
+                                       {
+                                               StringMap::iterator it;
+
+                                               name.Remove('%');
+
+                                               it = strings.find(name);
+
+                                               if (it != strings.end())
+                                               {
+                                                       name = it->second;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               name.Remove('"');
+                                       }
+
                                        name.Trim();
                                        description.Trim();
                                        
@@ -493,7 +565,7 @@ CThirdPage::LoadPrintDriverDefsFromFile(Manufacturers & manufacturers, const CSt
                                        //
                                        if (checkForDuplicateModels == true)
                                        {
-                                               if ( MatchModel( iter->second, name ) != NULL )
+                                               if ( MatchModel( iter->second, ConvertToModelName( name ) ) != NULL )
                                                {
                                                        continue;
                                                }
@@ -764,7 +836,7 @@ CThirdPage::NormalizeManufacturerName( const CString & name )
 // MatchManufacturer and MatchModel in turn.
 //
 
-OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * printer)
+OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * printer, Service * service)
 {
        CString                                 normalizedProductName;
        Manufacturer            *       manufacturer    =       NULL;
@@ -776,17 +848,17 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print
        //
        // first look to see if we have a usb_MFG descriptor
        //
-       if (printer->usb_MFG.GetLength() > 0)
+       if (service->usb_MFG.GetLength() > 0)
        {
-               manufacturer = MatchManufacturer( manufacturers, ConvertToManufacturerName ( printer->usb_MFG ) );
+               manufacturer = MatchManufacturer( manufacturers, ConvertToManufacturerName ( service->usb_MFG ) );
        }
 
        if ( manufacturer == NULL )
        {
-               printer->product.Remove('(');
-               printer->product.Remove(')');
+               service->product.Remove('(');
+               service->product.Remove(')');
 
-               manufacturer = MatchManufacturer( manufacturers, ConvertToManufacturerName ( printer->product ) );
+               manufacturer = MatchManufacturer( manufacturers, ConvertToManufacturerName ( service->product ) );
        }
        
        //
@@ -794,22 +866,22 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print
        //
        if ( manufacturer != NULL )
        {
-               if (printer->usb_MDL.GetLength() > 0)
+               if (service->usb_MDL.GetLength() > 0)
                {
-                       model = MatchModel ( manufacturer, ConvertToModelName ( printer->usb_MDL ) );
+                       model = MatchModel ( manufacturer, ConvertToModelName ( service->usb_MDL ) );
                }
 
                if ( model == NULL )
                {
-                       printer->product.Remove('(');
-                       printer->product.Remove(')');
+                       service->product.Remove('(');
+                       service->product.Remove(')');
 
-                       model = MatchModel ( manufacturer, ConvertToModelName ( printer->product ) );
+                       model = MatchModel ( manufacturer, ConvertToModelName ( service->product ) );
                }
 
                if ( model != NULL )
                {
-                       SelectMatch(printer, manufacturer, model);
+                       SelectMatch(printer, service, manufacturer, model);
                        found = true;
                }
        }
@@ -887,8 +959,8 @@ CThirdPage::MatchManufacturer( Manufacturers & manufacturers, const CString & na
 
                //
                // now try and find the lowered string in the name passed in.
-               // 
-               if (name.Find(lower) == 0)
+               //
+               if (name.Find(lower) != -1)
                {
                        return iter->second;
                }
@@ -927,6 +999,22 @@ CThirdPage::MatchModel(Manufacturer * manufacturer, const CString & name)
                {
                        return model;
                }
+
+               //
+               // <rdar://problem/3841218>
+               // try removing the first substring and search again
+               //
+
+               if ( name.Find(' ') != -1 )
+               {
+                       CString altered = name;
+                       altered.Delete( 0, altered.Find(' ') + 1 );
+
+                       if ( lowered.Find( altered ) != -1 )
+                       {
+                               return model;
+                       }
+               }
        }
 
        return NULL;
@@ -949,7 +1037,18 @@ OSStatus CThirdPage::OnInitPage()
        CString                                 ntPrint;
        OSStatus                                err;
        BOOL                                    ok;
+
+       // Load printer icon\r
+\r
+       check( m_printerImage == NULL );
        
+       m_printerImage = (CStatic*) GetDlgItem( IDR_MANIFEST );
+       check( m_printerImage );
+
+       if ( m_printerImage != NULL )
+       {
+               m_printerImage->SetIcon( LoadIcon( GetNonLocalizedResources(), MAKEINTRESOURCE( IDI_PRINTER ) ) );
+       }
 
        //
        // The CTreeCtrl widget automatically sends a selection changed
@@ -1005,7 +1104,7 @@ void CThirdPage::DoDataExchange(CDataExchange* pDX)
        DDX_Control(pDX, IDC_PRINTER_MODEL, m_modelListCtrl);
        DDX_Control(pDX, IDC_PRINTER_NAME, m_printerName);
        DDX_Control(pDX, IDC_DEFAULT_PRINTER, m_defaultPrinterCtrl);
-       DDX_Control(pDX, IDC_PRINTER_SELECTION_TEXT, m_printerSelectionText);
+       DDX_Control(pDX, IDC_PRINTER_SELECTION_TEXT, m_printerSelectionText);\r
 }
 
 
@@ -1021,6 +1120,7 @@ CThirdPage::OnSetActive()
 {
        CPrinterSetupWizardSheet        *       psheet;
        Printer                                         *       printer;
+       Service                                         *       service;
 
        psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
        require_quiet( psheet, exit );
@@ -1038,6 +1138,9 @@ CThirdPage::OnSetActive()
        printer = psheet->GetSelectedPrinter();
        require_quiet( printer, exit );
 
+       service = printer->services.front();
+       require_quiet( service, exit );
+
        //
        // call OnInitPage once
        //
@@ -1061,7 +1164,7 @@ CThirdPage::OnSetActive()
        //
        // and try and match the printer
        //
-       MatchPrinter( m_manufacturers, printer );
+       MatchPrinter( m_manufacturers, printer, service );
 
 exit:
 
@@ -1144,6 +1247,7 @@ void CThirdPage::OnLvnItemchangedPrinterModel(NMHDR *pNMHDR, LRESULT *pResult)
        
        CPrinterSetupWizardSheet        *       psheet;
        Printer                                         *       printer;
+       Service                                         *       service;
 
        psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
        require_quiet( psheet, exit );
@@ -1151,6 +1255,9 @@ void CThirdPage::OnLvnItemchangedPrinterModel(NMHDR *pNMHDR, LRESULT *pResult)
        printer = psheet->GetSelectedPrinter();
        require_quiet( printer, exit );
 
+       service = printer->services.front();
+       require_quiet( service, exit );
+
        check ( m_manufacturerSelected );
 
        POSITION p = m_modelListCtrl.GetFirstSelectedItemPosition();
@@ -1160,7 +1267,7 @@ void CThirdPage::OnLvnItemchangedPrinterModel(NMHDR *pNMHDR, LRESULT *pResult)
        {
                m_modelSelected = (Model*) m_modelListCtrl.GetItemData(nSelected);
 
-               CopyPrinterSettings( printer, m_manufacturerSelected, m_modelSelected );
+               CopyPrinterSettings( printer, service, m_manufacturerSelected, m_modelSelected );
 
                psheet->SetWizardButtons(PSWIZB_BACK|PSWIZB_NEXT);
        }
@@ -1197,6 +1304,7 @@ void CThirdPage::OnBnClickedHaveDisk()
 {
        CPrinterSetupWizardSheet        *       psheet;
        Printer                                         *       printer;
+       Service                                         *       service;
 
        CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY|OFN_FILEMUSTEXIST, L"Setup Information (*.inf)|*.inf||", this);
 
@@ -1206,6 +1314,9 @@ void CThirdPage::OnBnClickedHaveDisk()
        printer = psheet->GetSelectedPrinter();
        require_quiet( printer, exit );
        
+       service = printer->services.front();
+       require_quiet( service, exit );
+
        if ( dlg.DoModal() == IDOK )
        {
                Manufacturers   manufacturers;
@@ -1215,7 +1326,7 @@ void CThirdPage::OnBnClickedHaveDisk()
    
                PopulateUI( manufacturers );
 
-               MatchPrinter( manufacturers, printer );
+               MatchPrinter( manufacturers, printer, service );
        }
 
 exit:
index dfdb69d98535666b8d3788496b297820a2e0705b..b775fb8efe61efe9a205b4c972cc59b43a671e37 100644 (file)
     Change History (most recent first):
     
 $Log: ThirdPage.h,v $
+Revision 1.3  2005/01/25 08:57:28  shersche
+<rdar://problem/3911084> Add m_printerControl member for dynamic loading of icons from resource DLLs
+Bug #: 3911084
+
+Revision 1.2  2004/12/29 18:53:38  shersche
+<rdar://problem/3725106>
+<rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
+Bug #: 3725106, 3737413
+
 Revision 1.1  2004/06/18 04:36:58  rpantos
 First checked in
 
@@ -88,7 +97,7 @@ private:
        //
        // Tries to match printer based on manufacturer and model
        //
-       OSStatus MatchPrinter(Manufacturers & manufacturers, Printer * printer);
+       OSStatus MatchPrinter(Manufacturers & manufacturers, Printer * printer, Service * service);
 
        //
        // OnInitPage
@@ -106,8 +115,8 @@ private:
 
        Manufacturer    *       MatchManufacturer( Manufacturers & manufacturer, const CString & name );
        Model                   *       MatchModel( Manufacturer * manufacturer, const CString & name );
-       void                            SelectMatch(Printer * printer, Manufacturer * manufacturer, Model * model);
-       void                            CopyPrinterSettings(Printer * printer, Manufacturer * manufacturer, Model * model);
+       void                            SelectMatch(Printer * printer, Service * service, Manufacturer * manufacturer, Model * model);
+       void                            CopyPrinterSettings(Printer * printer, Service * service, Manufacturer * manufacturer, Model * model);
 
        Manufacturers           m_manufacturers;
        
@@ -129,5 +138,6 @@ private:
        CButton m_defaultPrinterCtrl;
 public:
        CStatic m_printerSelectionText;
+       CStatic *       m_printerImage;
        afx_msg void OnBnClickedHaveDisk();
 };
index f702ebc9284637cbb871099fc0f26a5e6a816e6b..11042ddf136151afa9ea855832e9d890bc164655 100644 (file)
     Change History (most recent first):
     
 $Log: UtilTypes.h,v $
+Revision 1.8  2005/01/06 08:18:26  shersche
+Add protocol field to service, add EmptyQueues() function to service
+
+Revision 1.7  2005/01/04 21:07:29  shersche
+add description member to service object.  this member corresponds to the 'ty' key in a printer text record
+
+Revision 1.6  2004/12/30 01:24:02  shersche
+<rdar://problem/3906182> Remove references to description key
+Bug #: 3906182
+
+Revision 1.5  2004/12/29 18:53:38  shersche
+<rdar://problem/3725106>
+<rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
+Bug #: 3725106, 3737413
+
 Revision 1.4  2004/09/13 21:22:44  shersche
 <rdar://problem/3796483> Add moreComing argument to OnAddPrinter and OnRemovePrinter callbacks
 Bug #: 3796483
@@ -43,45 +58,54 @@ First checked in
 #pragma once
 
 #include <dns_sd.h>
+#include <string>
 #include <list>
+#include <DebugServices.h>
 
-class CPrinterSetupWizardSheet;
+class CSecondPage;
+
+#define        kDefaultPriority        50
+#define kDefaultQTotal         1
 
 namespace PrinterSetupWizard
 {
        struct Printer;
+       struct Service;
+       struct Queue;
        struct Manufacturer;
        struct Model;
-       
-       typedef std::list<CString>      TextRecord;
+
+       typedef std::list<Queue*>       Queues;
+       typedef std::list<Service*>     Services;
        typedef std::list<Model*>       Models;
 
        struct Printer
        {
-               DNSServiceRef                                   serviceRef;
-               CPrinterSetupWizardSheet        *       window;
-               HTREEITEM                                               item;
-               DWORD                                                   refs;
+               Printer();
+
+               ~Printer();
+
+               Service*
+               LookupService
+                       (
+                       const std::string       &       type
+                       );
+
+               CSecondPage     *       window;
+               HTREEITEM               item;
 
                //
-               // these are from the browse reply
+               // These are from the browse reply
                //
-               uint32_t                                                ifi;
-               std::string                                             name;
-               CString                                                 displayName;
-               CString                                                 actualName;
-               std::string                                             type;
-               std::string                                             domain;
+               std::string             name;
+               CString                 displayName;
+               CString                 actualName;
 
                //
-               // these are from the resolve
+               // These keep track of the different services associated with this printer.
+               // the services are ordered according to preference.
                //
-               CString                                                 hostname;
-               unsigned short                                  portNumber;
-               CString                                                 usb_MFG;
-               CString                                                 usb_MDL;
-               CString                                                 description;
-               CString                                                 product;
+               Services                services;
 
                //
                // these are derived from the printer matching code
@@ -93,17 +117,71 @@ namespace PrinterSetupWizard
                // if driverInstalled is true, then model is the name
                // of the driver to use in AddPrinter
                // 
-               bool                                                    driverInstalled;
-               CString                                                 infFileName;
-               CString                                                 manufacturer;
-               CString                                                 model;
-               CString                                                 portName;
-               bool                                                    deflt;
+               bool                    driverInstalled;
+               CString                 infFileName;
+               CString                 manufacturer;
+               CString                 model;
+               CString                 portName;
+               bool                    deflt;
 
                //
                // state
                //
-               bool                                                    installed;
+               unsigned                resolving;
+               bool                    installed;
+       };
+
+
+       struct Service
+       {
+               Service();
+
+               ~Service();
+
+               void
+               EmptyQueues();
+
+               Printer         *       printer;
+               uint32_t                ifi;
+               std::string             type;
+               std::string             domain;
+
+               //
+               // these are from the resolve
+               //
+               DNSServiceRef   serviceRef;
+               CString                 hostname;
+               unsigned short  portNumber;
+               CString                 usb_MFG;
+               CString                 usb_MDL;
+               CString                 description;
+               CString                 location;
+               CString                 product;
+               CString                 protocol;
+               unsigned short  qtotal;
+
+               //
+               // There will usually one be one of these, however
+               // this will handle printers that have multiple
+               // queues.  These are ordered according to preference.
+               //
+               Queues                  queues;
+
+               //
+               // Reference count
+               //
+               unsigned                refs;
+       };
+
+
+       struct Queue
+       {
+               Queue();
+
+               ~Queue();
+
+               CString         name;
+               uint32_t        priority;
        };
 
 
@@ -123,22 +201,80 @@ namespace PrinterSetupWizard
        };
 
 
-       class EventHandler
+       inline
+       Printer::Printer()
+       {
+       }
+
+       inline
+       Printer::~Printer()
+       {
+               while ( services.size() > 0 )
+               {
+                       Service * service = services.front();
+                       services.pop_front();
+                       delete service;
+               }
+       }
+
+       inline Service*
+       Printer::LookupService
+                               (
+                               const std::string       &       type
+                               )
        {
-       public:
+               Services::iterator it;
 
-               virtual void
-               OnAddPrinter(
-                               Printer *       printer,
-                               bool                    moreComing) = 0;
+               for ( it = services.begin(); it != services.end(); it++ )
+               {
+                       Service * service = *it;
 
-               virtual void
-               OnRemovePrinter(
-                               Printer *       printer,
-                               bool                    moreComing) = 0;
+                       if ( strcmp(service->type.c_str(), type.c_str()) == 0 )
+                       {
+                               return service;
+                       }
+               }
 
-               virtual void
-               OnResolvePrinter(
-                               Printer * printer) = 0;
-       };
+               return NULL;
+       }
+
+       inline
+       Service::Service()
+       :
+               qtotal(kDefaultQTotal)
+       {
+       }
+
+       inline
+       Service::~Service()
+       {
+               check( serviceRef == NULL );
+
+               EmptyQueues();
+       }
+
+       inline void
+       Service::EmptyQueues()
+       {
+               while ( queues.size() > 0 )
+               {
+                       Queue * q = queues.front();
+                       queues.pop_front();
+                       delete q;
+               }
+       }
+
+       inline
+       Queue::Queue()
+       :
+               priority(kDefaultPriority)
+       {
+       }
+
+       inline
+       Queue::~Queue()
+       {
+       }
 }
+
+
diff --git a/Clients/PrinterSetupWizard/res/PrinterSetupWizardLocRes.rc2 b/Clients/PrinterSetupWizard/res/PrinterSetupWizardLocRes.rc2
new file mode 100755 (executable)
index 0000000..27e049a
--- /dev/null
@@ -0,0 +1,13 @@
+//
+// Wiz97_3.RC2 - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/Clients/PrinterSetupWizard/res/PrinterSetupWizardRes.rc2 b/Clients/PrinterSetupWizard/res/PrinterSetupWizardRes.rc2
new file mode 100755 (executable)
index 0000000..27e049a
--- /dev/null
@@ -0,0 +1,13 @@
+//
+// Wiz97_3.RC2 - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+/////////////////////////////////////////////////////////////////////////////
index 8c2a6cad8c5378504490c222517451e994f8b4dc..5d21d404b112667a18a999905aee09c8ff858564 100644 (file)
@@ -1,74 +1,38 @@
-//{{NO_DEPENDENCIES}}\r
-// Microsoft Visual C++ generated include file.\r
-// Used by PrinterSetupWizard.rc\r
-//\r
-#define IDR_MANIFEST                    1\r
-#define IDM_ABOUTBOX                    0x0010\r
-#define IDD_ABOUTBOX                    100\r
-#define IDS_ABOUTBOX                    101\r
-#define IDD_PRINTERSETUPWIZARD_DIALOG   102\r
-#define IDS_GOODBYE                     102\r
-#define IDS_GREETING                    103\r
-#define IDS_BROWSE_TITLE                104\r
-#define IDS_BROWSE_SUBTITLE             105\r
-#define IDS_CAPTION                     106\r
-#define IDD_FIRST_PAGE                  107\r
-#define IDS_GOODBYE_GOOD1               107\r
-#define IDS_SEARCHING                   108\r
-#define IDD_SECOND_PAGE                 109\r
-#define IDS_GOODBYTE_GOOD2              109\r
-#define IDS_INSTALL_TITLE               110\r
-#define IDS_INSTALL_SUBTITLE            111\r
-#define IDS_ERROR_SELECTING_PRINTER_TEXT       112\r
-#define IDS_ERROR_SELECTING_PRINTER_CAPTION    113\r
-#define IDS_INSTALL_ERROR_CAPTION       114\r
-#define IDS_INSTALL_ERROR_MESSAGE       115\r
-#define IDS_MANUFACTURER_HEADING        116\r
-#define IDS_MODEL_HEADING               117\r
-#define IDS_NO_RENDEZVOUS_PRINTERS      118\r
-#define IDS_NO_MDNSRESPONDER_SERVICE_TEXT      119\r
-#define IDS_NO_MDNSRESPONDER_SERVICE_CAPTION   120\r
-#define IDS_PRINTER_MATCH_GOOD          121\r
-#define IDS_PRINTER_MATCH_BAD           122\r
-#define IDS_YES                         123\r
-#define IDS_NO                          124\r
-#define IDS_LARGE_FONT                  125\r
-#define IDR_MAINFRAME                   128\r
-#define IDB_BANNER_ICON                 129\r
-#define IDD_THIRD_PAGE                  130\r
-#define IDB_WATERMARK                   131\r
-#define IDD_FOURTH_PAGE                 132\r
-#define IDI_INFO                        136\r
-#define IDB_ABOUT                       138\r
-#define IDD_DIALOG1                     139\r
-#define IDI_ICON2                       141\r
-#define IDI_PRINTER                     141\r
-#define IDC_BUTTON1                     1000\r
-#define IDC_LIST1                       1000\r
-#define IDC_BROWSE_LIST                 1000\r
-#define IDC_RADIO1                      1001\r
-#define IDC_COMBO1                      1001\r
-#define IDC_RADIO2                      1002\r
-#define IDC_GREETING                    1003\r
-#define IDC_CHECK1                      1016\r
-#define IDC_DEFAULT_PRINTER             1016\r
-#define IDC_PRINTER_IMAGE               1017\r
-#define IDC_PRINTER_NAME                1018\r
-#define IDC_PRINTER_MANUFACTURER        1019\r
-#define IDC_PRINTER_MODEL               1020\r
-#define IDC_GOODBYE                     1021\r
-#define IDC_PRINTER_PORT                1022\r
-#define IDC_PRINTER_DEFAULT             1023\r
-#define IDC_PRINTER_SELECTION_TEXT      1024\r
-#define IDC_HAVE_DISK                   1025\r
+/*\r
+ * Copyright (c) 1997-2004 Apple Computer, Inc. All rights reserved.\r
+ *\r
+ * @APPLE_LICENSE_HEADER_START@\r
+ * \r
+ * This file contains Original Code and/or Modifications of Original Code\r
+ * as defined in and that are subject to the Apple Public Source License\r
+ * Version 2.0 (the 'License'). You may not use this file except in\r
+ * compliance with the License. Please obtain a copy of the License at\r
+ * http://www.opensource.apple.com/apsl/ and read it before using this\r
+ * file.\r
+ * \r
+ * The Original Code and all software distributed under the License are\r
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER\r
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\r
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\r
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.\r
+ * Please see the License for the specific language governing rights and\r
+ * limitations under the License.\r
+ * \r
+ * @APPLE_LICENSE_HEADER_END@\r
 \r
-// Next default values for new objects\r
-// \r
-#ifdef APSTUDIO_INVOKED\r
-#ifndef APSTUDIO_READONLY_SYMBOLS\r
-#define _APS_NEXT_RESOURCE_VALUE        142\r
-#define _APS_NEXT_COMMAND_VALUE         32771\r
-#define _APS_NEXT_CONTROL_VALUE         1026\r
-#define _APS_NEXT_SYMED_VALUE           101\r
-#endif\r
-#endif\r
+    Change History (most recent first):\r
+\r
+ */\r
+    \r
+\r
+// Include resources for Wizard app\r
+\r
+#include "resource_exe.h"\r
+\r
+// Include resources for non-localizable resource DLL\r
+\r
+#include "resource_res.h"\r
+\r
+// Include resources for localizable resource DLL\r
+\r
+#include "resource_loc_res.h"\r
diff --git a/Clients/PrinterSetupWizard/resource_exe.h b/Clients/PrinterSetupWizard/resource_exe.h
new file mode 100755 (executable)
index 0000000..c0f5429
--- /dev/null
@@ -0,0 +1,85 @@
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Visual C++ generated include file.\r
+// Used by PrinterSetupWizard.rc\r
+//\r
+#define IDR_MANIFEST                    1\r
+#define IDM_ABOUTBOX                    0x0010\r
+#define IDD_ABOUTBOX                    100\r
+#define IDS_ABOUTBOX                    101\r
+#define IDD_PRINTERSETUPWIZARD_DIALOG   102\r
+#define IDS_GOODBYE                     102\r
+#define IDS_GREETING                    103\r
+#define IDS_BROWSE_TITLE                104\r
+#define IDS_BROWSE_SUBTITLE             105\r
+#define IDS_CAPTION                     106\r
+#define IDD_FIRST_PAGE                  107\r
+#define IDS_GOODBYE_GOOD1               107\r
+#define IDS_SEARCHING                   108\r
+#define IDD_SECOND_PAGE                 109\r
+#define IDS_GOODBYTE_GOOD2              109\r
+#define IDS_INSTALL_TITLE               110\r
+#define IDS_INSTALL_SUBTITLE            111\r
+#define IDS_ERROR_SELECTING_PRINTER_TEXT 112\r
+#define IDS_ERROR_SELECTING_PRINTER_CAPTION 113\r
+#define IDS_INSTALL_ERROR_CAPTION       114\r
+#define IDS_INSTALL_ERROR_MESSAGE       115\r
+#define IDS_MANUFACTURER_HEADING        116\r
+#define IDS_MODEL_HEADING               117\r
+#define IDS_NO_RENDEZVOUS_PRINTERS      118\r
+#define IDS_NO_MDNSRESPONDER_SERVICE_TEXT 119\r
+#define IDS_NO_MDNSRESPONDER_SERVICE_CAPTION 120\r
+#define IDS_PRINTER_MATCH_GOOD          121\r
+#define IDS_PRINTER_MATCH_BAD           122\r
+#define IDS_YES                         123\r
+#define IDS_NO                          124\r
+#define IDS_LARGE_FONT                  125\r
+#define IDS_FIREWALL                    126\r
+#define IDS_ERROR_CAPTION               127\r
+#define IDR_MAINFRAME                   128\r
+#define IDS_FIREWALL_CAPTION            128\r
+#define IDB_BANNER_ICON                 129\r
+#define IDD_THIRD_PAGE                  130\r
+#define IDB_WATERMARK                   131\r
+#define IDD_FOURTH_PAGE                 132\r
+#define IDI_INFO                        136\r
+#define IDB_ABOUT                       138\r
+#define IDD_DIALOG1                     139\r
+#define IDI_ICON2                       141\r
+#define IDI_PRINTER                     141\r
+#define IDS_REINSTALL                                  142\r
+#define IDS_REINSTALL_CAPTION                  143\r
+#define IDC_BUTTON1                     1000\r
+#define IDC_LIST1                       1000\r
+#define IDC_BROWSE_LIST                 1000\r
+#define IDC_RADIO1                      1001\r
+#define IDC_COMBO1                      1001\r
+#define IDC_RADIO2                      1002\r
+#define IDC_GREETING                    1003\r
+#define IDC_CHECK1                      1016\r
+#define IDC_DEFAULT_PRINTER             1016\r
+#define IDC_PRINTER_IMAGE               1017\r
+#define IDC_PRINTER_NAME                1018\r
+#define IDC_PRINTER_MANUFACTURER        1019\r
+#define IDC_PRINTER_MODEL               1020\r
+#define IDC_GOODBYE                     1021\r
+#define IDC_PRINTER_PORT                1022\r
+#define IDC_PRINTER_PROTOCOL            1022\r
+#define IDC_PRINTER_DEFAULT             1023\r
+#define IDC_PRINTER_SELECTION_TEXT      1024\r
+#define IDC_HAVE_DISK                   1025\r
+#define IDC_PRINTER_INFORMATION         1026\r
+#define IDC_LOCATION_LABEL              1029\r
+#define IDC_DESCRIPTION_FIELD           1030\r
+#define IDC_LOCATION_FIELD              1032\r
+#define IDC_DESCRIPTION_LABEL           1033\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE        142\r
+#define _APS_NEXT_COMMAND_VALUE         32771\r
+#define _APS_NEXT_CONTROL_VALUE         1034\r
+#define _APS_NEXT_SYMED_VALUE           101\r
+#endif\r
+#endif\r
diff --git a/Clients/PrinterSetupWizard/resource_loc_res.h b/Clients/PrinterSetupWizard/resource_loc_res.h
new file mode 100755 (executable)
index 0000000..7f77da3
--- /dev/null
@@ -0,0 +1,86 @@
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Visual C++ generated include file.\r
+// Used by PrinterSetupWizardLocRes.rc\r
+//\r
+#define IDR_MANIFEST                    1\r
+#define IDM_ABOUTBOX                    0x0010\r
+#define IDD_ABOUTBOX                    100\r
+#define IDS_ABOUTBOX                    101\r
+#define IDD_PRINTERSETUPWIZARD_DIALOG   102\r
+#define IDS_GOODBYE                     102\r
+#define IDS_GREETING                    103\r
+#define IDS_BROWSE_TITLE                104\r
+#define IDS_BROWSE_SUBTITLE             105\r
+#define IDS_CAPTION                     106\r
+#define IDD_FIRST_PAGE                  107\r
+#define IDS_GOODBYE_GOOD1               107\r
+#define IDS_SEARCHING                   108\r
+#define IDD_SECOND_PAGE                 109\r
+#define IDS_GOODBYTE_GOOD2              109\r
+#define IDS_INSTALL_TITLE               110\r
+#define IDS_INSTALL_SUBTITLE            111\r
+#define IDS_ERROR_SELECTING_PRINTER_TEXT 112\r
+#define IDS_ERROR_SELECTING_PRINTER_CAPTION 113\r
+#define IDS_INSTALL_ERROR_CAPTION       114\r
+#define IDS_INSTALL_ERROR_MESSAGE       115\r
+#define IDS_MANUFACTURER_HEADING        116\r
+#define IDS_MODEL_HEADING               117\r
+#define IDS_NO_RENDEZVOUS_PRINTERS      118\r
+#define IDS_NO_MDNSRESPONDER_SERVICE_TEXT 119\r
+#define IDS_NO_MDNSRESPONDER_SERVICE_CAPTION 120\r
+#define IDS_PRINTER_MATCH_GOOD          121\r
+#define IDS_PRINTER_MATCH_BAD           122\r
+#define IDS_YES                         123\r
+#define IDS_NO                          124\r
+#define IDS_LARGE_FONT                  125\r
+#define IDS_FIREWALL                    126\r
+#define IDS_ERROR_CAPTION               127\r
+#define IDR_MAINFRAME                   128\r
+#define IDS_FIREWALL_CAPTION            128\r
+#define IDB_BANNER_ICON                 129\r
+#define IDD_THIRD_PAGE                  130\r
+#define IDB_WATERMARK                   131\r
+#define IDD_FOURTH_PAGE                 132\r
+#define IDI_INFO                        136\r
+#define IDB_ABOUT                       138\r
+#define IDD_DIALOG1                     139\r
+#define IDI_ICON2                       141\r
+#define IDI_PRINTER                     141\r
+#define IDS_REINSTALL                   142\r
+#define IDS_REINSTALL_CAPTION           143\r
+#define IDC_INFO                                                                144\r
+#define IDC_BUTTON1                     1000\r
+#define IDC_LIST1                       1000\r
+#define IDC_BROWSE_LIST                 1000\r
+#define IDC_RADIO1                      1001\r
+#define IDC_COMBO1                      1001\r
+#define IDC_RADIO2                      1002\r
+#define IDC_GREETING                    1003\r
+#define IDC_CHECK1                      1016\r
+#define IDC_DEFAULT_PRINTER             1016\r
+#define IDC_PRINTER_IMAGE               1017\r
+#define IDC_PRINTER_NAME                1018\r
+#define IDC_PRINTER_MANUFACTURER        1019\r
+#define IDC_PRINTER_MODEL               1020\r
+#define IDC_GOODBYE                     1021\r
+#define IDC_PRINTER_PORT                1022\r
+#define IDC_PRINTER_PROTOCOL            1022\r
+#define IDC_PRINTER_DEFAULT             1023\r
+#define IDC_PRINTER_SELECTION_TEXT      1024\r
+#define IDC_HAVE_DISK                   1025\r
+#define IDC_PRINTER_INFORMATION         1026\r
+#define IDC_LOCATION_LABEL              1029\r
+#define IDC_DESCRIPTION_FIELD           1030\r
+#define IDC_LOCATION_FIELD              1032\r
+#define IDC_DESCRIPTION_LABEL           1033\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE        142\r
+#define _APS_NEXT_COMMAND_VALUE         32771\r
+#define _APS_NEXT_CONTROL_VALUE         1034\r
+#define _APS_NEXT_SYMED_VALUE           101\r
+#endif\r
+#endif\r
diff --git a/Clients/PrinterSetupWizard/resource_res.h b/Clients/PrinterSetupWizard/resource_res.h
new file mode 100755 (executable)
index 0000000..c0f5429
--- /dev/null
@@ -0,0 +1,85 @@
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Visual C++ generated include file.\r
+// Used by PrinterSetupWizard.rc\r
+//\r
+#define IDR_MANIFEST                    1\r
+#define IDM_ABOUTBOX                    0x0010\r
+#define IDD_ABOUTBOX                    100\r
+#define IDS_ABOUTBOX                    101\r
+#define IDD_PRINTERSETUPWIZARD_DIALOG   102\r
+#define IDS_GOODBYE                     102\r
+#define IDS_GREETING                    103\r
+#define IDS_BROWSE_TITLE                104\r
+#define IDS_BROWSE_SUBTITLE             105\r
+#define IDS_CAPTION                     106\r
+#define IDD_FIRST_PAGE                  107\r
+#define IDS_GOODBYE_GOOD1               107\r
+#define IDS_SEARCHING                   108\r
+#define IDD_SECOND_PAGE                 109\r
+#define IDS_GOODBYTE_GOOD2              109\r
+#define IDS_INSTALL_TITLE               110\r
+#define IDS_INSTALL_SUBTITLE            111\r
+#define IDS_ERROR_SELECTING_PRINTER_TEXT 112\r
+#define IDS_ERROR_SELECTING_PRINTER_CAPTION 113\r
+#define IDS_INSTALL_ERROR_CAPTION       114\r
+#define IDS_INSTALL_ERROR_MESSAGE       115\r
+#define IDS_MANUFACTURER_HEADING        116\r
+#define IDS_MODEL_HEADING               117\r
+#define IDS_NO_RENDEZVOUS_PRINTERS      118\r
+#define IDS_NO_MDNSRESPONDER_SERVICE_TEXT 119\r
+#define IDS_NO_MDNSRESPONDER_SERVICE_CAPTION 120\r
+#define IDS_PRINTER_MATCH_GOOD          121\r
+#define IDS_PRINTER_MATCH_BAD           122\r
+#define IDS_YES                         123\r
+#define IDS_NO                          124\r
+#define IDS_LARGE_FONT                  125\r
+#define IDS_FIREWALL                    126\r
+#define IDS_ERROR_CAPTION               127\r
+#define IDR_MAINFRAME                   128\r
+#define IDS_FIREWALL_CAPTION            128\r
+#define IDB_BANNER_ICON                 129\r
+#define IDD_THIRD_PAGE                  130\r
+#define IDB_WATERMARK                   131\r
+#define IDD_FOURTH_PAGE                 132\r
+#define IDI_INFO                        136\r
+#define IDB_ABOUT                       138\r
+#define IDD_DIALOG1                     139\r
+#define IDI_ICON2                       141\r
+#define IDI_PRINTER                     141\r
+#define IDS_REINSTALL                                  142\r
+#define IDS_REINSTALL_CAPTION                  143\r
+#define IDC_BUTTON1                     1000\r
+#define IDC_LIST1                       1000\r
+#define IDC_BROWSE_LIST                 1000\r
+#define IDC_RADIO1                      1001\r
+#define IDC_COMBO1                      1001\r
+#define IDC_RADIO2                      1002\r
+#define IDC_GREETING                    1003\r
+#define IDC_CHECK1                      1016\r
+#define IDC_DEFAULT_PRINTER             1016\r
+#define IDC_PRINTER_IMAGE               1017\r
+#define IDC_PRINTER_NAME                1018\r
+#define IDC_PRINTER_MANUFACTURER        1019\r
+#define IDC_PRINTER_MODEL               1020\r
+#define IDC_GOODBYE                     1021\r
+#define IDC_PRINTER_PORT                1022\r
+#define IDC_PRINTER_PROTOCOL            1022\r
+#define IDC_PRINTER_DEFAULT             1023\r
+#define IDC_PRINTER_SELECTION_TEXT      1024\r
+#define IDC_HAVE_DISK                   1025\r
+#define IDC_PRINTER_INFORMATION         1026\r
+#define IDC_LOCATION_LABEL              1029\r
+#define IDC_DESCRIPTION_FIELD           1030\r
+#define IDC_LOCATION_FIELD              1032\r
+#define IDC_DESCRIPTION_LABEL           1033\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE        142\r
+#define _APS_NEXT_COMMAND_VALUE         32771\r
+#define _APS_NEXT_CONTROL_VALUE         1034\r
+#define _APS_NEXT_SYMED_VALUE           101\r
+#endif\r
+#endif\r
index 17c4a767d46849e0b2bfce6405cb5a0fdbff7961..5c6adac45689e0b02f2d35bede2d672a8c8ad657 100644 (file)
@@ -69,6 +69,7 @@ cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT -DNOT_HAVE_SETLINEBUF ws2_32.lib .
 #include <string.h>                    // For strlen(), strcpy(), bzero()
 #include <errno.h>          // For errno, EINTR
 #include <time.h>
+#include <sys/types.h>      // For u_char
 
 #ifdef _WIN32
 #include <process.h>
@@ -89,6 +90,7 @@ typedef       int     pid_t;
 typedef union { unsigned char b[2]; unsigned short NotAnInteger; } Opaque16;
 
 static int operation;
+static uint32_t interface = kDNSServiceInterfaceIndexAny;
 static DNSServiceRef client  = NULL;
 static DNSServiceRef client2 = NULL;
 static int num_printed;
@@ -549,7 +551,7 @@ static DNSServiceErrorType RegisterService(DNSServiceRef *sdRef,
        printf("Registering Service %s.%s%s", nam, typ, dom);
        if (host && *host) printf(" host %s", host);
        printf(" port %s %s\n", port, txt);
-       return(DNSServiceRegister(sdRef, /* kDNSServiceFlagsAllowRemoteQuery */ 0, 0, nam, typ, dom, host, registerPort.NotAnInteger, ptr-txt, txt, reg_reply, NULL));
+       return(DNSServiceRegister(sdRef, /* kDNSServiceFlagsAllowRemoteQuery */ 0, interface, nam, typ, dom, host, registerPort.NotAnInteger, ptr-txt, txt, reg_reply, NULL));
        }
 
 int main(int argc, char **argv)
@@ -567,6 +569,14 @@ int main(int argc, char **argv)
        setlinebuf(stdout);             // Want to see lines as they appear, not block buffered
 #endif
 
+       if (argc > 1 && !strcmp(argv[1], "-lo"))
+               {
+               argc--;
+               argv++;
+               interface = kDNSServiceInterfaceIndexLocalOnly;
+               printf("Using LocalOnly\n");
+               }
+
        if (argc < 2) goto Fail;        // Minimum command line is the command name and one argument
        operation = getfirstoption( argc, argv, "EFBLQRPAUNTMI", &optind);
        if (operation == -1) goto Fail;
@@ -574,11 +584,11 @@ int main(int argc, char **argv)
        switch (operation)
                {
                case 'E':       printf("Looking for recommended registration domains:\n");
-                                       err = DNSServiceEnumerateDomains(&client, kDNSServiceFlagsRegistrationDomains, 0, enum_reply, NULL);
+                                       err = DNSServiceEnumerateDomains(&client, kDNSServiceFlagsRegistrationDomains, interface, enum_reply, NULL);
                                        break;
 
                case 'F':       printf("Looking for recommended browsing domains:\n");
-                                       err = DNSServiceEnumerateDomains(&client, kDNSServiceFlagsBrowseDomains, 0, enum_reply, NULL);
+                                       err = DNSServiceEnumerateDomains(&client, kDNSServiceFlagsBrowseDomains, interface, enum_reply, NULL);
                                        //enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "nicta.com.au.", NULL);
                                        //enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "rendezvous.nicta.com.au.", NULL);
                                        //enum_reply(client, kDNSServiceFlagsAdd, 0, 0, "ibm.com.", NULL);
@@ -589,14 +599,14 @@ int main(int argc, char **argv)
                                        dom = (argc < optind+2) ? "" : argv[optind+1];
                                        if (dom[0] == '.' && dom[1] == 0) dom[0] = 0;   // We allow '.' on the command line as a synonym for empty string
                                        printf("Browsing for %s%s\n", argv[optind+0], dom);
-                                       err = DNSServiceBrowse(&client, 0, 0, argv[optind+0], dom, browse_reply, NULL);
+                                       err = DNSServiceBrowse(&client, 0, interface, argv[optind+0], dom, browse_reply, NULL);
                                        break;
 
                case 'L':       if (argc < optind+2) goto Fail;
                                        dom = (argc < optind+3) ? "local" : argv[optind+2];
                                        if (dom[0] == '.' && dom[1] == 0) dom = "local";   // We allow '.' on the command line as a synonym for "local"
                                        printf("Lookup %s.%s.%s\n", argv[optind+0], argv[optind+1], dom);
-                                       err = DNSServiceResolve(&client, 0, 0, argv[optind+0], argv[optind+1], dom, resolve_reply, NULL);
+                                       err = DNSServiceResolve(&client, 0, interface, argv[optind+0], argv[optind+1], dom, resolve_reply, NULL);
                                        break;
 
                case 'R':       if (argc < optind+4) goto Fail;
@@ -616,7 +626,7 @@ int main(int argc, char **argv)
                                        rrtype = (argc <= optind+1) ? kDNSServiceType_A  : GetRRType(argv[optind+1]);
                                        rrclass = (argc <= optind+2) ? kDNSServiceClass_IN : atoi(argv[optind+2]);
                                        if (rrtype == kDNSServiceType_TXT || rrtype == kDNSServiceType_PTR) flags |= kDNSServiceFlagsLongLivedQuery;
-                                       err = DNSServiceQueryRecord(&client, flags, 0, argv[optind+0], rrtype, rrclass, qr_reply, NULL);
+                                       err = DNSServiceQueryRecord(&client, flags, interface, argv[optind+0], rrtype, rrclass, qr_reply, NULL);
                                        break;
                                        }
 
@@ -626,7 +636,7 @@ int main(int argc, char **argv)
                                        Opaque16 registerPort = { { 0x12, 0x34 } };
                                        static const char TXT[] = "\xC" "First String" "\xD" "Second String" "\xC" "Third String";
                                        printf("Registering Service Test._testupdate._tcp.local.\n");
-                                       err = DNSServiceRegister(&client, 0, 0, "Test", "_testupdate._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT)-1, TXT, reg_reply, NULL);
+                                       err = DNSServiceRegister(&client, 0, interface, "Test", "_testupdate._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT)-1, TXT, reg_reply, NULL);
                                        break;
                                        }
 
@@ -637,7 +647,7 @@ int main(int argc, char **argv)
                                        for (i=0; i<sizeof(TXT); i++)
                                                if ((i & 0x1F) == 0) TXT[i] = 0x1F; else TXT[i] = 'A' + (i >> 5);
                                        printf("Registering Service Test._testlargetxt._tcp.local.\n");
-                                       err = DNSServiceRegister(&client, 0, 0, "Test", "_testlargetxt._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT), TXT, reg_reply, NULL);
+                                       err = DNSServiceRegister(&client, 0, interface, "Test", "_testlargetxt._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT), TXT, reg_reply, NULL);
                                        break;
                                        }
 
@@ -647,7 +657,7 @@ int main(int argc, char **argv)
                                        static const char TXT1[] = "\xC" "First String"  "\xD" "Second String" "\xC" "Third String";
                                        static const char TXT2[] = "\xD" "Fourth String" "\xC" "Fifth String"  "\xC" "Sixth String";
                                        printf("Registering Service Test._testdualtxt._tcp.local.\n");
-                                       err = DNSServiceRegister(&client, 0, 0, "Test", "_testdualtxt._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT1)-1, TXT1, reg_reply, NULL);
+                                       err = DNSServiceRegister(&client, 0, interface, "Test", "_testdualtxt._tcp.", "", NULL, registerPort.NotAnInteger, sizeof(TXT1)-1, TXT1, reg_reply, NULL);
                                        if (!err) err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_TXT, sizeof(TXT2)-1, TXT2, 0);
                                        break;
                                        }
@@ -657,7 +667,7 @@ int main(int argc, char **argv)
                                        Opaque16 registerPort = { { pid >> 8, pid & 0xFF } };
                                        static const char TXT[] = "\x09" "Test Data";
                                        printf("Registering Service Test._testtxt._tcp.local.\n");
-                                       err = DNSServiceRegister(&client, 0, 0, "Test", "_testtxt._tcp.", "", NULL, registerPort.NotAnInteger, 0, NULL, reg_reply, NULL);
+                                       err = DNSServiceRegister(&client, 0, interface, "Test", "_testtxt._tcp.", "", NULL, registerPort.NotAnInteger, 0, NULL, reg_reply, NULL);
                                        if (!err) err = DNSServiceUpdateRecord(client, NULL, 0, sizeof(TXT)-1, TXT, 0);
                                        break;
                                        }
index 20adec54afbd9091301d8e03e1e8909c366704d3..436297d6217a3ee11001ff5bab5dabba68248071 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@
 
 include /Developer/Makefiles/pb_makefiles/platform.make
 
-MVERS = "mDNSResponder-87"
+MVERS = "mDNSResponder-98"
 
 install:
        cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install     OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS)
index 13319c10a4eb0ea85d3871ac5516b70e37601047..4116c1cdb1339ffcbe4418964a274b6779ee18d9 100644 (file)
     Change History (most recent first):
 
 $Log: DNSCommon.c,v $
+Revision 1.83  2005/01/27 22:57:55  cheshire
+Fix compile errors on gcc4
+
+Revision 1.82  2005/01/19 03:27:03  cheshire
+<rdar://problem/3961051> CPU Spin in mDNSResponder
+GetNextScheduledEvent() needs to check LocalRecordReady()
+
+Revision 1.81  2004/12/18 03:13:45  cheshire
+<rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
+
+Revision 1.80  2004/12/16 21:46:43  cheshire
+Add DNSTypeName case for kDNSType_SOA
+
+Revision 1.79  2004/12/16 21:38:37  cheshire
+Add DNSTypeName case for kDNSType_NS
+
+Revision 1.78  2004/12/16 21:27:37  ksekar
+Fixed build failures when compiled with verbose debugging messages
+
+Revision 1.77  2004/12/16 20:12:59  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
+Revision 1.76  2004/12/16 08:05:29  shersche
+Remove extranenous semicolons that cause compilation errors on Windows
+
+Revision 1.75  2004/12/15 02:11:22  ksekar
+<rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness
+
 Revision 1.74  2004/12/09 22:49:15  ksekar
 <rdar://problem/3913653> Wide-Area Goodbyes broken
 
@@ -299,7 +327,7 @@ mDNSexport DNameListElem *mDNS_CopyDNameList(const DNameListElem *orig)
                {
                newelem = (DNameListElem*)mDNSPlatformMemAllocate(sizeof(DNameListElem));
                if (!newelem) { LogMsg("ERROR: malloc"); return mDNSNULL; }
-               AssignDomainName(newelem->name, ptr->name);
+               AssignDomainName(&newelem->name, &ptr->name);
                newelem->next = copy;
                copy = newelem;
                }
@@ -352,10 +380,10 @@ mDNSexport mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *
 mDNSexport mDNSu32 NumCacheRecordsForInterfaceID(const mDNS *const m, mDNSInterfaceID id)
        {
        mDNSu32 slot, used = 0;
+       CacheGroup *cg;
        CacheRecord *rr;
-       for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
-               for (rr = m->rrcache_hash[slot]; rr; rr=rr->next)
-                       if (rr->resrec.InterfaceID == id) used++;
+       FORALL_CACHERECORDS(slot, cg, rr)
+               if (rr->resrec.InterfaceID == id) used++;
        return(used);
        }
 
@@ -364,7 +392,9 @@ mDNSexport char *DNSTypeName(mDNSu16 rrtype)
        switch (rrtype)
                {
                case kDNSType_A:    return("Addr");
+               case kDNSType_NS:   return("NS");
                case kDNSType_CNAME:return("CNAME");
+               case kDNSType_SOA:  return("SOA");
                case kDNSType_NULL: return("NULL");
                case kDNSType_PTR:  return("PTR");
                case kDNSType_HINFO:return("HINFO");
@@ -383,7 +413,7 @@ mDNSexport char *DNSTypeName(mDNSu16 rrtype)
 mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *rr, RDataBody *rd, char *buffer)
        {
        char *ptr = buffer;
-       mDNSu32 length = mDNS_snprintf(buffer, 79, "%4d %##s %s ", rr->rdlength, rr->name.c, DNSTypeName(rr->rrtype));
+       mDNSu32 length = mDNS_snprintf(buffer, 79, "%4d %##s %s ", rr->rdlength, rr->name->c, DNSTypeName(rr->rrtype));
        switch (rr->rrtype)
                {
                case kDNSType_A:        mDNS_snprintf(buffer+length, 79-length, "%.4a", &rd->ipv4);          break;
@@ -1029,26 +1059,26 @@ mDNSexport mDNSBool SameResourceRecord(ResourceRecord *r1, ResourceRecord *r2)
        {
        return (r1->namehash == r2->namehash &&
                        r1->rrtype == r2->rrtype && 
-                       SameDomainName(&r1->name, &r2->name) &&
+                       SameDomainName(r1->name, r2->name) &&
                        SameRData(r1, r2));
        }
 
 mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
        {
        if (rr->InterfaceID &&
-               q ->InterfaceID &&
+               q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
                rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
 
        // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
        if (rr->rrtype != kDNSType_CNAME && rr->rrtype  != q->qtype  && q->qtype  != kDNSQType_ANY ) return(mDNSfalse);
        if (                                rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
-       return(rr->namehash == q->qnamehash && SameDomainName(&rr->name, &q->qname));
+       return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
        }
 
 mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate)
        {
        const RDataBody *rd = &rr->rdata->u;
-       const domainname *const name = estimate ? &rr->name : mDNSNULL;
+       const domainname *const name = estimate ? rr->name : mDNSNULL;
        switch (rr->rrtype)
                {
                case kDNSType_A:        return(sizeof(rd->ipv4));
@@ -1259,7 +1289,7 @@ mDNSlocal mDNSu8 *putOptRData(mDNSu8 *ptr, const mDNSu8 *limit, ResourceRecord *
                {
                // check if space for opt/optlen
                if (ptr + (2 * sizeof(mDNSu16)) > limit) goto space_err;
-               (mDNSu8 *)opt = rr->rdata->u.data + nput;
+               opt = (rdataOpt *)(rr->rdata->u.data + nput);
                ptr = putVal16(ptr, opt->opt);
                ptr = putVal16(ptr, opt->optlen);
                nput += 2 * sizeof(mDNSu16);
@@ -1400,11 +1430,11 @@ mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *
 
        if (rr->RecordType == kDNSRecordTypeUnregistered)
                {
-               LogMsg("PutResourceRecord ERROR! Attempt to put kDNSRecordTypeUnregistered %##s (%s)", rr->name.c, DNSTypeName(rr->rrtype));
+               LogMsg("PutResourceRecord ERROR! Attempt to put kDNSRecordTypeUnregistered %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype));
                return(ptr);
                }
 
-       ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->name);
+       ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
        if (!ptr || ptr + 10 >= limit) return(mDNSNULL);        // If we're out-of-space, return mDNSNULL
        ptr[0] = (mDNSu8)(rr->rrtype  >> 8);
        ptr[1] = (mDNSu8)(rr->rrtype  &  0xFF);
@@ -1415,7 +1445,7 @@ mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *
        ptr[6] = (mDNSu8)((ttl >>  8) &  0xFF);
        ptr[7] = (mDNSu8)( ttl        &  0xFF);
        endofrdata = putRData(msg, ptr+10, limit, rr);
-       if (!endofrdata) { verbosedebugf("Ran out of space in PutResourceRecord for %##s (%s)", rr->name.c, DNSTypeName(rr->rrtype)); return(mDNSNULL); }
+       if (!endofrdata) { verbosedebugf("Ran out of space in PutResourceRecord for %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype)); return(mDNSNULL); }
 
        // Go back and fill in the actual number of data bytes we wrote
        // (actualLength can be less than rdlength when domain name compression is used)
@@ -1424,7 +1454,7 @@ mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *
        ptr[9] = (mDNSu8)(actualLength &  0xFF);
 
        if (count) (*count)++;
-       else LogMsg("PutResourceRecordTTL: ERROR: No target count to update for %##s (%s)", rr->name.c, DNSTypeName(rr->rrtype));
+       else LogMsg("PutResourceRecordTTL: ERROR: No target count to update for %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype));
        return(endofrdata);
        }
 
@@ -1438,7 +1468,7 @@ mDNSexport mDNSu8 *PutResourceRecordCappedTTL(DNSMessage *const msg, mDNSu8 *ptr
 mDNSexport mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit,
        mDNSu16 *count, const AuthRecord *rr)
        {
-       ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->resrec.name);
+       ptr = putDomainNameAsLabels(msg, ptr, limit, rr->resrec.name);
        if (!ptr || ptr + 10 > limit) return(mDNSNULL);         // If we're out-of-space, return mDNSNULL
        ptr[0] = (mDNSu8)(rr->resrec.rrtype  >> 8);                             // Put type
        ptr[1] = (mDNSu8)(rr->resrec.rrtype  &  0xFF);
@@ -1481,7 +1511,8 @@ mDNSexport mDNSu8 *putPrereqNameNotInUse(domainname *name, DNSMessage *msg, mDNS
        AuthRecord prereq;
 
        mDNSPlatformMemZero(&prereq, sizeof(AuthRecord));
-       AssignDomainName(prereq.resrec.name, *name);
+       mDNS_SetupResourceRecord(&prereq, mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
+       AssignDomainName(prereq.resrec.name, name);
        prereq.resrec.rrtype = kDNSQType_ANY;
        prereq.resrec.rrclass = kDNSClass_NONE;
        ptr = putEmptyResourceRecord(msg, ptr, end, &msg->h.mDNS_numPrereqs, &prereq);
@@ -1501,10 +1532,28 @@ mDNSexport mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecor
        return ptr;
        }
 
+mDNSexport mDNSu8 *putDeleteRRSet(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype)
+       {
+       const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
+       mDNSu16 class = kDNSQClass_ANY;
+       
+       ptr = putDomainNameAsLabels(msg, ptr, limit, name);
+       if (!ptr || ptr + 10 >= limit) return mDNSNULL; // If we're out-of-space, return mDNSNULL
+       ptr[0] = (mDNSu8)(rrtype  >> 8);
+       ptr[1] = (mDNSu8)(rrtype  &  0xFF);
+       ptr[2] = (mDNSu8)(class >> 8);
+       ptr[3] = (mDNSu8)(class &  0xFF);
+       ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl
+       ptr[8] = ptr[9] = 0; // zero rdlength/rdata
+
+       msg->h.mDNS_numUpdates++;
+       return ptr + 10;
+       }
+
 // for dynamic updates
 mDNSexport mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name)
        {
-       const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;;
+       const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
        mDNSu16 class = kDNSQClass_ANY;
        mDNSu16 rrtype = kDNSQType_ANY;
        
@@ -1529,7 +1578,7 @@ mDNSexport mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease)
        rdataOpt *optRD;
 
        mDNSPlatformMemZero(&rr, sizeof(AuthRecord));
-       opt->rdata = &rr.rdatastorage;
+       mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, 0, mDNSNULL, mDNSNULL);
        
        opt->RecordType = kDNSRecordTypeKnownUnique;  // to avoid warnings in other layers
        opt->rrtype = kDNSType_OPT;
@@ -1688,6 +1737,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
 
        rr->next              = mDNSNULL;
        rr->resrec.RecordType = RecordType;
+       rr->resrec.name       = &largecr->namestorage;
 
        rr->NextInKAList      = mDNSNULL;
        rr->TimeRcvd          = m ? m->timenow : 0;
@@ -1704,7 +1754,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
        rr->NextInCFList      = mDNSNULL;
 
        rr->resrec.InterfaceID       = InterfaceID;
-       ptr = getDomainName(msg, ptr, end, &rr->resrec.name);
+       ptr = getDomainName(msg, ptr, end, rr->resrec.name);
        if (!ptr) { debugf("GetResourceRecord: Malformed RR name"); return(mDNSNULL); }
 
        if (ptr + 10 > end) { debugf("GetResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
@@ -1726,7 +1776,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
        rr->resrec.rdata = (RData*)&rr->rdatastorage;
        rr->resrec.rdata->MaxRDLength = MaximumRDSize;
 
-       if (!RecordType) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr->resrec.name.c);
+       if (!RecordType) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr->resrec.name->c);
 
        switch (rr->resrec.rrtype)
                {
@@ -1799,7 +1849,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
                                                        break;
                }
 
-       rr->resrec.namehash = DomainNameHashValue(&rr->resrec.name);
+       rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
        SetNewRData(&rr->resrec, mDNSNULL, 0);
 
        return(ptr + pktrdlength);
@@ -1974,10 +2024,9 @@ mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
                if (m->NewQuestions->DelayAnswering) e = m->NewQuestions->DelayAnswering;
                else return(m->timenow);
                }
-       if (m->NewLocalOnlyQuestions)   return(m->timenow);
-       if (m->NewLocalOnlyRecords)     return(m->timenow);
-       if (m->DiscardLocalOnlyRecords) return(m->timenow);
-       if (m->SuppressSending)         return(m->SuppressSending);
+       if (m->NewLocalOnlyQuestions)                                   return(m->timenow);
+       if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords)) return(m->timenow);
+       if (m->SuppressSending)                                         return(m->SuppressSending);
 #ifndef UNICAST_DISABLED
        if (e - m->uDNS_info.nextevent   > 0) e = m->uDNS_info.nextevent;
 #endif
index 5466501525d088def4bdb3ee124425a8ef1f7941..6a6ae706b0df81b439b0a52fb40fcc76dfc80c5d 100644 (file)
     Change History (most recent first):
 
 $Log: DNSCommon.h,v $
+Revision 1.30  2005/01/19 03:12:44  cheshire
+Move LocalRecordReady() macro from mDNS.c to DNSCommon.h
+
+Revision 1.29  2004/12/15 02:11:22  ksekar
+<rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness
+
 Revision 1.28  2004/12/06 21:15:22  ksekar
 <rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
 
@@ -236,6 +242,7 @@ extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate);
        ((RR)->rrtype == kDNSType_SRV                                  ) ? &(RR)->rdata->u.srv.target : mDNSNULL )
 
 extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd);
+#define LocalRecordReady(X) ((X)->resrec.RecordType != kDNSRecordTypeUnique && (X)->resrec.RecordType != kDNSRecordTypeDeregistering)
 
 
 // ***************************************************************************
@@ -275,6 +282,8 @@ extern mDNSu8 *putPrereqNameNotInUse(domainname *name, DNSMessage *msg, mDNSu8 *
 
 extern mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr);
 
+extern  mDNSu8 *putDeleteRRSet(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype);
+
 extern mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name);
        
 extern mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease);
@@ -332,7 +341,7 @@ extern mStatus mDNSSendDNSMessage(const mDNS *const m, DNSMessage *const msg, mD
 
 extern void mDNS_Lock(mDNS *const m);
 extern void mDNS_Unlock(mDNS *const m);
-       
+
 #ifdef __cplusplus
        }
 #endif
index 55e304c2c8060a6732901fefe2b700d03be55c7f..89d7b013fd835b80f4d5d161eec39b94c0b26ff8 100644 (file)
@@ -23,6 +23,9 @@
     Change History (most recent first):
 
 $Log: DNSDigest.c,v $
+Revision 1.13  2004/12/16 20:12:59  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
 Revision 1.12  2004/12/03 07:20:50  ksekar
 <rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
 
@@ -1374,7 +1377,7 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16
        mDNS_SetupResourceRecord(&tsig, mDNSNULL, 0, kDNSType_TSIG, 0, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
 
        // key name
-       AssignDomainName(tsig.resrec.name, info->keyname);
+       AssignDomainName(tsig.resrec.name, &info->keyname);
        MD5_Update(&c, info->keyname.c, DomainNameLength(&info->keyname));
 
        // class
@@ -1387,7 +1390,7 @@ mDNSexport mDNSu8 *DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, mDNSu16
        MD5_Update(&c, (mDNSu8 *)&tsig.resrec.rroriginalttl, sizeof(tsig.resrec.rroriginalttl));
        
        // alg name
-       AssignDomainName(tsig.resrec.rdata->u.name, HMAC_MD5_AlgName);
+       AssignDomainName(&tsig.resrec.rdata->u.name, &HMAC_MD5_AlgName);
        len = DomainNameLength(&HMAC_MD5_AlgName);
        rdata = tsig.resrec.rdata->u.data + len;
        MD5_Update(&c, HMAC_MD5_AlgName.c, len);
index 83f634bc83eb0244e74f88e1667206ade6282405..f517066a256c5a5d20eede35431f84fd6908de08 100755 (executable)
     Change History (most recent first):
 
 $Log: mDNS.c,v $
+Revision 1.516  2005/01/28 06:06:32  cheshire
+Update comment
+
+Revision 1.515  2005/01/27 00:21:49  cheshire
+<rdar://problem/3973798> Remove mDNSResponder sleep/wake syslog message
+
+Revision 1.514  2005/01/21 01:33:45  cheshire
+<rdar://problem/3962979> Shutdown time regression: mDNSResponder not responding to SIGTERM
+
+Revision 1.513  2005/01/21 00:07:54  cheshire
+<rdar://problem/3962717> Infinite loop when the same service is registered twice, and then suffers a name conflict
+
+Revision 1.512  2005/01/20 00:37:45  cheshire
+<rdar://problem/3941448> mDNSResponder crashed in mDNSCoreReceiveResponse
+Take care not to recycle records while they are on the CacheFlushRecords list
+
+Revision 1.511  2005/01/19 22:48:53  cheshire
+<rdar://problem/3955355> Handle services with subtypes correctly when doing mDNS_RenameAndReregisterService()
+
+Revision 1.510  2005/01/19 03:12:45  cheshire
+Move LocalRecordReady() macro from mDNS.c to DNSCommon.h
+
+Revision 1.509  2005/01/19 03:08:49  cheshire
+<rdar://problem/3961051> CPU Spin in mDNSResponder
+Log messages to help catch and report CPU spins
+
+Revision 1.508  2005/01/18 18:56:32  cheshire
+<rdar://problem/3934245> QU responses not promoted to multicast responses when appropriate
+
+Revision 1.507  2005/01/18 01:12:07  cheshire
+<rdar://problem/3956258> Logging into VPN causes mDNSResponder to reissue multicast probes
+
+Revision 1.506  2005/01/17 23:28:53  cheshire
+Fix compile error
+
+Revision 1.505  2005/01/11 02:02:56  shersche
+Move variable declaration to the beginning of statement block
+
+Revision 1.504  2004/12/20 20:24:35  cheshire
+<rdar://problem/3928456> Network efficiency: Don't keep polling if we have at least one unique-type answer
+
+Revision 1.503  2004/12/20 18:41:47  cheshire
+<rdar://problem/3591622> Low memory support: Provide answers even when we don't have cache space
+
+Revision 1.502  2004/12/20 18:04:08  cheshire
+<rdar://problem/3923098> For now, don't put standard wide-area unicast responses in our main cache
+
+Revision 1.501  2004/12/19 23:50:18  cheshire
+<rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
+Don't show "No active interface to send" messages for kDNSServiceInterfaceIndexLocalOnly services
+
+Revision 1.500  2004/12/18 03:13:46  cheshire
+<rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
+
+Revision 1.499  2004/12/17 23:37:45  cheshire
+<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
+(and other repetitive configuration changes)
+
+Revision 1.498  2004/12/17 05:25:46  cheshire
+<rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
+
+Revision 1.497  2004/12/17 03:20:58  cheshire
+<rdar://problem/3925168> Don't send unicast replies we know will be ignored
+
+Revision 1.496  2004/12/16 22:18:26  cheshire
+Make AddressIsLocalSubnet() a little more selective -- ignore point-to-point interfaces
+
+Revision 1.495  2004/12/16 21:27:37  ksekar
+Fixed build failures when compiled with verbose debugging messages
+
+Revision 1.494  2004/12/16 20:46:56  cheshire
+Fix compiler warnings
+
+Revision 1.493  2004/12/16 20:13:00  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
+Revision 1.492  2004/12/16 08:03:24  shersche
+Fix compilation error when UNICAST_DISABLED is set
+
 Revision 1.491  2004/12/11 01:52:11  cheshire
 <rdar://problem/3785820> Support kDNSServiceFlagsAllowRemoteQuery for registering services too
 
@@ -1592,8 +1671,6 @@ Revision 1.56  2002/09/16 19:44:17  cheshire
 Merge in license terms from Quinn's copy, in preparation for Darwin release
 */
 
-#define TEST_LOCALONLY_FOR_EVERYTHING 0
-
 #include "DNSCommon.h"                  // Defines general DNS untility routines
 #include "uDNS.h"                                              // Defines entry points into unicast-specific routines
 // Disable certain benign warnings with Microsoft compilers
@@ -1626,9 +1703,8 @@ mDNSexport const mDNSv6Addr      onesIPv6Addr      = { { 255, 255, 255, 255, 255
 mDNSexport const mDNSAddr        zeroAddr          = { mDNSAddrType_None, {{{ 0 }}} };
 
 mDNSexport const mDNSInterfaceID mDNSInterface_Any        = 0;
-mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly  = (mDNSInterfaceID)-1;
+mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly  = (mDNSInterfaceID)1;
 
-// Note that mDNSInterfaceMark is the same value as mDNSInterface_LocalOnly, but they are used in different contexts
 mDNSlocal  const mDNSInterfaceID mDNSInterfaceMark        = (mDNSInterfaceID)~0;
 
 #define UnicastDNSPortAsNumber 53
@@ -1653,13 +1729,13 @@ mDNSexport const mDNSOpaque16 UpdateRespFlags={ { kDNSFlag0_QR_Response | kDNSFl
 #define kMaxUpdateCredits 10
 #define kUpdateCreditRefreshInterval (mDNSPlatformOneSecond * 6)
 
-static const char *const mDNS_DomainTypeNames[] =
+mDNSexport const char *const mDNS_DomainTypeNames[] =
        {
-       "_browse._dns-sd._udp.",
-       "_default._browse._dns-sd._udp.",
-       "_register._dns-sd._udp.",
-       "_default._register._dns-sd._udp.",
-       "_legacy._browse._dns-sd._udp."
+        "b._dns-sd._udp.",             // Browse
+       "db._dns-sd._udp.",             // Default Browse
+       "lb._dns-sd._udp.",             // Legacy Browse
+        "r._dns-sd._udp.",             // Registration
+       "dr._dns-sd._udp."              // Default Registration
        };
 
 #ifdef UNICAST_DISABLED
@@ -1984,6 +2060,141 @@ mDNSlocal void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
                        m->NextScheduledQuery = (q->LastQTime + q->ThisQInterval);
        }
 
+mDNSlocal CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name)
+       {
+       CacheGroup *cg;
+       for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
+               if (cg->namehash == namehash && SameDomainName(cg->name, name))
+                       break;
+       return(cg);
+       }
+
+mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr)
+       {
+       return(CacheGroupForName(m, slot, rr->namehash, rr->name));
+       }
+
+mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
+       {
+       NetworkInterfaceInfo *intf;
+
+       if (addr->type == mDNSAddrType_IPv4)
+               {
+               if (addr->ip.v4.b[0] == 169 && addr->ip.v4.b[1] == 254) return(mDNStrue);
+               for (intf = m->HostInterfaces; intf; intf = intf->next)
+                       if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
+                               if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0)
+                                       return(mDNStrue);
+               }
+
+       if (addr->type == mDNSAddrType_IPv6)
+               {
+               if (addr->ip.v6.b[0] == 0xFE && addr->ip.v6.b[1] == 0x80) return(mDNStrue);
+               for (intf = m->HostInterfaces; intf; intf = intf->next)
+                       if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID && intf->McastTxRx)
+                               if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) &&
+                                       (((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) &&
+                                       (((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) &&
+                                       (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0))
+                                               return(mDNStrue);
+               }
+
+       return(mDNSfalse);
+       }
+
+// Set up a AuthRecord with sensible default values.
+// These defaults may be overwritten with new values before mDNS_Register is called
+mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
+       mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context)
+       {
+       mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo));
+       // Don't try to store a TTL bigger than we can represent in platform time units
+       if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond)
+               ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond;
+       else if (ttl == 0)              // And Zero TTL is illegal
+               ttl = DefaultTTLforRRType(rrtype);
+
+       // Field Group 1: The actual information pertaining to this resource record
+       rr->resrec.RecordType        = RecordType;
+       rr->resrec.InterfaceID       = InterfaceID;
+       rr->resrec.name              = &rr->namestorage;
+       rr->resrec.rrtype            = rrtype;
+       rr->resrec.rrclass           = kDNSClass_IN;
+       rr->resrec.rroriginalttl     = ttl;
+//     rr->resrec.rdlength          = MUST set by client and/or in mDNS_Register_internal
+//     rr->resrec.rdestimate        = set in mDNS_Register_internal
+//     rr->resrec.rdata             = MUST be set by client
+
+       if (RDataStorage)
+               rr->resrec.rdata = RDataStorage;
+       else
+               {
+               rr->resrec.rdata = &rr->rdatastorage;
+               rr->resrec.rdata->MaxRDLength = sizeof(RDataBody);
+               }
+
+       // Field Group 2: Persistent metadata for Authoritative Records
+       rr->Additional1       = mDNSNULL;
+       rr->Additional2       = mDNSNULL;
+       rr->DependentOn       = mDNSNULL;
+       rr->RRSet             = mDNSNULL;
+       rr->RecordCallback    = Callback;
+       rr->RecordContext     = Context;
+
+       rr->HostTarget        = mDNSfalse;
+       rr->AllowRemoteQuery  = mDNSfalse;
+       rr->ForceMCast        = mDNSfalse;
+
+       // Field Group 3: Transient state for Authoritative Records (set in mDNS_Register_internal)
+       
+       rr->namestorage.c[0]  = 0;              // MUST be set by client before calling mDNS_Register()
+       }
+
+// For a single given DNSQuestion, deliver an add/remove result for the single given AuthRecord
+// Used by AnswerLocalQuestions() and AnswerNewLocalOnlyQuestion()
+mDNSlocal void AnswerLocalOnlyQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, mDNSBool AddRecord)
+       {
+       // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
+       if (AddRecord) rr->LocalAnswer = mDNStrue;
+       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
+       if (q->QuestionCallback)
+               q->QuestionCallback(m, q, &rr->resrec, AddRecord);
+       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
+       }
+
+// When a new local AuthRecord is created or deleted, AnswerLocalQuestions() runs though our LocalOnlyQuestions delivering answers to each,
+// stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
+// If the AuthRecord is marked mDNSInterface_LocalOnly, then we also deliver it to any other questions we have using mDNSInterface_Any.
+// Used by AnswerForNewLocalRecords() and mDNS_Deregister_internal()
+mDNSlocal void AnswerLocalQuestions(mDNS *const m, AuthRecord *rr, mDNSBool AddRecord)
+       {
+       if (m->CurrentQuestion) LogMsg("AnswerLocalQuestions ERROR m->CurrentQuestion already set");
+
+       m->CurrentQuestion = m->LocalOnlyQuestions;
+       while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions)
+               {
+               DNSQuestion *q = m->CurrentQuestion;
+               m->CurrentQuestion = q->next;
+               if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+                       AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord);                 // MUST NOT dereference q again
+               }
+
+       // If this AuthRecord is marked LocalOnly, then we want to deliver it to all local 'mDNSInterface_Any' questions
+       if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
+               {
+               m->CurrentQuestion = m->Questions;
+               while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
+                       {
+                       DNSQuestion *q = m->CurrentQuestion;
+                       m->CurrentQuestion = q->next;
+                       if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+                               AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord);         // MUST NOT dereference q again
+                       }
+               }
+
+       m->CurrentQuestion = mDNSNULL;
+       }
+
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -2038,7 +2249,7 @@ mDNSlocal mDNSBool SameResourceRecordSignature(const ResourceRecord *const r1, c
        if (r1->InterfaceID &&
                r2->InterfaceID &&
                r1->InterfaceID != r2->InterfaceID) return(mDNSfalse);
-       return(mDNSBool)(r1->rrtype == r2->rrtype && r1->rrclass == r2->rrclass && r1->namehash == r2->namehash && SameDomainName(&r1->name, &r2->name));
+       return(mDNSBool)(r1->rrtype == r2->rrtype && r1->rrclass == r2->rrclass && r1->namehash == r2->namehash && SameDomainName(r1->name, r2->name));
        }
 
 // PacketRRMatchesSignature behaves as SameResourceRecordSignature, except that types may differ if our
@@ -2054,7 +2265,7 @@ mDNSlocal mDNSBool PacketRRMatchesSignature(const CacheRecord *const pktrr, cons
                authrr->resrec.InterfaceID &&
                pktrr->resrec.InterfaceID != authrr->resrec.InterfaceID) return(mDNSfalse);
        if (!(authrr->resrec.RecordType & kDNSRecordTypeUniqueMask) && pktrr->resrec.rrtype != authrr->resrec.rrtype) return(mDNSfalse);
-       return(mDNSBool)(pktrr->resrec.rrclass == authrr->resrec.rrclass && pktrr->resrec.namehash == authrr->resrec.namehash && SameDomainName(&pktrr->resrec.name, &authrr->resrec.name));
+       return(mDNSBool)(pktrr->resrec.rrclass == authrr->resrec.rrclass && pktrr->resrec.namehash == authrr->resrec.namehash && SameDomainName(pktrr->resrec.name, authrr->resrec.name));
        }
 
 // IdenticalResourceRecord returns true if two resources records have
@@ -2063,7 +2274,7 @@ mDNSlocal mDNSBool IdenticalResourceRecord(const ResourceRecord *const r1, const
        {
        if (!r1) { LogMsg("IdenticalResourceRecord ERROR: r1 is NULL"); return(mDNSfalse); }
        if (!r2) { LogMsg("IdenticalResourceRecord ERROR: r2 is NULL"); return(mDNSfalse); }
-       if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass || r1->namehash != r2->namehash || !SameDomainName(&r1->name, &r2->name)) return(mDNSfalse);
+       if (r1->rrtype != r2->rrtype || r1->rrclass != r2->rrclass || r1->namehash != r2->namehash || !SameDomainName(r1->name, r2->name)) return(mDNSfalse);
        return(SameRData(r1, r2));
        }
 
@@ -2077,7 +2288,7 @@ mDNSlocal mDNSBool IdenticalResourceRecord(const ResourceRecord *const r1, const
 mDNSlocal mDNSBool ShouldSuppressKnownAnswer(const CacheRecord *const ka, const AuthRecord *const rr)
        {
        // If RR signature is different, or data is different, then don't suppress our answer
-       if (!IdenticalResourceRecord(&ka->resrec,&rr->resrec)) return(mDNSfalse);
+       if (!IdenticalResourceRecord(&ka->resrec, &rr->resrec)) return(mDNSfalse);
        
        // If the requester's indicated TTL is less than half the real TTL,
        // we need to give our answer before the requester's copy expires.
@@ -2159,11 +2370,11 @@ mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
        if (!target) debugf("SetTargetToHostName: Don't know how to set the target of rrtype %d", rr->resrec.rrtype);
 
        if (target && SameDomainName(target, &m->MulticastHostname))
-               debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name.c, target->c);
+               debugf("SetTargetToHostName: Target of %##s is already %##s", rr->resrec.name->c, target->c);
        
        if (target && !SameDomainName(target, &m->MulticastHostname))
                {
-               AssignDomainName(*target, m->MulticastHostname);
+               AssignDomainName(target, &m->MulticastHostname);
                SetNewRData(&rr->resrec, mDNSNULL, 0);
                
                // If we're in the middle of probing this record, we need to start again,
@@ -2175,7 +2386,7 @@ mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
                // changing to the new rdata. However, in practice, we only do SetTargetToHostName for unique records,
                // so when we announce them we'll set the kDNSClass_UniqueRRSet and clear any stale data that way.
                if (rr->RequireGoodbye && rr->resrec.RecordType == kDNSRecordTypeShared)
-                       debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                       debugf("Have announced shared record %##s (%s) at least once: should have sent a goodbye packet before updating", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
 
                rr->AnnounceCount  = InitialAnnounceCount;
                rr->RequireGoodbye = mDNSfalse;
@@ -2207,29 +2418,23 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        AuthRecord *r;
        AuthRecord **p = &m->ResourceRecords;
        AuthRecord **d = &m->DuplicateRecords;
-       AuthRecord **l = &m->LocalOnlyRecords;
 
        mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo));
 
        if ((mDNSs32)rr->resrec.rroriginalttl <= 0)
                { LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
        
-#if TEST_LOCALONLY_FOR_EVERYTHING
-       rr->resrec.InterfaceID = mDNSInterface_LocalOnly;
-#endif
-
 #ifndef UNICAST_DISABLED
-    if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(&rr->resrec.name))
+    if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(rr->resrec.name))
        rr->uDNS_info.id = zeroID;
     else return uDNS_RegisterRecord(m, rr);
 #endif
        
        while (*p && *p != rr) p=&(*p)->next;
        while (*d && *d != rr) d=&(*d)->next;
-       while (*l && *l != rr) l=&(*l)->next;
-       if (*d || *p || *l)
+       if (*d || *p)
                {
-               LogMsg("Error! Tried to register a AuthRecord %p %##s (%s) that's already in the list", rr, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+               LogMsg("Error! Tried to register a AuthRecord %p %##s (%s) that's already in the list", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                return(mStatus_AlreadyRegistered);
                }
 
@@ -2240,13 +2445,13 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
                else
                        {
                        LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn && RecordType != kDNSRecordTypeUnique",
-                               rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                               rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                        return(mStatus_Invalid);
                        }
                if (!(rr->DependentOn->resrec.RecordType & (kDNSRecordTypeUnique | kDNSRecordTypeVerified)))
                        {
                        LogMsg("mDNS_Register_internal: ERROR! %##s (%s): rr->DependentOn->RecordType bad type %X",
-                               rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), rr->DependentOn->resrec.RecordType);
+                               rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->DependentOn->resrec.RecordType);
                        return(mStatus_Invalid);
                        }
                }
@@ -2284,6 +2489,7 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        rr->ProbeCount        = DefaultProbeCountForRecordType(rr->resrec.RecordType);
        rr->AnnounceCount     = InitialAnnounceCount;
        rr->RequireGoodbye    = mDNSfalse;
+       rr->LocalAnswer       = mDNSfalse;
        rr->IncludeInProbe    = mDNSfalse;
        rr->ImmedAnswer       = mDNSNULL;
        rr->ImmedUnicast      = mDNSfalse;
@@ -2308,7 +2514,7 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        rr->UpdateBlocked     = 0;
 
 //     rr->resrec.interface         = already set in mDNS_SetupResourceRecord
-//     rr->resrec.name.c            = MUST be set by client
+//     rr->resrec.name->c            = MUST be set by client
 //     rr->resrec.rrtype            = already set in mDNS_SetupResourceRecord
 //     rr->resrec.rrclass           = already set in mDNS_SetupResourceRecord
 //     rr->resrec.rroriginalttl     = already set in mDNS_SetupResourceRecord
@@ -2322,7 +2528,7 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
                rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
                }
 
-       if (!ValidateDomainName(&rr->resrec.name))
+       if (!ValidateDomainName(rr->resrec.name))
                { LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
 
        // Some (or perhaps all) versions of BIND named (name daemon) don't allow updates with zero-length rdata. It's common for
@@ -2333,62 +2539,57 @@ mDNSlocal mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
                { LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
 
-       rr->resrec.namehash   = DomainNameHashValue(&rr->resrec.name);
+       rr->resrec.namehash   = DomainNameHashValue(rr->resrec.name);
        rr->resrec.rdatahash  = RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u);
        rr->resrec.rdnamehash = target ? DomainNameHashValue(target) : 0;
        
        if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
                {
-               debugf("Adding %p %##s (%s) to LocalOnly list", rr, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
-               *l = rr;
-               if (!m->NewLocalOnlyRecords) m->NewLocalOnlyRecords = rr;
                // If this is supposed to be unique, make sure we don't have any name conflicts
                if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
                        {
                        const AuthRecord *s1 = rr->RRSet ? rr->RRSet : rr;
-                       for (r = m->LocalOnlyRecords; r; r=r->next)
+                       for (r = m->ResourceRecords; r; r=r->next)
                                {
                                const AuthRecord *s2 = r->RRSet ? r->RRSet : r;
                                if (s1 != s2 && SameResourceRecordSignature(&r->resrec, &rr->resrec) && !SameRData(&r->resrec, &rr->resrec))
                                        break;
                                }
-                       if (r)  // If we found a conflict, set DiscardLocalOnlyRecords so we'll deliver the callback
+                       if (r)  // If we found a conflict, set RecordType = kDNSRecordTypeDeregistering so we'll deliver the callback
                                {
-                               debugf("Name conflict %p %##s (%s)", rr, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
-                               m->DiscardLocalOnlyRecords = mDNStrue;
-                               }
-                       else    // else no conflict, so set ProbeCount to zero and update RecordType as appropriate
-                               {
-                               rr->ProbeCount = 0;
-                               if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
+                               debugf("Name conflict %p %##s (%s)", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+                               rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
+                               rr->resrec.rroriginalttl = 0;
+                               rr->ImmedAnswer          = mDNSInterfaceMark;
+                               m->NextScheduledResponse = m->timenow;
                                }
                        }
                }
+
+       // Now that we've finished building our new record, make sure it's not identical to one we already have
+       for (r = m->ResourceRecords; r; r=r->next) if (RecordIsLocalDuplicate(r, rr)) break;
+       
+       if (r)
+               {
+               debugf("Adding %p %##s (%s) to duplicate list", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+               *d = rr;
+               // If the previous copy of this record is already verified unique,
+               // then indicate that we should move this record promptly to kDNSRecordTypeUnique state.
+               // Setting ProbeCount to zero will cause SendQueries() to advance this record to
+               // kDNSRecordTypeVerified state and call the client callback at the next appropriate time.
+               if (rr->resrec.RecordType == kDNSRecordTypeUnique && r->resrec.RecordType == kDNSRecordTypeVerified)
+                       rr->ProbeCount = 0;
+               }
        else
                {
-               // Now that's we've finished building our new record, make sure it's not identical to one we already have
-               for (r = m->ResourceRecords; r; r=r->next) if (RecordIsLocalDuplicate(r, rr)) break;
-               
-               if (r)
-                       {
-                       debugf("Adding %p %##s (%s) to duplicate list", rr, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
-                       *d = rr;
-                       // If the previous copy of this record is already verified unique,
-                       // then indicate that we should move this record promptly to kDNSRecordTypeUnique state.
-                       // Setting ProbeCount to zero will cause SendQueries() to advance this record to
-                       // kDNSRecordTypeVerified state and call the client callback at the next appropriate time.
-                       if (rr->resrec.RecordType == kDNSRecordTypeUnique && r->resrec.RecordType == kDNSRecordTypeVerified)
-                               rr->ProbeCount = 0;
-                       }
-               else
-                       {
-                       debugf("Adding %p %##s (%s) to active record list", rr, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
-                       *p = rr;
-                       }
+               debugf("Adding %p %##s (%s) to active record list", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+               if (!m->NewLocalRecords) m->NewLocalRecords = rr;
+               *p = rr;
                }
 
        // For records that are not going to probe, acknowledge them right away
-       if (rr->resrec.RecordType != kDNSRecordTypeUnique) AcknowledgeRecord(m, rr);
+       if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering)
+               AcknowledgeRecord(m, rr);
 
        return(mStatus_NoError);
        }
@@ -2408,7 +2609,7 @@ mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr)
                {
                m->SuppressProbes = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5);
                LogMsg("Excessive name conflicts (%lu) for %##s (%s); rate limiting in effect",
-                       m->NumFailedProbes, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                       m->NumFailedProbes, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                }
        }
 
@@ -2430,15 +2631,15 @@ typedef enum { mDNS_Dereg_normal, mDNS_Dereg_conflict, mDNS_Dereg_repeat } mDNS_
 // Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
 mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt)
        {
+       AuthRecord *r2;
        mDNSu8 RecordType = rr->resrec.RecordType;
        AuthRecord **p = &m->ResourceRecords;   // Find this record in our list of active records
 
 #ifndef UNICAST_DISABLED
-    if (!(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(&rr->resrec.name)))
+    if (!(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->ForceMCast || IsLocalDomain(rr->resrec.name)))
                return uDNS_DeregisterRecord(m, rr);
 #endif
        
-       if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly) p = &m->LocalOnlyRecords;
        while (*p && *p != rr) p=&(*p)->next;
 
        if (*p)
@@ -2446,12 +2647,9 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
                // We found our record on the main list. See if there are any duplicates that need special handling.
                if (drt == mDNS_Dereg_conflict)         // If this was a conflict, see that all duplicates get the same treatment
                        {
-                       AuthRecord *r2 = m->DuplicateRecords;
-                       while (r2)
-                               {
-                               if (RecordIsLocalDuplicate(r2, rr)) { mDNS_Deregister_internal(m, r2, drt); r2 = m->DuplicateRecords; }
-                               else r2=r2->next;
-                               }
+                       // Scan for duplicates of rr, and mark them for deregistration at the end of this routine, after we've finished
+                       // deregistering rr. We need to do this scan *before* we give the client the chance to free and reuse the rr memory.
+                       for (r2 = m->DuplicateRecords; r2; r2=r2->next) if (RecordIsLocalDuplicate(r2, rr)) r2->ProbeCount = 0xFF;                                              
                        }
                else
                        {
@@ -2462,7 +2660,7 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
                        if (*d)
                                {
                                AuthRecord *dup = *d;
-                               debugf("Duplicate record %p taking over from %p %##s (%s)", dup, rr, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                               debugf("Duplicate record %p taking over from %p %##s (%s)", dup, rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                                *d        = dup->next;          // Cut replacement record from DuplicateRecords list
                                dup->next = rr->next;           // And then...
                                rr->next  = dup;                        // ... splice it in right after the record we're about to delete
@@ -2491,14 +2689,14 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
                while (*p && *p != rr) p=&(*p)->next;
                // If we found our record on the duplicate list, then make sure we don't send a goodbye for it
                if (*p) rr->RequireGoodbye = mDNSfalse;
-               if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)", rr, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+               if (*p) debugf("DNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                }
 
        if (!*p)
                {
                // No need to log an error message if we already know this is a potentially repeated deregistration
                if (drt != mDNS_Dereg_repeat)
-                       LogMsg("mDNS_Deregister_internal: Record %p %##s (%s) not found in list", rr, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                       LogMsg("mDNS_Deregister_internal: Record %p %##s (%s) not found in list", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                return(mStatus_BadReferenceErr);
                }
 
@@ -2506,56 +2704,65 @@ mDNSlocal mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
        // we need to retract that announcement before we delete the record
        if (RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
                {
-               verbosedebugf("mDNS_Deregister_internal: Sending deregister for %##s (%s)", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+               verbosedebugf("mDNS_Deregister_internal: Sending deregister for %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
                rr->resrec.rroriginalttl = 0;
                rr->ImmedAnswer          = mDNSInterfaceMark;
-               if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
-                       m->DiscardLocalOnlyRecords = mDNStrue;
-               else
-                       {
-                       if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0)
-                               m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10);
-                       }
+               if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0)
+                       m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10);
                }
        else
                {
                *p = rr->next;                                  // Cut this record from the list
                // If someone is about to look at this, bump the pointer forward
-               if (m->CurrentRecord       == rr) m->CurrentRecord       = rr->next;
-               if (m->NewLocalOnlyRecords == rr) m->NewLocalOnlyRecords = rr->next;
+               if (m->CurrentRecord   == rr) m->CurrentRecord   = rr->next;
+               if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next;
                rr->next = mDNSNULL;
 
                if      (RecordType == kDNSRecordTypeUnregistered)
                        debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeUnregistered",
-                               rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                               rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                else if (RecordType == kDNSRecordTypeDeregistering)
                        debugf("mDNS_Deregister_internal: Record %##s (%s) already marked kDNSRecordTypeDeregistering",
-                               rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                               rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                else
                        {
-                       verbosedebugf("mDNS_Deregister_internal: Deleting record for %##s (%s)", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                       verbosedebugf("mDNS_Deregister_internal: Deleting record for %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                        rr->resrec.RecordType = kDNSRecordTypeUnregistered;
                        }
 
                if ((drt == mDNS_Dereg_conflict || drt == mDNS_Dereg_repeat) && RecordType == kDNSRecordTypeShared)
                        debugf("mDNS_Deregister_internal: Cannot have a conflict on a shared record! %##s (%s)",
-                               rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                               rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
 
                // If we have an update queued up which never executed, give the client a chance to free that memory
                if (rr->NewRData) CompleteRDataUpdate(m, rr);   // Update our rdata, clear the NewRData pointer, and return memory to the client
                
+               if (rr->LocalAnswer) AnswerLocalQuestions(m, rr, mDNSfalse);
+
                // CAUTION: MUST NOT do anything more with rr after calling rr->Callback(), because the client's callback function
                // is allowed to do anything, including starting/stopping queries, registering/deregistering records, etc.
                // In this case the likely client action to the mStatus_MemFree message is to free the memory,
                // so any attempt to touch rr after this is likely to lead to a crash.
                m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-               if (drt == mDNS_Dereg_conflict)
+               if (drt != mDNS_Dereg_conflict)
+                       {
+                       if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree);                     // MUST NOT touch rr after this
+                       }
+               else
                        {
                        RecordProbeFailure(m, rr);
-                       if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_NameConflict);
+                       if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_NameConflict);        // MUST NOT touch rr after this
+                       // Now that we've finished deregistering rr, check our DuplicateRecords list for any that we marked previously.
+                       // Note that with all the client callbacks going on, by the time we get here all the
+                       // records we marked may have been explicitly deregistered by the client anyway.
+                       r2 = m->DuplicateRecords;
+                       while (r2)
+                               {
+                               if (r2->ProbeCount != 0xFF) r2 = r2->next;
+                               else { mDNS_Deregister_internal(m, r2, mDNS_Dereg_conflict); r2 = m->DuplicateRecords; }
+                               }
                        }
-               else if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree);
                m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
                }
        return(mStatus_NoError);
@@ -2580,7 +2787,7 @@ mDNSlocal void AddRecordToResponseList(AuthRecord ***nrpp, AuthRecord *rr, AuthR
                rr->NR_AdditionalTo = add;
                *nrpp = &rr->NextResponse;
                }
-       debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+       debugf("AddRecordToResponseList: %##s (%s) already in list", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
        }
 
 mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseRecords, AuthRecord ***nrpp, const mDNSInterfaceID InterfaceID)
@@ -2602,7 +2809,7 @@ mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseR
                                if (RRTypeIsAddressType(rr2->resrec.rrtype) &&                                  // For all address records (A/AAAA) ...
                                        ResourceRecordIsValidInterfaceAnswer(rr2, InterfaceID) &&       // ... which are valid for answer ...
                                        rr->resrec.rdnamehash == rr2->resrec.namehash &&                        // ... whose name is the name of the SRV target
-                                       SameDomainName(&rr->resrec.rdata->u.srv.target, &rr2->resrec.name))
+                                       SameDomainName(&rr->resrec.rdata->u.srv.target, rr2->resrec.name))
                                        AddRecordToResponseList(nrpp, rr2, rr);
                }
        }
@@ -2702,9 +2909,10 @@ mDNSlocal void DiscardDeregistrations(mDNS *const m)
        while (m->CurrentRecord)
                {
                AuthRecord *rr = m->CurrentRecord;
-               m->CurrentRecord = rr->next;
                if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
                        CompleteDeregistration(m, rr);          // Don't touch rr after this
+               else
+                       m->CurrentRecord = rr->next;
                }
        }
 
@@ -2792,7 +3000,7 @@ mDNSlocal void SendResponses(mDNS *const m)
                                        ResourceRecordIsValidAnswer(r2) &&                                      // ... which are valid for answer ...
                                        rr->LastMCTime - r2->LastMCTime >= 0 &&                         // ... which we have not sent recently ...
                                        rr->resrec.rdnamehash == r2->resrec.namehash &&         // ... whose name is the name of the SRV target
-                                       SameDomainName(&rr->resrec.rdata->u.srv.target, &r2->resrec.name) &&
+                                       SameDomainName(&rr->resrec.rdata->u.srv.target, r2->resrec.name) &&
                                        (rr->ImmedAnswer == mDNSInterfaceMark || rr->ImmedAnswer == r2->resrec.InterfaceID))
                                        r2->ImmedAdditional = r2->resrec.InterfaceID;           // ... then mark this address record for sending too
 
@@ -2837,7 +3045,7 @@ mDNSlocal void SendResponses(mDNS *const m)
                                rr->ThisAPInterval *= 2;
                                rr->LastAPTime = m->timenow;
                                if (rr->LastAPTime + rr->ThisAPInterval - rr->AnnounceUntil >= 0) rr->AnnounceCount = 0;
-                               debugf("Announcing %##s (%s) %d", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), rr->AnnounceCount);
+                               debugf("Announcing %##s (%s) %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->AnnounceCount);
                                }
                        }
                else if (rr->ImmedAnswer)                                               // Else, just respond to a single query on single interface:
@@ -3000,7 +3208,11 @@ mDNSlocal void SendResponses(mDNS *const m)
                m->CurrentRecord = rr->next;
 
                if (rr->SendRNow)
-                       { LogMsg("SendResponses: No active interface to send: %s", ARDisplayString(m, rr)); rr->SendRNow = mDNSNULL; }
+                       {
+                       if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
+                               LogMsg("SendResponses: No active interface to send: %s", ARDisplayString(m, rr));
+                       rr->SendRNow = mDNSNULL;
+                       }
 
                if (rr->ImmedAnswer)
                        {
@@ -3053,7 +3265,7 @@ mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr)
                rr->NextRequiredQuery -= TicksTTL(rr)/20 * (MaxUnansweredQueries - rr->UnansweredQueries);
                rr->NextRequiredQuery += mDNSRandom((mDNSu32)TicksTTL(rr)/50);
                verbosedebugf("SetNextCacheCheckTime: %##s (%s) NextRequiredQuery in %ld sec",
-                       rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond);
+                       rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond);
                }
 
        if (m->NextCacheCheck - (rr->NextRequiredQuery + CacheCheckGracePeriod(rr)) > 0)
@@ -3096,7 +3308,7 @@ mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr,
 mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **queryptr, DNSQuestion *q,
        CacheRecord ***kalistptrptr, mDNSu32 *answerforecast)
        {
-       mDNSBool ucast = (q->LargeAnswers || q->ThisQInterval <= InitialQuestionInterval*2) && m->CanReceiveUnicastOn5353;
+       mDNSBool ucast = (q->LargeAnswers || q->RequestUnicast) && m->CanReceiveUnicastOn5353;
        mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
        const mDNSu8 *const limit = query->data + NormalMaxDNSMessageData;
        mDNSu8 *newptr = putQuestion(query, *queryptr, limit, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
@@ -3114,10 +3326,12 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer
        else
                {
                mDNSu32 forecast = *answerforecast;
+               const mDNSu32 slot = HashSlot(&q->qname);
+               CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
                CacheRecord *rr;
                CacheRecord **ka = *kalistptrptr;       // Make a working copy of the pointer we're going to update
 
-               for (rr=m->rrcache_hash[HashSlot(&q->qname)]; rr; rr=rr->next)          // If we have a resource record in our cache,
+               for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)                         // If we have a resource record in our cache,
                        if (rr->resrec.InterfaceID == q->SendQNow &&                                    // received on this interface
                                rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList &&      // which is not already in the known answer list
                                rr->resrec.rdlength <= SmallRecordLimit &&                                      // which is small enough to sensibly fit in the packet
@@ -3166,7 +3380,7 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer
                *kalistptrptr    = ka;                                  // Update the known answer list pointer
                if (ucast) m->ExpectUnicastResponse = m->timenow;
 
-               for (rr=m->rrcache_hash[HashSlot(&q->qname)]; rr; rr=rr->next)          // For every resource record in our cache,
+               for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)                         // For every resource record in our cache,
                        if (rr->resrec.InterfaceID == q->SendQNow &&                                    // received on this interface
                                rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList &&      // which is not in the known answer list
                                ResourceRecordAnswersQuestion(&rr->resrec, q))                          // which answers our question
@@ -3183,12 +3397,12 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer
 mDNSlocal void ReconfirmAntecedents(mDNS *const m, DNSQuestion *q)
        {
        mDNSu32 slot;
+       CacheGroup *cg;
        CacheRecord *rr;
        domainname *target;
-       for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
-               for (rr = m->rrcache_hash[slot]; rr; rr=rr->next)
-                       if ((target = GetRRDomainNameTarget(&rr->resrec)) && rr->resrec.rdnamehash == q->qnamehash && SameDomainName(target, &q->qname))
-                               mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer);
+       FORALL_CACHERECORDS(slot, cg, rr)
+               if ((target = GetRRDomainNameTarget(&rr->resrec)) && rr->resrec.rdnamehash == q->qnamehash && SameDomainName(target, &q->qname))
+                       mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForNoAnswer);
        }
 
 // Only DupSuppressInfos newer than the specified 'time' are allowed to remain active
@@ -3254,8 +3468,10 @@ mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q)
                {
                // We forecast: qname (n) type (2) class (2)
                mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4;
+               const mDNSu32 slot = HashSlot(&q->qname);
+               CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
                CacheRecord *rr;
-               for (rr=m->rrcache_hash[HashSlot(&q->qname)]; rr; rr=rr->next)          // If we have a resource record in our cache,
+               for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)                         // If we have a resource record in our cache,
                        if (rr->resrec.rdlength <= SmallRecordLimit &&                                  // which is small enough to sensibly fit in the packet
                                ResourceRecordAnswersQuestion(&rr->resrec, q) &&                        // which answers our question
                                rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0 &&                      // and it is less than half-way to expiry
@@ -3296,24 +3512,24 @@ mDNSlocal void SendQueries(mDNS *const m)
        if (m->timenow - m->NextScheduledQuery >= 0)
                {
                mDNSu32 slot;
+               CacheGroup *cg;
                CacheRecord *rr;
                m->NextScheduledQuery = m->timenow + 0x78000000;
 
                // We're expecting to send a query anyway, so see if any expiring cache records are close enough
                // to their NextRequiredQuery to be worth batching them together with this one
-               for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
-                       for (rr = m->rrcache_hash[slot]; rr; rr=rr->next)
-                               if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
-                                       if (m->timenow + TicksTTL(rr)/50 - rr->NextRequiredQuery >= 0)
-                                               {
-                                               q = rr->CRActiveQuestion;
-                                               ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(rr)/20, rr->resrec.InterfaceID);
-                                               if (q->Target.type) q->SendQNow = mDNSInterfaceMark;    // If unicast query, mark it
-                                               else if (q->SendQNow == mDNSNULL)               q->SendQNow = rr->resrec.InterfaceID;
-                                               else if (q->SendQNow != rr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark;
-                                               }
+               FORALL_CACHERECORDS(slot, cg, rr)
+                       if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
+                               if (m->timenow + TicksTTL(rr)/50 - rr->NextRequiredQuery >= 0)
+                                       {
+                                       q = rr->CRActiveQuestion;
+                                       ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(rr)/20, rr->resrec.InterfaceID);
+                                       if (q->Target.type) q->SendQNow = mDNSInterfaceMark;    // If unicast query, mark it
+                                       else if (q->SendQNow == mDNSNULL)               q->SendQNow = rr->resrec.InterfaceID;
+                                       else if (q->SendQNow != rr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark;
+                                       }
 
-               // Scan our list of questions to see which unicast queries need to be sent
+               // Scan our list of questions to see which *unicast* queries need to be sent
                for (q = m->Questions; q; q=q->next)
                        if (q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
                                {
@@ -3323,6 +3539,8 @@ mDNSlocal void SendQueries(mDNS *const m)
                                qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass);
                                mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, &q->Target, q->TargetPort, -1, mDNSNULL);
                                q->ThisQInterval   *= 2;
+                               if (q->ThisQInterval > MaxQuestionInterval)
+                                       q->ThisQInterval = MaxQuestionInterval;
                                q->LastQTime        = m->timenow;
                                q->LastQTxTime      = m->timenow;
                                q->RecentAnswerPkts = 0;
@@ -3330,7 +3548,7 @@ mDNSlocal void SendQueries(mDNS *const m)
                                m->ExpectUnicastResponse = m->timenow;
                                }
        
-               // Scan our list of questions to see which ones we're definitely going to send
+               // Scan our list of questions to see which *multicast* queries we're definitely going to send
                for (q = m->Questions; q; q=q->next)
                        if (!q->Target.type && TimeToSendThisQuestion(q, m->timenow))
                                {
@@ -3341,7 +3559,7 @@ mDNSlocal void SendQueries(mDNS *const m)
        
                // Scan our list of questions
                // (a) to see if there are any more that are worth accelerating, and
-               // (b) to update the state variables for all the questions we're going to send
+               // (b) to update the state variables for *all* the questions we're going to send
                for (q = m->Questions; q; q=q->next)
                        {
                        if (q->SendQNow ||
@@ -3376,6 +3594,7 @@ mDNSlocal void SendQueries(mDNS *const m)
 
                                q->LastQTxTime      = m->timenow;
                                q->RecentAnswerPkts = 0;
+                               if (q->RequestUnicast) q->RequestUnicast--;
                                }
                        // For all questions (not just the ones we're sending) check what the next scheduled event will be
                        SetNextQueryTime(m,q);
@@ -3468,7 +3687,7 @@ mDNSlocal void SendQueries(mDNS *const m)
                                        mDNSBool ucast = (rr->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353;
                                        mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
                                        const mDNSu8 *const limit = m->omsg.data + ((m->omsg.h.numQuestions) ? NormalMaxDNSMessageData : AbsoluteMaxDNSMessageData);
-                                       mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit, &rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit));
+                                       mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit, rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit));
                                        // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
                                        mDNSu32 forecast = answerforecast + 12 + rr->resrec.rdestimate;
                                        if (newptr && newptr + forecast < limit)
@@ -3477,11 +3696,11 @@ mDNSlocal void SendQueries(mDNS *const m)
                                                answerforecast = forecast;
                                                rr->SendRNow = (rr->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
                                                rr->IncludeInProbe = mDNStrue;
-                                               verbosedebugf("SendQueries:   Put Question %##s (%s) probecount %d", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount);
+                                               verbosedebugf("SendQueries:   Put Question %##s (%s) probecount %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount);
                                                }
                                        else
                                                {
-                                               verbosedebugf("SendQueries:   Retracting Question %##s (%s)", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                                               verbosedebugf("SendQueries:   Retracting Question %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                                                m->omsg.h.numQuestions--;
                                                }
                                        }
@@ -3495,7 +3714,7 @@ mDNSlocal void SendQueries(mDNS *const m)
                        mDNSu8 *newptr = PutResourceRecordTTL(&m->omsg, queryptr, &m->omsg.h.numAnswers, &rr->resrec, rr->resrec.rroriginalttl - SecsSinceRcvd);
                        if (newptr)
                                {
-                               verbosedebugf("SendQueries:   Put %##s (%s) at %d - %d", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
+                               verbosedebugf("SendQueries:   Put %##s (%s) at %d - %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), queryptr - m->omsg.data, newptr - m->omsg.data);
                                queryptr = newptr;
                                KnownAnswerList = rr->NextInKAList;
                                rr->NextInKAList = mDNSNULL;
@@ -3518,7 +3737,7 @@ mDNSlocal void SendQueries(mDNS *const m)
                                rr->IncludeInProbe = mDNSfalse;
                                if (newptr) queryptr = newptr;
                                else LogMsg("SendQueries:   How did we fail to have space for the Update record %##s (%s)?",
-                                       rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                                       rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                                }
                
                if (queryptr > m->omsg.data)
@@ -3553,7 +3772,11 @@ mDNSlocal void SendQueries(mDNS *const m)
                AuthRecord *rr;
                for (rr = m->ResourceRecords; rr; rr=rr->next)
                        if (rr->SendRNow)
-                               { LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, rr)); rr->SendRNow = mDNSNULL; }
+                               {
+                               if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
+                                       LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, rr));
+                               rr->SendRNow = mDNSNULL;
+                               }
                }
        }
 
@@ -3568,7 +3791,7 @@ mDNSlocal void SendQueries(mDNS *const m)
 mDNSlocal void AnswerQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, CacheRecord *rr, mDNSBool AddRecord)
        {
        verbosedebugf("AnswerQuestionWithResourceRecord:%4lu %s TTL%6lu %##s (%s)",
-               q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+               q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
 
        // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerQuestionWithResourceRecord(... mDNStrue)
        // may be called twice, once when the record is received, and again when it's time to notify local clients.
@@ -3582,6 +3805,21 @@ mDNSlocal void AnswerQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, C
                SetNextCacheCheckTime(m, rr);
                }
 
+       // If this is:
+       // (a) a no-cache add, where we've already done at least one 'QM' query, or
+       // (b) a normal add, where we have at least one unique-type answer,
+       // then there's no need to keep polling the network.
+       // (If we have an answer in the cache, then we'll automatically ask again in time to stop it expiring.)
+       if ((AddRecord == 2 && !q->RequestUnicast) ||
+               (AddRecord == 1 && (q->ExpectUnique || (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))))
+               if (ActiveQuestion(q))
+                       {
+                       q->LastQTime      = m->timenow;
+                       q->LastQTxTime    = m->timenow;
+                       q->ThisQInterval  = MaxQuestionInterval;
+                       q->RequestUnicast = mDNSfalse;
+                       }
+
        if (rr->DelayDelivery) return;          // We'll come back later when CacheRecordDeferredAdd() calls us
 
        m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
@@ -3615,9 +3853,10 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *c
        const mDNSs32 threshhold = m->timenow + mDNSPlatformOneSecond;  // See if there are any records expiring within one second
        const mDNSs32 start      = m->timenow - 0x10000000;
        mDNSs32 delay = start;
+       CacheGroup *cg = CacheGroupForName(m, slot, namehash, name);
        CacheRecord *rr;
-       for (rr = m->rrcache_hash[slot]; rr; rr=rr->next)
-               if (rr->resrec.namehash == namehash && SameDomainName(&rr->resrec.name, name))
+       for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+               if (rr->resrec.namehash == namehash && SameDomainName(rr->resrec.name, name))
                        if (threshhold - RRExpireTime(rr) >= 0)         // If we have records about to expire within a second
                                if (delay - RRExpireTime(rr) < 0)               // then delay until after they've been deleted
                                        delay = RRExpireTime(rr);
@@ -3652,16 +3891,16 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
                                {
                                q->LastAnswerPktNum = m->PktNum;
                                if (ActiveQuestion(q) && ++q->RecentAnswerPkts >= 10 &&
-                                       q->ThisQInterval > InitialQuestionInterval*16 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond)
+                                       q->ThisQInterval > InitialQuestionInterval*32 && m->timenow - q->LastQTxTime < mDNSPlatformOneSecond)
                                        {
                                        LogMsg("CacheRecordAdd: %##s (%s) got immediate answer burst; restarting exponential backoff sequence",
                                                q->qname.c, DNSTypeName(q->qtype));
-                                       q->LastQTime     = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4);
-                                       q->ThisQInterval = InitialQuestionInterval;
+                                       q->LastQTime      = m->timenow - InitialQuestionInterval + (mDNSs32)mDNSRandom((mDNSu32)mDNSPlatformOneSecond*4);
+                                       q->ThisQInterval  = InitialQuestionInterval;
                                        SetNextQueryTime(m,q);
                                        }
                                }
-                       verbosedebugf("CacheRecordAdd %p %##s (%s) %lu", rr, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl);
+                       verbosedebugf("CacheRecordAdd %p %##s (%s) %lu", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl);
                        q->CurrentAnswers++;
                        if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
                        if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
@@ -3681,6 +3920,32 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
        m->CurrentQuestion = mDNSNULL;
        }
 
+// NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
+// If new questions are created as a result of invoking client callbacks, they will be added to
+// the end of the question list, and m->NewQuestions will be set to indicate the first new question.
+// rr is a new CacheRecord just received from the wire (kDNSRecordTypePacketAns/AnsUnique/Add/AddUnique)
+// but we don't have any place to cache it. We'll deliver question 'add' events now, but we won't have any
+// way to deliver 'remove' events in future, nor will we be able to include this in known-answer lists,
+// so we immediately bump ThisQInterval up to MaxQuestionInterval to avoid pounding the network.
+// NOTE: NoCacheAnswer calls AnswerQuestionWithResourceRecord which can call a user callback,
+// which may change the record list and/or question list.
+// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
+mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
+       {
+       LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c);
+       if (m->CurrentQuestion) LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set");
+       m->CurrentQuestion = m->Questions;
+       while (m->CurrentQuestion)
+               {
+               DNSQuestion *q = m->CurrentQuestion;
+               m->CurrentQuestion = q->next;
+               if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+                       AnswerQuestionWithResourceRecord(m, q, rr, 2);  // Value '2' indicates "don't expect 'remove' events for this"
+               // MUST NOT dereference q again after calling AnswerQuestionWithResourceRecord()
+               }
+       m->CurrentQuestion = mDNSNULL;
+       }
+
 // CacheRecordRmv is only called from CheckCacheExpiration, which is called from mDNS_Execute
 // If new questions are created as a result of invoking client callbacks, they will be added to
 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
@@ -3699,7 +3964,7 @@ mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
                m->CurrentQuestion = q->next;
                if (ResourceRecordAnswersQuestion(&rr->resrec, q))
                        {
-                       verbosedebugf("CacheRecordRmv %p %##s (%s)", rr, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                       verbosedebugf("CacheRecordRmv %p %##s (%s)", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                        if (q->CurrentAnswers == 0)
                                LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?", q, q->qname.c, DNSTypeName(q->qtype));
                        else
@@ -3720,21 +3985,41 @@ mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
        m->CurrentQuestion = mDNSNULL;
        }
 
-mDNSlocal void ReleaseCacheRR(mDNS *const m, CacheRecord *r)
+mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e)
        {
-       if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->rdatastorage)
-               mDNSPlatformMemFree(r->resrec.rdata);
-       r->resrec.rdata = mDNSNULL;
-       r->next = m->rrcache_free;
-       m->rrcache_free = r;
+#if MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+       unsigned int i;
+       for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
+#endif
+       e->next = m->rrcache_free;
+       m->rrcache_free = e;
        m->rrcache_totalused--;
        }
 
+mDNSlocal void ReleaseCacheGroup(mDNS *const m, CacheGroup **cp)
+       {
+       CacheEntity *e = (CacheEntity *)(*cp);
+       //LogMsg("ReleaseCacheGroup: Releasing CacheGroup for %p, %##s", (*cp)->name->c, (*cp)->name->c);
+       if ((*cp)->rrcache_tail != &(*cp)->members) LogMsg("ERROR: (*cp)->members == mDNSNULL but (*cp)->rrcache_tail != &(*cp)->members)");
+       //if ((*cp)->name != (domainname*)((*cp)->namestorage)) LogMsg("ReleaseCacheGroup: %##s, %p %p", (*cp)->name->c, (*cp)->name, (domainname*)((*cp)->namestorage));
+       if ((*cp)->name != (domainname*)((*cp)->namestorage)) mDNSPlatformMemFree((*cp)->name);
+       (*cp)->name = mDNSNULL;
+       *cp = (*cp)->next;                      // Cut record from list
+       ReleaseCacheEntity(m, e);
+       }
+
+mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *r)
+       {
+       if (r->resrec.rdata && r->resrec.rdata != (RData*)&r->rdatastorage) mDNSPlatformMemFree(r->resrec.rdata);
+       r->resrec.rdata = mDNSNULL;
+       ReleaseCacheEntity(m, (CacheEntity *)r);
+       }
+
 // Note: We want to be careful that we deliver all the CacheRecordRmv calls before delivering CacheRecordDeferredAdd calls
 // The in-order nature of the cache lists ensures that all callbacks for old records are delivered before callbacks for newer records
-mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot)
+mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *cg)
        {
-       CacheRecord **rp = &(m->rrcache_hash[slot]);
+       CacheRecord **rp = &cg->members;
 
        if (m->lock_rrcache) { LogMsg("CheckCacheExpiration ERROR! Cache already locked!"); return; }
        m->lock_rrcache = 1;
@@ -3752,8 +4037,7 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot)
                                CacheRecordRmv(m, rr);
                                m->rrcache_active--;
                                }
-                       m->rrcache_used[slot]--;
-                       ReleaseCacheRR(m, rr);
+                       ReleaseCacheRecord(m, rr);
                        }
                else                                                    // else, not expired; see if we need to query
                        {
@@ -3782,8 +4066,8 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot)
                        rp = &rr->next;
                        }
                }
-       if (m->rrcache_tail[slot] != rp) verbosedebugf("CheckCacheExpiration: Updating m->rrcache_tail[%lu] from %p to %p", slot, m->rrcache_tail[slot], rp);
-       m->rrcache_tail[slot] = rp;
+       if (cg->rrcache_tail != rp) verbosedebugf("CheckCacheExpiration: Updating CacheGroup tail from %p to %p", cg->rrcache_tail, rp);
+       cg->rrcache_tail = rp;
        m->lock_rrcache = 0;
        }
 
@@ -3793,10 +4077,11 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
        CacheRecord *rr;
        DNSQuestion *q = m->NewQuestions;               // Grab the question we're going to answer
        const mDNSu32 slot = HashSlot(&q->qname);
+       CacheGroup *cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
 
        verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 
-       CheckCacheExpiration(m, slot);
+       if (cg) CheckCacheExpiration(m, cg);
        m->NewQuestions = q->next;                              // Advance NewQuestions to the next *after* calling CheckCacheExpiration();
 
        if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!");
@@ -3807,7 +4092,27 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
        m->lock_rrcache = 1;
        if (m->CurrentQuestion) LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set");
        m->CurrentQuestion = q;         // Indicate which question we're answering, so we'll know if it gets deleted
-       for (rr=m->rrcache_hash[slot]; rr; rr=rr->next)
+
+       if (q->InterfaceID == mDNSInterface_Any)        // If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records
+               {
+               if (m->CurrentRecord) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set");
+               m->CurrentRecord = m->ResourceRecords;
+               while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
+                       {
+                       AuthRecord *rr = m->CurrentRecord;
+                       m->CurrentRecord = rr->next;
+                       if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
+                               if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+                                       {
+                                       AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, mDNStrue);
+                                       // MUST NOT dereference q again after calling AnswerLocalOnlyQuestionWithResourceRecord()
+                                       if (m->CurrentQuestion != q) break;             // If callback deleted q, then we're finished here
+                                       }
+                       }
+               m->CurrentRecord   = mDNSNULL;
+               }
+
+       for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
                if (ResourceRecordAnswersQuestion(&rr->resrec, q))
                        {
                        // SecsSinceRcvd is whole number of elapsed seconds, rounded down
@@ -3815,7 +4120,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
                        if (rr->resrec.rroriginalttl <= SecsSinceRcvd)
                                {
                                LogMsg("AnswerNewQuestion: How is rr->resrec.rroriginalttl %lu <= SecsSinceRcvd %lu for %##s (%s)",
-                                       rr->resrec.rroriginalttl, SecsSinceRcvd, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                                       rr->resrec.rroriginalttl, SecsSinceRcvd, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                                continue;       // Go to next one in loop
                                }
 
@@ -3831,29 +4136,21 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
                        if (m->CurrentQuestion != q) break;             // If callback deleted q, then we're finished here
                        }
                else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
-                       if (rr->resrec.namehash == q->qnamehash && SameDomainName(&rr->resrec.name, &q->qname))
+                       if (rr->resrec.namehash == q->qnamehash && SameDomainName(rr->resrec.name, &q->qname))
                                ShouldQueryImmediately = mDNSfalse;
 
        if (ShouldQueryImmediately && m->CurrentQuestion == q)
                {
-               q->ThisQInterval = InitialQuestionInterval;
-               q->LastQTime = m->timenow - q->ThisQInterval;
+               q->ThisQInterval  = InitialQuestionInterval;
+               q->LastQTime      = m->timenow - q->ThisQInterval;
                m->NextScheduledQuery = m->timenow;
                }
        m->CurrentQuestion = mDNSNULL;
        m->lock_rrcache = 0;
        }
 
-mDNSlocal void AnswerLocalOnlyQuestionWithResourceRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, mDNSBool AddRecord)
-       {
-       // Indicate that we've given at least one positive answer for this record, so we should be prepared to send a goodbye for it
-       if (AddRecord) rr->RequireGoodbye = mDNStrue;
-       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-       if (q->QuestionCallback)
-               q->QuestionCallback(m, q, &rr->resrec, AddRecord);
-       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-       }
-
+// When a NewLocalOnlyQuestion is created, AnswerNewLocalOnlyQuestion runs though our ResourceRecords delivering any appropriate answers,
+// stopping if it reaches a NewLocalRecord -- these will be handled by AnswerLocalQuestions
 mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
        {
        DNSQuestion *q = m->NewLocalOnlyQuestions;              // Grab the question we're going to answer
@@ -3865,8 +4162,8 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
        m->CurrentQuestion = q;         // Indicate which question we're answering, so we'll know if it gets deleted
 
        if (m->CurrentRecord) LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentRecord already set");
-       m->CurrentRecord = m->LocalOnlyRecords;
-       while (m->CurrentRecord && m->CurrentRecord != m->NewLocalOnlyRecords)
+       m->CurrentRecord = m->ResourceRecords;
+       while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
                {
                AuthRecord *rr = m->CurrentRecord;
                m->CurrentRecord = rr->next;
@@ -3882,47 +4179,9 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
        m->CurrentRecord   = mDNSNULL;
        }
 
-mDNSlocal void AnswerLocalOnlyQuestions(mDNS *const m, AuthRecord *rr, mDNSBool AddRecord)
-       {
-       if (m->CurrentQuestion) LogMsg("AnswerLocalOnlyQuestions ERROR m->CurrentQuestion already set");
-       m->CurrentQuestion = m->LocalOnlyQuestions;
-       while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions)
-               {
-               DNSQuestion *q = m->CurrentQuestion;
-               m->CurrentQuestion = q->next;
-               if (ResourceRecordAnswersQuestion(&rr->resrec, q))
-                       {
-                       debugf("AnswerLocalOnlyQuestions %p %##s (%s) %lu", rr, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl);
-                       AnswerLocalOnlyQuestionWithResourceRecord(m, q, rr, AddRecord);
-                       // MUST NOT dereference q again after calling AnswerLocalOnlyQuestionWithResourceRecord()
-                       }
-               }
-       m->CurrentQuestion = mDNSNULL;
-       }
-
-mDNSlocal void DiscardLocalOnlyRecords(mDNS *const m)
-       {
-       AuthRecord *rr = m->LocalOnlyRecords;
-       while (rr)
-               {
-               if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
-                       { AnswerLocalOnlyQuestions(m, rr, mDNSfalse); CompleteDeregistration(m, rr); return; }
-               if (rr->ProbeCount) { mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict); return; }
-               rr=rr->next;
-               }
-       m->DiscardLocalOnlyRecords = mDNSfalse;
-       }
-
-mDNSlocal void AnswerForNewLocalOnlyRecords(mDNS *const m)
-       {
-       AuthRecord *rr = m->NewLocalOnlyRecords;
-       m->NewLocalOnlyRecords = m->NewLocalOnlyRecords->next;
-       AnswerLocalOnlyQuestions(m, rr, mDNStrue);
-       }
-
-mDNSlocal CacheRecord *GetFreeCacheRR(mDNS *const m, mDNSu16 RDLength)
+mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const PreserveCG)
        {
-       CacheRecord *r = mDNSNULL;
+       CacheEntity *e = mDNSNULL;
 
        if (m->lock_rrcache) { LogMsg("GetFreeCacheRR ERROR! Cache already locked!"); return(mDNSNULL); }
        m->lock_rrcache = 1;
@@ -3959,56 +4218,93 @@ mDNSlocal CacheRecord *GetFreeCacheRR(mDNS *const m, mDNSu16 RDLength)
                mDNSu32 slot;
                for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
                        {
-                       CacheRecord **rp = &(m->rrcache_hash[slot]);
-                       while (*rp)
+                       CacheGroup **cp = &m->rrcache_hash[slot];
+                       while (*cp)
                                {
-                               // Records that answer still-active questions are not candidates for deletion
-                               if ((*rp)->CRActiveQuestion)
-                                       rp=&(*rp)->next;
-                               else
+                               CacheRecord **rp = &(*cp)->members;
+                               while (*rp)
                                        {
-                                       CacheRecord *rr = *rp;
-                                       *rp = (*rp)->next;                      // Cut record from list
-                                       m->rrcache_used[slot]--;        // Decrement counts
-                                       ReleaseCacheRR(m, rr);
+                                       // Records that answer still-active questions are not candidates for recycling
+                                       // Records that are currently linked into the CacheFlushRecords list may not be recycled, or we'll crash
+                                       if ((*rp)->CRActiveQuestion || (*rp)->NextInCFList)
+                                               rp=&(*rp)->next;
+                                       else
+                                               {
+                                               CacheRecord *rr = *rp;
+                                               *rp = (*rp)->next;                      // Cut record from list
+                                               ReleaseCacheRecord(m, rr);
+                                               }
                                        }
+                               if ((*cp)->rrcache_tail != rp) verbosedebugf("GetFreeCacheRR: Updating rrcache_tail[%lu] from %p to %p", slot, (*cp)->rrcache_tail, rp);
+                               (*cp)->rrcache_tail = rp;
+                               if ((*cp)->members || (*cp)==PreserveCG) cp=&(*cp)->next;
+                               else ReleaseCacheGroup(m, cp);
                                }
-                       if (m->rrcache_tail[slot] != rp) verbosedebugf("GetFreeCacheRR: Updating m->rrcache_tail[%lu] from %p to %p", slot, m->rrcache_tail[slot], rp);
-                       m->rrcache_tail[slot] = rp;
                        }
                #if MDNS_DEBUGMSGS
                debugf("Clear unused records; m->rrcache_totalused was %lu; now %lu", oldtotalused, m->rrcache_totalused);
                #endif
                }
-       
-       if (m->rrcache_free)    // If there are records in the free list, take one
-               {
-               r = m->rrcache_free;
-               m->rrcache_free = r->next;
-               }
 
-       if (r)
+       if (m->rrcache_free)    // If there are records in the free list, take one
                {
+               e = m->rrcache_free;
+               m->rrcache_free = e->next;
                if (++m->rrcache_totalused >= m->rrcache_report)
                        {
-                       debugf("RR Cache now using %ld records", m->rrcache_totalused);
+                       LogOperation("RR Cache now using %ld objects", m->rrcache_totalused);
                        if (m->rrcache_report < 100) m->rrcache_report += 10;
                        else                         m->rrcache_report += 100;
                        }
-               mDNSPlatformMemZero(r, sizeof(*r));
+               mDNSPlatformMemZero(e, sizeof(*e));
+               }
+
+       m->lock_rrcache = 0;
+
+       return(e);
+       }
+
+mDNSlocal CacheRecord *GetCacheRecord(mDNS *const m, CacheGroup *cg, mDNSu16 RDLength)
+       {
+       CacheRecord *r = (CacheRecord *)GetCacheEntity(m, cg);
+       if (r)
+               {
                r->resrec.rdata = (RData*)&r->rdatastorage;     // By default, assume we're usually going to be using local storage
-       
                if (RDLength > InlineCacheRDSize)                       // If RDLength is too big, allocate extra storage
                        {
                        r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength);
                        if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength;
-                       else { ReleaseCacheRR(m, r); r = mDNSNULL; }
+                       else { ReleaseCacheEntity(m, (CacheEntity*)r); r = mDNSNULL; }
                        }
                }
+       return(r);
+       }
 
-       m->lock_rrcache = 0;
+mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const ResourceRecord *const rr)
+       {
+       mDNSu16 namelen = DomainNameLength(rr->name);
+       CacheGroup *cg = (CacheGroup*)GetCacheEntity(m, mDNSNULL);
+       if (!cg) { LogMsg("GetCacheGroup: Failed to allocate memory for %##s", rr->name->c); return(mDNSNULL); }
+       cg->next         = m->rrcache_hash[slot];
+       cg->namehash     = rr->namehash;
+       cg->members      = mDNSNULL;
+       cg->rrcache_tail = &cg->members;
+       cg->name         = (domainname*)cg->namestorage;
+       //LogMsg("GetCacheGroup: %-10s %d-byte cache name %##s", (namelen > InlineCacheGroupNameSize) ? "Allocating" : "Inline", namelen, rr->name->c);
+       if (namelen > InlineCacheGroupNameSize) cg->name = mDNSPlatformMemAllocate(namelen);
+       if (!cg->name)
+               {
+               LogMsg("GetCacheGroup: Failed to allocate name storage for %##s", rr->name->c);
+               ReleaseCacheEntity(m, (CacheEntity*)cg);
+               return(mDNSNULL);
+               }
+       AssignDomainName(cg->name, rr->name);
 
-       return(r);
+       if (CacheGroupForRecord(m, slot, rr)) LogMsg("GetCacheGroup: Already have CacheGroup for %##s", rr->name->c);
+       m->rrcache_hash[slot] = cg;
+       if (CacheGroupForRecord(m, slot, rr) != cg) LogMsg("GetCacheGroup: Not finding CacheGroup for %##s", rr->name->c);
+       
+       return(cg);
        }
 
 mDNSlocal void PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr)
@@ -4062,7 +4358,16 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
                        {
                        mDNSu32 slot;
                        m->NextCacheCheck = m->timenow + 0x3FFFFFFF;
-                       for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) CheckCacheExpiration(m, slot);
+                       for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
+                               {
+                               CacheGroup **cp = &m->rrcache_hash[slot];
+                               while (*cp)
+                                       {
+                                       CheckCacheExpiration(m, *cp);
+                                       if ((*cp)->members) cp=&(*cp)->next;
+                                       else ReleaseCacheGroup(m, cp);
+                                       }
+                               }
                        }
        
                // 4. See if we can answer any of our new local questions from the cache
@@ -4071,16 +4376,18 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
                        if (m->NewQuestions->DelayAnswering && m->timenow - m->NewQuestions->DelayAnswering < 0) break;
                        AnswerNewQuestion(m);
                        }
-               if (i >= 1000) debugf("mDNS_Execute: AnswerNewQuestion exceeded loop limit");
+               if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit");
                
-               for (i=0; m->DiscardLocalOnlyRecords && i<1000; i++) DiscardLocalOnlyRecords(m);
-               if (i >= 1000) debugf("mDNS_Execute: DiscardLocalOnlyRecords exceeded loop limit");
-
                for (i=0; m->NewLocalOnlyQuestions && i<1000; i++) AnswerNewLocalOnlyQuestion(m);
-               if (i >= 1000) debugf("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit");
+               if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit");
 
-               for (i=0; m->NewLocalOnlyRecords && i<1000; i++) AnswerForNewLocalOnlyRecords(m);
-               if (i >= 1000) debugf("mDNS_Execute: AnswerLocalOnlyQuestions exceeded loop limit");
+               for (i=0; i<1000 && m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords); i++)
+                       {
+                       AuthRecord *rr = m->NewLocalRecords;
+                       m->NewLocalRecords = m->NewLocalRecords->next;
+                       AnswerLocalQuestions(m, rr, mDNStrue);
+                       }
+               if (i >= 1000) LogMsg("mDNS_Execute: AnswerForNewLocalRecords exceeded loop limit");
 
                // 5. See what packets we need to send
                if (m->mDNSPlatformStatus != mStatus_NoError || m->SleepState) DiscardDeregistrations(m);
@@ -4164,7 +4471,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
        mDNS_Lock(m);
 
        m->SleepState = sleepstate;
-       LogMsg("%s at %ld", sleepstate ? "Sleeping" : "Waking", m->timenow);
+       LogOperation("%s at %ld", sleepstate ? "Sleeping" : "Waking", m->timenow);
 
        if (sleepstate)
                {
@@ -4181,6 +4488,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
                {
                DNSQuestion *q;
                mDNSu32 slot;
+               CacheGroup *cg;
                CacheRecord *cr;
 
 #ifndef UNICAST_DISABLED
@@ -4191,6 +4499,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
                        if (ActiveQuestion(q))
                                {
                                q->ThisQInterval    = InitialQuestionInterval;  // MUST be > zero for an active question
+                               q->RequestUnicast   = 2;                                                // Set to 2 because is decremented once *before* we check it
                                q->LastQTime        = m->timenow - q->ThisQInterval;
                                q->RecentAnswerPkts = 0;
                                ExpireDupSuppressInfo(q->DupSuppress, m->timenow);
@@ -4199,9 +4508,8 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleepstate)
 
                // 2. Re-validate our cache records
                m->NextCacheCheck  = m->timenow;
-               for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
-                       for (cr = m->rrcache_hash[slot]; cr; cr=cr->next)
-                               mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForCableDisconnect);
+               FORALL_CACHERECORDS(slot, cg, cr)
+                       mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForCableDisconnect);
 
                // 3. Retrigger probing and announcing for all our authoritative records
                for (rr = m->ResourceRecords; rr; rr=rr->next)
@@ -4416,10 +4724,10 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q
                                if (!result) result = CompareRData(our, &m->rec.r);
                                switch (result)
                                        {
-                                       case  1:        debugf("ResolveSimultaneousProbe: %##s (%s): We won",  our->resrec.name.c, DNSTypeName(our->resrec.rrtype));
+                                       case  1:        debugf("ResolveSimultaneousProbe: %##s (%s): We won",  our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
                                                                break;
                                        case  0:        break;
-                                       case -1:        debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name.c, DNSTypeName(our->resrec.rrtype));
+                                       case -1:        debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
                                                                mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict);
                                                                goto exit;
                                        }
@@ -4428,15 +4736,17 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q
                m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
                }
        if (!FoundUpdate)
-               debugf("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name.c, DNSTypeName(our->resrec.rrtype));
+               debugf("ResolveSimultaneousProbe: %##s (%s): No Update Record found", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
 exit:
        m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
        }
 
 mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, ResourceRecord *pktrr)
        {
+       mDNSu32 slot = HashSlot(pktrr->name);
+       CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr);
        CacheRecord *rr;
-       for (rr = m->rrcache_hash[HashSlot(&pktrr->name)]; rr; rr=rr->next)
+       for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
                if (pktrr->InterfaceID == rr->resrec.InterfaceID && IdenticalResourceRecord(pktrr, &rr->resrec)) break;
        return(rr);
        }
@@ -4446,6 +4756,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
        const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast, mDNSBool QueryWasLocalUnicast,
        DNSMessage *const response)
        {
+       mDNSBool      FromLocalSubnet    = AddressIsLocalSubnet(m, InterfaceID, srcaddr);
        AuthRecord   *ResponseRecords    = mDNSNULL;
        AuthRecord  **nrp                = &ResponseRecords;
        CacheRecord  *ExpectedAnswers    = mDNSNULL;                    // Records in our cache we expect to see updated
@@ -4502,13 +4813,16 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                                        {
                                        NumAnswersForThisQuestion++;
                                        // Notes:
-                                       // NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may also choose to multicast as well)
-                                       // NR_AnswerTo == (mDNSu8*)~1             means "answer via delayed unicast" (to modern querier)
+                                       // NR_AnswerTo pointing into query packet means "answer via immediate legacy unicast" (may *also* choose to multicast)
+                                       // NR_AnswerTo == (mDNSu8*)~1             means "answer via delayed unicast" (to modern querier; may promote to multicast instead)
                                        // NR_AnswerTo == (mDNSu8*)~0             means "definitely answer via multicast" (can't downgrade to unicast later)
-                                       if (QuestionNeedsMulticastResponse)
+                                       // If we're not multicasting this record because the kDNSQClass_UnicastResponse bit was set,
+                                       // but the multicast querier is not on a matching subnet (e.g. because of overalyed subnets on one link)
+                                       // then we'll multicast it anyway (if we unicast, the receiver will ignore it because it has an apparently non-local source)
+                                       if (QuestionNeedsMulticastResponse || (!FromLocalSubnet && QueryWasMulticast && !LegacyQuery))
                                                {
                                                // We only mark this question for sending if it is at least one second since the last time we multicast it
-                                               // on this interface. If it is more than a second, or LastMCInterface is different, then we should multicast it.
+                                               // on this interface. If it is more than a second, or LastMCInterface is different, then we may multicast it.
                                                // This is to guard against the case where someone blasts us with queries as fast as they can.
                                                if (m->timenow - (rr->LastMCTime + mDNSPlatformOneSecond) >= 0 ||
                                                        (rr->LastMCInterface != mDNSInterfaceMark && rr->LastMCInterface != InterfaceID))
@@ -4528,11 +4842,13 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                // For any query generating a unicast response we don't do this because we can't assume we will see the response
                if (QuestionNeedsMulticastResponse)
                        {
+                       const mDNSu32 slot = HashSlot(&pktq.qname);
+                       CacheGroup *cg = CacheGroupForName(m, slot, pktq.qnamehash, &pktq.qname);
                        CacheRecord *rr;
 
                        // Make a list indicating which of our own cache records we expect to see updated as a result of this query
                        // Note: Records larger than 1K are not habitually multicast, so don't expect those to be updated
-                       for (rr = m->rrcache_hash[HashSlot(&pktq.qname)]; rr; rr=rr->next)
+                       for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
                                if (ResourceRecordAnswersQuestion(&rr->resrec, &pktq) && rr->resrec.rdlength <= SmallRecordLimit)
                                        if (!rr->NextInKAList && eap != &rr->NextInKAList)
                                                {
@@ -4670,7 +4986,14 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                        mDNSBool SendUnicastResponse   = mDNSfalse;             // Send modern unicast response (not legacy unicast response)
                        
                        // If it's been a while since we multicast this, then send a multicast response for conflict detection, etc.
-                       if (m->timenow - (rr->LastMCTime + TicksTTL(rr)/4) >= 0) SendMulticastResponse = mDNStrue;
+                       if (m->timenow - (rr->LastMCTime + TicksTTL(rr)/4) >= 0)
+                               {
+                               SendMulticastResponse = mDNStrue;
+                               // If this record was marked for modern (delayed) unicast response, then mark it as promoted to
+                               // multicast response instead (don't want to end up ALSO setting SendUnicastResponse in the check below).
+                               // If this record was marked for legacy unicast response, then we mustn't change the NR_AnswerTo value.
+                               if (rr->NR_AnswerTo == (mDNSu8*)~1) rr->NR_AnswerTo = (mDNSu8*)~0;
+                               }
                        
                        // If the client insists on a multicast response, then we'd better send one
                        if      (rr->NR_AnswerTo == (mDNSu8*)~0) SendMulticastResponse = mDNStrue;
@@ -4848,34 +5171,6 @@ exit:
        return(responseptr);
        }
 
-mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
-       {
-       NetworkInterfaceInfo *intf;
-
-       if (addr->type == mDNSAddrType_IPv4)
-               {
-               if (addr->ip.v4.b[0] == 169 && addr->ip.v4.b[1] == 254) return(mDNStrue);
-               for (intf = m->HostInterfaces; intf; intf = intf->next)
-                       if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID)
-                               if (((intf->ip.ip.v4.NotAnInteger ^ addr->ip.v4.NotAnInteger) & intf->mask.ip.v4.NotAnInteger) == 0)
-                                       return(mDNStrue);
-               }
-
-       if (addr->type == mDNSAddrType_IPv6)
-               {
-               if (addr->ip.v6.b[0] == 0xFE && addr->ip.v6.b[1] == 0x80) return(mDNStrue);
-               for (intf = m->HostInterfaces; intf; intf = intf->next)
-                       if (intf->ip.type == addr->type && intf->InterfaceID == InterfaceID)
-                               if ((((intf->ip.ip.v6.l[0] ^ addr->ip.v6.l[0]) & intf->mask.ip.v6.l[0]) == 0) &&
-                                       (((intf->ip.ip.v6.l[1] ^ addr->ip.v6.l[1]) & intf->mask.ip.v6.l[1]) == 0) &&
-                                       (((intf->ip.ip.v6.l[2] ^ addr->ip.v6.l[2]) & intf->mask.ip.v6.l[2]) == 0) &&
-                                       (((intf->ip.ip.v6.l[3] ^ addr->ip.v6.l[3]) & intf->mask.ip.v6.l[3]) == 0))
-                                               return(mDNStrue);
-               }
-
-       return(mDNSfalse);
-       }
-
 mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
        const mDNSAddr *srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport,
        const mDNSInterfaceID InterfaceID)
@@ -4925,7 +5220,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
        {
        int i;
        const mDNSu8 *ptr = LocateAnswers(response, end);       // We ignore questions (if any) in a DNS response packet
-       CacheRecord *CacheFlushRecords = mDNSNULL;
+       CacheRecord *CacheFlushRecords = (CacheRecord*)1;       // "(CacheRecord*)1" is special (non-zero) end-of-list marker
        CacheRecord **cfp = &CacheFlushRecords;
 
        // All records in a DNS response packet are treated as equally valid statements of truth. If we want
@@ -4946,8 +5241,14 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
 
        // If we get a unicast response when we weren't expecting one, then we assume it is someone trying to spoof us
        if (!mDNSAddrIsDNSMulticast(dstaddr))
+               {
                if (!AddressIsLocalSubnet(m, InterfaceID, srcaddr) || (mDNSu32)(m->timenow - m->ExpectUnicastResponse) > (mDNSu32)(mDNSPlatformOneSecond*2))
                        return;
+               // For now we don't put standard wide-area unicast responses in our main cache
+               // (Later we should fix this and cache all known results in a unified manner.)
+               if (response->h.id.NotAnInteger != 0 || srcport.NotAnInteger != MulticastDNSPort.NotAnInteger)
+                       return;
+               }
 
        for (i = 0; i < totalrecords && ptr && ptr < end; i++)
                {
@@ -4995,7 +5296,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                                // If we'd previously verified this record, put it back to probing state and try again
                                                if (rr->resrec.RecordType == kDNSRecordTypeVerified)
                                                        {
-                                                       debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                                                       debugf("mDNSCoreReceiveResponse: Reseting to Probing: %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                                                        rr->resrec.RecordType     = kDNSRecordTypeUnique;
                                                        rr->ProbeCount     = DefaultProbeCountForTypeUnique + 1;
                                                        rr->ThisAPInterval = DefaultAPIntervalForRecordType(kDNSRecordTypeUnique);
@@ -5005,7 +5306,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                                // If we're probing for this record, we just failed
                                                else if (rr->resrec.RecordType == kDNSRecordTypeUnique)
                                                        {
-                                                       debugf("mDNSCoreReceiveResponse: Will rename %##s (%s)", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                                                       debugf("mDNSCoreReceiveResponse: Will rename %##s (%s)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                                                        mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
                                                        }
                                                // We assumed this record must be unique, but we were wrong.
@@ -5015,12 +5316,12 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                                else if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
                                                        {
                                                        debugf("mDNSCoreReceiveResponse: Unexpected conflict on %##s (%s) -- discarding our record",
-                                                               rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                                                               rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                                                        mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
                                                        }
                                                else
                                                        debugf("mDNSCoreReceiveResponse: Unexpected record type %X %##s (%s)",
-                                                               rr->resrec.RecordType, rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype));
+                                                               rr->resrec.RecordType, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                                                }
                                        }
                                // Else, matching signature, different type or rdata, but not a considered a conflict.
@@ -5036,10 +5337,11 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                // 2. See if we want to add this packet resource record to our cache
                if (m->rrcache_size)    // Only try to cache answers if we have a cache to put them in
                        {
-                       const mDNSu32 slot = HashSlot(&m->rec.r.resrec.name);
+                       const mDNSu32 slot = HashSlot(m->rec.r.resrec.name);
+                       CacheGroup *cg = CacheGroupForRecord(m, slot, &m->rec.r.resrec);
                        CacheRecord *rr;
                        // 2a. Check if this packet resource record is already in our cache
-                       for (rr = m->rrcache_hash[slot]; rr; rr=rr->next)
+                       for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
                                {
                                // If we found this exact resource record, refresh its TTL
                                if (rr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &rr->resrec))
@@ -5053,7 +5355,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                                {
                                                // If this packet record has the kDNSClass_UniqueRRSet flag set, then add it to our cache flushing list
                                                if (rr->NextInCFList == mDNSNULL && cfp != &rr->NextInCFList)
-                                                       { *cfp = rr; cfp = &rr->NextInCFList; }
+                                                       { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
 
                                                // If this packet record is marked unique, and our previous cached copy was not, then fix it
                                                if (!(rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))
@@ -5091,27 +5393,30 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                        // (unless it is just a deletion of a record we never had, in which case we don't care)
                        if (!rr && m->rec.r.resrec.rroriginalttl > 0)
                                {
-                               rr = GetFreeCacheRR(m, m->rec.r.resrec.rdlength);
-                               if (!rr) debugf("No cache space to add record for %#s", m->rec.r.resrec.name.c);
+                               // If we don't have a CacheGroup for this name, make one now
+                               if (!cg) cg = GetCacheGroup(m, slot, &m->rec.r.resrec);
+                               if (cg) rr = GetCacheRecord(m, cg, m->rec.r.resrec.rdlength);   // Make a cache record, being careful not to recycle cg
+                               if (!rr) NoCacheAnswer(m, &m->rec.r);
                                else
                                        {
                                        RData *saveptr = rr->resrec.rdata;              // Save the rr->resrec.rdata pointer
-                                       *rr = m->rec.r;
-                                       rr->resrec.rdata = saveptr;                             // and then restore it after the structure assignment
+                                       *rr = m->rec.r;                                                 // Block copy the CacheRecord object
+                                       rr->resrec.rdata = saveptr;                             // Restore rr->resrec.rdata after the structure assignment
+                                       rr->resrec.name  = cg->name;                    // And set rr->resrec.name to point into our CacheGroup header
                                        if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)
-                                               { *cfp = rr; cfp = &rr->NextInCFList; }
+                                               { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
                                        // If this is an oversized record with external storage allocated, copy rdata to external storage
+                                       if (rr->resrec.rdata != (RData*)&rr->rdatastorage && !(m->rec.r.resrec.rdlength > InlineCacheRDSize))
+                                               LogMsg("rr->resrec.rdata != &rr->rdatastorage but length <= InlineCacheRDSize %##s", m->rec.r.resrec.name->c);
                                        if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
                                                mDNSPlatformMemCopy(m->rec.r.resrec.rdata, rr->resrec.rdata, sizeofRDataHeader + m->rec.r.resrec.rdlength);
                                        rr->next = mDNSNULL;                                    // Clear 'next' pointer
-                                       *(m->rrcache_tail[slot]) = rr;                  // Append this record to tail of cache slot list
-                                       m->rrcache_tail[slot] = &(rr->next);    // Advance tail pointer
-                                       m->rrcache_used[slot]++;
+                                       *(cg->rrcache_tail) = rr;                               // Append this record to tail of cache slot list
+                                       cg->rrcache_tail = &(rr->next);                 // Advance tail pointer
                                        if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)     // If marked unique, assume we may have
                                                rr->DelayDelivery = m->timenow + mDNSPlatformOneSecond; // to delay delivery of this 'add' event
                                        else
-                                               rr->DelayDelivery = CheckForSoonToExpireRecords(m, &rr->resrec.name, rr->resrec.namehash, slot);
-                                       //debugf("Adding RR %##s to cache (%d)", m->rec.r.name.c, m->rrcache_used);
+                                               rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot);
                                        CacheRecordAdd(m, rr);
                                        // MUST do this AFTER CacheRecordAdd(), because that's what sets CRActiveQuestion for us
                                        SetNextCacheCheckTime(m, rr);
@@ -5126,35 +5431,43 @@ exit:
 
        // If we've just received one or more records with their cache flush bits set,
        // then scan that cache slot to see if there are any old stale records we need to flush
-       while (CacheFlushRecords)
+       while (CacheFlushRecords != (CacheRecord*)1)
                {
                CacheRecord *r1 = CacheFlushRecords, *r2;
-               const mDNSu32 slot = HashSlot(&r1->resrec.name);
+               const mDNSu32 slot = HashSlot(r1->resrec.name);
+               CacheGroup *cg = CacheGroupForRecord(m, slot, &r1->resrec);
                CacheFlushRecords = CacheFlushRecords->NextInCFList;
                r1->NextInCFList = mDNSNULL;
-               for (r2 = m->rrcache_hash[slot]; r2; r2=r2->next)
-                       if (SameResourceRecordSignature(&r1->resrec, &r2->resrec) && m->timenow - r2->TimeRcvd > mDNSPlatformOneSecond)
+               for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next)
+                       if (SameResourceRecordSignature(&r1->resrec, &r2->resrec))
                                {
-                               verbosedebugf("Cache flush %p X %p %##s (%s)", r1, r2, r2->resrec.name.c, DNSTypeName(r2->resrec.rrtype));
-                               // We set stale records to expire in one second.
-                               // This gives the owner a chance to rescue it if necessary.
-                               // This is important in the case of multi-homing and bridged networks:
-                               //   Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
-                               //   bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
-                               //   set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
-                               //   will promptly delete their cached copies of the (still valid) Ethernet IP address record.
-                               //   By delaying the deletion by one second, we give X a change to notice that this bridging has
-                               //   happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
-                               // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
-                               // final expiration queries for this record.
-                               r2->resrec.rroriginalttl = 1;
-                               r2->TimeRcvd          = m->timenow;
-                               r2->UnansweredQueries = MaxUnansweredQueries;
-                               SetNextCacheCheckTime(m, r2);
+                               // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics)
+                               // else, if record is old, mark it to be flushed
+                               if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond)
+                                       r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
+                               else
+                                       {
+                                       verbosedebugf("Cache flush %p X %p %##s (%s)", r1, r2, r2->resrec.name->c, DNSTypeName(r2->resrec.rrtype));
+                                       // We set stale records to expire in one second.
+                                       // This gives the owner a chance to rescue it if necessary.
+                                       // This is important in the case of multi-homing and bridged networks:
+                                       //   Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
+                                       //   bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
+                                       //   set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
+                                       //   will promptly delete their cached copies of the (still valid) Ethernet IP address record.
+                                       //   By delaying the deletion by one second, we give X a change to notice that this bridging has
+                                       //   happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
+                                       // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
+                                       // final expiration queries for this record.
+                                       r2->resrec.rroriginalttl = 1;
+                                       r2->TimeRcvd          = m->timenow;
+                                       r2->UnansweredQueries = MaxUnansweredQueries;
+                                       SetNextCacheCheckTime(m, r2);
+                                       }
                                }
                if (r1->DelayDelivery)  // If we were planning to delay delivery of this record, see if we still need to
                        {
-                       r1->DelayDelivery = CheckForSoonToExpireRecords(m, &r1->resrec.name, r1->resrec.namehash, slot);
+                       r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, slot);
                        if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1);
                        }
                }
@@ -5169,11 +5482,11 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co
        const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
        mDNSu8 QR_OP;
        mDNSu8 *ptr = mDNSNULL;
+       const mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
 
 #ifndef UNICAST_DISABLED       
        mDNSIPPort NATPort = mDNSOpaque16fromIntVal(NATMAP_PORT);
-       const mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
-       
+
        if (srcport.NotAnInteger == NATPort.NotAnInteger)
                {
                mDNS_Lock(m);
@@ -5254,6 +5567,7 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, const DNSQuestion *const
                if (q->DuplicateOf == question)                 // To see if any questions were referencing this as their duplicate
                        {
                        q->ThisQInterval    = question->ThisQInterval;
+                       q->RequestUnicast   = question->RequestUnicast;
                        q->LastQTime        = question->LastQTime;
                        q->RecentAnswerPkts = 0;
                        q->DuplicateOf      = FindDuplicateQuestion(m, q);
@@ -5267,10 +5581,6 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, const DNSQuestion *const
 
 mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question)
        {
-#if TEST_LOCALONLY_FOR_EVERYTHING
-       question->InterfaceID = mDNSInterface_LocalOnly;
-#endif
-
        if (question->Target.type && !ValidQuestionTarget(question))
                {
                LogMsg("Warning! Target.type = %ld port = %u (Client forgot to initialize before calling mDNS_StartQuery?)",
@@ -5342,6 +5652,7 @@ mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const que
                question->qnamehash        = DomainNameHashValue(&question->qname);     // MUST do this before FindDuplicateQuestion()
                question->DelayAnswering   = CheckForSoonToExpireRecords(m, &question->qname, question->qnamehash, HashSlot(&question->qname));
                question->ThisQInterval    = InitialQuestionInterval * 2;                       // MUST be > zero for an active question
+               question->RequestUnicast   = 2;                                                                         // Set to 2 because is decremented once *before* we check it
                question->LastQTime        = m->timenow - m->RandomQueryDelay;          // Avoid inter-machine synchronization
                question->LastAnswerPktNum = m->PktNum;
                question->RecentAnswerPkts = 0;
@@ -5381,6 +5692,8 @@ mDNSlocal mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const que
 
 mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question)
        {
+       const mDNSu32 slot = HashSlot(&question->qname);
+       CacheGroup *cg = CacheGroupForName(m, slot, question->qnamehash, &question->qname);
        CacheRecord *rr;
        DNSQuestion **q = &m->Questions;
 
@@ -5404,7 +5717,7 @@ mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const ques
 
        // If there are any cache records referencing this as their active question, then see if any other
        // question that is also referencing them, else their CRActiveQuestion needs to get set to NULL.
-       for (rr = m->rrcache_hash[HashSlot(&question->qname)]; rr; rr=rr->next)
+       for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
                {
                if (rr->CRActiveQuestion == question)
                        {
@@ -5412,7 +5725,7 @@ mDNSlocal mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const ques
                        for (q = m->Questions; q; q=q->next)            // Scan our list of questions
                                if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
                                        break;
-                       verbosedebugf("mDNS_StopQuery_internal: Cache RR %##s (%s) setting CRActiveQuestion to %p", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), q);
+                       verbosedebugf("mDNS_StopQuery_internal: Cache RR %##s (%s) setting CRActiveQuestion to %p", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), q);
                        rr->CRActiveQuestion = q;               // Question used to be active; new value may or may not be null
                        if (!q) m->rrcache_active--;    // If no longer active, decrement rrcache_active count
                        }
@@ -5538,9 +5851,9 @@ mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const R
                {
                query->GotSRV             = mDNStrue;
                query->qAv4.InterfaceID   = answer->InterfaceID;
-               AssignDomainName(query->qAv4.qname, answer->rdata->u.srv.target);
+               AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target);
                query->qAv6.InterfaceID   = answer->InterfaceID;
-               AssignDomainName(query->qAv6.qname, answer->rdata->u.srv.target);
+               AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
                mDNS_StartQuery(m, &query->qAv4);
                // Only do the AAAA query if this machine actually has IPv6 active
                if (MachineHasActiveIPv6(m)) mDNS_StartQuery(m, &query->qAv6);
@@ -5564,9 +5877,9 @@ mDNSlocal void FoundServiceInfoSRV(mDNS *const m, DNSQuestion *question, const R
                else
                        {
                        query->qAv4.InterfaceID   = answer->InterfaceID;
-                       AssignDomainName(query->qAv4.qname, answer->rdata->u.srv.target);
+                       AssignDomainName(&query->qAv4.qname, &answer->rdata->u.srv.target);
                        query->qAv6.InterfaceID   = answer->InterfaceID;
-                       AssignDomainName(query->qAv6.qname, answer->rdata->u.srv.target);
+                       AssignDomainName(&query->qAv6.qname, &answer->rdata->u.srv.target);
                        }
                debugf("FoundServiceInfoSRV: Restarting address queries for %##s", query->qAv4.qname.c);
                mDNS_StartQuery(m, &query->qAv4);
@@ -5628,7 +5941,7 @@ mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const Reso
                }
        else
                {
-               debugf("FoundServiceInfo: answer %##s type %d (%s) unexpected", answer->name.c, answer->rrtype, DNSTypeName(answer->rrtype));
+               debugf("FoundServiceInfo: answer %##s type %d (%s) unexpected", answer->name->c, answer->rrtype, DNSTypeName(answer->rrtype));
                return;
                }
 
@@ -5665,7 +5978,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
        query->qSRV.ThisQInterval       = -1;           // So that mDNS_StopResolveService() knows whether to cancel this question
        query->qSRV.InterfaceID         = info->InterfaceID;
        query->qSRV.Target              = zeroAddr;
-       AssignDomainName(query->qSRV.qname, info->name);
+       AssignDomainName(&query->qSRV.qname, &info->name);
        query->qSRV.qtype               = kDNSType_SRV;
        query->qSRV.qclass              = kDNSClass_IN;
        query->qSRV.LongLived           = mDNSfalse;
@@ -5677,7 +5990,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
        query->qTXT.ThisQInterval       = -1;           // So that mDNS_StopResolveService() knows whether to cancel this question
        query->qTXT.InterfaceID         = info->InterfaceID;
        query->qTXT.Target              = zeroAddr;
-       AssignDomainName(query->qTXT.qname, info->name);
+       AssignDomainName(&query->qTXT.qname, &info->name);
        query->qTXT.qtype               = kDNSType_TXT;
        query->qTXT.qclass              = kDNSClass_IN;
        query->qTXT.LongLived           = mDNSfalse;
@@ -5734,18 +6047,14 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
        return(status);
        }
 
-mDNSexport void    mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *query)
+mDNSexport void    mDNS_StopResolveService (mDNS *const m, ServiceInfoQuery *q)
        {
        mDNS_Lock(m);
        // We use mDNS_StopQuery_internal here because we're already holding the lock
-       if (query->qSRV.ThisQInterval >= 0 || uDNS_IsActiveQuery(&query->qSRV, &m->uDNS_info))
-               mDNS_StopQuery_internal(m, &query->qSRV);
-       if (query->qTXT.ThisQInterval >= 0 || uDNS_IsActiveQuery(&query->qTXT, &m->uDNS_info))
-               mDNS_StopQuery_internal(m, &query->qTXT);
-       if (query->qAv4.ThisQInterval >= 0 || uDNS_IsActiveQuery(&query->qAv4, &m->uDNS_info))
-               mDNS_StopQuery_internal(m, &query->qAv4);
-       if (query->qAv6.ThisQInterval >= 0 || uDNS_IsActiveQuery(&query->qAv6, &m->uDNS_info))
-               mDNS_StopQuery_internal(m, &query->qAv6);
+       if (q->qSRV.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qSRV, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qSRV);
+       if (q->qTXT.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qTXT, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qTXT);
+       if (q->qAv4.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qAv4, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qAv4);
+       if (q->qAv6.ThisQInterval >= 0 || uDNS_IsActiveQuery(&q->qAv6, &m->uDNS_info)) mDNS_StopQuery_internal(m, &q->qAv6);
        mDNS_Unlock(m);
        }
 
@@ -5761,7 +6070,7 @@ mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, m
        question->ForceMCast       = mDNSfalse;
        question->QuestionCallback = Callback;
        question->QuestionContext  = Context;
-       if (DomainType > mDNS_DomainTypeBrowseLegacy) return(mStatus_BadParamErr);
+       if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr);
        if (!MakeDomainNameFromDNSNameString(&question->qname, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
        if (!dom) dom = &localdomain;
        if (!AppendDomainName(&question->qname, dom)) return(mStatus_BadParamErr);
@@ -5774,53 +6083,6 @@ mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, m
 #pragma mark - Responder Functions
 #endif
 
-// Set up a AuthRecord with sensible default values.
-// These defaults may be overwritten with new values before mDNS_Register is called
-mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
-       mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, mDNSRecordCallback Callback, void *Context)
-       {
-         mDNSPlatformMemZero(&rr->uDNS_info, sizeof(uDNS_RegInfo));
-       // Don't try to store a TTL bigger than we can represent in platform time units
-       if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond)
-               ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond;
-       else if (ttl == 0)              // And Zero TTL is illegal
-               ttl = DefaultTTLforRRType(rrtype);
-
-       // Field Group 1: Persistent metadata for Authoritative Records
-       rr->Additional1       = mDNSNULL;
-       rr->Additional2       = mDNSNULL;
-       rr->DependentOn       = mDNSNULL;
-       rr->RRSet             = mDNSNULL;
-       rr->RecordCallback    = Callback;
-       rr->RecordContext     = Context;
-
-       rr->resrec.RecordType        = RecordType;
-       rr->HostTarget        = mDNSfalse;
-       rr->AllowRemoteQuery  = mDNSfalse;
-       rr->ForceMCast        = mDNSfalse;
-       
-       // Field Group 2: Transient state for Authoritative Records (set in mDNS_Register_internal)
-       // Field Group 3: Transient state for Cache Records         (set in mDNS_Register_internal)
-
-       // Field Group 4: The actual information pertaining to this resource record
-       rr->resrec.InterfaceID       = InterfaceID;
-       rr->resrec.name.c[0]         = 0;               // MUST be set by client
-       rr->resrec.rrtype            = rrtype;
-       rr->resrec.rrclass           = kDNSClass_IN;
-       rr->resrec.rroriginalttl     = ttl;
-//     rr->resrec.rdlength          = MUST set by client and/or in mDNS_Register_internal
-//     rr->resrec.rdestimate        = set in mDNS_Register_internal
-//     rr->resrec.rdata             = MUST be set by client
-
-       if (RDataStorage)
-               rr->resrec.rdata = RDataStorage;
-       else
-               {
-               rr->resrec.rdata = &rr->rdatastorage;
-               rr->resrec.rdata->MaxRDLength = sizeof(RDataBody);
-               }
-       }
-
 mDNSexport mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr)
        {
        mStatus status;
@@ -5834,7 +6096,7 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt
        const mDNSu16 newrdlength, RData *const newrdata, mDNSRecordUpdateCallback *Callback)
        {
 #ifndef UNICAST_DISABLED
-       mDNSBool unicast = !(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&rr->resrec.name));
+       mDNSBool unicast = !(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(rr->resrec.name));
 #else
        mDNSBool unicast = mDNSfalse;
 #endif
@@ -5869,7 +6131,7 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt
                {
                domainlabel name;
                domainname type, domain;
-               DeconstructServiceName(&rr->resrec.name, &name, &type, &domain);
+               DeconstructServiceName(rr->resrec.name, &name, &type, &domain);
                rr->AnnounceCount = InitialAnnounceCount;
                // iChat often does suprious record updates where no data has changed. For the _presence service type, using
                // name/value pairs, the mDNSPlatformMemSame() check above catches this and correctly suppresses the wasteful
@@ -5885,11 +6147,11 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt
                if (rr->AnnounceCount > rr->UpdateCredits + 1) rr->AnnounceCount = (mDNSu8)(rr->UpdateCredits + 1);
                if (rr->UpdateCredits <= 5)
                        {
-                       mDNSs32 delay = 6 - rr->UpdateCredits;          // Delay 1 second, then 2, then 3, etc. up to 6 seconds maximum
-                       if (!rr->UpdateBlocked) rr->UpdateBlocked = NonZeroTime(m->timenow + delay * mDNSPlatformOneSecond);
+                       mDNSu32 delay = 6 - rr->UpdateCredits;          // Delay 1 second, then 2, then 3, etc. up to 6 seconds maximum
+                       if (!rr->UpdateBlocked) rr->UpdateBlocked = NonZeroTime(m->timenow + (mDNSs32)delay * mDNSPlatformOneSecond);
                        rr->ThisAPInterval *= 4;
                        rr->LastAPTime = rr->UpdateBlocked - rr->ThisAPInterval;
-                       LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s", rr->resrec.name.c, delay, delay > 1 ? "s" : "");
+                       LogMsg("Excessive update rate for %##s; delaying announcement by %ld second%s", rr->resrec.name->c, delay, delay > 1 ? "s" : "");
                        }
                rr->resrec.rroriginalttl = newttl;
                }
@@ -5938,7 +6200,7 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
 #endif
        // 1. Set up Address record to map from host name ("foo.local.") to IP address
        // 2. Set up reverse-lookup PTR record to map from our address back to our host name
-       AssignDomainName(set->RR_A.resrec.name, m->MulticastHostname);
+       AssignDomainName(set->RR_A.resrec.name, &m->MulticastHostname);
        if (set->ip.type == mDNSAddrType_IPv4)
                {
                set->RR_A.resrec.rrtype = kDNSType_A;
@@ -5963,7 +6225,7 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
                mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
                }
 
-       MakeDomainNameFromDNSNameString(&set->RR_PTR.resrec.name, buffer);
+       MakeDomainNameFromDNSNameString(set->RR_PTR.resrec.name, buffer);
        set->RR_PTR.HostTarget = mDNStrue;      // Tell mDNS that the target of this PTR is to be kept in sync with our host name
        set->RR_PTR.ForceMCast = mDNStrue;      // This PTR points to our dot-local name, so don't ever try to write it into a uDNS server
 
@@ -5975,7 +6237,7 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
        if (m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254)
                {
                mDNSu8 *p = set->RR_HINFO.resrec.rdata->u.data;
-               AssignDomainName(set->RR_HINFO.resrec.name, m->MulticastHostname);
+               AssignDomainName(set->RR_HINFO.resrec.name, &m->MulticastHostname);
                set->RR_HINFO.DependentOn = &set->RR_A;
                mDNSPlatformMemCopy(&m->HIHardware, p, 1 + (mDNSu32)m->HIHardware.c[0]);
                p += 1 + (int)p[0];
@@ -6022,7 +6284,7 @@ mDNSexport void mDNS_SetFQDN(mDNS *const m)
        if (SameDomainName(&m->MulticastHostname, &newmname)) { LogMsg("mDNS_SetFQDN - hostname unchanged"); return; }
 
        mDNS_Lock(m);
-       AssignDomainName(m->MulticastHostname, newmname);
+       AssignDomainName(&m->MulticastHostname, &newmname);
 
        // 1. Stop advertising our address records on all interfaces
        for (intf = m->HostInterfaces; intf; intf = intf->next)
@@ -6049,7 +6311,7 @@ mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStat
                char *msg = "Unknown result";
                if      (result == mStatus_NoError)      msg = "Name registered";
                else if (result == mStatus_NameConflict) msg = "Name conflict";
-               debugf("mDNS_HostNameCallback: %##s (%s) %s (%ld)", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), msg, result);
+               debugf("mDNS_HostNameCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result);
                }
        #endif
 
@@ -6091,7 +6353,7 @@ mDNSexport void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStat
                debugf("mDNS_HostNameCallback: MemFree (ignored)");
                }
        else
-               LogMsg("mDNS_HostNameCallback: Unknown error %ld for registration of record %s", result,  rr->resrec.name.c);
+               LogMsg("mDNS_HostNameCallback: Unknown error %ld for registration of record %s", result,  rr->resrec.name->c);
        }
 
 mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *active)
@@ -6107,7 +6369,7 @@ mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *act
                        }
        }
 
-mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set)
+mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSs32 delay)
        {
        mDNSBool FirstOfType = mDNStrue;
        NetworkInterfaceInfo **p = &m->HostInterfaces;
@@ -6149,6 +6411,9 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
        set->next = mDNSNULL;
        *p = set;
        
+       if (set->Advertise)
+               AdvertiseInterface(m, set);
+
        debugf("mDNS_RegisterInterface: InterfaceID %p %#a %s", set->InterfaceID, &set->ip,
                set->InterfaceActive ?
                        "not represented in list; marking active and retriggering queries" :
@@ -6158,21 +6423,34 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
        // giving the false impression that there's an active representative of this interface when there really isn't.
        // Therefore, when registering an interface, we want to re-trigger our questions and re-probe our Resource Records,
        // even if we believe that we previously had an active representative of this interface.
-       if ((m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) || FirstOfType || set->InterfaceActive)
+       if (set->McastTxRx && ((m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) || FirstOfType || set->InterfaceActive))
                {
                DNSQuestion *q;
                AuthRecord *rr;
+               mDNSs32 initial = InitialQuestionInterval;
+
                // Use a small amount of randomness:
                // In the case of a network administrator turning on an Ethernet hub so that all the connected machines establish link at
                // exactly the same time, we don't want them to all go and hit the network with identical queries at exactly the same moment.
                if (!m->SuppressSending) m->SuppressSending = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
+               
+               if (delay)
+                       {
+                       LogMsg("Repeated transitions for interface %s (%#a); delaying packets by %d seconds",
+                               set->ifname, &set->ip, delay/mDNSPlatformOneSecond);
+                       initial = InitialQuestionInterval * 8;          // Delay between first and second queries is eight seconds
+                       if (!m->SuppressProbes ||
+                               m->SuppressProbes - (m->timenow + delay) < 0)
+                               m->SuppressProbes = (m->timenow + delay);
+                       }
                for (q = m->Questions; q; q=q->next)                                                    // Scan our list of questions
                        if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)      // If non-specific Q, or Q on this specific interface,
                                {                                                                                                               // then reactivate this question
-                               q->ThisQInterval    = InitialQuestionInterval;                  // MUST be > zero for an active question
-                               q->LastQTime        = m->timenow - q->ThisQInterval;
+                               q->ThisQInterval    = initial;                                                  // MUST be > zero for an active question
+                               q->RequestUnicast   = 2;                                                                // Set to 2 because is decremented once *before* we check it
+                               q->LastQTime        = m->timenow - q->ThisQInterval + delay;
                                q->RecentAnswerPkts = 0;
-                               if (ActiveQuestion(q)) m->NextScheduledQuery = m->timenow;
+                               SetNextQueryTime(m,q);
                                }
                
                // For all our non-specific authoritative resource records (and any dormant records specific to this interface)
@@ -6182,15 +6460,12 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
                                {
                                if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
                                rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
-                               rr->AnnounceCount  = InitialAnnounceCount;
+                               rr->AnnounceCount  = delay ? (mDNSu8)1 : InitialAnnounceCount;
                                rr->ThisAPInterval = DefaultAPIntervalForRecordType(rr->resrec.RecordType);
                                InitializeLastAPTime(m, rr);
                                }
                }
 
-       if (set->Advertise)
-               AdvertiseInterface(m, set);
-
        mDNS_Unlock(m);
        return(mStatus_NoError);
        }
@@ -6248,9 +6523,10 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
                        }
                else
                        {
+                       mDNSu32 slot;
+                       CacheGroup *cg;
                        CacheRecord *rr;
                        DNSQuestion *q;
-                       mDNSu32 slot;
                        debugf("mDNS_DeregisterInterface: Last representative of InterfaceID %p deregistered; marking questions etc. dormant",
                                set->InterfaceID);
 
@@ -6261,10 +6537,9 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
 
                        // 2. Flush any cache records received on this interface
                        revalidate = mDNSfalse;         // Don't revalidate if we're flushing the records
-                       for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
-                               for (rr = m->rrcache_hash[slot]; rr; rr=rr->next)
-                                       if (rr->resrec.InterfaceID == set->InterfaceID)
-                                               PurgeCacheResourceRecord(m, rr);
+                       FORALL_CACHERECORDS(slot, cg, rr)
+                               if (rr->resrec.InterfaceID == set->InterfaceID)
+                                       PurgeCacheResourceRecord(m, rr);
                        }
                }
 
@@ -6278,12 +6553,12 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
        if (revalidate && !m->mDNS_shutdown)
                {
                mDNSu32 slot;
+               CacheGroup *cg;
                CacheRecord *rr;
                m->NextCacheCheck = m->timenow;
-               for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
-                       for (rr = m->rrcache_hash[slot]; rr; rr=rr->next)
-                               if (rr->resrec.InterfaceID == set->InterfaceID)
-                                       mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForCableDisconnect);
+               FORALL_CACHERECORDS(slot, cg, rr)
+                       if (rr->resrec.InterfaceID == set->InterfaceID)
+                               mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForCableDisconnect);
                }
 
        mDNS_Unlock(m);
@@ -6300,7 +6575,7 @@ mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus resu
                if      (result == mStatus_NoError)      msg = "Name Registered";
                else if (result == mStatus_NameConflict) msg = "Name Conflict";
                else if (result == mStatus_MemFree)      msg = "Memory Free";
-               debugf("ServiceCallback: %##s (%s) %s (%ld)", rr->resrec.name.c, DNSTypeName(rr->resrec.rrtype), msg, result);
+               debugf("ServiceCallback: %##s (%s) %s (%ld)", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), msg, result);
                }
        #endif
 
@@ -6317,7 +6592,7 @@ mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus resu
        
        if (result == mStatus_MemFree)
                {
-               // If the PTR record or any of the subtype PTR record are still in the process of deregistering,
+               // If the PTR record or any of the subtype PTR records are still in the process of deregistering,
                // don't pass on the NameConflict/MemFree message until every record is finished cleaning up.
                mDNSu32 i;
                if (sr->RR_PTR.resrec.RecordType != kDNSRecordTypeUnregistered) return;
@@ -6384,18 +6659,18 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
        // Set up the record names
        // For now we only create an advisory record for the main type, not for subtypes
        // We need to gain some operational experience before we decide if there's a need to create them for subtypes too
-       if (ConstructServiceName(&sr->RR_ADV.resrec.name, (domainlabel*)"\x09_services", (domainname*)"\x07_dns-sd\x04_udp", domain) == mDNSNULL)
+       if (ConstructServiceName(sr->RR_ADV.resrec.name, (domainlabel*)"\x09_services", (domainname*)"\x07_dns-sd\x04_udp", domain) == mDNSNULL)
                return(mStatus_BadParamErr);
-       if (ConstructServiceName(&sr->RR_PTR.resrec.name, mDNSNULL, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
-       if (ConstructServiceName(&sr->RR_SRV.resrec.name, name,     type, domain) == mDNSNULL) return(mStatus_BadParamErr);
+       if (ConstructServiceName(sr->RR_PTR.resrec.name, mDNSNULL, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
+       if (ConstructServiceName(sr->RR_SRV.resrec.name, name,     type, domain) == mDNSNULL) return(mStatus_BadParamErr);
        AssignDomainName(sr->RR_TXT.resrec.name, sr->RR_SRV.resrec.name);
        
        // 1. Set up the ADV record rdata to advertise our service type
-       AssignDomainName(sr->RR_ADV.resrec.rdata->u.name, sr->RR_PTR.resrec.name);
+       AssignDomainName(&sr->RR_ADV.resrec.rdata->u.name, sr->RR_PTR.resrec.name);
 
        // 2. Set up the PTR record rdata to point to our service name
        // We set up two additionals, so when a client asks for this PTR we automatically send the SRV and the TXT too
-       AssignDomainName(sr->RR_PTR.resrec.rdata->u.name, sr->RR_SRV.resrec.name);
+       AssignDomainName(&sr->RR_PTR.resrec.rdata->u.name, sr->RR_SRV.resrec.name);
        sr->RR_PTR.Additional1 = &sr->RR_SRV;
        sr->RR_PTR.Additional2 = &sr->RR_TXT;
 
@@ -6405,11 +6680,12 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
        for (i=0; i<NumSubTypes; i++)
                {
                domainname st;
-               AssignDomainName(st, sr->SubTypes[i].resrec.name);
+               AssignDomainName(&st, sr->SubTypes[i].resrec.name);
+               st.c[1+st.c[0]] = 0;                    // Only want the first label, not the whole FQDN (particularly for mDNS_RenameAndReregisterService())
                AppendDomainName(&st, type);
                mDNS_SetupResourceRecord(&sr->SubTypes[i], mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, ServiceCallback, sr);
-               if (ConstructServiceName(&sr->SubTypes[i].resrec.name, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr);
-               AssignDomainName(sr->SubTypes[i].resrec.rdata->u.name, sr->RR_SRV.resrec.name);
+               if (ConstructServiceName(sr->SubTypes[i].resrec.name, mDNSNULL, &st, domain) == mDNSNULL) return(mStatus_BadParamErr);
+               AssignDomainName(&sr->SubTypes[i].resrec.rdata->u.name, sr->RR_SRV.resrec.name);
                sr->SubTypes[i].Additional1 = &sr->RR_SRV;
                sr->SubTypes[i].Additional2 = &sr->RR_TXT;
                }
@@ -6420,7 +6696,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
        sr->RR_SRV.resrec.rdata->u.srv.port     = port;
 
        // Setting HostTarget tells DNS that the target of this SRV is to be automatically kept in sync with our host name
-       if (sr->Host.c[0]) AssignDomainName(sr->RR_SRV.resrec.rdata->u.srv.target, sr->Host);
+       if (sr->Host.c[0]) AssignDomainName(&sr->RR_SRV.resrec.rdata->u.srv.target, &sr->Host);
        else { sr->RR_SRV.HostTarget = mDNStrue; sr->RR_SRV.resrec.rdata->u.srv.target.c[0] = '\0'; }
 
        // 4. Set up the TXT record rdata,
@@ -6437,7 +6713,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
 #ifndef UNICAST_DISABLED       
        // If the client has specified an explicit InterfaceID,
        // then we do a multicast registration  on that interface, even for unicast domains.
-       if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&sr->RR_SRV.resrec.name)))
+       if (!(InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
                {
                mStatus status;
                mDNS_Lock(m);
@@ -6478,7 +6754,7 @@ mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
        AssignDomainName(extra->r.resrec.name, sr->RR_SRV.resrec.name);
        
 #ifndef UNICAST_DISABLED
-       if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&sr->RR_SRV.resrec.name)))
+       if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
                {
                mDNS_Lock(m);
                // Some (or perhaps all) versions of BIND named (name daemon) don't allow updates with zero-length rdata.
@@ -6499,7 +6775,7 @@ mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
 
        extra->r.DependentOn = &sr->RR_SRV;
        
-       debugf("mDNS_AddRecordToService adding record to %##s", extra->r.resrec.name.c);
+       debugf("mDNS_AddRecordToService adding record to %##s", extra->r.resrec.name->c);
        
        status = mDNS_Register_internal(m, &extra->r);
        if (status == mStatus_NoError) *e = extra;
@@ -6517,17 +6793,17 @@ mDNSexport mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet
        while (*e && *e != extra) e = &(*e)->next;
        if (!*e)
                {
-               debugf("mDNS_RemoveRecordFromService failed to remove record from %##s", extra->r.resrec.name.c);
+               debugf("mDNS_RemoveRecordFromService failed to remove record from %##s", extra->r.resrec.name->c);
                status = mStatus_BadReferenceErr;
                }
        else
                {
-               debugf("mDNS_RemoveRecordFromService removing record from %##s", extra->r.resrec.name.c);
+               debugf("mDNS_RemoveRecordFromService removing record from %##s", extra->r.resrec.name->c);
                extra->r.RecordCallback = MemFreeCallback;
                extra->r.RecordContext  = Context;
                *e = (*e)->next;
 #ifndef UNICAST_DISABLED       
-               if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&sr->RR_SRV.resrec.name)))
+               if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
                        status = uDNS_DeregisterRecord(m, &extra->r);
                else
 #endif
@@ -6547,14 +6823,14 @@ mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordS
        ExtraResourceRecord *extras = sr->Extras;
        mStatus err;
 
-       DeconstructServiceName(&sr->RR_SRV.resrec.name, &name1, &type, &domain);
+       DeconstructServiceName(sr->RR_SRV.resrec.name, &name1, &type, &domain);
        if (!newname)
                {
                name2 = name1;
                IncrementLabelSuffix(&name2, mDNStrue);
                newname = &name2;
                }
-       LogMsg("Service \"%##s\" renamed to \"%#s\"", sr->RR_SRV.resrec.name.c, newname->c);
+       LogMsg("Service \"%##s\" renamed to \"%#s\"", sr->RR_SRV.resrec.name->c, newname->c);
        if (sr->RR_SRV.HostTarget == mDNSfalse && sr->Host.c[0]) host = &sr->Host;
        
        err = mDNS_RegisterService(m, sr, newname, &type, &domain,
@@ -6584,7 +6860,7 @@ mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
        if (!sr->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV));
 
 #ifndef UNICAST_DISABLED       
-       if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&sr->RR_SRV.resrec.name)))
+       if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
                {
                mStatus status;
                mDNS_Lock(m);
@@ -6595,12 +6871,12 @@ mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
 #endif
        if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeUnregistered)
                {
-               debugf("Service set for %##s already deregistered", sr->RR_SRV.resrec.name.c);
+               debugf("Service set for %##s already deregistered", sr->RR_SRV.resrec.name->c);
                return(mStatus_BadReferenceErr);
                }
        else if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeDeregistering)
                {
-               debugf("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name.c);
+               debugf("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name->c);
                return(mStatus_NoError);
                }
        else
@@ -6652,11 +6928,11 @@ mDNSexport mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const r
        const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context)
        {
        mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, kDNSRecordTypeUnique, Callback, Context);
-       if (ConstructServiceName(&rr->resrec.name, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
+       if (ConstructServiceName(rr->resrec.name, name, type, domain) == mDNSNULL) return(mStatus_BadParamErr);
        rr->resrec.rdata->u.srv.priority    = 0;
        rr->resrec.rdata->u.srv.weight      = 0;
        rr->resrec.rdata->u.srv.port        = zeroIPPort;
-       if (host && host->c[0]) AssignDomainName(rr->resrec.rdata->u.srv.target, *host);
+       if (host && host->c[0]) AssignDomainName(&rr->resrec.rdata->u.srv.target, host);
        else rr->HostTarget = mDNStrue;
        return(mDNS_Register(m, rr));
        }
@@ -6665,7 +6941,7 @@ mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr,
        mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname)
        {
        mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, kDNSType_PTR, kStandardTTL, kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
-       if (!MakeDomainNameFromDNSNameString(&rr->resrec.name, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
+       if (!MakeDomainNameFromDNSNameString(rr->resrec.name, mDNS_DomainTypeNames[DomainType])) return(mStatus_BadParamErr);
        if (!MakeDomainNameFromDNSNameString(&rr->resrec.rdata->u.name, domname))                 return(mStatus_BadParamErr);
        return(mDNS_Register(m, rr));
        }
@@ -6677,11 +6953,12 @@ mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr,
 #pragma mark - Startup and Shutdown
 #endif
 
-mDNSlocal void mDNS_GrowCache_internal(mDNS *const m, CacheRecord *storage, mDNSu32 numrecords)
+mDNSlocal void mDNS_GrowCache_internal(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords)
        {
        if (storage && numrecords)
                {
                mDNSu32 i;
+               LogOperation("Adding cache storage for %d more records (%d bytes)", numrecords, numrecords*sizeof(CacheEntity));
                for (i=0; i<numrecords; i++) storage[i].next = &storage[i+1];
                storage[numrecords-1].next = m->rrcache_free;
                m->rrcache_free = storage;
@@ -6689,7 +6966,7 @@ mDNSlocal void mDNS_GrowCache_internal(mDNS *const m, CacheRecord *storage, mDNS
                }
        }
 
-mDNSexport void mDNS_GrowCache(mDNS *const m, CacheRecord *storage, mDNSu32 numrecords)
+mDNSexport void mDNS_GrowCache(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords)
        {
        mDNS_Lock(m);
        mDNS_GrowCache_internal(m, storage, numrecords);
@@ -6697,7 +6974,7 @@ mDNSexport void mDNS_GrowCache(mDNS *const m, CacheRecord *storage, mDNSu32 numr
        }
 
 mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
-       CacheRecord *rrcachestorage, mDNSu32 rrcachesize,
+       CacheEntity *rrcachestorage, mDNSu32 rrcachesize,
        mDNSBool AdvertiseLocalAddresses, mDNSCallback *Callback, void *Context)
        {
        mDNSu32 slot;
@@ -6759,12 +7036,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
        m->rrcache_report          = 10;
        m->rrcache_free            = mDNSNULL;
 
-       for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
-               {
-               m->rrcache_hash[slot] = mDNSNULL;
-               m->rrcache_tail[slot] = &m->rrcache_hash[slot];
-               m->rrcache_used[slot] = 0;
-               }
+       for (slot = 0; slot < CACHE_HASH_SLOTS; slot++) m->rrcache_hash[slot] = mDNSNULL;
 
        mDNS_GrowCache_internal(m, rrcachestorage, rrcachesize);
 
@@ -6776,9 +7048,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
        m->HISoftware.c[0]         = 0;
        m->ResourceRecords         = mDNSNULL;
        m->DuplicateRecords        = mDNSNULL;
-       m->LocalOnlyRecords        = mDNSNULL;
-       m->NewLocalOnlyRecords     = mDNSNULL;
-       m->DiscardLocalOnlyRecords = mDNSfalse;
+       m->NewLocalRecords         = mDNSNULL;
        m->CurrentRecord           = mDNSNULL;
        m->HostInterfaces          = mDNSNULL;
        m->ProbeFailTime           = 0;
@@ -6822,23 +7092,24 @@ mDNSexport void mDNS_Close(mDNS *const m)
        rrcache_totalused = m->rrcache_totalused;
        for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
                {
-               while (m->rrcache_hash[slot])
+               while(m->rrcache_hash[slot])
                        {
-                       CacheRecord *rr = m->rrcache_hash[slot];
-                       m->rrcache_hash[slot] = rr->next;
-                       if (rr->CRActiveQuestion) rrcache_active++;
-                       m->rrcache_used[slot]--;
-                       ReleaseCacheRR(m, rr);
+                       CacheGroup *cg = m->rrcache_hash[slot];
+                       while (cg->members)
+                               {
+                               CacheRecord *rr = cg->members;
+                               cg->members = cg->members->next;
+                               if (rr->CRActiveQuestion) rrcache_active++;
+                               ReleaseCacheRecord(m, rr);
+                               }
+                       cg->rrcache_tail = &cg->members;
+                       ReleaseCacheGroup(m, &m->rrcache_hash[slot]);
                        }
-               // Reset tail pointer back to empty state (not that it really matters on exit, but we'll do it anyway, for the sake of completeness)
-               m->rrcache_tail[slot] = &m->rrcache_hash[slot];
                }
        debugf("mDNS_Close: RR Cache was using %ld records, %lu active", rrcache_totalused, rrcache_active);
        if (rrcache_active != m->rrcache_active)
                LogMsg("*** ERROR *** rrcache_active %lu != m->rrcache_active %lu", rrcache_active, m->rrcache_active);
 
-       m->Questions = mDNSNULL;                // We won't be answering any more questions!
-       
        for (intf = m->HostInterfaces; intf; intf = intf->next)
                if (intf->Advertise)
                        DeadvertiseInterface(m, intf);
@@ -6849,23 +7120,22 @@ mDNSexport void mDNS_Close(mDNS *const m)
        while (m->CurrentRecord)
                {
                AuthRecord *rr = m->CurrentRecord;
-               m->CurrentRecord = rr->next;
                if (rr->resrec.RecordType != kDNSRecordTypeDeregistering)
                        {
-                       debugf("mDNS_Close: Record type %X still in ResourceRecords list %##s", rr->resrec.RecordType, rr->resrec.name.c);
+                       debugf("mDNS_Close: Record type %X still in ResourceRecords list %##s", rr->resrec.RecordType, rr->resrec.name->c);
                        mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
                        }
+               else
+                       m->CurrentRecord = rr->next;
                }
 
        if (m->ResourceRecords) debugf("mDNS_Close: Sending final packets for deregistering records");
        else debugf("mDNS_Close: No deregistering records remain");
 
        // If any deregistering records remain, send their deregistration announcements before we exit
-       if (m->mDNSPlatformStatus != mStatus_NoError)
-               DiscardDeregistrations(m);
-       else
-               while (m->ResourceRecords)
-                       SendResponses(m);
+       if (m->mDNSPlatformStatus != mStatus_NoError) DiscardDeregistrations(m);
+       else if (m->ResourceRecords) SendResponses(m);
+       if (m->ResourceRecords) LogMsg("mDNS_Close failed to send goodbye for: %s", ARDisplayString(m, m->ResourceRecords));
        
        mDNS_Unlock(m);
        debugf("mDNS_Close: mDNSPlatformClose");
index 8f95d424081e5e8ab993ee69ce7368c893b83cb1..11c97378dd1d09d19be8e3ac8a27cde7af03407e 100755 (executable)
@@ -23,6 +23,9 @@
     Change History (most recent first):
 
 $Log: mDNSDebug.h,v $
+Revision 1.25  2004/12/14 21:34:16  cheshire
+Add "#define ANSWER_REMOTE_HOSTNAME_QUERIES 0" and comment
+
 Revision 1.24  2004/09/16 01:58:21  cheshire
 Fix compiler warnings
 
@@ -141,6 +144,9 @@ extern void LogMsg(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
 extern void LogMsgIdent(const char *ident, const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(2,3);
 extern void LogMsgNoIdent(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
 
+// Set this symbol to 1 to answer remote queries for our Address, reverse mapping PTR, and HINFO records
+#define ANSWER_REMOTE_HOSTNAME_QUERIES 0
+
 // Set this symbol to 1 to do extra debug checks on malloc() and free()
 // Set this symbol to 2 to write a log message for every malloc() and free()
 #define MACOSX_MDNS_MALLOC_DEBUGGING 0
index ac0215df041f47fe93bc5cdc5a041441d04e8afb..6397c1fa6b42f75d6f7ce89051dfe5ec54fddd41 100755 (executable)
     Change History (most recent first):
 
 $Log: mDNSEmbeddedAPI.h,v $
+Revision 1.275  2005/01/27 22:57:55  cheshire
+Fix compile errors on gcc4
+
+Revision 1.274  2005/01/19 21:01:54  ksekar
+<rdar://problem/3955355> uDNS needs to support subtype registration and browsing
+
+Revision 1.273  2005/01/19 19:15:31  ksekar
+Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
+
+Revision 1.272  2005/01/18 18:10:55  ksekar
+<rdar://problem/3954575> Use 10.4 resolver API to get search domains
+
+Revision 1.271  2005/01/15 00:56:41  ksekar
+<rdar://problem/3954575> Unicast services don't disappear when logging
+out of VPN
+
+Revision 1.270  2005/01/14 18:34:22  ksekar
+<rdar://problem/3954571> Services registered outside of firewall don't succeed after location change
+
+Revision 1.269  2005/01/11 22:50:52  ksekar
+Fixed constant naming (was using kLLQ_DefLease for update leases)
+
+Revision 1.268  2004/12/22 22:25:47  ksekar
+<rdar://problem/3734265> NATPMP: handle location changes
+
+Revision 1.267  2004/12/22 00:13:49  ksekar
+<rdar://problem/3873993> Change version, port, and polling interval for LLQ
+
+Revision 1.266  2004/12/18 03:13:45  cheshire
+<rdar://problem/3751638> kDNSServiceInterfaceIndexLocalOnly should return all local records
+
+Revision 1.265  2004/12/17 23:37:45  cheshire
+<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
+(and other repetitive configuration changes)
+
+Revision 1.264  2004/12/17 05:25:46  cheshire
+<rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
+
+Revision 1.263  2004/12/16 20:40:25  cheshire
+Fix compile warnings
+
+Revision 1.262  2004/12/16 20:13:00  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
+Revision 1.261  2004/12/14 21:21:20  ksekar
+<rdar://problem/3825979> NAT-PMP: Update response format to contain "Seconds Since Boot"
+
 Revision 1.260  2004/12/12 23:51:42  ksekar
 <rdar://problem/3845683> Wide-area registrations should fallback to using DHCP hostname as target
 
@@ -1104,7 +1151,7 @@ enum
        mStatus_NoAuth            = -65555,
        mStatus_NoSuchKey         = -65556,
        mStatus_NATTraversal      = -65557,
-       mStatus_DblNAT            = -65558,
+       mStatus_DoubleNAT         = -65558,
        mStatus_BadTime           = -65559,
        mStatus_BadSig            = -65560,     // while we define this per RFC 2845, BIND 9 returns Refused for bad/missing signatures
        mStatus_BadKey            = -65561,
@@ -1155,8 +1202,13 @@ typedef struct { mDNSu8 c[256]; } UTF8str255;            // Null-terminated C string
 // For records containing a hostname (in the name on the left, or in the rdata on the right),
 // like A, AAAA, reverse-mapping PTR, and SRV, we use a two-minute TTL by default, because we don't want
 // them to hang around for too long in the cache if the host in question crashes or otherwise goes away.
-#define kStandardTTL (3600 * 100 / 80)
-#define kHostNameTTL 120
+// Wide-area service discovery records have a very short TTL to aviod poluting intermediate caches with
+// dynamic records.  When discovered via Long Lived Queries (with change notifications), resource record
+// TTLs can be safely ignored.
+       
+#define kStandardTTL (3600UL * 100 / 80)
+#define kHostNameTTL 120UL
+#define kWideAreaTTL 3
 
 #define DefaultTTLforRRType(X) (((X) == kDNSType_A || (X) == kDNSType_AAAA || (X) == kDNSType_SRV) ? kHostNameTTL : kStandardTTL)
 
@@ -1320,8 +1372,12 @@ typedef packedstruct
 // 184 were sixteen-byte AAAA records
 // 780 were various PTR, TXT and SRV records from 12-64 bytes
 // Only 69 records had rdata bigger than 64 bytes
+// Note that since CacheRecord object and a CacheGroup object are allocated out of the same pool, it's sensible to
+// have them both be the same size. Making one smaller without making the other smaller won't actually save any memory.
 #define InlineCacheRDSize 64
 
+#define InlineCacheGroupNameSize 144
+
 typedef union
        {
        mDNSu8      data[StandardAuthRDSize];
@@ -1344,7 +1400,7 @@ typedef struct
 
 typedef struct AuthRecord_struct AuthRecord;
 typedef struct CacheRecord_struct CacheRecord;
-typedef struct ResourceRecord_struct ResourceRecord;
+typedef struct CacheGroup_struct CacheGroup;
 typedef struct DNSQuestion_struct DNSQuestion;
 typedef struct mDNS_struct mDNS;
 typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport;
@@ -1359,14 +1415,14 @@ typedef void mDNSRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus res
 // The internal data structures of the mDNS code may not be in a state where mDNS API calls may be made safely.
 typedef void mDNSRecordUpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData);
 
-struct ResourceRecord_struct
+typedef struct
        {
        mDNSu8          RecordType;                     // See enum above
        mDNSInterfaceID InterfaceID;            // Set if this RR is specific to one interface
                                                                                // For records received off the wire, InterfaceID is *always* set to the receiving interface
                                                                                // For our authoritative records, InterfaceID is usually zero, except for those few records
                                                                                // that are interface-specific (e.g. address records, especially linklocal addresses)
-       domainname      name;
+       domainname     *name;
        mDNSu16         rrtype;
        mDNSu16         rrclass;
        mDNSu32         rroriginalttl;          // In seconds
@@ -1376,7 +1432,7 @@ struct ResourceRecord_struct
        mDNSu32         rdatahash;                      // 32-bit hash of the raw rdata
        mDNSu32         rdnamehash;                     // Set if this rdata contains a domain name (e.g. PTR, SRV, CNAME etc.)
        RData           *rdata;                         // Pointer to storage for this rdata
-       };
+       } ResourceRecord;
 
 // Unless otherwise noted, states may apply to either independent record registrations or service registrations        
 typedef enum
@@ -1392,7 +1448,8 @@ typedef enum
        regState_NATMap            = 10,    // establishing NAT port mapping or learning public address
        regState_UpdatePending     = 11,    // update in flight as result of mDNS_Update call
        regState_NoTarget          = 12,    // service registration pending registration of hostname (ServiceRegistrations only)
-    regState_ExtraQueued       = 13     // extra record to be registered upon completion of service registration (RecordRegistrations only)
+    regState_ExtraQueued       = 13,    // extra record to be registered upon completion of service registration (RecordRegistrations only)
+       regState_NATError          = 14     // unable to complete NAT traversal
        } regState_t; 
 
 // context for both ServiceRecordSet and individual AuthRec structs
@@ -1414,12 +1471,12 @@ typedef struct
        
        // NAT traversal context
        NATTraversalInfo *NATinfo; // may be NULL
-       
+
        // state for deferred operations
     mDNSBool     ClientCallbackDeferred;  // invoke client callback on completion of pending operation(s)
        mStatus      DeferredStatus;          // status to deliver when above flag is set
     mDNSBool     SRVUpdateDeferred;       // do we need to change target or port once current operation completes?
-    mDNSBool     LostTarget;              // temporarily deregistered service because its target was deregistered
+    mDNSBool     SRVChanged;              // temporarily deregistered service because its SRV target or port changed
 
     // uDNS_UpdateRecord support fields
        mDNSBool     UpdateQueued; // Update the rdata once the current pending operation completes
@@ -1436,10 +1493,11 @@ struct AuthRecord_struct
        // mDNS_SetupResourceRecord() is avaliable as a helper routine to set up most fields to sensible default values for you
 
        AuthRecord     *next;                           // Next in list; first element of structure for efficiency reasons
+       // Field Group 1: Common ResourceRecord fields
        ResourceRecord  resrec;
        uDNS_RegInfo uDNS_info;
 
-       // Persistent metadata for Authoritative Records
+       // Field Group 2: Persistent metadata for Authoritative Records
        AuthRecord     *Additional1;            // Recommended additional record to include in response
        AuthRecord     *Additional2;            // Another additional
        AuthRecord     *DependentOn;            // This record depends on another for its uniqueness checking
@@ -1450,11 +1508,12 @@ struct AuthRecord_struct
        mDNSu8          AllowRemoteQuery;       // Set if we allow hosts not on the local link to query this record
        mDNSu8          ForceMCast;                     // Set by client to advertise solely via multicast, even for apparently unicast names
 
-       // Transient state for Authoritative Records
+       // Field Group 3: Transient state for Authoritative Records
        mDNSu8          Acknowledged;           // Set if we've given the success callback to the client
        mDNSu8          ProbeCount;                     // Number of probes remaining before this record is valid (kDNSRecordTypeUnique)
        mDNSu8          AnnounceCount;          // Number of announcements remaining (kDNSRecordTypeShared)
        mDNSu8          RequireGoodbye;         // Set if this RR has been announced on the wire and will require a goodbye packet
+       mDNSu8          LocalAnswer;            // Set if this RR has been delivered to LocalOnly questions
        mDNSu8          IncludeInProbe;         // Set if this RR is being put into a probe right now
        mDNSInterfaceID ImmedAnswer;            // Someone on this interface issued a query we need to answer (all-ones for all interfaces)
        mDNSu8          ImmedUnicast;           // Set if we may send our response directly via unicast to the requester
@@ -1480,6 +1539,7 @@ struct AuthRecord_struct
        mDNSs32         NextUpdateCredit;       // Time next token is added to bucket
        mDNSs32         UpdateBlocked;          // Set if update delaying is in effect
 
+       domainname      namestorage;
        RData           rdatastorage;           // Normally the storage is right here, except for oversized records
        // rdatastorage MUST be the last thing in the structure -- when using oversized AuthRecords, extra bytes
        // are appended after the end of the AuthRecord, logically augmenting the size of the rdatastorage
@@ -1493,6 +1553,16 @@ typedef struct ARListElem
        AuthRecord ar;          // Note: Must be last struct in field to accomodate oversized AuthRecords
        } ARListElem;
 
+struct CacheGroup_struct                               // Header object for a list of CacheRecords with the same name
+       {
+       CacheGroup     *next;                           // Next CacheGroup object in this hash table bucket
+       mDNSu32         namehash;                       // Name-based (i.e. case insensitive) hash of name
+       CacheRecord    *members;                        // List of CacheRecords with this same name
+       CacheRecord   **rrcache_tail;           // Tail end of that list
+       domainname     *name;                           // Common name for all CacheRecords in this list
+       mDNSu8          namestorage[InlineCacheGroupNameSize];
+       };
+
 struct CacheRecord_struct
        {
        CacheRecord    *next;                           // Next in list; first element of structure for efficiency reasons
@@ -1516,10 +1586,15 @@ struct CacheRecord_struct
        struct { mDNSu16 MaxRDLength; mDNSu8 data[InlineCacheRDSize]; } rdatastorage;   // Storage for small records is right here
        };
 
+// Storage sufficient to hold either a CacheGroup header or a CacheRecord
+typedef union CacheEntity_union CacheEntity;
+union CacheEntity_union { CacheEntity *next; CacheGroup cg; CacheRecord cr; };
+
 typedef struct
        {
        CacheRecord r;
        mDNSu8 _extradata[MaximumRDSize-InlineCacheRDSize];             // Glue on the necessary number of extra bytes
+       domainname namestorage;                                                                 // Needs to go *after* the extra rdata bytes
        } LargeCacheRecord;
 
 typedef struct uDNS_HostnameInfo
@@ -1665,9 +1740,8 @@ typedef struct
 // LLQ constants
 #define kDNSOpt_LLQ       1
 #define kDNSOpt_Lease  2
-#define kLLQ_Vers      0 // prerelease
+#define kLLQ_Vers      1
 #define kLLQ_DefLease  7200 // 2 hours
-#define kUpdate_DefLease 7200
 #define kLLQ_MAX_TRIES 3    // retry an operation 3 times max
 #define kLLQ_INIT_RESEND 2 // resend an un-ack'd packet after 2 seconds, then double for each additional
 #define kLLQ_DEF_RETRY 1800 // retry a failed operation after 30 minutes
@@ -1727,6 +1801,7 @@ struct DNSQuestion_struct
        DupSuppressInfo       DupSuppress[DupSuppressInfoSize];
        mDNSInterfaceID       SendQNow;                 // The interface this query is being sent on right now
        mDNSBool              SendOnAll;                // Set if we're sending this question on all active interfaces
+       mDNSu32               RequestUnicast;   // Non-zero if we want to send query with kDNSQClass_UnicastResponse bit set
        mDNSs32               LastQTxTime;              // Last time this Q was sent on one (but not necessarily all) interfaces
        uDNS_QuestionInfo     uDNS_info;
 
@@ -1792,9 +1867,6 @@ struct ServiceInfoQuery_struct
 #define NATMAP_DEFAULT_LEASE (60 * 60)  // lease life in seconds
 #define NATMAP_VERS 0
 #define NATMAP_PORT 5351
-#define ADDR_REQUEST_PKTLEN 2
-#define ADDR_REPLY_PKTLEN 8
-#define PORTMAP_PKTLEN 12
 #define NATMAP_RESPONSE_MASK 0x80
 
 typedef enum
@@ -1818,17 +1890,53 @@ typedef mDNSu16 NATErr_t;
 
 typedef enum
        {
-       NATState_Init,
-       NATState_Request,
-       NATState_Established,
-       NATState_Legacy,
-       NATState_Error,
-       NATState_Refresh,
-       NATState_Deleted
+       NATState_Init         = 0,
+       NATState_Request      = 1,
+       NATState_Established  = 2,
+       NATState_Legacy       = 3,
+       NATState_Error        = 4,
+       NATState_Refresh      = 5,
+       NATState_Deleted      = 6
        } NATState_t;
 // Note: we have no explicit "cancelled" state, where a service/interface is deregistered while we
  // have an outstanding NAT request.  This is conveyed by the "reg" pointer being set to NULL
 
+typedef packedstruct
+       {
+       mDNSu8 vers;
+       mDNSu8 opcode;
+       } NATAddrRequest;       
+       
+typedef packedstruct
+       {
+       mDNSu8 vers;
+       mDNSu8 opcode;
+       mDNSOpaque16 err;
+       mDNSOpaque32 uptime;
+       mDNSv4Addr   PubAddr;
+       } NATAddrReply;
+
+typedef packedstruct
+       {
+       mDNSu8 vers;
+       mDNSu8 opcode;
+       mDNSOpaque16 unused;
+       mDNSIPPort priv;
+       mDNSIPPort pub;
+       mDNSOpaque32 lease;
+       } NATPortMapRequest;
+       
+typedef packedstruct
+       {
+       mDNSu8 vers;
+       mDNSu8 opcode;
+       mDNSOpaque16 err;
+       mDNSOpaque32 uptime;
+       mDNSIPPort priv;
+       mDNSIPPort pub;
+       mDNSOpaque32 lease;
+       } NATPortMapReply;
+       
 // Pass NULL for pkt on error (including timeout)
 typedef void (*NATResponseHndlr)(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len);
 
@@ -1837,9 +1945,9 @@ struct NATTraversalInfo_struct
        NATOp_t op;
        NATResponseHndlr ReceiveResponse;
        union { AuthRecord *RecordRegistration; ServiceRecordSet *ServiceRegistration; } reg;
-       mDNSIPPort PublicPort;
-       mDNSu8 request[PORTMAP_PKTLEN];  // buffer for request messages
-       int requestlen;                  // length of buffer used
+    mDNSAddr Router;
+    mDNSIPPort PublicPort;
+    union { NATAddrRequest AddrReq; NATPortMapRequest PortReq; } request;
        mDNSs32 retry;                   // absolute time when we retry
        mDNSs32 RetryInterval;           // delta between time sent and retry
        int ntries;
@@ -1883,6 +1991,8 @@ typedef struct
     DNSQuestion      ReverseMap;         // Reverse-map query to find  static hostname for service target
     mDNSBool         ReverseMapActive;   // Is above query active?
     domainname       StaticHostname;     // Current answer to reverse-map query (above)
+    mDNSBool         DelaySRVUpdate;     // Delay SRV target/port update to avoid "flap"
+    mDNSs32          NextSRVUpdate;      // Time to perform delayed update
        } uDNS_GlobalInfo;
 
 struct mDNS_struct
@@ -1938,10 +2048,8 @@ struct mDNS_struct
        mDNSu32 rrcache_totalused;                      // Number of cache entries currently occupied
        mDNSu32 rrcache_active;                         // Number of cache entries currently occupied by records that answer active questions
        mDNSu32 rrcache_report;
-       CacheRecord *rrcache_free;
-       CacheRecord *rrcache_hash[CACHE_HASH_SLOTS];
-       CacheRecord **rrcache_tail[CACHE_HASH_SLOTS];
-       mDNSu32 rrcache_used[CACHE_HASH_SLOTS];
+       CacheEntity *rrcache_free;
+       CacheGroup *rrcache_hash[CACHE_HASH_SLOTS];
 
        // Fields below only required for mDNS Responder...
        domainlabel nicelabel;                          // Rich text label encoded using canonically precomposed UTF-8
@@ -1951,9 +2059,7 @@ struct mDNS_struct
        UTF8str255  HISoftware;
        AuthRecord *ResourceRecords;
        AuthRecord *DuplicateRecords;           // Records currently 'on hold' because they are duplicates of existing records
-       AuthRecord *LocalOnlyRecords;           // Local records registered with InterfaceID set to mDNSInterface_LocalOnly
-       AuthRecord *NewLocalOnlyRecords;        // Fresh local-only records not yet delivered to local-only questions
-       mDNSBool    DiscardLocalOnlyRecords;// Set when we have "remove" events we need to deliver to local-only questions
+       AuthRecord *NewLocalRecords;            // Fresh local-only records not yet delivered to local-only questions
        AuthRecord *CurrentRecord;                      // Next AuthRecord about to be examined
        NetworkInterfaceInfo *HostInterfaces;
        mDNSs32 ProbeFailTime;
@@ -1969,6 +2075,11 @@ struct mDNS_struct
        LargeCacheRecord rec;   // Resource Record extracted from received message
        };
 
+#define FORALL_CACHERECORDS(SLOT,CG,CR)                          \
+       for ((SLOT) = 0; (SLOT) < CACHE_HASH_SLOTS; (SLOT)++)        \
+               for((CG)=m->rrcache_hash[(SLOT)]; (CG); (CG)=(CG)->next) \
+                       for ((CR) = (CG)->members; (CR); (CR)=(CR)->next)
+
 // ***************************************************************************
 #if 0
 #pragma mark - Useful Static Constants
@@ -1983,7 +2094,7 @@ extern const mDNSv6Addr      onesIPv6Addr;
 extern const mDNSAddr        zeroAddr;
 
 extern const mDNSInterfaceID mDNSInterface_Any;                                // Zero
-extern const mDNSInterfaceID mDNSInterface_LocalOnly;          // (mDNSInterfaceID)-1;
+extern const mDNSInterfaceID mDNSInterface_LocalOnly;          // Special value
 
 extern const mDNSIPPort      UnicastDNSPort;
 extern const mDNSIPPort      MulticastDNSPort;
@@ -2000,7 +2111,8 @@ extern const mDNSOpaque16 UpdateReqFlags;
 extern const mDNSOpaque16 UpdateRespFlags;
 
 #define localdomain (*(const domainname *)"\x5local")
-
+#define LocalReverseMapomain (*(const domainname *)"\x3" "254" "\x3" "169" "\x7" "in-addr" "\x4" "arpa")
+       
 // ***************************************************************************
 #if 0
 #pragma mark - Inline functions
@@ -2014,6 +2126,7 @@ extern const mDNSOpaque16 UpdateRespFlags;
 
 // If we're not doing inline functions, then this header needs to have the extern declarations
 #if !defined(mDNSinline)
+extern mDNSs32      NonZeroTime(mDNSs32 t);
 extern mDNSu16      mDNSVal16(mDNSOpaque16 x);
 extern mDNSu32      mDNSVal32(mDNSOpaque32 x);
 extern mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v);
@@ -2103,7 +2216,7 @@ mDNSinline mDNSOpaque32 mDNSOpaque32fromIntVal(mDNSu32 v)
 // code is not entered by an interrupt-time timer callback while in the middle of processing a client call.
 
 extern mStatus mDNS_Init      (mDNS *const m, mDNS_PlatformSupport *const p,
-                                                               CacheRecord *rrcachestorage, mDNSu32 rrcachesize,
+                                                               CacheEntity *rrcachestorage, mDNSu32 rrcachesize,
                                                                mDNSBool AdvertiseLocalAddresses,
                                                                mDNSCallback *Callback, void *Context);
 // See notes above on use of NoCache/ZeroCacheSize
@@ -2115,7 +2228,7 @@ extern mStatus mDNS_Init      (mDNS *const m, mDNS_PlatformSupport *const p,
 #define mDNS_Init_NoInitCallback              mDNSNULL
 #define mDNS_Init_NoInitCallbackContext       mDNSNULL
 
-extern void    mDNS_GrowCache (mDNS *const m, CacheRecord *storage, mDNSu32 numrecords);
+extern void    mDNS_GrowCache (mDNS *const m, CacheEntity *storage, mDNSu32 numrecords);
 extern void    mDNS_Close     (mDNS *const m);
 extern mDNSs32 mDNS_Execute   (mDNS *const m);
 
@@ -2195,11 +2308,15 @@ typedef enum
        {
        mDNS_DomainTypeBrowse              = 0,
        mDNS_DomainTypeBrowseDefault       = 1,
-       mDNS_DomainTypeRegistration        = 2,
-       mDNS_DomainTypeRegistrationDefault = 3,
-       mDNS_DomainTypeBrowseLegacy        = 4, 
+       mDNS_DomainTypeBrowseLegacy        = 2,
+       mDNS_DomainTypeRegistration        = 3,
+       mDNS_DomainTypeRegistrationDefault = 4,
+       
+       mDNS_DomainTypeMax = 4
        } mDNS_DomainType;
 
+extern const char *const mDNS_DomainTypeNames[];
+
 extern mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
                                                                const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context);
 #define        mDNS_StopGetDomains mDNS_StopQuery
@@ -2220,7 +2337,7 @@ extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainT
 // A simple C structure assignment of a domainname can cause a protection fault by accessing unmapped memory,
 // because that object is defined to be 256 bytes long, but not all domainname objects are truly the full size.
 // This macro uses mDNSPlatformMemCopy() to make sure it only touches the actual bytes that are valid.
-#define AssignDomainName(DST, SRC) mDNSPlatformMemCopy((SRC).c, (DST).c, DomainNameLength(&(SRC)))
+#define AssignDomainName(DST, SRC) mDNSPlatformMemCopy((SRC)->c, (DST)->c, DomainNameLength((SRC)))
 
 // Comparison functions
 extern mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
@@ -2363,7 +2480,7 @@ typedef struct uDNS_AuthInfo
 // Calling this routine multiple times for a zone replaces previously entered values.  Call with a NULL key
 // to dissable authentication for the zone.
 
-extern mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const mDNSu8 *sharedSecret, mDNSu32 ssLen, mDNSBool base64);
+extern mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const char *sharedSecret, mDNSu32 ssLen, mDNSBool base64);
 
 // Hostname/Unicast Interface Configuration
 
@@ -2392,7 +2509,7 @@ extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *addr, const mD
 extern void mDNS_UpdateLLQs(mDNS *m);
 extern void mDNS_AddDNSServer(mDNS *const m, const mDNSAddr *dnsAddr, const domainname *domain);
 extern void mDNS_DeleteDNSServers(mDNS *const m);
-       
+
 // Routines called by the core, exported by DNSDigest.c
 
 // Convert a base64 encoded key into a binary byte stream
@@ -2554,7 +2671,7 @@ extern mStatus LNT_UnmapPort(mDNSIPPort PubPort, mDNSBool tcp);
 // not lightweight second-by-second CPU power management modes.)
 
 extern void     mDNS_SetFQDN(mDNS *const m);
-extern mStatus  mDNS_RegisterInterface  (mDNS *const m, NetworkInterfaceInfo *set);
+extern mStatus  mDNS_RegisterInterface  (mDNS *const m, NetworkInterfaceInfo *set, mDNSs32 delay);
 extern void     mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set);
 extern void     mDNSCoreInitComplete(mDNS *const m, mStatus result);
 extern void     mDNSCoreReceive(mDNS *const m, void *const msg, const mDNSu8 *const end,
@@ -2591,6 +2708,7 @@ struct mDNS_CompileTimeAssertionChecks
        char assert9[(sizeof(mDNSOpaque16)     ==   2                          ) ? 1 : -1];
        char assertA[(sizeof(mDNSOpaque32)     ==   4                          ) ? 1 : -1];
        char assertB[(sizeof(mDNSOpaque128)    ==  16                          ) ? 1 : -1];
+       char assertC[(sizeof(CacheRecord  )    >=  sizeof(CacheGroup)          ) ? 1 : -1];
        };
 
 // ***************************************************************************
index b2f8f3f529af90aeeb58c6d28f4f594479f94d08..c4eda13b168bb6eeddbd544336dbc72d9fcf567a 100755 (executable)
     Change History (most recent first):
 
 $Log: uDNS.c,v $
+Revision 1.183  2005/01/27 22:57:55  cheshire
+Fix compile errors on gcc4
+
+Revision 1.182  2005/01/25 18:55:05  ksekar
+Shortened log message
+
+Revision 1.181  2005/01/25 02:17:32  cheshire
+<rdar://problem/3971263> Don't use query ID zero in uDNS queries
+
+Revision 1.180  2005/01/19 21:01:54  ksekar
+<rdar://problem/3955355> uDNS needs to support subtype registration and browsing
+
+Revision 1.179  2005/01/19 19:15:35  ksekar
+Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
+
+Revision 1.178  2005/01/17 23:47:58  cheshire
+<rdar://problem/3904954> Wide-area services not found on little-endian
+
+Revision 1.177  2005/01/17 23:41:26  cheshire
+Fix compile errors
+
+Revision 1.176  2005/01/17 21:03:04  cheshire
+<rdar://problem/3904954> Wide-area services not found on little-endian
+
+Revision 1.175  2005/01/15 00:56:41  ksekar
+<rdar://problem/3954575> Unicast services don't disappear when logging
+out of VPN
+
+Revision 1.174  2005/01/14 18:44:28  ksekar
+<rdar://problem/3954609> mDNSResponder is crashing when changing domains
+
+Revision 1.173  2005/01/14 18:34:22  ksekar
+<rdar://problem/3954571> Services registered outside of firewall don't succeed after location change
+
+Revision 1.172  2005/01/11 22:50:52  ksekar
+Fixed constant naming (was using kLLQ_DefLease for update leases)
+
+Revision 1.171  2005/01/10 04:52:49  ksekar
+Changed LogMsg to debugf
+
+Revision 1.170  2005/01/08 00:50:05  ksekar
+Fixed spelling mistake in log msg
+
+Revision 1.169  2005/01/08 00:42:18  ksekar
+<rdar://problem/3922758> Clean up syslog messages
+
+Revision 1.168  2004/12/23 23:22:47  ksekar
+<rdar://problem/3933606> Unicast known answers "name" pointers point to garbage stack memory
+
+Revision 1.167  2004/12/22 22:25:47  ksekar
+<rdar://problem/3734265> NATPMP: handle location changes
+
+Revision 1.166  2004/12/22 00:04:12  ksekar
+<rdar://problem/3930324> mDNSResponder crashing in ReceivePortMapReply
+
+Revision 1.165  2004/12/18 03:14:22  cheshire
+DblNAT -> DoubleNAT
+
+Revision 1.164  2004/12/17 03:55:40  ksekar
+Don't use -1 as special meaning for expiration timer (it is a valid
+value, and is redundant with our state variables)
+
+Revision 1.163  2004/12/17 03:51:53  ksekar
+<rdar://problem/3920991> Don't update TXT record if service registration fails
+
+Revision 1.162  2004/12/17 01:29:11  ksekar
+<rdar://problem/3920598> Questions can go deaf on location changes
+
+Revision 1.161  2004/12/16 20:42:02  cheshire
+Fix compiler warnings
+
+Revision 1.160  2004/12/16 20:13:00  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
+Revision 1.159  2004/12/15 02:11:22  ksekar
+<rdar://problem/3917317> Don't check for Dynamic DNS hostname uniqueness
+
+Revision 1.158  2004/12/15 02:04:28  ksekar
+Refinement to previous checkin - we should still return NatTraversal error  when the port mapping fails
+
+Revision 1.157  2004/12/15 01:39:21  ksekar
+Refinement to previous checkin - we should still return NatTraversal error  when the port mapping fails
+
+Revision 1.156  2004/12/15 01:18:57  ksekar
+<rdar://problem/3825979> Call DeregisterService on nat port map failure
+
+Revision 1.155  2004/12/14 21:21:20  ksekar
+<rdar://problem/3825979> NAT-PMP: Update response format to contain "Seconds Since Boot"
+
+Revision 1.154  2004/12/14 20:52:27  cheshire
+Add question->qnamehash and cr->resrec.namehash to log message
+
+Revision 1.153  2004/12/14 20:45:02  cheshire
+Improved error logging in "unexpected answer" message
+
+Revision 1.152  2004/12/14 03:02:10  ksekar
+<rdar://problem/3919016> Rare race condition can cause crash
+
 Revision 1.151  2004/12/13 21:45:08  ksekar
 uDNS_DeregisterService should return NoError if called twice (to follow mDNS behavior expected by daemon layer)
 
@@ -549,7 +647,7 @@ typedef enum
 
 typedef struct
        {
-    domainname zoneName; 
+    domainname zoneName;
     mDNSAddr primaryAddr;
     mDNSu16 zoneClass;
     mDNSIPPort llqPort;
@@ -565,7 +663,7 @@ typedef struct
     // other async result structs go here
        } AsyncOpResult;
 
-typedef void AsyncOpCallback(mStatus err, mDNS *const m, void *info, const AsyncOpResult *result); 
+typedef void AsyncOpCallback(mStatus err, mDNS *const m, void *info, const AsyncOpResult *result);
 
 
 // Private Function Prototypes
@@ -574,6 +672,7 @@ typedef void AsyncOpCallback(mStatus err, mDNS *const m, void *info, const Async
 // foo), or when they aid in the grouping or readability of code (e.g. state machine code that is easier
 // read top-to-bottom.)
 
+mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n);
 mDNSlocal void hndlTruncatedAnswer(DNSQuestion *question,  const mDNSAddr *src, mDNS *m);
 mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdatePort, mDNSBool findLLQPort, AsyncOpCallback callback, void *callbackInfo);
 mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSInterfaceID InterfaceID);
@@ -582,7 +681,6 @@ mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs);
 mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs);
 mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result);
 mDNSlocal void SendRecordUpdate(mDNS *m, AuthRecord *rr, uDNS_RegInfo *info);
-mDNSlocal mStatus RegisterService(mDNS *m, ServiceRecordSet *srs);
 mDNSlocal void SuspendLLQs(mDNS *m, mDNSBool DeregisterActive);
 mDNSlocal void RestartQueries(mDNS *m);
 mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer);
@@ -631,7 +729,8 @@ mDNSlocal mDNSOpaque16 newMessageID(uDNS_GlobalInfo *u)
        {
        static mDNSBool randomized = mDNSfalse;
 
-       if (!randomized) { u->NextMessageID = mDNSRandom(~0); randomized = mDNStrue; }
+       if (!randomized) { u->NextMessageID = (mDNSu16)mDNSRandom(0xFFFF); randomized = mDNStrue; }
+       if (u->NextMessageID == 0) u->NextMessageID++;
        return mDNSOpaque16fromIntVal(u->NextMessageID++);
        }
 
@@ -655,9 +754,25 @@ mDNSlocal mStatus unlinkAR(AuthRecord **list, AuthRecord *const rr)
        return mStatus_UnknownErr;
        }
 
-mDNSlocal void unlinkSRS(uDNS_GlobalInfo *u, ServiceRecordSet *srs)
+mDNSlocal void unlinkSRS(mDNS *m, ServiceRecordSet *srs)
        {
+       uDNS_GlobalInfo *u = &m->uDNS_info;
        ServiceRecordSet **p;
+       NATTraversalInfo *n = u->NATTraversals;
+
+       // verify that no NAT objects reference this service
+       while (n)
+               {
+               if (n->reg.ServiceRegistration == srs)
+                       {
+                       NATTraversalInfo *tmp = n;
+                       n = n->next;
+                       LogMsg("ERROR: Unlinking service record set %##s still referenced by NAT traversal object!", srs->RR_SRV.resrec.name->c);
+                       FreeNATInfo(m, tmp);
+                       }
+               else n = n->next;
+               }
+                       
        for (p = &u->ServiceRegistrations; *p; p = &(*p)->next)
                if (*p == srs) { *p = srs->next; srs->next = mDNSNULL; return; }
        LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list");
@@ -695,7 +810,7 @@ mDNSlocal void SwapRData(mDNS *m, AuthRecord *rr, mDNSBool DeallocOld)
 // (for service record sets, use RR_SRV as representative for time checks
 mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr)
        {
-       rr->LastAPTime = mDNSPlatformTimeNow(m);        
+       rr->LastAPTime = mDNSPlatformTimeNow(m);
        if (rr->ThisAPInterval < INIT_UCAST_POLL_INTERVAL)   { rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL; return; }
        if (rr->ThisAPInterval*2 <= MAX_UCAST_POLL_INTERVAL) { rr->ThisAPInterval *= 2;                       return; }
        if (rr->ThisAPInterval != MAX_UCAST_POLL_INTERVAL)   { rr->ThisAPInterval = MAX_UCAST_POLL_INTERVAL;          }
@@ -726,7 +841,7 @@ mDNSexport void mDNS_AddDNSServer(mDNS *const m, const mDNSAddr *addr, const dom
        s = umalloc(sizeof(*s));
        if (!s) { LogMsg("Error: mDNS_AddDNSServer - malloc"); goto end; }
        s->addr = *addr;
-       AssignDomainName(s->domain, *d);
+       AssignDomainName(&s->domain, d);
        s->next = mDNSNULL;
        *p = s;
        
@@ -766,7 +881,7 @@ mDNSlocal uDNS_AuthInfo *GetAuthInfoForZone(const uDNS_GlobalInfo *u, const doma
                zone = (const domainname *)(zone->c + 1 + zone->c[0]);
                }
        return mDNSNULL;
-       }       
+       }
 
 mDNSlocal void DeleteAuthInfoForZone(uDNS_GlobalInfo *u, const domainname *zone)
        {
@@ -785,7 +900,7 @@ mDNSlocal void DeleteAuthInfoForZone(uDNS_GlobalInfo *u, const domainname *zone)
                }
        }
 
-mDNSexport mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const mDNSu8 *sharedSecret, mDNSu32 ssLen, mDNSBool base64)
+mDNSexport mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const domainname *key, const char *sharedSecret, mDNSu32 ssLen, mDNSBool base64)
        {
        uDNS_AuthInfo *info;
        mDNSu8 keybuf[1024];
@@ -801,22 +916,22 @@ mDNSexport mStatus mDNS_SetSecretForZone(mDNS *m, const domainname *zone, const
        info = (uDNS_AuthInfo*)umalloc(sizeof(uDNS_AuthInfo) + ssLen);
        if (!info) { LogMsg("ERROR: umalloc"); status = mStatus_NoMemoryErr; goto exit; }
        ubzero(info, sizeof(uDNS_AuthInfo));
-       AssignDomainName(info->zone, *zone);
-       AssignDomainName(info->keyname, *key);
+       AssignDomainName(&info->zone, zone);
+       AssignDomainName(&info->keyname, key);
 
        if (base64)
                {
-               keylen = DNSDigest_Base64ToBin((const char*)sharedSecret, keybuf, 1024);
+               keylen = DNSDigest_Base64ToBin(sharedSecret, keybuf, 1024);
                if (keylen < 0)
                        {
                        LogMsg("ERROR: mDNS_UpdateDomainRequiresAuthentication - could not convert shared secret from base64");
                        ufree(info);
                        status = mStatus_UnknownErr;
                        goto exit;
-                       }               
-               DNSDigest_ConstructHMACKey(info, keybuf, (mDNSu32)keylen);              
+                       }
+               DNSDigest_ConstructHMACKey(info, keybuf, (mDNSu32)keylen);
                }
-       else DNSDigest_ConstructHMACKey(info, sharedSecret, ssLen);
+       else DNSDigest_ConstructHMACKey(info, (mDNSu8*)sharedSecret, ssLen);
 
     // link into list
        info->next = m->uDNS_info.AuthInfoList;
@@ -831,17 +946,6 @@ exit:
 #pragma mark - NAT Traversal
 #endif
 
-mDNSlocal mDNSBool MapServicePort(mDNS *m)
-       {
-       uDNS_HostnameInfo *i;
-
-       //!!!KRS this could be cached
-       for (i = m->uDNS_info.Hostnames; i; i= i->next)
-               if (i->ar->uDNS_info.NATinfo && i->ar->uDNS_info.NATinfo->state != NATState_Error) return mDNStrue;
-       
-       return mDNSfalse;
-       }
-
 mDNSlocal mDNSBool DomainContainsLabelString(const domainname *d, const char *str)
        {
        const domainlabel *l;
@@ -868,6 +972,7 @@ mDNSlocal NATTraversalInfo *AllocNATInfo(mDNS *const m, NATOp_t op, NATResponseH
        info->state = NATState_Init;
        info->ReceiveResponse = callback;
        info->PublicPort.NotAnInteger = 0;
+       info->Router = u->Router;
        return info;
        }
 
@@ -875,6 +980,18 @@ mDNSlocal NATTraversalInfo *AllocNATInfo(mDNS *const m, NATOp_t op, NATResponseH
 mDNSlocal mDNSBool FreeNATInfo(mDNS *m, NATTraversalInfo *n)
        {
        NATTraversalInfo *ptr, *prev = mDNSNULL;
+       ServiceRecordSet *s = m->uDNS_info.ServiceRegistrations;
+
+       // Verify that object is not referenced by any services
+       while (s)
+               {
+               if (s->uDNS_info.NATinfo == n)
+                       {
+                       LogMsg("Error: Freeing NAT info object still referenced by Service Record Set %##s!", s->RR_SRV.resrec.name->c);
+                       s->uDNS_info.NATinfo = mDNSNULL;
+                       }
+               s = s->next;
+               }
        
        if (n == m->uDNS_info.LLQNatInfo) m->uDNS_info.LLQNatInfo = mDNSNULL;
        ptr = m->uDNS_info.NATTraversals;
@@ -907,10 +1024,14 @@ mDNSlocal void SendNATMsg(NATTraversalInfo *info, mDNS *m)
        if (u->Router.ip.v4.NotAnInteger)
                {
                // send msg     if we have a router
+               const mDNSu8 *end = (mDNSu8 *)&info->request;
+               if (info->op == NATOp_AddrRequest) end += sizeof(NATAddrRequest);
+               else end += sizeof(NATPortMapRequest);
                dst.type = u->Router.type;
                dst.ip.v4 = u->Router.ip.v4;
                dstport = mDNSOpaque16fromIntVal(NATMAP_PORT);
-               err = mDNSPlatformSendUDP(m, info->request, info->request+info->requestlen, 0, &dst, dstport);
+               err = mDNSPlatformSendUDP(m, &info->request, end, 0, &dst, dstport);
                if (!err) (info->ntries++);  // don't increment attempt counter if the send failed
                }
        
@@ -923,10 +1044,10 @@ mDNSlocal void SendNATMsg(NATTraversalInfo *info, mDNS *m)
 
 mDNSlocal void ReceiveNATAddrResponse(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
        {
-       NATErr_t NatErr = NATErr_None;
        mStatus err = mStatus_NoError;
        AuthRecord *rr = mDNSNULL;
-       mDNSAddr addr; 
+       NATAddrReply *response = (NATAddrReply *)pkt;
+       mDNSAddr addr;
 
        if (n->state != NATState_Request)
                {
@@ -960,38 +1081,35 @@ mDNSlocal void ReceiveNATAddrResponse(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt,
                }
        else
                {
-               if (len < ADDR_REPLY_PKTLEN)
+               if (len < sizeof(*response))
                        {
                        LogMsg("ReceiveNATAddrResponse: response too short (%d bytes)", len);
                        err = mStatus_NATTraversal;
                        goto end;
                        }
-               if (pkt[0] != NATMAP_VERS)
+               if (response->vers != NATMAP_VERS)
                        {
                        LogMsg("ReceiveNATAddrResponse: received  version %d (expect version %d)", pkt[0], NATMAP_VERS);
                        err = mStatus_NATTraversal;
                        goto end;
                        }
-               if (pkt[1] != (NATOp_AddrRequest | NATMAP_RESPONSE_MASK))
+               if (response->opcode != (NATOp_AddrRequest | NATMAP_RESPONSE_MASK))
                        {
-                       LogMsg("ReceiveNATAddrResponse: bad response code %d", pkt[1]);
+                       LogMsg("ReceiveNATAddrResponse: bad response code %d", response->opcode);
                        err = mStatus_NATTraversal;
                        goto end;
                        }
-               NatErr = (NATErr_t)((NATErr_t)pkt[2] << 8 | (NATErr_t)pkt[3]);
-               if (NatErr) { LogMsg("ReceiveAddrResponse: received error %d", err); err = mStatus_NATTraversal; goto end; }
-               
-               addr.ip.v4.b[0] = pkt[4];
-               addr.ip.v4.b[1] = pkt[5];
-               addr.ip.v4.b[2] = pkt[6];
-               addr.ip.v4.b[3] = pkt[7];
+               if (response->err.NotAnInteger)
+                       { LogMsg("ReceiveAddrResponse: received error %d", mDNSVal16(response->err)); err = mStatus_NATTraversal; goto end; }
+
+               addr.ip.v4 = response->PubAddr;
                n->state = NATState_Established;
                }
        
        if (IsPrivateV4Addr(&addr))
                {
                LogMsg("ReceiveNATAddrResponse: Double NAT");
-               err = mStatus_DblNAT;
+               err = mStatus_DoubleNAT;
                goto end;
                }
        
@@ -1008,7 +1126,7 @@ mDNSlocal void ReceiveNATAddrResponse(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt,
                        }
                return;
                }
-       else LogMsg("Received public IP address %d.%d.%d.%d from NAT.", addr.ip.v4.b[0], addr.ip.v4.b[1], addr.ip.v4.b[2], addr.ip.v4.b[3]);    
+       else LogMsg("Received public IP address %d.%d.%d.%d from NAT.", addr.ip.v4.b[0], addr.ip.v4.b[1], addr.ip.v4.b[2], addr.ip.v4.b[3]);
        rr->resrec.rdata->u.ipv4 = addr.ip.v4;  // replace rdata w/ public address
        uDNS_RegisterRecord(m, rr);
        }
@@ -1016,20 +1134,19 @@ mDNSlocal void ReceiveNATAddrResponse(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt,
 
 mDNSlocal void StartGetPublicAddr(mDNS *m, uDNS_HostnameInfo *hInfo)
        {
-       mDNSu8 *msg;
+       NATAddrRequest *req;
        uDNS_GlobalInfo *u = &m->uDNS_info;
        
        NATTraversalInfo *info = AllocNATInfo(m, NATOp_AddrRequest, ReceiveNATAddrResponse);
-       if (!info) { uDNS_RegisterRecord(m, hInfo->ar); return; } 
+       if (!info) { uDNS_RegisterRecord(m, hInfo->ar); return; }
        hInfo->ar->uDNS_info.NATinfo = info;
        info->reg.RecordRegistration = hInfo->ar;
        info->state = NATState_Request;
        
     // format message
-       msg = info->request;
-       msg[0] = NATMAP_VERS;
-       msg[1] = NATOp_AddrRequest;
-       info->requestlen = ADDR_REQUEST_PKTLEN; 
+       req = &info->request.AddrReq;
+       req->vers = NATMAP_VERS;
+       req->opcode = NATOp_AddrRequest;
        
        if (!u->Router.ip.v4.NotAnInteger)
                {
@@ -1075,23 +1192,23 @@ mDNSlocal void LLQNatMapComplete(mDNS *m)
                                llqInfo->question->LastQTime = mDNSPlatformTimeNow(m) - (2 * INIT_UCAST_POLL_INTERVAL);  // trigger immediate poll
                                llqInfo->question->ThisQInterval = INIT_UCAST_POLL_INTERVAL;
                                }
-                       else { llqInfo->state = LLQ_GetZoneInfo; startLLQHandshake(m, llqInfo, mDNSfalse); }    
+                       else { llqInfo->state = LLQ_GetZoneInfo; startLLQHandshake(m, llqInfo, mDNSfalse); }
                        }
                }
        }
 
 mDNSlocal void ReceivePortMapReply(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mDNSu16 len)
        {
-       NATErr_t err;
        ServiceRecordSet *srs;
-       mDNSIPPort priv, pktpriv, pub;
+       mDNSIPPort priv;
        mDNSu32 lease;
        mDNSBool deletion;
+       NATPortMapReply *reply = (NATPortMapReply *)pkt;
        
        if (n->state != NATState_Request && n->state != NATState_Refresh)
                { LogMsg("ReceivePortMapReply: bad state %d", n->state);  return; }
 
-       deletion = !(n->request[8] |  n->request[9] | n->request[10] | n->request[11]);  // zero lease
+       deletion = (!n->request.PortReq.lease.NotAnInteger);
        if (deletion) { n->state = NATState_Deleted; return; }
        // note that we explicitly ignore timeouts here
        // we keep the context struct around so that the SendServiceDeregistration code can reference
@@ -1110,9 +1227,10 @@ mDNSlocal void ReceivePortMapReply(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mD
        if (!pkt) // timeout
                {
 #ifdef _LEGACY_NAT_TRAVERSAL_
+               mDNSIPPort pub;
                int ntries = 0;
                mStatus err;
-               mDNSBool tcp = (srs && DomainContainsLabelString(&srs->RR_PTR.resrec.name, "_tcp"));
+               mDNSBool tcp = (srs && DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp"));
           
                pub = priv; // initially request priv == pub
                while (1)
@@ -1141,30 +1259,22 @@ mDNSlocal void ReceivePortMapReply(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mD
 #endif // _LEGACY_NAT_TRAVERSAL_
                }
 
-       if (len < PORTMAP_PKTLEN) { LogMsg("ReceivePortMapReply: response too short (%d bytes)", len); goto end; }
-       if (pkt[0] != NATMAP_VERS) { LogMsg("ReceivePortMapReply: received  version %d (expect version %d)", pkt[0], NATMAP_VERS);  goto end; }
-       if (pkt[1] != (n->op | NATMAP_RESPONSE_MASK)) { LogMsg("ReceivePortMapReply: bad response code %d", pkt[1]); goto end; }
-       err = (NATErr_t)((NATErr_t)pkt[2] << 8 | (NATErr_t)pkt[3]);
-       if (err) { LogMsg("ReceivePortMapReply: received error %d", err);  goto end; }
-
-       pktpriv.b[0] = pkt[4];
-       pktpriv.b[1] = pkt[5];
-       pub.b[0]  = pkt[6];
-       pub.b[1]  = pkt[7];
+       if (len < sizeof(*reply)) { LogMsg("ReceivePortMapReply: response too short (%d bytes)", len); goto end; }
+       if (reply->vers != NATMAP_VERS) { LogMsg("ReceivePortMapReply: received  version %d (expect version %d)", pkt[0], NATMAP_VERS);  goto end; }
+       if (reply->opcode != (n->op | NATMAP_RESPONSE_MASK)) { LogMsg("ReceivePortMapReply: bad response code %d", pkt[1]); goto end; }
+       if (reply->err.NotAnInteger) { LogMsg("ReceivePortMapReply: received error %d", mDNSVal16(reply->err));  goto end; }
+       if (priv.NotAnInteger != reply->priv.NotAnInteger)
+               { LogMsg("ReceivePortMapReply: reply private port does not match requested private port");  goto end; }
 
-       lease = (mDNSu32) ((mDNSu32)pkt[8] << 24 | (mDNSu32)pkt[9] << 16 | (mDNSu32)pkt[10] << 8 | pkt[11]);
-       if (lease > 0x70000000UL / mDNSPlatformOneSecond)
-               lease = 0x70000000UL / mDNSPlatformOneSecond;
+       lease = (mDNSu32)mDNSVal32(reply->lease);
+       if (lease > 0x70000000UL / mDNSPlatformOneSecond) lease = 0x70000000UL / mDNSPlatformOneSecond;
 
-       if (priv.NotAnInteger != pktpriv.NotAnInteger)
-               { LogMsg("ReceivePortMapReply: reply private port does not match requested private port");  goto end; }
-       
-       if (n->state == NATState_Refresh && pub.NotAnInteger != n->PublicPort.NotAnInteger)                                     
-               LogMsg("ReceivePortMapReply: NAT refresh changed public port from %d to %d", mDNSVal16(n->PublicPort), mDNSVal16(pub));
+               if (n->state == NATState_Refresh && reply->pub.NotAnInteger != n->PublicPort.NotAnInteger)
+               LogMsg("ReceivePortMapReply: NAT refresh changed public port from %d to %d", mDNSVal16(n->PublicPort), mDNSVal16(reply->pub));
        // !!!KRS we need to update the SRV here!
-       n->PublicPort = pub;
+               n->PublicPort = reply->pub;
 
-       n->retry = mDNSPlatformTimeNow(m) + ((mDNSs32)lease * mDNSPlatformOneSecond/2);  // retry half way to expiration
+       n->retry = mDNSPlatformTimeNow(m) + ((mDNSs32)lease * mDNSPlatformOneSecond / 2);  // retry half way to expiration
        
        if (n->state == NATState_Refresh) { n->state = NATState_Established; return; }
        n->state = NATState_Established;
@@ -1174,39 +1284,32 @@ mDNSlocal void ReceivePortMapReply(NATTraversalInfo *n, mDNS *m, mDNSu8 *pkt, mD
                {
                LogMsg("NAT Port Mapping: timeout");
                n->state = NATState_Error;
-               if (!srs) { LLQNatMapComplete(m); return; }
-               FreeNATInfo(m, n);
-               srs->uDNS_info.NATinfo = mDNSNULL;
-               unlinkSRS(&m->uDNS_info, srs);
-               srs->uDNS_info.state = regState_Unregistered;
-               srs->ServiceCallback(m, srs, mStatus_NATTraversal);
+               if (srs) srs->uDNS_info.state = regState_NATError;
+               else LLQNatMapComplete(m);
                return;  // note - unsafe to touch srs here
                }
 
        LogMsg("Mapped private port %d to public port %d", mDNSVal16(priv), mDNSVal16(n->PublicPort));
        if (!srs) { LLQNatMapComplete(m); return; }
-       srs->uDNS_info.state = regState_FetchingZoneData;
-       startGetZoneData(&srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
+
+       if (srs->uDNS_info.ns.ip.v4.NotAnInteger) SendServiceRegistration(m, srs);  // non-zero server address means we already have necessary zone data to send update
+       else
+               {       
+               srs->uDNS_info.state = regState_FetchingZoneData;
+               startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
+               }
        }
 
 mDNSlocal void FormatPortMaprequest(NATTraversalInfo *info, mDNSIPPort port)
        {
-       mDNSu8 *msg = info->request;
-       mDNSOpaque32 lease = mDNSOpaque32fromIntVal(NATMAP_DEFAULT_LEASE);
-       
-       msg[0] = NATMAP_VERS;
-       msg[1] = info->op;
-       msg[2] = 0; // reserved
-       msg[3] = 0; // reserved
-       msg[4] = port.b[0];  // private port
-       msg[5] = port.b[1];
-       msg[6] = port.b[0];  // requested pub. port
-       msg[7] = port.b[1];
-       
-       msg[8]  = lease.b[0];
-       msg[9]  = lease.b[1];
-       msg[10] = lease.b[2];
-       msg[11] = lease.b[3];
+       NATPortMapRequest *req = &info->request.PortReq;
+
+       req->vers = NATMAP_VERS;
+       req->opcode = info->op;
+       req->unused.NotAnInteger = 0;
+       req->priv = port;
+       req->pub = port;
+       req->lease = mDNSOpaque32fromIntVal(NATMAP_DEFAULT_LEASE);
        }
 
 mDNSlocal void SendInitialPMapReq(mDNS *m, NATTraversalInfo *info)
@@ -1227,22 +1330,22 @@ mDNSlocal void StartNATPortMap(mDNS *m, ServiceRecordSet *srs)
        NATOp_t op;
        NATTraversalInfo *info;
 
-       if (DomainContainsLabelString(&srs->RR_PTR.resrec.name, "_tcp")) op = NATOp_MapTCP;
-       else if (DomainContainsLabelString(&srs->RR_PTR.resrec.name, "_udp")) op = NATOp_MapUDP;
-       else { LogMsg("StartNATPortMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name.c); goto error; }
+       if (DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp")) op = NATOp_MapTCP;
+       else if (DomainContainsLabelString(srs->RR_PTR.resrec.name, "_udp")) op = NATOp_MapUDP;
+       else { LogMsg("StartNATPortMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name->c); goto error; }
 
+       if (srs->uDNS_info.NATinfo) { LogMsg("Error: StartNATPortMap - NAT info already initialized!");  FreeNATInfo(m, srs->uDNS_info.NATinfo); }
        info = AllocNATInfo(m, op, ReceivePortMapReply);
        srs->uDNS_info.NATinfo = info;
        info->reg.ServiceRegistration = srs;
        info->state = NATState_Request;
-       info->requestlen = PORTMAP_PKTLEN;
        
        FormatPortMaprequest(info, srs->RR_SRV.resrec.rdata->u.srv.port);
        SendInitialPMapReq(m, info);
        return;
        
        error:
-       startGetZoneData(&srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
+       startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
        }
 
 mDNSlocal void DeleteNATPortMapping(mDNS *m, NATTraversalInfo *nat, ServiceRecordSet *srs)
@@ -1250,18 +1353,15 @@ mDNSlocal void DeleteNATPortMapping(mDNS *m, NATTraversalInfo *nat, ServiceRecor
        if (nat->state == NATState_Established)  // let other edge-case states expire for simplicity
                {
                // zero lease
-               nat->request[8]  = 0;
-               nat->request[9]  = 0;
-               nat->request[10] = 0 ;
-               nat->request[11] = 0;
+               nat->request.PortReq.lease.NotAnInteger = 0;
                nat->state = NATState_Request;
-               SendNATMsg(nat, m); 
+               SendNATMsg(nat, m);
                }
 #ifdef _LEGACY_NAT_TRAVERSAL_
        else if (nat->state == NATState_Legacy)
                {
                mStatus err = mStatus_NoError;
-               mDNSBool tcp = srs ? DomainContainsLabelString(&srs->RR_PTR.resrec.name, "_tcp") : mDNSfalse;
+               mDNSBool tcp = srs ? DomainContainsLabelString(srs->RR_PTR.resrec.name, "_tcp") : mDNSfalse;
                err = LNT_UnmapPort(nat->PublicPort, tcp);
                if (err) LogMsg("Legacy NAT Traversal - unmap request failed with error %ld", err);
                }
@@ -1277,10 +1377,9 @@ mDNSlocal void StartLLQNatMap(mDNS *m)
        
        u->LLQNatInfo = info;
 
-       info->reg.RecordRegistration = mDNSNULL;        
+       info->reg.RecordRegistration = mDNSNULL;
        info->reg.ServiceRegistration = mDNSNULL;
     info->state = NATState_Request;
-       info->requestlen = PORTMAP_PKTLEN;
        FormatPortMaprequest(info, m->UnicastPort4);
     SendInitialPMapReq(m, info);
        return;
@@ -1319,23 +1418,51 @@ mDNSlocal mDNSBool GetServiceTarget(uDNS_GlobalInfo *u, AuthRecord *srv, domainn
        while (hi)
                {
                if (hi->ar->uDNS_info.state == regState_Registered || hi->ar->uDNS_info.state == regState_Refresh)
-                       { AssignDomainName(*dst, hi->ar->resrec.name); return mDNStrue; }
+                       { AssignDomainName(dst, hi->ar->resrec.name); return mDNStrue; }
                hi = hi->next;
                }
 
-       if (u->StaticHostname.c[0]) { AssignDomainName(*dst, u->StaticHostname); return mDNStrue; }
+       if (u->StaticHostname.c[0]) { AssignDomainName(dst, &u->StaticHostname); return mDNStrue; }
        return mDNSfalse;
        }
 
 mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
-       {       
+       {
        uDNS_GlobalInfo *u = &m->uDNS_info;
        ExtraResourceRecord *e;
+
+       // Target change if:
+       // We have a target and were previously waiting for one, or
+       // We had a target and no longer do, or
+       // The target has changed
+
        domainname newtarget;
        domainname *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target;
-       mDNSBool havetarget = GetServiceTarget(u, &srs->RR_SRV, &newtarget);
+       mDNSBool HaveTarget = GetServiceTarget(u, &srs->RR_SRV, &newtarget);
+       mDNSBool TargetChanged = (HaveTarget && srs->uDNS_info.state == regState_NoTarget) || (curtarget->c[0] && !HaveTarget) || !SameDomainName(curtarget, &newtarget);
+       mDNSBool HaveZoneData = srs->uDNS_info.ns.ip.v4.NotAnInteger ? mDNStrue : mDNSfalse;
        
-       if ((!havetarget && srs->uDNS_info.state == regState_NoTarget) || (havetarget && SameDomainName(curtarget, &newtarget))) return;  // target unchanged
+       // Nat state change if:
+       // We were behind a NAT, and now we are behind a new NAT, or
+       // We're not behind a NAT but our port was previously mapped to a different public port
+       // We were not behind a NAT and now we are
+       
+       NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
+       mDNSIPPort port = srs->RR_SRV.resrec.rdata->u.srv.port;
+       mDNSBool NATChanged = mDNSfalse;
+       mDNSBool NowBehindNAT = port.NotAnInteger && IsPrivateV4Addr(&u->PrimaryIP);
+       mDNSBool WereBehindNAT = nat != mDNSNULL;
+       mDNSBool NATRouterChanged = nat && nat->Router.ip.v4.NotAnInteger != u->Router.ip.v4.NotAnInteger;
+       mDNSBool PortWasMapped = nat && (nat->state == NATState_Established || nat->state == NATState_Legacy) && nat->PublicPort.NotAnInteger != port.NotAnInteger;
+       
+       if (WereBehindNAT && NowBehindNAT && NATRouterChanged) NATChanged = mDNStrue;
+       else if (!NowBehindNAT && PortWasMapped)               NATChanged = mDNStrue;
+       else if (!WereBehindNAT && NowBehindNAT)               NATChanged = mDNStrue;
+       
+       if (!TargetChanged && !NATChanged) return;
+
+       debugf("UpdateSRV (%##s) HadZoneData=%d, TargetChanged=%d, HaveTarget=%d, NowBehindNAT=%d, WereBehindNAT=%d, NATRouterChanged=%d, PortWasMapped=%d",
+                  srs->RR_SRV.resrec.name->c,  HaveZoneData, TargetChanged, HaveTarget, NowBehindNAT, WereBehindNAT, NATRouterChanged, PortWasMapped); 
        
        switch(srs->uDNS_info.state)
                {
@@ -1356,18 +1483,34 @@ mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
                        // let the in-flight operation complete before updating
                        srs->uDNS_info.SRVUpdateDeferred = mDNStrue;
                        return;
-                       
+                                               
+               case regState_NATError:
+                       if (!NATChanged) return;
+                       // if nat changed, register if we have a target (below)
+
                case regState_NoTarget:
-                       // Service has not been registered due to lack of a target hostname
-                       if (havetarget) SendServiceRegistration(m, srs);
+                       if (HaveTarget)
+                               {
+                               debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowBehindNAT ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c);      
+                               if (!HaveZoneData)
+                                       {
+                                       srs->uDNS_info.state = regState_FetchingZoneData;
+                                       startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
+                                       }
+                               else
+                                       {
+                                       if (nat && (NATChanged || !NowBehindNAT)) { srs->uDNS_info.NATinfo = mDNSNULL; FreeNATInfo(m, nat); }
+                                       if (NATChanged && NowBehindNAT) { srs->uDNS_info.state = regState_NATMap; StartNATPortMap(m, srs); }
+                                       else SendServiceRegistration(m, srs);
+                                       }
+                               }
                        return;
                        
                case regState_Registered:
-                       // target lost or changed.  deregister service.  upon completion, we'll look for a new target
-                       // extra will be re-registed if the service is re-registered
-                       for (e = srs->Extras; e; e = e->next) e->r.uDNS_info.state = regState_ExtraQueued;
-                       
-                       srs->uDNS_info.LostTarget = mDNStrue;
+                       // target or nat changed.  deregister service.  upon completion, we'll look for a new target
+                       debugf("UpdateSRV: SRV record changed for service %##s - deregistering (will re-register with new SRV)",  srs->RR_SRV.resrec.name->c);
+                       for (e = srs->Extras; e; e = e->next) e->r.uDNS_info.state = regState_ExtraQueued;  // extra will be re-registed if the service is re-registered
+                       srs->uDNS_info.SRVChanged = mDNStrue;
                        SendServiceDeregistration(m, srs);
                        return;
                }
@@ -1387,35 +1530,19 @@ mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus res
        
        if (result == mStatus_MemFree)
                {
-               debugf("MemFree:  %##s IP %d.%d.%d.%d", rr->resrec.name.c, ip[0], ip[1], ip[2], ip[3]);
+               debugf("MemFree:  %##s IP %d.%d.%d.%d", rr->resrec.name->c, ip[0], ip[1], ip[2], ip[3]);
                if (hi) ufree(hi);
-               ufree(rr);        
-               return;
-               }
-       
-       if (result == mStatus_NameConflict && rr->resrec.RecordType == kDNSRecordTypeUnique)
-               {
-               // if we get a name conflict, make sure our name/addr isn't already registered by re-registering
-               debugf("Name in use - retrying as type KnownUnique");
-               rr->resrec.RecordType = kDNSRecordTypeKnownUnique;
-               uDNS_RegisterRecord(m, rr);
+               ufree(rr);
                return;
                }
        
-       if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
-               {
-               // we've already tried to re-register.  reset RecordType before returning RR to client
-               if (result == mStatus_NoSuchRecord)  // name is advertised for some other address
-                       result = mStatus_NameConflict;
-               }
-       
        if (result)
                {
                // don't unlink or free - we can retry when we get a new address/router
-               LogMsg("HostnameCallback: Error %ld for registration of %##s IP %d.%d.%d.%d", result, rr->resrec.name.c, ip[0], ip[1], ip[2], ip[3]);
+               LogMsg("HostnameCallback: Error %ld for registration of %##s IP %d.%d.%d.%d", result, rr->resrec.name->c, ip[0], ip[1], ip[2], ip[3]);
                if (!hi) { ufree(rr); return; }
                if (hi->ar->uDNS_info.state != regState_Unregistered) LogMsg("Error: HostnameCallback invoked with error code for record not in regState_Unregistered!");
-               (const void *)rr->RecordContext = hi->StatusContext;
+               rr->RecordContext = (void *)hi->StatusContext;
                if (hi->StatusCallback)
                        hi->StatusCallback(m, rr, result); // client may NOT make API calls here
                rr->RecordContext = (void *)hi;
@@ -1427,8 +1554,8 @@ mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus res
        
        // Deliver success to client
        if (!hi) { LogMsg("HostnameCallback invoked with orphaned address record"); return; }
-       LogMsg("Registered hostname %##s IP %d.%d.%d.%d", rr->resrec.name.c, ip[0], ip[1], ip[2], ip[3]);       
-       (const void *)rr->RecordContext = hi->StatusContext;
+       LogMsg("Registered hostname %##s IP %d.%d.%d.%d", rr->resrec.name->c, ip[0], ip[1], ip[2], ip[3]);
+       rr->RecordContext = (void *)hi->StatusContext;
        if (hi->StatusCallback)
                hi->StatusCallback(m, rr, result); // client may NOT make API calls here
        rr->RecordContext = (void *)hi;
@@ -1437,13 +1564,13 @@ mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus res
 // register record or begin NAT traversal
 mDNSlocal void AdvertiseHostname(mDNS *m, uDNS_HostnameInfo *h)
        {
-       if (IsPrivateV4Addr(&m->uDNS_info.PrimaryIP)) 
+       if (IsPrivateV4Addr(&m->uDNS_info.PrimaryIP))
                StartGetPublicAddr(m, h);
-       else 
+       else
          {
          mDNSu8 *ip = m->uDNS_info.PrimaryIP.ip.v4.b;
-         LogMsg("Advertising %##s IP %d.%d.%d.%d", h->ar->resrec.name.c, ip[0], ip[1], ip[2], ip[3]);
-         uDNS_RegisterRecord(m, h->ar); 
+         LogMsg("Advertising %##s IP %d.%d.%d.%d", h->ar->resrec.name->c, ip[0], ip[1], ip[2], ip[3]);
+         uDNS_RegisterRecord(m, h->ar);
          }
        }
 
@@ -1451,12 +1578,25 @@ mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const R
        {
        const domainname *pktname = &answer->rdata->u.name;
        domainname *storedname = &m->uDNS_info.StaticHostname;
+       uDNS_HostnameInfo *h = m->uDNS_info.Hostnames;
+
        (void)question;
        
        debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed");
        if (AddRecord && !SameDomainName(pktname, storedname))
                {
-               AssignDomainName(*storedname, *pktname);
+               AssignDomainName(storedname, pktname);
+               while (h)
+                       {
+                       if (h->ar && (h->ar->uDNS_info.state == regState_FetchingZoneData || h->ar->uDNS_info.state == regState_Pending || h->ar->uDNS_info.state == regState_NATMap))
+                               {
+                               // if we're in the process of registering a dynamic hostname, delay SRV update so we don't have to reregister services if the dynamic name succeeds
+                               m->uDNS_info.DelaySRVUpdate = mDNStrue;
+                               m->uDNS_info.NextSRVUpdate = mDNSPlatformTimeNow(m) + (5 * mDNSPlatformOneSecond);
+                               return;
+                               }
+                       h = h->next;
+                       }
                UpdateSRVRecords(m);
                }
        else if (!AddRecord && SameDomainName(pktname, storedname))
@@ -1472,8 +1612,6 @@ mDNSlocal void GetStaticHostname(mDNS *m)
        DNSQuestion *q = &m->uDNS_info.ReverseMap;
        mDNSu8 *ip = m->uDNS_info.PrimaryIP.ip.v4.b;
        mStatus err;
-
-       ubzero(q, sizeof(*q));
        
        if (m->uDNS_info.ReverseMapActive)
                {
@@ -1481,11 +1619,13 @@ mDNSlocal void GetStaticHostname(mDNS *m)
                m->uDNS_info.ReverseMapActive = mDNSfalse;
                }
 
+       m->uDNS_info.StaticHostname.c[0] = 0;
        if (!m->uDNS_info.PrimaryIP.ip.v4.NotAnInteger) return;
+       ubzero(q, sizeof(*q));
        mDNS_snprintf(buf, MAX_ESCAPED_DOMAIN_NAME, "%d.%d.%d.%d.in-addr.arpa.", ip[3], ip[2], ip[1], ip[0]);
-    if (!MakeDomainNameFromDNSNameString(&q->qname, buf)) { LogMsg("Error: GetStaticHostname - bad name %s", buf); return; }   
+    if (!MakeDomainNameFromDNSNameString(&q->qname, buf)) { LogMsg("Error: GetStaticHostname - bad name %s", buf); return; }
 
-       q->InterfaceID       = mDNSInterface_Any;
+       q->InterfaceID      = mDNSInterface_Any;
     q->Target           = zeroAddr;
     q->qtype            = kDNSType_PTR;
     q->qclass           = kDNSClass_IN;
@@ -1500,11 +1640,11 @@ mDNSlocal void GetStaticHostname(mDNS *m)
        else m->uDNS_info.ReverseMapActive = mDNStrue;
        }
 
-// Deregister hostnames and  register new names for each host domain with the current global 
+// Deregister hostnames and  register new names for each host domain with the current global
 // values for the hostlabel and primary IP address
 mDNSlocal void UpdateHostnameRegistrations(mDNS *m)
        {
-       uDNS_GlobalInfo *u = &m->uDNS_info;     
+       uDNS_GlobalInfo *u = &m->uDNS_info;
        AuthRecord *new;
        uDNS_HostnameInfo *i;
 
@@ -1516,7 +1656,7 @@ mDNSlocal void UpdateHostnameRegistrations(mDNS *m)
                        {
                        new = umalloc(sizeof(AuthRecord));
                        if (!new) { LogMsg("ERROR: UpdateHostnameRegistration - malloc"); return; }
-                       mDNS_SetupResourceRecord(new, mDNSNULL, 0, kDNSType_A,  1, kDNSRecordTypeUnique, HostnameCallback, i);
+                       mDNS_SetupResourceRecord(new, mDNSNULL, 0, kDNSType_A, kWideAreaTTL, kDNSRecordTypeKnownUnique, HostnameCallback, i);
                        }
 
                // setup new record
@@ -1524,16 +1664,16 @@ mDNSlocal void UpdateHostnameRegistrations(mDNS *m)
                new->resrec.rdata->u.ipv4 = u->PrimaryIP.ip.v4;
 
                if (i->ar->uDNS_info.state != regState_Unregistered)
-                       {                       
+                       {
                        // delete old record
                        i->ar->RecordContext = mDNSNULL;  // clear backpointer to HostnameInfo
-                       uDNS_DeregisterRecord(m, i->ar);  
+                       uDNS_DeregisterRecord(m, i->ar);
                        i->ar = new;
                        }
                
                // advertise new
                AdvertiseHostname(m, i);
-               }       
+               }
        }
 
 mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
@@ -1546,7 +1686,7 @@ mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSReco
        // check if domain already registered
        for (ptr = u->Hostnames; ptr; ptr = ptr->next)
                {
-               if (SameDomainName(fqdn, &ptr->ar->resrec.name))
+               if (SameDomainName(fqdn, ptr->ar->resrec.name))
                        { LogMsg("Host Domain %##s already in list", fqdn->c); goto exit; }
                }
 
@@ -1556,8 +1696,8 @@ mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSReco
        if (!new || !new->ar) { LogMsg("ERROR: mDNS_AddDynDNSHostname - malloc"); goto exit; }
        new->StatusCallback = StatusCallback;
        new->StatusContext = StatusContext;
-       mDNS_SetupResourceRecord(new->ar, mDNSNULL, 0, kDNSType_A,  1, kDNSRecordTypeUnique, HostnameCallback, new);    
-       AppendDomainName(&new->ar->resrec.name, fqdn);
+       mDNS_SetupResourceRecord(new->ar, mDNSNULL, 0, kDNSType_A,  1, kDNSRecordTypeKnownUnique, HostnameCallback, new);
+       AppendDomainName(new->ar->resrec.name, fqdn);
        new->next = u->Hostnames;
        u->Hostnames = new;
        if (u->PrimaryIP.ip.v4.NotAnInteger)
@@ -1579,13 +1719,13 @@ mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
 
        mDNS_Lock(m);
 
-       while (*ptr && !SameDomainName(fqdn, &(*ptr)->ar->resrec.name)) ptr = &(*ptr)->next;
-       if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c);               
+       while (*ptr && !SameDomainName(fqdn, (*ptr)->ar->resrec.name)) ptr = &(*ptr)->next;
+       if (!*ptr) LogMsg("mDNS_RemoveDynDNSHostName: no such domainname %##s", fqdn->c);
        else
                {
                uDNS_HostnameInfo *hi = *ptr;
                *ptr = (*ptr)->next; // unlink
-               hi->ar->RecordContext = mDNSNULL; // about to free wrapper struct               
+               hi->ar->RecordContext = mDNSNULL; // about to free wrapper struct
                if (hi->ar->uDNS_info.state != regState_Unregistered) uDNS_DeregisterRecord(m, hi->ar);
                else { ufree(hi->ar); hi->ar = mDNSNULL; }
                ufree(hi);
@@ -1603,8 +1743,8 @@ mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *addr, cons
        if (router && router->type !=mDNSAddrType_IPv4) { LogMsg("mDNS_SetPrimaryInterfaceInfo passed non-V4 address.  Discarding."); return; }
        mDNS_Lock(m);
 
-       AddrChanged = addr ? (addr->ip.v4.NotAnInteger != u->PrimaryIP.ip.v4.NotAnInteger) : u->PrimaryIP.ip.v4.NotAnInteger;
-       RouterChanged = router ? (router->ip.v4.NotAnInteger != u->Router.ip.v4.NotAnInteger) : u->Router.ip.v4.NotAnInteger;
+       AddrChanged   = ((addr   ? addr  ->ip.v4.NotAnInteger : 0) != u->PrimaryIP.ip.v4.NotAnInteger);
+       RouterChanged = ((router ? router->ip.v4.NotAnInteger : 0) != u->Router   .ip.v4.NotAnInteger);
        
 #if MDNS_DEBUGMSGS
        if (addr && (AddrChanged || RouterChanged))
@@ -1617,13 +1757,10 @@ mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *addr, cons
        if (router) u->Router = *router;
        else        u->Router.ip.v4.NotAnInteger = 0; // setting router to zero indicates that nat mappings must be reestablished when router is reset
        
-       if (AddrChanged)
+       if ((AddrChanged || RouterChanged ) && (addr && router))
                {
-               if (addr)
-                       {
-                       UpdateHostnameRegistrations(m);
-                       UpdateSRVRecords(m);
-                       }
+               UpdateHostnameRegistrations(m);
+               UpdateSRVRecords(m);
                GetStaticHostname(m);  // look up reverse map record to find any static hostnames for our IP address
                }
        
@@ -1668,7 +1805,7 @@ mDNSlocal void removeKnownAnswer(DNSQuestion *question, CacheRecord *rr)
 mDNSlocal void addKnownAnswer(DNSQuestion *question, const CacheRecord *rr)
        {
        CacheRecord *newCR = mDNSNULL;
-       mDNSu32 size;   
+       mDNSu32 size;
 
        size = sizeof(CacheRecord) + rr->resrec.rdlength - InlineCacheRDSize;
        newCR = (CacheRecord *)umalloc(size);
@@ -1676,6 +1813,7 @@ mDNSlocal void addKnownAnswer(DNSQuestion *question, const CacheRecord *rr)
        umemcpy(newCR, rr, size);
        newCR->resrec.rdata = (RData*)&newCR->rdatastorage;
        newCR->resrec.rdata->MaxRDLength = rr->resrec.rdlength;
+       newCR->resrec.name = &question->qname;
        newCR->next = question->uDNS_info.knownAnswers;
        question->uDNS_info.knownAnswers = newCR;
        }
@@ -1698,7 +1836,7 @@ mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const  mDNSu8 *en
                ka = question->uDNS_info.knownAnswers;
                while (ka)
                        {
-                       debugf("deriving goodbye for %##s", ka->resrec.name.c);
+                       debugf("deriving goodbye for %##s", ka->resrec.name->c);
                        
                        m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
                        question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
@@ -1725,7 +1863,7 @@ mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const  mDNSu8 *en
                ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAns, lcr);
                if (!ptr) goto pkt_error;
                cr = &lcr->r;
-               if (ResourceRecordAnswersQuestion(&cr->resrec, question)) 
+               if (ResourceRecordAnswersQuestion(&cr->resrec, question))
                        {
                        cr->next = answers;
                        answers = cr;
@@ -1744,7 +1882,7 @@ mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const  mDNSu8 *en
                        // record is in KA list but not answer list - remove from KA list
                        if (prev) prev->next = ka->next;
                        else question->uDNS_info.knownAnswers = ka->next;
-                       debugf("deriving goodbye for %##s", ka->resrec.name.c);
+                       debugf("deriving goodbye for %##s", ka->resrec.name->c);
                        m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
                        question->QuestionCallback(m, question, &ka->resrec, mDNSfalse);
                        m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
@@ -1776,7 +1914,7 @@ mDNSlocal void deriveGoodbyes(mDNS * const m, DNSMessage *msg, const  mDNSu8 *en
        return;
 
        malloc_error:
-       LogMsg("ERROR: Malloc");        
+       LogMsg("ERROR: Malloc");
        }
 
 mDNSlocal void pktResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *end, DNSQuestion *question, mDNSBool llq)
@@ -1788,6 +1926,7 @@ mDNSlocal void pktResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *
        mDNSBool goodbye, inKAList, followedCName = mDNSfalse;
        LLQ_Info *llqInfo = question->uDNS_info.llq;
        domainname origname;
+       origname.c[0] = 0;
        
        if (question != m->uDNS_info.CurrentQuery)
                { LogMsg("ERROR: pktResponseHdnlr called without CurrentQuery ptr set!");  return; }
@@ -1809,11 +1948,11 @@ mDNSlocal void pktResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *
                                else
                                        {
                                        debugf("Following cname %##s -> %##s", question->qname.c, cr->resrec.rdata->u.name.c);
-                                       AssignDomainName(origname, question->qname);                                    
-                                       AssignDomainName(question->qname, cr->resrec.rdata->u.name);
+                                       AssignDomainName(&origname, &question->qname);
+                                       AssignDomainName(&question->qname, &cr->resrec.rdata->u.name);
                                        question->qnamehash = DomainNameHashValue(&question->qname);
                                        followedCName = mDNStrue;
-                                       i = -1; // restart packet answer matching                                       
+                                       i = -1; // restart packet answer matching
                                        ptr = LocateAnswers(msg, end);
                                        continue;
                                        }
@@ -1833,9 +1972,11 @@ mDNSlocal void pktResponseHndlr(mDNS * const m, DNSMessage *msg, const  mDNSu8 *
                                debugf("pktResponseHndlr - CurrentQuery changed by QuestionCallback - returning");
                                return;
                                }
-                       }                       
-               else if (!followedCName || !SameDomainName(&cr->resrec.name, &origname))
-                       LogMsg("Question %##s type %d - unexpected answer %##s type %d", question->qname.c, question->qtype, cr->resrec.name.c, cr->resrec.rrtype);
+                       }
+               else if (!followedCName || !SameDomainName(cr->resrec.name, &origname))
+                       LogMsg("Question %##s %X %s %##s- unexpected answer %##s %X %s",
+                               question->qname.c, question->qnamehash, DNSTypeName(question->qtype), origname.c,
+                               cr->resrec.name->c, cr->resrec.namehash, DNSTypeName(cr->resrec.rrtype));
                }
        
        if (!llq || llqInfo->state == LLQ_Poll || llqInfo->deriveRemovesOnResume)
@@ -1878,7 +2019,7 @@ mDNSlocal mStatus ParseTSIGError(mDNS *m, const DNSMessage *msg, const mDNSu8 *e
        
        for (i = 0; i < msg->h.numAdditionals; i++)
                {
-               ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);;
+               ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
                if (!ptr) goto finish;
                if (lcr.r.resrec.rrtype == kDNSType_TSIG)
                        {
@@ -1889,7 +2030,7 @@ mDNSlocal mStatus ParseTSIGError(mDNS *m, const DNSMessage *msg, const mDNSu8 *e
                        
                        if (rd +  alglen > rdend) goto finish;
                        rd += alglen;                                       // algorithm name
-                       if (rd + 6 > rdend) goto finish;         
+                       if (rd + 6 > rdend) goto finish;
                        rd += 6;                                            // 48-bit timestamp
                        if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
                        rd += sizeof(mDNSOpaque16);                         // fudge
@@ -1903,10 +2044,10 @@ mDNSlocal mStatus ParseTSIGError(mDNS *m, const DNSMessage *msg, const mDNSu8 *e
                        if (rd + sizeof(mDNSOpaque16) > rdend) goto finish;
                        err = mDNSVal16(*(mDNSOpaque16 *)rd);               // error code
 
-                       if (err ==  TSIG_ErrBadSig)      { LogMsg("%##s: bad signature", displayname->c); err = mStatus_BadSig; }
-                       else if (err == TSIG_ErrBadKey)  { LogMsg("%##s: bad key", displayname->c);       err = mStatus_BadKey; }
-                       else if (err == TSIG_ErrBadTime) { LogMsg("%##s: bad time", displayname->c);      err = mStatus_BadTime; }
-                       else if (err)                    { LogMsg("%##s: unknown tsig error %d", err);    err = mStatus_UnknownErr; }
+                       if (err ==  TSIG_ErrBadSig)      { LogMsg("%##s: bad signature", displayname->c);              err = mStatus_BadSig;     }
+                       else if (err == TSIG_ErrBadKey)  { LogMsg("%##s: bad key", displayname->c);                    err = mStatus_BadKey;     }
+                       else if (err == TSIG_ErrBadTime) { LogMsg("%##s: bad time", displayname->c);                   err = mStatus_BadTime;    }
+                       else if (err)                    { LogMsg("%##s: unknown tsig error %d", displayname->c, err); err = mStatus_UnknownErr; }
                        goto finish;
                        }
                }
@@ -1916,7 +2057,7 @@ mDNSlocal mStatus ParseTSIGError(mDNS *m, const DNSMessage *msg, const mDNSu8 *e
        }
 
 mDNSlocal mStatus checkUpdateResult(domainname *displayname, mDNSu8 rcode, mDNS *m, const DNSMessage *msg, const mDNSu8 *end)
-       {       
+       {
        (void)msg;  // currently unused, needed for TSIG errors
        if (!rcode) return mStatus_NoError;
        else if (rcode == kDNSFlag1_RC_YXDomain)
@@ -1927,7 +2068,7 @@ mDNSlocal mStatus checkUpdateResult(domainname *displayname, mDNSu8 rcode, mDNS
        else if (rcode == kDNSFlag1_RC_Refused)
                {
                LogMsg("Update %##s refused", displayname->c);
-               return mStatus_Refused;                 
+               return mStatus_Refused;
                }
        else if (rcode == kDNSFlag1_RC_NXRRSet)
                {
@@ -1950,7 +2091,7 @@ mDNSlocal mStatus checkUpdateResult(domainname *displayname, mDNSu8 rcode, mDNS
                mStatus tsigerr = ParseTSIGError(m, msg, end, displayname);
                if (!tsigerr)
                        {
-                       LogMsg("Format Error: %##s", displayname->c);           
+                       LogMsg("Format Error: %##s", displayname->c);
                        return mStatus_UnknownErr;
                        }
                else return tsigerr;
@@ -1965,7 +2106,6 @@ mDNSlocal mStatus checkUpdateResult(domainname *displayname, mDNSu8 rcode, mDNS
 mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs,  mStatus err)
        {       
        mDNSBool InvokeCallback = mDNSfalse;    
-       AuthRecord *UpdateR = mDNSNULL;
        uDNS_RegInfo *info = &srs->uDNS_info;
        NATTraversalInfo *nat = srs->uDNS_info.NATinfo;
        ExtraResourceRecord **e = &srs->Extras;
@@ -1976,7 +2116,7 @@ mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs,  mS
                        if (err == mStatus_NameConflict && !info->TestForSelfConflict)
                                {
                                info->TestForSelfConflict = mDNStrue;
-                               debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name.c);
+                               debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c);
                                SendServiceRegistration(m, srs);
                                return;
                                }
@@ -1985,21 +2125,20 @@ mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs,  mS
                                info->TestForSelfConflict = mDNSfalse;
                                if (err == mStatus_NoSuchRecord) err = mStatus_NameConflict;  // NoSuchRecord implies that our prereq was not met, so we actually have a name conflict
                                if (err) info->state = regState_Unregistered;
-                               else info->state = regState_Registered;                         
+                               else info->state = regState_Registered;
                                InvokeCallback = mDNStrue;
                                break;
                                }
                        else if (err == mStatus_UnknownErr && info->lease)
                                {
-                               LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name.c);
+                               LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name->c);
                                info->lease = mDNSfalse;
-                               info->expire = -1;
                                SendServiceRegistration(m, srs);
                                return;
                                }
                        else
                                {
-                               if (err) { LogMsg("Error %ld for registration of service %##s", err, srs->RR_SRV.resrec.name.c); info->state = regState_Unregistered; } //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
+                               if (err) { LogMsg("Error %ld for registration of service %##s", err, srs->RR_SRV.resrec.name->c); info->state = regState_Unregistered; } //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
                                else info->state = regState_Registered;
                                InvokeCallback = mDNStrue;
                                break;
@@ -2007,19 +2146,19 @@ mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs,  mS
                case regState_Refresh:
                        if (err)
                                {
-                               LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name.c);
+                               LogMsg("Error %ld for refresh of service %##s", err, srs->RR_SRV.resrec.name->c);
                                InvokeCallback = mDNStrue;
-                               info->state = regState_Unregistered;                            
+                               info->state = regState_Unregistered;
                                }
                        else info->state = regState_Registered;
                        break;
                case regState_DeregPending:
-                       if (err) LogMsg("Error %ld for deregistration of service %##s", err, srs->RR_SRV.resrec.name.c);
-                       if (info->LostTarget)
+                       if (err) LogMsg("Error %ld for deregistration of service %##s", err, srs->RR_SRV.resrec.name->c);
+                       if (info->SRVChanged)
                                {
-                               info->state = regState_NoTarget;
+                               info->state = regState_NoTarget;  // NoTarget will allow us to pick up new target OR nat traversal state
                                break;
-                               } 
+                               }
                        err = mStatus_MemFree;
                        InvokeCallback = mDNStrue;
                        if (nat)
@@ -2030,27 +2169,27 @@ mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs,  mS
                        info->state = regState_Unregistered;
                        break;
                case regState_DeregDeferred:
-                       if (err) { debugf("Error %ld received prior to deferred derigstration of %##s", err, srs->RR_SRV.resrec.name.c); }
-                       debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name.c); 
-                       info->state = regState_Registered; // benign to set even if we've got an error
-                       SendServiceDeregistration(m, srs);
-                       return;            
-               case regState_UpdatePending:
-                       // find the record being updated
-                       UpdateR = &srs->RR_TXT;
                        if (err)
                                {
-                               LogMsg("hndlServiceUpdateReply: error updating resource record");                               
-                               UpdateR->uDNS_info.state = regState_Unregistered;
-                               InvokeCallback = mDNStrue;        // signal error via service callback
+                               debugf("Error %ld received prior to deferred derigstration of %##s", err, srs->RR_SRV.resrec.name->c);
+                               err = mStatus_MemFree;
+                               InvokeCallback = mDNStrue;
+                               info->state = regState_Unregistered;
+                               break;
                                }
                        else
                                {
-                               UpdateR->uDNS_info.state = regState_Registered;
-                               SwapRData(m, UpdateR, mDNStrue);                                
+                               debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c);
+                               info->state = regState_Registered;
+                               SendServiceDeregistration(m, srs);
+                               return;
                                }
-                       info->state = regState_Registered;                      
-                       break;                  
+               case regState_UpdatePending:
+                       // mDNS clients don't expect asyncronous UpdateRecord errors, so we just log (rare) failures
+                       if (err) LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c);
+                       info->state = regState_Registered;
+                       SwapRData(m, &srs->RR_TXT, mDNStrue);  // deallocate old rdata
+                       break;
                case regState_FetchingZoneData:
                case regState_Registered:
                case regState_Cancelled:
@@ -2058,13 +2197,20 @@ mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs,  mS
                case regState_NATMap:
                case regState_NoTarget:
                case regState_ExtraQueued:
+               case regState_NATError:
                        LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %ld.  Unlinking.",
-                                  srs->RR_SRV.resrec.name.c, info->state, err);
+                                  srs->RR_SRV.resrec.name->c, info->state, err);
                        err = mStatus_UnknownErr;
                }
 
-       if ((info->LostTarget || info->SRVUpdateDeferred) && (info->state == regState_NoTarget || info->state == regState_Registered))
+       if ((info->SRVChanged || info->SRVUpdateDeferred) && (info->state == regState_NoTarget || info->state == regState_Registered))
                {
+               if (InvokeCallback)
+                       {
+                       info->ClientCallbackDeferred = mDNStrue;
+                       info->DeferredStatus = err;
+                       }
+               info->SRVChanged = mDNSfalse;           
                UpdateSRV(m, srs);
                return;
                }
@@ -2073,11 +2219,11 @@ mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs,  mS
                {
                uDNS_RegInfo *einfo = &(*e)->r.uDNS_info;
                if (einfo->state == regState_ExtraQueued)
-                       {                       
+                       {
                        if (info->state == regState_Registered && !err)
                                {
                                // extra resource record queued for this service - copy zone info and register
-                               AssignDomainName(einfo->zone, info->zone);
+                               AssignDomainName(&einfo->zone, &info->zone);
                                einfo->ns = info->ns;
                                einfo->port = info->port;
                                einfo->lease = info->lease;
@@ -2095,11 +2241,22 @@ mDNSlocal void hndlServiceUpdateReply(mDNS * const m, ServiceRecordSet *srs,  mS
                else e = &(*e)->next;
                }
 
-       srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1;  // reset retry delay for future refreshes, dereg, etc.              
-       if (srs->RR_TXT.uDNS_info.UpdateQueued) SendRecordUpdate(m, &srs->RR_TXT, &srs->uDNS_info);             
-
-       if (info->state == regState_Unregistered) unlinkSRS(&m->uDNS_info, srs);
-
+       if (info->state == regState_Unregistered) unlinkSRS(m, srs);
+       else if (srs->RR_TXT.uDNS_info.UpdateQueued && !err)
+               {
+               if (InvokeCallback)
+                       {
+                       // if we were supposed to give a client callback, we'll do it after we update the primary txt record
+                       info->ClientCallbackDeferred = mDNStrue;
+                       info->DeferredStatus = err;
+                       }
+               srs->RR_TXT.uDNS_info.UpdateQueued = mDNSfalse;
+               info->state = regState_UpdatePending;
+               SendServiceRegistration(m, srs);
+               return;
+               }
+       else srs->RR_SRV.ThisAPInterval = INIT_UCAST_POLL_INTERVAL - 1;  // reset retry delay for future refreshes, dereg, etc.
+       
        m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
        if (InvokeCallback) srs->ServiceCallback(m, srs, err);
        else if (info->ClientCallbackDeferred)
@@ -2119,12 +2276,12 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
                {
                if (err)
                        {
-                       LogMsg("Update record failed for %##s (err %d)", rr->resrec.name.c, err);
+                       LogMsg("Update record failed for %##s (err %d)", rr->resrec.name->c, err);
                        rr->uDNS_info.state = regState_Unregistered;
                        }
                else
                        {
-                       debugf("Update record %##s - success", rr->resrec.name.c);
+                       debugf("Update record %##s - success", rr->resrec.name->c);
                        rr->uDNS_info.state = regState_Registered;
                        SwapRData(m, rr, mDNStrue);
                        }
@@ -2135,10 +2292,10 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
                }
 
        if (rr->uDNS_info.state == regState_DeregPending)
-               {                                       
-               debugf("Received reply for deregister record %##s type %d", rr->resrec.name.c, rr->resrec.rrtype);
+               {
+               debugf("Received reply for deregister record %##s type %d", rr->resrec.name->c, rr->resrec.rrtype);
                if (err) LogMsg("ERROR: Deregistration of record %##s type %d failed with error %ld",
-                                               rr->resrec.name.c, rr->resrec.rrtype, err);
+                                               rr->resrec.name->c, rr->resrec.rrtype, err);
                err = mStatus_MemFree;
                if (unlinkAR(&m->uDNS_info.RecordRegistrations, rr))
                        LogMsg("ERROR: Could not unlink resource record following deregistration");
@@ -2154,15 +2311,15 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
                if (err)
                        {
                        LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %ld",
-                                  rr->resrec.name.c, rr->resrec.rrtype, err);
+                                  rr->resrec.name->c, rr->resrec.rrtype, err);
                        unlinkAR(&m->uDNS_info.RecordRegistrations, rr);
                        rr->uDNS_info.state = regState_Unregistered;
                        return;
                        }
                LogMsg("Calling deferred deregistration of record %##s type %d",
-                          rr->resrec.name.c, rr->resrec.rrtype);
+                          rr->resrec.name->c, rr->resrec.rrtype);
                rr->uDNS_info.state = regState_Registered;
-               uDNS_DeregisterRecord(m, rr);                                   
+               uDNS_DeregisterRecord(m, rr);
                return;
                }
 
@@ -2172,16 +2329,15 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
                        {
                        if (rr->uDNS_info.lease && err == mStatus_UnknownErr)
                                {
-                               LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name.c);
+                               LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c);
                                rr->uDNS_info.lease = mDNSfalse;
-                               rr->uDNS_info.expire = -1;
                                sendRecordRegistration(m, rr);
                                return;
                                }
                        
                        LogMsg("Registration of record %##s type %d failed with error %ld",
-                                  rr->resrec.name.c, rr->resrec.rrtype, err);
-                       unlinkAR(&u->RecordRegistrations, rr); 
+                                  rr->resrec.name->c, rr->resrec.rrtype, err);
+                       unlinkAR(&u->RecordRegistrations, rr);
                        rr->uDNS_info.state = regState_Unregistered;
                        m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
                        if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
@@ -2192,13 +2348,13 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
                        {
                        if (rr->uDNS_info.UpdateQueued)
                                {
-                               debugf("%##s: sending queued update", rr->resrec.name.c);
+                               debugf("%##s: sending queued update", rr->resrec.name->c);
                                rr->uDNS_info.state = regState_Registered;
                                SendRecordUpdate(m ,rr, &rr->uDNS_info);
                                return;
                                }
                        if (rr->uDNS_info.state == regState_Refresh)
-                               rr->uDNS_info.state = regState_Registered;                      
+                               rr->uDNS_info.state = regState_Registered;
                        else
                                {
                                rr->uDNS_info.state = regState_Registered;
@@ -2211,7 +2367,7 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
                }
        
        LogMsg("Received unexpected response for record %##s type %d, in state %d, with response error %ld",
-                  rr->resrec.name.c, rr->resrec.rrtype, rr->uDNS_info.state, err);
+                  rr->resrec.name->c, rr->resrec.rrtype, rr->uDNS_info.state, err);
        }
 
 
@@ -2244,12 +2400,12 @@ mDNSlocal void SetUpdateExpiration(mDNS *m, DNSMessage *msg, const mDNSu8 *end,
        if (lease > 0)
                {
                expire = (mDNSPlatformTimeNow(m) + (((mDNSs32)lease * mDNSPlatformOneSecond)) * 3/4);
-               if (info->state == regState_UpdatePending)  
+               if (info->state == regState_UpdatePending)
             // if updating individual record, the service record set may expire sooner
                        { if (expire - info->expire < 0) info->expire = expire; }
                else info->expire = expire;
                }
-       else info->expire = -1;
+       else info->lease = mDNSfalse;
        }
 
 mDNSexport void uDNS_ReceiveNATMap(mDNS *m, mDNSu8 *pkt, mDNSu16 len)
@@ -2259,7 +2415,7 @@ mDNSexport void uDNS_ReceiveNATMap(mDNS *m, mDNSu8 *pkt, mDNSu16 len)
        NATOp_t op;
        
        // check length, version, opcode
-       if (len < ADDR_REPLY_PKTLEN && len < PORTMAP_PKTLEN) { LogMsg("NAT Traversal message too short (%d bytes)", len); return; }
+       if (len < sizeof(NATPortMapReply) && len < sizeof(NATAddrReply)) { LogMsg("NAT Traversal message too short (%d bytes)", len); return; }
        if (pkt[0] != NATMAP_VERS) { LogMsg("Received NAT Traversal response with version %d (expect version %d)", pkt[0], NATMAP_VERS); return; }
        op = pkt[1];
        if (!(op & NATMAP_RESPONSE_MASK)) { LogMsg("Received NAT Traversal message that is not a response (opcode %d)", op); return; }
@@ -2272,7 +2428,7 @@ mDNSexport void uDNS_ReceiveNATMap(mDNS *m, mDNSu8 *pkt, mDNSu16 len)
                if ((cur->state == NATState_Request || cur->state == NATState_Refresh) &&
                        (cur->op | NATMAP_RESPONSE_MASK) == op)
                        cur->ReceiveResponse(cur, m, pkt, len);  // callback may delete "cur"
-               // specific request/reply matching logic handled by callback - we don't know if this was a match, so we don't break here  
+               // specific request/reply matching logic handled by callback - we don't know if this was a match, so we don't break here
                }
        }
 
@@ -2299,7 +2455,7 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
        (void)InterfaceID;
        
        if (QR_OP == StdR)
-               {               
+               {
                // !!!KRS we should to a table lookup here to see if it answers an LLQ or a 1-shot
                // LLQ Responses over TCP not currently supported
                if (srcaddr && recvLLQResponse(m, msg, end, srcaddr, srcport, InterfaceID)) return;
@@ -2330,7 +2486,7 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
                        {
                        if (sptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
                                {
-                               err = checkUpdateResult(&sptr->RR_SRV.resrec.name, rcode, m, msg, end);
+                               err = checkUpdateResult(sptr->RR_SRV.resrec.name, rcode, m, msg, end);
                                if (!err) SetUpdateExpiration(m, msg, end, &sptr->uDNS_info);
                                hndlServiceUpdateReply(m, sptr, err);
                                return;
@@ -2340,8 +2496,8 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
                        {
                        if (rptr->uDNS_info.id.NotAnInteger == msg->h.id.NotAnInteger)
                                {
-                               err = checkUpdateResult(&rptr->resrec.name, rcode, m, msg, end);
-                               if (!err) SetUpdateExpiration(m, msg, end, &rptr->uDNS_info);                           
+                               err = checkUpdateResult(rptr->resrec.name, rcode, m, msg, end);
+                               if (!err) SetUpdateExpiration(m, msg, end, &rptr->uDNS_info);
                                hndlRecordUpdateReply(m, rptr, err);
                                return;
                                }
@@ -2359,7 +2515,7 @@ mDNSlocal mDNSBool GetServerForName(uDNS_GlobalInfo *u, const domainname *name,
        *addr = zeroAddr;
        ncount = name ? CountLabels(name) : 0;
        while (p)
-               {               
+               {
                scount = CountLabels(&p->domain);
                if (scount <= ncount && scount > curmatchlen)
                        {
@@ -2412,7 +2568,7 @@ mDNSlocal mStatus constructQueryMsg(DNSMessage *msg, mDNSu8 **endPtr, DNSQuestio
 mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, DNSQuestion *question, LLQOptData *data, mDNSBool includeQuestion)
        {
        AuthRecord rr;
-       ResourceRecord *opt = &rr.resrec; 
+       ResourceRecord *opt = &rr.resrec;
        rdataOpt *optRD;
        
        //!!!KRS when we implement multiple llqs per message, we'll need to memmove anything past the question section
@@ -2421,16 +2577,13 @@ mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, DNSQuestion *questi
                ptr = putQuestion(msg, ptr, msg->data + AbsoluteMaxDNSMessageData, &question->qname, question->qtype, question->qclass);
                if (!ptr) { LogMsg("ERROR: putLLQ - putQuestion"); return mDNSNULL; }
                }
-       // locate OptRR if it exists, set pointer to end 
+       // locate OptRR if it exists, set pointer to end
        // !!!KRS implement me
 
        
        // format opt rr (fields not specified are zero-valued)
        ubzero(&rr, sizeof(AuthRecord));
-       opt->rdata = &rr.rdatastorage;
-       
-       opt->RecordType = kDNSRecordTypeKnownUnique;  // to avoid warnings in other layers
-       opt->rrtype = kDNSType_OPT;
+       mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
        opt->rdlength = LLQ_OPT_SIZE;
        opt->rdestimate = LLQ_OPT_SIZE;
 
@@ -2458,9 +2611,9 @@ mDNSlocal mDNSBool getLLQAtIndex(mDNS *m, DNSMessage *msg, const mDNSu8 *end, LL
        for (i = 0; i < msg->h.numAdditionals; i++)
 //             { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; }
 //!!!KRS workaround for LH server bug, which puts OPT as first additional
-               { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; if (lcr.r.resrec.rrtype == kDNSType_OPT) break; }               
+               { ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr); if (!ptr) return mDNSfalse; if (lcr.r.resrec.rrtype == kDNSType_OPT) break; }
        if (lcr.r.resrec.rrtype != kDNSType_OPT) return mDNSfalse;
-       if (lcr.r.resrec.rdlength < (index + 1) * LLQ_OPT_SIZE) return mDNSfalse;  // rdata too small 
+       if (lcr.r.resrec.rdlength < (index + 1) * LLQ_OPT_SIZE) return mDNSfalse;  // rdata too small
        umemcpy(llq, (mDNSu8 *)&lcr.r.resrec.rdata->u.opt.OptData.llq + (index * sizeof(LLQOptData)), sizeof(LLQOptData));      // !!! Should convert to host byte order?
        return mDNStrue;
        }
@@ -2480,7 +2633,7 @@ mDNSlocal void recvRefreshReply(mDNS *m, DNSMessage *msg, const mDNSu8 *end, DNS
        qInfo->retry = qInfo->expire - ((mDNSs32)pktData.lease * mDNSPlatformOneSecond/2);
  
        qInfo->origLease = pktData.lease;
-       qInfo->state = LLQ_Established; 
+       qInfo->state = LLQ_Established;
        }
 
 mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease)
@@ -2521,7 +2674,7 @@ mDNSlocal void sendLLQRefresh(mDNS *m, DNSQuestion *q, mDNSu32 lease)
        else info->ntries++;
        info->state = LLQ_Refresh;
        q->LastQTime = timenow;
-       info->retry = (info->expire - q->LastQTime) / 2;        
+       info->retry = (info->expire - q->LastQTime) / 2;
        }
 
 mDNSlocal mDNSBool recvLLQEvent(mDNS *m, DNSQuestion *q, DNSMessage *msg, const mDNSu8 *end, const mDNSAddr *srcaddr, mDNSIPPort srcport, mDNSInterfaceID InterfaceID)
@@ -2534,10 +2687,10 @@ mDNSlocal mDNSBool recvLLQEvent(mDNS *m, DNSQuestion *q, DNSMessage *msg, const
        (void)InterfaceID;  // unused
 
     // find Opt RR, verify correct ID
-       if (!getLLQAtIndex(m, msg, end, &opt, 0)) { debugf("Pkt does not contain LLQ Opt"); return mDNSfalse; }
-       if (opt.llqOp != kLLQOp_Event) { LogMsg("recvLLQEvent - Bad LLQ Opcode %d", opt.llqOp); return mDNSfalse; }
-       if (!q->uDNS_info.llq) { LogMsg("Error: recvLLQEvent - question onject does not contain LLQ metadata"); return mDNSfalse; }
-       if (!sameID(opt.id, q->uDNS_info.llq->id)) { LogMsg("recvLLQEvent - incorrect ID. Discarding"); return mDNSfalse; }
+       if (!getLLQAtIndex(m, msg, end, &opt, 0))  { debugf("Pkt does not contain LLQ Opt");                                        return mDNSfalse; }
+       if (opt.llqOp != kLLQOp_Event)             { LogMsg("recvLLQEvent - Bad LLQ Opcode %d", opt.llqOp);                         return mDNSfalse; }
+       if (!q->uDNS_info.llq)                     { LogMsg("Error: recvLLQEvent - question object does not contain LLQ metadata"); return mDNSfalse; }
+       if (!sameID(opt.id, q->uDNS_info.llq->id)) {                                                                                return mDNSfalse; }
 
     // invoke response handler
        m->uDNS_info.CurrentQuery = q;
@@ -2548,7 +2701,7 @@ mDNSlocal mDNSBool recvLLQEvent(mDNS *m, DNSQuestion *q, DNSMessage *msg, const
        InitializeDNSMessage(&ack.h, msg->h.id, ResponseFlags);
        ackEnd = putQuestion(&ack, ack.data, ack.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
        if (!ackEnd) { LogMsg("ERROR: recvLLQEvent - putQuestion");  return mDNSfalse; }
-       err = mDNSSendDNSMessage(m, &ack, ackEnd, mDNSInterface_Any, srcaddr, srcport, -1, mDNSNULL); 
+       err = mDNSSendDNSMessage(m, &ack, ackEnd, mDNSInterface_Any, srcaddr, srcport, -1, mDNSNULL);
        if (err) LogMsg("ERROR: recvLLQEvent - mDNSSendDNSMessage returned %ld", err);
        return mDNStrue;
        }
@@ -2565,7 +2718,7 @@ mDNSlocal void hndlChallengeResponseAck(mDNS *m, DNSMessage *pktMsg, const mDNSu
        info->retry = info->expire - ((mDNSs32)llq->lease * mDNSPlatformOneSecond / 2);
  
        info->origLease = llq->lease;
-       info->state = LLQ_Established;  
+       info->state = LLQ_Established;
        
        q->uDNS_info.responseCallback = llqResponseHndlr;
        llqResponseHndlr(m, pktMsg, end, q, mDNSNULL);
@@ -2673,7 +2826,7 @@ mDNSlocal void hndlRequestChallenge(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *e
 
 
        error:
-       info->state = LLQ_Error;        
+       info->state = LLQ_Error;
        }
 
 
@@ -2696,8 +2849,8 @@ mDNSlocal void recvSetupResponse(mDNS *m, DNSMessage *pktMsg, const mDNSu8 *end,
                { LogMsg("ERROR: recvSetupResponse - mismatched question in response for llq setup %##s", q->qname.c);   goto poll; }
 
        if (!getLLQAtIndex(m, pktMsg, end, &llq, 0)) { debugf("recvSetupResponse - GetLLQAtIndex"); goto poll; }
-       if (llq.llqOp != kLLQOp_Setup) { LogMsg("ERROR: recvSetupResponse - bad op %d", llq.llqOp); goto poll; } 
-       if (llq.vers != kLLQ_Vers) { LogMsg("ERROR: recvSetupResponse - bad vers %d", llq.vers);  goto poll; } 
+       if (llq.llqOp != kLLQOp_Setup) { LogMsg("ERROR: recvSetupResponse - bad op %d", llq.llqOp); goto poll; }
+       if (llq.vers != kLLQ_Vers) { LogMsg("ERROR: recvSetupResponse - bad vers %d", llq.vers);  goto poll; }
 
        if (info->state == LLQ_InitialRequest) { hndlRequestChallenge(m, pktMsg, end, &llq, q); return; }
        if (info->state == LLQ_SecondaryRequest) { hndlChallengeResponseAck(m, pktMsg, end, &llq, q); return; }
@@ -2715,7 +2868,7 @@ mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer)
        DNSMessage msg;
        mDNSu8 *end;
        LLQOptData llqData;
-       DNSQuestion *q = info->question; 
+       DNSQuestion *q = info->question;
        mStatus err = mStatus_NoError;
        mDNSs32 timenow = mDNSPlatformTimeNow(m);
        uDNS_GlobalInfo *u = &m->uDNS_info;
@@ -2728,7 +2881,7 @@ mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer)
                        StartLLQNatMap(m);
                        return;
                        }
-               if (u->LLQNatInfo->state == NATState_Error) goto poll;          
+               if (u->LLQNatInfo->state == NATState_Error) goto poll;
                if (u->LLQNatInfo->state != NATState_Established && u->LLQNatInfo->state != NATState_Legacy)
                        { info->state = LLQ_NatMapWait; info->NATMap = mDNStrue; return; }
                info->NATMap = mDNStrue;  // this llq references the global llq nat mapping
@@ -2738,7 +2891,7 @@ mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer)
                {
                debugf("startLLQHandshake: %d failed attempts for LLQ %##s.  Polling.", kLLQ_MAX_TRIES, q->qname.c, kLLQ_DEF_RETRY / 60);
                goto poll;
-               }       
+               }
        
     // set llq rdata
        llqData.vers    = kLLQ_Vers;
@@ -2752,7 +2905,7 @@ mDNSlocal void startLLQHandshake(mDNS *m, LLQ_Info *info, mDNSBool defer)
        if (!end)
                {
                LogMsg("ERROR: startLLQHandshake - putLLQ");
-               info->state = LLQ_Error;                
+               info->state = LLQ_Error;
                return;
                }
 
@@ -2881,14 +3034,14 @@ mDNSlocal mDNSBool recvLLQResponse(mDNS *m, DNSMessage *msg, const mDNSu8 *end,
        while (q)
                {
                llqInfo = q->uDNS_info.llq;
-               if (q->LongLived &&                          
+               if (q->LongLived &&
                        llqInfo &&
-                       q->qnamehash == pktQ.qnamehash &&        
+                       q->qnamehash == pktQ.qnamehash &&
                        q->qtype == pktQ.qtype &&
                        SameDomainName(&q->qname, &pktQ.qname))
                        {
                        u->CurrentQuery = q;
-                       if (llqInfo->state == LLQ_Established || (llqInfo->state == LLQ_Refresh && msg->h.numAnswers))                  
+                       if (llqInfo->state == LLQ_Established || (llqInfo->state == LLQ_Refresh && msg->h.numAnswers))
                                { if (recvLLQEvent(m, q, msg, end, srcaddr, srcport, InterfaceID)) return mDNStrue; }
                        else if (msg->h.id.NotAnInteger == q->uDNS_info.id.NotAnInteger)
                                {
@@ -2939,17 +3092,17 @@ mDNSlocal void stopLLQ(mDNS *m, DNSQuestion *question)
                        //!!!KRS should we unlink info<->question here?
                        return;
                case LLQ_GetZoneInfo:
-               case LLQ_SuspendDeferred:               
+               case LLQ_SuspendDeferred:
                        info->question = mDNSNULL; // remove ref to question, as it may be freed when we get called back from async op
                        info->state = LLQ_Cancelled;
-                       return;                 
+                       return;
                case LLQ_Established:
                case LLQ_Refresh:
                        // refresh w/ lease 0
                        sendLLQRefresh(m, question, 0);
-                       goto end;       
-               default:                        
-                       debugf("stopLLQ - silently discarding LLQ in state %d", info->state);                           
+                       goto end;
+               default:
+                       debugf("stopLLQ - silently discarding LLQ in state %d", info->state);
                        goto end;
                }
        
@@ -3049,7 +3202,7 @@ mDNSexport mStatus uDNS_StartQuery(mDNS *const m, DNSQuestion *const question)
 mDNSlocal mStatus startInternalQuery(DNSQuestion *q, mDNS *m, InternalResponseHndlr callback, void *hndlrContext)
     {
        ubzero(&q->uDNS_info, sizeof(uDNS_QuestionInfo));
-    q->QuestionContext = hndlrContext; 
+    q->QuestionContext = hndlrContext;
     q->uDNS_info.responseCallback = callback;
        q->uDNS_info.context = hndlrContext;
     return startQuery(m, q, 1);
@@ -3116,8 +3269,8 @@ typedef enum
 // state machine actions
 typedef enum
     {
-    smContinue,  // continue immediately to next state 
-    smBreak,     // break until next packet/timeout 
+    smContinue,  // continue immediately to next state
+    smBreak,     // break until next packet/timeout
        smError      // terminal error - cleanup and abort
     } smAction;
  
@@ -3128,13 +3281,13 @@ typedef struct
     ntaState   state;               // determines what we do upon receiving a packet
     mDNS           *m;
     domainname  zone;                // left-hand-side of SOA record
-    mDNSu16     zoneClass; 
+    mDNSu16     zoneClass;
     domainname  ns;                  // mname in SOA rdata, verified in confirmNS state
     mDNSv4Addr  addr;                // address of nameserver
     DNSQuestion question;            // storage for any active question
     DNSQuestion extraQuestion;       // additional storage
     mDNSBool    questionActive;      // if true, StopQuery() can be called on the question field
-    mDNSBool    findUpdatePort;      
+    mDNSBool    findUpdatePort;
     mDNSBool    findLLQPort;
     mDNSIPPort  updatePort;
     mDNSIPPort  llqPort;
@@ -3159,7 +3312,7 @@ mDNSlocal mStatus startGetZoneData(domainname *name, mDNS *m, mDNSBool findUpdat
     ntaContext *context = (ntaContext*)umalloc(sizeof(ntaContext));
     if (!context) { LogMsg("ERROR: startGetZoneData - umalloc failed");  return mStatus_NoMemoryErr; }
        ubzero(context, sizeof(ntaContext));
-    AssignDomainName(context->origName, *name);
+    AssignDomainName(&context->origName, name);
     context->state = init;
     context->m = m;
        context->callback = callback;
@@ -3224,7 +3377,7 @@ mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DN
                        if (action == smBreak) return;
                        if (action == smContinue) context->state = complete;
                case foundPort:
-               case complete: break;                   
+               case complete: break;
                }
                                          
        if (context->state != complete)
@@ -3236,22 +3389,22 @@ mDNSlocal void getZoneData(mDNS *const m, DNSMessage *msg, const mDNSu8 *end, DN
        result.type = zoneDataResult;
        result.zoneData.primaryAddr.ip.v4.NotAnInteger = context->addr.NotAnInteger;
        result.zoneData.primaryAddr.type = mDNSAddrType_IPv4;
-       AssignDomainName(result.zoneData.zoneName, context->zone);
+       AssignDomainName(&result.zoneData.zoneName, &context->zone);
        result.zoneData.zoneClass = context->zoneClass;
        result.zoneData.llqPort    = context->findLLQPort    ? context->llqPort    : zeroIPPort;
        result.zoneData.updatePort = context->findUpdatePort ? context->updatePort : zeroIPPort;
        context->callback(mStatus_NoError, context->m, context->callbackInfo, &result);
-       goto cleanup;   
+       goto cleanup;
                        
 error:
        if (context && context->callback)
-               context->callback(mStatus_UnknownErr, context->m, context->callbackInfo, mDNSNULL);     
+               context->callback(mStatus_UnknownErr, context->m, context->callbackInfo, mDNSNULL);
 cleanup:
        if (context && context->questionActive)
                {
                uDNS_StopQuery(context->m, &context->question);
                context->questionActive = mDNSfalse;
-               }               
+               }
     if (context) ufree(context);
        }
 
@@ -3265,37 +3418,37 @@ mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext
        
     if (msg)
         {
-        // if msg contains SOA record in answer or authority sections, update context/state and return                 
+        // if msg contains SOA record in answer or authority sections, update context/state and return
                int i;
                ptr = LocateAnswers(msg, end);
                for (i = 0; i < msg->h.numAnswers; i++)
                        {
                        ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
                        if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Answers - GetLargeResourceRecord returned NULL");  return smError; }
-                       if (rr->rrtype == kDNSType_SOA && SameDomainName(context->curSOA, &rr->name))
+                       if (rr->rrtype == kDNSType_SOA && SameDomainName(context->curSOA, rr->name))
                                {
                                processSOA(context, rr);
                                return smContinue;
                                }
-                       }               
+                       }
                ptr = LocateAuthorities(msg, end);
                // SOA not in answers, check in authority
                for (i = 0; i < msg->h.numAuthorities; i++)
                        {
                        ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr); ///!!!KRS using type PacketAns for auth
-                       if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Authority - GetLargeResourceRecord returned NULL");  return smError; }                                
+                       if (!ptr) { LogMsg("ERROR: hndlLookupSOA, Authority - GetLargeResourceRecord returned NULL");  return smError; }
                        if (rr->rrtype == kDNSType_SOA)
                                {
                                processSOA(context, rr);
                                return smContinue;
                                }
                        }
-               }    
+               }
 
     if (context->state != init && !context->curSOA->c[0])
         {
-        // we've gone down to the root and have not found an SOA  
-        LogMsg("ERROR: hndlLookupSOA - recursed to root label of %##s without finding SOA", 
+        // we've gone down to the root and have not found an SOA
+        LogMsg("ERROR: hndlLookupSOA - recursed to root label of %##s without finding SOA",
                 context->origName.c);
                return smError;
         }
@@ -3306,21 +3459,21 @@ mDNSlocal smAction hndlLookupSOA(DNSMessage *msg, const mDNSu8 *end, ntaContext
     else                         context->curSOA = (domainname *)(context->curSOA->c + context->curSOA->c[0]+1);
     
     context->state = lookupSOA;
-    AssignDomainName(query->qname, *context->curSOA);
+    AssignDomainName(&query->qname, context->curSOA);
     query->qtype = kDNSType_SOA;
     query->qclass = kDNSClass_IN;
     err = startInternalQuery(query, context->m, getZoneData, context);
        context->questionActive = mDNStrue;
        if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
 
-    return smBreak;     // break from state machine until we receive another packet    
+    return smBreak;     // break from state machine until we receive another packet
     }
 
 mDNSlocal void processSOA(ntaContext *context, ResourceRecord *rr)
        {
-       AssignDomainName(context->zone, rr->name);
+       AssignDomainName(&context->zone, rr->name);
        context->zoneClass = rr->rrclass;
-       AssignDomainName(context->ns, rr->rdata->u.soa.mname);
+       AssignDomainName(&context->ns, &rr->rdata->u.soa.mname);
        context->state = foundZone;
        }
 
@@ -3337,11 +3490,11 @@ mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *con
        if (context->state == foundZone)
                {
                // we've just learned the zone.  confirm that an NS record exists
-               AssignDomainName(query->qname, context->zone);
+               AssignDomainName(&query->qname, &context->zone);
                query->qtype = kDNSType_NS;
                query->qclass = kDNSClass_IN;
                err = startInternalQuery(query, context->m, getZoneData, context);
-               context->questionActive = mDNStrue;        
+               context->questionActive = mDNStrue;
                if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission", err);
                context->state = lookupNS;
                return smBreak;  // break from SM until we receive another packet
@@ -3354,11 +3507,11 @@ mDNSlocal smAction confirmNS(DNSMessage *msg, const mDNSu8 *end, ntaContext *con
                        ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
                        if (!ptr) { LogMsg("ERROR: confirmNS, Answers - GetLargeResourceRecord returned NULL");  return smError; }
                        if (rr->rrtype == kDNSType_NS &&
-                               SameDomainName(&context->zone, &rr->name) && SameDomainName(&context->ns, &rr->rdata->u.name))
+                               SameDomainName(&context->zone, rr->name) && SameDomainName(&context->ns, &rr->rdata->u.name))
                                {
                                context->state = foundNS;
-                               return smContinue;  // next routine will examine additionals section of A record                                
-                               }                               
+                               return smContinue;  // next routine will examine additionals section of A record
+                               }
                        }
                LogMsg("ERROR: could not confirm existence of record %##s NS %##s", context->zone.c, context->ns.c);
                return smError;
@@ -3371,11 +3524,11 @@ mDNSlocal smAction queryNSAddr(ntaContext *context)
        mStatus err;
        DNSQuestion *query = &context->question;
        
-       AssignDomainName(query->qname, context->ns);
+       AssignDomainName(&query->qname, &context->ns);
        query->qtype = kDNSType_A;
        query->qclass = kDNSClass_IN;
        err = startInternalQuery(query, context->m, getZoneData, context);
-       context->questionActive = mDNStrue;     
+       context->questionActive = mDNStrue;
        if (err) LogMsg("confirmNS: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
        context->state = lookupA;
        return smBreak;
@@ -3408,7 +3561,7 @@ mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *
                                        LogMsg("ERROR: lookupNSAddr, Additionals - GetLargeResourceRecord returned NULL");
                                        return queryNSAddr(context);
                                        }
-                               if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, &rr->name))
+                               if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, rr->name))
                                        {
                                        context->addr.NotAnInteger = rr->rdata->u.ipv4.NotAnInteger;
                                        context->state = foundA;
@@ -3426,14 +3579,14 @@ mDNSlocal smAction lookupNSAddr(DNSMessage *msg, const mDNSu8 *end, ntaContext *
                for (i = 0; i < msg->h.numAnswers; i++)
                        {
                        ptr = GetLargeResourceRecord(context->m, msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
-                       if (!ptr) { LogMsg("ERROR: lookupNSAddr, Answers - GetLargeResourceRecord returned NULL"); break; }                     
-                       if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, &rr->name))
+                       if (!ptr) { LogMsg("ERROR: lookupNSAddr, Answers - GetLargeResourceRecord returned NULL"); break; }
+                       if (rr->rrtype == kDNSType_A && SameDomainName(&context->ns, rr->name))
                                {
                                context->addr.NotAnInteger = rr->rdata->u.ipv4.NotAnInteger;
                                context->state = foundA;
                                return smContinue;
                                }
-                       }               
+                       }
                LogMsg("ERROR: lookupNSAddr: Address record not found in answer section");
                return smError;
                }
@@ -3479,7 +3632,7 @@ mDNSlocal smAction lookupDNSPort(DNSMessage *msg, const mDNSu8 *end, ntaContext
     err = startInternalQuery(q, context->m, getZoneData, context);
        context->questionActive = mDNStrue;
     if (err) LogMsg("hndlLookupSOA: startInternalQuery returned error %ld (breaking until next periodic retransmission)", err);
-    return smBreak;     // break from state machine until we receive another packet    
+    return smBreak;     // break from state machine until we receive another packet
        }
 
 mDNSlocal smAction hndlLookupPorts(DNSMessage *msg, const mDNSu8 *end, ntaContext *context)
@@ -3541,20 +3694,28 @@ mDNSlocal void conQueryCallback(int sd, void *context, mDNSBool ConnectionEstabl
                if (!info->nread)
                        {
                        // read msg len
-                       n = mDNSPlatformReadTCP(sd, &info->replylen, 2);
+                       mDNSu8 lenbuf[2];
+                       n = mDNSPlatformReadTCP(sd, lenbuf, 2);
                        if (n != 2)
                                {
                                LogMsg("ERROR:conQueryCallback - attempt to read message length failed (read returned %d)", n);
                                goto error;
                                }
+                       info->replylen = (mDNSu16)((mDNSu16)lenbuf[0] << 8 | lenbuf[1]);
                        }
                n = mDNSPlatformReadTCP(sd, ((char *)&info->reply) + info->nread, info->replylen - info->nread);
                if (n < 0) { LogMsg("ERROR: conQueryCallback - read returned %d", n); goto error; }
                info->nread += n;
                if (info->nread == info->replylen)
                        {
-                       // finished reading message
-                       uDNS_ReceiveMsg(m, &info->reply, ((mDNSu8 *)&info->reply) + info->replylen, mDNSNULL, zeroIPPort, mDNSNULL, zeroIPPort, question->InterfaceID);
+                       // Finished reading message; convert the integer parts which are in IETF byte-order (MSB first, LSB second)
+                       DNSMessage *msg = &info->reply;
+                       mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions;
+                       msg->h.numQuestions   = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
+                       msg->h.numAnswers     = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
+                       msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
+                       msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
+                       uDNS_ReceiveMsg(m, msg, (mDNSu8 *)msg + info->replylen, mDNSNULL, zeroIPPort, mDNSNULL, zeroIPPort, question->InterfaceID);
                        mDNSPlatformTCPCloseConnection(sd);
                        ufree(info);
                        }
@@ -3622,16 +3783,16 @@ mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr)
        ptr = putZone(&msg, ptr, end, &regInfo->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
        if (!ptr) goto error;
        
-       if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique || rr->uDNS_info.state == regState_Refresh)
+       if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
          {
-               // KnownUnique means the record must ALREADY exist, as does refresh
-               // prereq: record must exist (put record in prereq section w/ TTL 0)
-           ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numPrereqs, &rr->resrec, 0);
-               if (!ptr) goto error;
+         // KnownUnique: Delete any previous value
+         ptr = putDeleteRRSet(&msg, ptr, rr->resrec.name, rr->resrec.rrtype);
+         if (!ptr) goto error;
          }
+
        else if (rr->resrec.RecordType != kDNSRecordTypeShared)
                {
-               ptr = putPrereqNameNotInUse(&rr->resrec.name, &msg, ptr, end);
+               ptr = putPrereqNameNotInUse(rr->resrec.name, &msg, ptr, end);
                if (!ptr) goto error;
                }
 
@@ -3639,16 +3800,14 @@ mDNSlocal void sendRecordRegistration(mDNS *const m, AuthRecord *rr)
        if (!ptr) goto error;
 
        if (rr->uDNS_info.lease)
-               { ptr = putUpdateLease(&msg, ptr, kLLQ_DefLease); if (!ptr) goto error; }
-          
-       rr->uDNS_info.expire = -1;
-       
+               { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; }
+               
        err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &regInfo->ns, regInfo->port, -1, GetAuthInfoForZone(u, &regInfo->zone));
        if (err) LogMsg("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %ld", err);
 
        SetRecordRetry(m, rr);
        
-       if (regInfo->state != regState_Refresh) regInfo->state = regState_Pending;
+       if (regInfo->state != regState_Refresh && regInfo->state != regState_DeregDeferred) regInfo->state = regState_Pending;
        return;
 
 error:
@@ -3661,10 +3820,10 @@ error:
        m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
        if (rr->RecordCallback) rr->RecordCallback(m, rr, err);
        m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-       // NOTE: not safe to touch any client structures here   
+       // NOTE: not safe to touch any client structures here
        }
 
-mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *authPtr, const AsyncOpResult *result)      
+mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *authPtr, const AsyncOpResult *result)
        {
        AuthRecord *newRR = (AuthRecord*)authPtr;
        const zoneData_t *zoneData = mDNSNULL;
@@ -3674,7 +3833,7 @@ mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *auth
        // make sure record is still in list
        for (ptr = u->RecordRegistrations; ptr; ptr = ptr->next)
                if (ptr == newRR) break;
-       if (!ptr) { LogMsg("RecordRegistrationCallback - RR no longer in list.  Discarding."); return; }                
+       if (!ptr) { LogMsg("RecordRegistrationCallback - RR no longer in list.  Discarding."); return; }
 
        // check error/result
        if (err) { LogMsg("RecordRegistrationCallback: error %ld", err); goto error; }
@@ -3685,7 +3844,7 @@ mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *auth
                {
                //!!!KRS we should send a memfree callback here!
                debugf("Registration of %##s type %d cancelled prior to update",
-                          newRR->resrec.name.c, newRR->resrec.rrtype);
+                          newRR->resrec.name->c, newRR->resrec.rrtype);
                newRR->uDNS_info.state = regState_Unregistered;
                unlinkAR(&u->RecordRegistrations, newRR);
                return;
@@ -3702,10 +3861,10 @@ mDNSlocal void RecordRegistrationCallback(mStatus err, mDNS *const m, void *auth
                LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)",
                           newRR->resrec.rrclass, zoneData->zoneClass);
                goto error;
-               }       
+               }
        
        // cache zone data
-       AssignDomainName(newRR->uDNS_info.zone, zoneData->zoneName);
+       AssignDomainName(&newRR->uDNS_info.zone, &zoneData->zoneName);
     newRR->uDNS_info.ns.type = mDNSAddrType_IPv4;
        newRR->uDNS_info.ns.ip.v4.NotAnInteger = zoneData->primaryAddr.ip.v4.NotAnInteger;
        if (zoneData->updatePort.NotAnInteger) newRR->uDNS_info.port = zoneData->updatePort;
@@ -3746,12 +3905,15 @@ mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
        mDNSBool mapped = mDNSfalse;
        domainname target;
        AuthRecord *srv = &srs->RR_SRV;
+       mDNSu32 i;
        
+       if (!rInfo->ns.ip.v4.NotAnInteger) { LogMsg("SendServiceRegistration - NS not set!"); return; }
+
        id = newMessageID(u);
        InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
 
        // setup resource records
-       SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0);  
+       SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0);
        SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0);
        
        // replace port w/ NAT mapping if necessary
@@ -3770,47 +3932,58 @@ mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
        
        if (srs->uDNS_info.TestForSelfConflict)
                {
-               // update w/ prereq that records already exist to make sure previous registration was ours
+               // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records
                if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0))) goto error;
-               if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numPrereqs, &srs->RR_TXT.resrec, 0))) goto error;
+               if (!(ptr = putDeleteRRSet(&msg, ptr, srs->RR_TXT.resrec.name, srs->RR_TXT.resrec.rrtype)))       goto error;
                }
        
-       else if (srs->uDNS_info.state != regState_Refresh)
+       else if (srs->uDNS_info.state != regState_Refresh && srs->uDNS_info.state != regState_UpdatePending)
                {
                // use SRV name for prereq
-               ptr = putPrereqNameNotInUse(&srv->resrec.name, &msg, ptr, end);
+               ptr = putPrereqNameNotInUse(srv->resrec.name, &msg, ptr, end);
                if (!ptr) goto error;
                }
        
        //!!!KRS  Need to do bounds checking and use TCP if it won't fit!!!
        if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_PTR.resrec, srs->RR_PTR.resrec.rroriginalttl))) goto error;
-       if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error;
+
+       for (i = 0; i < srs->NumSubTypes; i++)
+               if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->SubTypes[i].resrec, srs->SubTypes[i].resrec.rroriginalttl))) goto error;
+       
+       if (rInfo->state == regState_UpdatePending)
+               {
+               // we're updating the txt record - delete old, add new
+               if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_TXT.resrec))) goto error;  // delete old rdata
+               SwapRData(m, &srs->RR_TXT, mDNSfalse); // add the new rdata
+               if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error;
+               SwapRData(m, &srs->RR_TXT, mDNSfalse); // replace old rdata in case we need to retransmit
+               }
+       else
+               if (!(ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) goto error;
 
         if (!GetServiceTarget(u, srv, &target))
                {
-               debugf("Couldn't get target for service %##s", srv->resrec.name.c);
-               rInfo->state = regState_NoTarget;               
+               debugf("Couldn't get target for service %##s", srv->resrec.name->c);
+               rInfo->state = regState_NoTarget;
                return;
-               }       
-       if (!SameDomainName(&target, &srv->resrec.rdata->u.srv.target))
-               {
-               AssignDomainName(srv->resrec.rdata->u.srv.target, target);
-               SetNewRData(&srv->resrec, mDNSNULL, 0);
                }
 
+        if (!SameDomainName(&target, &srv->resrec.rdata->u.srv.target))
+                {
+                AssignDomainName(&srv->resrec.rdata->u.srv.target, &target);
+                SetNewRData(&srv->resrec, mDNSNULL, 0);
+                }
+
        ptr = PutResourceRecordTTLJumbo(&msg, ptr, &msg.h.mDNS_numUpdates, &srv->resrec, srv->resrec.rroriginalttl);
        if (!ptr) goto error;
-       // !!!KRS do subtypes/extras etc.
 
        if (srs->uDNS_info.lease)
-               { ptr = putUpdateLease(&msg, ptr, kLLQ_DefLease); if (!ptr) goto error; }
+               { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; }
           
-       srs->uDNS_info.expire = -1;
-
        err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rInfo->ns, rInfo->port, -1, GetAuthInfoForZone(u, &rInfo->zone));
        if (err) { LogMsg("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %ld", err); goto error; }
 
-       if (rInfo->state != regState_Refresh)
+       if (rInfo->state != regState_Refresh && rInfo->state != regState_DeregDeferred && srs->uDNS_info.state != regState_UpdatePending)
                rInfo->state = regState_Pending;
 
        SetRecordRetry(m, &srs->RR_SRV);
@@ -3820,21 +3993,20 @@ mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
 
 error:
        LogMsg("SendServiceRegistration - Error formatting message");
-       if (mapped) srv->resrec.rdata->u.srv.port = privport;   
-       unlinkSRS(u, srs);
+       if (mapped) srv->resrec.rdata->u.srv.port = privport;
+       unlinkSRS(m, srs);
        rInfo->state = regState_Unregistered;
        m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
        srs->ServiceCallback(m, srs, err);
        m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
        //!!!KRS will mem still be free'd on error?
-       // NOTE: not safe to touch any client structures here   
+       // NOTE: not safe to touch any client structures here
        }
 
 mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srsPtr, const AsyncOpResult *result)
        {
        ServiceRecordSet *srs = (ServiceRecordSet *)srsPtr;
        const zoneData_t *zoneData = mDNSNULL;
-       uDNS_GlobalInfo *u = &m->uDNS_info;
        
        if (err) goto error;
        if (!result) { LogMsg("ERROR: serviceRegistrationCallback invoked with NULL result and no error");  goto error; }
@@ -3850,7 +4022,7 @@ mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srs
                {
                // client cancelled registration while fetching zone data
                srs->uDNS_info.state = regState_Unregistered;
-               unlinkSRS(u, srs);
+               unlinkSRS(m, srs);
                m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
                srs->ServiceCallback(m, srs, mStatus_MemFree);
                m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
@@ -3859,30 +4031,33 @@ mDNSlocal void serviceRegistrationCallback(mStatus err, mDNS *const m, void *srs
        
        if (srs->RR_SRV.resrec.rrclass != zoneData->zoneClass)
                {
-               LogMsg("Service %##s - class does not match zone", srs->RR_SRV.resrec.name.c);
+               LogMsg("Service %##s - class does not match zone", srs->RR_SRV.resrec.name->c);
                goto error;
                }
+
        // cache zone data
-       AssignDomainName(srs->uDNS_info.zone, zoneData->zoneName);
+       AssignDomainName(&srs->uDNS_info.zone, &zoneData->zoneName);
     srs->uDNS_info.ns.type = mDNSAddrType_IPv4;
        srs->uDNS_info.ns = zoneData->primaryAddr;
-       if (zoneData->updatePort.NotAnInteger) srs->uDNS_info.port = zoneData->updatePort;              
+       if (zoneData->updatePort.NotAnInteger) srs->uDNS_info.port = zoneData->updatePort;
        else
                {
                debugf("Update port not advertised via SRV - guessing port 53, no lease option");
                srs->uDNS_info.port = UnicastDNSPort;
                srs->uDNS_info.lease = mDNSfalse;
                }
-       SendServiceRegistration(m, srs);
+
+       if (srs->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger && IsPrivateV4Addr(&m->uDNS_info.PrimaryIP))
+               { srs->uDNS_info.state = regState_NATMap; StartNATPortMap(m, srs); }
+       else SendServiceRegistration(m, srs);
        return;
                
 error:
-       unlinkSRS(u, srs);
+       unlinkSRS(m, srs);
        srs->uDNS_info.state = regState_Unregistered;
        m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
        srs->ServiceCallback(m, srs, err);
        m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-       //!!!KRS will mem still be free'd on error?
        // NOTE: not safe to touch any client structures here
        }
 
@@ -3892,21 +4067,21 @@ mDNSlocal mStatus SetupRecordRegistration(mDNS *m, AuthRecord *rr)
        AuthRecord *ptr = m->uDNS_info.RecordRegistrations;
 
        while (ptr && ptr != rr) ptr = ptr->next;
-       if (ptr) { LogMsg("Error: SetupRecordRegistration - record %##s already in list!", rr->resrec.name.c); return mStatus_AlreadyRegistered; }
+       if (ptr) { LogMsg("Error: SetupRecordRegistration - record %##s already in list!", rr->resrec.name->c); return mStatus_AlreadyRegistered; }
        
        if (rr->uDNS_info.state == regState_FetchingZoneData ||
                rr->uDNS_info.state == regState_Pending ||
                rr->uDNS_info.state ==  regState_Registered)
                {
                LogMsg("Requested double-registration of physical record %##s type %d",
-                          rr->resrec.name.c, rr->resrec.rrtype);
+                          rr->resrec.name->c, rr->resrec.rrtype);
                return mStatus_AlreadyRegistered;
                }
        
        rr->resrec.rdlength   = GetRDLength(&rr->resrec, mDNSfalse);
        rr->resrec.rdestimate = GetRDLength(&rr->resrec, mDNStrue);
 
-       if (!ValidateDomainName(&rr->resrec.name))
+       if (!ValidateDomainName(rr->resrec.name))
                {
                LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr));
                return mStatus_Invalid;
@@ -3914,12 +4089,12 @@ mDNSlocal mStatus SetupRecordRegistration(mDNS *m, AuthRecord *rr)
 
        // Don't do this until *after* we've set rr->resrec.rdlength
        if (!ValidateRData(rr->resrec.rrtype, rr->resrec.rdlength, rr->resrec.rdata))
-               { 
+               {
                LogMsg("Attempt to register record with invalid rdata: %s", ARDisplayString(m, rr));
                return mStatus_Invalid;
                }
 
-       rr->resrec.namehash   = DomainNameHashValue(&rr->resrec.name);
+       rr->resrec.namehash   = DomainNameHashValue(rr->resrec.name);
        rr->resrec.rdatahash  = RDataHashValue(rr->resrec.rdlength, &rr->resrec.rdata->u);
        rr->resrec.rdnamehash = target ? DomainNameHashValue(target) : 0;
 
@@ -3935,7 +4110,7 @@ mDNSexport mStatus uDNS_RegisterRecord(mDNS *const m, AuthRecord *const rr)
        {
        mStatus err = SetupRecordRegistration(m, rr);
        if (err) return err;
-       else return startGetZoneData(&rr->resrec.name, m, mDNStrue, mDNSfalse, RecordRegistrationCallback, rr);
+       else return startGetZoneData(rr->resrec.name, m, mDNStrue, mDNSfalse, RecordRegistrationCallback, rr);
        }
 
 mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
@@ -3953,7 +4128,7 @@ mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
        if (!(ptr = putDeletionRecord(&msg, ptr, &rr->resrec))) goto error;
 
        err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &rr->uDNS_info.ns, rr->uDNS_info.port, -1, GetAuthInfoForZone(u, &rr->uDNS_info.zone));
-       if (err) LogMsg("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err); 
+       if (err) LogMsg("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %ld", err);
 
        SetRecordRetry(m, rr);
        rr->uDNS_info.state = regState_DeregPending;
@@ -3976,17 +4151,17 @@ mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
                {
                case regState_NATMap:
             // we're in the middle of a NAT traversal operation
-                       if (!n) LogMsg("uDNS_DeregisterRecord: no NAT info context");           
+                       if (!n) LogMsg("uDNS_DeregisterRecord: no NAT info context");
                        else FreeNATInfo(m, n); // cause response to outstanding request to be ignored.
-                                               // Note: normally here we're trying to determine our public address, 
-                                               //in which case there is not state to be torn down.  For simplicity, 
-                                               //we allow other operations to expire.    
+                                               // Note: normally here we're trying to determine our public address,
+                                               //in which case there is not state to be torn down.  For simplicity,
+                                               //we allow other operations to expire.
             rr->uDNS_info.NATinfo = mDNSNULL;
                        rr->uDNS_info.state = regState_Unregistered;
                        break;
                case regState_ExtraQueued:
                        rr->uDNS_info.state = regState_Unregistered;
-                       break;                  
+                       break;
                case regState_FetchingZoneData:
                        rr->uDNS_info.state = regState_Cancelled;
                        return mStatus_NoError;
@@ -3994,22 +4169,23 @@ mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
                case regState_Pending:
                case regState_UpdatePending:
                        rr->uDNS_info.state = regState_DeregDeferred;
-                       LogMsg("Deferring deregistration of record %##s until registration completes", rr->resrec.name.c);
+                       LogMsg("Deferring deregistration of record %##s until registration completes", rr->resrec.name->c);
                        return mStatus_NoError;
-               case regState_Registered:                       
+               case regState_Registered:
                case regState_DeregPending:
                        break;
                case regState_DeregDeferred:
                case regState_Cancelled:
                        LogMsg("Double deregistration of record %##s type %d",
-                                  rr->resrec.name.c, rr->resrec.rrtype);
+                                  rr->resrec.name->c, rr->resrec.rrtype);
                        return mStatus_UnknownErr;
                case regState_Unregistered:
                        LogMsg("Requested deregistration of unregistered record %##s type %d",
-                                  rr->resrec.name.c, rr->resrec.rrtype);
+                                  rr->resrec.name->c, rr->resrec.rrtype);
                        return mStatus_UnknownErr;
+               case regState_NATError:
                case  regState_NoTarget:
-                       LogMsg("ERROR: uDNS_DeregisterRecord called for record %##s with bad state (regState_NoTarget)", rr->resrec.name.c);
+                       LogMsg("ERROR: uDNS_DeregisterRecord called for record %##s with bad state %s", rr->resrec.name->c, rr->uDNS_info.state == regState_NoTarget ? "regState_NoTarget" : "regState_NATError");
                        return mStatus_UnknownErr;
                }
 
@@ -4017,7 +4193,7 @@ mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
                {
                // unlink and deliver memfree
                
-               unlinkAR(&u->RecordRegistrations, rr);          
+               unlinkAR(&u->RecordRegistrations, rr);
                m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
                if (rr->RecordCallback) rr->RecordCallback(m, rr, mStatus_MemFree);
                m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
@@ -4030,42 +4206,38 @@ mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
        SendRecordDeregistration(m, rr);
        return mStatus_NoError;
        }
-
-// register a service already in list with initialized state
-mDNSlocal mStatus RegisterService(mDNS *m, ServiceRecordSet *srs)
-       {
-       uDNS_RegInfo *info = &srs->uDNS_info;   
        
-       srs->RR_SRV.resrec.rroriginalttl = 3;
-       srs->RR_TXT.resrec.rroriginalttl = 3;
-       srs->RR_PTR.resrec.rroriginalttl = 3;
+mDNSexport mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
+       {
+       mDNSu32 i;
+       domainname target;
+       uDNS_RegInfo *info = &srs->uDNS_info;
+       ServiceRecordSet **p = &m->uDNS_info.ServiceRegistrations;
+       while (*p && *p != srs) p=&(*p)->next;
+       if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name->c); return(mStatus_AlreadyRegistered); }
+       ubzero(info, sizeof(*info));
+       *p = srs;
+       srs->next = mDNSNULL;
+
+       srs->RR_SRV.resrec.rroriginalttl = kWideAreaTTL;
+       srs->RR_TXT.resrec.rroriginalttl = kWideAreaTTL;
+       srs->RR_PTR.resrec.rroriginalttl = kWideAreaTTL;
+       for (i = 0; i < srs->NumSubTypes;i++) srs->SubTypes[i].resrec.rroriginalttl = kWideAreaTTL;
        
        info->lease = mDNStrue;
 
-       if (srs->RR_SRV.resrec.rdata->u.srv.port.NotAnInteger && MapServicePort(m))
+       srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0;
+       if (!GetServiceTarget(&m->uDNS_info, &srs->RR_SRV, &target))
                {
-               // !!!KRS if interface is already in NATState_Legacy, don't try NATPMP
-               info->state = regState_NATMap;
-               StartNATPortMap(m, srs);
+               // defer registration until we've got a target
+               LogMsg("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c);
+               info->state = regState_NoTarget;
                return mStatus_NoError;
-               }
+               }  
        
        info->state = regState_FetchingZoneData;
-       return startGetZoneData(&srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
-       }       
-       
-mDNSexport mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
-       {
-       // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
-       ServiceRecordSet **p = &m->uDNS_info.ServiceRegistrations;
-       while (*p && *p != srs) p=&(*p)->next;
-       if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name.c); return(mStatus_AlreadyRegistered); }
-       ubzero(&srs->uDNS_info, sizeof(uDNS_RegInfo));
-       srs->uDNS_info.state = regState_Unregistered;
-       *p = srs;
-       srs->next = mDNSNULL;
-       return RegisterService(m, srs);
-       }       
+       return startGetZoneData(srs->RR_SRV.resrec.name, m, mDNStrue, mDNSfalse, serviceRegistrationCallback, srs);
+       }
 
 mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
        {
@@ -4076,7 +4248,8 @@ mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
        mDNSu8 *ptr = msg.data;
        mDNSu8 *end = (mDNSu8 *)&msg + sizeof(DNSMessage);
        mStatus err = mStatus_UnknownErr;
-
+       mDNSu32 i;
+       
        id = newMessageID(u);
        InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
        
@@ -4084,9 +4257,12 @@ mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
        ptr = putZone(&msg, ptr, end, &info->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
        if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); goto error; }
                
-       if (!(ptr = putDeleteAllRRSets(&msg, ptr, &srs->RR_SRV.resrec.name))) goto error;  // this deletes SRV, TXT, and Extras
+       if (!(ptr = putDeleteAllRRSets(&msg, ptr, srs->RR_SRV.resrec.name))) goto error;  // this deletes SRV, TXT, and Extras
        if (!(ptr = putDeletionRecord(&msg, ptr, &srs->RR_PTR.resrec))) goto error;
+       for (i = 0; i < srs->NumSubTypes; i++)
+               if (!(ptr = putDeletionRecord(&msg, ptr, &srs->SubTypes[i].resrec))) goto error;
 
+       
        err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &info->ns, info->port, -1, GetAuthInfoForZone(u, &info->zone));
        if (err) { LogMsg("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %ld", err); goto error; }
 
@@ -4097,7 +4273,7 @@ mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
        return;
        
        error:
-       unlinkSRS(u, srs);
+       unlinkSRS(m, srs);
        info->state = regState_Unregistered;
        }
 
@@ -4112,28 +4288,27 @@ mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs)
        // the server when we delete all RRSets for this name
        while (*r)
                {
-               if (SameDomainName(&srs->RR_SRV.resrec.name, &(*r)->resrec.name)) *r = (*r)->next;
+               if (SameDomainName(srs->RR_SRV.resrec.name, (*r)->resrec.name)) *r = (*r)->next;
                else r = &(*r)->next;
                }
 
        // don't re-register with a new target following deregistration
-       srs->uDNS_info.LostTarget = srs->uDNS_info.SRVUpdateDeferred = mDNSfalse;
+       srs->uDNS_info.SRVChanged = srs->uDNS_info.SRVUpdateDeferred = mDNSfalse;
+
+       if (nat)
+               {
+               if (nat->state == NATState_Established || nat->state == NATState_Refresh || nat->state == NATState_Legacy)
+                       DeleteNATPortMapping(m, nat, srs);
+               nat->reg.ServiceRegistration = mDNSNULL;
+               srs->uDNS_info.NATinfo = mDNSNULL;
+               FreeNATInfo(m, nat);
+               }
        
        switch (srs->uDNS_info.state)
                {
-               case regState_NATMap:
-                       // we're in the middle of nat mapping.  clear ptr from NAT info to RR, unlink and give memfree                  
-                       if (!nat) LogMsg("uDNS_DeregisterRecord: no NAT info context");
-                       else { nat->reg.ServiceRegistration = mDNSNULL; FreeNATInfo(m, nat); }
-                       unlinkSRS(u, srs);
-                       srs->uDNS_info.state = regState_Unregistered;
-                       m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
-                       srs->ServiceCallback(m, srs, mStatus_MemFree);
-                       m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
-                       return mStatus_NoError;         
                case regState_Unregistered:
-                       errmsg = "service not registered";
-                       goto error;
+                       debugf("uDNS_DeregisterService - service %##s not registered", srs->RR_SRV.resrec.name->c);
+                       return mStatus_BadReferenceErr;
                case regState_FetchingZoneData:
                        // let the async op complete, then terminate
                        srs->uDNS_info.state = regState_Cancelled;
@@ -4147,17 +4322,18 @@ mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs)
                case regState_DeregPending:
                case regState_DeregDeferred:
                case regState_Cancelled:
-                       debugf("Double deregistration of service %##s", srs->RR_SRV.resrec.name.c);
+                       debugf("Double deregistration of service %##s", srs->RR_SRV.resrec.name->c);
                        return mStatus_NoError;
-               case regState_NoTarget:
-                       unlinkSRS(u, srs);
+               case regState_NATError:  // not registered
+               case regState_NATMap:    // not registered
+               case regState_NoTarget:  // not registered
+                       unlinkSRS(m, srs);
                        srs->uDNS_info.state = regState_Unregistered;
                        m->mDNS_reentrancy++; // Increment to allow client to legally make mDNS API calls from the callback
                        srs->ServiceCallback(m, srs, mStatus_MemFree);
                        m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
                        return mStatus_NoError;
                case regState_Registered:
-                       if (nat) DeleteNATPortMapping(m, nat, srs);                     
                        srs->uDNS_info.state = regState_DeregPending;
                        SendServiceDeregistration(m, srs);
                        return mStatus_NoError;
@@ -4171,7 +4347,6 @@ mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs)
        return mStatus_BadReferenceErr;
        }
 
-// note that the RegInfo will be either for the record, or for the parent ServiceRecordSet
 mDNSlocal void SendRecordUpdate(mDNS *m, AuthRecord *rr, uDNS_RegInfo *info)
        {
        DNSMessage msg;
@@ -4181,6 +4356,7 @@ mDNSlocal void SendRecordUpdate(mDNS *m, AuthRecord *rr, uDNS_RegInfo *info)
        mDNSOpaque16 id;
        mStatus err = mStatus_UnknownErr;
        
+       if (info != &rr->uDNS_info) LogMsg("ERROR: SendRecordUpdate - incorrect info struct!");
        rr->uDNS_info.UpdateQueued = mDNSfalse;  // if this was queued, clear flag
        id = newMessageID(u);
        InitializeDNSMessage(&msg.h, id, UpdateReqFlags);
@@ -4201,13 +4377,13 @@ mDNSlocal void SendRecordUpdate(mDNS *m, AuthRecord *rr, uDNS_RegInfo *info)
        if (!ptr) goto error;         // (rdata gets changed permanently on success)
 
        if (info->lease)
-               { ptr = putUpdateLease(&msg, ptr, kLLQ_DefLease); if (!ptr) goto error; }
+               { ptr = putUpdateLease(&msg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) goto error; }
        
        // don't report send errors - retransmission will occurr if necessary
        err = mDNSSendDNSMessage(m, &msg, ptr, mDNSInterface_Any, &info->ns, info->port, -1, GetAuthInfoForZone(u, &info->zone));
        if (err) debugf("ERROR: sendRecordRegistration - mDNSSendDNSMessage - %ld", err);
 
-       //!!! Update this when we implement retransmission for services 
+       //!!! Update this when we implement retransmission for services
        SetRecordRetry(m, rr);
        
        rr->uDNS_info.state = regState_UpdatePending;
@@ -4216,7 +4392,7 @@ mDNSlocal void SendRecordUpdate(mDNS *m, AuthRecord *rr, uDNS_RegInfo *info)
 
 error:
        LogMsg("ERROR: SendRecordUpdate.  Error formatting update message.");
-       info ->state = regState_Registered;  
+       info ->state = regState_Registered;
        }
 
 mDNSexport mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra)
@@ -4226,7 +4402,7 @@ mDNSexport mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
        extra->r.resrec.RecordType = kDNSRecordTypeShared;  // don't want it to conflict with the service name
        extra->r.RecordCallback = mDNSNULL;  // don't generate callbacks for extra RRs
        
-       if (sr->uDNS_info.state == regState_Registered || sr->uDNS_info.state == regState_Refresh)      
+       if (sr->uDNS_info.state == regState_Registered || sr->uDNS_info.state == regState_Refresh)
                err = uDNS_RegisterRecord(m, &extra->r);
        else
                {
@@ -4280,7 +4456,7 @@ mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
                case regState_FetchingZoneData:
                case regState_NATMap:
                case regState_ExtraQueued:
-                       // change rdata directly since it hasn't been sent yet                  
+                       // change rdata directly since it hasn't been sent yet
                        SwapRData(m, rr, mDNStrue);
                        return mStatus_NoError;
                        
@@ -4292,16 +4468,19 @@ mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
                        return mStatus_NoError;
                        
                case regState_Registered:
-                       SendRecordUpdate(m, rr, info);
+                       if (parent) { info->state = regState_UpdatePending; SendServiceRegistration(m, parent); }
+                       else SendRecordUpdate(m, rr, info);                             
                        return mStatus_NoError;
 
+               case regState_NATError:
                case regState_NoTarget:
-                       LogMsg("Bad state (regState_NoTarget)"); return mStatus_UnknownErr;  // state for service records only
+                       LogMsg("ERROR: uDNS_UpdateRecord called for record %##s with bad state %s", rr->resrec.name->c, rr->uDNS_info.state == regState_NoTarget ? "regState_NoTarget" : "regState_NATError");
+                       return mStatus_UnknownErr;  // states for service records only
                }
 
        unreg_error:
        LogMsg("Requested update of record %##s type %d, part of service not currently registered",
-                  rr->resrec.name.c, rr->resrec.rrtype);
+                  rr->resrec.name->c, rr->resrec.rrtype);
        return mStatus_Invalid;
        }
 
@@ -4324,16 +4503,19 @@ mDNSlocal mDNSs32 CheckNATMappings(mDNS *m, mDNSs32 timenow)
                {
                cur = ptr;
                ptr = ptr->next;
-               if (cur->retry - timenow < 0)
+               if (cur->op != NATOp_AddrRequest || cur->state != NATState_Established)  // no refresh necessary for established Add requests
                        {
-                       if (cur->state == NATState_Established) RefreshNATMapping(cur, m);
-                       else if (cur->state == NATState_Request || cur->state == NATState_Refresh)
+                       if (cur->retry - timenow < 0)
                                {
-                               if (cur->ntries >= NATMAP_MAX_TRIES) cur->ReceiveResponse(cur, m, mDNSNULL, 0); // may invalidate "cur"
-                               else SendNATMsg(cur, m);
+                               if (cur->state == NATState_Established) RefreshNATMapping(cur, m);
+                               else if (cur->state == NATState_Request || cur->state == NATState_Refresh)
+                                       {
+                                       if (cur->ntries >= NATMAP_MAX_TRIES) cur->ReceiveResponse(cur, m, mDNSNULL, 0); // may invalidate "cur"
+                                       else SendNATMsg(cur, m);
+                                       }
                                }
+                       else if (cur->retry - nextevent < 0) nextevent = cur->retry;
                        }
-               else if (cur->retry - nextevent < 0) nextevent = cur->retry;
                }
        return nextevent;
        }
@@ -4353,16 +4535,16 @@ mDNSlocal mDNSs32 CheckQueries(mDNS *m, mDNSs32 timenow)
        u->CurrentQuery = u->ActiveQueries;
        while (u->CurrentQuery)
                {
-               q = u->CurrentQuery;            
+               q = u->CurrentQuery;
                info = &q->uDNS_info;
                llq = info->llq;
                
-               if (!info->internal && ((!q->LongLived && !info->Answered) || (llq && llq->state < LLQ_Established)) && 
+               if (!info->internal && ((!q->LongLived && !info->Answered) || (llq && llq->state < LLQ_Established)) &&
                        info->RestartTime + RESTART_GOODBYE_DELAY - timenow < 0)
                        {
                        // if we've been spinning on restart setup, and we have known answers, give goodbyes (they may be re-added later)
                        while (info->knownAnswers)
-                               {                                               
+                               {
                                CacheRecord *cr = info->knownAnswers;
                                info->knownAnswers = info->knownAnswers->next;
                                
@@ -4371,26 +4553,26 @@ mDNSlocal mDNSs32 CheckQueries(mDNS *m, mDNSs32 timenow)
                                m->mDNS_reentrancy--; // Decrement to block mDNS API calls again
                                ufree(cr);
                                if (q != u->CurrentQuery) { debugf("CheckQueries - question removed via callback."); break; }
-                               }                                                                                       
+                               }
                        }
                if (q != u->CurrentQuery) continue;
                
                if (q->LongLived && llq->state != LLQ_Poll)
-                       {                       
+                       {
                        if (llq->state >= LLQ_InitialRequest && llq->state <= LLQ_Established)
                                {
-                               if (llq->retry - timenow < 0)                           
+                               if (llq->retry - timenow < 0)
                                        {
                                        // sanity check to avoid packet flood bugs
-                                       if (!llq->retry) 
+                                       if (!llq->retry)
                                                LogMsg("ERROR: retry timer not set for LLQ %##s in state %d", q->qname.c, llq->state);
                                        else if (llq->state == LLQ_Established || llq->state == LLQ_Refresh)
                                                sendLLQRefresh(m, q, llq->origLease);
-                                       else if (llq->state == LLQ_InitialRequest)                                              
+                                       else if (llq->state == LLQ_InitialRequest)
                                                startLLQHandshake(m, llq, mDNSfalse);
                                        else if (llq->state == LLQ_SecondaryRequest)
                                                sendChallengeResponse(m, q, mDNSNULL);
-                                       else if (llq->state == LLQ_Retry) 
+                                       else if (llq->state == LLQ_Retry)
                                                { llq->ntries = 0; startLLQHandshake(m, llq, mDNSfalse); }
                                        }
                                else if (llq->retry - nextevent < 0) nextevent = llq->retry;
@@ -4432,35 +4614,35 @@ mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m, mDNSs32 timenow)
        //!!!KRS list should be pre-sorted by expiration
        for (rr = u->RecordRegistrations; rr; rr = rr->next)
                {
-               rInfo = &rr->uDNS_info;         
+               rInfo = &rr->uDNS_info;
                if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_UpdatePending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh)
                        {
                        if (rr->LastAPTime + rr->ThisAPInterval - timenow < 0)
                                {
-#if MDNS_DEBUGMSGS                             
+#if MDNS_DEBUGMSGS
                                char *op = "(unknown operation)";
                                if (rInfo->state == regState_Pending) op = "registration";
                                else if (rInfo->state == regState_DeregPending) op = "deregistration";
                                else if (rInfo->state == regState_Refresh) op = "refresh";
-                               debugf("Retransmit record %s %##s", op, rr->resrec.name.c);
+                               debugf("Retransmit record %s %##s", op, rr->resrec.name->c);
 #endif
-                               //LogMsg("Retransmit record %##s", rr->resrec.name.c);
+                               //LogMsg("Retransmit record %##s", rr->resrec.name->c);
                                if      (rInfo->state == regState_DeregPending)   SendRecordDeregistration(m, rr);
                                else if (rInfo->state == regState_UpdatePending)  SendRecordUpdate(m, rr, rInfo);
                                else                                              sendRecordRegistration(m, rr);
                                }
                        if (rr->LastAPTime + rr->ThisAPInterval - nextevent < 0) nextevent = rr->LastAPTime + rr->ThisAPInterval;
                        }
-               if (rInfo->lease && rInfo->state == regState_Registered && rInfo->expire > 0)
-                   {               
+               if (rInfo->lease && rInfo->state == regState_Registered)
+                   {
                    if (rInfo->expire - timenow < 0)
                        {
-                       debugf("refreshing record %##s", rr->resrec.name.c);
+                       debugf("refreshing record %##s", rr->resrec.name->c);
                        rInfo->state = regState_Refresh;
                        sendRecordRegistration(m, rr);
                        }
                    if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
-                   }           
+                   }
                }
        return nextevent;
        }
@@ -4480,34 +4662,35 @@ mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m, mDNSs32 timenow)
                s = s->next;
                
                rInfo = &srs->uDNS_info;        
-               if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh)
+               if (rInfo->state == regState_Pending || rInfo->state == regState_DeregPending || rInfo->state == regState_DeregDeferred || rInfo->state == regState_Refresh  || rInfo->state == regState_UpdatePending)
                        {
                        if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - timenow < 0)
                                {
-#if MDNS_DEBUGMSGS                             
+#if MDNS_DEBUGMSGS
                                char *op = "unknown";
                                if (rInfo->state == regState_Pending) op = "registration";
                                else if (rInfo->state == regState_DeregPending) op = "deregistration";
                                else if (rInfo->state == regState_Refresh) op = "refresh";
-                               debugf("Retransmit service %s %##s", op, srs->RR_SRV.resrec.name.c);
+                               else if (rInfo->state == regState_UpdatePending) op = "txt record update";
+                               debugf("Retransmit service %s %##s", op, srs->RR_SRV.resrec.name->c);
 #endif
                                if (rInfo->state == regState_DeregPending) { SendServiceDeregistration(m, srs); continue; }
                                else                                         SendServiceRegistration  (m, srs);
                                }
                        if (nextevent - srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval > 0)
                                nextevent = srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval;
-                       }                       
+                       }
 
-               if (rInfo->lease && rInfo->state == regState_Registered && rInfo->expire > 0)
-                   {               
+               if (rInfo->lease && rInfo->state == regState_Registered)
+                   {
                    if (rInfo->expire - timenow < 0)
-                       {       
-                           debugf("refreshing service %##s", srs->RR_SRV.resrec.name.c);
+                       {
+                           debugf("refreshing service %##s", srs->RR_SRV.resrec.name->c);
                            rInfo->state = regState_Refresh;
                            SendServiceRegistration(m, srs);
                        }
                    if (rInfo->expire - nextevent < 0) nextevent = rInfo->expire;
-                   }           
+                   }
                }
        return nextevent;
        }
@@ -4515,9 +4698,15 @@ mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m, mDNSs32 timenow)
 mDNSexport void uDNS_Execute(mDNS *const m)
        {
        uDNS_GlobalInfo *u = &m->uDNS_info;
-       mDNSs32 nexte, timenow = mDNSPlatformTimeNow(m);        
+       mDNSs32 nexte, timenow = mDNSPlatformTimeNow(m);
 
        u->nextevent = timenow + MIN_UCAST_PERIODIC_EXEC;
+
+       if (u->DelaySRVUpdate && u->NextSRVUpdate - timenow < 0)
+               {
+               u->DelaySRVUpdate = mDNSfalse;
+               UpdateSRVRecords(m);
+               }
        
        nexte = CheckNATMappings(m, timenow);
        if (nexte - u->nextevent < 0) u->nextevent = nexte;
@@ -4588,8 +4777,8 @@ mDNSlocal void RestartQueries(mDNS *m)
                q->uDNS_info.Answered = mDNSfalse;
                if (q->LongLived)
                        {
-                       if (!llqInfo) { LogMsg("Error: RestartQueries - %##s long-lived with NULL info", q->qname.c); continue; } 
-                       if (llqInfo->state == LLQ_Suspended || llqInfo->state == LLQ_NatMapWait)                
+                       if (!llqInfo) { LogMsg("Error: RestartQueries - %##s long-lived with NULL info", q->qname.c); continue; }
+                       if (llqInfo->state == LLQ_Suspended || llqInfo->state == LLQ_NatMapWait)
                                {
                                llqInfo->ntries = -1;
                                llqInfo->deriveRemovesOnResume = mDNStrue;
@@ -4640,7 +4829,7 @@ mDNSlocal void SleepRecordRegistrations(mDNS *m)
        mDNSs32 timenow = mDNSPlatformTimeNow(m);
 
        while (rr)
-               {               
+               {
                if (rr->uDNS_info.state == regState_Registered ||
                        rr->uDNS_info.state == regState_Refresh)
                        {
@@ -4649,7 +4838,7 @@ mDNSlocal void SleepRecordRegistrations(mDNS *m)
                        
                        // construct deletion update
                        ptr = putZone(&msg, ptr, end, &rr->uDNS_info.zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
-                       if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put zone"); return; }                   
+                       if (!ptr) { LogMsg("Error: SleepRecordRegistrations - could not put zone"); return; }
                        ptr = putDeletionRecord(&msg, ptr, &rr->resrec);
                        if (!ptr) {  LogMsg("Error: SleepRecordRegistrations - could not put deletion record"); return; }
 
@@ -4692,7 +4881,7 @@ mDNSlocal void SleepServiceRegistrations(mDNS *m)
                        srs->uDNS_info.state = regState_DeregPending;  // state expected by SendDereg()
                        SendServiceDeregistration(m, srs);
                        srs->uDNS_info.id = origid;
-                       srs->uDNS_info.state = regState_Refresh;                        
+                       srs->uDNS_info.state = regState_Refresh;
                        srs->RR_SRV.LastAPTime = timenow;
                        srs->RR_SRV.ThisAPInterval = 300 * mDNSPlatformOneSecond;
                        }
index 20edb2d4faf98c4f49cae848abc5f8ddb27781b0..7ae7f3cc9c9285e8d79e783c30d0e425e6811573 100755 (executable)
     Change History (most recent first):
 
 $Log: uDNS.h,v $
+Revision 1.29  2005/01/11 22:50:53  ksekar
+Fixed constant naming (was using kLLQ_DefLease for update leases)
+
+Revision 1.28  2004/12/22 00:13:49  ksekar
+<rdar://problem/3873993> Change version, port, and polling interval for LLQ
+
 Revision 1.27  2004/11/23 04:06:50  cheshire
 Get rid of floating point constant -- in a small embedded device, bringing in all
 the floating point libraries just to halve an integer value is a bit too heavyweight.
@@ -126,10 +132,11 @@ Revision 1.1  2003/12/13 03:05:27  ksekar
 #define MIN_UCAST_PERIODIC_EXEC (5 * mDNSPlatformOneSecond)    
 #define INIT_UCAST_POLL_INTERVAL mDNSPlatformOneSecond      // this interval is used after send failures on network transitions
                                                                // which typically heal quickly, so we start agressively and exponentially back off
-#define MAX_UCAST_POLL_INTERVAL (15 * 60 * mDNSPlatformOneSecond)
+#define MAX_UCAST_POLL_INTERVAL (60 * 60 * mDNSPlatformOneSecond)
 #define RESPONSE_WINDOW (60 * mDNSPlatformOneSecond)        // require server responses within one minute of request
 #define UPDATE_PORT_NAME "_dns-update._udp."
 #define LLQ_PORT_NAME "_dns-llq._udp"
+#define DEFAULT_UPDATE_LEASE 7200
        
 // Entry points into unicast-specific routines
 
index cf0386220a517a0e8227799d136c409e62f86b5e..76a426c232fd729f276d3923a03c840074e8c2a2 100644 (file)
@@ -23,6 +23,9 @@
     Change History (most recent first):
 
 $Log: Mac\040OS\040Test\040Responder.c,v $
+Revision 1.24  2004/12/16 20:49:34  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
 Revision 1.23  2004/09/17 01:08:50  cheshire
 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
   The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
@@ -80,10 +83,10 @@ mDNSlocal void Callback(mDNS *const m, ServiceRecordSet *const sr, mStatus resul
        {
        switch (result)
                {
-               case mStatus_NoError:      debugf("Callback: %##s Name Registered",   sr->RR_SRV.resrec.name.c); break;
-               case mStatus_NameConflict: debugf("Callback: %##s Name Conflict",     sr->RR_SRV.resrec.name.c); break;
-               case mStatus_MemFree:      debugf("Callback: %##s Memory Free",       sr->RR_SRV.resrec.name.c); break;
-               default:                   debugf("Callback: %##s Unknown Result %d", sr->RR_SRV.resrec.name.c, result); break;
+               case mStatus_NoError:      debugf("Callback: %##s Name Registered",   sr->RR_SRV.resrec.name->c); break;
+               case mStatus_NameConflict: debugf("Callback: %##s Name Conflict",     sr->RR_SRV.resrec.name->c); break;
+               case mStatus_MemFree:      debugf("Callback: %##s Memory Free",       sr->RR_SRV.resrec.name->c); break;
+               default:                   debugf("Callback: %##s Unknown Result %d", sr->RR_SRV.resrec.name->c, result); break;
                }
 
        if (result == mStatus_NameConflict) mDNS_RenameAndReregisterService(m, sr, mDNSNULL);
@@ -119,7 +122,7 @@ mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset,
                mDNSInterface_Any,                                                      // Interface ID
                Callback, mDNSNULL);                                            // Callback and context
 
-       ConvertDomainNameToCString(&recordset->RR_SRV.resrec.name, buffer);
+       ConvertDomainNameToCString(recordset->RR_SRV.resrec.name, buffer);
        printf("Made Service Records for %s\n", buffer);
        }
 
index f2fb9ce924d8e1b088030ca87e25aebdc85d5ff0..fd28def8dfbdf487b7fff750f487d897c5a6550b 100644 (file)
@@ -23,6 +23,9 @@
     Change History (most recent first):
 
 $Log: Mac\040OS\040Test\040Searcher.c,v $
+Revision 1.21  2004/12/16 20:49:34  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
 Revision 1.20  2004/10/19 21:33:18  cheshire
 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
@@ -78,7 +81,7 @@ typedef struct { ServiceInfo i; mDNSBool add; mDNSBool dom; OTLink link; } linke
 // These don't have to be globals, but their memory does need to remain valid for as
 // long as the search is going on. They are declared as globals here for simplicity.
 #define RR_CACHE_SIZE 1000
-static CacheRecord rrcachestorage[RR_CACHE_SIZE];
+static CacheEntity rrcachestorage[RR_CACHE_SIZE];
 static mDNS mDNSStorage;
 static mDNS_PlatformSupport PlatformSupportStorage;
 static SearcherServices services;
@@ -156,7 +159,7 @@ static void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRe
        SearcherServices *services = (SearcherServices *)question->QuestionContext;
        linkedServiceInfo *info;
 
-       debugf("FoundInstance %##s PTR %##s", answer->name.c, answer->rdata->u.name.c);
+       debugf("FoundInstance %##s PTR %##s", answer->name->c, answer->rdata->u.name.c);
 
        if (answer->rrtype != kDNSType_PTR) return;
        if (!services) { debugf("FoundInstance: services is NULL"); return; }
@@ -189,7 +192,7 @@ static void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceReco
        SearcherServices *services = (SearcherServices *)question->QuestionContext;
        linkedServiceInfo *info;
 
-       debugf("FoundDomain %##s PTR %##s", answer->name.c, answer->rdata->u.name.c);
+       debugf("FoundDomain %##s PTR %##s", answer->name->c, answer->rdata->u.name.c);
 
        if (answer->rrtype != kDNSType_PTR) return;
        if (!services) { debugf("FoundDomain: services is NULL"); return; }
index 7c153a319d225859a08453e92e969d6fd90dedc0..2206b225be4896e7f7574f37fa3c2b768baecb55 100644 (file)
@@ -23,6 +23,9 @@
     Change History (most recent first):
 
 $Log: SubTypeTester.c,v $
+Revision 1.6  2004/12/16 20:49:35  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
 Revision 1.5  2004/09/17 01:08:50  cheshire
 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
   The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
@@ -111,7 +114,7 @@ mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset,
                mDNSInterface_Any,                                                      // Interface ID
                Callback, mDNSNULL);                                            // Callback and context
 
-       ConvertDomainNameToCString(&recordset->RR_SRV.resrec.name, buffer);
+       ConvertDomainNameToCString(recordset->RR_SRV.resrec.name, buffer);
        printf("Made Service Records for %s\n", buffer);
        }
 
@@ -162,8 +165,8 @@ mDNSlocal OSStatus mDNSResponderSetAvail(mDNS *m, AuthRecord *rr, ServiceRecordS
        // 3. Set target of subtype PTR record to point to our SRV record (exactly the same as the main service PTR record)
        // 4. And register it
        mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_Any, kDNSType_PTR, 2*3600, kDNSRecordTypeShared, AvailCallback, &availRec2Active);
-       MakeDomainNameFromDNSNameString(&rr->resrec.name, "a._sub._raop._tcp.local.");
-       AssignDomainName(rr->resrec.rdata->u.name, sr->RR_SRV.resrec.name);
+       MakeDomainNameFromDNSNameString(rr->resrec.name, "a._sub._raop._tcp.local.");
+       AssignDomainName(&rr->resrec.rdata->u.name, sr->RR_SRV.resrec.name);
        return(mDNS_Register(m, rr));
        }
 
index 13dc10a6db72573ae6ec12d922cb17f2b1321259..d385cb45ee978468b3dccd64aad0b717a832aaaa 100644 (file)
@@ -23,6 +23,9 @@
     Change History (most recent first):
 
 $Log: mDNSLibrary.c,v $
+Revision 1.3  2004/12/16 20:49:35  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
 Revision 1.2  2004/09/17 01:08:50  cheshire
 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
   The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
@@ -42,18 +45,17 @@ like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code
 
 mDNS mDNSStorage;
 static mDNS_PlatformSupport PlatformSupportStorage;
-#define RR_CACHE_SIZE 64
-static CacheRecord rrcachestorage[RR_CACHE_SIZE];
+// Start off with a default cache of 16K (about 100 records)
+#define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord))
+static CacheEntity rrcachestorage[RR_CACHE_SIZE];
 
 mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
        {
        if (result == mStatus_GrowCache)
                {
-               // If we've run out of cache space, then double the total cache size and give the memory to mDNSCore
-               mDNSu32 numrecords = m->rrcache_size;
-               CacheRecord *storage = OTAllocMem(sizeof(CacheRecord) * numrecords);
-               LogMsg("mStatus_GrowCache %d", numrecords);
-               if (storage) mDNS_GrowCache(m, storage, numrecords);
+               // Allocate another chunk of cache storage
+               CacheEntity *storage = OTAllocMem(sizeof(CacheEntity) * RR_CACHE_SIZE);
+               if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE);
                }
        }
 
index b699ed5de3eb9f8ded7137e3a60b12507b472784..d69b739f78a54a3905a83944558023e1ecc96530 100644 (file)
     Change History (most recent first):
 
 $Log: mDNSLibraryResources.r,v $
+Revision 1.25  2005/01/28 00:04:16  cheshire
+mDNSResponder-98
+
+Revision 1.24  2005/01/22 01:15:14  ksekar
+Update version string to 1.0a97
+
+Revision 1.23  2005/01/13 19:50:17  ksekar
+Update version string to 1.0a94
+
+Revision 1.22  2005/01/10 16:33:26  ksekar
+Update version string to 1.0a93
+
+Revision 1.21  2004/12/23 23:50:59  ksekar
+Update version string to 1.0a92
+
+Revision 1.20  2004/12/20 23:26:47  cheshire
+mDNSResponder-90
+
+Revision 1.19  2004/12/16 20:52:38  cheshire
+mDNSResponder-89
+
+Revision 1.18  2004/12/15 20:25:49  cheshire
+mDNSResponder-88
+
 Revision 1.17  2004/12/13 21:54:30  cheshire
 mDNSResponder-87
 
@@ -92,15 +116,15 @@ like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code
 
 resource 'vers' (1, purgeable)
        {
-   0x01, 0x00, alpha, 87, verUS,
-   "1.0a87",
-   "Multicast DNS & DNS Service Discovery 1.0a87"
+   0x01, 0x00, alpha, 98, verUS,
+   "1.0a98",
+   "Multicast DNS & DNS Service Discovery 1.0a98"
        };
 
 resource 'vers' (2, purgeable)
        {
-   0x01, 0x00, alpha, 87, verUS,
-   "1.0a87",
+   0x01, 0x00, alpha, 98, verUS,
+   "1.0a98",
    "developer.apple.com/darwin/projects/rendezvous/"
        };
 
index d38facc59e39af66c76ba30605aef0e2bd86d0af..61da0a088156bb506e5b3b72b0168709275b53e2 100644 (file)
     Change History (most recent first):
 
 $Log: mDNSMacOS9.c,v $
+Revision 1.43  2004/12/17 23:37:49  cheshire
+<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
+(and other repetitive configuration changes)
+
+Revision 1.42  2004/12/16 20:43:39  cheshire
+interfaceinfo.fMask should be interfaceinfo.fNetmask
+
 Revision 1.41  2004/10/16 00:17:00  cheshire
 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
 
@@ -368,7 +375,7 @@ mDNSlocal pascal void mDNSNotifier(void *contextPtr, OTEventCode code, OTResult
                        m->p->interface.ip  .type               = mDNSAddrType_IPv4;
                        m->p->interface.ip  .ip.v4.NotAnInteger = interfaceinfo.fAddress;
                        m->p->interface.mask.type               = mDNSAddrType_IPv4;
-                       m->p->interface.mask.ip.v4.NotAnInteger = interfaceinfo.fMask;
+                       m->p->interface.mask.ip.v4.NotAnInteger = interfaceinfo.fNetmask;
                        m->p->interface.ifname[0]               = 0;
                        m->p->interface.Advertise               = m->AdvertiseLocalAddresses;
                        m->p->interface.McastTxRx               = mDNStrue;
@@ -396,7 +403,7 @@ mDNSlocal pascal void mDNSNotifier(void *contextPtr, OTEventCode code, OTResult
                                case mOT_Bind:                  OTBind(m->p->ep, (TBind*)&mDNSbindReq, NULL); break;
                                case mOT_Ready:         mDNSinitComplete(m, mStatus_NoError);
                                                                                // Can't do mDNS_RegisterInterface until *after* mDNSinitComplete has set m->mDNSPlatformStatus to mStatus_NoError
-                                                                               mDNS_RegisterInterface(m, &m->p->interface);
+                                                                               mDNS_RegisterInterface(m, &m->p->interface, 0);
                                                                                break;
                                default:                LogMsg("Unexpected m->p->mOTstate %d", m->p->mOTstate-1);
                                }
diff --git a/mDNSMacOSX/LaunchDaemonInfo.plist b/mDNSMacOSX/LaunchDaemonInfo.plist
new file mode 100644 (file)
index 0000000..e91b775
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>Label</key>
+       <string>com.apple.mDNSResponder</string>
+       <key>OnDemand</key>
+       <false/>
+       <key>ProgramArguments</key>
+       <array>
+                       <string>/usr/sbin/mDNSResponder</string>
+                       <string>-launchdaemon</string>
+       </array>
+       <key>ServiceIPC</key>
+       <false/>
+</dict>
+</plist>
index e82657ed6ed733c65d812534a8ddad1f604282d6..d977a4adedd3fa2306403d8ba4ffbbbc78a6af06 100644 (file)
     Change History (most recent first):
 
 $Log: daemon.c,v $
+Revision 1.244  2005/01/28 00:34:49  cheshire
+Turn off "Starting time value" log message
+
+Revision 1.243  2005/01/27 17:46:58  cheshire
+Added comment about CFSocketInvalidate closing the underlying socket
+
+Revision 1.242  2005/01/27 00:10:58  cheshire
+<rdar://problem/3967867> Name change log messages every time machine boots
+
+Revision 1.241  2005/01/25 17:28:06  ksekar
+<rdar://problem/3971467> Should not return "local" twice for domain enumeration
+
+Revision 1.240  2005/01/21 02:39:18  cheshire
+Rename FoundDomain() to DomainEnumFound() to avoid order-file symbol clash with other routine called FoundDomain()
+
+Revision 1.239  2005/01/20 00:25:01  cheshire
+Improve validatelists() log message generation
+
+Revision 1.238  2005/01/19 19:15:35  ksekar
+Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
+
+Revision 1.237  2005/01/19 03:33:09  cheshire
+<rdar://problem/3945652> When changing Computer Name, we drop our own Goobye Packets
+
+Revision 1.236  2005/01/19 03:16:38  cheshire
+<rdar://problem/3961051> CPU Spin in mDNSResponder
+Improve detail of "Task Scheduling Error" diagnostic messages
+
+Revision 1.235  2005/01/15 00:56:41  ksekar
+<rdar://problem/3954575> Unicast services don't disappear when logging
+out of VPN
+
+Revision 1.234  2005/01/10 03:42:30  ksekar
+Clarify debugf
+
+Revision 1.233  2004/12/18 00:53:46  cheshire
+Use symbolic constant mDNSInterface_LocalOnly instead of (mDNSInterfaceID)~0
+
+Revision 1.232  2004/12/17 23:37:48  cheshire
+<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
+(and other repetitive configuration changes)
+
+Revision 1.231  2004/12/17 04:13:38  cheshire
+Removed debugging check
+
+Revision 1.230  2004/12/17 04:09:30  cheshire
+<rdar://problem/3191011> Switch mDNSResponder to launchd
+
+Revision 1.229  2004/12/16 21:51:36  cheshire
+Remove some startup messages
+
+Revision 1.228  2004/12/16 20:13:01  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
 Revision 1.227  2004/12/10 13:52:57  cheshire
 <rdar://problem/3909995> Turn off SIGPIPE signals
 
@@ -510,7 +564,7 @@ Add $Log header
 #include "DNSServiceDiscoveryRequestServer.h"
 #include "DNSServiceDiscoveryReply.h"
 
-#include "mDNSEmbeddedAPI.h"                   // Defines the interface to the client layer above
+#include "DNSCommon.h"
 #include "mDNSMacOSX.h"                                // Defines the specific types needed to run mDNS on this platform
 
 #include "uds_daemon.h"                                // Interface to the server side implementation of dns_sd.h
@@ -534,8 +588,10 @@ Add $Log header
 #define LOCAL_DEFAULT_REG 1 // empty string means register in the local domain
 #define DEFAULT_REG_DOMAIN "apple.com." // used if the above flag is turned off
 static mDNS_PlatformSupport PlatformStorage;
-#define RR_CACHE_SIZE 64
-static CacheRecord rrcachestorage[RR_CACHE_SIZE];
+
+// Start off with a default cache of 16K (about 100 records)
+#define RR_CACHE_SIZE ((16*1024) / sizeof(CacheRecord))
+static CacheEntity rrcachestorage[RR_CACHE_SIZE];
 
 static const char kmDNSBootstrapName[] = "com.apple.mDNSResponderRestart";
 static mach_port_t client_death_port = MACH_PORT_NULL;
@@ -551,6 +607,7 @@ static mach_port_t server_priv_port  = MACH_PORT_NULL;
 #define MDNS_MM_TIMEOUT 250
 
 static int restarting_via_mach_init = 0;
+static int started_via_launchdaemon = 0;
 
 //*************************************************************************************************************
 // Active client list structures
@@ -657,6 +714,7 @@ static void validatelists(mDNS *const m)
        DNSServiceResolver          *l;
        DNSServiceRegistration      *r;
        AuthRecord                  *rr;
+       CacheGroup                  *cg;
        CacheRecord                 *cr;
        DNSQuestion                 *q;
        mDNSu32 slot;
@@ -679,8 +737,13 @@ static void validatelists(mDNS *const m)
                        LogMsg("!!!! DNSServiceRegistrationList: %p is garbage (%X) !!!!", r, r->ClientMachPort);
 
        for (rr = m->ResourceRecords; rr; rr=rr->next)
+               {
                if (rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
                        LogMsg("!!!! ResourceRecords list: %p is garbage (%X) !!!!", rr, rr->resrec.RecordType);
+               if (rr->resrec.name != &rr->namestorage)
+                       LogMsg("!!!! ResourceRecords list: %p name %p does not point to namestorage %p %##s",
+                               rr, rr->resrec.name->c, rr->namestorage.c, rr->namestorage.c);
+               }
 
        for (rr = m->DuplicateRecords; rr; rr=rr->next)
                if (rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
@@ -690,10 +753,9 @@ static void validatelists(mDNS *const m)
                if (q->ThisQInterval == (mDNSs32)~0)
                        LogMsg("!!!! Questions list: %p is garbage (%lX) !!!!", q, q->ThisQInterval);
 
-       for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
-               for (cr = m->rrcache_hash[slot]; cr; cr=cr->next)
-                       if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF)
-                               LogMsg("!!!! Cache slot %lu: %p is garbage (%X) !!!!", slot, rr, rr->resrec.RecordType);
+       FORALL_CACHERECORDS(slot, cg, cr)
+               if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF)
+                       LogMsg("!!!! Cache slot %lu: %p is garbage (%X) !!!!", slot, rr, rr->resrec.RecordType);
 
        for (i = m->p->InterfaceList; i; i = i->next)
                if (!i->ifa_name)
@@ -841,8 +903,8 @@ mDNSlocal void AbortClient(mach_port_t ClientMachPort, void *m)
                        ServiceInstance *instance = si;
                        si = si->next;                 
                        instance->autorename = mDNSfalse;
-                       if (m && m != x) LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort, instance->srs.RR_SRV.resrec.name.c, SRS_PORT(&instance->srs), m, x);                        
-                       else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort, instance->srs.RR_SRV.resrec.name.c, SRS_PORT(&instance->srs));
+                       if (m && m != x) LogMsg("%5d: DNSServiceRegistration(%##s, %u) STOP; WARNING m %p != x %p", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs), m, x);                       
+                       else LogOperation("%5d: DNSServiceRegistration(%##s, %u) STOP", ClientMachPort, instance->srs.RR_SRV.resrec.name->c, SRS_PORT(&instance->srs));
 
                        // If mDNS_DeregisterService() returns mStatus_NoError, that means that the service was found in the list,
                        // is sending its goodbye packet, and we'll get an mStatus_MemFree message when we can free the memory.
@@ -882,7 +944,7 @@ mDNSlocal void AbortClientWithLogMessage(mach_port_t c, char *reason, char *msg,
        else if (r)
                {
                ServiceInstance *si;
-               for (si = r->regs; si; si = si->next) LogMsg("%5d: Registration(%##s) %s%s", c, si->srs.RR_SRV.resrec.name.c, reason, msg);
+               for (si = r->regs; si; si = si->next) LogMsg("%5d: Registration(%##s) %s%s", c, si->srs.RR_SRV.resrec.name->c, reason, msg);
                }
        else            LogMsg("%5d: (%s) %s, but no record of client can be found!", c,                            reason, msg);
 
@@ -908,7 +970,7 @@ mDNSlocal mDNSBool CheckForExistingClient(mach_port_t c)
                        LogMsg("%5d: Browser(%##s) already exists!",          c, qptr->q.qname.c);
                }
        if (l) LogMsg("%5d: Resolver(%##s) already exists!",          c, l->i.name.c);
-       if (r) LogMsg("%5d: Registration(%##s) already exists!",      c, r->regs ? r->regs->srs.RR_SRV.resrec.name.c : NULL);
+       if (r) LogMsg("%5d: Registration(%##s) already exists!",      c, r->regs ? r->regs->srs.RR_SRV.resrec.name->c : NULL);
        return(e || b || l || r);
        }
 
@@ -941,7 +1003,7 @@ mDNSlocal void EnableDeathNotificationForClient(mach_port_t ClientMachPort, void
 //*************************************************************************************************************
 // Domain Enumeration
 
-mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void DomainEnumFound(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
        {
        kern_return_t status;
        #pragma unused(m)
@@ -949,9 +1011,9 @@ mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceR
        DNSServiceDomainEnumerationReplyResultType rt;
        DNSServiceDomainEnumeration *x = (DNSServiceDomainEnumeration *)question->QuestionContext;
 
-       debugf("FoundDomain: %##s PTR %##s", answer->name.c, answer->rdata->u.name.c);
+       debugf("DomainEnumFound: %##s PTR %##s", answer->name->c, answer->rdata->u.name.c);
        if (answer->rrtype != kDNSType_PTR) return;
-       if (!x) { debugf("FoundDomain: DNSServiceDomainEnumeration is NULL"); return; }
+       if (!x) { debugf("DomainEnumFound: DNSServiceDomainEnumeration is NULL"); return; }
 
        if (AddRecord)
                {
@@ -987,7 +1049,6 @@ mDNSexport kern_return_t provide_DNSServiceDomainEnumerationCreate_rpc(mach_port
 
        mDNS_DomainType dt1 = regDom ? mDNS_DomainTypeRegistration        : mDNS_DomainTypeBrowse;
        mDNS_DomainType dt2 = regDom ? mDNS_DomainTypeRegistrationDefault : mDNS_DomainTypeBrowseDefault;
-       const DNSServiceDomainEnumerationReplyResultType rt = DNSServiceDomainEnumerationReplyAddDomainDefault;
 
        // Allocate memory, and handle failure
        DNSServiceDomainEnumeration *x = mallocL("DNSServiceDomainEnumeration", sizeof(*x));
@@ -998,16 +1059,11 @@ mDNSexport kern_return_t provide_DNSServiceDomainEnumerationCreate_rpc(mach_port
        x->next = DNSServiceDomainEnumerationList;
        DNSServiceDomainEnumerationList = x;
 
-       // Generate initial response
        verbosedebugf("%5d: Enumerate %s Domains", client, regDom ? "Registration" : "Browsing");
-       // We always give local. as the initial default browse domain, and then look for more
-       kern_return_t status = DNSServiceDomainEnumerationReply_rpc(x->ClientMachPort, rt, "local.", 0, MDNS_MM_TIMEOUT);
-       if (status == MACH_SEND_TIMED_OUT)
-               { AbortBlockedClient(x->ClientMachPort, "local enumeration", x); return(mStatus_UnknownErr); }
 
        // Do the operation
-       err           = mDNS_GetDomains(&mDNSStorage, &x->dom, dt1, NULL, mDNSInterface_LocalOnly, FoundDomain, x);
-       if (!err) err = mDNS_GetDomains(&mDNSStorage, &x->def, dt2, NULL, mDNSInterface_LocalOnly, FoundDomain, x);
+       err           = mDNS_GetDomains(&mDNSStorage, &x->dom, dt1, NULL, mDNSInterface_LocalOnly, DomainEnumFound, x);
+       if (!err) err = mDNS_GetDomains(&mDNSStorage, &x->def, dt2, NULL, mDNSInterface_LocalOnly, DomainEnumFound, x);
        if (err) { AbortClient(client, x); errormsg = "mDNS_GetDomains"; goto fail; }
 
        // Succeeded: Wrap up and return
@@ -1035,7 +1091,7 @@ mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const Resourc
        if (!DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain))
                {
                LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
-                       answer->name.c, answer->rdata->u.name.c);
+                       answer->name->c, answer->rdata->u.name.c);
                return;
                }
 
@@ -1043,7 +1099,7 @@ mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const Resourc
        if (!x) { LogMsg("FoundInstance: Failed to allocate memory for result %##s", answer->rdata->u.name.c); return; }
 
        verbosedebugf("FoundInstance: %s %##s", AddRecord ? "Add" : "Rmv", answer->rdata->u.name.c);
-       AssignDomainName(x->result, answer->rdata->u.name);
+       AssignDomainName(&x->result, &answer->rdata->u.name);
        if (AddRecord)
                 x->resultType = DNSServiceBrowserReplyAddInstance;
        else x->resultType = DNSServiceBrowserReplyRemoveInstance;
@@ -1068,7 +1124,7 @@ mDNSlocal mStatus AddDomainToBrowser(DNSServiceBrowser *browser, const domainnam
        
        question = mallocL("DNSServiceBrowserQuestion", sizeof(DNSServiceBrowserQuestion));
        if (!question) { LogMsg("Error: malloc"); return mStatus_NoMemoryErr; }
-       AssignDomainName(question->domain, *d);
+       AssignDomainName(&question->domain, d);
        question->next = browser->qlist;
        browser->qlist = question;
        LogOperation("%5d: DNSServiceBrowse(%##s%##s) START", browser->ClientMachPort, browser->type.c, d->c);
@@ -1081,7 +1137,7 @@ mDNSexport void DefaultBrowseDomainChanged(const domainname *d, mDNSBool add)
        {
        DNSServiceBrowser *ptr;
 
-       debugf("%s default browse domain %##s", add ? "Adding" : "Removing", d->c);
+       debugf("DefaultBrowseDomainChanged: %s default browse domain %##s", add ? "Adding" : "Removing", d->c);
        for (ptr = DNSServiceBrowserList; ptr; ptr = ptr->next)
                {
                if (ptr->DefaultDomain)
@@ -1093,30 +1149,28 @@ mDNSexport void DefaultBrowseDomainChanged(const domainname *d, mDNSBool add)
                                }
                        else
                                {
-#if 0
-                               /*
-                                * By cancelling the browse immediately, we may lose remove events.
-                                * Instead, we allow the browse to run.  If our previous results are no longer valid (e.g. because we
-                                * moved out from behind a firewall) we will get remove events for those names.
-                                */
-                                // find the question for this domain
-                                DNSServiceBrowserQuestion *q = ptr->qlist, *prev = NULL;
-                                while (q)
-                                        {
-                                        if (SameDomainName(&q->domain, d))
-                                                {
-                                                if (prev) prev->next = q->next;
-                                                else ptr->qlist = q->next;
-                                                mDNS_StopBrowse(&mDNSStorage, &q->q);
-                                                freeL("DNSServiceBrowserQuestion", q);
-                                                break;
-                                                }
-                                        prev = q;
-                                        q = q->next;
-                                        }
-                                if (!q) LogMsg("Requested removal of default domain %##s not in client %5d's list", d->c, ptr->ClientMachPort);
-#endif
-                 }                     
+                               DNSServiceBrowserQuestion **q = &ptr->qlist;
+                               while (*q)
+                                       {
+                                       if (SameDomainName(&(*q)->domain, d))
+                                               {
+                                               DNSServiceBrowserQuestion *remove = *q;
+                                               *q = (*q)->next;
+                                               if (remove->q.LongLived)
+                                                       {
+                                                       // give goodbyes for known answers.  note that since events are sent to client via udns_execute(),
+                                                       // we don't need to worry about the question being cancelled mid-loop
+                                                       CacheRecord *ka = remove->q.uDNS_info.knownAnswers;
+                                                       while (ka) { remove->q.QuestionCallback(&mDNSStorage, &remove->q, &ka->resrec, mDNSfalse); ka = ka->next; }
+                                                       }                                               
+                                               mDNS_StopBrowse(&mDNSStorage, &remove->q);
+                                               freeL("DNSServiceBrowserQuestion", remove );
+                                               return;                                         
+                                               }                                       
+                                       q = &(*q)->next;
+                                       }
+                           LogMsg("Requested removal of default domain %##s not in client %5d's list", d->c, ptr->ClientMachPort);
+                               }
                        }
                }
        }
@@ -1150,7 +1204,7 @@ mDNSexport kern_return_t provide_DNSServiceBrowserCreate_rpc(mach_port_t unuseds
        if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
 
        // Set up object, and link into list
-       AssignDomainName(x->type, t);
+       AssignDomainName(&x->type, &t);
        x->ClientMachPort = client;
        x->results = NULL;
        x->lastsuccess = 0;
@@ -1201,12 +1255,12 @@ fail:
 //*************************************************************************************************************
 // Resolve Service Info
        
-       mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
+mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
        {
        kern_return_t status;
        DNSServiceResolver *x = (DNSServiceResolver *)query->ServiceInfoQueryContext;
        NetworkInterfaceInfoOSX *ifx = (NetworkInterfaceInfoOSX *)query->info->InterfaceID;
-       if (query->info->InterfaceID == (mDNSInterfaceID)~0) ifx = mDNSNULL;
+       if (query->info->InterfaceID == mDNSInterface_LocalOnly) ifx = mDNSNULL;
        struct sockaddr_storage interface;
        struct sockaddr_storage address;
        char cstring[1024];
@@ -1344,7 +1398,7 @@ mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus r
        if (result == mStatus_NoError)
                {
                kern_return_t status;
-               LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si->ClientMachPort, srs->RR_SRV.resrec.name.c, SRS_PORT(srs));
+               LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Registered", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs));
                status = DNSServiceRegistrationReply_rpc(si->ClientMachPort, result, MDNS_MM_TIMEOUT);
                if (status == MACH_SEND_TIMED_OUT)
                        AbortBlockedClient(si->ClientMachPort, "registration success", si);
@@ -1354,7 +1408,7 @@ mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus r
 
        else if (result == mStatus_NameConflict)
                {
-               LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si->ClientMachPort, srs->RR_SRV.resrec.name.c, SRS_PORT(srs));
+               LogOperation("%5d: DNSServiceRegistration(%##s, %u) Name Conflict", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs));
                // Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
                // and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
                if (si->autoname && CountPeerRegistrations(m, srs) == 0)
@@ -1399,7 +1453,7 @@ mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus r
                                        {
                                        if (sp == si)
                                                {                                 
-                                               LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", srs->RR_SRV.resrec.name.c);                          
+                                               LogMsg("RegCallback: %##s Still in DNSServiceRegistration list; removing now", srs->RR_SRV.resrec.name->c);                         
                                                if (prev) prev->next = sp->next;
                                                else r->regs = sp->next;
                                                break;
@@ -1414,7 +1468,7 @@ mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus r
                }
 
        else if (result != mStatus_NATTraversal)
-               LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld", si->ClientMachPort, srs->RR_SRV.resrec.name.c, SRS_PORT(srs), result);
+               LogMsg("%5d: DNSServiceRegistration(%##s, %u) Unknown Result %ld", si->ClientMachPort, srs->RR_SRV.resrec.name->c, SRS_PORT(srs), result);
        }
 
 mDNSlocal mStatus AddServiceInstance(DNSServiceRegistration *x, const domainname *domain)
@@ -1690,7 +1744,7 @@ mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
                                        {
                                        if (!SameDomainLabel(si->name.c, m->nicelabel.c))
                                                {
-                                               debugf("NetworkChanged renaming %##s to %#s", si->srs.RR_SRV.resrec.name.c, m->nicelabel.c);
+                                               debugf("NetworkChanged renaming %##s to %#s", si->srs.RR_SRV.resrec.name->c, m->nicelabel.c);
                                                si->autorename = mDNStrue;
                                                if (mDNS_DeregisterService(m, &si->srs))        // If service deregistered already, we can re-register immediately
                                                        RegCallback(m, &si->srs, mStatus_MemFree);
@@ -1701,10 +1755,9 @@ mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
                }
        else if (result == mStatus_GrowCache)
                {
-               // If we've run out of cache space, then double the total cache size and give the memory to mDNSCore
-               mDNSu32 numrecords = m->rrcache_size;
-               CacheRecord *storage = mallocL("mStatus_GrowCache", sizeof(CacheRecord) * numrecords);
-               if (storage) mDNS_GrowCache(m, storage, numrecords);
+               // Allocate another chunk of cache storage
+               CacheEntity *storage = mallocL("mStatus_GrowCache", sizeof(CacheEntity) * RR_CACHE_SIZE);
+               if (storage) mDNS_GrowCache(m, storage, RR_CACHE_SIZE);
                }
        }
 
@@ -1747,7 +1800,7 @@ mDNSexport kern_return_t provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t
 
                // Do the operation
                LogOperation("%5d: DNSServiceRegistrationAddRecord(%##s, type %d, length %d) REF %p",
-                                        client, si->srs.RR_SRV.resrec.name.c, type, data_len, extra);
+                                        client, si->srs.RR_SRV.resrec.name->c, type, data_len, extra);
                err = mDNS_AddRecordToService(&mDNSStorage, &si->srs, extra, &extra->r.rdatastorage, ttl);
 
                if (err)
@@ -1781,7 +1834,7 @@ mDNSlocal mStatus UpdateRecord(ServiceRecordSet *srs, mach_port_t client, AuthRe
        const char *errormsg = "Unknown";
        domainname *name = (domainname *)"";
 
-       name = &srs->RR_SRV.resrec.name;
+       name = srs->RR_SRV.resrec.name;
 
        unsigned int size = sizeof(RDataBody);
     if (size < data_len)
@@ -1797,7 +1850,7 @@ mDNSlocal mStatus UpdateRecord(ServiceRecordSet *srs, mach_port_t client, AuthRe
 
        // Do the operation
        LogOperation("%5d: DNSServiceRegistrationUpdateRecord(%##s, new length %d)",
-               client, srs->RR_SRV.resrec.name.c, data_len);
+               client, srs->RR_SRV.resrec.name->c, data_len);
 
        err = mDNS_Update(&mDNSStorage, rr, ttl, data_len, newrdata, UpdateCallback);
        if (err)
@@ -1860,11 +1913,11 @@ fail:
 
 mDNSlocal mStatus RemoveRecord(ServiceRecordSet *srs, ExtraResourceRecord *extra, mach_port_t client)
        {
-       domainname *name = &srs->RR_SRV.resrec.name;
+       domainname *name = srs->RR_SRV.resrec.name;
        mStatus err = mStatus_NoError;
 
        // Do the operation
-       LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client, srs->RR_SRV.resrec.name.c);
+       LogOperation("%5d: DNSServiceRegistrationRemoveRecord(%##s)", client, srs->RR_SRV.resrec.name->c);
 
        err = mDNS_RemoveRecordFromService(&mDNSStorage, srs, extra, FreeExtraRR, extra);
        if (err) LogMsg("%5d: DNSServiceRegistrationRemoveRecord (%##s) failed: %d", client, name->c, err);
@@ -2060,17 +2113,10 @@ mDNSlocal kern_return_t destroyBootstrapService()
 
 mDNSlocal void ExitCallback(int signal)
        {
-#if 0
-       CacheRecord *rr;
-       int rrcache_active = 0;
-       for (rr = mDNSStorage.rrcache; rr; rr=rr->next) if (CacheRRActive(&mDNSStorage, rr)) rrcache_active++;
-       debugf("ExitCallback: RR Cache now using %d records, %d active", mDNSStorage.rrcache_used, rrcache_active);
-#endif
-
        LogMsgIdent(mDNSResponderVersionString, "stopping");
 
-       debugf("ExitCallback: destroyBootstrapService");
-       if (!mDNS_DebugMode && signal != SIGHUP)
+       debugf("ExitCallback");
+       if (!mDNS_DebugMode && !started_via_launchdaemon && signal != SIGHUP)
                destroyBootstrapService();
 
        debugf("ExitCallback: Aborting MIG clients");
@@ -2109,6 +2155,7 @@ mDNSlocal void HandleSIG(int signal)
 
 mDNSlocal void INFOCallback(void)
        {
+       mDNSs32 utc = mDNSPlatformUTC();
        DNSServiceDomainEnumeration *e;
        DNSServiceBrowser           *b;
        DNSServiceResolver          *l;
@@ -2116,7 +2163,7 @@ mDNSlocal void INFOCallback(void)
        NetworkInterfaceInfoOSX     *i;
 
        LogMsgIdent(mDNSResponderVersionString, "---- BEGIN STATE LOG ----");
-
+       
        udsserver_info(&mDNSStorage);
 
        for (e = DNSServiceDomainEnumerationList; e; e=e->next)
@@ -2135,14 +2182,14 @@ mDNSlocal void INFOCallback(void)
                {
                ServiceInstance *si;
                for (si = r->regs; si; si = si->next)
-                       LogMsgNoIdent("%5d: Mach ServiceInstance     %##s %u", si->ClientMachPort, si->srs.RR_SRV.resrec.name.c, mDNSVal16(si->srs.RR_SRV.resrec.rdata->u.srv.port));
+                       LogMsgNoIdent("%5d: Mach ServiceInstance     %##s %u", si->ClientMachPort, si->srs.RR_SRV.resrec.name->c, mDNSVal16(si->srs.RR_SRV.resrec.rdata->u.srv.port));
                }
 
        for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
                {
                if (!i->Exists)
-                       LogMsgNoIdent("Interface: %s %5s(%lu) %.6a DORMANT",
-                               i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID);
+                       LogMsgNoIdent("Interface: %s %5s(%lu) %.6a DORMANT %d",
+                               i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID, utc - i->LastSeen);
                else
                        LogMsgNoIdent("Interface: %s %5s(%lu) %.6a %s %s %2d %s %2d InterfaceID %p %s %s %#a",
                                i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifa_name, i->scope_id, &i->BSSID,
@@ -2215,19 +2262,29 @@ mDNSlocal kern_return_t mDNSDaemonInitialize(void)
        CFRelease(s_rls);
        CFRelease(i_rls);
        if (mDNS_DebugMode) printf("Service registered with Mach Port %d\n", m_port);
-       err = udsserver_init();
-       if (err) { LogMsg("Daemon start: udsserver_init failed"); return err; }
        return(err);
        }
 
 mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m)
        {
-       // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
+       mDNSs32 now = mDNS_TimeNow(m);
+
+       // 1. If we have network change events to handle, do them FIRST, before calling mDNS_Execute()
+       // Detailed reason:
+       // mDNSMacOSXNetworkChanged() currently closes and re-opens its sockets. If there are received packets waiting, they are lost.
+       // mDNS_Execute() generates packets, including multicasts that are looped back to ourself.
+       // If we call mDNS_Execute() first, and generate packets, and then call mDNSMacOSXNetworkChanged() immediately afterwards
+       // we then systematically lose our own looped-back packets.
+       if (m->p->NetworkChanged && now - m->p->NetworkChanged >= 0) { m->p->NetworkChanged = 0; mDNSMacOSXNetworkChanged(m); }
+
+       // 2. Call mDNS_Execute() to let mDNSCore do what it needs to do
        mDNSs32 nextevent = mDNS_Execute(m);
 
-       mDNSs32 now = mDNS_TimeNow(m);
+       if (m->p->NetworkChanged)
+               if (nextevent - m->p->NetworkChanged > 0)
+                       nextevent = m->p->NetworkChanged;
 
-       // 2. Deliver any waiting browse messages to clients
+       // 3. Deliver any waiting browse messages to clients
        DNSServiceBrowser *b = DNSServiceBrowserList;
 
        while (b)
@@ -2306,21 +2363,41 @@ mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m)
                                nextevent = m->p->NotifyUser;
                }
 
-       if (m->p->NetworkChanged)
-               {
-               if (m->p->NetworkChanged - now < 0)
-                       {
-                       m->p->NetworkChanged = 0;
-                       mDNSMacOSXNetworkChanged(m);
-                       }
-               else
-                       if (nextevent - m->p->NetworkChanged > 0)
-                               nextevent = m->p->NetworkChanged;
-               }
-
        return(nextevent);
        }
 
+mDNSlocal void ShowTaskSchedulingError(mDNS *const m)
+       {
+       mDNS_Lock(m);
+
+       LogMsg("Task Scheduling Error: Continuously busy for more than a second");
+       
+       if (m->NewQuestions && (!m->NewQuestions->DelayAnswering || m->timenow - m->NewQuestions->DelayAnswering >= 0))
+               LogMsg("Task Scheduling Error: NewQuestion %##s (%s)",
+                       m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
+       if (m->NewLocalOnlyQuestions)
+               LogMsg("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)",
+                       m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
+       if (m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords))
+               LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m, m->NewLocalRecords));
+       if (m->SuppressSending && m->timenow - m->SuppressSending >= 0)
+               LogMsg("Task Scheduling Error: m->SuppressSending %d",       m->timenow - m->SuppressSending);
+#ifndef UNICAST_DISABLED
+       if (m->timenow - m->uDNS_info.nextevent   >= 0)
+               LogMsg("Task Scheduling Error: m->uDNS_info.nextevent %d",   m->timenow - m->uDNS_info.nextevent);
+#endif
+       if (m->timenow - m->NextCacheCheck        >= 0)
+               LogMsg("Task Scheduling Error: m->NextCacheCheck %d",        m->timenow - m->NextCacheCheck);
+       if (m->timenow - m->NextScheduledQuery    >= 0)
+               LogMsg("Task Scheduling Error: m->NextScheduledQuery %d",    m->timenow - m->NextScheduledQuery);
+       if (m->timenow - m->NextScheduledProbe    >= 0)
+               LogMsg("Task Scheduling Error: m->NextScheduledProbe %d",    m->timenow - m->NextScheduledProbe);
+       if (m->timenow - m->NextScheduledResponse >= 0)
+               LogMsg("Task Scheduling Error: m->NextScheduledResponse %d", m->timenow - m->NextScheduledResponse);
+
+       mDNS_Unlock(&mDNSStorage);
+       }
+
 mDNSexport int main(int argc, char **argv)
        {
        int i;
@@ -2329,6 +2406,7 @@ mDNSexport int main(int argc, char **argv)
        for (i=1; i<argc; i++)
                {
                if (!strcmp(argv[i], "-d")) mDNS_DebugMode = mDNStrue;
+               if (!strcmp(argv[i], "-launchdaemon")) started_via_launchdaemon = mDNStrue;
                }
 
        signal(SIGHUP,  HandleSIG);             // (Debugging) Exit cleanly and let mach_init restart us (for debugging)
@@ -2339,13 +2417,10 @@ mDNSexport int main(int argc, char **argv)
        signal(SIGUSR1, HandleSIG);             // (Debugging) Simulate network change notification from System Configuration Framework
 
        // Register the server with mach_init for automatic restart only during normal (non-debug) mode
-    if (!mDNS_DebugMode) registerBootstrapService();
-
-       if (!mDNS_DebugMode && !restarting_via_mach_init)
-               exit(0); /* mach_init will restart us immediately as a daemon */
-
-       if (!mDNS_DebugMode)
-               {
+    if (!mDNS_DebugMode && !started_via_launchdaemon)
+       {
+       registerBootstrapService();
+       if (!restarting_via_mach_init) exit(0); // mach_init will restart us immediately as a daemon
                int fd = open(_PATH_DEVNULL, O_RDWR, 0);
                if (fd < 0) LogMsg("open(_PATH_DEVNULL, O_RDWR, 0) failed errno %d (%s)", errno, strerror(errno));
                else
@@ -2358,6 +2433,11 @@ mDNSexport int main(int argc, char **argv)
                        }
                }
 
+       // Make our PID file and Unix Domain Socket first, because launchd waits for those before it starts launching other daemons.
+       // The sooner we do this, the faster the machine will boot.
+       status = udsserver_init();
+       if (status) { LogMsg("Daemon start: udsserver_init failed"); return(status); }
+       
        // First do the all the initialization we need root privilege for, before we change to user "nobody"
        LogMsgIdent(mDNSResponderVersionString, "starting");
        status = mDNSDaemonInitialize();
@@ -2373,7 +2453,7 @@ mDNSexport int main(int argc, char **argv)
 
        if (status == 0)
                {
-               LogMsg("Starting time value 0x%08lX (%ld)", (mDNSu32)mDNSStorage.timenow_last, mDNSStorage.timenow_last);
+               LogOperation("Starting time value 0x%08lX (%ld)", (mDNSu32)mDNSStorage.timenow_last, mDNSStorage.timenow_last);
                int numevents = 0;
                int RunLoopStatus = kCFRunLoopRunTimedOut;
 
@@ -2398,8 +2478,7 @@ mDNSexport int main(int argc, char **argv)
                        else
                                {
                                ticks = 1;
-                               if (++RepeatedBusy >= mDNSPlatformOneSecond * 10)
-                                       { LogMsg("Task Scheduling Error: Continuously busy for the last ten seconds"); RepeatedBusy = 0; }
+                               if (++RepeatedBusy >= mDNSPlatformOneSecond) { ShowTaskSchedulingError(&mDNSStorage); RepeatedBusy = 0; }
                                }
                        CFAbsoluteTime interval = (CFAbsoluteTime)ticks / (CFAbsoluteTime)mDNSPlatformOneSecond;
 
@@ -2423,8 +2502,9 @@ mDNSexport int main(int argc, char **argv)
                mDNS_Close(&mDNSStorage);
                }
 
-       if (!mDNS_DebugMode) destroyBootstrapService();
+       if (!mDNS_DebugMode && !started_via_launchdaemon) destroyBootstrapService();
 
+       LogMsgIdent(mDNSResponderVersionString, "exiting");
        return(status);
        }
 
@@ -2489,7 +2569,7 @@ mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *cont
                {
                if (newSource->cfs)
                        {
-                       CFSocketInvalidate(newSource->cfs); // automatically closes socket
+                       CFSocketInvalidate(newSource->cfs);             // Note: Also closes the underlying socket
                        CFRelease(newSource->cfs);
                        }
                return mStatus_NoMemoryErr;
@@ -2498,7 +2578,7 @@ mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *cont
        return mStatus_NoError;
        }
 
-mStatus udsSupportRemoveFDFromEventLoop(int fd)
+mStatus udsSupportRemoveFDFromEventLoop(int fd)                // Note: This also CLOSES the file descriptor
        // Reverse what was done in udsSupportAddFDToEventLoop().
        {
        CFSocketEventSource     *iSource;
@@ -2511,7 +2591,7 @@ mStatus udsSupportRemoveFDFromEventLoop(int fd)
                        CFRunLoopRemoveSource(CFRunLoopGetCurrent(), iSource->RLS, kCFRunLoopDefaultMode);
                        CFRunLoopSourceInvalidate(iSource->RLS);
                        CFRelease(iSource->RLS);
-                       CFSocketInvalidate(iSource->cfs);
+                       CFSocketInvalidate(iSource->cfs);               // Note: Also closes the underlying socket
                        CFRelease(iSource->cfs);
                        free(iSource);
                        return mStatus_NoError;
index eebba79a6e5d71f9f98c05268f808a8b8bbb6ac7..8a74c6f74a1a77f291743432d5293b5b9738db8c 100644 (file)
     Change History (most recent first):
 
 $Log: mDNSMacOSX.c,v $
+Revision 1.294  2005/01/27 21:30:23  cheshire
+<rdar://problem/3952067> "Can't assign requested address" message after AirPort turned off
+Don't write syslog messages for EADDRNOTAVAIL if we know network configuration changes are happening
+
+Revision 1.293  2005/01/27 19:15:41  cheshire
+Remove extraneous LogMsg() call
+
+Revision 1.292  2005/01/27 17:48:38  cheshire
+Added comment about CFSocketInvalidate closing the underlying socket
+
+Revision 1.291  2005/01/27 00:10:58  cheshire
+<rdar://problem/3967867> Name change log messages every time machine boots
+
+Revision 1.290  2005/01/25 23:18:30  ksekar
+fix for <rdar://problem/3971467> requires that local-only ".local" registration record be created
+
+Revision 1.289  2005/01/25 18:08:31  ksekar
+Removed redundant debug output
+
+Revision 1.288  2005/01/25 17:42:26  ksekar
+Renamed FoundDefBrowseDomain -> FoundLegacyBrowseDomain,
+cleaned up duplicate log messages when adding/removing browse domains
+
+Revision 1.287  2005/01/25 16:59:23  ksekar
+<rdar://problem/3971138> sa_len not set checking reachability for TCP connections
+
+Revision 1.286  2005/01/25 02:02:37  cheshire
+<rdar://problem/3970673> mDNSResponder leaks
+GetSearchDomains() was not calling dns_configuration_free().
+
+Revision 1.285  2005/01/22 00:07:54  ksekar
+<rdar://problem/3960546> mDNSResponder should look at all browse domains in SCPreferences
+
+Revision 1.284  2005/01/21 23:07:17  ksekar
+<rdar://problem/3960795> mDNSResponder causes Dial on Demand
+
+Revision 1.283  2005/01/19 21:16:16  cheshire
+Make sure when we set NetworkChanged that we don't set it to zero
+
+Revision 1.282  2005/01/19 19:19:21  ksekar
+<rdar://problem/3960191> Need a way to turn off domain discovery
+
+Revision 1.281  2005/01/18 18:10:55  ksekar
+<rdar://problem/3954575> Use 10.4 resolver API to get search domains
+
+Revision 1.280  2005/01/17 22:48:52  ksekar
+No longer need to call MarkSearchListElem for registration domain
+
+Revision 1.279  2005/01/17 20:40:34  ksekar
+SCPreferences changes should remove exactly one browse and one legacy browse domain for each remove event
+
+Revision 1.278  2005/01/17 19:53:34  ksekar
+Refinement to previous fix - register _legacy._browse records for SCPreference domains to achieve correct reference counting
+
+Revision 1.277  2005/01/12 00:17:50  ksekar
+<rdar://problem/3933573> Update LLQs *after* setting DNS
+
+Revision 1.276  2005/01/10 17:39:10  ksekar
+Refinement to 1.272 - avoid spurious warnings when registration and browse domains are set to same value and toggled on/off
+
+Revision 1.275  2005/01/10 04:02:22  ksekar
+Refinement to <rdar://problem/3891628> - strip trailing dot before writing hostname status to dynamic store
+
+Revision 1.274  2005/01/10 03:41:36  ksekar
+Correction to checkin 1.272 - check that registration domain is set
+before trying to remove it as an implicit browse domain
+
+Revision 1.273  2005/01/08 00:42:18  ksekar
+<rdar://problem/3922758> Clean up syslog messages
+
+Revision 1.272  2005/01/07 23:21:42  ksekar
+<rdar://problem/3891628> Clean up SCPreferences format
+
+Revision 1.271  2004/12/20 23:18:12  cheshire
+<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
+One more refinement: When an interface with a v6LL address gets a v4 address too, that's not a flap
+
+Revision 1.270  2004/12/20 21:28:14  cheshire
+<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
+Additional refinements to handle sleep/wake better
+
+Revision 1.269  2004/12/20 20:48:11  cheshire
+Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xxx) or later
+
+Revision 1.268  2004/12/18 03:19:04  cheshire
+Show netmask in error log
+
+Revision 1.267  2004/12/18 00:51:52  cheshire
+Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
+
+Revision 1.266  2004/12/17 23:49:38  cheshire
+<rdar://problem/3922754> Computer Name change is slow
+Also treat changes to "Setup:/Network/DynamicDNS" the same way
+
+Revision 1.265  2004/12/17 23:37:47  cheshire
+<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
+(and other repetitive configuration changes)
+
+Revision 1.264  2004/12/17 19:03:05  cheshire
+Update debugging messages to show netmask a simple CIDR-style numeric value (0-128)
+
+Revision 1.263  2004/12/17 05:25:46  cheshire
+<rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
+
+Revision 1.262  2004/12/17 04:48:32  cheshire
+<rdar://problem/3922754> Computer Name change is slow
+
+Revision 1.261  2004/12/17 02:40:08  cheshire
+Undo last change -- it was too strict
+
+Revision 1.260  2004/12/16 22:17:16  cheshire
+Only accept multicast packets on interfaces that have McastTxRx set
+
+Revision 1.259  2004/12/16 20:13:01  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
 Revision 1.258  2004/12/14 00:18:05  cheshire
 Don't log dns_configuration_copy() failures in the first three minutes after boot
 
@@ -855,9 +971,11 @@ static DNameListElem *DefRegList = NULL;       // manually generated list of dom
 static ARListElem *SCPrefBrowseDomains = NULL; // manually generated local-only PTR records for browse domains we get from SCPreferences
 
 static domainname DynDNSRegDomain;             // Default wide-area zone for service registration
-static domainname DynDNSBrowseDomain;          // Default wide-area zone for legacy ("empty string") browses
+static CFArrayRef DynDNSBrowseDomains = NULL;  // Default wide-area zones for legacy ("empty string") browses
 static domainname DynDNSHostname;
 
+static mDNSBool DomainDiscoveryDisabled = mDNSfalse;
+
 #define CONFIG_FILE "/etc/mDNSResponder.conf"
 #define DYNDNS_KEYCHAIN_SERVICE "DynDNS Shared Secret"
 #define SYS_KEYCHAIN_PATH "/Library/Keychains/System.keychain"
@@ -895,7 +1013,7 @@ mDNSlocal void AddDefRegDomain(domainname *d)
        
        newelem = mallocL("DNameListElem", sizeof(*newelem));
        if (!newelem) { LogMsg("Error - malloc"); return; }
-       AssignDomainName(newelem->name, *d);
+       AssignDomainName(&newelem->name, d);
        newelem->next = DefRegList;
        DefRegList = newelem;
 
@@ -988,7 +1106,7 @@ mDNSlocal int myIfIndexToName(u_short index, char* name)
 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *const m, mDNSu32 index)
        {
        NetworkInterfaceInfoOSX *i;
-       if (index == (uint32_t)~0) return(mDNSInterface_LocalOnly);
+       if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
        if (index)
                for (i = m->p->InterfaceList; i; i = i->next)
                        // Don't get tricked by inactive interfaces with no InterfaceID set
@@ -999,7 +1117,7 @@ mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS
 mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m, mDNSInterfaceID id)
        {
        NetworkInterfaceInfoOSX *i;
-       if (id == mDNSInterface_LocalOnly) return((mDNSu32)~0);
+       if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
        if (id)
                for (i = m->p->InterfaceList; i; i = i->next)
                        // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces, which have no InterfaceID set
@@ -1007,6 +1125,22 @@ mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m
        return 0;
        }
 
+mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
+       {
+       mDNSBool result = mDNSfalse;
+       SCNetworkConnectionFlags flags;
+       SCNetworkReachabilityRef ReachRef = NULL;
+
+       ReachRef = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, addr);   
+       if (!ReachRef) { LogMsg("ERROR: RequiresConnection - SCNetworkReachabilityCreateWithAddress"); goto end; }
+       if (!SCNetworkReachabilityGetFlags(ReachRef, &flags)) { LogMsg("ERROR: AddrRequiresPPPConnection - SCNetworkReachabilityGetFlags"); goto end; }
+       result = flags & kSCNetworkFlagsConnectionRequired;
+
+       end:
+       if (ReachRef) CFRelease(ReachRef);
+       return result;  
+       }
+
 // NOTE: If InterfaceID is NULL, it means, "send this packet through our anonymous unicast socket"
 // NOTE: If InterfaceID is non-NULL it means, "send this packet through our port 5353 socket on the specified interface"
 // OR send via our primary v4 unicast socket
@@ -1032,7 +1166,7 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
                if ((m->h.flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Query)
                        LogMsg("mDNSPlatformSendUDP: ERROR: Sending query OP from mDNS port to non-mDNS destination %#a:%d", dst, mDNSVal16(dstPort));
                }
-
+       
        if (dst->type == mDNSAddrType_IPv4)
                {
                struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
@@ -1059,6 +1193,15 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
                return mStatus_BadParamErr;
                }
 
+       // Don't send if it would cause dial on demand connection initiation.  As an optimization,
+       // don't bother consulting reachability API / routing table when sending Multicast DNS
+       // since we ignore PPP interfaces for mDNS traffic
+       if (!mDNSAddrIsDNSMulticast(dst) && AddrRequiresPPPConnection((struct sockaddr *)&to))
+               {
+               debugf("mDNSPlatformSendUDP: Surpressing sending to avoid dial-on-demand connection");
+               return mStatus_NoError;
+               }
+               
        if (s >= 0)
                verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
                        InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
@@ -1079,6 +1222,8 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
                // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
                // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
                if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(err);
+               // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
+               if (errno == EADDRNOTAVAIL && m->p->NetworkChanged) return(err);
                LogMsg("mDNSPlatformSendUDP sendto failed to send packet on InterfaceID %p %5s/%ld to %#a:%d skt %d error %d errno %d (%s) %lu",
                        InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
                return(err);
@@ -1232,7 +1377,7 @@ mDNSlocal void myCFSocketCallBack(CFSocketRef cfs, CFSocketCallBackType CallBack
                        // interface they arrive on. According to the official Unix Powers That Be, this is Not A Bug.
                        // To work around this weirdness, we use the IP_RECVIF option to find the name of the interface
                        // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
-                       if (!ss->info)
+                       if (!ss->info || !ss->info->Exists)
                                {
                                verbosedebugf("myCFSocketCallBack got multicast packet from %#a to %#a on unicast socket (Ignored)", &senderAddr, &destAddr);
                                return;
@@ -1341,6 +1486,19 @@ mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstp
                return mStatus_UnknownErr;
                }
 
+       bzero(&saddr, sizeof(saddr));
+       saddr.sin_family = AF_INET;
+       saddr.sin_port = dstport.NotAnInteger;
+       saddr.sin_len = sizeof(saddr);
+       memcpy(&saddr.sin_addr, &dst->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
+
+       // Don't send if it would cause dial on demand connection initiation.
+       if (AddrRequiresPPPConnection((struct sockaddr *)&saddr))
+               {
+               debugf("mDNSPlatformTCPConnect: Surpressing sending to avoid dial-on-demand connection");
+               return mStatus_UnknownErr;
+               }
+
        sd = socket(AF_INET, SOCK_STREAM, 0);
        if (sd < 3) { LogMsg("mDNSPlatformTCPConnect: socket error %d errno %d (%s)", sd, errno, strerror(errno)); return mStatus_UnknownErr; }
 
@@ -1383,10 +1541,6 @@ mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstp
        CFRelease(rls);
        
        // initiate connection wth peer
-       bzero(&saddr, sizeof(saddr));
-       saddr.sin_family = AF_INET;
-       saddr.sin_port = dstport.NotAnInteger;
-       memcpy(&saddr.sin_addr, &dst->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
        if (connect(sd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
                {
                if (errno == EINPROGRESS)
@@ -1397,7 +1551,7 @@ mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstp
                        }
                LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: %s", strerror(errno));
                freeL("mDNSPlatformTCPConnect", info);
-               CFSocketInvalidate(sr);
+               CFSocketInvalidate(sr);         // Note: Also closes the underlying socket
                return mStatus_ConnFailed;
                }
        info->connected = 1;
@@ -1484,14 +1638,23 @@ mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
                }
        }
 
-mDNSlocal void GetUserSpecifiedDDNSConfig(domainname *const fqdn, domainname *const regDomain, domainname *const browseDomain)
+mDNSlocal mDNSBool DDNSSettingEnabled(CFDictionaryRef dict)
+       {
+       mDNSs32 val;
+       CFNumberRef state = CFDictionaryGetValue(dict, CFSTR("Enabled"));
+       if (!state) return mDNSfalse;
+       if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val)) { LogMsg("ERROR: DDNSSettingEnabled - CFNumberGetValue"); return mDNSfalse; }
+       return val ? mDNStrue : mDNSfalse;
+       }
+
+mDNSlocal void GetUserSpecifiedDDNSConfig(domainname *const fqdn, domainname *const regDomain, CFArrayRef *const browseDomains)
        {
        char buf[MAX_ESCAPED_DOMAIN_NAME];
 
        fqdn->c[0] = 0;
        regDomain->c[0] = 0;
-       browseDomain->c[0] = 0;
        buf[0] = 0;
+       *browseDomains = NULL;
        
        SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetUserSpecifiedDDNSConfig"), NULL, NULL);
        if (store)
@@ -1499,42 +1662,45 @@ mDNSlocal void GetUserSpecifiedDDNSConfig(domainname *const fqdn, domainname *co
                CFDictionaryRef dict = SCDynamicStoreCopyValue(store, CFSTR("Setup:/Network/DynamicDNS"));
                if (dict)
                        {
-                       CFArrayRef fqdnArray = CFDictionaryGetValue(dict, CFSTR("FQDN"));
-                       CFArrayRef regArray = CFDictionaryGetValue(dict, CFSTR("DefaultRegistrationDomain"));
-                       CFArrayRef browseArray = CFDictionaryGetValue(dict, CFSTR("DefaultBrowseDomain"));
+                       CFArrayRef fqdnArray = CFDictionaryGetValue(dict, CFSTR("HostNames"));
                        if (fqdnArray)
-                               {
-                               CFStringRef name = CFArrayGetValueAtIndex(fqdnArray, 0);
-                               if (name)
-                                       {
-                                       if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
-                        !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
-                                               LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
-                                       else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
+                               {                               
+                               CFDictionaryRef fqdnDict = CFArrayGetValueAtIndex(fqdnArray, 0); // for now, we only look at the first array element.  if we ever support multiple configurations, we will walk the list
+                               if (fqdnDict && DDNSSettingEnabled(fqdnDict))
+                                       {                                               
+                                       CFStringRef name = CFDictionaryGetValue(fqdnDict, CFSTR("Domain"));
+                                       if (name)
+                                               {
+                                               if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
+                                                       !MakeDomainNameFromDNSNameString(fqdn, buf) || !fqdn->c[0])
+                                                       LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS host name: %s", buf[0] ? buf : "(unknown)");
+                                               else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS host name: %s", buf);
+                                               }
                                        }
-                               }                       
+                               }
+
+                       CFArrayRef regArray = CFDictionaryGetValue(dict, CFSTR("RegistrationDomains"));
                        if (regArray)
                                {
-                               CFStringRef name = CFArrayGetValueAtIndex(regArray, 0);
-                               if (name)
+                               CFDictionaryRef regDict = CFArrayGetValueAtIndex(regArray, 0);
+                               if (regDict && DDNSSettingEnabled(regDict))
                                        {
-                                       if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
-                        !MakeDomainNameFromDNSNameString(regDomain, buf) || !regDomain->c[0])
-                                               LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
-                                       else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration zone: %s", buf);
+                                       CFStringRef name = CFDictionaryGetValue(regDict, CFSTR("Domain"));
+                                       if (name)
+                                               {
+                                               if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
+                                                       !MakeDomainNameFromDNSNameString(regDomain, buf) || !regDomain->c[0])
+                                                       LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS registration domain: %s", buf[0] ? buf : "(unknown)");
+                                               else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS registration zone: %s", buf);
+                                               }
                                        }
                                }
+                       CFArrayRef browseArray = CFDictionaryGetValue(dict, CFSTR("BrowseDomains"));
                        if (browseArray)
                                {
-                               CFStringRef name = CFArrayGetValueAtIndex(browseArray, 0);
-                               if (name)
-                                       {
-                                       if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) ||
-                        !MakeDomainNameFromDNSNameString(browseDomain, buf) || !browseDomain->c[0])
-                                               LogMsg("GetUserSpecifiedDDNSConfig SCDynamicStore bad DDNS browse domain: %s", buf[0] ? buf : "(unknown)");
-                                       else debugf("GetUserSpecifiedDDNSConfig SCDynamicStore DDNS browse zone: %s", buf);
-                                       }
-                               }                       
+                               CFRetain(browseArray);
+                               *browseDomains = browseArray;
+                               }
                        CFRelease(dict);
                        }
                CFRelease(store);
@@ -1549,18 +1715,32 @@ mDNSlocal void SetDDNSNameStatus(domainname *const dname, mStatus status)
                char uname[MAX_ESCAPED_DOMAIN_NAME];
                ConvertDomainNameToCString(dname, uname);
                char *p = uname;
-               while (*p) { *p = tolower(*p); p++; }
-               const void *n1 = CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8); // CFStringRef
-               const void *v1 = CFNumberCreate(NULL, kCFNumberSInt32Type, &status); // CFNumberRef
-               const void *n2 = CFSTR("FQDN"); // CFStringRef
-               const void *v2 = CFDictionaryCreate(NULL, &n1, &v1, 1, NULL, NULL); // CFDictionaryRef
-               CFDictionaryRef dict = CFDictionaryCreate(NULL, &n2, &v2, 1, NULL, NULL);
-               SCDynamicStoreSetValue(store, CFSTR("State:/Network/DynamicDNS"), dict);
-               CFRelease(dict);
-               CFRelease(v2);
-               CFRelease(n2);
-               CFRelease(v1);
-               CFRelease(n1);
+
+               while (*p)
+                       {
+                       *p = tolower(*p);
+                       if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
+                       p++;
+                       }
+               
+               const void *StatusKey = CFSTR("Status");                
+               const void *StatusVal = CFNumberCreate(NULL, kCFNumberSInt32Type, &status); // CFNumberRef
+               const void *StatusDict = CFDictionaryCreate(NULL, &StatusKey, &StatusVal, 1, NULL, NULL);
+
+               const void *HostKey = CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8);
+               const void *HostDict = CFDictionaryCreate(NULL, &HostKey, &StatusDict, 1, NULL, NULL);
+                               
+               const void *StateKey = CFSTR("HostNames"); // CFStringRef
+               CFDictionaryRef StateDict = CFDictionaryCreate(NULL, &StateKey, &HostDict, 1, NULL, NULL);
+               SCDynamicStoreSetValue(store, CFSTR("State:/Network/DynamicDNS"), StateDict);
+
+               CFRelease(StateDict);
+               CFRelease(StateKey);
+               CFRelease(HostDict);
+               CFRelease(HostKey);
+               CFRelease(StatusDict);
+               CFRelease(StatusVal);
+               CFRelease(StatusKey);
                CFRelease(store);
                }
        }
@@ -1771,7 +1951,7 @@ mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
        return(eth);
        }
 
-mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa)
+mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc)
        {
        mDNSu32 scope_id  = if_nametoindex(ifa->ifa_name);
        mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
@@ -1807,6 +1987,7 @@ mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifad
        
        i->next            = mDNSNULL;
        i->Exists          = mDNStrue;
+       i->LastSeen        = utc;
        i->scope_id        = scope_id;
        i->BSSID           = bssid;
        i->sa_family       = ifa->ifa_addr->sa_family;
@@ -1832,7 +2013,7 @@ mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope
        return(mDNSNULL);
        }
 
-mDNSlocal mStatus UpdateInterfaceList(mDNS *const m)
+mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
        {
        mDNSBool foundav4           = mDNSfalse;
        mDNSBool foundav6           = mDNSfalse;
@@ -1849,25 +2030,25 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m)
                {
 #if LIST_ALL_INTERFACES
                if (ifa->ifa_addr->sa_family == AF_APPLETALK)
-                       debugf("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
+                       LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_APPLETALK",
                                ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
                else if (ifa->ifa_addr->sa_family == AF_LINK)
-                       debugf("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
+                       LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d is AF_LINK",
                                ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
                else if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)
-                       debugf("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
+                       LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d not AF_INET (2) or AF_INET6 (30)",
                                ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
                if (!(ifa->ifa_flags & IFF_UP))
-                       debugf("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
+                       LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_UP",
                                ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
                if (!(ifa->ifa_flags & IFF_MULTICAST))
-                       debugf("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
+                       LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface not IFF_MULTICAST",
                                ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
                if (ifa->ifa_flags & IFF_POINTOPOINT)
-                       debugf("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
+                       LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_POINTOPOINT",
                                ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
                if (ifa->ifa_flags & IFF_LOOPBACK)
-                       debugf("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
+                       LogMsg("UpdateInterfaceList: %5s(%d) Flags %04X Family %2d Interface IFF_LOOPBACK",
                                ifa->ifa_name, if_nametoindex(ifa->ifa_name), ifa->ifa_flags, ifa->ifa_addr->sa_family);
 #endif
 
@@ -1916,7 +2097,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m)
                                                        else                                     v6Loopback = ifa;
                                                else
                                                        {
-                                                       AddInterfaceToList(m, ifa);
+                                                       AddInterfaceToList(m, ifa, utc);
                                                        if (ifa->ifa_addr->sa_family == AF_INET) foundav4 = mDNStrue;
                                                        else                                     foundav6 = mDNStrue;
                                                        }
@@ -1927,8 +2108,8 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m)
                }
 
     // For efficiency, we don't register a loopback interface when other interfaces of that family are available
-       if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback);
-       if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback);
+       if (!foundav4 && v4Loopback) AddInterfaceToList(m, v4Loopback, utc);
+       if (!foundav6 && v6Loopback) AddInterfaceToList(m, v6Loopback, utc);
 
        // Now the list is complete, set the McastTxRx setting for each interface.
        // We always send and receive using IPv4.
@@ -1958,13 +2139,21 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m)
        domainlabel nicelabel;
        nicelabel.c[0] = 0;
        GetUserSpecifiedFriendlyComputerName(&nicelabel);
-       if (nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
+       if (nicelabel.c[0] == 0)
+               {
+               LogMsg("Couldn't read user-specified Computer Name; using default “%s” instead", defaultname);
+               MakeDomainLabelFromLiteralString(&nicelabel, defaultname);
+               }
 
        // Set up the RFC 1034-compliant label
        domainlabel hostlabel;
        hostlabel.c[0] = 0;
        GetUserSpecifiedLocalHostName(&hostlabel);
-       if (hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
+       if (hostlabel.c[0] == 0)
+               {
+               LogMsg("Couldn't read user-specified local hostname; using default “%s.local” instead", defaultname);
+               MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
+               }
 
        if (SameDomainLabel(m->p->usernicelabel.c, nicelabel.c))
                debugf("Usernicelabel (%#s) unchanged since last time; not changing m->nicelabel (%#s)", m->p->usernicelabel.c, m->nicelabel.c);
@@ -1986,8 +2175,22 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m)
        return(mStatus_NoError);
        }
 
+mDNSlocal int CountMaskBits(mDNSAddr *mask)
+       {
+       int i = 0, bits = 0;
+       int bytes = mask->type == mDNSAddrType_IPv4 ? 4 : mask->type == mDNSAddrType_IPv6 ? 16 : 0;
+       while (i < bytes)
+               {
+               mDNSu8 b = mask->ip.v6.b[i++];
+               while (b & 0x80) { bits++; b <<= 1; }
+               if (b) return(-1);
+               }
+       while (i < bytes) if (mask->ip.v6.b[i++]) return(-1);
+       return(bits);
+       }
+
 // returns count of non-link local V4 addresses registered
-mDNSlocal int SetupActiveInterfaces(mDNS *const m)
+mDNSlocal int SetupActiveInterfaces(mDNS *const m, mDNSs32 utc)
        {
        NetworkInterfaceInfoOSX *i;
        int count = 0;
@@ -2010,10 +2213,15 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m)
                                // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
                                // If n->InterfaceID is NOT set, then we haven't registered it and we should not try to deregister it
                                n->InterfaceID = (mDNSInterfaceID)primary;
-                               mDNS_RegisterInterface(m, n);
+                               // If i->LastSeen == utc, then this is a brand-new interface, just created, or an interface that never went away.
+                               // If i->LastSeen != utc, then this is an old interface, previously seen, that went away for (utc - i->LastSeen) seconds.
+                               // If the interface is an old one that went away and came back in less than a minute, then we're in a flapping scenario.
+                               mDNSBool flapping = (utc - i->LastSeen > 0 && utc - i->LastSeen < 60);
+                               mDNS_RegisterInterface(m, n, flapping ? mDNSPlatformOneSecond * 5 : 0);
                                if (i->ifinfo.ip.type == mDNSAddrType_IPv4 &&  (i->ifinfo.ip.ip.v4.b[0] != 169 || i->ifinfo.ip.ip.v4.b[1] != 254)) count++;
-                               LogOperation("SetupActiveInterfaces:   Registered    %5s(%lu) %.6a InterfaceID %p %#a/%#a%s",
-                                       i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip, &n->mask, n->InterfaceActive ? " (Primary)" : "");
+                               LogOperation("SetupActiveInterfaces:   Registered    %5s(%lu) %.6a InterfaceID %p %#a/%d%s%s",
+                                       i->ifa_name, i->scope_id, &i->BSSID, primary, &n->ip, CountMaskBits(&n->mask),
+                                       flapping ? " (Flapping)" : "", n->InterfaceActive ? " (Primary)" : "");
                                }
        
                        if (!n->McastTxRx)
@@ -2023,30 +2231,34 @@ mDNSlocal int SetupActiveInterfaces(mDNS *const m)
                                if (i->sa_family == AF_INET && primary->ss.sktv4 == -1)
                                        {
                                        mStatus err = SetupSocket(m, &primary->ss, mDNStrue, &i->ifinfo.ip, AF_INET);
-                                       if (err == 0) debugf("SetupActiveInterfaces:   v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a",          primary->ss.sktv4, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip);
-                                       else          LogMsg("SetupActiveInterfaces:   v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a FAILED",   primary->ss.sktv4, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip);
+                                       if (err == 0) debugf("SetupActiveInterfaces:   v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d",          primary->ss.sktv4, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
+                                       else          LogMsg("SetupActiveInterfaces:   v4 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d FAILED",   primary->ss.sktv4, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
                                        }
                        
                                if (i->sa_family == AF_INET6 && primary->ss.sktv6 == -1)
                                        {
                                        mStatus err = SetupSocket(m, &primary->ss, mDNStrue, &i->ifinfo.ip, AF_INET6);
-                                       if (err == 0) debugf("SetupActiveInterfaces:   v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a",          primary->ss.sktv6, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip);
-                                       else          LogMsg("SetupActiveInterfaces:   v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a FAILED",   primary->ss.sktv6, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip);
+                                       if (err == 0) debugf("SetupActiveInterfaces:   v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d",          primary->ss.sktv6, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
+                                       else          LogMsg("SetupActiveInterfaces:   v6 socket%2d %5s(%lu) %.6a InterfaceID %p %#a/%d FAILED",   primary->ss.sktv6, i->ifa_name, i->scope_id, &i->BSSID, n->InterfaceID, &n->ip, CountMaskBits(&n->mask));
                                        }
                                }
                        }
        return count;
        }
 
-mDNSlocal void MarkAllInterfacesInactive(mDNS *const m)
+mDNSlocal void MarkAllInterfacesInactive(mDNS *const m, mDNSs32 utc)
        {
        NetworkInterfaceInfoOSX *i;
        for (i = m->p->InterfaceList; i; i = i->next)
+               {
+               if (i->Exists) i->LastSeen = utc;
                i->Exists = mDNSfalse;
+               }
        }
 
 mDNSlocal void CloseRunLoopSourceSocket(CFRunLoopSourceRef rls, CFSocketRef cfs)
        {
+       // Note: CFSocketInvalidate also closes the underlying socket for us
        // Comments show retain counts (obtained via CFGetRetainCount()) after each call.          rls 3 cfs 3
        CFRunLoopRemoveSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);                       // rls 2 cfs 3
        CFRelease(rls);                                                                                                                                         // rls ? cfs 3
@@ -2067,7 +2279,7 @@ mDNSlocal void CloseSocketSet(CFSocketSet *ss)
        }
 
 // returns count of non-link local V4 addresses deregistered
-mDNSlocal int ClearInactiveInterfaces(mDNS *const m)
+mDNSlocal int ClearInactiveInterfaces(mDNS *const m, mDNSs32 utc)
        {
        // First pass:
        // If an interface is going away, then deregister this from the mDNSCore.
@@ -2085,10 +2297,11 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m)
                if (i->ifinfo.InterfaceID)
                        if (i->Exists == 0 || i->Exists == 2 || i->ifinfo.InterfaceID != (mDNSInterfaceID)primary)
                                {
-                               LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a%s",
-                                       i->ifa_name, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, &i->ifinfo.ip, i->ifinfo.InterfaceActive ? " (Primary)" : "");
+                               LogOperation("ClearInactiveInterfaces: Deregistering %5s(%lu) %.6a InterfaceID %p %#a/%d%s",
+                                       i->ifa_name, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
+                                       &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), i->ifinfo.InterfaceActive ? " (Primary)" : "");
                                mDNS_DeregisterInterface(m, &i->ifinfo);
-                               if (i->ifinfo.ip.type == mDNSAddrType_IPv4 &&  (i->ifinfo.ip.ip.v4.b[0] != 169 || i->ifinfo.ip.ip.v4.b[1] != 254)) count++;
+                               if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && (i->ifinfo.ip.ip.v4.b[0] != 169 || i->ifinfo.ip.ip.v4.b[1] != 254)) count++;
                                i->ifinfo.InterfaceID = mDNSNULL;
                                // NOTE: If n->InterfaceID is set, that means we've called mDNS_RegisterInterface() for this interface,
                                // so we need to make sure we call mDNS_DeregisterInterface() before disposing it.
@@ -2106,31 +2319,39 @@ mDNSlocal int ClearInactiveInterfaces(mDNS *const m)
                // (We may have previously had both v4 and v6, and we may not need both any more.)
                CloseSocketSet(&i->ss);
                // 3. If no longer active, delete interface from list and free memory
-               if (!i->Exists && NumCacheRecordsForInterfaceID(m, (mDNSInterfaceID)i) == 0)
+               if (!i->Exists)
                        {
-                       debugf("ClearInactiveInterfaces: Deleting      %#a", &i->ifinfo.ip);
-                       *p = i->next;
-                       if (i->ifa_name) freeL("NetworkInterfaceInfoOSX name", i->ifa_name);
-                       freeL("NetworkInterfaceInfoOSX", i);
+                       if (i->LastSeen == utc) i->LastSeen = utc - 1;
+                       mDNSBool delete = (NumCacheRecordsForInterfaceID(m, (mDNSInterfaceID)i) == 0) && (utc - i->LastSeen >= 60);
+                       LogOperation("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
+                               i->ifa_name, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID,
+                               &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
+                               i->ifinfo.InterfaceActive ? " (Primary)" : "");
+                       if (delete)
+                               {
+                               *p = i->next;
+                               if (i->ifa_name) freeL("NetworkInterfaceInfoOSX name", i->ifa_name);
+                               freeL("NetworkInterfaceInfoOSX", i);
+                               continue;       // After deleting this object, don't want to do the "p = &i->next;" thing at the end of the loop
+                               }
                        }
-               else
-                       p = &i->next;
+               p = &i->next;
                }
        return count;
        }
 
-mDNSlocal mStatus RegisterSplitDNS(mDNS *m)
+mDNSlocal mStatus GetDNSConfig(void **result)
        {
 #ifndef MAC_OS_X_VERSION_10_4
        static int MessageShown = 0;
-       (void)m;
        if (!MessageShown) { MessageShown = 1; LogMsg("Note: Compiled without Apple-specific split DNS support"); }
-    return mStatus_UnsupportedErr;
+       *result = NULL;
+       return mStatus_UnsupportedErr;
 #else
-       int i;
-       dns_config_t *config = dns_configuration_copy();
 
-       if (!config)
+       *result = dns_configuration_copy();
+
+       if (!*result)
                {
                // When running on 10.3 (build 7xxx) and earlier, we don't expect dns_configuration_copy() to succeed
                if (mDNSMacOSXSystemBuildNumber(NULL) < 8) return mStatus_UnsupportedErr;
@@ -2139,55 +2360,70 @@ mDNSlocal mStatus RegisterSplitDNS(mDNS *m)
                // Apparently this is expected behaviour -- "not a bug".
                // Accordingly, we suppress syslog messages for the first three minutes after boot.
                // If we are still getting failures after three minutes, then we log them.
-               if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return mStatus_UnknownErr;
+               if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return mStatus_NoError;
 
-               LogMsg("RegisterSplitDNS: Error: dns_configuration_copy returned NULL");
+               LogMsg("GetDNSConfig: Error: dns_configuration_copy returned NULL");
                return mStatus_UnknownErr;
                }
-       mDNS_DeleteDNSServers(m);
+       return mStatus_NoError;
+#endif // MAC_OS_X_VERSION_10_4
+       }
 
-       LogOperation("RegisterSplitDNS: Registering %d resolvers", config->n_resolver);
-       for (i = 0; i < config->n_resolver; i++)                
+mDNSlocal mStatus RegisterSplitDNS(mDNS *m)
+       {
+       (void)m;  // unused on 10.3 systems
+       void *v;
+       mStatus err = GetDNSConfig(&v);
+       if (!err && v)
                {
-               int j, n;
-               domainname d;
-               dns_resolver_t *r = config->resolver[i];
-               if (r->port == MulticastDNSPort.NotAnInteger) continue; // ignore configurations for .local
-               if (r->search_order == DEFAULT_SEARCH_ORDER || !r->domain || !*r->domain) d.c[0] = 0; // we ignore domain for "default" resolver
-               else if (!MakeDomainNameFromDNSNameString(&d, r->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", r->domain); continue; }
-
-               // check if this is the lowest-weighted server for the domain
-               for (j = 0; j < config->n_resolver; j++)
+#ifdef MAC_OS_X_VERSION_10_4
+               int i;
+               dns_config_t *config = v;  // use void * to allow compilation on 10.3 systems
+               mDNS_DeleteDNSServers(m);
+               
+               LogOperation("RegisterSplitDNS: Registering %d resolvers", config->n_resolver);
+               for (i = 0; i < config->n_resolver; i++)                
                        {
-                       dns_resolver_t *p = config->resolver[j];
-                       if (p->port == MulticastDNSPort.NotAnInteger) continue;
-                       if (p->search_order <= r->search_order)
+                       int j, n;
+                       domainname d;
+                       dns_resolver_t *r = config->resolver[i];
+                       if (r->port == MulticastDNSPort.NotAnInteger) continue; // ignore configurations for .local
+                       if (r->search_order == DEFAULT_SEARCH_ORDER || !r->domain || !*r->domain) d.c[0] = 0; // we ignore domain for "default" resolver
+                       else if (!MakeDomainNameFromDNSNameString(&d, r->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", r->domain); continue; }
+                       
+                       // check if this is the lowest-weighted server for the domain
+                       for (j = 0; j < config->n_resolver; j++)
                                {
-                               domainname tmp;                         
-                               if (p->search_order == DEFAULT_SEARCH_ORDER || !p->domain || !*p->domain) tmp.c[0] = '\0';
-                               else if (!MakeDomainNameFromDNSNameString(&tmp, p->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", p->domain); continue; }
-                               if (SameDomainName(&d, &tmp))
-                                       if (p->search_order < r->search_order || j < i) break;  // if equal weights, pick first in list, otherwise pick lower-weight (p)
+                               dns_resolver_t *p = config->resolver[j];
+                               if (p->port == MulticastDNSPort.NotAnInteger) continue;
+                               if (p->search_order <= r->search_order)
+                                       {
+                                       domainname tmp;                         
+                                       if (p->search_order == DEFAULT_SEARCH_ORDER || !p->domain || !*p->domain) tmp.c[0] = '\0';
+                                       else if (!MakeDomainNameFromDNSNameString(&tmp, p->domain)) { LogMsg("RegisterSplitDNS: bad domain %s", p->domain); continue; }
+                                       if (SameDomainName(&d, &tmp))
+                                               if (p->search_order < r->search_order || j < i) break;  // if equal weights, pick first in list, otherwise pick lower-weight (p)
+                                       }
                                }
-                       }
-               if (j < config->n_resolver) // found a lower-weighted resolver for this domain
-                       { debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i, d.c, j); continue; }
-               // we're using this resolver - find the first IPv4 address
-               for (n = 0; n < r->n_nameserver; n++)
-                       {
-                       if (r->nameserver[n]->sa_family == AF_INET)
+                       if (j < config->n_resolver) // found a lower-weighted resolver for this domain
+                               { debugf("Rejecting DNS server in slot %d domain %##s (slot %d outranks)", i, d.c, j); continue; }
+                       // we're using this resolver - find the first IPv4 address
+                       for (n = 0; n < r->n_nameserver; n++)
                                {
-                               mDNSAddr saddr;
-                               if (SetupAddr(&saddr, r->nameserver[n])) { LogMsg("RegisterSplitDNS: bad IP address"); continue; }
-                               debugf("Adding dns server from slot %d %d.%d.%d.%d for domain %##s", i, saddr.ip.v4.b[0], saddr.ip.v4.b[1], saddr.ip.v4.b[2], saddr.ip.v4.b[3], d.c);
-                               mDNS_AddDNSServer(m, &saddr, &d);
-                               break;  // !!!KRS if we ever support round-robin servers, don't break here
+                               if (r->nameserver[n]->sa_family == AF_INET && !AddrRequiresPPPConnection(r->nameserver[n]))
+                                       {
+                                       mDNSAddr saddr;
+                                       if (SetupAddr(&saddr, r->nameserver[n])) { LogMsg("RegisterSplitDNS: bad IP address"); continue; }
+                                       debugf("Adding dns server from slot %d %d.%d.%d.%d for domain %##s", i, saddr.ip.v4.b[0], saddr.ip.v4.b[1], saddr.ip.v4.b[2], saddr.ip.v4.b[3], d.c);
+                                       mDNS_AddDNSServer(m, &saddr, &d);
+                                       break;  // !!!KRS if we ever support round-robin servers, don't break here
+                                       }
                                }
                        }
+               dns_configuration_free(config);
+#endif
                }
-       dns_configuration_free(config);
-       return mStatus_NoError;
-#endif 
+               return err;
        }
 
 mDNSlocal mStatus RegisterNameServers(mDNS *const m, CFDictionaryRef dict)
@@ -2235,7 +2471,7 @@ mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceR
        SearchListElem *slElem = question->QuestionContext;
        ARListElem *arElem, *ptr, *prev;
     AuthRecord *dereg;
-       char *name;
+       const char *name;
        mStatus err;
        
        if (AddRecord)
@@ -2243,15 +2479,16 @@ mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceR
                arElem = mallocL("FoundDomain - arElem", sizeof(ARListElem));
                if (!arElem) { LogMsg("ERROR: malloc");  return; }
                mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, FreeARElemCallback, arElem);
-               if      (question == &slElem->BrowseQ)       name = "_browse._dns-sd._udp.local.";
-               else if (question == &slElem->DefBrowseQ)    name = "_default._browse._dns-sd._udp.local.";
-               else if (question == &slElem->LegacyBrowseQ) name = "_legacy._browse._dns-sd._udp.local.";
-               else if (question == &slElem->RegisterQ)     name = "_register._dns-sd._udp.local.";
-               else if (question == &slElem->DefRegisterQ)  name = "_default._register._dns-sd._udp.local.";
+               if      (question == &slElem->BrowseQ)       name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowse];
+               else if (question == &slElem->DefBrowseQ)    name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault];
+               else if (question == &slElem->LegacyBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseLegacy];
+               else if (question == &slElem->RegisterQ)     name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistration];
+               else if (question == &slElem->DefRegisterQ)  name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistrationDefault];
                else { LogMsg("FoundDomain - unknown question"); return; }
                
-               MakeDomainNameFromDNSNameString(&arElem->ar.resrec.name, name);
-               AssignDomainName(arElem->ar.resrec.rdata->u.name, answer->rdata->u.name);
+               MakeDomainNameFromDNSNameString(arElem->ar.resrec.name, name);
+               AppendDNSNameString            (arElem->ar.resrec.name, "local");
+               AssignDomainName(&arElem->ar.resrec.rdata->u.name, &answer->rdata->u.name);
                err = mDNS_Register(m, &arElem->ar);
                if (err)
                        {
@@ -2270,7 +2507,7 @@ mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceR
                        {
                        if (SameDomainName(&ptr->ar.resrec.rdata->u.name, &answer->rdata->u.name))
                                {
-                               debugf("Deregistering PTR %s -> %s", ptr->ar.resrec.name.c, ptr->ar.resrec.rdata->u.name.c);
+                               debugf("Deregistering PTR %s -> %s", ptr->ar.resrec.name->c, ptr->ar.resrec.rdata->u.name.c);
                 dereg = &ptr->ar;
                                if (prev) prev->next = ptr->next;
                                else slElem->AuthRecs = ptr->next;
@@ -2287,13 +2524,20 @@ mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceR
                }
        }
 
-mDNSlocal void MarkSearchListElem(domainname *domain)
+mDNSlocal void MarkSearchListElem(const char *d)
        {
        SearchListElem *new, *ptr;
+       domainname domain;
        
+       if (!MakeDomainNameFromDNSNameString(&domain, d))
+               { LogMsg("ERROR: MarkSearchListElem - bad domain %##s", d); return; }
+
+       if (SameDomainName(&domain, &localdomain) || SameDomainName(&domain, &LocalReverseMapomain))
+               { debugf("MarkSearchListElem - ignoring local domain %##s", domain.c); return; } 
+
        // if domain is in list, mark as pre-existent (0)
        for (ptr = SearchList; ptr; ptr = ptr->next)
-               if (SameDomainName(&ptr->domain, domain))
+               if (SameDomainName(&ptr->domain, &domain))
                        {
                        if (ptr->flag != 1) ptr->flag = 0;  // gracefully handle duplicates - if it is already marked as add, don't bump down to preexistent
                        break;
@@ -2305,26 +2549,41 @@ mDNSlocal void MarkSearchListElem(domainname *domain)
                new = mallocL("MarkSearchListElem - SearchListElem", sizeof(SearchListElem));
                if (!new) { LogMsg("ERROR: MarkSearchListElem - malloc"); return; }
                bzero(new, sizeof(SearchListElem));
-               AssignDomainName(new->domain, *domain);
+               AssignDomainName(&new->domain, &domain);
                new->flag = 1;  // add
                new->next = SearchList;
                SearchList = new;
                }
        }
 
-mDNSlocal mStatus RegisterSearchDomains(mDNS *const m, CFDictionaryRef dict)
+// Get the search domains via OS X resolver routines.  Returns mStatus_UnsupporterErr if compiled or run on 10.3 systems
+mDNSlocal mStatus GetSearchDomains(void)
        {
-       struct ifaddrs *ifa = NULL;
+       void *v;
+       mStatus err = GetDNSConfig(&v);
+       if (!err && v)
+               {
+#ifdef MAC_OS_X_VERSION_10_4   
+               int i;
+               dns_config_t *config = v;
+               if (!config->n_resolver) return err;
+               dns_resolver_t *resolv = config->resolver[0];  // use the first slot for search domains
+
+               for (i = 0; i < resolv->n_search; i++) MarkSearchListElem(resolv->search[i]);
+               if (resolv->domain) MarkSearchListElem(resolv->domain);
+               dns_configuration_free(config);
+#endif
+               }
+       return err;
+       }
+
+// Get search domains from dynamic store - used as a fallback mechanism on 10.3 systems, if GetSearchDomains (above) fails.
+mDNSlocal void GetDSSearchDomains(CFDictionaryRef dict)
+       {
+       char buf[MAX_ESCAPED_DOMAIN_NAME];
        int i, count;
-       domainname domain;
-       char  buf[MAX_ESCAPED_DOMAIN_NAME];
+
        CFStringRef s;
-       SearchListElem *ptr, *prev, *freeSLPtr;
-       ARListElem *arList;
-       mStatus err;
-       
-       // step 1: mark each elem for removal (-1), unless we aren't passed a dictionary in which case we mark as preexistent
-       for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = dict ? -1 : 0;
 
        // get all the domains from "Search Domains" field of sharing prefs
        if (dict)
@@ -2336,32 +2595,42 @@ mDNSlocal mStatus RegisterSearchDomains(mDNS *const m, CFDictionaryRef dict)
                        for (i = 0; i < count; i++)
                                {
                                s = CFArrayGetValueAtIndex(searchdomains, i);
-                               if (!s) { LogMsg("ERROR: RegisterSearchDomains - CFArrayGetValueAtIndex"); break; }
+                               if (!s) { LogMsg("ERROR: GetDSSearchDomains - CFArrayGetValueAtIndex"); break; }
                                if (!CFStringGetCString(s, buf, MAX_ESCAPED_DOMAIN_NAME, kCFStringEncodingUTF8))
                                        {
-                                       LogMsg("ERROR: RegisterSearchDomains - CFStringGetCString");
+                                       LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString");
                                        continue;
                                        }
-                               if (!MakeDomainNameFromDNSNameString(&domain, buf))
-                                       {
-                                       LogMsg("ERROR: RegisterSearchDomains - invalid search domain %s", buf);
-                                       continue;
-                                       }
-                               MarkSearchListElem(&domain);
+                               MarkSearchListElem(buf);
                                }
                        }
+
+               // get DHCP domain field
                CFStringRef dname = CFDictionaryGetValue(dict, kSCPropNetDNSDomainName);
                if (dname)
                        {
                        if (CFStringGetCString(dname, buf, MAX_ESCAPED_DOMAIN_NAME, kCFStringEncodingUTF8))
-                               {
-                               if (MakeDomainNameFromDNSNameString(&domain, buf)) MarkSearchListElem(&domain);
-                               else LogMsg("ERROR: RegisterSearchDomains - invalid domain %s", buf);
-                               }
-                       else LogMsg("ERROR: RegisterSearchDomains - CFStringGetCString");
+                               MarkSearchListElem(buf);
+                       else LogMsg("ERROR: GetDSSearchDomains - CFStringGetCString");
                        }
                }
+       }
+
+mDNSlocal mStatus RegisterSearchDomains(mDNS *const m, CFDictionaryRef dict)
+       {
+       struct ifaddrs *ifa = NULL;
+       SearchListElem *ptr, *prev, *freeSLPtr;
+       ARListElem *arList;
+       mStatus err;
+
+       if (DomainDiscoveryDisabled) return mStatus_NoError;
        
+       // step 1: mark each elem for removal (-1), unless we aren't passed a dictionary in which case we mark as preexistent
+       for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = dict ? -1 : 0;
+
+       // Get search domains from resolver library (available in OS X 10.4 and later), reverting to dynamic store on 10.3 systems
+       if (GetSearchDomains() == mStatus_UnsupportedErr) GetDSSearchDomains(dict);
+       
        // Construct reverse-map search domains
        ifa = myGetIfAddrs(1);
        while (ifa)
@@ -2377,14 +2646,11 @@ mDNSlocal mStatus RegisterSearchDomains(mDNS *const m, CFDictionaryRef dict)
                                                              addr.ip.v4.b[2] & netmask.ip.v4.b[2],
                                                              addr.ip.v4.b[1] & netmask.ip.v4.b[1],
                                                              addr.ip.v4.b[0] & netmask.ip.v4.b[0]);
-                               MakeDomainNameFromDNSNameString(&domain, buffer);
-                               MarkSearchListElem(&domain);
+                               MarkSearchListElem(buffer);
                                }
                        }
                ifa = ifa->ifa_next;
                }
-
-       if (DynDNSRegDomain.c[0]) MarkSearchListElem(&DynDNSRegDomain);         // implicitly browse reg domain too (no-op if same as BrowseDomain)
        
        // delete elems marked for removal, do queries for elems marked add
        prev = NULL;
@@ -2406,7 +2672,7 @@ mDNSlocal mStatus RegisterSearchDomains(mDNS *const m, CFDictionaryRef dict)
                                {
                                AuthRecord *dereg = &arList->ar;
                                arList = arList->next;
-                               debugf("Deregistering PTR %s -> %s", dereg->resrec.name.c, dereg->resrec.rdata->u.name.c);
+                               debugf("Deregistering PTR %s -> %s", dereg->resrec.name->c, dereg->resrec.rdata->u.name.c);
                                err = mDNS_Deregister(m, dereg);
                                if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err);
                                }
@@ -2452,8 +2718,8 @@ mDNSlocal mStatus RegisterSearchDomains(mDNS *const m, CFDictionaryRef dict)
 mDNSlocal void SCPrefsDynDNSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
        {
        (void)m;  // unused
-       debugf("SCPrefsDynDNSCallback: result %d for registration of name %##s", result, rr->resrec.name.c);
-       SetDDNSNameStatus(&rr->resrec.name, result);
+       debugf("SCPrefsDynDNSCallback: result %d for registration of name %##s", result, rr->resrec.name->c);
+       SetDDNSNameStatus(rr->resrec.name, result);
        }
 
 mDNSlocal void SetSecretForDomain(mDNS *m, const domainname *domain)
@@ -2500,36 +2766,80 @@ mDNSlocal void SetSecretForDomain(mDNS *m, const domainname *domain)
                }
        }
 
+mDNSlocal void SetSCPrefsBrowseDomainsFromCFArray(mDNS *m, CFArrayRef browseDomains, mDNSBool add)
+       {
+       if (browseDomains)
+               {
+               CFIndex count = CFArrayGetCount(browseDomains);
+               CFDictionaryRef browseDict;
+               char buf[MAX_ESCAPED_DOMAIN_NAME];
+               int i;
+               
+               for (i = 0; i < count; i++)
+                       {
+                       browseDict = (CFDictionaryRef)CFArrayGetValueAtIndex(browseDomains, i);
+                       if (browseDict && DDNSSettingEnabled(browseDict))
+                               {
+                               CFStringRef name = CFDictionaryGetValue(browseDict, CFSTR("Domain"));
+                               if (name)
+                                       {
+                                       domainname BrowseDomain;
+                                       if (!CFStringGetCString(name, buf, sizeof(buf), kCFStringEncodingUTF8) || !MakeDomainNameFromDNSNameString(&BrowseDomain, buf) || !BrowseDomain.c[0])
+                                               LogMsg("SetSCPrefsBrowseDomainsFromCFArray SCDynamicStore bad DDNS browse domain: %s", buf[0] ? buf : "(unknown)");
+                                       else SetSCPrefsBrowseDomain(m, &BrowseDomain, add);
+                                       }
+                               }
+                       }
+               }
+       }
+
+
 mDNSlocal void DynDNSConfigChanged(mDNS *const m)
        {
        static mDNSBool LegacyNATInitialized = mDNSfalse;
        uDNS_GlobalInfo *u = &m->uDNS_info;
        CFDictionaryRef dict;
        CFStringRef     key;
-       domainname BrowseDomain, RegDomain, fqdn;
+       domainname RegDomain, fqdn;
+       CFArrayRef NewBrowseDomains = NULL;
        
        // get fqdn, zone from SCPrefs
-       GetUserSpecifiedDDNSConfig(&fqdn, &RegDomain, &BrowseDomain);
-       if (!fqdn.c[0] && !RegDomain.c[0]) ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &fqdn, &RegDomain);
+       GetUserSpecifiedDDNSConfig(&fqdn, &RegDomain, &NewBrowseDomains);
+       ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, fqdn.c[0] ? NULL : &fqdn, RegDomain.c[0] ? NULL : &RegDomain, &DomainDiscoveryDisabled);
 
-       if (!SameDomainName(&BrowseDomain, &DynDNSBrowseDomain))
-               {
-               if (DynDNSBrowseDomain.c[0]) SetSCPrefsBrowseDomain(m, &DynDNSBrowseDomain, mDNSfalse);
-               AssignDomainName(DynDNSBrowseDomain, BrowseDomain);
-               if (DynDNSBrowseDomain.c[0]) SetSCPrefsBrowseDomain(m, &DynDNSBrowseDomain, mDNStrue);
-               }
-       
        if (!SameDomainName(&RegDomain, &DynDNSRegDomain))
                {               
-               if (DynDNSRegDomain.c[0]) RemoveDefRegDomain(&DynDNSRegDomain);
-               AssignDomainName(DynDNSRegDomain, RegDomain);           
-               if (DynDNSRegDomain.c[0]) { SetSecretForDomain(m, &DynDNSRegDomain); AddDefRegDomain(&DynDNSRegDomain); }
+               if (DynDNSRegDomain.c[0])
+                       {
+                       RemoveDefRegDomain(&DynDNSRegDomain);
+                       SetSCPrefsBrowseDomain(m, &DynDNSRegDomain, mDNSfalse); // if we were automatically browsing in our registration domain, stop
+                       }
+               AssignDomainName(&DynDNSRegDomain, &RegDomain);         
+               if (DynDNSRegDomain.c[0])
+                       {
+                       SetSecretForDomain(m, &DynDNSRegDomain);
+                       AddDefRegDomain(&DynDNSRegDomain);
+                       SetSCPrefsBrowseDomain(m, &DynDNSRegDomain, mDNStrue);
+                       }
                }
+
+    // Add new browse domains to internal list
+       if (NewBrowseDomains) SetSCPrefsBrowseDomainsFromCFArray(m, NewBrowseDomains, mDNStrue);
+
+       // Remove old browse domains from internal list
+       if (DynDNSBrowseDomains) 
+               {
+               SetSCPrefsBrowseDomainsFromCFArray(m, DynDNSBrowseDomains, mDNSfalse);
+               CFRelease(DynDNSBrowseDomains);
+               }
+
+       // Replace the old browse domains array with the new array
+       DynDNSBrowseDomains = NewBrowseDomains;
        
        if (!SameDomainName(&fqdn, &DynDNSHostname))
                {
                if (DynDNSHostname.c[0]) mDNS_RemoveDynDNSHostName(m, &DynDNSHostname);
-               AssignDomainName(DynDNSHostname, fqdn);
+               AssignDomainName(&DynDNSHostname, &fqdn);
                if (DynDNSHostname.c[0])
                        {
                        SetSecretForDomain(m, &fqdn); // no-op if "zone" secret, above, is to be used for hostname
@@ -2570,9 +2880,19 @@ mDNSlocal void DynDNSConfigChanged(mDNS *const m)
        CFStringRef router = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
        if (router)
                {
+               struct sockaddr_in saddr;
+               
                if (!CFStringGetCString(router, buf, 256, kCFStringEncodingUTF8))
                        LogMsg("Could not convert router to CString");
-               else inet_aton(buf, (struct in_addr *)&r.ip.v4);
+               else
+                       {
+                       saddr.sin_len = sizeof(saddr);
+                       saddr.sin_family = AF_INET;
+                       saddr.sin_port = 0;                     
+                       inet_aton(buf, &saddr.sin_addr);
+                       if (AddrRequiresPPPConnection((struct sockaddr *)&saddr)) { debugf("Ignoring router %s (requires PPP connection)", buf); }
+                       else *(in_addr_t *)&r.ip.v4 = saddr.sin_addr.s_addr;
+                       }
                }
 
        // handle primary interface changes
@@ -2597,7 +2917,7 @@ mDNSlocal void DynDNSConfigChanged(mDNS *const m)
                                        r.ip.v4.NotAnInteger != u->Router.ip.v4.NotAnInteger)
                                        {
                                        if (LegacyNATInitialized) { LegacyNATDestroy(); LegacyNATInitialized = mDNSfalse; }
-                                       if (IsPrivateV4Addr(&ip))
+                                       if (r.ip.v4.NotAnInteger && IsPrivateV4Addr(&ip))
                                                {
                                                mStatus err = LegacyNATInit();
                                                if (err)  LogMsg("ERROR: LegacyNATInit");
@@ -2610,20 +2930,21 @@ mDNSlocal void DynDNSConfigChanged(mDNS *const m)
                        ifa = ifa->ifa_next;
                        }
                }
-
+       
        error:
        CFRelease(dict);
        }
 
 mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
-       {
+   {
        LogOperation("***   Network Configuration Change   ***");
-       MarkAllInterfacesInactive(m);
-       UpdateInterfaceList(m);
-       int nDeletions = ClearInactiveInterfaces(m);
-       int nAdditions = SetupActiveInterfaces(m);
-       if (nDeletions || nAdditions) mDNS_UpdateLLQs(m);
-       DynDNSConfigChanged(m);
+       mDNSs32 utc = mDNSPlatformUTC();
+       MarkAllInterfacesInactive(m, utc);
+       UpdateInterfaceList(m, utc);
+       int nDeletions = ClearInactiveInterfaces(m, utc);
+       int nAdditions = SetupActiveInterfaces(m, utc);
+       DynDNSConfigChanged(m);                           // note - call DynDNSConfigChanged *before* mDNS_UpdateLLQs                           
+       if (nDeletions || nAdditions) mDNS_UpdateLLQs(m); // so that LLQs are restarted against the up to date name servers
        
        if (m->MainCallback)
                m->MainCallback(m, mStatus_ConfigChanged);
@@ -2633,10 +2954,31 @@ mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, v
        {
        (void)store;        // Parameter not used
        (void)changedKeys;  // Parameter not used
-       LogOperation("***   NetworkChanged   ***");
        mDNS *const m = (mDNS *const)context;
        mDNS_Lock(m);
-       m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
+
+       mDNSs32 delay = mDNSPlatformOneSecond * 2;                                                      // Start off assuming a two-second delay
+
+       int c = CFArrayGetCount(changedKeys);                                                           // Count changes
+       CFRange range = { 0, c };
+       CFStringRef k1 = SCDynamicStoreKeyCreateComputerName(NULL);
+       CFStringRef k2 = SCDynamicStoreKeyCreateHostNames(NULL);
+       if (k1 && k2)
+               {
+               int c1 = (CFArrayContainsValue(changedKeys, range, k1) != 0);   // See if ComputerName changed
+               int c2 = (CFArrayContainsValue(changedKeys, range, k2) != 0);   // See if Local Hostname changed
+               int c3 = (CFArrayContainsValue(changedKeys, range, CFSTR("Setup:/Network/DynamicDNS")) != 0);
+               if (c && c - c1 - c2 - c3 == 0) delay = mDNSPlatformOneSecond/10;       // If these were the only changes, shorten delay
+               }
+       if (k1) CFRelease(k1);
+       if (k2) CFRelease(k2);
+
+       LogOperation("***   NetworkChanged   *** %d change%s, delay %d", c, c>1?"s":"", delay);
+
+       if (!m->p->NetworkChanged ||
+               m->p->NetworkChanged - NonZeroTime(m->timenow + delay) < 0)
+               m->p->NetworkChanged = NonZeroTime(m->timenow + delay);
+       
        if (!m->SuppressSending ||
                m->SuppressSending - m->p->NetworkChanged < 0)
                m->SuppressSending = m->p->NetworkChanged;
@@ -2706,10 +3048,12 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag
        switch(messageType)
                {
                case kIOMessageCanSystemPowerOff:               debugf("PowerChanged kIOMessageCanSystemPowerOff (no action)");                                                 break; // E0000240
-               case kIOMessageSystemWillPowerOff:              debugf("PowerChanged kIOMessageSystemWillPowerOff"); mDNSCoreMachineSleep(m, true);             break; // E0000250
+               case kIOMessageSystemWillPowerOff:              debugf("PowerChanged kIOMessageSystemWillPowerOff");
+                                                                                               mDNSCoreMachineSleep(m, true); mDNSMacOSXNetworkChanged(m);                                                             break; // E0000250
                case kIOMessageSystemWillNotPowerOff:   debugf("PowerChanged kIOMessageSystemWillNotPowerOff (no action)");                                             break; // E0000260
                case kIOMessageCanSystemSleep:                  debugf("PowerChanged kIOMessageCanSystemSleep (no action)");                                                    break; // E0000270
-               case kIOMessageSystemWillSleep:                 debugf("PowerChanged kIOMessageSystemWillSleep");        mDNSCoreMachineSleep(m, true);         break; // E0000280
+               case kIOMessageSystemWillSleep:                 debugf("PowerChanged kIOMessageSystemWillSleep");
+                                                                                               mDNSCoreMachineSleep(m, true); mDNSMacOSXNetworkChanged(m);                                                             break; // E0000280
                case kIOMessageSystemWillNotSleep:              debugf("PowerChanged kIOMessageSystemWillNotSleep (no action)");                                                break; // E0000290
                case kIOMessageSystemHasPoweredOn:              debugf("PowerChanged kIOMessageSystemHasPoweredOn");
                                                                                                // If still sleeping (didn't get 'WillPowerOn' message for some reason?) wake now
@@ -2790,17 +3134,19 @@ mDNSlocal mDNSBool mDNSPlatformInit_CanReceiveUnicast(void)
        }
 
 // Callback for the _legacy._browse queries - add answer to list of domains to search for empty-string browses
-mDNSlocal void FoundDefBrowseDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void FoundLegacyBrowseDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
        {
        DNameListElem *ptr, *prev, *new;
        (void)m; // unused;
        (void)question;  // unused
 
+       LogMsg("%s browse domain %##s", AddRecord ? "Adding" : "Removing", answer->rdata->u.name.c);
+       
        if (AddRecord)
                {
-               new = mallocL("FoundDefBrowseDomain", sizeof(DNameListElem));
+               new = mallocL("FoundLegacyBrowseDomain", sizeof(DNameListElem));
                if (!new) { LogMsg("ERROR: malloc"); return; }
-               AssignDomainName(new->name, answer->rdata->u.name);
+               AssignDomainName(&new->name, &answer->rdata->u.name);
                new->next = DefBrowseList;
                DefBrowseList = new;
                DefaultBrowseDomainChanged(&new->name, mDNStrue);
@@ -2819,13 +3165,55 @@ mDNSlocal void FoundDefBrowseDomain(mDNS *const m, DNSQuestion *question, const
                                udsserver_default_browse_domain_changed(&ptr->name, mDNSfalse);
                                if (prev) prev->next = ptr->next;
                                else DefBrowseList = ptr->next;
-                               freeL("FoundDefBrowseDomain", ptr);                             
+                               freeL("FoundLegacyBrowseDomain", ptr);                          
                                return;
                                }
                        prev = ptr;
                        ptr = ptr->next;
                        }
-               LogMsg("FoundDefBrowseDomain: Got remove event for domain %s not in list", answer->rdata->u.name.c);
+               LogMsg("FoundLegacyBrowseDomain: Got remove event for domain %s not in list", answer->rdata->u.name.c);
+               }
+       }
+
+mDNSlocal void RegisterBrowseDomainPTR(mDNS *m, const domainname *d, int type)
+       {
+       // allocate/register legacy and non-legacy _browse PTR record
+       ARListElem *browse = mallocL("ARListElem", sizeof(*browse));
+       mDNS_SetupResourceRecord(&browse->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, FreeARElemCallback, browse);
+       MakeDomainNameFromDNSNameString(browse->ar.resrec.name, mDNS_DomainTypeNames[type]);
+       AppendDNSNameString            (browse->ar.resrec.name, "local");
+       AssignDomainName(&browse->ar.resrec.rdata->u.name, d);
+       mStatus err = mDNS_Register(m, &browse->ar);
+       if (err)
+               {
+               LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err);
+               freeL("ARListElem", browse);
+               }
+       else
+               {
+               browse->next = SCPrefBrowseDomains;
+               SCPrefBrowseDomains = browse;
+               }
+       }
+
+mDNSlocal void DeregisterBrowseDomainPTR(mDNS *m, const domainname *d, int type)
+       {
+       ARListElem *remove, **ptr = &SCPrefBrowseDomains;
+       domainname lhs; // left-hand side of PTR, for comparison
+       
+       MakeDomainNameFromDNSNameString(&lhs, mDNS_DomainTypeNames[type]);
+       AppendDNSNameString            (&lhs, "local");
+
+       while (*ptr)
+               {
+               if (SameDomainName(&(*ptr)->ar.resrec.rdata->u.name, d) && SameDomainName((*ptr)->ar.resrec.name, &lhs))
+                       {
+                       remove = *ptr;
+                       *ptr = (*ptr)->next;
+                       mDNS_Deregister(m, &remove->ar);
+                       return;
+                       }
+               else ptr = &(*ptr)->next;
                }
        }
 
@@ -2833,51 +3221,25 @@ mDNSlocal void FoundDefBrowseDomain(mDNS *const m, DNSQuestion *question, const
 // Also register a non-legacy _browse PTR record so that the domain appears in enumeration lists
 mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add)
        {
-       AuthRecord rec;
+       debugf("SetSCPrefsBrowseDomain: %s default browse domain %##s", add ? "Adding" : "Removing", d->c);
        
-       // Create dummy  record pointing to the domain to be added/removed
-       mDNS_SetupResourceRecord(&rec, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
-       AssignDomainName(rec.resrec.rdata->u.name, *d);
-
-       // add/remove the "_legacy" entry
-       MakeDomainNameFromDNSNameString(&rec.resrec.name, "_legacy._browse._dns-sd._udp.local.");
-       FoundDefBrowseDomain(m, &LegacyBrowseDomainQ, &rec.resrec, add);
-
        if (add)
                {
-               // allocate/register a non-legacy _browse PTR record
-               ARListElem *ptr = mallocL("ARListElem", sizeof(*ptr));
-               mDNS_SetupResourceRecord(&ptr->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, FreeARElemCallback, ptr);
-               MakeDomainNameFromDNSNameString(&ptr->ar.resrec.name, "_browse._dns-sd._udp.local.");
-               AssignDomainName(ptr->ar.resrec.rdata->u.name, *d);
-               mStatus err = mDNS_Register(m, &ptr->ar);
-               if (err)
-                       {
-                       LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err);
-                       freeL("ARListElem", ptr);
-                       }
-               else
-                       {
-                       ptr->next = SCPrefBrowseDomains;
-                       SCPrefBrowseDomains = ptr;
-                       }
+               RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse);
+               RegisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy);
                }
        else
                {
-               ARListElem **remove = &SCPrefBrowseDomains;
-               while (*remove && !SameDomainName(&(*remove)->ar.resrec.rdata->u.name, d)) remove = &(*remove)->next;
-               if (!*remove) { LogMsg("SetSCPrefsBrowseDomain (remove) - domain %##s not found!", d->c); return; }
-               mDNS_Deregister(m, &(*remove)->ar);
-               *remove = (*remove)->next;
+               DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowse);
+               DeregisterBrowseDomainPTR(m, d, mDNS_DomainTypeBrowseLegacy);
                }
        }
 
-
 // Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
-// 1) query for _browse._dns-sd._udp.local on LocalOnly interface
+// 1) query for b._dns-sd._udp.local on LocalOnly interface
 //    (.local manually generated via explicit callback)
-// 2) for each search domain (from prefs pane), query for _browse._dns-sd._udp.<searchdomain>.
-// 3) for each result from (2), register LocalOnly PTR record_browse._dns-sd._udp.local. -> <result>
+// 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
+// 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
 // 4) result above should generate a callback from question in (1).  result added to global list
 // 5) global list delivered to client via GetSearchDomainList()
 // 6) client calls to enumerate domains now go over LocalOnly interface
@@ -2886,17 +3248,39 @@ mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add
 mDNSlocal mStatus InitDNSConfig(mDNS *const m)
        {
        mStatus err;
-
+       static AuthRecord LocalRegPTR;
+       
        // start query for domains to be used in default (empty string domain) browses
-       err = mDNS_GetDomains(m, &LegacyBrowseDomainQ, mDNS_DomainTypeBrowseLegacy, NULL, mDNSInterface_LocalOnly, FoundDefBrowseDomain, NULL);
+       err = mDNS_GetDomains(m, &LegacyBrowseDomainQ, mDNS_DomainTypeBrowseLegacy, NULL, mDNSInterface_LocalOnly, FoundLegacyBrowseDomain, NULL);
 
-       // provide .local automatically
+       // provide browse domain "local" automatically
        SetSCPrefsBrowseDomain(m, &localdomain, mDNStrue);
-    return mStatus_NoError;
+
+       // register registration domain "local"
+       mDNS_SetupResourceRecord(&LocalRegPTR, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, NULL, NULL);
+       MakeDomainNameFromDNSNameString(LocalRegPTR.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeRegistration]);
+       AppendDNSNameString            (LocalRegPTR.resrec.name, "local");
+       AssignDomainName(&LocalRegPTR.resrec.rdata->u.name, &localdomain);
+       err = mDNS_Register(m, &LocalRegPTR);
+       if (err) LogMsg("ERROR: InitDNSConfig - mDNS_Register returned error %d", err);
+       
+       return mStatus_NoError;
        }
 
 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
        {
+       // In 10.4, mDNSResponder is launched very early in the boot process, while other subsystems are still in the process of starting up.
+       // If we can't read the user's preferences, then we sleep a bit and try again, for up to five seconds before we give up.
+       int i;
+       for (i=0; i<100; i++)
+               {
+               domainlabel testlabel;
+               testlabel.c[0] = 0;
+               GetUserSpecifiedLocalHostName(&testlabel);
+               if (testlabel.c[0]) break;
+               usleep(50000);
+               }
+
        mStatus err;
 
        m->hostlabel.c[0]        = 0;
@@ -2944,8 +3328,9 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
        m->p->userhostlabel.c[0] = 0;
        m->p->usernicelabel.c[0] = 0;
        m->p->NotifyUser         = 0;
-       UpdateInterfaceList(m);
-       SetupActiveInterfaces(m);
+       mDNSs32 utc = mDNSPlatformUTC();
+       UpdateInterfaceList(m, utc);
+       SetupActiveInterfaces(m, utc);
 
        err = WatchForNetworkChanges(m);
        if (err) return(err);
@@ -2954,7 +3339,6 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
        if (err) return err;
 
        DynDNSRegDomain.c[0] = '\0';
-       DynDNSBrowseDomain.c[0] = '\0';
        DynDNSConfigChanged(m);                                         // Get initial DNS configuration
 
        InitDNSConfig(m);
@@ -2994,8 +3378,9 @@ mDNSexport void mDNSPlatformClose(mDNS *const m)
                m->p->StoreRLS = NULL;
                }
        
-       MarkAllInterfacesInactive(m);
-       ClearInactiveInterfaces(m);
+       mDNSs32 utc = mDNSPlatformUTC();
+       MarkAllInterfacesInactive(m, utc);
+       ClearInactiveInterfaces(m, utc);
        CloseSocketSet(&m->p->unicastsockets);
        }
 
@@ -3044,7 +3429,9 @@ mDNSexport mDNSs32 mDNSPlatformRawTime(void)
                LogMsg("mDNSPlatformRawTime: this_mach_absolute_time %08X%08X", this_mach_absolute_time);
                // Update last_mach_absolute_time *before* calling NotifyOfElusiveBug()
                last_mach_absolute_time = this_mach_absolute_time;
-               NotifyOfElusiveBug("mach_absolute_time went backwards!", 3438376, "");
+               // Only show "mach_absolute_time went backwards" notice on 10.4 (build 8xxx) or later
+               if (mDNSMacOSXSystemBuildNumber(NULL) >= 8)
+                       NotifyOfElusiveBug("mach_absolute_time went backwards!", 3438376, "");
                }
        last_mach_absolute_time = this_mach_absolute_time;
 
index 2a81939f017dda090888ad1eb490aac9ef32d4b1..0222d04fe427853750a1ada24f9d6d4fd62163b3 100644 (file)
     Change History (most recent first):
 
 $Log: mDNSMacOSX.h,v $
+Revision 1.49  2004/12/17 23:37:47  cheshire
+<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
+(and other repetitive configuration changes)
+
 Revision 1.48  2004/12/07 01:31:31  cheshire
 mDNSMacOSXSystemBuildNumber() returns int, not mDNSBool
 
@@ -203,7 +207,6 @@ Defines mDNS_PlatformSupport_struct for OS X
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include "mDNSEmbeddedAPI.h"  // for domain name structure
-       
 
 typedef struct NetworkInterfaceInfoOSX_struct NetworkInterfaceInfoOSX;
 
@@ -225,6 +228,7 @@ struct NetworkInterfaceInfoOSX_struct
        NetworkInterfaceInfoOSX *next;
        mDNSu32                  Exists;                        // 1 = currently exists in getifaddrs list; 0 = doesn't
                                                                                                // 2 = exists, but McastTxRx state changed
+       mDNSs32                  LastSeen;                      // If Exists==0, last time this interface appeared in getifaddrs list
        char                    *ifa_name;                      // Memory for this is allocated using malloc
        mDNSu32                  scope_id;                      // interface index / IPv6 scope ID
        mDNSEthAddr              BSSID;                         // BSSID of 802.11 base station, if applicable
diff --git a/mDNSMacOSX/mDNSResponder.order b/mDNSMacOSX/mDNSResponder.order
new file mode 100644 (file)
index 0000000..62c0240
--- /dev/null
@@ -0,0 +1,377 @@
+no_module:start
+no_module:__call_mod_init_funcs
+no_module:__start
+no_module:__dyld_func_lookup
+no_module:dyld_stub_binding_helper
+no_module:_main
+no_module:_LogMsgIdent
+no_module:_mDNS_vsnprintf
+no_module:_WriteLogMsg
+no_module:_mDNSDaemonInitialize
+no_module:_mDNSMacOSXSystemBuildNumber
+no_module:_mDNS_Init
+no_module:_mDNSPlatformTimeInit
+no_module:___udivdi3
+no_module:_mDNSRandom
+no_module:_mDNSPlatformRandomSeed
+no_module:_mDNSPlatformRawTime
+no_module:_mDNS_GrowCache_internal
+no_module:_LogMsg
+no_module:_uDNS_Init
+no_module:_mDNSPlatformMemZero
+no_module:_mDNSPlatformInit
+no_module:_mDNSPlatformInit_setup
+no_module:_mDNS_snprintf
+no_module:_mDNSPlatformInit_CanReceiveUnicast
+no_module:_mDNSPlatformStrLen
+no_module:_mDNSPlatformMemCopy
+no_module:_SetupSocket
+no_module:_mDNSPlatformUTC
+no_module:_UpdateInterfaceList
+no_module:_myGetIfAddrs
+no_module:_AddInterfaceToList
+no_module:_GetBSSID
+no_module:_SetupAddr
+no_module:_mallocL
+no_module:_validatelists
+no_module:_mDNSSameAddress
+no_module:_FindRoutableIPv4
+no_module:_GetUserSpecifiedFriendlyComputerName
+no_module:_GetUserSpecifiedLocalHostName
+no_module:_SameDomainLabel
+no_module:_mDNS_SetFQDN
+no_module:_AppendDomainLabel
+no_module:_DomainNameLength
+no_module:_AppendLiteralLabelString
+no_module:_SameDomainName
+no_module:_mDNS_Lock
+no_module:_mDNSPlatformLock
+no_module:_mDNS_Unlock
+no_module:_GetNextScheduledEvent
+no_module:_mDNSPlatformUnlock
+no_module:_SetupActiveInterfaces
+no_module:_SearchForInterfaceByName
+no_module:_mDNS_RegisterInterface
+no_module:_AdvertiseInterface
+no_module:_FindFirstAdvertisedInterface
+no_module:_mDNS_SetupResourceRecord
+no_module:_MakeDomainNameFromDNSNameString
+no_module:_AppendDNSNameString
+no_module:_mDNS_Register_internal
+no_module:_IsLocalDomain
+no_module:_InitializeLastAPTime
+no_module:_SetNextAnnounceProbeTime
+no_module:_GetRDLength
+no_module:_ValidateRData
+no_module:_DomainNameHashValue
+no_module:_RDataHashValue
+no_module:_SetTargetToHostName
+no_module:_SetNewRData
+no_module:_CompressedDomainNameLength
+no_module:_AcknowledgeRecord
+no_module:_IdenticalResourceRecord
+no_module:_CountMaskBits
+no_module:_SameRData
+no_module:_mDNSPlatformMemSame
+no_module:_WatchForNetworkChanges
+no_module:_WatchForPowerChanges
+no_module:_DynDNSConfigChanged
+no_module:_GetUserSpecifiedDDNSConfig
+no_module:_ReadDDNSSettingsFromConfFile
+no_module:_RegisterSplitDNS
+no_module:_GetDNSConfig
+no_module:_RegisterSearchDomains
+no_module:_GetSearchDomains
+no_module:_GetDSSearchDomains
+no_module:_IsPrivateV4Addr
+no_module:_mDNS_SetPrimaryInterfaceInfo
+no_module:_InitDNSConfig
+no_module:_mDNS_GetDomains
+no_module:_AppendDomainName
+no_module:_mDNS_StartQuery
+no_module:_mDNS_StartQuery_internal
+no_module:_CheckForSoonToExpireRecords
+no_module:_CacheGroupForName
+no_module:_FindDuplicateQuestion
+no_module:_SetSCPrefsBrowseDomain
+no_module:_RegisterBrowseDomainPTR
+no_module:_mDNS_Register
+no_module:_FreeARElemCallback
+no_module:_mDNSCoreInitComplete
+no_module:_mDNS_StatusCallback
+no_module:_RecordUpdatedNiceLabel
+no_module:_udsserver_init
+no_module:_udsSupportAddFDToEventLoop
+no_module:_InitLinkedList
+no_module:_AddToTail
+no_module:_mDNSDaemonIdle
+no_module:_mDNS_TimeNow
+no_module:_mDNS_Execute
+no_module:_AnswerNewLocalOnlyQuestion
+no_module:_uDNS_Execute
+no_module:_mDNSPlatformTimeNow
+no_module:_CheckNATMappings
+no_module:_CheckQueries
+no_module:_CheckRecordRegistrations
+no_module:_CheckServiceRegistrations
+no_module:_udsserver_idle
+no_module:_cf_callback
+no_module:_connect_callback
+no_module:_request_callback
+no_module:_read_msg
+no_module:_ConvertHeaderBytes
+no_module:_validate_message
+no_module:_handle_regservice_request
+no_module:_get_long
+no_module:_mDNSPlatformInterfaceIDfromInterfaceIndex
+no_module:_get_string
+no_module:_get_short
+no_module:_get_rdata
+no_module:_ChopSubTypes
+no_module:_FindFirstSubType
+no_module:_ConstructServiceName
+no_module:_CountExistingRegistrations
+no_module:_register_service_instance
+no_module:_AllocateSubTypes
+no_module:_mDNS_RegisterService
+no_module:_ServiceCallback
+no_module:_mDNSPlatformGetRegDomainList
+no_module:_mDNS_CopyDNameList
+no_module:_mDNS_FreeDNameList
+no_module:_deliver_error
+no_module:_dnssd_htonl
+no_module:_put_long
+no_module:_reset_connected_rstate
+no_module:_freeL
+no_module:_SendQueries
+no_module:_GetFirstActiveInterface
+no_module:_InitializeDNSMessage
+no_module:_putQuestion
+no_module:_putDomainNameAsLabels
+no_module:_FindCompressionPointer
+no_module:_GetNextActiveInterfaceID
+no_module:_PutResourceRecordTTLWithLimit
+no_module:_putRData
+no_module:_mDNSSendDNSMessage
+no_module:_mDNSPlatformSendUDP
+no_module:_mDNSAddrIsDNSMulticast
+no_module:_myCFSocketCallBack
+no_module:_myrecvfrom
+no_module:_mDNSCoreReceive
+no_module:_mDNSCoreReceiveQuery
+no_module:_ProcessQuery
+no_module:_AddressIsLocalSubnet
+no_module:_getQuestion
+no_module:_getDomainName
+no_module:_ResourceRecordAnswersQuestion
+no_module:_ResolveSimultaneousProbe
+no_module:_LocateAuthorities
+no_module:_LocateAnswers
+no_module:_skipQuestion
+no_module:_skipDomainName
+no_module:_GetLargeResourceRecord
+no_module:_PacketRRConflict
+no_module:_MatchDependentOn
+no_module:_FindRRSet
+no_module:_AddAdditionalsToResponseList
+no_module:_NetworkChanged
+no_module:_MakeDomainLabelFromLiteralString
+no_module:_mDNSMacOSXNetworkChanged
+no_module:_MarkAllInterfacesInactive
+no_module:_ClearInactiveInterfaces
+no_module:_mDNS_DeregisterInterface
+no_module:_UpdateInterfaceProtocols
+no_module:_DeadvertiseInterface
+no_module:_mDNS_Deregister_internal
+no_module:_mDNS_HostNameCallback
+no_module:_CloseSocketSet
+no_module:_CloseRunLoopSourceSocket
+no_module:_NumCacheRecordsForInterfaceID
+no_module:_RegisterNameServers
+no_module:_mDNS_DeleteDNSServers
+no_module:_mDNS_AddDNSServer
+no_module:_mDNSPlatformMemAllocate
+no_module:_MarkSearchListElem
+no_module:_uDNS_StartQuery
+no_module:_startQuery
+no_module:_newMessageID
+no_module:_constructQueryMsg
+no_module:_initializeQuery
+no_module:_LinkActiveQuestion
+no_module:_uDNS_IsActiveQuery
+no_module:_GetServerForName
+no_module:_CountLabels
+no_module:_UpdateHostnameRegistrations
+no_module:_UpdateSRVRecords
+no_module:_GetStaticHostname
+no_module:_mDNS_UpdateLLQs
+no_module:_SuspendLLQs
+no_module:_CheckForUnreferencedLLQMapping
+no_module:_RestartQueries
+no_module:_udsserver_handle_configchange
+no_module:_rename_service
+no_module:_AnswerLocalQuestions
+no_module:_AnswerLocalOnlyQuestionWithResourceRecord
+no_module:_FoundDefBrowseDomain
+no_module:_DefaultBrowseDomainChanged
+no_module:_udsserver_default_browse_domain_changed
+no_module:_SendResponses
+no_module:_uDNS_ReceiveMsg
+no_module:_recvLLQResponse
+no_module:_simpleResponseHndlr
+no_module:_pktResponseHndlr
+no_module:_deriveGoodbyes
+no_module:_mDNSCoreReceiveResponse
+no_module:_kaListContainsAnswer
+no_module:_addKnownAnswer
+no_module:_FoundDomain
+no_module:_SameResourceRecord
+no_module:_mDNSPlatformMemFree
+no_module:_FoundStaticHostname
+no_module:_PacketRRMatchesSignature
+no_module:_CacheGroupForRecord
+no_module:_GetCacheGroup
+no_module:_GetCacheEntity
+no_module:_GetCacheRecord
+no_module:_CacheRecordAdd
+no_module:_SetNextCacheCheckTime
+no_module:_SameResourceRecordSignature
+no_module:_CacheRecordDeferredAdd
+no_module:_regservice_callback
+no_module:_process_service_registration
+no_module:_gen_rr_response
+no_module:_DeconstructServiceName
+no_module:_ConvertDomainLabelToCString_withescape
+no_module:_ConvertDomainNameToCString_withescape
+no_module:_create_reply
+no_module:_mDNSPlatformInterfaceIndexfromInterfaceID
+no_module:_put_string
+no_module:_send_msg
+no_module:_CountPeerRegistrations
+no_module:_CheckCacheExpiration
+no_module:_FindIdenticalRecordInCache
+no_module:_handle_browse_request
+no_module:_mDNSPlatformGetSearchDomainList
+no_module:_add_domain_to_browser
+no_module:_mDNS_StartBrowse
+no_module:_SetNextQueryTime
+no_module:_startLLQ
+no_module:_startGetZoneData
+no_module:_getZoneData
+no_module:_hndlLookupSOA
+no_module:_startInternalQuery
+no_module:_AnswerNewQuestion
+no_module:_ExpireDupSuppressInfo
+no_module:_SuppressOnThisInterface
+no_module:_BuildQuestion
+no_module:_uDNS_StopQuery
+no_module:_processSOA
+no_module:_confirmNS
+no_module:_lookupNSAddr
+no_module:_LocateAdditionals
+no_module:_skipResourceRecord
+no_module:_hndlLookupPorts
+no_module:_lookupDNSPort
+no_module:_startLLQHandshakeCallback
+no_module:_mDNS_GrowCache
+no_module:_AnswerQuestionWithResourceRecord
+no_module:_browse_result_callback
+no_module:_DNSTypeName
+no_module:_GetRRDisplayString_rdb
+no_module:_append_reply
+no_module:_llqResponseHndlr
+no_module:_AccelerateThisQuery
+no_module:_ReconfirmAntecedents
+no_module:_handle_enum_request
+no_module:_format_enumeration_reply
+no_module:_enum_result_callback
+no_module:_ReleaseCacheRecord
+no_module:_ReleaseCacheEntity
+no_module:_AddRecordToResponseList
+no_module:_ShouldSuppressKnownAnswer
+no_module:_RecordDupSuppressInfo
+no_module:_ReleaseCacheGroup
+no_module:_CacheRecordRmv
+no_module:_hndlTruncatedAnswer
+no_module:_mDNSPlatformTCPConnect
+no_module:_tcpCFSocketCallback
+no_module:_conQueryCallback
+no_module:_mDNSPlatformWriteTCP
+no_module:_mDNSPlatformReadTCP
+no_module:_mDNSPlatformTCPCloseConnection
+no_module:_handle_add_request
+no_module:_add_record_to_service
+no_module:_mDNS_AddRecordToService
+no_module:_handle_update_request
+no_module:_update_record
+no_module:_mDNS_Update
+no_module:_handle_query_request
+no_module:_question_result_callback
+no_module:_put_short
+no_module:_put_rdata
+no_module:_abort_request
+no_module:_question_termination_callback
+no_module:_mDNS_StopQuery
+no_module:_mDNS_StopQuery_internal
+no_module:_UpdateQuestionDuplicates
+no_module:_udsSupportRemoveFDFromEventLoop
+no_module:_RemoveFromList
+no_module:_unlink_request
+no_module:_DNSserverCallback
+no_module:_DNSServiceDiscoveryRequest_server
+no_module:__XDNSServiceResolverResolve_rpc
+no_module:___MIG_check__Request__DNSServiceResolverResolve_rpc_t
+no_module:_provide_DNSServiceResolverResolve_rpc
+no_module:_CheckForExistingClient
+no_module:_mDNS_StartResolveService
+no_module:_EnableDeathNotificationForClient
+no_module:_FoundServiceInfoSRV
+no_module:_MachineHasActiveIPv6
+no_module:_FoundServiceInfoTXT
+no_module:_FoundServiceInfo
+no_module:_FoundInstanceInfo
+no_module:_DNSServiceResolverReply_rpc
+no_module:_ExpireDupSuppressInfoOnInterface
+no_module:_CompleteRDataUpdate
+no_module:_update_callback
+no_module:_GenerateUnicastResponse
+no_module:_PutResourceRecordCappedTTL
+no_module:_ClientDeathCallback
+no_module:_AbortClient
+no_module:_mDNS_StopResolveService
+no_module:_mDNS_Reconfirm_internal
+no_module:_browse_termination_callback
+no_module:_stopLLQ
+no_module:_GrantUpdateCredit
+no_module:__XDNSServiceBrowserCreate_rpc
+no_module:___MIG_check__Request__DNSServiceBrowserCreate_rpc_t
+no_module:_provide_DNSServiceBrowserCreate_rpc
+no_module:_AddDomainToBrowser
+no_module:_FoundInstance
+no_module:_DNSServiceBrowserReply_rpc
+no_module:__XDNSServiceRegistrationCreate_rpc
+no_module:___MIG_check__Request__DNSServiceRegistrationCreate_rpc_t
+no_module:_provide_DNSServiceRegistrationCreate_rpc
+no_module:_AddServiceInstance
+no_module:_RegCallback
+no_module:_DNSServiceRegistrationReply_rpc
+no_module:_mDNS_DeregisterService
+no_module:_CompleteDeregistration
+no_module:_FreeServiceInstance
+no_module:_PowerChanged
+no_module:_mDNSCoreMachineSleep
+no_module:_uDNS_Sleep
+no_module:_SleepServiceRegistrations
+no_module:_SleepRecordRegistrations
+no_module:_PurgeCacheResourceRecord
+no_module:_regservice_termination_callback
+no_module:_free_service_instance
+no_module:_FreeExtraRR
+no_module:_mDNS_Deregister
+no_module:_uDNS_Wake
+no_module:_WakeServiceRegistrations
+no_module:_WakeRecordRegistrations
+no_module:_SendDelayedUnicastResponse
+no_module:_mDNS_RenameAndReregisterService
+no_module:_FindNextSubType
+no_module:_handle_removerecord_request
index 8ba74f874ce05cbd02cdde2a414ee1ea4c3f9484..41f07c3ee8ce821b3b95962eb593f0163a339b9f 100644 (file)
@@ -32,7 +32,7 @@
                                OTHER_REZFLAGS = "";
                                PRODUCT_NAME = mDNSResponder.debug;
                                REZ_EXECUTABLE = YES;
-                               SECTORDER_FLAGS = "";
+                               SECTORDER_FLAGS = "-sectorder __TEXT __text mDNSResponder.order";
                                STRIPFLAGS = "-S";
                                WARNING_CFLAGS = "-W -Wall -Wmissing-prototypes -Wno-four-char-constants -Wno-unknown-pragmas";
                        };
                                08FB77A3FE84155DC02AAC07,
                                08FB77A5FE84155DC02AAC07,
                                FF5A0AE705632EA600743C27,
+                               FF5585E507790732008D1C14,
                        );
                        buildSettings = {
                                FRAMEWORK_SEARCH_PATHS = "";
                                OTHER_REZFLAGS = "";
                                PRODUCT_NAME = mDNSResponder;
                                REZ_EXECUTABLE = YES;
-                               SECTORDER_FLAGS = "";
+                               SECTORDER_FLAGS = "-sectorder __TEXT __text mDNSResponder.order";
                                STRIPFLAGS = "-S";
                                WARNING_CFLAGS = "-W -Wall -Wmissing-prototypes -Wno-four-char-constants -Wno-unknown-pragmas";
                        };
                        path = ../mDNSShared/mDNSResponder.8;
                        refType = 2;
                };
+               FF5585E507790732008D1C14 = {
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       generatedFileNames = (
+                       );
+                       isa = PBXShellScriptBuildPhase;
+                       neededFileNames = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/sh;
+                       shellScript = "mkdir -p ${DSTROOT}/System/Library/LaunchDaemons\ncp ${SRCROOT}/LaunchDaemonInfo.plist ${DSTROOT}/System/Library/LaunchDaemons/com.apple.mDNSResponder.plist";
+               };
                FF5A0AE705632EA600743C27 = {
                        buildActionMask = 8;
                        dstPath = /usr/share/man/man8;
index ad3480ce04822fb0247c352b38a785f5a4802573..7b0d48e8ead8caf65d0aefa37b0e7f7fc8810df8 100755 (executable)
@@ -24,6 +24,9 @@
     Change History (most recent first):
 
 $Log: Client.c,v $
+Revision 1.15  2004/12/16 20:17:11  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
 Revision 1.14  2004/11/30 22:37:00  cheshire
 Update copyright dates and add "Mode: C; tab-width: 4" headers
 
@@ -91,7 +94,7 @@ First checkin
 static mDNS mDNSStorage;       // mDNS core uses this to store its globals
 static mDNS_PlatformSupport PlatformStorage;  // Stores this platform's globals
 #define RR_CACHE_SIZE 500
-static CacheRecord gRRCache[RR_CACHE_SIZE];
+static CacheEntity gRRCache[RR_CACHE_SIZE];
 
 static const char *gProgramName = "mDNSResponderPosix";
 
index 27b2505580c41817146790644c1e16408de6fec7..c1724f2574120b5df85df606df6acc15ecc6f07c 100644 (file)
@@ -37,6 +37,9 @@
     Change History (most recent first):
 
 $Log: Identify.c,v $
+Revision 1.34  2004/12/16 20:17:11  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
 Revision 1.33  2004/11/30 22:37:00  cheshire
 Update copyright dates and add "Mode: C; tab-width: 4" headers
 
@@ -181,7 +184,7 @@ Add mDNSIdentify tool, used to discover what version of mDNSResponder a particul
 static mDNS mDNSStorage;       // mDNS core uses this to store its globals
 static mDNS_PlatformSupport PlatformStorage;  // Stores this platform's globals
 #define RR_CACHE_SIZE 500
-static CacheRecord gRRCache[RR_CACHE_SIZE];
+static CacheEntity gRRCache[RR_CACHE_SIZE];
 
 static volatile int StopNow;   // 0 means running, 1 means stop because we got an answer, 2 means stop because of Ctrl-C
 static volatile int NumAnswers, NumAddr, NumAAAA, NumHINFO;
@@ -233,7 +236,7 @@ static void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRec
                {
                ConvertDomainNameToCString(&answer->rdata->u.name, hostname);
                StopNow = 1;
-               mprintf("%##s %s %##s\n", answer->name.c, DNSTypeName(answer->rrtype), answer->rdata->u.name.c);
+               mprintf("%##s %s %##s\n", answer->name->c, DNSTypeName(answer->rrtype), answer->rdata->u.name.c);
                }
        }
 
@@ -247,7 +250,7 @@ static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRec
                if (!id.NotAnInteger) id = lastid;
                NumAnswers++;
                NumAddr++;
-               mprintf("%##s %s %.4a\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.ipv4);
+               mprintf("%##s %s %.4a\n", answer->name->c, DNSTypeName(answer->rrtype), &answer->rdata->u.ipv4);
                hostaddr.type = mDNSAddrType_IPv4;      // Prefer v4 target to v6 target, for now
                hostaddr.ip.v4 = answer->rdata->u.ipv4;
                }
@@ -256,7 +259,7 @@ static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRec
                if (!id.NotAnInteger) id = lastid;
                NumAnswers++;
                NumAAAA++;
-               mprintf("%##s %s %.16a\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.ipv6);
+               mprintf("%##s %s %.16a\n", answer->name->c, DNSTypeName(answer->rrtype), &answer->rdata->u.ipv6);
                if (!hostaddr.type)     // Prefer v4 target to v6 target, for now
                        {
                        hostaddr.type = mDNSAddrType_IPv6;
@@ -291,7 +294,7 @@ static void ServicesCallback(mDNS *const m, DNSQuestion *question, const Resourc
                {
                NumAnswers++;
                NumAddr++;
-               mprintf("%##s %s %##s\n", answer->name.c, DNSTypeName(answer->rrtype), answer->rdata->u.name.c);
+               mprintf("%##s %s %##s\n", answer->name->c, DNSTypeName(answer->rrtype), answer->rdata->u.name.c);
                StopNow = 1;
                }
        }
index 1f8b65b8ce3ee7b9e742f6338c27244ec55da469..b9ed8ecf5ee58771fccbeee91a3e28237d88d934 100755 (executable)
 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
 # $Log: Makefile,v $
+# Revision 1.55  2005/01/27 22:55:00  cheshire
+# Add "make os=tiger" target which uses gcc4 and "-Wdeclaration-after-statement"
+#
+# Revision 1.54  2004/12/17 19:33:03  cheshire
+# Add "-lresolv" for Solaris
+#
 # Revision 1.53  2004/12/01 20:04:31  cheshire
 # Tidy up alignment
 #
@@ -236,7 +242,7 @@ CFLAGS_OS = -DNOT_HAVE_DAEMON -DNOT_HAVE_SA_LEN -DNOT_HAVE_SOCKLEN_T -DNOT_HAVE_
         -DLOG_PERROR=0 -D_XPG4_2 -D__EXTENSIONS__ -DHAVE_BROKEN_RECVIF_NAME -DUSE_TCP_LOOPBACK
 CC = gcc
 LD = gcc -shared
-LIBFLAGS = -lsocket -lnsl
+LIBFLAGS = -lsocket -lnsl -lresolv
 JAVACFLAGS_OS += -I$(JDK)/include/solaris
 ifneq ($(DEBUG),1)
 STRIP = strip
@@ -289,7 +295,17 @@ JDK = /System/Library/Frameworks/JavaVM.framework/Home
 JAVACFLAGS_OS = -dynamiclib -I/System/Library/Frameworks/JavaVM.framework/Headers -framework JavaVM 
 else
 
-$(error ERROR: Must specify target OS on command-line, e.g. "make os=panther [target]".\
+ifeq ($(os),tiger)
+CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Wdeclaration-after-statement
+CC = @gcc-4.0
+LD = libtool -dynamic
+LIBFLAGS = -lSystem
+LDSUFFIX = dylib
+JDK = /System/Library/Frameworks/JavaVM.framework/Home
+JAVACFLAGS_OS = -dynamiclib -I/System/Library/Frameworks/JavaVM.framework/Headers -framework JavaVM 
+else
+
+$(error ERROR: Must specify target OS on command-line, e.g. "make os=tiger [target]".\
 Supported operating systems include: jaguar, panther, linux, netbsd, freebsd, openbsd, solaris) 
 endif
 endif
@@ -298,6 +314,7 @@ endif
 endif
 endif
 endif
+endif
 
 NSSLIBNAME  := libnss_mdns
 NSSVERSION  := 0.2
index c8aad7b0f17afeb564bf3280fb4d29ecde838ada..4fce88d3514363022b753bdd8feb0384ef505623 100644 (file)
@@ -37,6 +37,9 @@
     Change History (most recent first):
 
 $Log: NetMonitor.c,v $
+Revision 1.71  2004/12/16 20:17:11  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
 Revision 1.70  2004/12/04 02:13:20  cheshire
 Pass proper record type in GetLargeResourceRecord() calls
 
@@ -489,14 +492,14 @@ mDNSlocal void RecordHostInfo(HostEntry *entry, const ResourceRecord *const pktr
                        {
                        // Should really check that the rdata in the address record matches the source address of this packet
                        entry->NumQueries = 0;
-                       AssignDomainName(entry->hostname, pktrr->name);
+                       AssignDomainName(&entry->hostname, pktrr->name);
                        }
 
                if (pktrr->rrtype == kDNSType_PTR)
-                       if (SameDomainName(&entry->revname, &pktrr->name))
+                       if (SameDomainName(&entry->revname, pktrr->name))
                                {
                                entry->NumQueries = 0;
-                               AssignDomainName(entry->hostname, pktrr->rdata->u.name);
+                               AssignDomainName(&entry->hostname, &pktrr->rdata->u.name);
                                }
                }
        else if (pktrr->rrtype == kDNSType_HINFO)
@@ -507,7 +510,7 @@ mDNSlocal void RecordHostInfo(HostEntry *entry, const ResourceRecord *const pktr
                mDNSu8 *sw = hw + 1 + (mDNSu32)hw[0];
                if (sw + 1 + sw[0] <= rdend)
                        {
-                       AssignDomainName(entry->hostname, pktrr->name);
+                       AssignDomainName(&entry->hostname, pktrr->name);
                        mDNSPlatformMemCopy(hw, entry->HIHardware.c, 1 + (mDNSu32)hw[0]);
                        mDNSPlatformMemCopy(sw, entry->HISoftware.c, 1 + (mDNSu32)sw[0]);
                        }
@@ -731,7 +734,7 @@ mDNSlocal void DisplayResourceRecord(const mDNSAddr *const srcaddr, const char *
 
        RDataBody *rd = &pktrr->rdata->u;
        mDNSu8 *rdend = (mDNSu8 *)rd + pktrr->rdlength;
-       int n = mprintf("%#-16a %-5s %-5s%5lu %##s -> ", srcaddr, op, DNSTypeName(pktrr->rrtype), pktrr->rroriginalttl, pktrr->name.c);
+       int n = mprintf("%#-16a %-5s %-5s%5lu %##s -> ", srcaddr, op, DNSTypeName(pktrr->rrtype), pktrr->rroriginalttl, pktrr->name->c);
 
        switch(pktrr->rrtype)
                {
@@ -864,7 +867,7 @@ mDNSlocal void DisplayQuery(mDNS *const m, const DNSMessage *const msg, const mD
                // the same as a single query, to more accurately reflect the burden on the network
                // (A query with a six-packet KA list is *at least* six times the burden on the network as a single-packet query.)
                if (msg->h.numQuestions == 0 && i == 0)
-                       recordstat(entry, &pkt.r.resrec.name, OP_query, pkt.r.resrec.rrtype);
+                       recordstat(entry, pkt.r.resrec.name, OP_query, pkt.r.resrec.rrtype);
                }
 
        for (i=0; i<msg->h.numAuthorities; i++)
@@ -909,14 +912,14 @@ mDNSlocal void DisplayResponse(mDNS *const m, const DNSMessage *const msg, const
                        {
                        NumAnswers++;
                        DisplayResourceRecord(srcaddr, (pkt.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "(AN)" : "(AN+)", &pkt.r.resrec);
-                       if (msg->h.id.NotAnInteger != 0xFFFF) recordstat(entry, &pkt.r.resrec.name, OP_answer, pkt.r.resrec.rrtype);
+                       if (msg->h.id.NotAnInteger != 0xFFFF) recordstat(entry, pkt.r.resrec.name, OP_answer, pkt.r.resrec.rrtype);
                        if (entry) RecordHostInfo(entry, &pkt.r.resrec);
                        }
                else
                        {
                        NumGoodbyes++;
                        DisplayResourceRecord(srcaddr, "(DE)", &pkt.r.resrec);
-                       recordstat(entry, &pkt.r.resrec.name, OP_goodbye, pkt.r.resrec.rrtype);
+                       recordstat(entry, pkt.r.resrec.name, OP_goodbye, pkt.r.resrec.rrtype);
                        }
                }
 
@@ -926,7 +929,7 @@ mDNSlocal void DisplayResponse(mDNS *const m, const DNSMessage *const msg, const
                ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &pkt);
                if (!ptr) { DisplayError(srcaddr, ep, end, "AUTHORITY"); return; }
                mprintf("%#-16a (?)  **** ERROR: SHOULD NOT HAVE AUTHORITY IN mDNS RESPONSE **** %-5s %##s\n",
-                       srcaddr, DNSTypeName(pkt.r.resrec.rrtype), pkt.r.resrec.name.c);
+                       srcaddr, DNSTypeName(pkt.r.resrec.rrtype), pkt.r.resrec.name->c);
                }
 
        for (i=0; i<msg->h.numAdditionals; i++)
index fcb3990b5c26b488117d7720f9569615b2163aad..3ebc3044d1b7a00b242e278900290d0a0dbbf28c 100644 (file)
        Change History (most recent first):
 
 $Log: PosixDaemon.c,v $
+Revision 1.25  2005/01/27 20:01:50  cheshire
+udsSupportRemoveFDFromEventLoop() needs to close the file descriptor as well
+
+Revision 1.24  2005/01/19 19:20:49  ksekar
+<rdar://problem/3960191> Need a way to turn off domain discovery
+
+Revision 1.23  2004/12/16 20:17:11  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
 Revision 1.22  2004/12/10 13:12:08  cheshire
 Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
 
@@ -125,7 +134,7 @@ static domainname DynDNSZone;                // Default wide-area zone for servi
 static domainname DynDNSHostname;
 
 #define RR_CACHE_SIZE 500
-static CacheRecord gRRCache[RR_CACHE_SIZE];
+static CacheEntity gRRCache[RR_CACHE_SIZE];
 
 extern const char mDNSResponderVersionString[];
 
@@ -162,7 +171,7 @@ static void Reconfigure(mDNS *m)
        mDNS_DeleteDNSServers(m);
        if (ParseDNSServers(m, uDNS_SERVERS_FILE) < 0)
                LogMsg("Unable to parse DNS server list. Unicast DNS-SD unavailable");
-       ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &DynDNSHostname, &DynDNSZone);
+       ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &DynDNSHostname, &DynDNSZone, NULL);
        FindDefaultRouteIP(&DynDNSIP);
        if (DynDNSHostname.c[0]) mDNS_AddDynDNSHostName(m, &DynDNSHostname, NULL, NULL);
        if (DynDNSIP.type)       mDNS_SetPrimaryInterfaceInfo(m, &DynDNSIP, NULL);
@@ -297,9 +306,10 @@ mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *cont
        return mDNSPosixAddFDToEventLoop(fd, callback, context);
        }
 
-mStatus udsSupportRemoveFDFromEventLoop(int fd)
+mStatus udsSupportRemoveFDFromEventLoop(int fd)                // Note: This also CLOSES the file descriptor
        {
        return mDNSPosixRemoveFDFromEventLoop(fd);
+       close(fd);
        }
 
 mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
index bca7356dd133b0fa649c737e9ea48b496e65ce7c..f113d6525e75a1df6d9db0ceaf343f7611c61eb9 100644 (file)
@@ -24,6 +24,9 @@
     Change History (most recent first):
 
 $Log: ProxyResponder.c,v $
+Revision 1.35  2004/12/16 20:17:11  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
 Revision 1.34  2004/12/01 04:27:28  cheshire
 <rdar://problem/3872803> Darwin patches for Solaris and Suse
 Don't use uint32_t, etc. -- they require stdint.h, which doesn't exist on FreeBSD 4.x, Solaris, etc.
@@ -145,10 +148,10 @@ mDNSlocal void HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus res
        {
        ProxyHost *f = (ProxyHost*)rr->RecordContext;
        if (result == mStatus_NoError)
-               debugf("Host name successfully registered: %##s", rr->resrec.name.c);
+               debugf("Host name successfully registered: %##s", rr->resrec.name->c);
        else
                {
-               debugf("Host name conflict for %##s", rr->resrec.name.c);
+               debugf("Host name conflict for %##s", rr->resrec.name->c);
                mDNS_Deregister(m, &f->RR_A);
                mDNS_Deregister(m, &f->RR_PTR);
                exit(-1);
@@ -162,20 +165,20 @@ mDNSlocal mStatus mDNS_RegisterProxyHost(mDNS *m, ProxyHost *p)
        mDNS_SetupResourceRecord(&p->RR_A,   mDNSNULL, mDNSInterface_Any, kDNSType_A,   60, kDNSRecordTypeUnique,      HostNameCallback, p);
        mDNS_SetupResourceRecord(&p->RR_PTR, mDNSNULL, mDNSInterface_Any, kDNSType_PTR, 60, kDNSRecordTypeKnownUnique, HostNameCallback, p);
 
-       p->RR_A.resrec.name.c[0] = 0;
-       AppendDomainLabel(&p->RR_A.resrec.name, &p->hostlabel);
-       AppendLiteralLabelString(&p->RR_A.resrec.name, "local");
+       p->RR_A.resrec.name->c[0] = 0;
+       AppendDomainLabel(p->RR_A.resrec.name, &p->hostlabel);
+       AppendLiteralLabelString(p->RR_A.resrec.name, "local");
 
        mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", p->ip.b[3], p->ip.b[2], p->ip.b[1], p->ip.b[0]);
-       MakeDomainNameFromDNSNameString(&p->RR_PTR.resrec.name, buffer);
+       MakeDomainNameFromDNSNameString(p->RR_PTR.resrec.name, buffer);
 
        p->RR_A.  resrec.rdata->u.ipv4 = p->ip;
-       p->RR_PTR.resrec.rdata->u.name = p->RR_A.resrec.name;
+       AssignDomainName(&p->RR_PTR.resrec.rdata->u.name, p->RR_A.resrec.name);
 
        mDNS_Register(m, &p->RR_A);
        mDNS_Register(m, &p->RR_PTR);
 
-       debugf("Made Proxy Host Records for %##s", p->RR_A.resrec.name.c);
+       debugf("Made Proxy Host Records for %##s", p->RR_A.resrec.name->c);
        
        return(mStatus_NoError);
        }
@@ -191,25 +194,25 @@ mDNSlocal void ServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatu
        {
        switch (result)
                {
-               case mStatus_NoError:      debugf("Callback: %##s Name Registered",    sr->RR_SRV.resrec.name.c); break;
-               case mStatus_NameConflict: debugf("Callback: %##s Name Conflict",      sr->RR_SRV.resrec.name.c); break;
-               case mStatus_MemFree:      debugf("Callback: %##s Memory Free",        sr->RR_SRV.resrec.name.c); break;
-               default:                   debugf("Callback: %##s Unknown Result %ld", sr->RR_SRV.resrec.name.c, result); break;
+               case mStatus_NoError:      debugf("Callback: %##s Name Registered",    sr->RR_SRV.resrec.name->c); break;
+               case mStatus_NameConflict: debugf("Callback: %##s Name Conflict",      sr->RR_SRV.resrec.name->c); break;
+               case mStatus_MemFree:      debugf("Callback: %##s Memory Free",        sr->RR_SRV.resrec.name->c); break;
+               default:                   debugf("Callback: %##s Unknown Result %ld", sr->RR_SRV.resrec.name->c, result); break;
                }
 
        if (result == mStatus_NoError)
                {
                char buffer[MAX_ESCAPED_DOMAIN_NAME];
-               ConvertDomainNameToCString(&sr->RR_SRV.resrec.name, buffer);
+               ConvertDomainNameToCString(sr->RR_SRV.resrec.name, buffer);
                printf("Service %s now registered and active\n", buffer);
                }
 
        if (result == mStatus_NameConflict)
                {
                char buffer1[MAX_ESCAPED_DOMAIN_NAME], buffer2[MAX_ESCAPED_DOMAIN_NAME];
-               ConvertDomainNameToCString(&sr->RR_SRV.resrec.name, buffer1);
+               ConvertDomainNameToCString(sr->RR_SRV.resrec.name, buffer1);
                mDNS_RenameAndReregisterService(m, sr, mDNSNULL);
-               ConvertDomainNameToCString(&sr->RR_SRV.resrec.name, buffer2);
+               ConvertDomainNameToCString(sr->RR_SRV.resrec.name, buffer2);
                printf("Name Conflict! %s renamed as %s\n", buffer1, buffer2);
                }
        }
@@ -247,7 +250,7 @@ mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset,
                mDNSInterface_Any,                      // Interface ID
                ServiceCallback, mDNSNULL);     // Callback and context
 
-       ConvertDomainNameToCString(&recordset->RR_SRV.resrec.name, buffer);
+       ConvertDomainNameToCString(recordset->RR_SRV.resrec.name, buffer);
        printf("Made Service Records for %s\n", buffer);
        }
 
@@ -264,16 +267,16 @@ mDNSlocal void NoSuchServiceCallback(mDNS *const m, AuthRecord *const rr, mStatu
        domainname *proxyhostname = (domainname *)rr->RecordContext;
        switch (result)
                {
-               case mStatus_NoError:      debugf("Callback: %##s Name Registered",    rr->resrec.name.c); break;
-               case mStatus_NameConflict: debugf("Callback: %##s Name Conflict",      rr->resrec.name.c); break;
-               case mStatus_MemFree:      debugf("Callback: %##s Memory Free",        rr->resrec.name.c); break;
-               default:                   debugf("Callback: %##s Unknown Result %ld", rr->resrec.name.c, result); break;
+               case mStatus_NoError:      debugf("Callback: %##s Name Registered",    rr->resrec.name->c); break;
+               case mStatus_NameConflict: debugf("Callback: %##s Name Conflict",      rr->resrec.name->c); break;
+               case mStatus_MemFree:      debugf("Callback: %##s Memory Free",        rr->resrec.name->c); break;
+               default:                   debugf("Callback: %##s Unknown Result %ld", rr->resrec.name->c, result); break;
                }
 
        if (result == mStatus_NoError)
                {
                char buffer[MAX_ESCAPED_DOMAIN_NAME];
-               ConvertDomainNameToCString(&rr->resrec.name, buffer);
+               ConvertDomainNameToCString(rr->resrec.name, buffer);
                printf("Non-existence assertion %s now registered and active\n", buffer);
                }
 
@@ -282,11 +285,11 @@ mDNSlocal void NoSuchServiceCallback(mDNS *const m, AuthRecord *const rr, mStatu
                domainlabel n;
                domainname t, d;
                char buffer1[MAX_ESCAPED_DOMAIN_NAME], buffer2[MAX_ESCAPED_DOMAIN_NAME];
-               ConvertDomainNameToCString(&rr->resrec.name, buffer1);
-               DeconstructServiceName(&rr->resrec.name, &n, &t, &d);
+               ConvertDomainNameToCString(rr->resrec.name, buffer1);
+               DeconstructServiceName(rr->resrec.name, &n, &t, &d);
                IncrementLabelSuffix(&n, mDNStrue);
                mDNS_RegisterNoSuchService(m, rr, &n, &t, &d, proxyhostname, mDNSInterface_Any, NoSuchServiceCallback, mDNSNULL);
-               ConvertDomainNameToCString(&rr->resrec.name, buffer2);
+               ConvertDomainNameToCString(rr->resrec.name, buffer2);
                printf("Name Conflict! %s renamed as %s\n", buffer1, buffer2);
                }
        }
@@ -301,7 +304,7 @@ mDNSlocal void RegisterNoSuchService(mDNS *m, AuthRecord *const rr, domainname *
        MakeDomainNameFromDNSNameString(&t, type);
        MakeDomainNameFromDNSNameString(&d, domain);
        mDNS_RegisterNoSuchService(m, rr, &n, &t, &d, proxyhostname, mDNSInterface_Any, NoSuchServiceCallback, proxyhostname);
-       ConvertDomainNameToCString(&rr->resrec.name, buffer);
+       ConvertDomainNameToCString(rr->resrec.name, buffer);
        printf("Made Non-existence Record for %s\n", buffer);
        }
 
@@ -357,7 +360,7 @@ mDNSexport int main(int argc, char **argv)
 
                if (argc >=6)
                        RegisterService(&mDNSStorage, &proxyservice, argv[3], argv[4], "local.",
-                                                       &proxyhost.RR_A.resrec.name, atoi(argv[5]), argc-6, &argv[6]);
+                                                       proxyhost.RR_A.resrec.name, atoi(argv[5]), argc-6, &argv[6]);
                }
 
        do 
index 93b0c816b8f5eac496cffbd0318fd8d55955374d..b54d3a8edb7f844373a1abec9941d3c35bacd125 100755 (executable)
@@ -24,6 +24,9 @@
     Change History (most recent first):
 
 $Log: Responder.c,v $
+Revision 1.28  2005/01/11 01:55:26  ksekar
+Fix compile errors in Posix debug build
+
 Revision 1.27  2004/12/01 04:28:43  cheshire
 <rdar://problem/3872803> Darwin patches for Solaris and Suse
 Use version of daemon() provided in mDNSUNP.c instead of local copy
@@ -461,13 +464,13 @@ static void RegistrationCallback(mDNS *const m, ServiceRecordSet *const thisRegi
     switch (status) {
 
         case mStatus_NoError:      
-            debugf("Callback: %##s Name Registered",   thisRegistration->RR_SRV.resrec.name.c); 
+            debugf("Callback: %##s Name Registered",   thisRegistration->RR_SRV.resrec.name->c); 
             // Do nothing; our name was successfully registered.  We may 
             // get more call backs in the future.
             break;
 
         case mStatus_NameConflict: 
-            debugf("Callback: %##s Name Conflict",     thisRegistration->RR_SRV.resrec.name.c); 
+            debugf("Callback: %##s Name Conflict",     thisRegistration->RR_SRV.resrec.name->c); 
 
             // In the event of a conflict, this sample RegistrationCallback 
             // just calls mDNS_RenameAndReregisterService to automatically 
@@ -485,7 +488,7 @@ static void RegistrationCallback(mDNS *const m, ServiceRecordSet *const thisRegi
             break;
 
         case mStatus_MemFree:      
-            debugf("Callback: %##s Memory Free",       thisRegistration->RR_SRV.resrec.name.c); 
+            debugf("Callback: %##s Memory Free",       thisRegistration->RR_SRV.resrec.name->c); 
             
             // When debugging is enabled, make sure that thisRegistration 
             // is not on our gServiceList.
@@ -505,7 +508,7 @@ static void RegistrationCallback(mDNS *const m, ServiceRecordSet *const thisRegi
             break;
 
         default:                   
-            debugf("Callback: %##s Unknown Status %ld", thisRegistration->RR_SRV.resrec.name.c, status); 
+            debugf("Callback: %##s Unknown Status %ld", thisRegistration->RR_SRV.resrec.name->c, status); 
             break;
     }
 }
index 41bc5e74e32a048147be2dc8134b2628796b70c8..c9d0c73ea709abe9de0c241ccdd1391c32907d2f 100644 (file)
     Change History (most recent first):
 
 $Log: dnsextd.c,v $
+Revision 1.30  2005/01/27 22:57:56  cheshire
+Fix compile errors on gcc4
+
+Revision 1.29  2004/12/22 00:13:50  ksekar
+<rdar://problem/3873993> Change version, port, and polling interval for LLQ
+
+Revision 1.28  2004/12/17 00:30:00  ksekar
+<rdar://problem/3924045> dnsextd memory leak
+
+Revision 1.27  2004/12/17 00:27:32  ksekar
+Ignore SIGPIPE
+
+Revision 1.26  2004/12/17 00:21:33  ksekar
+Fixes for new CacheRecord structure with indirect name pointer
+
+Revision 1.25  2004/12/16 20:13:02  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
+Revision 1.24  2004/12/14 17:09:06  ksekar
+fixed incorrect usage instructions
+
 Revision 1.23  2004/12/06 20:24:31  ksekar
 <rdar://problem/3907303> dnsextd leaks sockets
 
@@ -136,7 +157,7 @@ Revision 1.1  2004/08/11 00:43:26  ksekar
 
 #define LOOPBACK "127.0.0.1"
 #define NS_PORT 53
-#define DAEMON_PORT 5355                // default, may be overridden via command line argument
+#define DAEMON_PORT 5352                // default, may be overridden via command line argument
 #define LISTENQ 128                     // tcp connection backlog
 #define RECV_BUFLEN 9000                
 #define LEASETABLE_INIT_NBUCKETS 256    // initial hashtable size (doubles as table fills)
@@ -181,6 +202,7 @@ typedef struct RRTableElem
     struct sockaddr_in cli;   // client's source address
     long expire;              // expiration time, in seconds since epoch
     domainname zone;          // from zone field of update message
+    domainname name;          // name of the record
     CacheRecord rr;           // last field in struct allows for allocation of oversized RRs
        } RRTableElem;
 
@@ -283,7 +305,7 @@ mDNSlocal void PrintLog(const char *buffer)
 // Verbose Logging (conditional on -v option)
 mDNSlocal void VLog(const char *format, ...)
        {
-       unsigned char buffer[512];
+       char buffer[512];
        va_list ptr;
 
        if (!verbose) return;
@@ -296,7 +318,7 @@ mDNSlocal void VLog(const char *format, ...)
 // Unconditional Logging
 mDNSlocal void Log(const char *format, ...)
        {
-       unsigned char buffer[512];
+       char buffer[512];
        va_list ptr;
 
        va_start(ptr,format);
@@ -426,7 +448,7 @@ mDNSlocal PktMsg *ReadTCPMsg(int sd, PktMsg *storage)
        int nread, allocsize;
        mDNSu16 msglen = 0;     
        PktMsg *pkt = NULL;
-       int srclen;
+       unsigned int srclen;
        
        nread = my_recv(sd, &msglen, sizeof(msglen));
        if (nread < 0) { LogErr("TCPRequestForkFn", "recv"); goto error; }
@@ -525,8 +547,10 @@ mDNSlocal mDNSBool SuccessfulUpdateTransaction(PktMsg *request, PktMsg *reply)
        return mDNSfalse;
        }
 
-// Allocate an appropriately sized CacheRecord and copy data from original
-mDNSlocal CacheRecord *CopyCacheRecord(CacheRecord *orig)
+// Allocate an appropriately sized CacheRecord and copy data from original.
+// Name pointer in CacheRecord object is set to point to the name specified
+//
+mDNSlocal CacheRecord *CopyCacheRecord(const CacheRecord *orig, domainname *name)
        {
        CacheRecord *cr;
        size_t size = sizeof(*cr);
@@ -535,6 +559,8 @@ mDNSlocal CacheRecord *CopyCacheRecord(CacheRecord *orig)
        if (!cr) { LogErr("CopyCacheRecord", "malloc"); return NULL; }
        memcpy(cr, orig, size);
        cr->resrec.rdata = (RData*)&cr->rdatastorage;
+       cr->resrec.name = name;
+       
        return cr;
        }
 
@@ -605,7 +631,7 @@ mDNSlocal void PrintLeaseTable(DaemonInfo *d)
 // delete all RRS of a given name/type
 mDNSlocal mDNSu8 *putRRSetDeletion(DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit,  ResourceRecord *rr)
        {
-       ptr = putDomainNameAsLabels(msg, ptr, limit, &rr->name);
+       ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
        if (!ptr || ptr + 10 >= limit) return NULL;  // out of space
        ptr[0] = (mDNSu8)(rr->rrtype  >> 8);
        ptr[1] = (mDNSu8)(rr->rrtype  &  0xFF);
@@ -630,8 +656,8 @@ mDNSlocal mDNSu8 *PutUpdateSRV(DaemonInfo *d, PktMsg *pkt, mDNSu8 *ptr, char *re
        if (!gethostname(hostname, 1024) < 0 || MakeDomainNameFromDNSNameString(&rr.resrec.rdata->u.srv.target, hostname))
                rr.resrec.rdata->u.srv.target.c[0] = '\0';
        
-       MakeDomainNameFromDNSNameString(&rr.resrec.name, regtype);
-       strcpy(rr.resrec.name.c + strlen(rr.resrec.name.c), d->zone.c);
+       MakeDomainNameFromDNSNameString(rr.resrec.name, regtype);
+       AppendDomainName(rr.resrec.name, &d->zone);
        VLog("%s  %s", registration ? "Registering SRV record" : "Deleting existing RRSet",
                 GetRRDisplayString_rdb(&rr.resrec, &rr.resrec.rdata->u, buf));
        if (registration) ptr = PutResourceRecord(&pkt->msg, ptr, &pkt->msg.h.mDNS_numUpdates, &rr.resrec);
@@ -715,7 +741,7 @@ mDNSlocal int SetUpdateSRV(DaemonInfo *d)
 mDNSlocal int ReadAuthKey(int argc, char *argv[], DaemonInfo *d)
        {
        uDNS_AuthInfo *auth = NULL;
-       char keybuf[512];
+       unsigned char keybuf[512];
        mDNSs32 keylen;
        
        auth = malloc(sizeof(*auth));
@@ -748,7 +774,7 @@ mDNSlocal int SetPort(DaemonInfo *d, char *PortAsString)
        
 mDNSlocal void PrintUsage(void)
        {
-       fprintf(stderr, "Usage: dnsextd -z <zone> [-vf] [ -s server ] [-k zone keyname secret] ...\n"
+       fprintf(stderr, "Usage: dnsextd -z <zone> [-vf] [ -s server ] [-k keyname secret] ...\n"
                        "Use \"dnsextd -h\" for help\n");
        }
 
@@ -822,7 +848,7 @@ mDNSlocal int ProcessArgs(int argc, char *argv[], DaemonInfo *d)
                }
                
        if (!d->zone.c[0]) goto arg_error;  // zone is the only required argument
-       if (d->AuthInfo) AssignDomainName(d->AuthInfo->zone, d->zone); // if we have a shared secret, use it for the entire zone
+       if (d->AuthInfo) AssignDomainName(&d->AuthInfo->zone, &d->zone); // if we have a shared secret, use it for the entire zone
        return 0;
        
        arg_error:
@@ -1040,9 +1066,11 @@ mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease)
                        if (!new) { LogErr("UpdateLeaseTable", "malloc"); goto cleanup; }
                        memcpy(&new->rr, &lcr.r, sizeof(CacheRecord) + lcr.r.resrec.rdlength - InlineCacheRDSize);
                        new->rr.resrec.rdata = (RData *)&new->rr.rdatastorage;
+                       AssignDomainName(&new->name, lcr.r.resrec.name);
+                       new->rr.resrec.name = &new->name;
                        new->expire = time.tv_sec + (unsigned)lease;
                        new->cli.sin_addr = pkt->src.sin_addr;
-                       strcpy(new->zone.c, zone.qname.c);
+                       AssignDomainName(&new->zone, &zone.qname);
                        new->next = d->table[bucket];
                        d->table[bucket] = new;
                        d->nelems++;
@@ -1122,9 +1150,7 @@ mDNSlocal PktMsg *HandleRequest(PktMsg *pkt, DaemonInfo *d)
 mDNSlocal void FormatLLQOpt(AuthRecord *opt, int opcode, mDNSu8 *id, mDNSs32 lease)
        {
        bzero(opt, sizeof(*opt));
-       opt->resrec.rdata = &opt->rdatastorage;
-       opt->resrec.RecordType = kDNSRecordTypeKnownUnique; // to suppress warnings from other layers
-       opt->resrec.rrtype = kDNSType_OPT;
+       mDNS_SetupResourceRecord(opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
        opt->resrec.rdlength = LLQ_OPT_SIZE;
        opt->resrec.rdestimate = LLQ_OPT_SIZE;
        opt->resrec.rdata->u.opt.opt = kDNSOpt_LLQ;
@@ -1244,14 +1270,14 @@ mDNSlocal CacheRecord *AnswerQuestion(DaemonInfo *d, LLQEntry *e, int sd)
                //if (!rr) { LogErr("AnswerQuestion", "malloc"); goto end; }
                ansptr = GetLargeResourceRecord(NULL, &reply->msg, ansptr, end, 0, kDNSRecordTypePacketAns, &lcr);
                if (!ansptr) { Log("AnswerQuestions: GetLargeResourceRecord returned NULL"); goto end; }
-               if (lcr.r.resrec.rrtype != e->qtype || lcr.r.resrec.rrclass != kDNSClass_IN || !SameDomainName(&lcr.r.resrec.name, &e->qname))
+               if (lcr.r.resrec.rrtype != e->qtype || lcr.r.resrec.rrclass != kDNSClass_IN || !SameDomainName(lcr.r.resrec.name, &e->qname))
                        {
                        Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d.  Discarding",
-                                 lcr.r.resrec.name.c, lcr.r.resrec.rrtype, e->qname.c, e->qtype);
+                                 lcr.r.resrec.name->c, lcr.r.resrec.rrtype, e->qname.c, e->qtype);
                        }
                else
                        {
-                       CacheRecord *cr = CopyCacheRecord(&lcr.r);
+                       CacheRecord *cr = CopyCacheRecord(&lcr.r, &e->qname);
                        if (!cr) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end; }                                               
                        cr->next = AnswerList;
                        AnswerList = cr;
@@ -1296,7 +1322,7 @@ mDNSlocal void UpdateAnswerList(DaemonInfo *d, LLQEntry *e, CacheRecord *answers
                if (!ka)
                        {
                        // answer is not in KA list
-                       CacheRecord *cr = CopyCacheRecord(na);
+                       CacheRecord *cr = CopyCacheRecord(na, &e->qname);
                        if (!cr) { Log("Error: UpdateAnswerList - CopyCacheRecord returned NULL"); return; }
                        cr->resrec.rroriginalttl = 1; // 1 means add
                        cr->next = e->KnownAnswers;
@@ -1400,8 +1426,9 @@ mDNSlocal void GenLLQEvents(DaemonInfo *d)
                                }
                        else
                                {
-                               CacheRecord *answers = AnswerQuestion(d, e, sd);
+                               CacheRecord *tmp, *answers = AnswerQuestion(d, e, sd);
                                UpdateAnswerList(d, e, answers);
+                               while (answers) { tmp = answers; answers = answers->next; free(tmp); }                          
                                e = e->next;
                                }
                        }               
@@ -1421,7 +1448,7 @@ mDNSlocal void *LLQEventMonitor(void *DInfoPtr)
        mDNSs32 serial = 0;
        mDNSBool SerialInitialized = mDNSfalse;
        int sd;
-     LargeCacheRecord lcr;
+    LargeCacheRecord lcr;
        ResourceRecord *rr = &lcr.r.resrec;
        int i, sleeptime = 0;
        domainname zone;
@@ -1430,7 +1457,7 @@ mDNSlocal void *LLQEventMonitor(void *DInfoPtr)
        // create question
        id.NotAnInteger = 0;
        InitializeDNSMessage(&q.msg.h, id, flags);
-       AssignDomainName(zone, d->zone);
+       AssignDomainName(&zone, &d->zone);
        end = putQuestion(&q.msg, end, end + AbsoluteMaxDNSMessageData, &zone, kDNSType_SOA, kDNSClass_IN);
        if (!end) { Log("Error: LLQEventMonitor - putQuestion returned NULL"); return NULL; }
        q.len = (int)(end - (mDNSu8 *)&q.msg);
@@ -1456,7 +1483,7 @@ mDNSlocal void *LLQEventMonitor(void *DInfoPtr)
                        {
                        ptr = GetLargeResourceRecord(NULL, &reply.msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
                        if (!ptr) { Log("Error: LLQEventMonitor - GetLargeResourceRecord  returned NULL"); continue; }
-                       if (rr->rrtype != kDNSType_SOA || rr->rrclass != kDNSClass_IN || !SameDomainName(&rr->name, &zone)) continue;
+                       if (rr->rrtype != kDNSType_SOA || rr->rrclass != kDNSClass_IN || !SameDomainName(rr->name, &zone)) continue;
                        if (!SerialInitialized)
                                {
                                // first time through loop
@@ -1494,7 +1521,7 @@ mDNSlocal LLQEntry *NewLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qn
        
        // initialize structure
        e->cli = cli;
-       AssignDomainName(e->qname, *qname);
+       AssignDomainName(&e->qname, qname);
        e->qtype = qtype;
        memset(e->id, 0, 8);
        e->state = RequestReceived;
@@ -1801,7 +1828,7 @@ mDNSlocal int RecvUDPRequest(int sd, DaemonInfo *d)
        {
        UDPRequestArgs *req;
        pthread_t tid;
-       int clisize = sizeof(req->cliaddr);
+       unsigned int clisize = sizeof(req->cliaddr);
        
        req = malloc(sizeof(UDPRequestArgs));
        if (!req) { LogErr("RecvUDPRequest", "malloc"); return -1; }
@@ -1868,7 +1895,7 @@ mDNSlocal int RecvTCPRequest(int sd, DaemonInfo *d)
        {
        TCPRequestArgs *req;
        pthread_t tid;
-       int clilen = sizeof(req->cliaddr);
+       unsigned int clilen = sizeof(req->cliaddr);
        
        req = malloc(sizeof(TCPRequestArgs));
        if (!req) { LogErr("RecvTCPRequest", "malloc"); return -1; }
@@ -1957,6 +1984,7 @@ int main(int argc, char *argv[])
        if (signal(SIGTERM,     HndlSignal) == SIG_ERR) perror("Can't catch SIGTERM");
        if (signal(INFO_SIGNAL, HndlSignal) == SIG_ERR) perror("Can't catch SIGINFO");
        if (signal(SIGINT,      HndlSignal) == SIG_ERR) perror("Can't catch SIGINT");
+       if (signal(SIGPIPE,     SIG_IGN  )  == SIG_ERR) perror("Can't ignore SIGPIPE");
        
        if (ProcessArgs(argc, argv, &d) < 0) exit(1);
 
index 5aca8fabe47bed9b28ea06b51b4fc6bccf32b2da..f15a88ac9a0d161b9fef123f83a4d49e3bee30d5 100755 (executable)
        Change History (most recent first):
 
 $Log: mDNSPosix.c,v $
+Revision 1.69  2004/12/18 02:03:28  cheshire
+Need to #include "dns_sd.h"
+
+Revision 1.68  2004/12/18 00:51:52  cheshire
+Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
+
+Revision 1.67  2004/12/17 23:37:48  cheshire
+<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
+(and other repetitive configuration changes)
+
 Revision 1.66  2004/12/01 04:27:28  cheshire
 <rdar://problem/3872803> Darwin patches for Solaris and Suse
 Don't use uint32_t, etc. -- they require stdint.h, which doesn't exist on FreeBSD 4.x, Solaris, etc.
@@ -257,6 +267,7 @@ First checkin
 
 #include "mDNSEmbeddedAPI.h"           // Defines the interface provided to the client layer above
 #include "mDNSPosix.h"                          // Defines the specific types needed to run mDNS on this platform
+#include "dns_sd.h"
 
 #include <assert.h>
 #include <stdio.h>
@@ -621,7 +632,7 @@ extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(const mDNS *con
 
        assert(m != NULL);
 
-       if (index == (mDNSu32)~0) return(mDNSInterface_LocalOnly);
+       if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
 
        intf = (PosixNetworkInterface*)(m->HostInterfaces);
        while ( (intf != NULL) && (mDNSu32) intf->index != index) 
@@ -636,7 +647,7 @@ mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(const mDNS *const m
 
        assert(m != NULL);
 
-       if (id == mDNSInterface_LocalOnly) return((mDNSu32)~0);
+       if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
 
        intf = (PosixNetworkInterface*)(m->HostInterfaces);
        while ( (intf != NULL) && (mDNSInterfaceID) intf != id)
@@ -958,7 +969,7 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct
 
        // The interface is all ready to go, let's register it with the mDNS core.
        if (err == 0)
-               err = mDNS_RegisterInterface(m, &intf->coreIntf);
+               err = mDNS_RegisterInterface(m, &intf->coreIntf, 0);
 
        // Clean up.
        if (err == 0)
index 45d92355e57bb3ad8aee3e478ab34961677e4c19..786fef7e50a42940d444d7d4f95af61569defac5 100755 (executable)
@@ -24,6 +24,9 @@
     Change History (most recent first):
 
 $Log: mDNSUNP.h,v $
+Revision 1.17  2004/12/17 19:32:43  cheshire
+Add missing semicolon
+
 Revision 1.16  2004/12/01 04:25:05  cheshire
 <rdar://problem/3872803> Darwin patches for Solaris and Suse
 Provide daemon() for platforms that don't have it
@@ -156,7 +159,7 @@ extern struct ifi_info  *get_ifi_info(int family, int doaliases);
 extern void             free_ifi_info(struct ifi_info *);
 
 #ifdef NOT_HAVE_DAEMON
-extern int daemon(int nochdir, int noclose)
+extern int daemon(int nochdir, int noclose);
 #endif
 
 #ifdef  __cplusplus
index 4525eb4ba44e7e35fcda4b4b6764d363b463165b..9bee556382e8d529f3ab89fa9c879e058e0b580e 100644 (file)
@@ -24,6 +24,9 @@
     Change History (most recent first):
 
 $Log: PlatformCommon.c,v $
+Revision 1.4  2005/01/19 19:19:21  ksekar
+<rdar://problem/3960191> Need a way to turn off domain discovery
+
 Revision 1.3  2004/12/13 17:46:52  cheshire
 Use sizeof(buf) instead of fixed constant 1024
 
@@ -67,10 +70,10 @@ mDNSexport void FindDefaultRouteIP(mDNSAddr *a)
        a->ip.v4.NotAnInteger = addr.sin_addr.s_addr;
        }
 
-// dst must be at least MAX_ESCAPED_DOMAIN_NAME bytes, and option must be less than 20 bytes in length
+// dst must be at least MAX_ESCAPED_DOMAIN_NAME bytes, and option must be less than 32 bytes in length
 mDNSlocal mDNSBool GetConfigOption(char *dst, const char *option, FILE *f)
        {
-       char buf[20+1+MAX_ESCAPED_DOMAIN_NAME]; // Option name, one space, option value
+       char buf[32+1+MAX_ESCAPED_DOMAIN_NAME]; // Option name, one space, option value
        unsigned int len = strlen(option);
        if (len + 1 + MAX_ESCAPED_DOMAIN_NAME > sizeof(buf)-1) { LogMsg("GetConfigOption: option %s too long", option); return mDNSfalse; }
        fseek(f, 0, SEEK_SET);  // set position to beginning of stream
@@ -89,23 +92,24 @@ mDNSlocal mDNSBool GetConfigOption(char *dst, const char *option, FILE *f)
        return mDNSfalse;
        }
 
-mDNSexport void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain)
+mDNSexport void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain, mDNSBool *DomainDiscoveryDisabled)
        {
-       char zone  [MAX_ESCAPED_DOMAIN_NAME];
-       char fqdn  [MAX_ESCAPED_DOMAIN_NAME];
+       char buf   [MAX_ESCAPED_DOMAIN_NAME];
        char secret[MAX_ESCAPED_DOMAIN_NAME] = "";
        int slen;
        mStatus err;
        FILE *f = fopen(filename, "r");
 
-    hostname->c[0] = 0;
-    domain->c[0] = 0;
+    if (hostname)                 hostname->c[0] = 0;
+    if (domain)                   domain->c[0] = 0;
+       if (DomainDiscoveryDisabled) *DomainDiscoveryDisabled = mDNSfalse;
 
        if (f)
                {
-               if (GetConfigOption(fqdn, "hostname", f) && !MakeDomainNameFromDNSNameString(hostname, fqdn)) goto badf;
-               if (GetConfigOption(zone, "zone", f) && !MakeDomainNameFromDNSNameString(domain, zone)) goto badf;
-               GetConfigOption(secret, "secret-64", f);  // failure means no authentication       
+               if (DomainDiscoveryDisabled && GetConfigOption(buf, "DomainDiscoveryDisabled", f) && !strcasecmp(buf, "true")) *DomainDiscoveryDisabled = mDNStrue;
+               if (hostname && GetConfigOption(buf, "hostname", f) && !MakeDomainNameFromDNSNameString(hostname, buf)) goto badf;
+               if (domain && GetConfigOption(buf, "zone", f) && !MakeDomainNameFromDNSNameString(domain, buf)) goto badf;
+               GetConfigOption(secret, "secret-64", f);  // failure means no authentication                    
                fclose(f);
                f = NULL;
                }
@@ -115,7 +119,7 @@ mDNSexport void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const fi
                return;
                }
 
-       if (secret[0])
+       if (domain && domain->c[0] && secret[0])
                {
                // for now we assume keyname = service reg domain and we use same key for service and hostname registration
                slen = strlen(secret);
index 9e4638bcba82600bb87878fe9066fd1c5fb089e4..46a672ad66b4b591347dd11f526fbabfc8c9a1b2 100644 (file)
@@ -24,6 +24,9 @@
     Change History (most recent first):
 
 $Log: PlatformCommon.h,v $
+Revision 1.3  2005/01/19 19:19:21  ksekar
+<rdar://problem/3960191> Need a way to turn off domain discovery
+
 Revision 1.2  2004/12/01 03:30:29  cheshire
 <rdar://problem/3889346> Add Unicast DNS support to mDNSPosix
 
@@ -33,4 +36,4 @@ Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c
  */
 
 extern void FindDefaultRouteIP(mDNSAddr *a);
-extern void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain);
+extern void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain, mDNSBool *DomainDiscoveryDisabled);
index 7d14fca4c2e87e39c33877739f7e56891becd02a..4f22f679ce135034b386040780c8da21be7f42e1 100755 (executable)
@@ -100,7 +100,7 @@ enum
      * by renaming the service.  NoAutoRename overrides this behavior - with this
      * flag set, name conflicts will result in a callback.  The NoAutorename flag
      * is only valid if a name is explicitly specified when registering a service
-     * (ie the default name is not used.)
+     * (i.e. the default name is not used.)
      */
 
     kDNSServiceFlagsShared              = 0x10,
@@ -225,7 +225,7 @@ enum
     kDNSServiceErr_NoAuth              = -65555,
     kDNSServiceErr_NoSuchKey           = -65556,
     kDNSServiceErr_NATTraversal        = -65557,
-    kDNSServiceErr_DblNAT              = -65558,
+    kDNSServiceErr_DoubleNAT           = -65558,
     kDNSServiceErr_BadTime             = -65559
     /* mDNS Error codes are in the range
      * FFFE FF00 (-65792) to FFFE FFFF (-65537) */
@@ -298,23 +298,16 @@ enum
  * 
  * If the client passes kDNSServiceInterfaceIndexLocalOnly when registering
  * a service, then that service will be found *only* by other local clients
- * on the same machine that pass kDNSServiceInterfaceIndexLocalOnly when browsing.
+ * on the same machine that are browsing using kDNSServiceInterfaceIndexLocalOnly
+ * or kDNSServiceInterfaceIndexAny.
  * If a client has a 'private' service, accessible only to other processes
  * running on the same machine, this allows the client to advertise that service
  * in a way such that it does not inadvertently appear in service lists on
  * all the other machines on the network.
- * Note that to discover these special non-public services, the browsing
- * client also has to explicitly use kDNSServiceInterfaceIndexLocalOnly in its
- * DNSServiceBrowse() call. These special non-public services are not reported to
- * other clients on the same machine using interface index 0 or other index values.
  * 
  * If the client passes kDNSServiceInterfaceIndexLocalOnly when browsing
- * then it will find only records registered on that same local machine.
- * Note that this is *not* exactly symmetrical with the registering case:
- * Services advertised using LocalOnly are ONLY discovered by clients browsing
- * on LocalOnly; in contrast, clients browsing on LocalOnly find ALL services
- * advertised by this machine, not only those advertised on LocalOnly.
- * Clients explicitly wishing to discover only LocalOnly services can
+ * then it will find *all* records registered on that same local machine.
+ * Clients explicitly wishing to discover *only* LocalOnly services can
  * accomplish this by inspecting the interfaceIndex of each service reported
  * to their DNSServiceBrowseReply() callback function, and discarding those
  * where the interface index is not kDNSServiceInterfaceIndexLocalOnly.
index 121b0df237cd01fc1a7cb53e843c363fd0360df8..7259a9c71173c701e3a01d36a7e8635770da00b8 100644 (file)
@@ -31,6 +31,9 @@
        Change History (most recent first):
 
 $Log: dnssd_clientshim.c,v $
+Revision 1.8  2004/12/16 20:47:34  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
 Revision 1.7  2004/12/10 04:08:43  cheshire
 Added comments about autoname and autorename
 
@@ -211,7 +214,7 @@ mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus re
        char namestr[MAX_DOMAIN_LABEL+1];               // Unescaped name: up to 63 bytes plus C-string terminating NULL.
        char typestr[MAX_ESCAPED_DOMAIN_NAME];
        char domstr [MAX_ESCAPED_DOMAIN_NAME];
-    if (!DeconstructServiceName(&sr->RR_SRV.resrec.name, &name, &type, &dom)) return;
+    if (!DeconstructServiceName(sr->RR_SRV.resrec.name, &name, &type, &dom)) return;
     if (!ConvertDomainLabelToCString_unescaped(&name, namestr)) return;
     if (!ConvertDomainNameToCString(&type, typestr)) return;
     if (!ConvertDomainNameToCString(&dom, domstr)) return;
@@ -402,7 +405,7 @@ mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const Resourc
        if (!DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain))
                {
                LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
-                       answer->name.c, answer->rdata->u.name.c);
+                       answer->name->c, answer->rdata->u.name.c);
                return;
                }
 
@@ -487,7 +490,7 @@ mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const Reso
                if (x->SRV && x->TXT && x->callback)
                        {
                        char fullname[MAX_ESCAPED_DOMAIN_NAME], targethost[MAX_ESCAPED_DOMAIN_NAME];
-                   ConvertDomainNameToCString(&answer->name, fullname);
+                   ConvertDomainNameToCString(answer->name, fullname);
                    ConvertDomainNameToCString(&x->SRV->rdata->u.srv.target, targethost);
                        x->callback((DNSServiceRef)x, 0, 0, kDNSServiceErr_NoError, fullname, targethost,
                                x->SRV->rdata->u.srv.port.NotAnInteger, x->TXT->rdlength, (char*)x->TXT->rdata->u.txt.c, x->context);
@@ -536,7 +539,7 @@ DNSServiceErrorType DNSServiceResolve
        x->qSRV.ThisQInterval       = -1;               // So that DNSServiceResolveDispose() knows whether to cancel this question
        x->qSRV.InterfaceID         = mDNSInterface_Any;
        x->qSRV.Target              = zeroAddr;
-       AssignDomainName(x->qSRV.qname, srv);
+       AssignDomainName(&x->qSRV.qname, &srv);
        x->qSRV.qtype               = kDNSType_SRV;
        x->qSRV.qclass              = kDNSClass_IN;
        x->qSRV.LongLived           = mDNSfalse;
@@ -548,7 +551,7 @@ DNSServiceErrorType DNSServiceResolve
        x->qTXT.ThisQInterval       = -1;               // So that DNSServiceResolveDispose() knows whether to cancel this question
        x->qTXT.InterfaceID         = mDNSInterface_Any;
        x->qTXT.Target              = zeroAddr;
-       AssignDomainName(x->qTXT.qname, srv);
+       AssignDomainName(&x->qTXT.qname, &srv);
        x->qTXT.qtype               = kDNSType_TXT;
        x->qTXT.qclass              = kDNSClass_IN;
        x->qTXT.LongLived           = mDNSfalse;
@@ -634,7 +637,7 @@ mDNSlocal void DNSServiceQueryRecordResponse(mDNS *const m, DNSQuestion *questio
        mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)question->QuestionContext;
        char fullname[MAX_ESCAPED_DOMAIN_NAME];
        (void)m;        // Unused
-       ConvertDomainNameToCString(&answer->name, fullname);
+       ConvertDomainNameToCString(answer->name, fullname);
        x->callback((DNSServiceRef)x, AddRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0, 0, kDNSServiceErr_NoError,
                fullname, answer->rrtype, answer->rrclass, answer->rdlength, answer->rdata->u.data, answer->rroriginalttl, x->context);
        }
index d060a669761a3de6275a3b9a10f627f2581ecfca..d06b5d2edad514ef5fab60630d74c8f982d425d4 100755 (executable)
     Change History (most recent first):
 
 $Log: dnssd_clientstub.c,v $
+Revision 1.44  2005/01/27 22:57:56  cheshire
+Fix compile errors on gcc4
+
+Revision 1.43  2005/01/27 00:02:29  cheshire
+<rdar://problem/3947461> Handle case where client runs before daemon has finished launching
+
+Revision 1.42  2005/01/11 02:01:02  shersche
+Use dnssd_close() rather than close() for Windows compatibility
+
+Revision 1.41  2004/12/23 17:34:26  ksekar
+<rdar://problem/3931319> Rendevzous calls leak sockets if mDNSResponder is not running
+
 Revision 1.40  2004/11/23 03:39:47  cheshire
 Let interface name/index mapping capability live directly in JNISupport.c,
 instead of having to call through to the daemon via IPC to get this information.
@@ -294,6 +306,7 @@ static DNSServiceRef connect_to_server(void)
     {
        dnssd_sockaddr_t saddr;
        DNSServiceRef sdr;
+       int NumTries = 0;
 
 #if defined(_WIN32)
        if (!g_initWinsock)
@@ -321,7 +334,25 @@ static DNSServiceRef connect_to_server(void)
        saddr.sun_family = AF_LOCAL;
        strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
 #endif
-       if (connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) { free(sdr); return NULL; }
+       while (1)
+               {
+               int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
+               if (!err) break;                // If we succeeded, return sdr
+               // If we failed, then it may be because the daemon is still launching.
+               // This can happen for processes that launch early in the boot process, while the
+               // daemon is still coming up. Rather than fail here, we'll wait a bit and try again.
+               // If, after ten seconds, we still can't connect to the daemon,
+               // then we give up and return a failure code.
+               if (++NumTries < 10)
+                       sleep(1);               // Sleep a bit, then try again
+               else
+                       {
+                       dnssd_close(sdr->sockfd);
+                       sdr->sockfd = dnssd_InvalidSocket;
+                       free(sdr);
+                       return NULL;
+                       }
+               }
     return sdr;
        }
 
@@ -332,7 +363,8 @@ static DNSServiceErrorType deliver_request(void *msg, DNSServiceRef sdr, int reu
     dnssd_sockaddr_t caddr, daddr;  // (client and daemon address structs)
     char *data = (char *)msg + sizeof(ipc_msg_hdr);
     dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
-       int ret, len = sizeof(caddr);
+       int ret;
+       unsigned int len = sizeof(caddr);
     DNSServiceErrorType err = kDNSServiceErr_Unknown;
 
     if (!hdr || sdr->sockfd < 0) return kDNSServiceErr_Unknown;
index e06737b7a0a222e434a39bc51bcc0f4a287d3e76..6a0236df98a2c982bdc18d7ba2aa3aa815b6659a 100644 (file)
@@ -27,6 +27,9 @@
        Change History (most recent first):
 
 $Log: dnssd_ipc.c,v $
+Revision 1.15  2005/01/27 22:57:56  cheshire
+Fix compile errors on gcc4
+
 Revision 1.14  2004/10/06 02:22:20  cheshire
 Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
 
@@ -103,7 +106,7 @@ int get_string(char **ptr, char *buffer, int buflen)
        return overrun;
        }
 
-void put_rdata(const int rdlen, const char *rdata, char **ptr)
+void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr)
        {
        memcpy(*ptr, rdata, rdlen);
        *ptr += rdlen;
index 60ffc166238407586a5abf315888fc27c8b43a15..ca0014b4622b21a2865945f0f0ac4567da2949f1 100644 (file)
@@ -27,6 +27,9 @@
     Change History (most recent first):
 
 $Log: dnssd_ipc.h,v $
+Revision 1.18  2005/01/27 22:57:56  cheshire
+Fix compile errors on gcc4
+
 Revision 1.17  2004/11/23 03:39:47  cheshire
 Let interface name/index mapping capability live directly in JNISupport.c,
 instead of having to call through to the daemon via IPC to get this information.
@@ -217,7 +220,7 @@ uint16_t get_short(char **ptr);
 int put_string(const char *str, char **ptr);
 int get_string(char **ptr, char *buffer, int buflen);
 
-void put_rdata(const int rdlen, const char *rdata, char **ptr);
+void put_rdata(const int rdlen, const unsigned char *rdata, char **ptr);
 char *get_rdata(char **ptr, int rdlen);  // return value is rdata pointed to by *ptr -
                                          // rdata is not copied from buffer.
 
index dc5ad0f292be9a625480b9b3d781d22444a43bc6..fcf16ffbbb9fe3f92b2d7f3a400c636a806bbc85 100644 (file)
@@ -29,6 +29,9 @@
     Change History (most recent first):
 
 $Log: mDNSDebug.c,v $
+Revision 1.6  2005/01/27 22:57:56  cheshire
+Fix compile errors on gcc4
+
 Revision 1.5  2004/09/17 01:08:55  cheshire
 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
   The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
@@ -119,7 +122,7 @@ mDNSlocal void WriteLogMsg(const char *ident, const char *buffer, int logoptflag
 // Log message with default "mDNSResponder" ident string at the start
 mDNSexport void LogMsg(const char *format, ...)
        {
-       unsigned char buffer[512];
+       char buffer[512];
        va_list ptr;
        va_start(ptr,format);
        buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
@@ -130,7 +133,7 @@ mDNSexport void LogMsg(const char *format, ...)
 // Log message with specified ident string at the start
 mDNSexport void LogMsgIdent(const char *ident, const char *format, ...)
        {
-       unsigned char buffer[512];
+       char buffer[512];
        va_list ptr;
        va_start(ptr,format);
        buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
@@ -141,7 +144,7 @@ mDNSexport void LogMsgIdent(const char *ident, const char *format, ...)
 // Log message with no ident string at the start
 mDNSexport void LogMsgNoIdent(const char *format, ...)
        {
-       unsigned char buffer[512];
+       char buffer[512];
        va_list ptr;
        va_start(ptr,format);
        buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
index 7f50d74c21007a30ea052d6d9aa2536b4ea5d280..e14db7aeecb801c6c81787d5864a7349b68af223 100644 (file)
     Change History (most recent first):
 
 $Log: uds_daemon.c,v $
+Revision 1.164  2005/01/28 06:07:55  cheshire
+Don't use deliver_error() from within handle_regrecord_request()
+
+Revision 1.163  2005/01/28 01:39:16  cheshire
+Include file descriptor number in "broken pipe" message
+
+Revision 1.162  2005/01/27 23:59:20  cheshire
+Remove extraneous LogMsg
+
+Revision 1.161  2005/01/27 22:57:56  cheshire
+Fix compile errors on gcc4
+
+Revision 1.160  2005/01/27 20:52:11  cheshire
+<rdar://problem/3972566> mDNSResponder leaks sockets for add/update/remove record calls
+
+Revision 1.159  2005/01/27 01:45:25  cheshire
+<rdar://problem/3976147> mDNSResponder should never call exit(1);
+
+Revision 1.158  2005/01/25 17:28:07  ksekar
+<rdar://problem/3971467> Should not return "local" twice for domain enumeration
+
+Revision 1.157  2005/01/21 02:20:39  cheshire
+Fix mistake in LogOperation() format string
+
+Revision 1.156  2005/01/19 19:15:36  ksekar
+Refinement to <rdar://problem/3954575> - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer
+
+Revision 1.155  2005/01/19 03:00:47  cheshire
+Show Add/Rmv in DNSServiceBrowse LogOperation() message
+
+Revision 1.154  2005/01/15 00:56:42  ksekar
+<rdar://problem/3954575> Unicast services don't disappear when logging
+out of VPN
+
+Revision 1.153  2005/01/14 18:44:28  ksekar
+<rdar://problem/3954609> mDNSResponder is crashing when changing domains
+
+Revision 1.152  2005/01/13 17:16:38  ksekar
+Back out checkin 1.150 - correct fix is on clientstub side
+
+Revision 1.151  2005/01/11 21:06:29  ksekar
+Changed now-benign LogMsg to debugf
+
+Revision 1.150  2005/01/07 23:59:15  ksekar
+<rdar://problem/3942900> dnd-sd shows the wrong port numbers
+
+Revision 1.149  2004/12/20 23:20:35  cheshire
+<rdar://problem/3928361> mDNSResponder crashes repeatedly when printer sharing is enabled
+Make sure to call mDNS_SetupResourceRecord() for all newly created AuthRecords
+
+Revision 1.148  2004/12/20 20:37:35  cheshire
+AllowRemoteQuery not set for the extras in a ServiceRecordSet
+
+Revision 1.147  2004/12/20 00:15:41  cheshire
+Include client file descriptor numbers in udsserver_info() output
+
+Revision 1.146  2004/12/17 05:25:47  cheshire
+<rdar://problem/3925163> Shorten DNS-SD queries to avoid NAT bugs
+
+Revision 1.145  2004/12/16 21:39:46  cheshire
+Include CacheGroup objects in CacheUsed count
+
+Revision 1.144  2004/12/16 21:27:38  ksekar
+Fixed build failures when compiled with verbose debugging messages
+
+Revision 1.143  2004/12/16 20:13:02  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
+Revision 1.142  2004/12/16 08:07:33  shersche
+Fix compiler error (mixed declarations and code) on Windows
+
+Revision 1.141  2004/12/16 01:56:21  cheshire
+Improve DNSServiceEnumerateDomains syslog message
+
+Revision 1.140  2004/12/14 03:02:10  ksekar
+<rdar://problem/3919016> Rare race condition can cause crash
+
 Revision 1.139  2004/12/13 21:18:45  ksekar
 Include uDNS registrations in CountPeerRegistrations
 
@@ -508,7 +585,7 @@ typedef struct registered_record_entry
 // to facilitate cleanup, when instances and parent may be deallocated at different times.
 typedef struct service_instance
     {
-    struct service_instance *next;  
+    struct service_instance *next;
     mDNSBool autoname;                         // Set if this name is tied to the Computer Name
     mDNSBool autorename;                       // Set if this client wants us to automatically rename on conflict
     mDNSBool allowremotequery;         // Respond to unicast queries from outside the local link?
@@ -519,7 +596,7 @@ typedef struct service_instance
     struct request_state *request;
     int sd;
     AuthRecord *subtypes;
-    ServiceRecordSet srs; // note - must be last field in struct 
+    ServiceRecordSet srs; // note - must be last field in struct
     } service_instance;
 
 // A client-created service.  May reference several service_info objects if default
@@ -562,7 +639,7 @@ typedef struct
     browser_t *browsers;
        } browser_info_t;
 
-typedef struct 
+typedef struct
     {
     mStatus err;               // Note: This field is in NETWORK byte order
     int nwritten;
@@ -572,9 +649,9 @@ typedef struct
 typedef struct request_state
     {
     // connection structures
-    dnssd_sock_t sd, errfd;            
-                                
-    // state of read (in case message is read over several recv() calls)                            
+    dnssd_sock_t sd;
+
+    // state of read (in case message is read over several recv() calls)
     transfer_state ts;
     uint32_t hdr_bytes;                // bytes of header already read
     ipc_msg_hdr hdr;
@@ -591,7 +668,7 @@ typedef struct request_state
     undelivered_error_t *u_err;
     void *termination_context;
     req_termination_fn terminate;
-    
+
     //!!!KRS toss these pointers in a union
     // registration context associated with this request (null if not applicable)
     registered_record_entry *reg_recs;  // muliple registrations for a connection-oriented request
@@ -607,7 +684,6 @@ typedef struct
     uint32_t ifi;                                      // Note: This field is in NETWORK byte order
     DNSServiceErrorType error;         // Note: This field is in NETWORK byte order
     } reply_hdr;
-    
 
 typedef struct reply_state
     {
@@ -624,10 +700,9 @@ typedef struct reply_state
     reply_hdr *rhdr;
     char *sdata;  // pointer to start of call-specific data
     // pointer to malloc'd buffer
-    char *msgbuf;      
+    char *msgbuf;
     } reply_state;
 
-
 // domain enumeration and resolv calls require 2 mDNSCore calls, so we need separate interconnected
 // structures to handle callbacks
 typedef struct
@@ -658,7 +733,7 @@ typedef struct
     mDNSu16    txtlen;
     mDNSu8     txtdata[AbsoluteMaxDNSMessageData];
     } resolve_termination_t;
-    
+
 #ifdef _HAVE_SETDOMAIN_SUPPORT_
 typedef struct default_browse_list_t
        {
@@ -674,13 +749,13 @@ static default_browse_list_t *default_browse_list = NULL;
 mDNSexport mDNS mDNSStorage;
 #define gmDNS (&mDNSStorage)
 
-static dnssd_sock_t                    listenfd                =       dnssd_InvalidSocket;  
-static request_state   *       all_requests    =       NULL;  
+static dnssd_sock_t                    listenfd                =       dnssd_InvalidSocket;
+static request_state   *       all_requests    =       NULL;
 
 #define MAX_TIME_BLOCKED 60 * mDNSPlatformOneSecond  // try to send data to a blocked client for 60 seconds before
                                                      // terminating connection
 #define MSG_PAD_BYTES 5                              // pad message buffer (read from client) with n zero'd bytes to guarantee
-                                                     // n get_string() calls w/o buffer overrun    
+                                                     // n get_string() calls w/o buffer overrun
 // private function prototypes
 static void connect_callback(void *info);
 static int read_msg(request_state *rs);
@@ -697,8 +772,8 @@ static void handle_regservice_request(request_state *request);
 static void regservice_termination_callback(void *context);
 static void process_service_registration(ServiceRecordSet *const srs);
 static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
-static void handle_add_request(request_state *rstate);
-static void handle_update_request(request_state *rstate);
+static mStatus handle_add_request(request_state *rstate);
+static mStatus handle_update_request(request_state *rstate);
 static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep);
 static void append_reply(request_state *req, reply_state *rep);
 static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain);
@@ -707,12 +782,12 @@ static void enum_result_callback(mDNS *const m, DNSQuestion *question, const Res
 static void handle_query_request(request_state *rstate);
 static reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
 static void handle_enum_request(request_state *rstate);
-static void handle_regrecord_request(request_state *rstate);
+static mStatus handle_regrecord_request(request_state *rstate);
 static void regrecord_callback(mDNS *const m, AuthRecord *const rr, mStatus result);
 static void connected_registration_termination(void *context);
 static void handle_reconfirm_request(request_state *rstate);
 static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flags);
-static void handle_removerecord_request(request_state *rstate);
+static mStatus handle_removerecord_request(request_state *rstate);
 static void reset_connected_rstate(request_state *rstate);
 static int deliver_error(request_state *rstate, mStatus err);
 static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err);
@@ -737,8 +812,15 @@ static void handle_setdomain_request(request_state *rstate);
 #define PID_FILE "/var/run/mDNSResponder.pid"
 #endif
 
+static void FatalError(char *errmsg)
+       {
+       LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
+       *(long*)0 = 0;  // On OS X abort() doesn't generate a crash log, but writing to zero does
+       abort();                // On platforms where writing to zero doesn't generate an exception, abort instead
+       }
+
 int udsserver_init(void)
-    {
+       {
        dnssd_sockaddr_t laddr;
        int                              ret;
 #if defined(_WIN32)
@@ -761,7 +843,7 @@ int udsserver_init(void)
 
     bzero(&laddr, sizeof(laddr));
 
-#if defined(USE_TCP_LOOPBACK)
+       #if defined(USE_TCP_LOOPBACK)
                {
                laddr.sin_family                =       AF_INET;
                laddr.sin_port                  =       htons(MDNS_TCP_SERVERPORT);
@@ -770,34 +852,34 @@ int udsserver_init(void)
                if (ret < 0)
                        goto error;
                }
-#else
+       #else
                {
        mode_t mask = umask(0);
        unlink(MDNS_UDS_SERVERPATH);  //OK if this fails
        laddr.sun_family = AF_LOCAL;
-#      ifndef NOT_HAVE_SA_LEN  
-       // According to Stevens (section 3.2), there is no portable way to 
-       // determine whether sa_len is defined on a particular platform. 
+       #ifndef NOT_HAVE_SA_LEN
+       // According to Stevens (section 3.2), there is no portable way to
+       // determine whether sa_len is defined on a particular platform.
        laddr.sun_len = sizeof(struct sockaddr_un);
-#      endif
+       #endif
        strcpy(laddr.sun_path, MDNS_UDS_SERVERPATH);
                ret = bind(listenfd, (struct sockaddr *) &laddr, sizeof(laddr));
                umask(mask);
                if (ret < 0)
                        goto error;
                }
-#endif
+       #endif
 
-#if defined(_WIN32)
+       #if defined(_WIN32)
        //
        // SEH: do we even need to do this on windows?  this socket
        // will be given to WSAEventSelect which will automatically
        // set it to non-blocking
        //
        if (ioctlsocket(listenfd, FIONBIO, &opt) != 0)
-#else
+       #else
     if (fcntl(listenfd, F_SETFL, O_NONBLOCK) != 0)
-#endif
+       #endif
        {
                my_perror("ERROR: could not set listen socket to non-blocking mode");
                goto error;
@@ -857,18 +939,17 @@ int udsserver_exit(void)
     return 0;
     }
 
-
 mDNSs32 udsserver_idle(mDNSs32 nextevent)
     {
     request_state *req = all_requests, *tmp, *prev = NULL;
     reply_state *fptr;
-    transfer_state result; 
+    transfer_state result;
     mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
 
     while(req)
         {
         result = t_uninitialized;
-        if (req->u_err) 
+        if (req->u_err)
             result = send_undelivered_error(req);
         if (result != t_error && result != t_morecoming &&             // don't try to send msg if send_error failed
             (req->ts == t_complete || req->ts == t_morecoming))
@@ -893,7 +974,7 @@ mDNSs32 udsserver_idle(mDNSs32 nextevent)
                 }
             }
         if (result == t_morecoming)
-        {      
+        {
            if (!req->time_blocked) req->time_blocked = now;
            debugf("udsserver_idle: client has been blocked for %ld seconds", (now - req->time_blocked) / mDNSPlatformOneSecond);
            if (now - req->time_blocked >= MAX_TIME_BLOCKED)
@@ -904,7 +985,7 @@ mDNSs32 udsserver_idle(mDNSs32 nextevent)
                }
            else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond;  // try again in a second
        }
-        if (result == t_terminated || result == t_error)  
+        if (result == t_terminated || result == t_error)
         //since we're already doing a list traversal, we unlink the request manunally instead of calling unlink_request()
             {
             tmp = req;
@@ -913,7 +994,7 @@ mDNSs32 udsserver_idle(mDNSs32 nextevent)
             req = req->next;
             freeL("udsserver_idle", tmp);
             }
-        else 
+        else
             {
             prev = req;
             req = req->next;
@@ -927,29 +1008,29 @@ void udsserver_info(mDNS *const m)
        mDNSs32 now = mDNS_TimeNow(m);
        mDNSu32 CacheUsed = 0, CacheActive = 0;
        mDNSu32 slot;
+       CacheGroup *cg;
+       CacheRecord *rr;
     request_state *req;
 
     LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
 
        for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
-               {
-               mDNSu32 SlotUsed = 0;
-               CacheRecord *rr;
-               for (rr = m->rrcache_hash[slot]; rr; rr=rr->next)
+               for(cg = m->rrcache_hash[slot]; cg; cg=cg->next)
                        {
-                       mDNSs32 remain = rr->resrec.rroriginalttl - (now - rr->TimeRcvd) / mDNSPlatformOneSecond;
-                       CacheUsed++;
-                       SlotUsed++;
-                       if (rr->CRActiveQuestion) CacheActive++;
-                       LogMsgNoIdent("%s%6ld %s%-6s%-6s%s",
-                               rr->CRActiveQuestion ? "*" : " ", remain,
-                               (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "-" : " ", DNSTypeName(rr->resrec.rrtype),
-                               ((NetworkInterfaceInfo *)rr->resrec.InterfaceID)->ifname, CRDisplayString(m, rr));
-                       usleep(1000);   // Limit rate a little so we don't flood syslog too fast
+                       CacheUsed++;    // Count one cache entity for the CacheGroup object
+                       for (rr = cg->members; rr; rr=rr->next)
+                               {
+                               mDNSs32 remain = rr->resrec.rroriginalttl - (now - rr->TimeRcvd) / mDNSPlatformOneSecond;
+                               CacheUsed++;
+                               if (rr->CRActiveQuestion) CacheActive++;
+                               LogMsgNoIdent("%s%6ld %s%-6s%-6s%s",
+                                       rr->CRActiveQuestion ? "*" : " ", remain,
+                                       (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "-" : " ", DNSTypeName(rr->resrec.rrtype),
+                                       ((NetworkInterfaceInfo *)rr->resrec.InterfaceID)->ifname, CRDisplayString(m, rr));
+                               usleep(1000);   // Limit rate a little so we don't flood syslog too fast
+                               }
                        }
-               if (m->rrcache_used[slot] != SlotUsed)
-                       LogMsgNoIdent("Cache use mismatch: rrcache_used[slot] is %lu, true count %lu", m->rrcache_used[slot], SlotUsed);
-               }
+
        if (m->rrcache_totalused != CacheUsed)
                LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
        if (m->rrcache_active != CacheActive)
@@ -964,20 +1045,20 @@ void udsserver_info(mDNS *const m)
                        {
                        service_instance *ptr;
                        for (ptr = ((service_info *)t)->instances; ptr; ptr = ptr->next)
-                               LogMsgNoIdent("DNSServiceRegister         %##s %u", ptr->srs.RR_SRV.resrec.name.c, SRS_PORT(&ptr->srs));
+                               LogMsgNoIdent("%3d: DNSServiceRegister         %##s %u", req->sd, ptr->srs.RR_SRV.resrec.name->c, SRS_PORT(&ptr->srs));
                        }
                else if (req->terminate == browse_termination_callback)
                        {
                        browser_t *blist;
                        for (blist = req->browser_info->browsers; blist; blist = blist->next)
-                               LogMsgNoIdent("DNSServiceBrowse           %##s", blist->q.qname.c);
+                               LogMsgNoIdent("%3d: DNSServiceBrowse           %##s", req->sd, blist->q.qname.c);
                        }
         else if (req->terminate == resolve_termination_callback)
-            LogMsgNoIdent("DNSServiceResolve          %##s", ((resolve_termination_t *)t)->qsrv.qname.c);
+            LogMsgNoIdent("%3d: DNSServiceResolve          %##s", req->sd, ((resolve_termination_t *)t)->qsrv.qname.c);
         else if (req->terminate == question_termination_callback)
-            LogMsgNoIdent("DNSServiceQueryRecord      %##s", ((DNSQuestion *)          t)->qname.c);
+            LogMsgNoIdent("%3d: DNSServiceQueryRecord      %##s", req->sd, ((DNSQuestion *)          t)->qname.c);
         else if (req->terminate == enum_termination_callback)
-            LogMsgNoIdent("DNSServiceEnumerateDomains %##s", ((enum_termination_t *)   t)->all->question.qname.c);
+            LogMsgNoIdent("%3d: DNSServiceEnumerateDomains %##s", req->sd, ((enum_termination_t *)   t)->all->question.qname.c);
         }
 
     now = mDNS_TimeNow(m);
@@ -991,7 +1072,7 @@ static void rename_service(service_instance *srv)
                srv->rename_on_memfree = 1;
                if (mDNS_DeregisterService(gmDNS, &srv->srs))   // If service deregistered already, we can re-register immediately
                        regservice_callback(gmDNS, &srv->srs, mStatus_MemFree);
-               }       
+               }
        }
 
 void udsserver_handle_configchange(void)
@@ -1013,7 +1094,7 @@ void udsserver_handle_configchange(void)
 static void connect_callback(void *info)
     {
     dnssd_sock_t sd;
-       int len;
+       unsigned int len;
        unsigned long optval;
     dnssd_sockaddr_t cliaddr;
     request_state *rstate;
@@ -1025,7 +1106,7 @@ static void connect_callback(void *info)
 
     if (sd == dnssd_InvalidSocket)
         {
-        if (dnssd_errno() == dnssd_EWOULDBLOCK) return; 
+        if (dnssd_errno() == dnssd_EWOULDBLOCK) return;
         my_perror("ERROR: accept");
         return;
        }
@@ -1035,7 +1116,7 @@ static void connect_callback(void *info)
        // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
     if (setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
        {
-        my_perror("ERROR: setsockopt - SOL_NOSIGPIPE - aborting client");  
+        my_perror("ERROR: setsockopt - SO_NOSIGPIPE - aborting client");
         dnssd_close(sd);
         return;
        }
@@ -1047,18 +1128,14 @@ static void connect_callback(void *info)
        if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
 #endif
         {
-               my_perror("ERROR: setsockopt - SOL_NOSIGPIPE - aborting client");  
+               my_perror("ERROR: fcntl(sd, F_SETFL, O_NONBLOCK) - aborting client");
                dnssd_close(sd);
                return;
                }
        
        // allocate a request_state struct that will live with the socket
     rstate = mallocL("connect_callback", sizeof(request_state));
-    if (!rstate)
-       {
-        my_perror("ERROR: malloc");
-        exit(1);
-       }
+    if (!rstate) FatalError("ERROR: malloc");
     bzero(rstate, sizeof(request_state));
     rstate->ts = t_morecoming;
     rstate->sd = sd;
@@ -1070,131 +1147,155 @@ static void connect_callback(void *info)
     all_requests = rstate;
     }
 
-
 // handler
 static void request_callback(void *info)
-    {
-    request_state *rstate = info;
-    transfer_state result;
-    dnssd_sockaddr_t cliaddr;
+       {
+       request_state *rstate = info;
+       transfer_state result;
+       dnssd_sockaddr_t cliaddr;
+       int dedicated_error_socket;
 #if defined(_WIN32)
-    u_long opt = 1;
+       u_long opt = 1;
 #endif
-    
-    result = read_msg(rstate);
-    if (result == t_morecoming)
-       {
-        return;
-       }
-    if (result == t_terminated)
-       {
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-       }
-    if (result == t_error)
-       {
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-       }
-
-    if (rstate->hdr.version != VERSION)
-    {
-        LogMsg("ERROR: client incompatible with daemon (client version = %d, "
-                "daemon version = %d)\n", rstate->hdr.version, VERSION);
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-    }
-    
-    if (validate_message(rstate) < 0)
-       {
-       // note that we cannot deliver an error message if validation fails, since the path to the error socket
-       // may be contained in the (invalid) message body for some message types
-       abort_request(rstate);
-       unlink_request(rstate);
-       LogMsg("Invalid message sent by client - may indicate a malicious program running on this machine!");
-       return;
-       }    
-    
-    // check if client wants silent operation
-    if (rstate->hdr.flags & IPC_FLAGS_NOREPLY) rstate->no_reply = 1;
-
-    // check if primary socket is to be used for synchronous errors, else open new socket
-    if (rstate->hdr.flags & IPC_FLAGS_REUSE_SOCKET)
-        rstate->errfd = rstate->sd;
-    else
+       
+       result = read_msg(rstate);
+       if (result == t_morecoming)
                {
-               if ((rstate->errfd = socket(AF_DNSSD, SOCK_STREAM, 0)) == dnssd_InvalidSocket)
-            {
-            my_perror("ERROR: socket");        
-            exit(1);
-            }
+               return;
+               }
+       if (result == t_terminated)
+               {
+               abort_request(rstate);
+               unlink_request(rstate);
+               return;
+               }
+       if (result == t_error)
+               {
+               abort_request(rstate);
+               unlink_request(rstate);
+               return;
+               }
 
-#if defined(USE_TCP_LOOPBACK)
+       if (rstate->hdr.version != VERSION)
                {
-               mDNSOpaque16 port;
-               port.b[0] = rstate->msgdata[0];
-               port.b[1] = rstate->msgdata[1];
-        rstate->msgdata += 2;
-               cliaddr.sin_family      = AF_INET;
-               cliaddr.sin_port        = port.NotAnInteger;
-               cliaddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
+               LogMsg("ERROR: client incompatible with daemon (client version = %d, "
+                      "daemon version = %d)\n", rstate->hdr.version, VERSION);
+               abort_request(rstate);
+               unlink_request(rstate);
+               return;
                }
-#else
+       
+       if (validate_message(rstate) < 0)
                {
-       char ctrl_path[MAX_CTLPATH];
-        get_string(&rstate->msgdata, ctrl_path, 256);  // path is first element in message buffer
-        bzero(&cliaddr, sizeof(cliaddr));
-        cliaddr.sun_family = AF_LOCAL;
-        strcpy(cliaddr.sun_path, ctrl_path);
+               // note that we cannot deliver an error message if validation fails, since the path to the error socket
+               // may be contained in the (invalid) message body for some message types
+               abort_request(rstate);
+               unlink_request(rstate);
+               LogMsg("Invalid message sent by client - may indicate a malicious program running on this machine!");
+               return;
                }
-#endif
-        if (connect(rstate->errfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
-            {
-            my_perror("ERROR: connect");
-            abort_request(rstate);
-            unlink_request(rstate);
+       
+       // check if client wants silent operation
+       if (rstate->hdr.flags & IPC_FLAGS_NOREPLY) rstate->no_reply = 1;
+
+       dedicated_error_socket = (rstate->hdr.op == reg_record_request    || rstate->hdr.op == add_record_request ||
+                                 rstate->hdr.op == update_record_request || rstate->hdr.op == remove_record_request);
+       
+       if (((rstate->hdr.flags & IPC_FLAGS_REUSE_SOCKET) == 0) != dedicated_error_socket)
+               LogMsg("WARNING: client request %d with incorrect flags setting 0x%X", rstate->hdr.op, rstate->hdr.flags);
+
+       // check if primary socket is to be used for synchronous errors, else open new socket
+       if (dedicated_error_socket)
+               {
+               mStatus err = 0;
+               int nwritten;
+               int errfd = socket(AF_DNSSD, SOCK_STREAM, 0);
+               if (errfd == dnssd_InvalidSocket)
+                       {
+                       my_perror("ERROR: socket");
+                       abort_request(rstate);
+                       unlink_request(rstate);
                        return;
-            }
+                       }
+
+               #if defined(USE_TCP_LOOPBACK)
+                       {
+                       mDNSOpaque16 port;
+                       port.b[0] = rstate->msgdata[0];
+                       port.b[1] = rstate->msgdata[1];
+                       rstate->msgdata += 2;
+                       cliaddr.sin_family      = AF_INET;
+                       cliaddr.sin_port        = port.NotAnInteger;
+                       cliaddr.sin_addr.s_addr = inet_addr(MDNS_TCP_SERVERADDR);
+                       }
+               #else
+                       {
+                       char ctrl_path[MAX_CTLPATH];
+                       get_string(&rstate->msgdata, ctrl_path, 256);   // path is first element in message buffer
+                       bzero(&cliaddr, sizeof(cliaddr));
+                       cliaddr.sun_family = AF_LOCAL;
+                       strcpy(cliaddr.sun_path, ctrl_path);
+                       }
+               #endif
+               if (connect(errfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
+                       {
+                       my_perror("ERROR: connect");
+                       abort_request(rstate);
+                       unlink_request(rstate);
+                       return;
+                       }
 #if defined(_WIN32)
-               if (ioctlsocket(rstate->errfd, FIONBIO, &opt) != 0)
+               if (ioctlsocket(errfd, FIONBIO, &opt) != 0)
 #else
-       if (fcntl(rstate->errfd, F_SETFL, O_NONBLOCK) != 0)
+               if (fcntl(errfd, F_SETFL, O_NONBLOCK) != 0)
 #endif
-            {
-            my_perror("ERROR: could not set control socket to non-blocking mode");
-            abort_request(rstate);
-            unlink_request(rstate);
-            return;
-            }        
-               }
+                       {
+                       my_perror("ERROR: could not set control socket to non-blocking mode");
+                       abort_request(rstate);
+                       unlink_request(rstate);
+                       return;
+                       }
 
-    switch(rstate->hdr.op)
-       {
-        case resolve_request: handle_resolve_request(rstate); break;
-        case query_request: handle_query_request(rstate);  break;
-        case browse_request: handle_browse_request(rstate); break;
-        case reg_service_request: handle_regservice_request(rstate);  break;
-        case enumeration_request: handle_enum_request(rstate); break;
-        case reg_record_request: handle_regrecord_request(rstate);  break;
-        case add_record_request: handle_add_request(rstate); break;
-        case update_record_request: handle_update_request(rstate); break;
-        case remove_record_request: handle_removerecord_request(rstate); break;
-        case reconfirm_record_request: handle_reconfirm_request(rstate); break;
-               case setdomain_request: handle_setdomain_request(rstate); break;
-        default:
-            LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
-       }
-    }
+               switch(rstate->hdr.op)
+                       {
+                       case reg_record_request:    err = handle_regrecord_request   (rstate); break;
+                       case add_record_request:    err = handle_add_request         (rstate); break;
+                       case update_record_request: err = handle_update_request      (rstate); break;
+                       case remove_record_request: err = handle_removerecord_request(rstate); break;
+                       default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
+                       }
+
+               err = dnssd_htonl(err);
+               nwritten = send(errfd, &err, sizeof(err), 0);
+               // On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a four-byte write for us.
+               // If not, we don't attempt to handle this failure, but we do log it.
+               if (nwritten < (int)sizeof(err))
+                       LogMsg("ERROR: failed to write error response back to caller: %d %d %s",
+                               nwritten, dnssd_errno(), dnssd_strerror(dnssd_errno()));
+               dnssd_close(errfd);
+               reset_connected_rstate(rstate);         // Reset ready to accept the next request on this pipe
+               }
+       else
+               {
+               switch(rstate->hdr.op)
+                       {
+                       case resolve_request:          handle_resolve_request   (rstate); break;
+                       case query_request:            handle_query_request     (rstate); break;
+                       case browse_request:           handle_browse_request    (rstate); break;
+                       case reg_service_request:      handle_regservice_request(rstate); break;
+                       case enumeration_request:      handle_enum_request      (rstate); break;
+                       case reconfirm_record_request: handle_reconfirm_request (rstate); break;
+                       case setdomain_request:        handle_setdomain_request (rstate); break;
+                       default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
+                       }
+               }
+       }
 
 // mDNS operation functions.  Each operation has 3 associated functions - a request handler that parses
 // the client's request and makes the appropriate mDNSCore call, a result handler (passed as a callback
 // to the mDNSCore routine) that sends results back to the client, and a termination routine that aborts
 // the mDNSCore operation if the client dies or closes its socket.
 
-
 // query and resolve calls have separate request handlers that parse the arguments from the client and
 // massage the name parameters appropriately, but the rest of the operations (making the query call,
 // delivering the result to the client, and termination) are identical.
@@ -1231,16 +1332,12 @@ static void handle_query_request(request_state *rstate)
     if (ifi && !InterfaceID) goto bad_param;
 
     q = mallocL("DNSQuestion", sizeof(DNSQuestion));
-    if (!q)
-       {
-        my_perror("ERROR: handle_query - malloc");
-        exit(1);
-       }
-    bzero(q, sizeof(DNSQuestion));     
+    if (!q) FatalError("ERROR: handle_query - malloc");
+    bzero(q, sizeof(DNSQuestion));
 
     q->InterfaceID      = InterfaceID;
     q->Target           = zeroAddr;
-    if (!MakeDomainNameFromDNSNameString(&q->qname, name)) { freeL("DNSQuestion", q); goto bad_param; }        
+    if (!MakeDomainNameFromDNSNameString(&q->qname, name)) { freeL("DNSQuestion", q); goto bad_param; }
     q->qtype            = rrtype;
     q->qclass           = rrclass;
     q->LongLived        = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
@@ -1310,14 +1407,14 @@ static void handle_resolve_request(request_state *rstate)
     // free memory in rstate since we don't need it anymore
     freeL("handle_resolve_request", rstate->msgbuf);
     rstate->msgbuf = NULL;
-        
+
     if (build_domainname_from_strings(&fqdn, name, regtype, domain) < 0)
        { LogMsg("ERROR: handle_resolve_request - Couldn't build_domainname_from_strings “%s” “%s” “%s”", name, regtype, domain); goto bad_param; }
 
     // set up termination info
     term = mallocL("handle_resolve_request", sizeof(resolve_termination_t));
     bzero(term, sizeof(*term));
-    if (!term) goto malloc_error;
+    if (!term) FatalError("ERROR: malloc");
 
     // format questions
     term->qsrv.InterfaceID      = InterfaceID;
@@ -1356,7 +1453,7 @@ static void handle_resolve_request(request_state *rstate)
         freeL("handle_resolve_request", term);
         rstate->terminate = NULL;  // prevent abort_request() from invoking termination callback
         }
-    if (deliver_error(rstate, err) < 0 || err) 
+    if (deliver_error(rstate, err) < 0 || err)
         {
         abort_request(rstate);
         unlink_request(rstate);
@@ -1367,11 +1464,6 @@ bad_param:
     deliver_error(rstate, mStatus_BadParamErr);
     abort_request(rstate);
     unlink_request(rstate);
-    return;
-    
-malloc_error:
-    my_perror("ERROR: malloc");
-    exit(1);
     }
     
 static void resolve_termination_callback(void *context)
@@ -1379,7 +1471,7 @@ static void resolve_termination_callback(void *context)
     resolve_termination_t *term = context;
     request_state *rs;
     
-    if (!term) 
+    if (!term)
         {
         LogMsg("ERROR: resolve_termination_callback: double termination");
         return;
@@ -1423,7 +1515,7 @@ static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const
 
     if (answer->rrtype == kDNSType_SRV)
        {
-       AssignDomainName(res->target, answer->rdata->u.srv.target);
+       AssignDomainName(&res->target, &answer->rdata->u.srv.target);
        res->port = answer->rdata->u.srv.port;
        res->srv = mDNStrue;
        }
@@ -1437,7 +1529,7 @@ static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const
 
     if (!res->txt || !res->srv) return;                // only deliver result to client if we have both answers
     
-    ConvertDomainNameToCString(&answer->name, fullname);
+    ConvertDomainNameToCString(answer->name, fullname);
     ConvertDomainNameToCString(&res->target, target);
 
     // calculate reply length
@@ -1460,22 +1552,22 @@ static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const
     // write reply data to message
     put_string(fullname, &data);
     put_string(target, &data);
-    *data++ = res->port.b[0];
-    *data++ = res->port.b[1];
+       *data++ = res->port.b[0];
+       *data++ = res->port.b[1];
     put_short(res->txtlen, &data);
     put_rdata(res->txtlen, res->txtdata, &data);
     
     result = send_msg(rep);
-    if (result == t_error || result == t_terminated) 
-        {  
-        abort_request(rs);  
+    if (result == t_error || result == t_terminated)
+        {
+        abort_request(rs);
         unlink_request(rs);
-        freeL("resolve_result_callback", rep);  
+        freeL("resolve_result_callback", rep);
         }
     else if (result == t_complete) freeL("resolve_result_callback", rep);
     else append_reply(rs, rep);
     }
+
 // what gets called when a resolve is completed and we need to send the data back to the client
 static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
     {
@@ -1495,7 +1587,7 @@ static void question_result_callback(mDNS *const m, DNSQuestion *question, const
     len += sizeof(DNSServiceErrorType);
     len += 3 * sizeof(uint16_t); // type, class, rdlen
     len += answer->rdlength;
-    ConvertDomainNameToCString(&answer->name, name);
+    ConvertDomainNameToCString(answer->name, name);
     len += strlen(name) + 1;
     
     rep =  create_reply(query_reply, len, req);
@@ -1510,7 +1602,7 @@ static void question_result_callback(mDNS *const m, DNSQuestion *question, const
     put_short(answer->rrtype, &data);
     put_short(answer->rrclass, &data);
     put_short(answer->rdlength, &data);
-    put_rdata(answer->rdlength, (char *)&answer->rdata->u, &data);
+    put_rdata(answer->rdlength, answer->rdata->u.data, &data);
     put_long(AddRecord ? answer->rroriginalttl : 0, &data);
 
     append_reply(req, rep);
@@ -1586,16 +1678,16 @@ mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
                if (!st) return(mDNSNULL);
                for (i = 0; i < NumSubTypes; i++)
                        {
+                       mDNS_SetupResourceRecord(&st[i], mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, mDNSNULL, mDNSNULL);
                        while (*p) p++;
                        p++;
-                       if (!MakeDomainNameFromDNSNameString(&st[i].resrec.name, p))
+                       if (!MakeDomainNameFromDNSNameString(st[i].resrec.name, p))
                                { freeL("ServiceSubTypes", st); return(mDNSNULL); }
                        }
                }
        return(st);
        }
 
-
 #ifdef _HAVE_SETDOMAIN_SUPPORT_
 static void free_defdomain(mDNS *const m, AuthRecord *const rr, mStatus result)
        {
@@ -1627,7 +1719,7 @@ static void handle_setdomain_request(request_state *request)
     // extract flags/domain from message
     ptr = request->msgdata;
     flags = get_flags(&ptr);
-    if (get_string(&ptr, domainstr, MAX_ESCAPED_DOMAIN_NAME) < 0 || 
+    if (get_string(&ptr, domainstr, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
                !MakeDomainNameFromDNSNameString(&domain, domainstr))
                { err = mStatus_BadParamErr; goto end; }
 
@@ -1643,7 +1735,7 @@ static void handle_setdomain_request(request_state *request)
        if (getsockopt(request->sd, 0, LOCAL_PEERCRED, &xuc, &xuclen))
                { my_perror("ERROR: getsockopt, LOCAL_PEERCRED"); err = mStatus_UnknownErr; goto end; }
        if (xuc.cr_version != XUCRED_VERSION) { LogMsg("getsockopt, LOCAL_PEERCRED - bad version"); err = mStatus_UnknownErr; goto end; }
-       LogMsg("Default domain %s %s for UID %d", domainstr, flags & kDNSServiceFlagsAdd ? "set" : "removed", xuc.cr_uid);      
+       LogMsg("Default domain %s %s for UID %d", domainstr, flags & kDNSServiceFlagsAdd ? "set" : "removed", xuc.cr_uid);
 
        if (flags & kDNSServiceFlagsAdd)
                {
@@ -1651,8 +1743,9 @@ static void handle_setdomain_request(request_state *request)
                default_browse_list_t *newelem = malloc(sizeof(default_browse_list_t));
                if (!newelem) { LogMsg("ERROR: malloc"); err = mStatus_NoMemoryErr; goto end; }
                mDNS_SetupResourceRecord(&newelem->ptr_rec, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, free_defdomain, newelem);
-               MakeDomainNameFromDNSNameString(&newelem->ptr_rec.resrec.name, "_default._browse._dns-sd._udp.local.");
-               AssignDomainName(newelem->ptr_rec.resrec.rdata->u.name, domain);
+               MakeDomainNameFromDNSNameString(&newelem->ptr_rec.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault]);
+               AppendDNSNameString            (&newelem->ptr_rec.resrec.name, "local");
+               AssignDomainName(&newelem->ptr_rec.resrec.rdata->u.name, &domain);
                newelem->uid = xuc.cr_uid;
                err = mDNS_Register(gmDNS, &newelem->ptr_rec);
                if (err) free(newelem);
@@ -1681,7 +1774,7 @@ static void handle_setdomain_request(request_state *request)
                        ptr = ptr->next;
                        }
                if (!ptr) { LogMsg("Attempt to remove nonexistent domain %s for UID %d", domainstr, xuc.cr_uid); err = mStatus_Invalid; }
-               }               
+               }
 #else
        err = mStatus_NoError;
 #endif // _HAVE_SETDOMAIN_SUPPORT_
@@ -1700,12 +1793,12 @@ static mStatus add_domain_to_browser(browser_info_t *info, const domainname *d)
        for (p = info->browsers; p; p = p->next)
                {
                if (SameDomainName(&p->domain, d))
-                       { LogMsg("add_domain_to_browser - attempt to add domain %##d already in list", d->c); return mStatus_AlreadyRegistered; }
+                       { debugf("add_domain_to_browser - attempt to add domain %##d already in list", d->c); return mStatus_AlreadyRegistered; }
                }
 
        b = mallocL("browser_t", sizeof(*b));
        if (!b) return mStatus_NoMemoryErr;
-       AssignDomainName(b->domain, *d);
+       AssignDomainName(&b->domain, d);
        err = mDNS_StartBrowse(gmDNS, &b->q, &info->regtype, d, info->interface_id, info->ForceMCast, browse_result_callback, info->rstate);
        if (err)
                {
@@ -1745,7 +1838,7 @@ static void handle_browse_request(request_state *request)
     ptr = request->msgdata;
     flags = get_flags(&ptr);
     interfaceIndex = get_long(&ptr);
-    if (get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 || 
+    if (get_string(&ptr, regtype, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
         get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0)
                { err = mStatus_BadParamErr;  goto error; }
     freeL("handle_browse_request", request->msgbuf);
@@ -1772,7 +1865,7 @@ static void handle_browse_request(request_state *request)
        request->browser_info = info;
        info->ForceMCast = (flags & kDNSServiceFlagsForceMulticast) != 0;
        info->interface_id = InterfaceID;
-       AssignDomainName(info->regtype, typedn);
+       AssignDomainName(&info->regtype, &typedn);
        info->rstate = request;
        info->default_domain = !domain[0];
        info->browsers = NULL;
@@ -1821,12 +1914,13 @@ static void browse_result_callback(mDNS *const m, DNSQuestion *question, const R
     reply_state *rep;
     mStatus err;
     (void)m; // Unused
-       LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s", req->sd, question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer));
+       LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
+               req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
 
     err = gen_rr_response(&answer->rdata->u.name, answer->InterfaceID, req, &rep);
     if (err)
         {
-        if (deliver_async_error(req, browse_reply, err) < 0) 
+        if (deliver_async_error(req, browse_reply, err) < 0)
             {
             abort_request(req);
             unlink_request(req);
@@ -1861,8 +1955,8 @@ static void browse_termination_callback(void *context)
 mDNSexport void udsserver_default_browse_domain_changed(const domainname *d, mDNSBool add)
        {
        request_state *r;
-       
-       for (r = all_requests; r; r = r->next)
+
+       for (r = all_requests; r; r = r->next)
                {
                browser_info_t *info = r->browser_info;
                
@@ -1870,21 +1964,27 @@ mDNSexport void udsserver_default_browse_domain_changed(const domainname *d, mDN
                if (add) add_domain_to_browser(info, d);
                else
                        {
-                       browser_t *ptr = info->browsers, *prev = NULL;
-                       while (ptr)
+                       browser_t **ptr = &info->browsers;
+                       while (*ptr)
                                {
-                               if (SameDomainName(&ptr->domain, d))
+                               if (SameDomainName(&(*ptr)->domain, d))
                                        {
-                                       if (prev) prev->next = ptr->next;
-                                       else info->browsers = ptr->next;
-                                       mDNS_StopBrowse(gmDNS, &ptr->q);
-                                       freeL("browser_t", ptr);
-                                       break;
+                                       browser_t *remove = *ptr;
+                                       *ptr = (*ptr)->next;
+                                       if (remove->q.LongLived)
+                                               {
+                                               // give goodbyes for known answers.
+                                               // note that since events are sent to client via udsserver_idle(), we don't need to worry about the question being cancelled mid-loop
+                                               CacheRecord *ka = remove->q.uDNS_info.knownAnswers;
+                                               while (ka) { remove->q.QuestionCallback(gmDNS, &remove->q, &ka->resrec, mDNSfalse); ka = ka->next; }
+                                               }
+                                       mDNS_StopBrowse(gmDNS, &remove->q);
+                                       freeL("browser_t", remove);
+                                       return;
                                        }
-                               prev = ptr;
-                               ptr = ptr->next;
+                               ptr = &(*ptr)->next;
                                }
-                       if (!ptr) LogMsg("Requested removal of default domain %##s not in list for sd %s", d->c, r->sd);
+                       LogMsg("Requested removal of default domain %##s not in list for sd %d", d->c, r->sd);
                        }
                }
        }
@@ -1900,18 +2000,18 @@ mDNSexport int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs
        ServiceRecordSet *s;
        
        for (rr = m->ResourceRecords; rr; rr=rr->next)
-               if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(&rr->resrec.name, &r->name) && !SameRData(&rr->resrec, r))
+               if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
                        count++;
 
        for (rr = m->uDNS_info.RecordRegistrations; rr; rr=rr->next)
-               if (rr->uDNS_info.state != regState_Unregistered && rr->resrec.rrtype == kDNSType_SRV && SameDomainName(&rr->resrec.name, &r->name) && !SameRData(&rr->resrec, r))
+               if (rr->uDNS_info.state != regState_Unregistered && rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !SameRData(&rr->resrec, r))
                        count++;
 
        for (s = m->uDNS_info.ServiceRegistrations; s; s = s->next)
-               if (s->uDNS_info.state != regState_Unregistered && SameDomainName(&s->RR_SRV.resrec.name, &r->name) && !SameRData(&s->RR_SRV.resrec, r))
+               if (s->uDNS_info.state != regState_Unregistered && SameDomainName(s->RR_SRV.resrec.name, r->name) && !SameRData(&s->RR_SRV.resrec, r))
                        count++;
                
-       verbosedebugf("%d peer registrations for %##s", count, r->name.c);
+       verbosedebugf("%d peer registrations for %##s", count, r->name->c);
        return(count);
        }
 
@@ -1922,7 +2022,7 @@ mDNSexport int CountExistingRegistrations(domainname *srv, mDNSIPPort port)
        for (rr = gmDNS->ResourceRecords; rr; rr=rr->next)
                if (rr->resrec.rrtype == kDNSType_SRV &&
                        rr->resrec.rdata->u.srv.port.NotAnInteger == port.NotAnInteger &&
-                       SameDomainName(&rr->resrec.name, srv))
+                       SameDomainName(rr->resrec.name, srv))
                        count++;
        return(count);
        }
@@ -1940,14 +2040,14 @@ static mStatus register_service_instance(request_state *request, const domainnam
                        { LogMsg("register_service_instance: domain %##s already registered", domain->c); return mStatus_AlreadyRegistered; }
                }
        
-       instance_size = sizeof(*instance);      
+       instance_size = sizeof(*instance);
        if (info->txtlen > sizeof(RDataBody)) instance_size += (info->txtlen - sizeof(RDataBody));
        instance = mallocL("service_instance", instance_size);
-       if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; } 
+       if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
 
        instance->subtypes = AllocateSubTypes(info->num_subtypes, info->type_as_string);
        if (info->num_subtypes && !instance->subtypes)
-               { free_service_instance(instance); instance = NULL; goto malloc_error; }
+               { free_service_instance(instance); instance = NULL; FatalError("ERROR: malloc"); }
     instance->request           = request;
        instance->sd                = request->sd;
     instance->autoname          = info->autoname;
@@ -1955,7 +2055,7 @@ static mStatus register_service_instance(request_state *request, const domainnam
     instance->allowremotequery  = info->allowremotequery;
     instance->rename_on_memfree = 0;
        instance->name              = info->name;
-       AssignDomainName(instance->domain, *domain);
+       AssignDomainName(&instance->domain, domain);
        instance->default_local = (info->default_domain && SameDomainName(domain, &localdomain));
     result = mDNS_RegisterService(gmDNS, &instance->srs, &instance->name, &info->type, domain, info->host.c[0] ? &info->host : NULL, info->port,
                                                                  info->txtdata, info->txtlen, instance->subtypes, info->num_subtypes, info->InterfaceID, regservice_callback, instance);
@@ -1967,10 +2067,6 @@ static mStatus register_service_instance(request_state *request, const domainnam
                info->instances = instance;
                }
        return result;
-
-malloc_error:
-    my_perror("ERROR: malloc");
-    exit(1);
        }
 
 mDNSexport void udsserver_default_reg_domain_changed(const domainname *d, mDNSBool add)
@@ -1995,7 +2091,7 @@ mDNSexport void udsserver_default_reg_domain_changed(const domainname *d, mDNSBo
                                {
                                if (SameDomainName(&si->domain, d))
                                        {
-                                       mStatus err;                                    
+                                       mStatus err;
                                        if (prev) prev->next = si->next;
                                        else info->instances = si->next;
                                        err = mDNS_DeregisterService(gmDNS, &si->srs);
@@ -2050,13 +2146,14 @@ static void handle_regservice_request(request_state *request)
     if (ifi && !service->InterfaceID)
        { LogMsg("ERROR: handle_regservice_request - Couldn't find InterfaceID for interfaceIndex %d", ifi); goto bad_param; }
     if (get_string(&ptr, name, 256) < 0 ||
-        get_string(&ptr, service->type_as_string, MAX_ESCAPED_DOMAIN_NAME) < 0 || 
+        get_string(&ptr, service->type_as_string, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
         get_string(&ptr, domain, MAX_ESCAPED_DOMAIN_NAME) < 0 ||
         get_string(&ptr, host, MAX_ESCAPED_DOMAIN_NAME) < 0)
        { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); goto bad_param; }
         
-    service->port.b[0] = *ptr++;
-    service->port.b[1] = *ptr++;
+       service->port.b[0] = *ptr++;
+       service->port.b[1] = *ptr++;
+
     service->txtlen  = get_short(&ptr);
     service->txtdata = get_rdata(&ptr, service->txtlen);
 
@@ -2126,13 +2223,13 @@ static void handle_regservice_request(request_state *request)
        
 finish:
     deliver_error(request, result);
-    if (result != mStatus_NoError) 
+    if (result != mStatus_NoError)
         {
         abort_request(request);
         unlink_request(request);
         }
-    else 
-        reset_connected_rstate(request);  // reset to receive add/remove messages
+    else
+        reset_connected_rstate(request);  // prepare to receive add/remove messages
 
     return;
 
@@ -2156,22 +2253,24 @@ static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mSta
     if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; }
 
     if (result == mStatus_NoError)
-               LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED  ",  instance->sd, srs->RR_SRV.resrec.name.c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
+               LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED  ",  instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
        else if (result == mStatus_MemFree)
-               LogOperation("%3d: DNSServiceRegister(%##s, %u) DEREGISTERED",  instance->sd, srs->RR_SRV.resrec.name.c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
+               LogOperation("%3d: DNSServiceRegister(%##s, %u) DEREGISTERED",  instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
        else if (result == mStatus_NameConflict)
-               LogOperation("%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT", instance->sd, srs->RR_SRV.resrec.name.c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
+               LogOperation("%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
        else
-               LogOperation("%3d: DNSServiceRegister(%##s, %u) CALLBACK %d",   instance->sd, srs->RR_SRV.resrec.name.c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), result);
+               LogOperation("%3d: DNSServiceRegister(%##s, %u) CALLBACK %d",   instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), result);
 
     if (result == mStatus_NoError)
                {
                if (instance->allowremotequery)
                        {
+                       ExtraResourceRecord *e;
                        srs->RR_ADV.AllowRemoteQuery = mDNStrue;
                        srs->RR_PTR.AllowRemoteQuery = mDNStrue;
                        srs->RR_SRV.AllowRemoteQuery = mDNStrue;
                        srs->RR_TXT.AllowRemoteQuery = mDNStrue;
+                       for (e = instance->srs.Extras; e; e = e->next) e->r.AllowRemoteQuery = mDNStrue;
                        }
         process_service_registration(srs);
         if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
@@ -2188,7 +2287,7 @@ static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mSta
             if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %ld", err);
             // error should never happen - safest to log and continue
             }
-        else 
+        else
             {
                        free_service_instance(instance);
             return;
@@ -2212,21 +2311,21 @@ static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mSta
                    request_state *rs = instance->request;
                        if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
                        free_service_instance(instance);
-                       if (deliver_async_error(rs, reg_service_reply, result) < 0) 
+                       if (deliver_async_error(rs, reg_service_reply, result) < 0)
                 {
                 abort_request(rs);
                 unlink_request(rs);
                 }
             return;
             }
-       } 
-    else 
+       }
+    else
         {
                request_state *rs = instance->request;
                if (!rs) { LogMsg("ERROR: regservice_callback: received result %ld with a NULL request pointer", result); return; }
         if (result != mStatus_NATTraversal) LogMsg("ERROR: unknown result in regservice_callback: %ld", result);
                free_service_instance(instance);
-        if (deliver_async_error(rs, reg_service_reply, result) < 0) 
+        if (deliver_async_error(rs, reg_service_reply, result) < 0)
             {
             abort_request(rs);
             unlink_request(rs);
@@ -2242,13 +2341,12 @@ mDNSexport void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result)
        
        if (result != mStatus_MemFree) { LogMsg("Error: FreeExtraRR invoked with unexpected error %d", result); return; }
        
-       debugf("%##s: MemFree", rr->resrec.name.c);
+       debugf("%##s: MemFree", rr->resrec.name->c);
        if (rr->resrec.rdata != &rr->rdatastorage)
                freeL("Extra RData", rr->resrec.rdata);
        freeL("ExtraResourceRecord", extra);
        }
 
-
 static mStatus add_record_to_service(request_state *rstate, service_instance *instance, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl)
        {
        ServiceRecordSet *srs = &instance->srs;
@@ -2279,8 +2377,7 @@ static mStatus add_record_to_service(request_state *rstate, service_instance *in
        return result;
        }
 
-
-static void handle_add_request(request_state *rstate)
+static mStatus handle_add_request(request_state *rstate)
     {
     uint32_t ttl;
     uint16_t rrtype, rdlen;
@@ -2290,7 +2387,7 @@ static void handle_add_request(request_state *rstate)
        service_info *srvinfo = rstate->service_registration;
        service_instance *i;
 
-       if (!srvinfo) { LogMsg("handle_add_request called with NULL service_registration"); return; }
+       if (!srvinfo) { LogMsg("handle_add_request called with NULL service_registration"); return(-1); }
 
        ptr = rstate->msgdata;
     flags = get_flags(&ptr);
@@ -2301,8 +2398,8 @@ static void handle_add_request(request_state *rstate)
        
     if (!ttl) ttl = DefaultTTLforRRType(rrtype);
 
-       LogOperation("%3d: DNSServiceAddRecord(%##s, %s)", rstate->sd, 
-               (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name.c : NULL, DNSTypeName(rrtype));
+       LogOperation("%3d: DNSServiceAddRecord(%##s, %s)", rstate->sd,
+               (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype));
 
        for (i = srvinfo->instances; i; i = i->next)
                {
@@ -2311,12 +2408,11 @@ static void handle_add_request(request_state *rstate)
                else result = mStatus_NoError;  // suppress non-local default errors
                }
        
-    deliver_error(rstate, result);
-    reset_connected_rstate(rstate);
+       return(result);
     }
 
 static mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32_t ttl)
-       {       
+       {
        int rdsize;
        RData *newrd;
        mStatus result;
@@ -2324,11 +2420,7 @@ static mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32
        if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
     else rdsize = sizeof(RDataBody);
     newrd = mallocL("handle_update_request", sizeof(RData) - sizeof(RDataBody) + rdsize);
-    if (!newrd)
-        {
-        my_perror("ERROR: malloc");
-        exit(1);
-        }
+    if (!newrd) FatalError("ERROR: malloc");
     newrd->MaxRDLength = (mDNSu16) rdsize;
     memcpy(&newrd->u, rdata, rdlen);
     result = mDNS_Update(gmDNS, rr, ttl, rdlen, newrd, update_callback);
@@ -2336,7 +2428,7 @@ static mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32
        return result;
        }
 
-static void handle_update_request(request_state *rstate)
+static mStatus handle_update_request(request_state *rstate)
     {
        uint16_t rdlen;
     char *ptr, *rdata;
@@ -2351,7 +2443,7 @@ static void handle_update_request(request_state *rstate)
     get_flags(&ptr);   // flags unused
     rdlen = get_short(&ptr);
     rdata = get_rdata(&ptr, rdlen);
-    ttl = get_long(&ptr);      
+    ttl = get_long(&ptr);
 
        if (rstate->reg_recs)
                {
@@ -2378,7 +2470,7 @@ static void handle_update_request(request_state *rstate)
                        {
                        ExtraResourceRecord *e;
                        for (e = i->srs.Extras; e; e = e->next)
-                               if (e->ClientID == rstate->hdr.reg_index) { rr = &e->r; break; }                        
+                               if (e->ClientID == rstate->hdr.reg_index) { rr = &e->r; break; }
                        }
 
                if (!rr) { result = mStatus_BadReferenceErr; goto end; }
@@ -2389,15 +2481,14 @@ static void handle_update_request(request_state *rstate)
 
 end:
        LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)", rstate->sd,
-               (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name.c : NULL,
+               (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL,
                rr ? DNSTypeName(rr->resrec.rrtype) : "<NONE>");
 
-    deliver_error(rstate, result);
-    reset_connected_rstate(rstate);
+    return(result);
     }
     
 static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
-    {    
+    {
     (void)m; // Unused
     if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd);
     }
@@ -2410,9 +2501,9 @@ static void process_service_registration(ServiceRecordSet *const srs)
     service_instance *instance = srs->ServiceContext;
     request_state *req = instance->request;
 
-
-    err = gen_rr_response(&srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep);
-    if (err) 
+       if (!req) { LogMsg("ERROR: process_service_registration - null request object"); return; }
+    err = gen_rr_response(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep);
+    if (err)
         {
         if (deliver_async_error(req, reg_service_reply, err) < 0)
             {
@@ -2422,11 +2513,11 @@ static void process_service_registration(ServiceRecordSet *const srs)
         return;
         }
     send_result = send_msg(rep);
-    if (send_result == t_error || send_result == t_terminated) 
-        {  
-        abort_request(req);  
+    if (send_result == t_error || send_result == t_terminated)
+        {
+        abort_request(req);
         unlink_request(req);
-        freeL("process_service_registration", rep);  
+        freeL("process_service_registration", rep);
         }
     else if (send_result == t_complete) freeL("process_service_registration", rep);
     else append_reply(req, rep);
@@ -2478,15 +2569,15 @@ static void regservice_termination_callback(void *context)
                p = i;
                i = i->next;
                p->request = NULL;  // clear back pointer
-               // only safe to free memory if registration is not valid, ie deregister fails (which invalidates p)
-               LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP", info->request->sd, p->srs.RR_SRV.resrec.name.c, mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port));
+               // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
+               LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP", info->request->sd, p->srs.RR_SRV.resrec.name->c, mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port));
                if (mDNS_DeregisterService(gmDNS, &p->srs)) free_service_instance(p);
                }
        info->request->service_registration = NULL; // clear pointer from request back to info
        freeL("service_info", info);
        }
 
-static void handle_regrecord_request(request_state *rstate)
+static mStatus handle_regrecord_request(request_state *rstate)
     {
     AuthRecord *rr;
     registered_record_entry *re;
@@ -2497,19 +2588,15 @@ static void handle_regrecord_request(request_state *rstate)
         LogMsg("ERROR: handle_regrecord_request - transfer state != t_complete");
         abort_request(rstate);
         unlink_request(rstate);
-        return;
+        return(-1);
         }
         
     rr = read_rr_from_ipc_msg(rstate->msgdata, 1, 1);
-    if (!rr) 
-        {
-        deliver_error(rstate, mStatus_BadParamErr);
-        return;
-        }
+    if (!rr) return(mStatus_BadParamErr);
 
     // allocate registration entry, link into list
     re = mallocL("handle_regrecord_request", sizeof(registered_record_entry));
-    if (!re) goto malloc_error;
+    if (!re) FatalError("ERROR: malloc");
     re->key = rstate->hdr.reg_index;
     re->rr = rr;
     re->rstate = rstate;
@@ -2530,13 +2617,7 @@ static void handle_regrecord_request(request_state *rstate)
     
        LogOperation("%3d: DNSServiceRegisterRecord %s", rstate->sd, RRDisplayString(gmDNS, &rr->resrec));
     result = mDNS_Register(gmDNS, rr);
-    deliver_error(rstate, result); 
-    reset_connected_rstate(rstate);
-    return;
-
-malloc_error:
-    my_perror("ERROR: malloc");
-    return;
+    return(result);
     }
 
 static void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result)
@@ -2556,7 +2637,7 @@ static void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result)
                        {
                        if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
                        freeL("regrecord_callback", rr);
-                       }                       
+                       }
                return;
                }
        
@@ -2574,9 +2655,9 @@ static void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result)
        if (result)
                {
                // unlink from list, free memory
-               registered_record_entry **ptr = &re->rstate->reg_recs;                  
+               registered_record_entry **ptr = &re->rstate->reg_recs;
                while (*ptr && (*ptr) != re) ptr = &(*ptr)->next;
-               if (!*ptr) { LogMsg("regrecord_callback - record not in list!"); return; }                      
+               if (!*ptr) { LogMsg("regrecord_callback - record not in list!"); return; }
                *ptr = (*ptr)->next;
                freeL("regrecord_callback", re->rr);
                re->rr = rr = NULL;
@@ -2601,12 +2682,12 @@ static void connected_registration_termination(void *context)
         ptr = ptr->next;
         shared = fptr->rr->resrec.RecordType == kDNSRecordTypeShared;
                fptr->rr->RecordContext = NULL;
-        mDNS_Deregister(gmDNS, fptr->rr);              
+        mDNS_Deregister(gmDNS, fptr->rr);
         freeL("connected_registration_termination", fptr);
                }
        }
     
-static void handle_removerecord_request(request_state *rstate)
+static mStatus handle_removerecord_request(request_state *rstate)
     {
     mStatus err = mStatus_BadReferenceErr;
     char *ptr;
@@ -2619,9 +2700,9 @@ static void handle_removerecord_request(request_state *rstate)
        else if (!srvinfo) LogOperation("%3d: DNSServiceRemoveRecord (bad ref)", rstate->sd);
     else
                {
-               LogOperation("%3d: DNSServiceRemoveRecord(%##s, %s)", rstate->sd,
-                       (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name.c : NULL);
                service_instance *i;
+               LogOperation("%3d: DNSServiceRemoveRecord(%##s)", rstate->sd,
+                       (srvinfo->instances) ? srvinfo->instances->srs.RR_SRV.resrec.name->c : NULL);
                for (i = srvinfo->instances; i; i = i->next)
                        {
                        err = remove_extra(rstate, i);
@@ -2630,12 +2711,7 @@ static void handle_removerecord_request(request_state *rstate)
                        }
                }
        
-    reset_connected_rstate(rstate);
-    if (deliver_error(rstate, err) < 0)
-        {
-        abort_request(rstate);
-        unlink_request(rstate);
-        }
+    return(err);
     }
 
 // remove a resource record registered via DNSServiceRegisterRecord()
@@ -2650,7 +2726,7 @@ static mStatus remove_record(request_state *rstate)
        e = *ptr;
        *ptr = e->next; // unlink
        
-       LogOperation("%3d: DNSServiceRemoveRecord(%#s)", rstate->sd, e->rr->resrec.name.c);     
+       LogOperation("%3d: DNSServiceRemoveRecord(%#s)", rstate->sd, e->rr->resrec.name->c);
        shared = e->rr->resrec.RecordType == kDNSRecordTypeShared;
        e->rr->RecordContext = NULL;
        err = mDNS_Deregister(gmDNS, e->rr);
@@ -2663,7 +2739,6 @@ static mStatus remove_record(request_state *rstate)
        return err;
     }
 
-
 static mStatus remove_extra(request_state *rstate, service_instance *serv)
        {
        mStatus err = mStatus_BadReferenceErr;
@@ -2680,14 +2755,12 @@ static mStatus remove_extra(request_state *rstate, service_instance *serv)
 // domain enumeration
 static void handle_enum_request(request_state *rstate)
     {
-    DNSServiceFlags flags, add_default;
+    DNSServiceFlags flags;
     uint32_t ifi;
     mDNSInterfaceID InterfaceID;
     char *ptr = rstate->msgdata;
     domain_enum_t *def, *all;
     enum_termination_t *term;
-    reply_state *reply;  // initial default reply
-    transfer_state tr;
     mStatus err;
     int result;
     
@@ -2713,11 +2786,7 @@ static void handle_enum_request(request_state *rstate)
     def = mallocL("handle_enum_request", sizeof(domain_enum_t));
     all = mallocL("handle_enum_request", sizeof(domain_enum_t));
     term = mallocL("handle_enum_request", sizeof(enum_termination_t));
-    if (!def || !all || !term)
-       {
-        my_perror("ERROR: malloc");
-        exit(1);
-       }
+    if (!def || !all || !term) FatalError("ERROR: malloc");
 
     // enumeration requires multiple questions, so we must link all the context pointers so that
     // necessary context can be reached from the callbacks
@@ -2729,17 +2798,19 @@ static void handle_enum_request(request_state *rstate)
     rstate->termination_context = term;
     rstate->terminate = enum_termination_callback;
     def->question.QuestionContext = def;
-    def->type = (flags & kDNSServiceFlagsRegistrationDomains) ? 
+    def->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
         mDNS_DomainTypeRegistrationDefault: mDNS_DomainTypeBrowseDefault;
     all->question.QuestionContext = all;
-    all->type = (flags & kDNSServiceFlagsRegistrationDomains) ? 
+    all->type = (flags & kDNSServiceFlagsRegistrationDomains) ?
         mDNS_DomainTypeRegistration : mDNS_DomainTypeBrowse;
 
        // if the caller hasn't specified an explicit interface, we use local-only to get the system-wide list.
        if (!InterfaceID) InterfaceID = mDNSInterface_LocalOnly;
        
     // make the calls
-       LogOperation("%3d: DNSServiceEnumerateDomains(%X)", rstate->sd, flags);
+       LogOperation("%3d: DNSServiceEnumerateDomains(%X=%s)", rstate->sd, flags,
+               (flags & kDNSServiceFlagsBrowseDomains      ) ? "kDNSServiceFlagsBrowseDomains" :
+               (flags & kDNSServiceFlagsRegistrationDomains) ? "kDNSServiceFlagsRegistrationDomains" : "<<Unknown>>");
     err = mDNS_GetDomains(gmDNS, &all->question, all->type, NULL, InterfaceID, enum_result_callback, all);
     if (err == mStatus_NoError)
         err = mDNS_GetDomains(gmDNS, &def->question, def->type, NULL, InterfaceID, enum_result_callback, def);
@@ -2751,21 +2822,6 @@ static void handle_enum_request(request_state *rstate)
         unlink_request(rstate);
         return;
         }
-
-    // provide local. as the first domain automatically
-    add_default = kDNSServiceFlagsDefault | kDNSServiceFlagsAdd;
-    reply = format_enumeration_reply(rstate, "local.", add_default, ifi, 0);
-    tr = send_msg(reply);
-    if (tr == t_error || tr == t_terminated) 
-        {
-        freeL("handle_enum_request", def);
-        freeL("handle_enum_request", all);
-        abort_request(rstate);
-        unlink_request(rstate);
-        return;
-        }
-    if (tr == t_complete) freeL("handle_enum_request", reply);
-    if (tr == t_morecoming) append_reply(rstate, reply); // couldn't send whole reply because client is blocked - link into list
     }
 
 static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
@@ -2812,7 +2868,7 @@ static reply_state *format_enumeration_reply(request_state *rstate, const char *
   
     reply = create_reply(enumeration_reply, len, rstate);
     reply->rhdr->flags = dnssd_htonl(flags);
-    reply->rhdr->ifi = dnssd_htonl(ifi); 
+    reply->rhdr->ifi = dnssd_htonl(ifi);
     reply->rhdr->error = dnssd_htonl(err);
     data = reply->sdata;
     put_string(domain, &data);
@@ -2845,7 +2901,6 @@ static void handle_reconfirm_request(request_state *rstate)
     freeL("handle_reconfirm_request", rr);
     }
 
-
 // setup rstate to accept new reg/dereg requests
 static void reset_connected_rstate(request_state *rstate)
     {
@@ -2857,8 +2912,6 @@ static void reset_connected_rstate(request_state *rstate)
     rstate->bufsize = 0;
     }
 
-
-
 // returns a resource record (allocated w/ malloc) containing the data found in an IPC message
 // data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
 // (ttl only extracted/set if ttl argument is non-zero).  returns NULL for a bad-parameter error
@@ -2886,7 +2939,7 @@ static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_f
         LogMsg("ERROR: read_rr_from_ipc_msg - get_string");
         return NULL;
         }
-    type = get_short(&msgbuf);    
+    type = get_short(&msgbuf);
     class = get_short(&msgbuf);
     rdlen = get_short(&msgbuf);
 
@@ -2894,17 +2947,13 @@ static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_f
     else storage_size = sizeof(RDataBody);
     
     rr = mallocL("read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
-    if (!rr)   
-        { 
-        my_perror("ERROR: malloc");  
-        exit(1);
-        }
+    if (!rr) FatalError("ERROR: malloc");
     bzero(rr, sizeof(AuthRecord));  // ok if oversized rdata not zero'd
     
     mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex),
                type, 0, (flags & kDNSServiceFlagsShared) ? kDNSRecordTypeShared : kDNSRecordTypeUnique, mDNSNULL, mDNSNULL);
     
-    if (!MakeDomainNameFromDNSNameString(&rr->resrec.name, name))
+    if (!MakeDomainNameFromDNSNameString(rr->resrec.name, name))
        {
         LogMsg("ERROR: bad name: %s", name);
         freeL("read_rr_from_ipc_msg", rr);
@@ -2916,14 +2965,13 @@ static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_f
     rr->resrec.rdata->MaxRDLength = rdlen;
     rdata = get_rdata(&msgbuf, rdlen);
     memcpy(rr->resrec.rdata->u.data, rdata, rdlen);
-    if (GetTTL)        
+    if (GetTTL)
        {
         rr->resrec.rroriginalttl = get_long(&msgbuf);
        }
     return rr;
     }
 
-
 // generate a response message for a browse result, service registration result, or any other call with the
 // identical callback signature.  on successful completion rep is set to point to a malloc'd reply_state struct,
 // and mStatus_NoError is returned.  otherwise the appropriate error is returned.
@@ -2969,7 +3017,6 @@ static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, requ
     return mStatus_NoError;
     }
 
-
 static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
     {
     domainlabel n;
@@ -2982,7 +3029,6 @@ static int build_domainname_from_strings(domainname *srv, char *name, char *regt
     return 0;
     }
 
-
 // append a reply to the list in a request object
 static void append_reply(request_state *req, reply_state *rep)
     {
@@ -2998,7 +3044,6 @@ static void append_reply(request_state *req, reply_state *rep)
     rep->next = NULL;
     }
 
-
 // read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
 // returns the current state of the request (morecoming, error, complete, terminated.)
 // if there is no data on the socket, the socket will be closed and t_terminated will be returned
@@ -3006,7 +3051,7 @@ static int read_msg(request_state *rs)
     {
     uint32_t nleft;
     int nread;
-    char buf[4];   // dummy for death notification 
+    char buf[4];   // dummy for death notification
     
     if (rs->ts == t_terminated || rs->ts == t_error)
         {
@@ -3099,13 +3144,12 @@ static int read_msg(request_state *rs)
     return rs->ts;
 
 rerror:
-    if (dnssd_errno() == dnssd_EWOULDBLOCK || dnssd_errno() == dnssd_EINTR) return t_morecoming;       
+    if (dnssd_errno() == dnssd_EWOULDBLOCK || dnssd_errno() == dnssd_EINTR) return t_morecoming;
     my_perror("ERROR: read_msg");
     rs->ts = t_error;
     return t_error;
     }
 
-
 static int send_msg(reply_state *rs)
     {
     ssize_t nwriten;
@@ -3134,10 +3178,10 @@ static int send_msg(reply_state *rs)
 #if !defined(PLATFORM_NO_EPIPE)
             if (dnssd_errno() == EPIPE)
                {
-                LogMsg("broken pipe - cleanup should be handled by run-loop read wakeup");
+                LogMsg("%3d: broken pipe - cleanup will be handled by run-loop read wakeup", rs->sd);
                 rs->ts = t_terminated;
                 rs->request->ts = t_terminated;
-                return t_terminated;  
+                return t_terminated;
                }
             else
 #endif
@@ -3158,8 +3202,6 @@ static int send_msg(reply_state *rs)
     return rs->ts;
     }
 
-
-
 static reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request)
 {
     reply_state *reply;
@@ -3174,22 +3216,14 @@ static reply_state *create_reply(reply_op_t op, size_t datalen, request_state *r
     
     totallen = (int) (datalen + sizeof(ipc_msg_hdr));
     reply = mallocL("create_reply", sizeof(reply_state));
-    if (!reply) 
-        {
-        my_perror("ERROR: malloc");
-        exit(1);
-        }
+    if (!reply) FatalError("ERROR: malloc");
     bzero(reply, sizeof(reply_state));
     reply->ts = t_morecoming;
     reply->sd = request->sd;
     reply->request = request;
     reply->len = totallen;
     reply->msgbuf = mallocL("create_reply", totallen);
-    if (!reply->msgbuf)
-        {
-        my_perror("ERROR: malloc");
-        exit(1);
-        }
+    if (!reply->msgbuf) FatalError("ERROR: malloc");
     bzero(reply->msgbuf, totallen);
     reply->mhdr = (ipc_msg_hdr *)reply->msgbuf;
     reply->rhdr = (reply_hdr *)(reply->msgbuf + sizeof(ipc_msg_hdr));
@@ -3200,70 +3234,62 @@ static reply_state *create_reply(reply_op_t op, size_t datalen, request_state *r
     return reply;
     }
 
-
 static int deliver_error(request_state *rstate, mStatus err)
-    {
-    int nwritten = -1;
-    undelivered_error_t *undeliv;
-    
-    err = dnssd_htonl(err);
-    nwritten = send(rstate->errfd, &err, sizeof(mStatus), 0);
-    if (nwritten < (int)sizeof(mStatus))
-        {
-        if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)   
-            nwritten = 0;
-        if (nwritten < 0)
-            {
-            my_perror("ERROR: send - unable to deliver error to client");
-            goto error;
-            }
-        //client blocked - store result and come backr
-        undeliv = mallocL("deliver_error", sizeof(undelivered_error_t));
-        if (!undeliv)
-            {
-            my_perror("ERROR: malloc");
-            exit(1);
-            }
-        undeliv->err = err;
-        undeliv->nwritten = nwritten;
-        undeliv->sd = rstate->errfd;
-        rstate->u_err = undeliv;
-        return 0;
-    }
-    return 0;
-    
-error:
-    return -1;
-    
-    }
-           
+       {
+       int nwritten = -1;
+       undelivered_error_t *undeliv;
+       
+       err = dnssd_htonl(err);
+       nwritten = send(rstate->sd, &err, sizeof(mStatus), 0);
+       if (nwritten < (int)sizeof(mStatus))
+               {
+               if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
+                       nwritten = 0;
+               if (nwritten < 0)
+                       {
+                       my_perror("ERROR: send - unable to deliver error to client");
+                       return(-1);
+                       }
+               else
+                       {
+                       //client blocked - store result and come backr
+                       undeliv = mallocL("deliver_error", sizeof(undelivered_error_t));
+                       if (!undeliv) FatalError("ERROR: malloc");
+                       undeliv->err      = err;
+                       undeliv->nwritten = nwritten;
+                       undeliv->sd       = rstate->sd;
+                       rstate->u_err     = undeliv;
+                       return 0;
+                       }
+               }
+       return 0;
+       }
 
 // returns 0 on success, -1 if send is incomplete, or on terminal failure (request is aborted)
 static transfer_state send_undelivered_error(request_state *rs)
-    {
-    int nwritten;
-    
-    nwritten = send(rs->u_err->sd, (char *)(&rs->u_err->err) + rs->u_err->nwritten, sizeof(mStatus) - rs->u_err->nwritten, 0);
-    if (nwritten < 0)
-        {
-        if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
-            nwritten = 0;
-        else
-            {
-            my_perror("ERROR: send - unable to deliver error to client\n");
-            return t_error;
-            }
-        }
-    if (nwritten + rs->u_err->nwritten == sizeof(mStatus))
-        {
-        freeL("send_undelivered_error", rs->u_err);
-        rs->u_err = NULL;
-        return t_complete;
-        }
-    rs->u_err->nwritten += nwritten;
-    return t_morecoming;
-    }
-
+       {
+       int nwritten;
+       
+       nwritten = send(rs->u_err->sd, (char *)(&rs->u_err->err) + rs->u_err->nwritten, sizeof(mStatus) - rs->u_err->nwritten, 0);
+       if (nwritten < 0)
+               {
+               if (dnssd_errno() == dnssd_EINTR || dnssd_errno() == dnssd_EWOULDBLOCK)
+                       nwritten = 0;
+               else
+                       {
+                       my_perror("ERROR: send - unable to deliver error to client\n");
+                       return t_error;
+                       }
+               }
+       if ((unsigned int)(nwritten + rs->u_err->nwritten) >= sizeof(mStatus))
+               {
+               freeL("send_undelivered_error", rs->u_err);
+               rs->u_err = NULL;
+               return t_complete;
+               }
+       rs->u_err->nwritten += nwritten;
+       return t_morecoming;
+       }
 
 // send bogus data along with an error code to the app callback
 // returns 0 on success (linking reply into list of not fully delivered),
@@ -3289,7 +3315,6 @@ static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
     return 0;
     }
 
-
 static void abort_request(request_state *rs)
     {
     reply_state *rep, *ptr;
@@ -3297,10 +3322,8 @@ static void abort_request(request_state *rs)
     if (rs->terminate) rs->terminate(rs->termination_context);  // terminate field may not be set yet
     if (rs->msgbuf) freeL("abort_request", rs->msgbuf);
        LogOperation("%3d: Removing FD", rs->sd);
-    udsSupportRemoveFDFromEventLoop(rs->sd);
+    udsSupportRemoveFDFromEventLoop(rs->sd);                                   // Note: This also closes file descriptor rs->sd for us
     rs->sd = dnssd_InvalidSocket;
-    if (rs->errfd != rs->sd && rs->errfd != dnssd_InvalidSocket) dnssd_close(rs->errfd);
-    rs->errfd = dnssd_InvalidSocket;
 
     // free pending replies
     rep = rs->replies;
@@ -3319,7 +3342,6 @@ static void abort_request(request_state *rs)
         }
     }
 
-
 static void unlink_request(request_state *rs)
     {
     request_state *ptr;
@@ -3338,8 +3360,6 @@ static void unlink_request(request_state *rs)
             return;
         }
     }
-    
-
 
 //hack to search-replace perror's to LogMsg's
 static void my_perror(char *errmsg)
@@ -3360,7 +3380,7 @@ static int validate_message(request_state *rstate)
         case resolve_request: min_size =       sizeof(DNSServiceFlags) +       // flags
                                                sizeof(uint32_t) +              // interface
                                                (3 * sizeof(char));             // name, regtype, domain
-                                               break;  
+                                               break;
         case query_request: min_size =                 sizeof(DNSServiceFlags) +       // flags
                                                sizeof(uint32_t) +              // interface
                                                sizeof(char) +                  // fullname
@@ -3373,8 +3393,8 @@ static int validate_message(request_state *rstate)
         case reg_service_request: min_size =   sizeof(DNSServiceFlags) +       // flags
                                                sizeof(uint32_t) +              // interface
                                                (4 * sizeof(char)) +            // name, type, domain, host
-                                               (2 * sizeof(uint16_t));         // port, textlen        
-                                               break;  
+                                               (2 * sizeof(uint16_t));         // port, textlen
+                                               break;
         case enumeration_request: min_size =   sizeof(DNSServiceFlags) +       // flags
                                                sizeof(uint32_t);               // interface
                                                break;
@@ -3400,17 +3420,16 @@ static int validate_message(request_state *rstate)
                                                (3 * sizeof(uint16_t));         // type, class, rdlen
                                    break;
                case setdomain_request: min_size = sizeof(DNSServiceFlags) + sizeof(char);  // flags + domain
-                       break; 
+                       break;
                default:
-            LogMsg("ERROR: validate_message - unsupported request type: %d", rstate->hdr.op);      
+            LogMsg("ERROR: validate_message - unsupported request type: %d", rstate->hdr.op);
            return -1;
-       }    
+       }
     
        return (rstate->data_bytes >= min_size ? 0 : -1);
     
     }
 
-
 static uint32_t dnssd_htonl(uint32_t l)
        {
        uint32_t        ret;
@@ -3423,7 +3442,6 @@ static uint32_t dnssd_htonl(uint32_t l)
        return ret;
        }
 
-
 #if defined(_WIN32)
 
 static char * win32_strerror(int inErrorCode)
@@ -3433,9 +3451,9 @@ static char * win32_strerror(int inErrorCode)
 
        memset(buffer, 0, sizeof(buffer));
 
-       n = FormatMessageA( 
-                       FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 
-                       NULL, 
+       n = FormatMessageA(
+                       FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+                       NULL,
                        (DWORD) inErrorCode,
                        MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
                        buffer,
index 0b9dfab9a372cb1ad3e43baff20a43a83c08ebab..55688b75b35dae4021ce784790dced48659298de 100644 (file)
@@ -29,6 +29,9 @@
     Change History (most recent first):
 
 $Log: uds_daemon.h,v $
+Revision 1.14  2005/01/27 17:48:39  cheshire
+Added comment about CFSocketInvalidate closing the underlying socket
+
 Revision 1.13  2004/12/10 05:27:26  cheshire
 <rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
 
@@ -101,7 +104,7 @@ extern void udsserver_default_browse_domain_changed(const domainname *d, mDNSBoo
 typedef        void (*udsEventCallback)(void *context);
 
 extern mStatus udsSupportAddFDToEventLoop(dnssd_sock_t fd, udsEventCallback callback, void *context);
-extern mStatus udsSupportRemoveFDFromEventLoop(dnssd_sock_t fd);
+extern mStatus udsSupportRemoveFDFromEventLoop(dnssd_sock_t fd); // Note: This also CLOSES the file descriptor as well
 
 // RecordUpdatedNiceLabel() can be a no-op on platforms that don't care about updating the machine's
 // global default service name (was OS X calls the "Computer Name") in response to name conflicts.
index c93e9cbc8127feaa919ddb47515e4571da054f77..dc116b574cfec10b553e26261f53ea26e4dcd1e0 100644 (file)
        Change History (most recent first):
 
 $Log: mDNSVxWorks.c,v $
+Revision 1.27  2004/12/17 23:37:49  cheshire
+<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
+(and other repetitive configuration changes)
+
 Revision 1.26  2004/10/28 02:00:35  cheshire
 <rdar://problem/3841770> Call pipeDevDelete when disposing of commandPipe
 
@@ -1100,7 +1104,7 @@ mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inA
        item->hostSet.Advertise               = inMDNS->AdvertiseLocalAddresses;
        item->hostSet.McastTxRx               = mDNStrue;
 
-       err = mDNS_RegisterInterface( inMDNS, &item->hostSet );
+       err = mDNS_RegisterInterface( inMDNS, &item->hostSet, 0 );
        require_noerr( err, exit );
        item->hostRegistered = mDNStrue;
        
index 565286f795040c577c8596c0f305628d0fa62f17..312d7b6e58c17cd592987eb2c23726a8eaf74812 100755 (executable)
@@ -40,6 +40,9 @@
     Change History (most recent first):
 
 $Log: dnssd_NET.h,v $
+Revision 1.7  2004/12/16 19:56:12  cheshire
+Update comments
+
 Revision 1.6  2004/09/20 22:47:06  cheshire
 Add cautionary comment
 
@@ -115,7 +118,7 @@ namespace Apple
                                * by renaming the service.  NoAutoRename overrides this behavior - with this
                                * flag set, name conflicts will result in a callback.  The NoAutorename flag
                                * is only valid if a name is explicitly specified when registering a service
-                               * (ie the default name is not used.)
+                               * (i.e. the default name is not used.)
                                */
 
                        Shared                          =       16,
index f3c3dd428881de38cdc59d74789f52f983dd0130..c6340ee300ff14f3ddd1d92a9edec2e061cb316e 100755 (executable)
@@ -84,7 +84,7 @@ BEGIN
             VALUE "FileDescription", "dnssd.NET Dynamic Link Library"
             VALUE "FileVersion", MASTER_PROD_VERS_STR
             VALUE "InternalName", "dnssd.NET"
-            VALUE "LegalCopyright", "Copyright (C) 2004"
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
             VALUE "OriginalFilename", "dnssd.NET.dll"
             VALUE "ProductName", MASTER_PROD_NAME
             VALUE "ProductVersion", MASTER_PROD_VERS_STR
index f2145d931672c769de3ad6069752ca67f96a4e94..719de8dfa19c33b2f953133493fdf9fe2d24dc06 100755 (executable)
@@ -82,7 +82,8 @@
                                AdditionalDependencies="../DLL/Release/dnssd.lib mscoree.lib ws2_32.lib msvcrt.lib"\r
                                OutputFile="$(OutDir)\dnssd.NET.dll"\r
                                LinkIncremental="1"\r
-                               GenerateDebugInformation="TRUE"/>\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"/>\r
                        <Tool\r
                                Name="VCMIDLTool"/>\r
                        <Tool\r
index 70b4839eeb4e74bd05c8bae6c1679cd90e902bf9..7f8506363da97f88c1fc1c3af99199e937f928ff 100644 (file)
@@ -73,7 +73,7 @@ BEGIN
             VALUE "FileDescription", "dnssd Dynamic Link Library"
             VALUE "FileVersion", MASTER_PROD_VERS_STR
             VALUE "InternalName", "dnssd"
-            VALUE "LegalCopyright", "Copyright (C) 2004"
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
             VALUE "OriginalFilename", "dnssd.dll"
             VALUE "ProductName", MASTER_PROD_NAME
             VALUE "ProductVersion", MASTER_PROD_VERS_STR
index 01e412b891e95a7263679903975bc7806fa0d1fc..c8aac787b38901be8c643a04b91c0a45e9f878d5 100644 (file)
-<?xml version="1.0" encoding = "Windows-1252"?>
-<VisualStudioProject
-       ProjectType="Visual C++"
-       Version="7.00"
-       Name="DLL"
-       ProjectGUID="{AB581101-18F0-46F6-B56A-83A6B1EA657E}"
-       Keyword="Win32Proj">
-       <Platforms>
-               <Platform
-                       Name="Win32"/>
-       </Platforms>
-       <Configurations>
-               <Configuration
-                       Name="Debug|Win32"
-                       OutputDirectory=".\Debug"
-                       IntermediateDirectory=".\Debug"
-                       ConfigurationType="2"
-                       CharacterSet="2">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="0"
-                               AdditionalIncludeDirectories="../../mDNSCore;../../mDNSShared;../"
-                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;DEBUG=1;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK"
-                               StringPooling="TRUE"
-                               MinimalRebuild="TRUE"
-                               ExceptionHandling="FALSE"
-                               BasicRuntimeChecks="3"
-                               SmallerTypeCheck="TRUE"
-                               RuntimeLibrary="1"
-                               BufferSecurityCheck="TRUE"
-                               UsePrecompiledHeader="0"
-                               WarningLevel="4"
-                               Detect64BitPortabilityProblems="TRUE"
-                               DebugInformationFormat="4"
-                               CallingConvention="2"
-                               CompileAs="0"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalDependencies="ws2_32.lib iphlpapi.lib"
-                               OutputFile="$(OutDir)/dnssd.dll"
-                               LinkIncremental="2"
-                               ModuleDefinitionFile="dnssd.def"
-                               GenerateDebugInformation="TRUE"
-                               ProgramDatabaseFile="$(OutDir)/dnssd.pdb"
-                               SubSystem="2"
-                               ImportLibrary="$(OutDir)/dnssd.lib"
-                               TargetMachine="1"/>
-                       <Tool
-                               Name="VCMIDLTool"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               AdditionalIncludeDirectories="../"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-               </Configuration>
-               <Configuration
-                       Name="Release|Win32"
-                       OutputDirectory="Release"
-                       IntermediateDirectory="Release"
-                       ConfigurationType="2"
-                       CharacterSet="2">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               AdditionalIncludeDirectories="../../mDNSCore;../../mDNSShared;../"
-                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK"
-                               RuntimeLibrary="0"
-                               UsePrecompiledHeader="0"
-                               WarningLevel="4"
-                               Detect64BitPortabilityProblems="TRUE"
-                               DebugInformationFormat="3"
-                               CallingConvention="2"
-                               CompileAs="0"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalDependencies="ws2_32.lib iphlpapi.lib"
-                               OutputFile="$(OutDir)/dnssd.dll"
-                               LinkIncremental="1"
-                               ModuleDefinitionFile="dnssd.def"
-                               GenerateDebugInformation="TRUE"
-                               SubSystem="2"
-                               OptimizeReferences="2"
-                               EnableCOMDATFolding="2"
-                               ImportLibrary="$(OutDir)/dnssd.lib"
-                               TargetMachine="1"/>
-                       <Tool
-                               Name="VCMIDLTool"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               AdditionalIncludeDirectories="../"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-               </Configuration>
-       </Configurations>
-       <Files>
-               <Filter
-                       Name="Source Files"
-                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
-                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
-                       <File
-                               RelativePath="..\DebugServices.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSShared\GenLinkedList.c">
-                       </File>
-                       <File
-                               RelativePath=".\dllmain.c">
-                       </File>
-                       <File
-                               RelativePath=".\dnssd.def">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSShared\dnssd_clientlib.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSShared\dnssd_clientstub.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSShared\dnssd_ipc.c">
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Header Files"
-                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
-                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
-                       <File
-                               RelativePath="..\CommonServices.h">
-                       </File>
-                       <File
-                               RelativePath="..\DebugServices.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSShared\GenLinkedList.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSShared\dns_sd.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSShared\dnssd_ipc.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSShared\dnssd_sock.h">
-                       </File>
-                       <File
-                               RelativePath=".\resource.h">
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Resource Files"
-                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
-                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
-                       <File
-                               RelativePath=".\dll.rc">
-                       </File>
-               </Filter>
-       </Files>
-       <Globals>
-       </Globals>
-</VisualStudioProject>
+<?xml version="1.0" encoding = "Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.00"\r
+       Name="DLL"\r
+       ProjectGUID="{AB581101-18F0-46F6-B56A-83A6B1EA657E}"\r
+       Keyword="Win32Proj">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory=".\Debug\"\r
+                       IntermediateDirectory=".\Debug"\r
+                       ConfigurationType="2"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="../../mDNSCore;../../mDNSShared;../"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;DEBUG=1;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK"\r
+                               StringPooling="TRUE"\r
+                               MinimalRebuild="TRUE"\r
+                               ExceptionHandling="FALSE"\r
+                               BasicRuntimeChecks="3"\r
+                               SmallerTypeCheck="TRUE"\r
+                               RuntimeLibrary="1"\r
+                               BufferSecurityCheck="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="4"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="4"\r
+                               CallingConvention="2"\r
+                               CompileAs="0"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
+                               OutputFile="$(OutDir)/dnssd.dll"\r
+                               LinkIncremental="2"\r
+                               ModuleDefinitionFile="dnssd.def"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(OutDir)/dnssd.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(IntDir)\dnssd.lib"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               AdditionalIncludeDirectories="../"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory=".\Release\Root\Program Files\bin"\r
+                       IntermediateDirectory=".\Release"\r
+                       ConfigurationType="2"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="../../mDNSCore;../../mDNSShared;../"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="4"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="3"\r
+                               CallingConvention="2"\r
+                               CompileAs="0"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
+                               OutputFile="$(OutDir)/dnssd.dll"\r
+                               LinkIncremental="1"\r
+                               ModuleDefinitionFile="dnssd.def"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               ImportLibrary=".\Release\dnssd.lib"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               AdditionalIncludeDirectories="../"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">\r
+                       <File\r
+                               RelativePath="..\DebugServices.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSShared\GenLinkedList.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\dllmain.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\dnssd.def">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSShared\dnssd_clientlib.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSShared\dnssd_clientstub.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSShared\dnssd_ipc.c">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">\r
+                       <File\r
+                               RelativePath="..\CommonServices.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\DebugServices.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSShared\GenLinkedList.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSShared\dns_sd.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSShared\dnssd_ipc.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSShared\dnssd_sock.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\resource.h">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">\r
+                       <File\r
+                               RelativePath=".\dll.rc">\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
index a8aedb3b8cf98e3f7e6e16c5db3e5380888c3131..c32ebb01d3acdd25b1637c379ae162db01017619 100755 (executable)
@@ -23,6 +23,9 @@
     Change History (most recent first):
     
 $Log: DNSServices.c,v $
+Revision 1.32  2004/12/16 20:13:02  cheshire
+<rdar://problem/3324626> Cache memory management improvements
+
 Revision 1.31  2004/10/19 21:33:23  cheshire
 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
@@ -1278,7 +1281,7 @@ DNSStatus
        objectPtr->callback                     = inCallBack;
        objectPtr->callbackContext              = inCallBackContext;
        objectPtr->owner                                = inOwner;
-       AssignDomainName( objectPtr->info.name, fullName );
+       AssignDomainName( &objectPtr->info.name, &fullName );
        objectPtr->info.InterfaceID     = mDNSInterface_Any;
        
        // Save off the resolve info so the callback can get it.
@@ -2430,13 +2433,13 @@ DNSStatus
        mDNS_SetupResourceRecord( &object->RR_PTR, mDNSNULL, interfaceID, kDNSType_PTR, 60, kDNSRecordTypeKnownUnique, 
                                                          DNSHostRegistrationPrivateCallBack, object );
        
-       AssignDomainName( object->RR_A.resrec.name, name );
+       AssignDomainName( &object->RR_A.resrec.name, &name );
        
        mDNS_snprintf( buffer, sizeof( buffer ), "%d.%d.%d.%d.in-addr.arpa.", ip.b[ 3 ], ip.b[ 2 ], ip.b[ 1 ], ip.b[ 0 ] );
        MakeDomainNameFromDNSNameString( &object->RR_PTR.resrec.name, buffer );
        
        object->RR_A.resrec.rdata->u.ipv4 = ip;
-       AssignDomainName( object->RR_PTR.resrec.rdata->u.name, object->RR_A.resrec.name );
+       AssignDomainName( &object->RR_PTR.resrec.rdata->u.name, &object->RR_A.resrec.name );
        
        // Add the object to the list.
        
@@ -2607,7 +2610,7 @@ mDNSlocal void    DNSHostRegistrationPrivateCallBack( mDNS * const inMDNS, AuthReco
                        name.c[ 0 ] = 0;
                        AppendDomainLabel( &name, &object->name );
                        AppendDomainLabel( &name, &object->domain );
-                       AssignDomainName( object->RR_PTR.resrec.name, name );
+                       AssignDomainName( &object->RR_PTR.resrec.name, &name );
                        
                        err = mDNS_Register( gMDNSPtr, &object->RR_A );
                        check_noerr( err );
index d78741093f62cf3aa5d62518ca7976a23f7801ce..1b57da4e7b2662569f457599ac9598b6fc2285bc 100644 (file)
@@ -20,6 +20,9 @@
 # @APPLE_LICENSE_HEADER_END@
 #
 # $Log: makefile,v $
+# Revision 1.4  2004/12/16 22:38:00  shersche
+# Compile DNSSDException.java first to avoid build errors, copy output to appropriate "buildroot" folder
+#
 # Revision 1.3  2004/11/23 08:13:07  shersche
 # Link to the iphlpapi.lib for GetAdaptersInfo
 #
@@ -88,7 +91,7 @@ JAVACFLAGS = $(CFLAGS) $(JAVACFLAGS_OS)
 
 #############################################################################
 
-all: setup Java
+all: setup Java postbuild
 
 # 'setup' sets up the build directory structure the way we want
 setup:
@@ -97,6 +100,20 @@ setup:
        @if not exist $(OBJDIR)         mkdir $(OBJDIR)
        @if not exist $(BUILDDIR)       mkdir $(BUILDDIR)
 
+!if DEFINED(DNSSD_BUILD_ROOT)
+!if $(DEBUG) == 1
+postbuild:
+       copy $(BUILDDIR)\dns_sd.jar $(DNSSD_BUILD_ROOT)\Debug\Root\"Program Files"\bin
+       copy $(BUILDDIR)\jdns_sd.dll $(DNSSD_BUILD_ROOT)\Debug\Root\"Program Files"\bin
+!else
+postbuild:
+       copy $(BUILDDIR)\dns_sd.jar $(DNSSD_BUILD_ROOT)\Release\Root\"Program Files"\bin
+       copy $(BUILDDIR)\jdns_sd.dll $(DNSSD_BUILD_ROOT)\Release\Root\"Program Files"\bin
+!endif
+!else
+postbuild:
+!endif
+
 # clean removes targets and objects
 clean:
        @if exist $(OBJDIR)             $(RMDIR) $(OBJDIR)
@@ -106,13 +123,13 @@ clean:
 
 # The following targets build Java wrappers for the dns-sd.h API.
 
-Java: setup $(BUILDDIR)\dns_sd.jar $(BUILDDIR)\jdns_sd.dll
+Java: setup $(BUILDDIR)\dns_sd.jar $(BUILDDIR)\jdns_sd.dll postbuild
        @echo "Java wrappers done"
 
 JAVASRC        = $(SHAREDDIR)\Java
 JARCONTENTS =  $(OBJDIR)\com\apple\dnssd\DNSSDService.class \
-                               $(OBJDIR)\com\apple\dnssd\DNSRecord.class \
                                $(OBJDIR)\com\apple\dnssd\DNSSDException.class \
+                               $(OBJDIR)\com\apple\dnssd\DNSRecord.class \
                                $(OBJDIR)\com\apple\dnssd\TXTRecord.class \
                                $(OBJDIR)\com\apple\dnssd\DNSSDRegistration.class \
                                $(OBJDIR)\com\apple\dnssd\BaseListener.class \
index b75f621303641c8155c174f99e9a9c8b81ec04e1..9f39249b03bb7ecd1a6437ddf88d4f5568471f71 100644 (file)
@@ -8,6 +8,7 @@
 // Generated from the TEXTINCLUDE 2 resource.\r
 //\r
 #include "afxres.h"\r
+#include "WinVersRes.h"\r
 \r
 /////////////////////////////////////////////////////////////////////////////\r
 #undef APSTUDIO_READONLY_SYMBOLS\r
@@ -53,8 +54,8 @@ END
 //\r
 \r
 VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION 1,0,0,5\r
- PRODUCTVERSION 1,0,0,5\r
+ FILEVERSION MASTER_PROD_VERS\r
+ PRODUCTVERSION MASTER_PROD_VERS\r
  FILEFLAGSMASK 0x17L\r
 #ifdef _DEBUG\r
  FILEFLAGS 0x1L\r
@@ -71,12 +72,12 @@ BEGIN
         BEGIN\r
             VALUE "CompanyName", "Apple Computer, Inc."\r
             VALUE "FileDescription", "NSPTool Application"\r
-            VALUE "FileVersion", "1, 0, 0, 5"\r
+            VALUE "FileVersion", MASTER_PROD_VERS_STR\r
             VALUE "InternalName", "NSPTool"\r
-            VALUE "LegalCopyright", "Copyright (C) 2004"\r
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
             VALUE "OriginalFilename", "NSPTool.exe"\r
-            VALUE "ProductName", " NSPTool Application"\r
-            VALUE "ProductVersion", "1, 0, 0, 5"\r
+            VALUE "ProductName", MASTER_PROD_NAME\r
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
         END\r
     END\r
     BLOCK "VarFileInfo"\r
index 89ca1fba63d958ceb753a31d86f3bc2b8bda0fd8..7b3fc0efcde4e0c58e5edfb8c474ae90f2a19e59 100644 (file)
@@ -54,7 +54,8 @@
                        <Tool\r
                                Name="VCPreLinkEventTool"/>\r
                        <Tool\r
-                               Name="VCResourceCompilerTool"/>\r
+                               Name="VCResourceCompilerTool"\r
+                               AdditionalIncludeDirectories="..\"/>\r
                        <Tool\r
                                Name="VCWebServiceProxyGeneratorTool"/>\r
                        <Tool\r
@@ -62,8 +63,8 @@
                </Configuration>\r
                <Configuration\r
                        Name="Release|Win32"\r
-                       OutputDirectory="Release"\r
-                       IntermediateDirectory="Release"\r
+                       OutputDirectory=".\Release\Root\InstallTools"\r
+                       IntermediateDirectory=".\Release"\r
                        ConfigurationType="1"\r
                        CharacterSet="2">\r
                        <Tool\r
@@ -83,6 +84,7 @@
                                OutputFile="$(OutDir)/NSPTool.exe"\r
                                LinkIncremental="1"\r
                                GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
                                SubSystem="1"\r
                                OptimizeReferences="2"\r
                                EnableCOMDATFolding="2"\r
@@ -96,7 +98,8 @@
                        <Tool\r
                                Name="VCPreLinkEventTool"/>\r
                        <Tool\r
-                               Name="VCResourceCompilerTool"/>\r
+                               Name="VCResourceCompilerTool"\r
+                               AdditionalIncludeDirectories="..\"/>\r
                        <Tool\r
                                Name="VCWebServiceProxyGeneratorTool"/>\r
                        <Tool\r
index ecc5307b7538d35284f10e6154594d48a4974ba8..bfbf6a4a628b271e64ca16fac9be09de9aaa1e2e 100644 (file)
     Change History (most recent first):
     
 $Log: Service.c,v $
+Revision 1.24  2005/01/27 20:02:43  cheshire
+udsSupportRemoveFDFromEventLoop() needs to close the SocketRef as well
+
+Revision 1.23  2005/01/25 08:14:15  shersche
+Change CacheRecord to CacheEntity
+
 Revision 1.22  2004/12/10 13:18:40  cheshire
 Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
 
@@ -155,7 +161,7 @@ mDNSResponder Windows Service. Provides global Rendezvous support with an IPC in
 #define        kDNSServiceCacheEntryCountDefault       512
 
 #define RR_CACHE_SIZE 500
-static CacheRecord gRRCache[RR_CACHE_SIZE];
+static CacheEntity gRRCache[RR_CACHE_SIZE];
 #if 0
 #pragma mark == Structures ==
 #endif
@@ -1451,7 +1457,7 @@ exit:
 
 
 mStatus
-udsSupportRemoveFDFromEventLoop( SocketRef fd)
+udsSupportRemoveFDFromEventLoop( SocketRef fd)         // Note: This also CLOSES the socket
 {
        Win32EventSource        *       source;
        mStatus                                 err = mStatus_NoError;
@@ -1481,6 +1487,8 @@ udsSupportRemoveFDFromEventLoop( SocketRef fd)
        // done with the list
        //
        EventSourceUnlock();
+       
+       closesocket(fd);
 
        return err;
 }
index e13561ecb7a91ae156b222a032e57ca8741edee3..8300753241f15be423e9fcd59b670d124668e598 100644 (file)
@@ -47,7 +47,7 @@ BEGIN
             VALUE "FileDescription", "mDNSResponder"
             VALUE "FileVersion", MASTER_PROD_VERS_STR
             VALUE "InternalName", "mDNSResponder"
-            VALUE "LegalCopyright", "Copyright (C) 2003-2004 Apple Computer, Inc."
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
             VALUE "OriginalFilename", "mDNSResponder.exe"
             VALUE "ProductName", MASTER_PROD_NAME
             VALUE "ProductVersion", MASTER_PROD_VERS_STR
index f147c744f9ad77768336e93930edd135bb1f0f5c..dc458fd4e013c15a6c1c16ba5a907bb07d09cb5f 100644 (file)
-<?xml version="1.0" encoding = "Windows-1252"?>
-<VisualStudioProject
-       ProjectType="Visual C++"
-       Version="7.00"
-       Name="mDNSResponder"
-       ProjectGUID="{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}"
-       Keyword="Win32Proj">
-       <Platforms>
-               <Platform
-                       Name="Win32"/>
-       </Platforms>
-       <Configurations>
-               <Configuration
-                       Name="Debug|Win32"
-                       OutputDirectory=".\Debug"
-                       IntermediateDirectory=".\Debug"
-                       ConfigurationType="1"
-                       CharacterSet="2">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="0"
-                               AdditionalIncludeDirectories=".;../;../../mDNSCore;../../mDNSShared;&quot;C:\Program Files\Microsoft Platform SDK for Windows XP SP2\Include&quot;"
-                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;DEBUG=1;MDNS_DEBUGMSGS=0;UNICAST_DISABLED;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE=&quot;&quot;&quot;&quot;"
-                               StringPooling="TRUE"
-                               MinimalRebuild="TRUE"
-                               ExceptionHandling="FALSE"
-                               BasicRuntimeChecks="3"
-                               SmallerTypeCheck="TRUE"
-                               RuntimeLibrary="1"
-                               BufferSecurityCheck="TRUE"
-                               UsePrecompiledHeader="0"
-                               WarningLevel="4"
-                               Detect64BitPortabilityProblems="TRUE"
-                               DebugInformationFormat="4"
-                               CallingConvention="2"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalDependencies="ws2_32.lib iphlpapi.lib"
-                               OutputFile="$(OutDir)/mDNSResponder.exe"
-                               LinkIncremental="2"
-                               IgnoreAllDefaultLibraries="FALSE"
-                               GenerateDebugInformation="TRUE"
-                               ProgramDatabaseFile="$(OutDir)/mDNSResponder.pdb"
-                               SubSystem="1"
-                               TargetMachine="1"/>
-                       <Tool
-                               Name="VCMIDLTool"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               AdditionalIncludeDirectories="../"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-               </Configuration>
-               <Configuration
-                       Name="Release|Win32"
-                       OutputDirectory="Release"
-                       IntermediateDirectory="Release"
-                       ConfigurationType="1"
-                       CharacterSet="2">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               AdditionalIncludeDirectories=".;../;../../mDNSCore;../../mDNSShared;&quot;C:\Program Files\Microsoft Platform SDK for Windows XP SP2\Include&quot;"
-                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;UNICAST_DISABLED;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE=&quot;&quot;&quot;&quot;"
-                               RuntimeLibrary="0"
-                               UsePrecompiledHeader="0"
-                               WarningLevel="4"
-                               Detect64BitPortabilityProblems="TRUE"
-                               DebugInformationFormat="3"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalDependencies="ws2_32.lib iphlpapi.lib"
-                               OutputFile="$(OutDir)/mDNSResponder.exe"
-                               LinkIncremental="1"
-                               GenerateDebugInformation="TRUE"
-                               SubSystem="1"
-                               OptimizeReferences="2"
-                               EnableCOMDATFolding="2"
-                               TargetMachine="1"/>
-                       <Tool
-                               Name="VCMIDLTool"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               AdditionalIncludeDirectories="../"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-               </Configuration>
-       </Configurations>
-       <Files>
-               <Filter
-                       Name="Source Files"
-                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
-                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
-                       <File
-                               RelativePath="..\..\mDNSCore\DNSCommon.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSCore\DNSDigest.c">
-                       </File>
-                       <File
-                               RelativePath="..\DebugServices.c">
-                       </File>
-                       <File
-                               RelativePath="Firewall.cpp">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSShared\GenLinkedList.c">
-                       </File>
-                       <File
-                               RelativePath=".\Service.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSShared\dnssd_ipc.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSCore\mDNS.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSShared\mDNSDebug.c">
-                       </File>
-                       <File
-                               RelativePath="..\mDNSWin32.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSCore\uDNS.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSShared\uds_daemon.c">
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Header Files"
-                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
-                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
-                       <File
-                               RelativePath="..\CommonServices.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSCore\DNSCommon.h">
-                       </File>
-                       <File
-                               RelativePath="..\DebugServices.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSShared\GenLinkedList.h">
-                       </File>
-                       <File
-                               RelativePath=".\Resource.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSShared\dnssd_ipc.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSCore\mDNSClientAPI.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSCore\mDNSDebug.h">
-                       </File>
-                       <File
-                               RelativePath="..\mDNSWin32.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSCore\uDNS.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\mDNSShared\uds_daemon.h">
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Resource Files"
-                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
-                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
-                       <File
-                               RelativePath=".\Service.rc">
-                       </File>
-               </Filter>
-       </Files>
-       <Globals>
-       </Globals>
-</VisualStudioProject>
+<?xml version="1.0" encoding = "Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.00"\r
+       Name="mDNSResponder"\r
+       ProjectGUID="{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}"\r
+       Keyword="Win32Proj">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory=".\Debug"\r
+                       IntermediateDirectory=".\Debug"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".;../;../../mDNSCore;../../mDNSShared;&quot;C:\Program Files\Microsoft Platform SDK for Windows XP SP2\Include&quot;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;DEBUG=1;MDNS_DEBUGMSGS=0;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE=&quot;&quot;&quot;&quot;"\r
+                               StringPooling="TRUE"\r
+                               MinimalRebuild="TRUE"\r
+                               ExceptionHandling="FALSE"\r
+                               BasicRuntimeChecks="3"\r
+                               SmallerTypeCheck="TRUE"\r
+                               RuntimeLibrary="1"\r
+                               BufferSecurityCheck="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="4"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="4"\r
+                               CallingConvention="2"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="ws2_32.lib iphlpapi.lib crypt32.lib"\r
+                               OutputFile="$(OutDir)/mDNSResponder.exe"\r
+                               LinkIncremental="2"\r
+                               IgnoreAllDefaultLibraries="FALSE"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(OutDir)/mDNSResponder.pdb"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               AdditionalIncludeDirectories="../"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory=".\Release\Root\Program Files\bin"\r
+                       IntermediateDirectory=".\Release"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories=".;../;../../mDNSCore;../../mDNSShared;&quot;C:\Program Files\Microsoft Platform SDK for Windows XP SP2\Include&quot;"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE=&quot;&quot;&quot;&quot;"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="4"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="3"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
+                               OutputFile="$(OutDir)/mDNSResponder.exe"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               AdditionalIncludeDirectories="../"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">\r
+                       <File\r
+                               RelativePath="..\..\mDNSCore\DNSCommon.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSCore\DNSDigest.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\DebugServices.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="Firewall.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSShared\GenLinkedList.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Service.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\dDNS.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSShared\dnssd_ipc.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSCore\mDNS.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSShared\mDNSDebug.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\mDNSWin32.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSCore\uDNS.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSShared\uds_daemon.c">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">\r
+                       <File\r
+                               RelativePath="..\CommonServices.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSCore\DNSCommon.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\DebugServices.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSShared\GenLinkedList.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Resource.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\dDNS.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSShared\dnssd_ipc.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSCore\mDNSDebug.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSCore\mDNSEmbeddedAPI.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\mDNSWin32.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSCore\uDNS.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\mDNSShared\uds_daemon.h">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">\r
+                       <File\r
+                               RelativePath=".\Service.rc">\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
index b6edb1e3cfedec33c7768fa4a80c08cd5a5311ab..30d4984b009780d20a97981d50a84bb037a23244 100644 (file)
     Change History (most recent first):
 
 $Log: WinVersRes.h,v $
+Revision 1.22  2005/01/25 17:15:52  shersche
+Bump to 1.0.0.51. Add legal copyright string.
+
+Revision 1.21  2005/01/11 07:09:32  shersche
+Bump to version 1.0.0.51
+
+Revision 1.20  2004/12/17 01:23:24  shersche
+Bump version to 1.0.0.50
+
+Revision 1.19  2004/12/16 08:09:47  shersche
+Revert version number back to 1.0.0.22
+
+Revision 1.18  2004/12/16 02:48:10  shersche
+Bump version number to 1.1.0.0
+
 Revision 1.17  2004/10/20 15:37:46  shersche
 Bump to Windows-trial-21
 
@@ -82,9 +97,12 @@ First checked in.
 #define MASTER_PROD_NAME       "Rendezvous"
 
 // Define the product version for mDNSResponder on Windows
-#define MASTER_PROD_VERS               1,0,0,21
-#define MASTER_PROD_VERS_STR   "1,0,0,21"
-#define MASTER_PROD_VERS_STR2  "1.0.0.21"
-#define MASTER_PROD_VERS_STR3 "Explorer Plugin 1.0.0.21"
+#define MASTER_PROD_VERS               1,0,0,52
+#define MASTER_PROD_VERS_STR   "1,0,0,52"
+#define MASTER_PROD_VERS_STR2  "1.0.0.52"
+#define MASTER_PROD_VERS_STR3 "Explorer Plugin 1.0.0.52"
+
+// Define the legal copyright
+#define MASTER_LEGAL_COPYRIGHT "Copyright (C) 2003-2005 Apple Computer, Inc."
 
 #endif // WINRESVERS_H
diff --git a/mDNSWindows/dDNS.c b/mDNSWindows/dDNS.c
new file mode 100755 (executable)
index 0000000..e2e2d58
--- /dev/null
@@ -0,0 +1,590 @@
+/*
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+*/
+
+#include "dDNS.h"
+#include "DNSCommon.h"
+#include <winsock2.h>
+#include <iphlpapi.h>
+#include <ws2tcpip.h>
+
+typedef struct SearchListElem
+       {
+    struct SearchListElem *next;
+    domainname domain;
+    int flag;
+    DNSQuestion BrowseQ;
+    DNSQuestion DefBrowseQ;
+    DNSQuestion LegacyBrowseQ;
+    DNSQuestion RegisterQ;
+    DNSQuestion DefRegisterQ;
+    ARListElem *AuthRecs;
+       } SearchListElem;
+// for domain enumeration and default browsing/registration
+static SearchListElem *SearchList = mDNSNULL;      // where we search for _browse domains
+static DNSQuestion LegacyBrowseDomainQ;        // our local enumeration query for _legacy._browse domains
+static DNameListElem *DefBrowseList = mDNSNULL;    // cache of answers to above query (where we search for empty string browses)
+static DNameListElem *DefRegList = mDNSNULL;       // manually generated list of domains where we register for empty string registrations
+static ARListElem *SCPrefBrowseDomains = mDNSNULL; // manually generated local-only PTR records for browse domains we get from SCPreferences
+
+static domainname dDNSRegDomain;             // Default wide-area zone for service registration
+static domainname dDNSBrowseDomain;          // Default wide-area zone for legacy ("empty string") browses
+static domainname dDNSHostname;
+
+
+mStatus dDNS_SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
+       {
+       if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
+
+       if (sa->sa_family == AF_INET)
+               {
+               struct sockaddr_in *ifa_addr = (struct sockaddr_in *)sa;
+               ip->type = mDNSAddrType_IPv4;
+               ip->ip.v4.NotAnInteger = ifa_addr->sin_addr.s_addr;
+               return(mStatus_NoError);
+               }
+
+       if (sa->sa_family == AF_INET6)
+               {
+               struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
+               ip->type = mDNSAddrType_IPv6;
+#if !defined(_WIN32)
+               if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
+#else
+               if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.u.Word[1] = 0;
+#endif                 
+               ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
+               return(mStatus_NoError);
+               }
+
+       LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
+       return(mStatus_Invalid);
+       }
+
+mDNSlocal void MarkSearchListElem(domainname *domain)
+       {
+       SearchListElem *new, *ptr;
+       
+       // if domain is in list, mark as pre-existent (0)
+       for (ptr = SearchList; ptr; ptr = ptr->next)
+               if (SameDomainName(&ptr->domain, domain))
+                       {
+                       if (ptr->flag != 1) ptr->flag = 0;  // gracefully handle duplicates - if it is already marked as add, don't bump down to preexistent
+                       break;
+                       }
+       
+       // if domain not in list, add to list, mark as add (1)
+       if (!ptr)
+               {
+               new = mallocL("MarkSearchListElem - SearchListElem", sizeof(SearchListElem));
+               if (!new) { LogMsg("ERROR: MarkSearchListElem - malloc"); return; }
+               bzero(new, sizeof(SearchListElem));
+               AssignDomainName(&new->domain, domain);
+               new->flag = 1;  // add
+               new->next = SearchList;
+               SearchList = new;
+               }
+       }
+
+//!!!KRS here is where we will give success/failure notification to the UI
+mDNSlocal void SCPrefsdDNSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+       {
+       (void)m;  // unused
+       debugf("SCPrefsdDNSCallback: result %d for registration of name %##s", result, rr->resrec.name->c);
+       dDNSPlatformSetNameStatus(rr->resrec.name, result);
+       }
+
+mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+       {
+       ARListElem *elem = rr->RecordContext;
+       
+       (void)m;  // unused
+       
+       if (result == mStatus_MemFree) freeL("FreeARElemCallback", elem);
+       }
+
+mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+       {
+       SearchListElem *slElem = question->QuestionContext;
+       ARListElem *arElem, *ptr, *prev;
+    AuthRecord *dereg;
+       const char *name;
+       mStatus err;
+       
+       if (AddRecord)
+               {
+               arElem = mallocL("FoundDomain - arElem", sizeof(ARListElem));
+               if (!arElem) { LogMsg("ERROR: malloc");  return; }
+               mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, FreeARElemCallback, arElem);
+               if      (question == &slElem->BrowseQ)       name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowse];
+               else if (question == &slElem->DefBrowseQ)    name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseDefault];
+               else if (question == &slElem->LegacyBrowseQ) name = mDNS_DomainTypeNames[mDNS_DomainTypeBrowseLegacy];
+               else if (question == &slElem->RegisterQ)     name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistration];
+               else if (question == &slElem->DefRegisterQ)  name = mDNS_DomainTypeNames[mDNS_DomainTypeRegistrationDefault];
+               else { LogMsg("FoundDomain - unknown question"); return; }
+               
+               MakeDomainNameFromDNSNameString(arElem->ar.resrec.name, name);
+               AppendDNSNameString            (arElem->ar.resrec.name, "local");
+               AssignDomainName(&arElem->ar.resrec.rdata->u.name, &answer->rdata->u.name);
+               err = mDNS_Register(m, &arElem->ar);
+               if (err)
+                       {
+                       LogMsg("ERROR: FoundDomain - mDNS_Register returned %d", err);
+                       freeL("FoundDomain - arElem", arElem);
+                       return;
+                       }
+               arElem->next = slElem->AuthRecs;
+               slElem->AuthRecs = arElem;
+               }
+       else
+               {
+               ptr = slElem->AuthRecs;
+               prev = NULL;
+               while (ptr)
+                       {
+                       if (SameDomainName(&ptr->ar.resrec.rdata->u.name, &answer->rdata->u.name))
+                               {
+                               debugf("Deregistering PTR %s -> %s", ptr->ar.resrec.name->c, ptr->ar.resrec.rdata->u.name.c);
+                dereg = &ptr->ar;
+                               if (prev) prev->next = ptr->next;
+                               else slElem->AuthRecs = ptr->next;
+                ptr = ptr->next;
+                               err = mDNS_Deregister(m, dereg);
+                               if (err) LogMsg("ERROR: FoundDomain - mDNS_Deregister returned %d", err);
+                               }
+                       else
+                               {
+                               prev = ptr;
+                               ptr = ptr->next;
+                               }
+                       }
+               }
+       }
+
+mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
+       {
+       return mDNS_CopyDNameList(DefBrowseList);
+       }
+
+mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
+       {
+       return mDNS_CopyDNameList(DefRegList);
+       }
+
+mDNSlocal void AddDefRegDomain(domainname *d)
+       {
+       DNameListElem *newelem = NULL, *ptr;
+
+       // make sure name not already in list
+       for (ptr = DefRegList; ptr; ptr = ptr->next)
+               {
+               if (SameDomainName(&ptr->name, d))
+                       { debugf("duplicate addition of default reg domain %##s", d->c); return; }
+               }
+       
+       newelem = mallocL("DNameListElem", sizeof(*newelem));
+       if (!newelem) { LogMsg("Error - malloc"); return; }
+       AssignDomainName(&newelem->name, d);
+       newelem->next = DefRegList;
+       DefRegList = newelem;
+
+       dDNSPlatformDefaultRegDomainChanged(d, mDNStrue);
+       udsserver_default_reg_domain_changed(d, mDNStrue);
+       }
+
+mDNSlocal void RemoveDefRegDomain(domainname *d)
+       {
+       DNameListElem *ptr = DefRegList, *prev = NULL;
+
+       while (ptr)
+               {
+               if (SameDomainName(&ptr->name, d))
+                       {
+                       if (prev) prev->next = ptr->next;
+                       else DefRegList = ptr->next;
+                       freeL("DNameListElem", ptr);
+                       dDNSPlatformDefaultRegDomainChanged(d, mDNSfalse);
+                       udsserver_default_reg_domain_changed(d, mDNSfalse);
+                       return;
+                       }
+               prev = ptr;
+               ptr = ptr->next;
+               }
+       debugf("Requested removal of default registration domain %##s not in contained in list", d->c); 
+       }
+
+
+mDNSlocal void FoundDefBrowseDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+       {
+       DNameListElem *ptr, *prev, *new;
+       (void)m; // unused;
+       (void)question;  // unused
+
+       if (AddRecord)
+               {
+               new = mallocL("FoundDefBrowseDomain", sizeof(DNameListElem));
+               if (!new) { LogMsg("ERROR: malloc"); return; }
+               AssignDomainName(&new->name, &answer->rdata->u.name);
+               new->next = DefBrowseList;
+               DefBrowseList = new;
+               dDNSPlatformDefaultBrowseDomainChanged(&new->name, mDNStrue);
+               udsserver_default_browse_domain_changed(&new->name, mDNStrue);
+               return;
+               }
+       else
+               {
+               ptr = DefBrowseList;
+               prev = NULL;
+               while (ptr)
+                       {
+                       if (SameDomainName(&ptr->name, &answer->rdata->u.name))
+                               {
+                               dDNSPlatformDefaultBrowseDomainChanged(&ptr->name, mDNSfalse);
+                               udsserver_default_browse_domain_changed(&ptr->name, mDNSfalse);
+                               if (prev) prev->next = ptr->next;
+                               else DefBrowseList = ptr->next;
+                               freeL("FoundDefBrowseDomain", ptr);                             
+                               return;
+                               }
+                       prev = ptr;
+                       ptr = ptr->next;
+                       }
+               LogMsg("FoundDefBrowseDomain: Got remove event for domain %s not in list", answer->rdata->u.name.c);
+               }
+       }
+
+
+mDNSlocal mStatus RegisterNameServers( mDNS *const m )
+       {
+       IPAddrListElem  * list;
+       IPAddrListElem  * elem;
+
+       mDNS_DeleteDNSServers(m); // deregister orig list
+
+       list = dDNSPlatformGetDNSServers();
+
+       for ( elem = list; elem; elem = elem->next )
+               {
+               LogOperation("RegisterNameServers: Adding %#a", &elem->addr);
+               mDNS_AddDNSServer(m, &elem->addr, NULL);
+               }
+
+       dDNS_FreeIPAddrList( list );
+
+       return mStatus_NoError;
+       }
+
+
+mDNSlocal mStatus RegisterSearchDomains( mDNS *const m )
+       {
+       SearchListElem *ptr, *prev, *freeSLPtr;
+       DNameListElem   *       elem;
+       DNameListElem   *       list;
+       ARListElem *arList;
+       mStatus err;
+       mDNSBool dict = 1;
+       
+       // step 1: mark each elem for removal (-1), unless we aren't passed a dictionary in which case we mark as preexistent
+       for (ptr = SearchList; ptr; ptr = ptr->next) ptr->flag = dict ? -1 : 0;
+
+       // get all the domains from "Search Domains" field of sharing prefs
+
+       list = dDNSPlatformGetSearchDomainList();
+       
+       for ( elem = list; elem; elem = elem->next )
+               {
+               MarkSearchListElem(&elem->name);
+               }
+
+       mDNS_FreeDNameList( list );
+
+       list = dDNSPlatformGetDomainName();
+
+       if ( list )
+               {
+               MarkSearchListElem( &list->name );
+               mDNS_FreeDNameList( list );
+               }
+
+       list = dDNSPlatformGetReverseMapSearchDomainList( );
+
+       for ( elem = list; elem; elem = elem->next )
+               {
+               MarkSearchListElem(&elem->name);
+               }
+
+       mDNS_FreeDNameList( list );
+
+       if (dDNSRegDomain.c[0]) MarkSearchListElem(&dDNSRegDomain);         // implicitly browse reg domain too (no-op if same as BrowseDomain)
+       
+       // delete elems marked for removal, do queries for elems marked add
+       prev = mDNSNULL;
+       ptr = SearchList;
+       while (ptr)
+               {
+               if (ptr->flag == -1)  // remove
+                       {
+                       mDNS_StopQuery(m, &ptr->BrowseQ);
+                       mDNS_StopQuery(m, &ptr->RegisterQ);
+                       mDNS_StopQuery(m, &ptr->DefBrowseQ);
+                       mDNS_StopQuery(m, &ptr->DefRegisterQ);
+                       mDNS_StopQuery(m, &ptr->LegacyBrowseQ);                 
+                       
+            // deregister records generated from answers to the query
+                       arList = ptr->AuthRecs;
+                       ptr->AuthRecs = mDNSNULL;
+                       while (arList)
+                               {
+                               AuthRecord *dereg = &arList->ar;
+                               arList = arList->next;
+                               debugf("Deregistering PTR %s -> %s", dereg->resrec.name->c, dereg->resrec.rdata->u.name.c);
+                               err = mDNS_Deregister(m, dereg);
+                               if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err);
+                               }
+                       
+                       // remove elem from list, delete
+                       if (prev) prev->next = ptr->next;
+                       else SearchList = ptr->next;
+                       freeSLPtr = ptr;
+                       ptr = ptr->next;
+                       freeL("RegisterSearchDomains - freeSLPtr", freeSLPtr);
+                       continue;
+                       }
+               
+               if (ptr->flag == 1)  // add
+                       {
+                       mStatus err1, err2, err3, err4, err5;
+                       err1 = mDNS_GetDomains(m, &ptr->BrowseQ,       mDNS_DomainTypeBrowse,              &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+                       err2 = mDNS_GetDomains(m, &ptr->DefBrowseQ,    mDNS_DomainTypeBrowseDefault,       &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+                       err3 = mDNS_GetDomains(m, &ptr->RegisterQ,     mDNS_DomainTypeRegistration,        &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+                       err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ,  mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+                       err5 = mDNS_GetDomains(m, &ptr->LegacyBrowseQ, mDNS_DomainTypeBrowseLegacy,        &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
+                       if (err1 || err2 || err3 || err4 || err5)
+                               LogMsg("GetDomains for domain %##s returned error(s):\n"
+                                          "%d (mDNS_DomainTypeBrowse)\n"
+                                          "%d (mDNS_DomainTypeBrowseDefault)\n"
+                                          "%d (mDNS_DomainTypeRegistration)\n"
+                                          "%d (mDNS_DomainTypeRegistrationDefault)"
+                                          "%d (mDNS_DomainTypeBrowseLegacy)\n",
+                                          ptr->domain.c, err1, err2, err3, err4, err5);   
+                       ptr->flag = 0;
+                       }
+               
+               if (ptr->flag) { LogMsg("RegisterSearchDomains - unknown flag %d.  Skipping.", ptr->flag); }
+               
+               prev = ptr;
+               ptr = ptr->next;
+               }
+       
+       return mStatus_NoError;
+       }
+
+// Add or remove a user-specified domain to the list of empty-string browse domains
+// Also register a non-legacy _browse PTR record so that the domain appears in enumeration lists
+mDNSlocal void SetSCPrefsBrowseDomain(mDNS *m, const domainname *d, mDNSBool add)
+       {
+       AuthRecord rec;
+
+       LogMsg("%s default browse domain %##s", add ? "Adding" : "Removing", d->c);
+       
+       // Create dummy  record pointing to the domain to be added/removed
+       mDNS_SetupResourceRecord(&rec, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, mDNSNULL, mDNSNULL);
+       AssignDomainName(&rec.resrec.rdata->u.name, d);
+
+       // add/remove the "_legacy" entry
+       MakeDomainNameFromDNSNameString(rec.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeBrowseLegacy]);
+       AppendDNSNameString            (rec.resrec.name, "local");
+       FoundDefBrowseDomain(m, &LegacyBrowseDomainQ, &rec.resrec, add);
+
+       if (add)
+               {
+               mStatus err;
+
+               // allocate/register a non-legacy _browse PTR record
+               ARListElem *ptr = mallocL("ARListElem", sizeof(*ptr));
+               mDNS_SetupResourceRecord(&ptr->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200,  kDNSRecordTypeShared, FreeARElemCallback, ptr);
+               MakeDomainNameFromDNSNameString(ptr->ar.resrec.name, mDNS_DomainTypeNames[mDNS_DomainTypeBrowse]);
+               AppendDNSNameString            (ptr->ar.resrec.name, "local");
+               AssignDomainName(&ptr->ar.resrec.rdata->u.name, d);
+               err = mDNS_Register(m, &ptr->ar);
+               if (err)
+                       {
+                       LogMsg("SetSCPrefsBrowseDomain: mDNS_Register returned error %d", err);
+                       freeL("ARListElem", ptr);
+                       }
+               else
+                       {
+                       ptr->next = SCPrefBrowseDomains;
+                       SCPrefBrowseDomains = ptr;
+                       }
+               }
+       else
+               {
+               ARListElem **remove = &SCPrefBrowseDomains;
+               while (*remove && !SameDomainName(&(*remove)->ar.resrec.rdata->u.name, d)) remove = &(*remove)->next;
+               if (!*remove) { LogMsg("SetSCPrefsBrowseDomain (remove) - domain %##s not found!", d->c); return; }
+               mDNS_Deregister(m, &(*remove)->ar);
+               *remove = (*remove)->next;
+               }
+       }
+
+
+mStatus dDNS_Setup( mDNS *const m )
+       {
+       static mDNSBool LegacyNATInitialized = mDNSfalse;
+       mDNSBool dict = mDNStrue;
+       mDNSAddr ip;
+       mDNSAddr        r;
+       // YO CFDictionaryRef dict;
+       // YO CFStringRef     key;
+       domainname BrowseDomain, RegDomain, fqdn;
+       
+       // get fqdn, zone from SCPrefs
+       dDNSPlatformGetConfig(&fqdn, &RegDomain, &BrowseDomain);
+       
+       // YO if (!fqdn.c[0] && !RegDomain.c[0]) ReadDDNSSettingsFromConfFile(m, CONFIG_FILE, &fqdn, &RegDomain);
+
+       if (!SameDomainName(&RegDomain, &dDNSRegDomain))
+       {               
+               if (dDNSRegDomain.c[0])
+               {
+                       RemoveDefRegDomain(&dDNSRegDomain);
+                       SetSCPrefsBrowseDomain(m, &dDNSRegDomain, mDNSfalse); // if we were automatically browsing in our registration domain, stop
+               }
+
+               AssignDomainName(&dDNSRegDomain, &RegDomain);
+       
+               if (dDNSRegDomain.c[0])
+               {
+                       dDNSPlatformSetSecretForDomain(m, &dDNSRegDomain);
+                       AddDefRegDomain(&dDNSRegDomain);
+                       SetSCPrefsBrowseDomain(m, &dDNSRegDomain, mDNStrue);
+               }
+       }
+       
+       if (!SameDomainName(&BrowseDomain, &dDNSBrowseDomain))
+       {
+               if (dDNSBrowseDomain.c[0]) SetSCPrefsBrowseDomain(m, &dDNSBrowseDomain, mDNSfalse);
+               AssignDomainName(&dDNSBrowseDomain, &BrowseDomain);
+               if (dDNSBrowseDomain.c[0]) SetSCPrefsBrowseDomain(m, &dDNSBrowseDomain, mDNStrue);
+       }
+       
+       if (!SameDomainName(&fqdn, &dDNSHostname))
+               {
+               if (dDNSHostname.c[0]) mDNS_RemoveDynDNSHostName(m, &dDNSHostname);
+               AssignDomainName(&dDNSHostname, &fqdn);
+               if (dDNSHostname.c[0])
+                       {
+                       dDNSPlatformSetSecretForDomain(m, &fqdn); // no-op if "zone" secret, above, is to be used for hostname
+                       mDNS_AddDynDNSHostName(m, &dDNSHostname, SCPrefsdDNSCallback, mDNSNULL);
+                       dDNSPlatformSetNameStatus(&dDNSHostname, 1);
+                       }
+               }
+
+    // get DNS settings
+       // YO SCDynamicStoreRef store = SCDynamicStoreCreate(mDNSNULL, CFSTR("mDNSResponder:dDNSConfigChanged"), mDNSNULL, mDNSNULL);
+       // YO if (!store) return;
+       
+       // YO key = SCDynamicStoreKeyCreateNetworkGlobalEntity(mDNSNULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
+       // YO if (!key) {  LogMsg("ERROR: DNSConfigChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return;  }
+       // YO dict = SCDynamicStoreCopyValue(store, key);
+       // YO CFRelease(key);
+
+       // handle any changes to search domains and DNS server addresses
+       if ( dDNSPlatformRegisterSplitDNS(m) != mStatus_NoError)
+               if (dict) RegisterNameServers( m );  // fall back to non-split DNS aware configuration on failure
+       RegisterSearchDomains( m );  // note that we register name servers *before* search domains
+       // if (dict) CFRelease(dict);
+
+       // get IPv4 settings
+       // YO key = SCDynamicStoreKeyCreateNetworkGlobalEntity(mDNSNULL,kSCDynamicStoreDomainState, kSCEntNetIPv4);
+       // YO if (!key) {  LogMsg("ERROR: RouterChanged - SCDynamicStoreKeyCreateNetworkGlobalEntity"); CFRelease(store); return;  }
+       // YO dict = SCDynamicStoreCopyValue(store, key);
+       // YO CFRelease(key);
+       // YO CFRelease(store);
+       // YO if (!dict)
+       // YO   { mDNS_SetPrimaryInterfaceInfo(m, mDNSNULL, mDNSNULL); return; } // lost v4
+
+       // handle router changes
+       // YO mDNSAddr r;
+       // YO char buf[256];
+       // YO r.type = mDNSAddrType_IPv4;
+       // YO r.ip.v4.NotAnInteger = 0;
+       // YO CFStringRef router = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
+       // YO if (router)
+       // YO   {
+       // YO   if (!CFStringGetCString(router, buf, 256, kCFStringEncodingUTF8))
+       // YO           LogMsg("Could not convert router to CString");
+       // YO   else inet_aton(buf, (struct in_addr *)&r.ip.v4);
+       // YO   }
+
+       // handle router and primary interface changes
+
+       ip.type = r.type = mDNSAddrType_IPv4;
+       ip.ip.v4.NotAnInteger = r.ip.v4.NotAnInteger = 0;
+       
+       if ( dDNSPlatformGetPrimaryInterface( m, &ip, &r ) == mStatus_NoError )
+               {
+               mDNS_SetPrimaryInterfaceInfo(m, &ip, r.ip.v4.NotAnInteger ? &r : mDNSNULL);
+               }
+
+       return mStatus_NoError;
+}
+
+
+// Construction of Default Browse domain list (i.e. when clients pass NULL) is as follows:
+// 1) query for b._dns-sd._udp.local on LocalOnly interface
+//    (.local manually generated via explicit callback)
+// 2) for each search domain (from prefs pane), query for b._dns-sd._udp.<searchdomain>.
+// 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> <result>
+// 4) result above should generate a callback from question in (1).  result added to global list
+// 5) global list delivered to client via GetSearchDomainList()
+// 6) client calls to enumerate domains now go over LocalOnly interface
+//    (!!!KRS may add outgoing interface in addition)
+
+mStatus dDNS_InitDNSConfig(mDNS *const m)
+       {
+       mStatus err;
+
+       // start query for domains to be used in default (empty string domain) browses
+       err = mDNS_GetDomains(m, &LegacyBrowseDomainQ, mDNS_DomainTypeBrowseLegacy, NULL, mDNSInterface_LocalOnly, FoundDefBrowseDomain, NULL);
+
+       // provide .local automatically
+       SetSCPrefsBrowseDomain(m, &localdomain, mDNStrue);
+    return mStatus_NoError;
+}
+
+void
+dDNS_FreeIPAddrList(IPAddrListElem * list)
+{
+       IPAddrListElem * fptr;
+
+       while (list)
+       {
+               fptr = list;
+               list = list->next;
+               mDNSPlatformMemFree(fptr);
+       }
+}
diff --git a/mDNSWindows/dDNS.h b/mDNSWindows/dDNS.h
new file mode 100755 (executable)
index 0000000..e9d7a36
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+*/
+
+
+#ifndef __dDNS_h
+#define __dDNS_h
+
+#include "mDNSEmbeddedAPI.h"
+#include "dns_sd.h"
+
+#if 0
+#pragma mark - DynDNS structures
+#endif
+
+typedef struct IPAddrListElem
+       {
+       mDNSAddr addr;
+       struct IPAddrListElem *next;
+       } IPAddrListElem;
+
+extern void dDNS_FreeIPAddrList( IPAddrListElem * list );
+
+
+// ***************************************************************************
+#if 0
+#pragma mark - Main Client Functions
+#endif
+
+extern mStatus dDNS_Setup( mDNS *const m );
+extern mStatus dDNS_InitDNSConfig( mDNS *const m );
+extern mStatus dDNS_SetupAddr( mDNSAddr *ip, const struct sockaddr * const sa );
+
+
+// ***************************************************************************
+#if 0
+#pragma mark - PlatformSupport interface
+#endif
+
+// This section defines the interface to the DynDNS Platform Support layer.
+
+extern void                                    dDNSPlatformGetConfig(domainname *const fqdn, domainname *const regDomain, domainname *const browseDomain);
+extern void                                    dDNSPlatformSetNameStatus(domainname *const dname, mStatus status);
+extern void                                    dDNSPlatformSetSecretForDomain( mDNS *m, const domainname *domain );
+extern DNameListElem   *       dDNSPlatformGetSearchDomainList( void );
+extern DNameListElem   *       dDNSPlatformGetReverseMapSearchDomainList( void );
+extern IPAddrListElem  *       dDNSPlatformGetDNSServers( void );
+extern DNameListElem   *       dDNSPlatformGetDomainName( void );
+extern mStatus                         dDNSPlatformRegisterSplitDNS( mDNS *m );
+extern mStatus                         dDNSPlatformGetPrimaryInterface( mDNS * m, mDNSAddr * primary, mDNSAddr * router );
+extern void                                    dDNSPlatformDefaultBrowseDomainChanged( const domainname *d, mDNSBool add );
+extern void                                    dDNSPlatformDefaultRegDomainChanged(const domainname *d, mDNSBool add);
+
+#endif
+
diff --git a/mDNSWindows/isocode.h b/mDNSWindows/isocode.h
new file mode 100755 (executable)
index 0000000..19f8570
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+    
+*/
+
+/* isocode.h                                                             */
+/* ----------------------------------------------------------------------*/
+/* THIS FILE HAS BEEN AUTO-GENERATED.  DO NOT EDIT DIRECTLY              */
+/* If a language needs to be added, edit isocode.txt, and run isocode.pl */
+/* to generate a new version of this file                                */
+/* ----------------------------------------------------------------------*/
+/* ----------------------------------------------------------------------*/
+
+
+unsigned char ISOCODES[] = {
+12, 9, 'e','n', 0 , 0 , 0 , 0 ,
+40, 9, 'e','n', 0 , 0 , 0 , 0 ,
+16, 9, 'e','n', 0 , 0 , 0 , 0 ,
+36, 9, 'e','n', 0 , 0 , 0 , 0 ,
+24, 9, 'e','n', 0 , 0 , 0 , 0 ,
+32, 9, 'e','n', 0 , 0 , 0 , 0 ,
+20, 9, 'e','n', 0 , 0 , 0 , 0 ,
+52, 9, 'e','n', 0 , 0 , 0 , 0 ,
+28, 9, 'e','n', 0 , 0 , 0 , 0 ,
+44, 9, 'e','n', 0 , 0 , 0 , 0 ,
+8, 9, 'e','n', 0 , 0 , 0 , 0 ,
+4, 9, 'e','n', 0 , 0 , 0 , 0 ,
+48, 9, 'e','n', 0 , 0 , 0 , 0 ,
+8, 12, 'f','r', 0 , 0 , 0 , 0 ,
+44, 12, 'f','r', 0 , 0 , 0 , 0 ,
+12, 12, 'f','r', 0 , 0 , 0 , 0 ,
+36, 12, 'f','r', 0 , 0 , 0 , 0 ,
+48, 12, 'f','r', 0 , 0 , 0 , 0 ,
+4, 12, 'f','r', 0 , 0 , 0 , 0 ,
+20, 12, 'f','r', 0 , 0 , 0 , 0 ,
+52, 12, 'f','r', 0 , 0 , 0 , 0 ,
+24, 12, 'f','r', 0 , 0 , 0 , 0 ,
+40, 12, 'f','r', 0 , 0 , 0 , 0 ,
+16, 12, 'f','r', 0 , 0 , 0 , 0 ,
+28, 12, 'f','r', 0 , 0 , 0 , 0 ,
+4, 98, 'f','r', 0 , 0 , 0 , 0 ,
+12, 7, 'd','e', 0 , 0 , 0 , 0 ,
+4, 7, 'd','e', 0 , 0 , 0 , 0 ,
+20, 7, 'd','e', 0 , 0 , 0 , 0 ,
+16, 7, 'd','e', 0 , 0 , 0 , 0 ,
+8, 7, 'd','e', 0 , 0 , 0 , 0 ,
+4, 17, 'j','a', 0 , 0 , 0 , 0 ,
+8, 19, 'n','l', 0 , 0 , 0 , 0 ,
+4, 19, 'n','l', 0 , 0 , 0 , 0 ,
+4, 16, 'i','t', 0 , 0 , 0 , 0 ,
+8, 16, 'i','t', 0 , 0 , 0 , 0 ,
+44, 10, 'e','s', 0 , 0 , 0 , 0 ,
+64, 10, 'e','s', 0 , 0 , 0 , 0 ,
+52, 10, 'e','s', 0 , 0 , 0 , 0 ,
+36, 10, 'e','s', 0 , 0 , 0 , 0 ,
+20, 10, 'e','s', 0 , 0 , 0 , 0 ,
+28, 10, 'e','s', 0 , 0 , 0 , 0 ,
+48, 10, 'e','s', 0 , 0 , 0 , 0 ,
+68, 10, 'e','s', 0 , 0 , 0 , 0 ,
+16, 10, 'e','s', 0 , 0 , 0 , 0 ,
+72, 10, 'e','s', 0 , 0 , 0 , 0 ,
+12, 10, 'e','s', 0 , 0 , 0 , 0 ,
+8, 10, 'e','s', 0 , 0 , 0 , 0 ,
+76, 10, 'e','s', 0 , 0 , 0 , 0 ,
+24, 10, 'e','s', 0 , 0 , 0 , 0 ,
+60, 10, 'e','s', 0 , 0 , 0 , 0 ,
+40, 10, 'e','s', 0 , 0 , 0 , 0 ,
+80, 10, 'e','s', 0 , 0 , 0 , 0 ,
+4, 10, 'e','s', 0 , 0 , 0 , 0 ,
+56, 10, 'e','s', 0 , 0 , 0 , 0 ,
+32, 10, 'e','s', 0 , 0 , 0 , 0 ,
+8, 4, 'z','h','_','C','N', 0 ,
+16, 4, 'z','h','_','C','N', 0 ,
+12, 4, 'z','h','_','T','W', 0 ,
+20, 4, 'z','h','_','T','W', 0 ,
+4, 4, 'z','h','_','T','W', 0 ,
+4, 6, 'd','a', 0 , 0 , 0 , 0 ,
+4, 11, 'f','i', 0 , 0 , 0 , 0 ,
+4, 18, 'k','o', 0 , 0 , 0 , 0 ,
+4, 20, 'n','o', 0 , 0 , 0 , 0 ,
+8, 20, 'n','o', 0 , 0 , 0 , 0 ,
+4, 22, 'p','t', 0 , 0 , 0 , 0 ,
+4, 29, 's','v', 0 , 0 , 0 , 0 ,
+8, 29, 's','v', 0 , 0 , 0 , 0 ,
+20, 1, 'a','r', 0 , 0 , 0 , 0 ,
+60, 1, 'a','r', 0 , 0 , 0 , 0 ,
+12, 1, 'a','r', 0 , 0 , 0 , 0 ,
+8, 1, 'a','r', 0 , 0 , 0 , 0 ,
+44, 1, 'a','r', 0 , 0 , 0 , 0 ,
+52, 1, 'a','r', 0 , 0 , 0 , 0 ,
+48, 1, 'a','r', 0 , 0 , 0 , 0 ,
+16, 1, 'a','r', 0 , 0 , 0 , 0 ,
+24, 1, 'a','r', 0 , 0 , 0 , 0 ,
+32, 1, 'a','r', 0 , 0 , 0 , 0 ,
+64, 1, 'a','r', 0 , 0 , 0 , 0 ,
+4, 1, 'a','r', 0 , 0 , 0 , 0 ,
+40, 1, 'a','r', 0 , 0 , 0 , 0 ,
+28, 1, 'a','r', 0 , 0 , 0 , 0 ,
+56, 1, 'a','r', 0 , 0 , 0 , 0 ,
+36, 1, 'a','r', 0 , 0 , 0 , 0 ,
+4, 2, 'b','g', 0 , 0 , 0 , 0 ,
+4, 26, 'h','r', 0 , 0 , 0 , 0 ,
+4, 5, 'c','s', 0 , 0 , 0 , 0 ,
+4, 8, 'e','l', 0 , 0 , 0 , 0 ,
+4, 13, 'i','w', 0 , 0 , 0 , 0 ,
+4, 14, 'h','u', 0 , 0 , 0 , 0 ,
+4, 15, 'i','s', 0 , 0 , 0 , 0 ,
+4, 21, 'p','l', 0 , 0 , 0 , 0 ,
+8, 22, 'p','t','_','P','T', 0 ,
+4, 24, 'r','o', 0 , 0 , 0 , 0 ,
+8, 24, 'r','o', 0 , 0 , 0 , 0 ,
+4, 15, 'r','u', 0 , 0 , 0 , 0 ,
+8, 25, 'r','u', 0 , 0 , 0 , 0 ,
+4, 30, 't','h', 0 , 0 , 0 , 0 ,
+4, 31, 't','r', 0 , 0 , 0 , 0 ,
+4, 34, 'u','k', 0 , 0 , 0 , 0 ,
+};
+
+#define NUM_ISOCODES      101
+#define LANG_CODE_LEN     5
+#define MODULO_ISOCODES   8
+
+
diff --git a/mDNSWindows/loclibrary.c b/mDNSWindows/loclibrary.c
new file mode 100755 (executable)
index 0000000..78f16a4
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+ */
+    
+/* loclibrary.c                                                          
+ * ----------------------------------------------------------------------
+ * Source for localization library                                       
+ * Originally created by jsantamaria: 3 may 2004                         
+ * ----------------------------------------------------------------------
+ */
+#include <windows.h>
+#include <stdio.h>
+#include "isocode.h"
+#include "loclibrary.h"
+#include "Shlwapi.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <wchar.h>
+
+#ifdef __cplusplus
+extern "c" {
+#endif
+
+#ifdef _MSC_VER
+#define swprintf _snwprintf
+#define snprintf _snprintf
+#endif
+
+
+
+#define DEFAULT_LANG_CODE "en"
+
+// gets the user language
+static LANGID _getUserLanguage( void ) {
+       
+       return GetUserDefaultUILanguage();
+
+}
+
+
+// gets the ISO mapping
+static int _getISOCode(LANGID wLangID, char *isoLangCode, int codeLen) {
+       int i;
+       unsigned short langCode;
+
+       for (i = 0; i < NUM_ISOCODES; i++) {
+               int startIndex = i * MODULO_ISOCODES;
+               
+               langCode = (ISOCODES[startIndex] << 8);
+               langCode += ( (unsigned short) (ISOCODES[startIndex + 1]) );
+
+               if (langCode == wLangID) {
+                       char *langStr = (char *)&(ISOCODES[startIndex+2]);
+                       strncpy(isoLangCode, langStr, codeLen);
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+static char isoLangCode[LANG_CODE_LEN + 1] = "";
+static LANGID wLangID = (LANGID) -1;
+
+static void _setLanguageIfNeeded(void) {
+       
+       // get the language code if we don't have it cached
+       if (!strncmp(isoLangCode,"",LANG_CODE_LEN + 1)) {
+               
+               // if we haven't cached the language id, do the lookup
+               if (wLangID == (LANGID) -1) {
+                       wLangID = _getUserLanguage();
+               }
+               
+               // if no ISOCode, set it to DEFAULT_LANG_CODE
+               if (_getISOCode(wLangID, isoLangCode, LANG_CODE_LEN + 1)) {
+                       strncpy(isoLangCode, DEFAULT_LANG_CODE, LANG_CODE_LEN+1);
+               }
+       }
+
+}
+
+//// PathForResource
+
+// Gets the PathForResource for handle 0 for the current process
+
+
+static char appPathNameA[MAX_PATH] = "";
+
+int PathForResourceA ( HMODULE module, const char *name, char *locFile, int locFileLen) {
+       if (!strcmp(appPathNameA,"")) {
+               GetModuleFileNameA(module, appPathNameA, MAX_PATH);
+       }
+
+       return PathForResourceWithPathA (appPathNameA, name, locFile, locFileLen);
+
+}
+
+static wchar_t appPathNameW[MAX_PATH] = L"";
+
+int PathForResourceW ( HMODULE module, const wchar_t *name, wchar_t *locFile, int locFileLen) {
+       if (!wcscmp(appPathNameW,L"")) {
+               GetModuleFileNameW( module, appPathNameW, MAX_PATH);
+       }
+
+OutputDebugString( appPathNameW );
+
+       return PathForResourceWithPathW (appPathNameW, name, locFile, locFileLen);
+}
+
+
+//// PathForResourceWithPath
+
+#define TMP_BUF_SIZE MAX_PATH
+
+int PathForResourceWithPathA (const char *path, const char *nm, 
+                                                                       char *locFile, int locFileLen) {
+       char tmpBuffer[TMP_BUF_SIZE];
+
+       // build the path to the executable in the generic 
+       // resources folder, check there first
+       snprintf(tmpBuffer, MAX_PATH, "%s.Resources\\%s", path, nm);
+
+       if (!PathFileExistsA(tmpBuffer)) {
+
+               // didn't hit generic resource folder, so need to get language codes
+               _setLanguageIfNeeded();
+
+               // test to see if localized directory exists, 
+               // if so, we don't fall back if we don't find the file.
+               snprintf(tmpBuffer, TMP_BUF_SIZE, 
+                                "%s.Resources\\%s.lproj", path, isoLangCode);
+
+               if (PathFileExistsA(tmpBuffer)) {
+                       snprintf(tmpBuffer, TMP_BUF_SIZE, "%s\\%s", tmpBuffer, nm);
+
+                       if (!PathFileExistsA(tmpBuffer)) return 0;
+
+                       strncpy(locFile, tmpBuffer, locFileLen);
+                       return (int) strlen(locFile);
+               }
+
+               // fall back on DEFAULT_LANG_CODE if still no good
+               snprintf(tmpBuffer, TMP_BUF_SIZE, "%s.Resources\\%s.lproj\\%s", 
+                               path, DEFAULT_LANG_CODE, nm);
+                               
+               // we can't find the resource, so return 0
+               if (!PathFileExistsA(tmpBuffer)) return 0;
+       }
+       
+       strncpy(locFile, tmpBuffer, locFileLen);
+       return (int) strlen(locFile);
+
+}
+
+
+int PathForResourceWithPathW (const wchar_t *path, const wchar_t *nm, 
+                                                               wchar_t *locFile, int locFileLen) {
+
+       wchar_t tmpBuffer[TMP_BUF_SIZE];
+
+       // build the path to the executable in the generic
+       // resources folder, check there first
+       swprintf(tmpBuffer, TMP_BUF_SIZE, L"%ls.Resources\\%ls", path, nm);
+
+       if (!PathFileExistsW(tmpBuffer)) {
+               // didn't hit generic resource folder, so need to get language codes
+               _setLanguageIfNeeded();
+
+               // test to see if localized directory exists, 
+               // if so, we don't fall back if we don't find the file.
+               swprintf(tmpBuffer, TMP_BUF_SIZE, 
+                                 L"%ls.Resources\\%S.lproj", path, isoLangCode);
+
+               if (PathFileExistsW(tmpBuffer)) {
+                       swprintf(tmpBuffer, TMP_BUF_SIZE, L"%ls\\%ls", tmpBuffer, nm);
+
+                       if (!PathFileExistsW(tmpBuffer)) return 0;
+
+                       wcsncpy(locFile, tmpBuffer, locFileLen);
+                       return (int) wcslen(locFile);
+               }
+
+               // fall back on DEFAULT_LANG_CODE if still no good
+               swprintf(tmpBuffer, TMP_BUF_SIZE, L"%ls.Resources\\%s.lproj\\%ls", 
+                       path, DEFAULT_LANG_CODE, nm);
+
+               // we can't find the resource, so return 0
+               if (!PathFileExistsW(tmpBuffer)) return 0;
+       }
+       
+       wcsncpy(locFile, tmpBuffer, locFileLen);
+       return (int) wcslen(locFile);
+
+
+}
+
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/mDNSWindows/loclibrary.h b/mDNSWindows/loclibrary.h
new file mode 100755 (executable)
index 0000000..952dc44
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+
+    Change History (most recent first):
+
+ */
+    
+/* loclibrary.h                                                      
+ * ----------------------------------------------------------------------
+ * Header file for localization library                                       
+ * Originally created by jsantamaria: 3 may 2004                         
+ * ----------------------------------------------------------------------
+ */
+#ifndef _loclibrary_h_
+#define _loclibrary_h_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+int PathForResourceW ( HMODULE module, const wchar_t *name, wchar_t *locFile, int locFileLen);
+int PathForResourceWithPathW ( const wchar_t *path, const wchar_t *name, wchar_t *locFile, int locFileLen);
+
+int PathForResourceA ( HMODULE module, const char *name, char *locFile, int locFileLen);
+int PathForResourceWithPathA ( const char *path, const char *name, char *locFile, int locFileLen);
+
+
+#ifdef UNICODE
+#define PathForResource PathForResourceW
+#define PathForResourceWithPath PathForResourceWithPathW
+#else
+#define PathForResource PathForResourceA
+#define PathForResourceWithPath PathForResourceWithPathA
+#endif // UNICODE
+
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+
+#endif // _loclibrary_h_
index 1f48cf7c7d4d27eda5fd0188aea37fa7f1d1982d..7d4ea02a4e59fa280b5aa157c96c7f89bb289a34 100755 (executable)
     Change History (most recent first):
     
 $Log: mDNSWin32.c,v $
+Revision 1.71  2005/01/27 22:57:57  cheshire
+Fix compile errors on gcc4
+
+Revision 1.70  2005/01/25 08:12:52  shersche
+<rdar://problem/3947417> Enable Unicast and add Dynamic DNS support.
+Bug #: 3947417
+
+Revision 1.69  2005/01/11 04:39:48  shersche
+Workaround for GetAdaptersAddresses() bug in iphlpapi.dll
+
+Revision 1.68  2005/01/11 02:04:48  shersche
+Gracefully handle when IPv6 is not installed on a user's machine
+
+Revision 1.67  2004/12/18 00:51:52  cheshire
+Use symbolic constant kDNSServiceInterfaceIndexLocalOnly instead of (mDNSu32) ~0
+
+Revision 1.66  2004/12/17 23:37:49  cheshire
+<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
+(and other repetitive configuration changes)
+
+Revision 1.65  2004/12/15 07:34:45  shersche
+Add platform support for IPv4 and IPv6 unicast sockets
+
+Revision 1.64  2004/12/15 06:06:15  shersche
+Fix problem in obtaining IPv6 subnet mask
+
 Revision 1.63  2004/11/23 03:39:47  cheshire
 Let interface name/index mapping capability live directly in JNISupport.c,
 instead of having to call through to the daemon via IPC to get this information.
@@ -271,11 +297,13 @@ Multicast DNS platform plugin for Win32
 
 #include       "CommonServices.h"
 #include       "DebugServices.h"
+#include       <dns_sd.h>
 
 #include       <Iphlpapi.h>
 #if( !TARGET_OS_WINDOWS_CE )
        #include        <mswsock.h>
        #include        <process.h>
+       #include        <ntsecapi.h>
 #endif
 
 #include       "mDNSEmbeddedAPI.h"
@@ -297,6 +325,7 @@ Multicast DNS platform plugin for Win32
 #define        MDNS_WINDOWS_ENABLE_IPV6                                        1
 #define        MDNS_WINDOWS_EXCLUDE_IPV4_ROUTABLE_IPV6         1
 #define        MDNS_WINDOWS_AAAA_OVER_IPV4                                     1
+#define        MDNS_FIX_IPHLPAPI_PREFIX_BUG                            1
 
 #define        kMDNSDefaultName                                                        "My Computer"
 
@@ -306,13 +335,16 @@ Multicast DNS platform plugin for Win32
 #define        kWaitListCancelEvent                                            ( WAIT_OBJECT_0 + 0 )
 #define        kWaitListInterfaceListChangedEvent                      ( WAIT_OBJECT_0 + 1 )
 #define        kWaitListWakeupEvent                                            ( WAIT_OBJECT_0 + 2 )
-#define kWaitListRegEvent                                                      ( WAIT_OBJECT_0 + 3 )
-#define        kWaitListFixedItemCount                                         4
+#define kWaitListComputerDescriptionEvent                      ( WAIT_OBJECT_0 + 3 )
+#define kWaitListDynDNSEvent                                           ( WAIT_OBJECT_0 + 4 )
+#define        kWaitListFixedItemCount                                         5 + MDNS_WINDOWS_ENABLE_IPV4 + MDNS_WINDOWS_ENABLE_IPV6
+
 
 #if( !TARGET_OS_WINDOWS_CE )
        static GUID                                                                             kWSARecvMsgGUID = WSAID_WSARECVMSG;
 #endif
 
+
 #if 0
 #pragma mark == Prototypes ==
 #endif
@@ -330,7 +362,7 @@ mDNSlocal mStatus                   SetupInterfaceList( mDNS * const inMDNS );
 mDNSlocal mStatus                      TearDownInterfaceList( mDNS * const inMDNS );
 mDNSlocal mStatus                      SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD );
 mDNSlocal mStatus                      TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD );
-mDNSlocal mStatus                      SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, SocketRef *outSocketRef  );
+mDNSlocal mStatus                      SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef  );
 mDNSlocal mStatus                      SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort );
 mDNSlocal mStatus                      SetupNotifications( mDNS * const inMDNS );
 mDNSlocal mStatus                      TearDownNotifications( mDNS * const inMDNS );
@@ -342,7 +374,9 @@ mDNSlocal mStatus                   ProcessingThreadInitialize( mDNS * const inMDNS );
 mDNSlocal mStatus                      ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount );
 mDNSlocal void                         ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, SocketRef inSock );
 mDNSlocal void                         ProcessingThreadInterfaceListChanged( mDNS *inMDNS );
-mDNSlocal void                         ProcessingThreadRegistryChanged( mDNS * inMDNS );
+mDNSlocal void                         ProcessingThreadComputerDescriptionChanged( mDNS * inMDNS );
+mDNSlocal void                         ProcessingThreadDynDNSConfigChanged( mDNS * inMDNS );
+
 
 // Platform Accessors
 
@@ -364,7 +398,6 @@ mDNSexport mStatus  mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInter
 
 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
        mDNSlocal int   getifaddrs_ipv6( struct ifaddrs **outAddrs );
-       mDNSlocal int   getifnetmask_ipv6( struct ifaddrs * ifa );
 #endif
 
 #if( !TARGET_OS_WINDOWS_CE )
@@ -377,6 +410,12 @@ mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInter
 
 mDNSlocal mDNSBool     CanReceiveUnicast( void );
 
+mDNSlocal mStatus                      StringToAddress( mDNSAddr * ip, const char * string );
+mDNSlocal mStatus                      RegQueryString( HKEY key, const char * param, char ** string, DWORD * stringLen, DWORD * enabled );
+mDNSlocal struct ifaddrs*      myGetIfAddrs(int refresh);
+mDNSlocal OSStatus                     ConvertUTF8ToLsaString( const char * input, PLSA_UNICODE_STRING output );
+mDNSlocal OSStatus                     ConvertLsaStringToUTF8( PLSA_UNICODE_STRING input, char ** output );
+
 #ifdef __cplusplus
        }
 #endif
@@ -421,6 +460,8 @@ mStatus     mDNSPlatformInit( mDNS * const inMDNS )
        mStatus         err;
        WSADATA         wsaData;
        int                     supported;
+       struct sockaddr_in      sa4;
+       struct sockaddr_in6 sa6;
        
        dlog( kDebugLevelTrace, DEBUG_NAME "platform init\n" );
        
@@ -454,6 +495,84 @@ mStatus    mDNSPlatformInit( mDNS * const inMDNS )
        inMDNS->HISoftware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HISoftware.c[ 1 ] );
        dlog( kDebugLevelInfo, DEBUG_NAME "HISoftware: %#s\n", inMDNS->HISoftware.c );
        
+       // Set up the IPv4 unicast socket
+
+       inMDNS->p->unicastSock4                         = INVALID_SOCKET;
+       inMDNS->p->unicastSock4ReadEvent        = NULL;
+       inMDNS->p->unicastSock4RecvMsgPtr       = NULL;
+
+#if ( MDNS_WINDOWS_ENABLE_IPV4 )
+
+       sa4.sin_family          = AF_INET;
+       sa4.sin_addr.s_addr = INADDR_ANY;
+       err = SetupSocket( inMDNS, (const struct sockaddr*) &sa4, zeroIPPort, &inMDNS->p->unicastSock4 );
+       check_noerr( err );
+       inMDNS->p->unicastSock4ReadEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+       err = translate_errno( inMDNS->p->unicastSock4ReadEvent, (mStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+       err = WSAEventSelect( inMDNS->p->unicastSock4, inMDNS->p->unicastSock4ReadEvent, FD_READ );
+       require_noerr( err, exit );
+#if( !TARGET_OS_WINDOWS_CE )
+       {
+               DWORD size;
+
+               err = WSAIoctl( inMDNS->p->unicastSock4, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, 
+                                               sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock4RecvMsgPtr, sizeof( inMDNS->p->unicastSock4RecvMsgPtr ), &size, NULL, NULL );
+               
+               if ( err != 0 )
+               {
+                       inMDNS->p->unicastSock4RecvMsgPtr = NULL;
+               }
+       }
+#endif
+
+#endif
+
+       // Set up the IPv6 unicast socket
+
+       inMDNS->p->unicastSock6                         = INVALID_SOCKET;
+       inMDNS->p->unicastSock6ReadEvent        = NULL;
+       inMDNS->p->unicastSock6RecvMsgPtr       = NULL;
+
+#if ( MDNS_WINDOWS_ENABLE_IPV6 )
+
+       sa6.sin6_family         = AF_INET6;
+       sa6.sin6_addr           = in6addr_any;
+       sa6.sin6_scope_id       = 0;
+
+       // This call will fail if the machine hasn't installed IPv6.  In that case,
+       // the error will be WSAEAFNOSUPPORT.
+
+       err = SetupSocket( inMDNS, (const struct sockaddr*) &sa6, zeroIPPort, &inMDNS->p->unicastSock6 );
+       require_action( !err || ( err == WSAEAFNOSUPPORT ), exit, err = (mStatus) WSAGetLastError() );
+       inMDNS->p->unicastSock6ReadEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+       err = translate_errno( inMDNS->p->unicastSock6ReadEvent, (mStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+       
+       // If we weren't able to create the socket (because IPv6 hasn't been installed) don't do this
+
+       if ( inMDNS->p->unicastSock6 != INVALID_SOCKET )
+       {
+               err = WSAEventSelect( inMDNS->p->unicastSock6, inMDNS->p->unicastSock6ReadEvent, FD_READ );
+               require_noerr( err, exit );
+
+#if( !TARGET_OS_WINDOWS_CE )
+               {
+                       DWORD size;
+
+                       err = WSAIoctl( inMDNS->p->unicastSock6, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, 
+                                               sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock6RecvMsgPtr, sizeof( inMDNS->p->unicastSock6RecvMsgPtr ), &size, NULL, NULL );
+               
+                       if ( err != 0 )
+                       {
+                               inMDNS->p->unicastSock6RecvMsgPtr = NULL;
+                       }
+               }
+#endif
+       }
+
+#endif
+
        // Set up the mDNS thread.
        
        err = SetupSynchronizationObjects( inMDNS );
@@ -498,6 +617,36 @@ void       mDNSPlatformClose( mDNS * const inMDNS )
        err = TearDownSynchronizationObjects( inMDNS );
        check_noerr( err );
 
+#if ( MDNS_WINDOWS_ENABLE_IPV4 )
+
+       if ( inMDNS->p->unicastSock4ReadEvent )
+       {
+               CloseHandle( inMDNS->p->unicastSock4ReadEvent );
+               inMDNS->p->unicastSock4ReadEvent = 0;
+       }
+       
+       if ( IsValidSocket( inMDNS->p->unicastSock4 ) )
+       {
+               close_compat( inMDNS->p->unicastSock4 );
+       }
+
+#endif
+       
+#if ( MDNS_WINDOWS_ENABLE_IPV6 )
+
+       if ( inMDNS->p->unicastSock6ReadEvent )
+       {
+               CloseHandle( inMDNS->p->unicastSock6ReadEvent );
+               inMDNS->p->unicastSock6ReadEvent = 0;
+       }
+       
+       if ( IsValidSocket( inMDNS->p->unicastSock6 ) )
+       {
+               close_compat( inMDNS->p->unicastSock6 );
+       }
+
+#endif
+
        // Free the DLL needed for IPv6 support.
        
 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
@@ -528,8 +677,9 @@ mStatus
                const mDNSAddr *                        inDstIP, 
                mDNSIPPort                                      inDstPort )
 {
-       mStatus                                         err;
-       mDNSInterfaceData *                     ifd;
+       SOCKET                                          sendingsocket = INVALID_SOCKET;
+       mStatus                                         err = mStatus_NoError;
+       mDNSInterfaceData *                     ifd = (mDNSInterfaceData*) inInterfaceID;
        struct sockaddr_storage         addr;
        int                                                     n;
        
@@ -539,14 +689,8 @@ mStatus
        check( inMDNS );
        check( inMsg );
        check( inMsgEnd );
-       check( inInterfaceID );
        check( inDstIP );
        
-       ifd = (mDNSInterfaceData *) inInterfaceID;
-       require_action_quiet( ifd->interfaceInfo.McastTxRx, exit, err = mStatus_Invalid );                                      // Silent Interface
-       require_action_quiet( inDstIP->type == ifd->interfaceInfo.ip.type, exit, err = mStatus_NoError );       // Wrong Type
-       check( IsValidSocket( ifd->sock ) );
-       
        dlog( kDebugLevelChatty, DEBUG_NAME "platform send %d bytes to %#a:%u\n", n, inDstIP, ntohs( inDstPort.NotAnInteger ) );
        
        if( inDstIP->type == mDNSAddrType_IPv4 )
@@ -557,6 +701,7 @@ mStatus
                sa4->sin_family                 = AF_INET;
                sa4->sin_port                   = inDstPort.NotAnInteger;
                sa4->sin_addr.s_addr    = inDstIP->ip.v4.NotAnInteger;
+               sendingsocket           = ifd ? ifd->sock : inMDNS->p->unicastSock4;
        }
        else if( inDstIP->type == mDNSAddrType_IPv6 )
        {
@@ -568,6 +713,7 @@ mStatus
                sa6->sin6_flowinfo      = 0;
                sa6->sin6_addr          = *( (struct in6_addr *) &inDstIP->ip.v6 );
                sa6->sin6_scope_id      = 0;    // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
+               sendingsocket           = ifd ? ifd->sock : inMDNS->p->unicastSock6;
        }
        else
        {
@@ -576,9 +722,12 @@ mStatus
                goto exit;
        }
        
-       n = sendto( ifd->sock, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) );
-       err = translate_errno( n > 0, errno_compat(), kWriteErr );
-       require_noerr( err, exit );
+       if (IsValidSocket(sendingsocket))
+       {
+               n = sendto( sendingsocket, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) );
+               err = translate_errno( n > 0, errno_compat(), kWriteErr );
+               require_noerr( err, exit );
+       }
        
 exit:
        return( err );
@@ -821,7 +970,7 @@ mDNSInterfaceID     mDNSPlatformInterfaceIDfromInterfaceIndex( const mDNS * const in
        mDNSInterfaceID         id;
        
        id = mDNSNULL;
-       if( inIndex == (mDNSu32) ~0 )
+       if( inIndex == kDNSServiceInterfaceIndexLocalOnly )
        {
                id = mDNSInterface_LocalOnly;
        }
@@ -853,7 +1002,7 @@ mDNSu32    mDNSPlatformInterfaceIndexfromInterfaceID( const mDNS * const inMDNS, mD
        index = 0;
        if( inID == mDNSInterface_LocalOnly )
        {
-               index = (mDNSu32) ~0;
+               index = (mDNSu32) kDNSServiceInterfaceIndexLocalOnly;
        }
        else if( inID )
        {
@@ -947,33 +1096,612 @@ int     mDNSPlatformWriteTCP( int inSock, const char *inMsg, int inMsgSize )
 
 
 //===========================================================================================================================
-//     mDNSPlatformGetSearchDomainList
+//     dDNSPlatformGetConfig
+//===========================================================================================================================
+
+void
+dDNSPlatformGetConfig(domainname * const fqdn, domainname *const regDomain, domainname *const browseDomain)
+{
+       char    *       name = NULL;
+       DWORD           dwSize;
+       DWORD           enabled;
+       HKEY            key;
+       OSStatus        err;
+
+       // Initialize
+
+       fqdn->c[0] = regDomain->c[0] = browseDomain->c[0] = 0;
+       
+       err = RegCreateKey( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\" kServiceName "\\Parameters\\DynDNS\\Setup\\" kServiceDynDNSHostNames, &key );
+       require_noerr( err, exit );
+
+       err = RegQueryString( key, "", &name, &dwSize, &enabled );
+       if ( !err && ( name[0] != '\0' ) && enabled )
+       {
+               if ( !MakeDomainNameFromDNSNameString( fqdn, name ) || !fqdn->c[0] )
+               {
+                       dlog( kDebugLevelError, "bad DDNS host name in registry: %s", name[0] ? name : "(unknown)");
+               }
+       }
+
+       if ( key )
+       {
+               RegCloseKey( key );
+               key = NULL;
+       }
+
+       if ( name )
+       {
+               free( name );
+               name = NULL;
+       }
+
+       err = RegCreateKey( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\" kServiceName "\\Parameters\\DynDNS\\Setup\\" kServiceDynDNSBrowseDomains, &key );
+       require_noerr( err, exit );
+
+       err = RegQueryString( key, "", &name, &dwSize, &enabled );
+       if ( !err && ( name[0] != '\0' ) && enabled )
+       {
+               if ( !MakeDomainNameFromDNSNameString( browseDomain, name ) || !browseDomain->c[0] )
+               {
+                       dlog( kDebugLevelError, "bad DDNS browse domain in registry: %s", name[0] ? name : "(unknown)");
+               }
+       }
+
+       if ( key )
+       {
+               RegCloseKey( key );
+               key = NULL;
+       }
+
+       if ( name )
+       {
+               free( name );
+               name = NULL;
+       }
+
+       err = RegCreateKey( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\" kServiceName "\\Parameters\\DynDNS\\Setup\\" kServiceDynDNSRegistrationDomains, &key );
+       require_noerr( err, exit );
+       
+       err = RegQueryString( key, "", &name, &dwSize, &enabled );
+       if ( !err && ( name[0] != '\0' ) && enabled )
+       {
+               if ( !MakeDomainNameFromDNSNameString( regDomain, name ) || !regDomain->c[0] )
+               {
+                       dlog( kDebugLevelError, "bad DDNS registration domain in registry: %s", name[0] ? name : "(unknown)");
+               }
+       }
+
+exit:
+
+       if ( key )
+       {
+               RegCloseKey( key );
+       }
+
+       if ( name )
+       {
+               free( name );
+       }
+}
+
+
+//===========================================================================================================================
+//     dDNSPlatformSetNameStatus
+//===========================================================================================================================
+
+void
+dDNSPlatformSetNameStatus(domainname *const dname, mStatus status)
+{
+       char            uname[MAX_ESCAPED_DOMAIN_NAME];
+       char            name[MAX_ESCAPED_DOMAIN_NAME + 256];
+       HKEY            key = NULL;
+       mStatus         err;
+       char    *       p;
+       
+       ConvertDomainNameToCString(dname, uname);
+       
+       p = uname;
+
+       while (*p)
+       {
+               *p = (char) tolower(*p);
+               if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
+               p++;
+       }
+
+       check( strlen( p ) <= MAX_ESCAPED_DOMAIN_NAME );
+       sprintf( name, "SYSTEM\\CurrentControlSet\\Services\\%s\\Parameters\\DynDNS\\State\\HostNames", kServiceName );
+       err = RegCreateKey( HKEY_LOCAL_MACHINE, name, &key );
+       require_noerr( err, exit );
+
+       err = RegSetValueEx( key, kServiceDynDNSStatus, 0, REG_DWORD, (const LPBYTE) &status, sizeof(DWORD) );
+       require_noerr( err, exit );
+
+exit:
+
+       if ( key )
+       {
+               RegCloseKey( key );
+       }
+
+       return;
+}
+
+
+//===========================================================================================================================
+//     dDNSPlatformSetSecretForDomain
+//===========================================================================================================================
+
+void
+dDNSPlatformSetSecretForDomain( mDNS *m, const domainname * domain )
+{
+       char                                    dstring[MAX_ESCAPED_DOMAIN_NAME];
+       domainname                      *       d;
+       domainname                              canon;
+       size_t                                  i;
+       size_t                                  dlen;
+       LSA_OBJECT_ATTRIBUTES   attrs;
+       LSA_HANDLE                              handle = NULL;
+       LSA_UNICODE_STRING              keyName = { 0, 0, NULL };
+       LSA_UNICODE_STRING      *       secret = NULL;
+       char                            *       converted = NULL;
+       NTSTATUS                                res;
+       OSStatus                                err;
+
+       // canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
+       
+       ConvertDomainNameToCString(domain, dstring);
+       dlen = strlen(dstring);
+       for (i = 0; i < dlen; i++)
+       {
+               dstring[i] = (char) tolower(dstring[i]);  // canonicalize -> lower case
+       }
+
+       MakeDomainNameFromDNSNameString(&canon, dstring);
+       d = &canon;
+
+       // attrs are reserved, so initialize to zeroes.
+
+       ZeroMemory(&attrs, sizeof( attrs ) );
+
+       // Get a handle to the Policy object on the local system
+
+       res = LsaOpenPolicy( NULL, &attrs, POLICY_GET_PRIVATE_INFORMATION, &handle );
+       err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
+       require_noerr( err, exit );
+
+       // Get the encrypted data
+
+       err = ConvertUTF8ToLsaString( dstring, &keyName );
+       require_noerr( err, exit );
+
+       res = LsaRetrievePrivateData( handle, &keyName, &secret );
+       err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
+       require_noerr_quiet( err, exit );
+
+       // Convert the unicode to string to 8 bit
+
+       err = ConvertLsaStringToUTF8( secret, &converted );
+       require_noerr( err, exit );
+
+       mDNS_SetSecretForZone( m, d, d, converted, (mDNSu32) strlen( converted ) + 1, mDNStrue );
+
+exit:
+
+       if ( converted )
+       {
+               free( converted );
+               converted = NULL;
+       }
+
+       if ( secret )
+       {
+               LsaFreeMemory( secret );
+               secret = NULL;
+       }
+
+       if ( keyName.Buffer )
+       {
+               free( keyName.Buffer );
+               keyName.Buffer = NULL;
+       }
+
+       if ( handle )
+       {
+               LsaClose( handle );
+               handle = NULL;
+       }
+}
+
+
+//===========================================================================================================================
+//     dDNSPlatformGetSearchDomainList
+//===========================================================================================================================
+
+DNameListElem*
+dDNSPlatformGetSearchDomainList( void )
+{
+       char                    *       searchList      = NULL;
+       DWORD                           searchListLen;
+       DNameListElem   *       head = NULL;
+       DNameListElem   *       current = NULL;
+       char                    *       tok;
+       HKEY                            key;
+       mStatus                         err;
+
+       err = RegCreateKey( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", &key );
+       require_noerr( err, exit );
+
+       err = RegQueryString( key, "SearchList", &searchList, &searchListLen, NULL );
+       require_noerr( err, exit );
+
+       // Windows separates the search domains with ','
+
+       tok = strtok( searchList, "," );
+       while ( tok )
+       {
+               domainname domain;
+
+               if ( MakeDomainNameFromDNSNameString( &domain, tok ) )
+               {
+                       DNameListElem * last = current;
+
+                       current = (DNameListElem*) malloc( sizeof( DNameListElem ) );
+                       require_action( current, exit, err = mStatus_NoMemoryErr );
+
+                       AssignDomainName( &current->name, &domain );
+                       current->next = NULL;
+                       
+                       if ( !head )
+                       {
+                               head = current;
+                       }
+
+                       if ( last )
+                       {
+                               last->next = current;
+                       }
+               }
+
+               tok = strtok( NULL, "," );
+       }
+
+exit:
+
+       if ( searchList ) 
+       {
+               free( searchList );
+       }
+
+       if ( key )
+       {
+               RegCloseKey( key );
+       }
+
+       return head;
+}
+
+
+//===========================================================================================================================
+//     dDNSPlatformGetReverseMapSearchDomainList
 //===========================================================================================================================
 
+DNameListElem*
+dDNSPlatformGetReverseMapSearchDomainList( void )
+{
+       DNameListElem   *       head = NULL;
+       DNameListElem   *       current = NULL;
+       struct ifaddrs  *       ifa;
+       mStatus                         err;
+
+       ifa = myGetIfAddrs( 1 );
+       while (ifa)
+       {
+               mDNSAddr addr;
+               
+               if (ifa->ifa_addr->sa_family == AF_INET && !dDNS_SetupAddr(&addr, ifa->ifa_addr) && !IsPrivateV4Addr(&addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
+               {
+                       mDNSAddr        netmask;
+                       domainname      domain;
+                       char            buffer[256];
+                       
+                       if (!dDNS_SetupAddr(&netmask, ifa->ifa_netmask))
+                       {
+                               sprintf(buffer, "%d.%d.%d.%d.in-addr.arpa.", addr.ip.v4.b[3] & netmask.ip.v4.b[3],
+                                                             addr.ip.v4.b[2] & netmask.ip.v4.b[2],
+                                                             addr.ip.v4.b[1] & netmask.ip.v4.b[1],
+                                                             addr.ip.v4.b[0] & netmask.ip.v4.b[0]);
+                               
+                               if ( MakeDomainNameFromDNSNameString( &domain, buffer ) )
+                               {
+                                       DNameListElem * last = current;
+
+                                       current = (DNameListElem*) malloc( sizeof( DNameListElem ) );
+                                       require_action( current, exit, err = mStatus_NoMemoryErr );
+
+                                       AssignDomainName( &current->name, &domain );
+                                       current->next = NULL;
+                                       
+                                       if ( !head )
+                                       {
+                                               head = current;
+                                       }
+
+                                       if ( last )
+                                       {
+                                               last->next = current;
+                                       }
+                               }
+                       }
+               }
+       
+               ifa = ifa->ifa_next;
+       }
+
+exit:
+
+       return head;
+}
+
+
+//===========================================================================================================================
+//     dDNSPlatformGetDNSServers
+//===========================================================================================================================
+
+IPAddrListElem*
+dDNSPlatformGetDNSServers( void )
+{
+       FIXED_INFO              *       fixedInfo       = NULL;
+       ULONG                           bufLen          = sizeof( FIXED_INFO ); 
+       IP_ADDR_STRING  *       ipAddr;
+       IPAddrListElem  *       head            = NULL;
+       IPAddrListElem  *       current         = NULL;
+       int                                     i                       = 0;
+       mStatus                         err;
+
+       while ( 1 )
+       {
+               if ( fixedInfo )
+               {
+                       GlobalFree( fixedInfo );
+                       fixedInfo = NULL;
+               }
+
+               fixedInfo = (FIXED_INFO*) GlobalAlloc( GPTR, bufLen );
+   
+               err = GetNetworkParams( fixedInfo, &bufLen );
+
+               if ( ( err != ERROR_BUFFER_OVERFLOW ) || ( i++ == 100 ) )
+               {
+                       break;
+               }
+       }
+
+       require_noerr( err, exit );
+
+       for ( ipAddr = &fixedInfo->DnsServerList; ipAddr; ipAddr = ipAddr->Next )
+       {
+               mDNSAddr                        addr;
+               IPAddrListElem  *       last = current;
+
+               err = StringToAddress( &addr, ipAddr->IpAddress.String );
+
+               if ( err )
+               {
+                       continue;
+               }
+
+               current = (IPAddrListElem*) malloc( sizeof( IPAddrListElem ) );
+               require_action( current, exit, err = mStatus_NoMemoryErr );
+
+               memcpy( &current->addr, &addr, sizeof( mDNSAddr ) );
+               current->next = NULL;
+                       
+               if ( !head )
+               {
+                       head = current;
+               }
+
+               if ( last )
+               {
+                       last->next = current;
+               }
+       }
+
+exit:
 
-mDNSexport DNameListElem *mDNSPlatformGetSearchDomainList(void)
+       if ( fixedInfo )
        {
-       static DNameListElem tmp;
-       static int init = 0;
+               GlobalFree( fixedInfo );
+       }
 
-       if (!init)
+       return head;
+}
+
+
+//===========================================================================================================================
+//     dDNSPlatformGetDomainName
+//===========================================================================================================================
+
+DNameListElem*
+dDNSPlatformGetDomainName( void )
+{
+       FIXED_INFO              *       fixedInfo       = NULL;
+       ULONG                           bufLen          = sizeof( FIXED_INFO ); 
+       DNameListElem   *       head            = NULL;
+       int                                     i                       = 0;
+       mStatus                         err;
+
+       while ( 1 )
+       {
+               if ( fixedInfo )
+               {
+                       GlobalFree( fixedInfo );
+                       fixedInfo = NULL;
+               }
+
+               fixedInfo = (FIXED_INFO*) GlobalAlloc( GPTR, bufLen );
+   
+               err = GetNetworkParams( fixedInfo, &bufLen );
+
+               if ( ( err != ERROR_BUFFER_OVERFLOW ) || ( i++ == 100 ) )
                {
-               MakeDomainNameFromDNSNameString(&tmp.name, "local.");
-               tmp.next = NULL;
-               init = 1;
+                       break;
                }
-       return mDNS_CopyDNameList(&tmp);
        }
 
+       require_noerr( err, exit );
+
+       if ( fixedInfo->DomainName )
+       {
+               domainname dname;
+
+               if ( MakeDomainNameFromDNSNameString( &dname, fixedInfo->DomainName ) || !dname.c[0] )
+               {
+                       head = (DNameListElem*) malloc( sizeof( DNameListElem ) );
+                       require_action( head, exit, err = mStatus_NoMemoryErr );
+
+                       AssignDomainName( &head->name, &dname );
+                       head->next = NULL;
+               }
+               else
+               {
+                       dlog( kDebugLevelError, "bad DDNS host name from domain name: %s", fixedInfo->DomainName );
+               }
+       }
+
+exit:
+
+       if ( fixedInfo )
+       {
+               GlobalFree( fixedInfo );
+       }
+
+       return head;
+}
+
+
+//===========================================================================================================================
+//     dDNSPlatformRegisterSplitDNS
 //===========================================================================================================================
-//     mDNSPlatformGetRegDomainList
+
+mStatus
+dDNSPlatformRegisterSplitDNS( mDNS * m )
+{
+       DEBUG_UNUSED( m );
+
+       return mStatus_UnsupportedErr;
+}
+
+
 //===========================================================================================================================
+//     dDNSPlatformGetPrimaryInterface
+//===========================================================================================================================
+
+mStatus
+dDNSPlatformGetPrimaryInterface( mDNS * m, mDNSAddr * primary, mDNSAddr * router )
+{
+       IP_ADAPTER_INFO *       pAdapterInfo = NULL;
+       IP_ADAPTER_INFO *       pAdapter;
+       DWORD                           bufLen          = sizeof( IP_ADAPTER_INFO );
+       int                                     i;
+       BOOL                            found;
+       mStatus                         err = mStatus_NoError;
+
+       DEBUG_UNUSED( m );
+
+       pAdapterInfo = NULL;
+       found = FALSE;
+
+       for ( i = 0; i < 100; i++ )
+       {
+               if ( pAdapterInfo )
+               {
+                       free( pAdapterInfo );
+                       pAdapterInfo = NULL;
+               }
+
+               pAdapterInfo = (IP_ADAPTER_INFO*) malloc( bufLen );
+               require_action( pAdapterInfo, exit, err = kNoMemoryErr );
 
-mDNSexport DNameListElem *mDNSPlatformGetRegDomainList(void)
+               err = GetAdaptersInfo( pAdapterInfo, &bufLen);
+
+               if ( err != ERROR_BUFFER_OVERFLOW )
+               {
+                       break;
+               }
+       }
+
+       // Windows doesn't really have a concept of a primary adapter,
+       // so we're just going to iterate through all the adapters and
+       // pick the first one that has an IP address assigned and
+       // a gateway assigned
+
+       for ( pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next )
        {
-       return NULL;
+               if ( pAdapter->IpAddressList.IpAddress.String &&
+                    pAdapter->IpAddressList.IpAddress.String[0] &&
+                    pAdapter->GatewayList.IpAddress.String &&
+                    pAdapter->GatewayList.IpAddress.String[0] &&
+                    ( StringToAddress( primary, pAdapter->IpAddressList.IpAddress.String ) == mStatus_NoError ) &&
+                    ( StringToAddress( router, pAdapter->GatewayList.IpAddress.String ) == mStatus_NoError ) )
+               {
+                       // Found one that will work
+
+                       found = TRUE;
+                       break;
+               }
        }
 
+       if ( !found )
+       {
+               // If we couldn't find one, then let's try the first one in the list
+
+               err = StringToAddress( primary, pAdapter->IpAddressList.IpAddress.String );
+               require_noerr( err, exit );
+
+               found = TRUE;
+       }
+
+exit:
+
+       if ( pAdapterInfo )
+       {
+               free( pAdapterInfo );
+       }
+
+       return err;
+}
+
+
+//===========================================================================================================================
+//     dDNSPlatformDefaultBrowseDomainChanged
+//===========================================================================================================================
+
+void
+dDNSPlatformDefaultBrowseDomainChanged( const domainname *d, mDNSBool add )
+{
+       DEBUG_UNUSED( d );
+       DEBUG_UNUSED( add );
+
+       // This is a no-op on Windows
+}
+
+
+//===========================================================================================================================
+//     dDNSPlatformDefaultRegDomainChanged
+//===========================================================================================================================
+
+void
+dDNSPlatformDefaultRegDomainChanged( const domainname * d, mDNSBool add )
+{
+       DEBUG_UNUSED( d );
+       DEBUG_UNUSED( add );
+
+       // This is a no-op on Windows
+}
+
 
 #if 0
 #pragma mark -
@@ -1126,26 +1854,26 @@ mDNSlocal mStatus       SetupNiceName( mDNS * const inMDNS )
        tempString[ 0 ] = '\0';
 
        // First try and open the registry key that contains the computer description value
-       if (inMDNS->p->regKey == NULL)
+       if (inMDNS->p->descKey == NULL)
        {
                const char * s = "SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters";
-               err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s, 0, KEY_READ, &inMDNS->p->regKey);
+               err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s, 0, KEY_READ, &inMDNS->p->descKey);
                check_translated_errno( err == 0, errno_compat(), kNameErr );
 
                if (err)
                {
-                       inMDNS->p->regKey = NULL;
+                       inMDNS->p->descKey = NULL;
                }
        }
 
        // if we opened it...
-       if (inMDNS->p->regKey != NULL)
+       if (inMDNS->p->descKey != NULL)
        {
                DWORD type;
                DWORD valueLen = sizeof(tempString);
 
                // look for the computer description
-               err = RegQueryValueEx(inMDNS->p->regKey, "srvcomment", 0, &type, (LPBYTE) &tempString, &valueLen);
+               err = RegQueryValueEx(inMDNS->p->descKey, "srvcomment", 0, &type, (LPBYTE) &tempString, &valueLen);
                check_translated_errno( err == 0, errno_compat(), kNameErr );
        }
 
@@ -1259,12 +1987,16 @@ mDNSlocal mStatus       SetupInterfaceList( mDNS * const inMDNS )
        struct ifaddrs *                        loopback;
        u_int                                           flagMask;
        u_int                                           flagTest;
+       BOOL                                            foundUnicastSock4DestAddr;
+       BOOL                                            foundUnicastSock6DestAddr;
        
        dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list\n" );
        check( inMDNS );
        check( inMDNS->p );
        
-       addrs = NULL;
+       addrs                                           = NULL;
+       foundUnicastSock4DestAddr       = FALSE;
+       foundUnicastSock6DestAddr       = FALSE;
        
        // Tear down any existing interfaces that may be set up.
        
@@ -1312,10 +2044,24 @@ mDNSlocal mStatus       SetupInterfaceList( mDNS * const inMDNS )
                
                err = SetupInterface( inMDNS, p, &ifd );
                require_noerr( err, exit );
-                                               
+               
+               // If we're on a platform that doesn't have WSARecvMsg(), there's no way
+               // of determing the destination address of a packet that is sent to us.
+               // For multicast packets, that's easy to determine.  But for the unicast
+               // sockets, we'll fake it by taking the address of the first interface
+               // that is successfully setup.
+
+               if ( !foundUnicastSock4DestAddr )
+               {
+                       inMDNS->p->unicastSock4DestAddr = ifd->interfaceInfo.ip;
+                       foundUnicastSock4DestAddr = TRUE;
+               }
+                       
                *next = ifd;
                next  = &ifd->next;
                ++inMDNS->p->interfaceCount;
+
+               
        }
 #endif
        
@@ -1341,7 +2087,19 @@ mDNSlocal mStatus        SetupInterfaceList( mDNS * const inMDNS )
                
                err = SetupInterface( inMDNS, p, &ifd );
                require_noerr( err, exit );
-                                               
+                               
+               // If we're on a platform that doesn't have WSARecvMsg(), there's no way
+               // of determing the destination address of a packet that is sent to us.
+               // For multicast packets, that's easy to determine.  But for the unicast
+               // sockets, we'll fake it by taking the address of the first interface
+               // that is successfully setup.
+
+               if ( !foundUnicastSock6DestAddr )
+               {
+                       inMDNS->p->unicastSock6DestAddr = ifd->interfaceInfo.ip;
+                       foundUnicastSock6DestAddr = TRUE;
+               }
+
                *next = ifd;
                next  = &ifd->next;
                ++inMDNS->p->interfaceCount;
@@ -1379,11 +2137,26 @@ mDNSlocal mStatus       SetupInterfaceList( mDNS * const inMDNS )
                err = SetupInterface( inMDNS, loopback, &ifd );
                require_noerr( err, exit );
                
+#if( MDNS_WINDOWS_ENABLE_IPV4 )
+
+               // If we're on a platform that doesn't have WSARecvMsg(), there's no way
+               // of determing the destination address of a packet that is sent to us.
+               // For multicast packets, that's easy to determine.  But for the unicast
+               // sockets, we'll fake it by taking the address of the first interface
+               // that is successfully setup.
+
+               if ( !foundUnicastSock4DestAddr )
+               {
+                       inMDNS->p->unicastSock4DestAddr = ifd->defaultAddr;
+                       foundUnicastSock4DestAddr = TRUE;
+               }
+#endif
+
                *next = ifd;
                next  = &ifd->next;
                ++inMDNS->p->interfaceCount;
        }
-       
+
 exit:
        if( err )
        {
@@ -1538,7 +2311,7 @@ mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inI
        
        if( ifd->interfaceInfo.McastTxRx )
        {
-               err = SetupSocket( inMDNS, inIFA->ifa_addr, &sock );
+               err = SetupSocket( inMDNS, inIFA->ifa_addr, MulticastDNSPort, &sock );
                require_noerr( err, exit );
                ifd->sock = sock;
                ifd->defaultAddr = ( inIFA->ifa_addr->sa_family == AF_INET6 ) ? AllDNSLinkGroup_v6 : AllDNSLinkGroup_v4;
@@ -1586,7 +2359,7 @@ mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inI
        
        ifd->interfaceInfo.Advertise = inMDNS->AdvertiseLocalAddresses;
        
-       err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo );
+       err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, 0 );
        require_noerr( err, exit );
        ifd->hostRegistered = mDNStrue;
        
@@ -1663,7 +2436,7 @@ mDNSlocal mStatus TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inI
 //     SetupSocket
 //===========================================================================================================================
 
-mDNSlocal mStatus      SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, SocketRef *outSocketRef  )
+mDNSlocal mStatus      SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef  )
 {
        mStatus                 err;
        SocketRef               sock;
@@ -1681,11 +2454,15 @@ mDNSlocal mStatus       SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAdd
        err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
        require_noerr( err, exit );
                
-       // Turn on reuse address option so multiple servers can listen for Multicast DNS packets.
+       // Turn on reuse address option so multiple servers can listen for Multicast DNS packets,
+       // if we're creating a multicast socket
        
-       option = 1;
-       err = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
-       check_translated_errno( err == 0, errno_compat(), kOptionErr );
+       if ( port.NotAnInteger )
+       {
+               option = 1;
+               err = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
+               check_translated_errno( err == 0, errno_compat(), kOptionErr );
+       }
        
        if( inAddr->sa_family == AF_INET )
        {
@@ -1693,12 +2470,12 @@ mDNSlocal mStatus       SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAdd
                struct sockaddr_in              sa4;
                struct ip_mreq                  mreqv4;
                
-               // Bind to the multicast DNS port 5353.
+               // Bind the socket to the desired port
                
                ipv4.NotAnInteger       = ( (const struct sockaddr_in *) inAddr )->sin_addr.s_addr;
                memset( &sa4, 0, sizeof( sa4 ) );
                sa4.sin_family          = AF_INET;
-               sa4.sin_port            = MulticastDNSPort.NotAnInteger;
+               sa4.sin_port            = port.NotAnInteger;
                sa4.sin_addr.s_addr     = ipv4.NotAnInteger;
                
                err = bind( sock, (struct sockaddr *) &sa4, sizeof( sa4 ) );
@@ -1710,36 +2487,40 @@ mDNSlocal mStatus       SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAdd
                err = setsockopt( sock, IPPROTO_IP, IP_PKTINFO, (char *) &option, sizeof( option ) );
                check_translated_errno( err == 0, errno_compat(), kOptionErr );
                
-               // Join the all-DNS multicast group so we receive Multicast DNS packets.
+               if (port.NotAnInteger)
+               {
+                       // Join the all-DNS multicast group so we receive Multicast DNS packets
+
+                       mreqv4.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
+                       mreqv4.imr_interface.s_addr = ipv4.NotAnInteger;
+                       err = setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreqv4, sizeof( mreqv4 ) );
+                       check_translated_errno( err == 0, errno_compat(), kOptionErr );
                
-               mreqv4.imr_multiaddr.s_addr = AllDNSLinkGroupv4.NotAnInteger;
-               mreqv4.imr_interface.s_addr = ipv4.NotAnInteger;
-               err = setsockopt( sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreqv4, sizeof( mreqv4 ) );
-               check_translated_errno( err == 0, errno_compat(), kOptionErr );
+                       // Specify the interface to send multicast packets on this socket.
                
-               // Specify the interface to send multicast packets on this socket.
+                       sa4.sin_addr.s_addr = ipv4.NotAnInteger;
+                       err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &sa4.sin_addr, sizeof( sa4.sin_addr ) );
+                       check_translated_errno( err == 0, errno_compat(), kOptionErr );
                
-               sa4.sin_addr.s_addr = ipv4.NotAnInteger;
-               err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &sa4.sin_addr, sizeof( sa4.sin_addr ) );
-               check_translated_errno( err == 0, errno_compat(), kOptionErr );
+                       // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
                
+                       option = 1;
+                       err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
+                       check_translated_errno( err == 0, errno_compat(), kOptionErr );
+               }
+
                // Send unicast packets with TTL 255 (helps against spoofing).
                
                option = 255;
                err = setsockopt( sock, IPPROTO_IP, IP_TTL, (char *) &option, sizeof( option ) );
                check_translated_errno( err == 0, errno_compat(), kOptionErr );
-               
+
                // Send multicast packets with TTL 255 (helps against spoofing).
                
                option = 255;
                err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &option, sizeof( option ) );
                check_translated_errno( err == 0, errno_compat(), kOptionErr );
-               
-               // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
-               
-               option = 1;
-               err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
-               check_translated_errno( err == 0, errno_compat(), kOptionErr );
+
        }
        else if( inAddr->sa_family == AF_INET6 )
        {
@@ -1749,11 +2530,11 @@ mDNSlocal mStatus       SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAdd
                
                sa6p = (struct sockaddr_in6 *) inAddr;
                
-               // Bind to the multicast DNS port 5353.
+               // Bind the socket to the desired port
                
                memset( &sa6, 0, sizeof( sa6 ) );
                sa6.sin6_family         = AF_INET6;
-               sa6.sin6_port           = MulticastDNSPort.NotAnInteger;
+               sa6.sin6_port           = port.NotAnInteger;
                sa6.sin6_flowinfo       = 0;
                sa6.sin6_addr           = sa6p->sin6_addr;
                sa6.sin6_scope_id       = sa6p->sin6_scope_id;
@@ -1777,36 +2558,39 @@ mDNSlocal mStatus       SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAdd
                        check_translated_errno( err == 0, errno_compat(), kOptionErr );         
                #endif
                
-               // Join the all-DNS multicast group so we receive Multicast DNS packets.
+               if ( port.NotAnInteger )
+               {
+                       // Join the all-DNS multicast group so we receive Multicast DNS packets.
                
-               mreqv6.ipv6mr_multiaddr = *( (struct in6_addr *) &AllDNSLinkGroupv6 );
-               mreqv6.ipv6mr_interface = sa6p->sin6_scope_id;
-               err = setsockopt( sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreqv6, sizeof( mreqv6 ) );
-               check_translated_errno( err == 0, errno_compat(), kOptionErr );
+                       mreqv6.ipv6mr_multiaddr = *( (struct in6_addr *) &AllDNSLinkGroupv6 );
+                       mreqv6.ipv6mr_interface = sa6p->sin6_scope_id;
+                       err = setsockopt( sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *) &mreqv6, sizeof( mreqv6 ) );
+                       check_translated_errno( err == 0, errno_compat(), kOptionErr );
                
-               // Specify the interface to send multicast packets on this socket.
+                       // Specify the interface to send multicast packets on this socket.
                
-               option = (int) sa6p->sin6_scope_id;
-               err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &option, sizeof( option ) );
-               check_translated_errno( err == 0, errno_compat(), kOptionErr );
+                       option = (int) sa6p->sin6_scope_id;
+                       err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &option, sizeof( option ) );
+                       check_translated_errno( err == 0, errno_compat(), kOptionErr );
                
+                       // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
+                       
+                       option = 1;
+                       err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
+                       check_translated_errno( err == 0, errno_compat(), kOptionErr );
+               }
+
                // Send unicast packets with TTL 255 (helps against spoofing).
                
                option = 255;
                err = setsockopt( sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &option, sizeof( option ) );
                check_translated_errno( err == 0, errno_compat(), kOptionErr );
-               
+
                // Send multicast packets with TTL 255 (helps against spoofing).
-               
+                       
                option = 255;
                err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &option, sizeof( option ) );
                check_translated_errno( err == 0, errno_compat(), kOptionErr );
-               
-               // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
-               
-               option = 1;
-               err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
-               check_translated_errno( err == 0, errno_compat(), kOptionErr );
        }
        else
        {
@@ -1918,16 +2702,26 @@ mDNSlocal mStatus       SetupNotifications( mDNS * const inMDNS )
        err = translate_errno( err == 0, errno_compat(), kUnknownErr );
        require_noerr( err, exit );
 
-       inMDNS->p->regEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-       err = translate_errno( inMDNS->p->regEvent, (mStatus) GetLastError(), kUnknownErr );
+       inMDNS->p->descChangedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+       err = translate_errno( inMDNS->p->descChangedEvent, (mStatus) GetLastError(), kUnknownErr );
        require_noerr( err, exit );
 
-       if (inMDNS->p->regKey != NULL)
+       if (inMDNS->p->descKey != NULL)
        {
-               err = RegNotifyChangeKeyValue(inMDNS->p->regKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->regEvent, TRUE);
+               err = RegNotifyChangeKeyValue(inMDNS->p->descKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->descChangedEvent, TRUE);
                require_noerr( err, exit );
        }
 
+       inMDNS->p->ddnsChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+       err = translate_errno( inMDNS->p->ddnsChangedEvent, (mStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
+       err = RegCreateKey( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\" kServiceName "\\Parameters\\DynDNS\\Setup", &inMDNS->p->ddnsKey );
+       require_noerr( err, exit );
+
+       err = RegNotifyChangeKeyValue(inMDNS->p->ddnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->ddnsChangedEvent, TRUE);
+       require_noerr( err, exit );
+
 exit:
        if( err )
        {
@@ -1944,20 +2738,32 @@ mDNSlocal mStatus       TearDownNotifications( mDNS * const inMDNS )
 {
        if( IsValidSocket( inMDNS->p->interfaceListChangedSocket ) )
        {
-               close_compat( inMDNS->p->interfaceListChangedSocket );
-               inMDNS->p->interfaceListChangedSocket = kInvalidSocketRef;
+               close_compat( inMDNS->p->interfaceListChangedSocket );
+               inMDNS->p->interfaceListChangedSocket = kInvalidSocketRef;
+       }
+
+       if ( inMDNS->p->descChangedEvent != NULL )
+       {
+               CloseHandle( inMDNS->p->descChangedEvent );
+               inMDNS->p->descChangedEvent = NULL;
+       }
+
+       if ( inMDNS->p->descKey != NULL )
+       {
+               RegCloseKey( inMDNS->p->descKey );
+               inMDNS->p->descKey = NULL;
        }
 
-       if ( inMDNS->p->regEvent != NULL )
+       if ( inMDNS->p->ddnsChangedEvent != NULL )
        {
-               CloseHandle( inMDNS->p->regEvent );
-               inMDNS->p->regEvent = NULL;
+               CloseHandle( inMDNS->p->ddnsChangedEvent );
+               inMDNS->p->ddnsChangedEvent = NULL;
        }
 
-       if ( inMDNS->p->regKey != NULL )
+       if ( inMDNS->p->ddnsKey != NULL )
        {
-               RegCloseKey( inMDNS->p->regKey );
-               inMDNS->p->regKey = NULL;
+               RegCloseKey( inMDNS->p->ddnsKey );
+               inMDNS->p->ddnsKey = NULL;
        }
 
        return( mStatus_NoError );
@@ -2115,12 +2921,20 @@ mDNSlocal unsigned WINAPI       ProcessingThread( LPVOID inParam )
                                dlog( kDebugLevelChatty - 1, DEBUG_NAME "wakeup for mDNS_Execute\n" );
                                continue;
                        }
-                       else if ( result == kWaitListRegEvent )
+                       else if ( result == kWaitListComputerDescriptionEvent )
                        {
                                //
                                // The computer description might have changed
                                //
-                               ProcessingThreadRegistryChanged( m );
+                               ProcessingThreadComputerDescriptionChanged( m );
+                               break;
+                       }
+                       else if ( result == kWaitListDynDNSEvent )
+                       {
+                               //
+                               // The DynDNS config might have changed
+                               //
+                               ProcessingThreadDynDNSConfigChanged( m );
                                break;
                        }
                        else
@@ -2135,12 +2949,27 @@ mDNSlocal unsigned WINAPI       ProcessingThread( LPVOID inParam )
                                if( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) )
                                {
                                        HANDLE                                  signaledObject;
-                                       int                                             n;
+                                       int                                             n = 0;
                                        mDNSInterfaceData *             ifd;
                                        
                                        signaledObject = waitList[ waitItemIndex ];
+
+#if ( MDNS_WINDOWS_ENABLE_IPV4 )
+                                       if ( m->p->unicastSock4ReadEvent == signaledObject )
+                                       {
+                                               ProcessingThreadProcessPacket( m, NULL, m->p->unicastSock4 );
+                                               ++n;
+                                       }
+#endif
+                                       
+#if ( MDNS_WINDOWS_ENABLE_IPV6 )
+                                       if ( m->p->unicastSock6ReadEvent == signaledObject )
+                                       {
+                                               ProcessingThreadProcessPacket( m, NULL, m->p->unicastSock6 );
+                                               ++n;
+                                       }
+#endif
                                        
-                                       n = 0;
                                        for( ifd = m->p->interfaceList; ifd; ifd = ifd->next )
                                        {
                                                if( ifd->readPendingEvent == signaledObject )
@@ -2149,6 +2978,7 @@ mDNSlocal unsigned WINAPI ProcessingThread( LPVOID inParam )
                                                        ++n;
                                                }
                                        }
+
                                        check( n > 0 );
                                }
                                else
@@ -2196,8 +3026,15 @@ mDNSlocal mStatus ProcessingThreadInitialize( mDNS * const inMDNS )
        
        err = SetupInterfaceList( inMDNS );
        require_noerr( err, exit );
+
+       err = dDNS_Setup( inMDNS );
+       require_noerr( err, exit );
+
+       err = dDNS_InitDNSConfig( inMDNS );
+       require_noerr( err, exit );
        
 exit:
+
        if( err )
        {
                TearDownInterfaceList( inMDNS );
@@ -2239,10 +3076,18 @@ mDNSlocal mStatus       ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **o
        *waitItemPtr++ = inMDNS->p->cancelEvent;
        *waitItemPtr++ = inMDNS->p->interfaceListChangedEvent;
        *waitItemPtr++ = inMDNS->p->wakeupEvent;
-       *waitItemPtr++ = inMDNS->p->regEvent;
+       *waitItemPtr++ = inMDNS->p->descChangedEvent;
+       *waitItemPtr++ = inMDNS->p->ddnsChangedEvent;
        
        // Append all the dynamic wait items to the list.
-       
+#if ( MDNS_WINDOWS_ENABLE_IPV4 )
+       *waitItemPtr++ = inMDNS->p->unicastSock4ReadEvent;
+#endif
+
+#if ( MDNS_WINDOWS_ENABLE_IPV6 )
+       *waitItemPtr++ = inMDNS->p->unicastSock6ReadEvent;
+#endif
+
        for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
        {
                *waitItemPtr++ = ifd->readPendingEvent;
@@ -2270,6 +3115,8 @@ exit:
 mDNSlocal void ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, SocketRef inSock )
 {
        OSStatus                                        err;
+       const mDNSInterfaceID           iid = inIFD ? inIFD->interfaceInfo.InterfaceID : NULL;
+       LPFN_WSARECVMSG                         recvMsgPtr;
        mDNSAddr                                        srcAddr;
        mDNSIPPort                                      srcPort;
        mDNSAddr                                        dstAddr;
@@ -2281,17 +3128,39 @@ mDNSlocal void  ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *i
        int                                                     n;
        
        check( inMDNS );
-       check( inIFD );
        check( IsValidSocket( inSock ) );
        
        // Set up the default in case the packet info options are not supported or reported correctly.
        
-       dstAddr = inIFD->defaultAddr;
-       dstPort = MulticastDNSPort;
-       ttl             = 255;
+       if ( inIFD )
+       {
+               recvMsgPtr      = inIFD->wsaRecvMsgFunctionPtr;
+               dstAddr         = inIFD->defaultAddr;
+               dstPort         = MulticastDNSPort;
+               ttl                     = 255;
+       }
+       else if ( inSock == inMDNS->p->unicastSock4 )
+       {
+               recvMsgPtr      = inMDNS->p->unicastSock4RecvMsgPtr;
+               dstAddr         = inMDNS->p->unicastSock4DestAddr;
+               dstPort         = zeroIPPort;
+               ttl                     = 255;
+       }
+       else if ( inSock == inMDNS->p->unicastSock6 )
+       {
+               recvMsgPtr      = inMDNS->p->unicastSock6RecvMsgPtr;
+               dstAddr         = inMDNS->p->unicastSock6DestAddr;
+               dstPort         = zeroIPPort;
+               ttl                     = 255;
+       }
+       else
+       {
+               dlog( kDebugLevelError, DEBUG_NAME "packet received on unknown socket\n" );
+               goto exit;
+       }
 
 #if( !TARGET_OS_WINDOWS_CE )
-       if( inIFD->wsaRecvMsgFunctionPtr )
+       if( recvMsgPtr )
        {
                WSAMSG                          msg;
                WSABUF                          buf;
@@ -2311,7 +3180,7 @@ mDNSlocal void    ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *i
                msg.Control.len         = (u_long) sizeof( controlBuffer );
                msg.dwFlags                     = 0;
                                
-               err = inIFD->wsaRecvMsgFunctionPtr( inSock, &msg, &size, NULL, NULL );
+               err = recvMsgPtr( inSock, &msg, &size, NULL, NULL );
                err = translate_errno( err == 0, (OSStatus) GetLastError(), kUnknownErr );
                require_noerr( err, exit );
                n = (int) size;
@@ -2325,8 +3194,12 @@ mDNSlocal void   ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *i
                                IN_PKTINFO *            ipv4PacketInfo;
                                
                                ipv4PacketInfo = (IN_PKTINFO *) WSA_CMSG_DATA( header );
-                               require_action( ipv4PacketInfo->ipi_ifindex == ( inIFD->index >> 8 ), exit, err = kMismatchErr );
-                               
+
+                               if ( inIFD )
+                               {
+                                       require_action( ipv4PacketInfo->ipi_ifindex == ( inIFD->index >> 8 ), exit, err = kMismatchErr );
+                               }
+
                                dstAddr.type                            = mDNSAddrType_IPv4;
                                dstAddr.ip.v4.NotAnInteger      = ipv4PacketInfo->ipi_addr.s_addr;
                        }
@@ -2335,8 +3208,12 @@ mDNSlocal void   ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *i
                                IN6_PKTINFO *           ipv6PacketInfo;
                                
                                ipv6PacketInfo = (IN6_PKTINFO *) WSA_CMSG_DATA( header );
-                               require_action( ipv6PacketInfo->ipi6_ifindex == inIFD->index, exit, err = kMismatchErr );
-                               
+
+                               if ( inIFD )
+                               {
+                                       require_action( ipv6PacketInfo->ipi6_ifindex == inIFD->index, exit, err = kMismatchErr );
+                               }
+
                                dstAddr.type    = mDNSAddrType_IPv6;
                                dstAddr.ip.v6   = *( (mDNSv6Addr *) &ipv6PacketInfo->ipi6_addr );
                        }
@@ -2345,7 +3222,7 @@ mDNSlocal void    ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *i
        else
 #endif
        {
-               int             addrSize;
+               int     addrSize;
                
                addrSize = sizeof( addr );
                n = recvfrom( inSock, (char *) &packet, sizeof( packet ), 0, (struct sockaddr *) &addr, &addrSize );
@@ -2360,11 +3237,16 @@ mDNSlocal void  ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *i
        dlog( kDebugLevelChatty, DEBUG_NAME "    size      = %d\n", n );
        dlog( kDebugLevelChatty, DEBUG_NAME "    src       = %#a:%u\n", &srcAddr, ntohs( srcPort.NotAnInteger ) );
        dlog( kDebugLevelChatty, DEBUG_NAME "    dst       = %#a:%u\n", &dstAddr, ntohs( dstPort.NotAnInteger ) );
-       dlog( kDebugLevelChatty, DEBUG_NAME "    interface = %#a (index=0x%08X)\n", &inIFD->interfaceInfo.ip, (int) inIFD->index );
+
+       if ( inIFD )
+       {
+               dlog( kDebugLevelChatty, DEBUG_NAME "    interface = %#a (index=0x%08X)\n", &inIFD->interfaceInfo.ip, (int) inIFD->index );
+       }
+
        dlog( kDebugLevelChatty, DEBUG_NAME "\n" );
        
        end = ( (mDNSu8 *) &packet ) + n;
-       mDNSCoreReceive( inMDNS, &packet, end, &srcAddr, srcPort, &dstAddr, dstPort, inIFD->interfaceInfo.InterfaceID );
+       mDNSCoreReceive( inMDNS, &packet, end, &srcAddr, srcPort, &dstAddr, dstPort, iid );
        
 exit:
        return;
@@ -2412,13 +3294,13 @@ mDNSlocal void  ProcessingThreadInterfaceListChanged( mDNS *inMDNS )
 
 
 //===========================================================================================================================
-//     ProcessingThreadRegistryChanged
+//     ProcessingThreadComputerDescriptionChanged
 //===========================================================================================================================
-mDNSlocal void ProcessingThreadRegistryChanged( mDNS *inMDNS )
+mDNSlocal void ProcessingThreadComputerDescriptionChanged( mDNS *inMDNS )
 {
        mStatus         err;
        
-       dlog( kDebugLevelInfo, DEBUG_NAME "registry has changed\n" );
+       dlog( kDebugLevelInfo, DEBUG_NAME "computer description has changed\n" );
        check( inMDNS );
 
        mDNSPlatformLock( inMDNS );
@@ -2432,9 +3314,35 @@ mDNSlocal void   ProcessingThreadRegistryChanged( mDNS *inMDNS )
        }
        
        // and reset the event handler
-       if ((inMDNS->p->regKey != NULL) && (inMDNS->p->regEvent))
+       if ((inMDNS->p->descKey != NULL) && (inMDNS->p->descChangedEvent))
+       {
+               err = RegNotifyChangeKeyValue(inMDNS->p->descKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->descChangedEvent, TRUE);
+               check_noerr( err );
+       }
+
+       mDNSPlatformUnlock( inMDNS );
+}
+
+
+//===========================================================================================================================
+//     ProcessingThreadDynDNSConfigChanged
+//===========================================================================================================================
+mDNSlocal void ProcessingThreadDynDNSConfigChanged( mDNS *inMDNS )
+{
+       mStatus         err;
+       
+       dlog( kDebugLevelInfo, DEBUG_NAME "DynDNS config has changed\n" );
+       check( inMDNS );
+
+       mDNSPlatformLock( inMDNS );
+
+       err = dDNS_Setup( inMDNS );
+       check_noerr( err );
+
+       // and reset the event handler
+       if ((inMDNS->p->ddnsKey != NULL) && (inMDNS->p->ddnsChangedEvent))
        {
-               err = RegNotifyChangeKeyValue(inMDNS->p->regKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->regEvent, TRUE);
+               err = RegNotifyChangeKeyValue(inMDNS->p->ddnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->ddnsChangedEvent, TRUE);
                check_noerr( err );
        }
 
@@ -2559,7 +3467,10 @@ mDNSlocal int    getifaddrs_ipv6( struct ifaddrs **outAddrs )
        
        for( iaa = iaaList; iaa; iaa = iaa->Next )
        {
-               IP_ADAPTER_UNICAST_ADDRESS *            addr;
+               int                                                             addrIndex;
+               IP_ADAPTER_UNICAST_ADDRESS      *       addr;
+               DWORD                                                   ipv6IfIndex;
+               IP_ADAPTER_PREFIX                       *       firstPrefix;
 
                if( iaa->IfIndex > 0xFFFFFF )
                {
@@ -2569,18 +3480,49 @@ mDNSlocal int   getifaddrs_ipv6( struct ifaddrs **outAddrs )
                {
                        dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->Ipv6IfIndex );
                }
-               
+
+               // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the 
+               // following code to crash when iterating through the prefix list.  This seems
+               // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
+               // This shouldn't happen according to Microsoft docs which states:
+               //
+               //     "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
+               //
+               // So the data structure seems to be corrupted when we return from
+               // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
+               // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
+               // modify iaa to have the correct values.
+
+               if ( iaa->Length >= sizeof( IP_ADAPTER_ADDRESSES ) )
+               {
+                       ipv6IfIndex = iaa->Ipv6IfIndex;
+                       firstPrefix = iaa->FirstPrefix;
+               }
+               else
+               {
+                       ipv6IfIndex     = 0;
+                       firstPrefix = NULL;
+               }
+
                // Skip psuedo and tunnel interfaces.
                
-               if( ( iaa->Ipv6IfIndex == 1 ) || ( iaa->IfType == IF_TYPE_TUNNEL ) )
+               if( ( ipv6IfIndex == 1 ) || ( iaa->IfType == IF_TYPE_TUNNEL ) )
                {
                        continue;
                }
                
                // Add each address as a separate interface to emulate the way getifaddrs works.
                
-               for( addr = iaa->FirstUnicastAddress; addr; addr = addr->Next )
+               for( addrIndex = 0, addr = iaa->FirstUnicastAddress; addr; ++addrIndex, addr = addr->Next )
                {                       
+                       int                                             family;
+                       int                                             prefixIndex;
+                       IP_ADAPTER_PREFIX *             prefix;
+                       ULONG                                   prefixLength;
+                       
+                       family = addr->Address.lpSockaddr->sa_family;
+                       if( ( family != AF_INET ) && ( family != AF_INET6 ) ) continue;
+                       
                        ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
                        require_action( ifa, exit, err = WSAENOBUFS );
                        
@@ -2597,53 +3539,99 @@ mDNSlocal int   getifaddrs_ipv6( struct ifaddrs **outAddrs )
                        // Get interface flags.
                        
                        ifa->ifa_flags = 0;
-                       if( iaa->OperStatus == IfOperStatusUp )
-                       {
-                               ifa->ifa_flags |= IFF_UP;
-                       }
-                       if( iaa->IfType == IF_TYPE_SOFTWARE_LOOPBACK )
-                       {
-                               ifa->ifa_flags |= IFF_LOOPBACK;
-                       }
-                       if( !( iaa->Flags & IP_ADAPTER_NO_MULTICAST ) )
+                       if( iaa->OperStatus == IfOperStatusUp )                 ifa->ifa_flags |= IFF_UP;
+                       if( iaa->IfType == IF_TYPE_SOFTWARE_LOOPBACK )  ifa->ifa_flags |= IFF_LOOPBACK;
+                       if( !( iaa->Flags & IP_ADAPTER_NO_MULTICAST ) ) ifa->ifa_flags |= IFF_MULTICAST;
+                       
+                       // Get the interface index. Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes
+                       // so the following is a hack to put IPv4 interface indexes in the upper 24-bits and IPv6 interface indexes
+                       // in the lower 8-bits. This allows the IPv6 interface index to be usable as an IPv6 scope ID directly.
+                       
+                       switch( family )
                        {
-                               ifa->ifa_flags |= IFF_MULTICAST;
+                               case AF_INET:  ifa->ifa_extra.index = iaa->IfIndex << 8; break;
+                               case AF_INET6: ifa->ifa_extra.index = ipv6IfIndex;       break;
+                               default: break;
                        }
                        
-                       // Get the interface index. Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes
-                       // so the following is a hack to put IPv4 interface indexes in the upper 16-bits and IPv6 interface indexes
-                       // in the lower 16-bits. This allows the IPv6 interface index to be usable as an IPv6 scope ID directly.
+                       // Get address.
                        
-                       switch( addr->Address.lpSockaddr->sa_family )
+                       switch( family )
                        {
                                case AF_INET:
-                                       ifa->ifa_extra.index = iaa->IfIndex << 8;
-                                       break;
-                                       
                                case AF_INET6:
-                                       ifa->ifa_extra.index = iaa->Ipv6IfIndex;
+                                       ifa->ifa_addr = (struct sockaddr *) calloc( 1, (size_t) addr->Address.iSockaddrLength );
+                                       require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
+                                       memcpy( ifa->ifa_addr, addr->Address.lpSockaddr, (size_t) addr->Address.iSockaddrLength );
                                        break;
                                
                                default:
                                        break;
                        }
+                       check( ifa->ifa_addr );
                        
-                       // Get addresses.
+                       // Get subnet mask (IPv4)/link prefix (IPv6). It is specified as a bit length (e.g. 24 for 255.255.255.0).
                        
-                       switch( addr->Address.lpSockaddr->sa_family )
+                       prefixLength = 0;
+                       for( prefixIndex = 0, prefix = firstPrefix; prefix; ++prefixIndex, prefix = prefix->Next )
+                       {
+                               if( prefixIndex == addrIndex )
+                               {
+                                       check_string( prefix->Address.lpSockaddr->sa_family == family, "addr family != netmask family" );
+                                       prefixLength = prefix->PrefixLength;
+                                       break;
+                               }
+                       }
+                       switch( family )
                        {
                                case AF_INET:
+                               {
+                                       struct sockaddr_in *            sa4;
+                                       
+                                       require_action( prefixLength <= 32, exit, err = ERROR_INVALID_DATA );
+                                       
+                                       sa4 = (struct sockaddr_in *) calloc( 1, sizeof( *sa4 ) );
+                                       require_action( sa4, exit, err = WSAENOBUFS );
+                                       
+                                       sa4->sin_family = AF_INET;
+                                       if( prefixLength == 0 )
+                                       {
+                                               dlog( kDebugLevelWarning, DEBUG_NAME "%s: IPv4 netmask 0, defaulting to 255.255.255.255\n", __ROUTINE__ );
+                                               prefixLength = 32;
+                                       }
+                                       sa4->sin_addr.s_addr = htonl( 0xFFFFFFFFU << ( 32 - prefixLength ) );
+                                       ifa->ifa_netmask = (struct sockaddr *) sa4;
+                                       break;
+                               }
+                               
                                case AF_INET6:
-                                       ifa->ifa_addr = (struct sockaddr *) calloc( 1, (size_t) addr->Address.iSockaddrLength );
-                                       require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
-                                       memcpy( ifa->ifa_addr, addr->Address.lpSockaddr, (size_t) addr->Address.iSockaddrLength );
-
-                                       ifa->ifa_netmask = (struct sockaddr *) calloc( 1, sizeof(struct sockaddr) );
-                                       require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS );
-                                       err = getifnetmask_ipv6(ifa);
-                                       require_noerr(err, exit);
-
+                               {
+                                       struct sockaddr_in6 *           sa6;
+                                       int                                                     len;
+                                       int                                                     maskIndex;
+                                       uint8_t                                         maskByte;
+                                       
+                                       require_action( prefixLength <= 128, exit, err = ERROR_INVALID_DATA );
+                                       
+                                       sa6 = (struct sockaddr_in6 *) calloc( 1, sizeof( *sa6 ) );
+                                       require_action( sa6, exit, err = WSAENOBUFS );
+                                       sa6->sin6_family = AF_INET6;
+                                       
+                                       if( prefixLength == 0 )
+                                       {
+                                               dlog( kDebugLevelWarning, DEBUG_NAME "%s: IPv6 link prefix 0, defaulting to /128\n", __ROUTINE__ );
+                                               prefixLength = 128;
+                                       }
+                                       maskIndex = 0;
+                                       for( len = (int) prefixLength; len > 0; len -= 8 )
+                                       {
+                                               if( len >= 8 ) maskByte = 0xFF;
+                                               else               maskByte = (uint8_t)( ( 0xFFU << ( 8 - len ) ) & 0xFFU );
+                                               sa6->sin6_addr.s6_addr[ maskIndex++ ] = maskByte;
+                                       }
+                                       ifa->ifa_netmask = (struct sockaddr *) sa6;
                                        break;
+                               }
                                
                                default:
                                        break;
@@ -2672,59 +3660,6 @@ exit:
        return( (int) err );
 }
 
-mDNSlocal int
-getifnetmask_ipv6( struct ifaddrs * ifa )
-{
-       PMIB_IPADDRTABLE        pIPAddrTable    =       NULL;
-       DWORD                           dwSize                  =       0;
-       DWORD                           dwRetVal;
-       DWORD                           i;
-       int                                     err                             =       0;
-
-       // Make an initial call to GetIpAddrTable to get the
-       // necessary size into the dwSize variable
-
-       dwRetVal = GetIpAddrTable(NULL, &dwSize, 0);
-       require_action( dwRetVal == ERROR_INSUFFICIENT_BUFFER, exit, err = WSAENOBUFS );
-
-       pIPAddrTable = (MIB_IPADDRTABLE *) malloc ( dwSize );
-       require_action( pIPAddrTable != NULL, exit, err = WSAENOBUFS );
-
-       // Make a second call to GetIpAddrTable to get the
-       // actual data we want
-
-       dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
-       require_action(dwRetVal == NO_ERROR, exit, err = WSAENOBUFS);
-
-       // Now try and find the correct IP Address
-
-       for (i = 0; i < pIPAddrTable->dwNumEntries; i++)
-       {
-               struct sockaddr_in sa;
-
-               memset(&sa, 0, sizeof(sa));
-               sa.sin_family = AF_INET;
-               sa.sin_addr.s_addr = pIPAddrTable->table[i].dwAddr;
-
-               if (memcmp(ifa->ifa_addr, &sa, sizeof(sa)) == 0)
-               {
-                       // Found the right one, so copy the subnet mask information
-
-                       sa.sin_addr.s_addr = pIPAddrTable->table[i].dwMask;
-                       memcpy( ifa->ifa_netmask, &sa, sizeof(sa) );
-                       break;
-               }
-       }
-
-exit:
-
-       if ( pIPAddrTable != NULL )
-       {
-               free(pIPAddrTable);
-       }
-
-       return err;
-}
 #endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
 
 #if( !TARGET_OS_WINDOWS_CE )
@@ -3164,3 +4099,201 @@ exit:
        }
        return( err );
 }
+
+
+//===========================================================================================================================
+//     RegQueryString
+//===========================================================================================================================
+
+static mStatus
+RegQueryString( HKEY key, const char * valueName, char ** string, DWORD * stringLen, DWORD * enabled )
+{
+       DWORD   type;
+       int             i;
+       mStatus err;
+
+       *stringLen      = MAX_ESCAPED_DOMAIN_NAME;
+       *string         = NULL;
+       i                       = 0;
+
+       do
+       {
+               if ( *string )
+               {
+                       free( *string );
+               }
+
+               *string = (char*) malloc( *stringLen );
+               require_action( *string, exit, err = mStatus_NoMemoryErr );
+
+               err = RegQueryValueEx( key, valueName, 0, &type, (LPBYTE) *string, stringLen );
+
+               i++;
+       }
+       while ( ( err == ERROR_MORE_DATA ) && ( i < 100 ) );
+
+       if ( enabled )
+       {
+               DWORD dwSize = sizeof( DWORD );
+
+               err = RegQueryValueEx( key, "Enabled", NULL, NULL, (LPBYTE) enabled, &dwSize );
+               check_noerr( err );
+
+               err = kNoErr;
+       }
+
+exit:
+
+       return err;
+}
+
+
+//===========================================================================================================================
+//     StringToAddress
+//===========================================================================================================================
+
+static mStatus StringToAddress( mDNSAddr * ip, const char * string )
+{
+       struct sockaddr_in6 sa6;
+       struct sockaddr_in      sa4;
+       INT                                     dwSize;
+       mStatus                         err;
+
+       sa6.sin6_family = AF_INET6;
+       dwSize                  = sizeof( sa6 );
+
+       err = WSAStringToAddress( (LPSTR) string, AF_INET6, NULL, (struct sockaddr*) &sa6, &dwSize );
+
+       if ( err == mStatus_NoError )
+       {
+               err = dDNS_SetupAddr( ip, (struct sockaddr*) &sa6 );
+               require_noerr( err, exit );
+       }
+       else
+       {
+               sa4.sin_family = AF_INET;
+               dwSize = sizeof( sa4 );
+
+               err = WSAStringToAddress( (LPSTR) string, AF_INET, NULL, (struct sockaddr*) &sa4, &dwSize );
+               require_noerr( err, exit );
+                       
+               err = dDNS_SetupAddr( ip, (struct sockaddr*) &sa4 );
+               require_noerr( err, exit );
+       }
+
+exit:
+
+       return err;
+}
+
+
+//===========================================================================================================================
+//     myGetIfAddrs
+//===========================================================================================================================
+
+mDNSlocal struct ifaddrs*
+myGetIfAddrs(int refresh)
+{
+       static struct ifaddrs *ifa = NULL;
+       
+       if (refresh && ifa)
+       {
+               freeifaddrs(ifa);
+               ifa = NULL;
+       }
+       
+       if (ifa == NULL)
+       {
+               getifaddrs(&ifa);
+       }
+       
+       return ifa;
+}
+
+
+//===========================================================================================================================
+//     ConvertUTF8ToLsaString
+//===========================================================================================================================
+
+mDNSlocal OSStatus
+ConvertUTF8ToLsaString( const char * input, PLSA_UNICODE_STRING output )
+{
+       int                     size;
+       OSStatus        err;
+       
+       check( input );
+       check( output );
+
+       output->Buffer = NULL;
+
+       size = MultiByteToWideChar( CP_UTF8, 0, input, -1, NULL, 0 );
+       err = translate_errno( size > 0, GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
+       output->Length = (USHORT)( size * sizeof( wchar_t ) );
+       output->Buffer = (PWCHAR) malloc( output->Length );
+       require_action( output->Buffer, exit, err = mStatus_NoMemoryErr );
+       size = MultiByteToWideChar( CP_UTF8, 0, input, -1, output->Buffer, size );
+       err = translate_errno( size > 0, GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
+       // We're going to subtrace one wchar_t from the size, because we didn't
+       // include it when we encoded the string
+
+       output->MaximumLength = output->Length;
+       output->Length          -= sizeof( wchar_t );
+       
+exit:
+
+       if ( err && output->Buffer )
+       {
+               free( output->Buffer );
+               output->Buffer = NULL;
+       }
+
+       return( err );
+}
+
+
+//===========================================================================================================================
+//     ConvertLsaStringToUTF8
+//===========================================================================================================================
+
+static OSStatus
+ConvertLsaStringToUTF8( PLSA_UNICODE_STRING input, char ** output )
+{
+       int                     size;
+       OSStatus        err = kNoErr;
+
+       // The Length field of this structure holds the number of bytes,
+       // but WideCharToMultiByte expects the number of wchar_t's. So
+       // we divide by sizeof(wchar_t) to get the correct number.
+
+       size = WideCharToMultiByte(CP_UTF8, 0, input->Buffer, ( input->Length / sizeof( wchar_t ) ), NULL, 0, NULL, NULL);
+       err = translate_errno( size != 0, GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+       
+       // Add one for trailing '\0'
+
+       *output = (char*) malloc( size + 1 );
+       require_action( *output, exit, err = mStatus_NoMemoryErr );
+
+       size = WideCharToMultiByte(CP_UTF8, 0, input->Buffer, ( input->Length / sizeof( wchar_t ) ), *output, size, NULL, NULL);        
+       err = translate_errno( size != 0, GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
+       // have to add the trailing 0 because WideCharToMultiByte doesn't do it,
+       // although it does return the correct size
+
+       (*output)[size] = '\0';
+
+exit:
+
+       if ( err && *output )
+       {
+               free( *output );
+               *output = NULL;
+       }
+
+       return err;
+}
index 70dbe2290a99415fc3450778c10a4f8af15f8f0d..e94150e04cd079edca76f6e030d464333f48b1d8 100755 (executable)
     Change History (most recent first):
     
 $Log: mDNSWin32.h,v $
+Revision 1.20  2005/01/25 08:12:52  shersche
+<rdar://problem/3947417> Enable Unicast and add Dynamic DNS support.
+Bug #: 3947417
+
+Revision 1.19  2004/12/15 07:34:45  shersche
+Add platform support for IPv4 and IPv6 unicast sockets
+
 Revision 1.18  2004/10/11 21:53:15  shersche
 <rdar://problem/3832450> Change GetWindowsVersionString link scoping from static to non-static so that it can be accessed from other compilation units. The information returned in this function will be used to determine what service dependencies to use when calling CreateService().
 Bug #: 3832450
@@ -106,6 +113,7 @@ Multicast DNS platform plugin for Win32
 #endif
 
 #include       "mDNSEmbeddedAPI.h"
+#include       "dDNS.h"
 
 #ifdef __cplusplus
        extern "C" {
@@ -176,10 +184,12 @@ struct    mDNS_PlatformSupport_struct
        HANDLE                                          cancelEvent;
        HANDLE                                          quitEvent;
        HANDLE                                          interfaceListChangedEvent;
-       HANDLE                                          regEvent;
+       HANDLE                                          descChangedEvent;       // Computer description changed event
+       HANDLE                                          ddnsChangedEvent;       // DynDNS config changed
        HANDLE                                          wakeupEvent;
        HANDLE                                          initEvent;
-       HKEY                                            regKey;
+       HKEY                                            descKey;
+       HKEY                                            ddnsKey;
        mStatus                                         initStatus;
        SocketRef                                       interfaceListChangedSocket;
        int                                                     interfaceCount;
@@ -189,6 +199,18 @@ struct     mDNS_PlatformSupport_struct
        IdleThreadCallback                      idleThreadCallback;
        InterfaceListChangedCallback    interfaceListChangedCallback;
        HostDescriptionChangedCallback  hostDescriptionChangedCallback;
+       SocketRef                                               unicastSock4;
+       HANDLE                                                  unicastSock4ReadEvent;
+       mDNSAddr                                                unicastSock4DestAddr;
+#if( !defined( _WIN32_WCE ) )
+       LPFN_WSARECVMSG                                 unicastSock4RecvMsgPtr;
+#endif
+       SocketRef                                               unicastSock6;
+       HANDLE                                                  unicastSock6ReadEvent;
+       mDNSAddr                                                unicastSock6DestAddr;
+#if( !defined( _WIN32_WCE ) )
+       LPFN_WSARECVMSG                                 unicastSock6RecvMsgPtr;
+#endif
 };
 
 //---------------------------------------------------------------------------------------------------------------------------
@@ -241,6 +263,20 @@ int        getifaddrs( struct ifaddrs **outAddrs );
 
 void   freeifaddrs( struct ifaddrs *inAddrs );
 
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     Registry Constants
+//---------------------------------------------------------------------------------------------------------------------------
+
+#define        kServiceName                                                    "Apple mDNSResponder"
+#define kServiceDynDNSBrowseDomains                            "BrowseDomains"
+#define kServiceDynDNSHostNames                                        "HostNames"
+#define kServiceDynDNSRegistrationDomains              "RegistrationDomains"
+#define kServiceDynDNSDomains                                  "Domains"       // value is comma separated list of domains
+#define kServiceDynDNSEnabled                                  "Enabled"
+#define kServiceDynDNSStatus                                   "Status"
+
+
 #ifdef __cplusplus
        }
 #endif
index e0d47723feee349644194d973a967b71d59cf3d1..4fae1d81c165443cb71f0874a64b4c424948be11 100644 (file)
@@ -75,7 +75,7 @@ BEGIN
             VALUE "FileDescription", "mdnsNSP Dynamic Link Library"
             VALUE "FileVersion", MASTER_PROD_VERS_STR
             VALUE "InternalName", "mdnsNSP"
-            VALUE "LegalCopyright", "Copyright (C) 2004"
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
             VALUE "OriginalFilename", "mdnsNSP.dll"
             VALUE "ProductName", MASTER_PROD_NAME
             VALUE "ProductVersion", MASTER_PROD_VERS_STR
index 5e49db5e0e077a421cb6e44e42e7c70a322c54c7..f8aac541c72ed1be864b35dc2bbb1e7b2765f29d 100644 (file)
-<?xml version="1.0" encoding = "Windows-1252"?>
-<VisualStudioProject
-       ProjectType="Visual C++"
-       Version="7.00"
-       Name="mdnsNSP"
-       ProjectGUID="{F4F15529-F0EB-402F-8662-73C5797EE557}"
-       Keyword="Win32Proj">
-       <Platforms>
-               <Platform
-                       Name="Win32"/>
-       </Platforms>
-       <Configurations>
-               <Configuration
-                       Name="Debug|Win32"
-                       OutputDirectory=".\Debug"
-                       IntermediateDirectory=".\Debug"
-                       ConfigurationType="2"
-                       CharacterSet="2">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="0"
-                               AdditionalIncludeDirectories=".;../;../../mDNSShared"
-                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;NSP_EXPORTS;DEBUG;WIN32_LEAN_AND_MEAN"
-                               StringPooling="TRUE"
-                               MinimalRebuild="TRUE"
-                               ExceptionHandling="FALSE"
-                               BasicRuntimeChecks="3"
-                               SmallerTypeCheck="TRUE"
-                               RuntimeLibrary="1"
-                               BufferSecurityCheck="TRUE"
-                               UsePrecompiledHeader="0"
-                               WarningLevel="4"
-                               Detect64BitPortabilityProblems="TRUE"
-                               DebugInformationFormat="4"
-                               CallingConvention="2"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalDependencies="../DLL/Debug/dnssd.lib ws2_32.lib iphlpapi.lib"
-                               OutputFile="$(OutDir)/mdnsNSP.dll"
-                               LinkIncremental="2"
-                               ModuleDefinitionFile="mdnsNSP.def"
-                               GenerateDebugInformation="TRUE"
-                               ProgramDatabaseFile="$(OutDir)/mdnsNSP.pdb"
-                               SubSystem="2"
-                               ImportLibrary="$(OutDir)/mdnsNSP.lib"
-                               TargetMachine="1"/>
-                       <Tool
-                               Name="VCMIDLTool"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               AdditionalIncludeDirectories="../"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-               </Configuration>
-               <Configuration
-                       Name="Release|Win32"
-                       OutputDirectory="Release"
-                       IntermediateDirectory="Release"
-                       ConfigurationType="2"
-                       CharacterSet="2">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               AdditionalIncludeDirectories=".;../;../../mDNSShared"
-                               PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;NSP_EXPORTS;WIN32_LEAN_AND_MEAN"
-                               StringPooling="TRUE"
-                               MinimalRebuild="TRUE"
-                               ExceptionHandling="FALSE"
-                               BasicRuntimeChecks="0"
-                               SmallerTypeCheck="FALSE"
-                               RuntimeLibrary="0"
-                               UsePrecompiledHeader="0"
-                               WarningLevel="4"
-                               Detect64BitPortabilityProblems="TRUE"
-                               DebugInformationFormat="3"
-                               CallingConvention="2"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalDependencies="../DLL/Release/dnssd.lib ws2_32.lib iphlpapi.lib"
-                               OutputFile="$(OutDir)/mdnsNSP.dll"
-                               LinkIncremental="1"
-                               ModuleDefinitionFile="mdnsNSP.def"
-                               GenerateDebugInformation="TRUE"
-                               SubSystem="2"
-                               OptimizeReferences="0"
-                               EnableCOMDATFolding="0"
-                               ImportLibrary="$(OutDir)/mdnsNSP.lib"
-                               TargetMachine="1"/>
-                       <Tool
-                               Name="VCMIDLTool"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               AdditionalIncludeDirectories="../"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-               </Configuration>
-       </Configurations>
-       <Files>
-               <Filter
-                       Name="Source Files"
-                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
-                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
-                       <File
-                               RelativePath="..\DebugServices.c">
-                       </File>
-                       <File
-                               RelativePath=".\mdnsNSP.c">
-                       </File>
-                       <File
-                               RelativePath=".\mdnsNSP.def">
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Header Files"
-                       Filter="h;hpp;hxx;hm;inl;inc;xsd"
-                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
-                       <File
-                               RelativePath="..\CommonServices.h">
-                       </File>
-                       <File
-                               RelativePath="..\DebugServices.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\mDNSShared\dns_sd.h">
-                       </File>
-                       <File
-                               RelativePath=".\resource.h">
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Resource Files"
-                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
-                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
-                       <File
-                               RelativePath=".\mdnsNSP.rc">
-                       </File>
-               </Filter>
-       </Files>
-       <Globals>
-       </Globals>
-</VisualStudioProject>
+<?xml version="1.0" encoding = "Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.00"\r
+       Name="mdnsNSP"\r
+       ProjectGUID="{F4F15529-F0EB-402F-8662-73C5797EE557}"\r
+       Keyword="Win32Proj">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory=".\Debug"\r
+                       IntermediateDirectory=".\Debug"\r
+                       ConfigurationType="2"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".;../;../../mDNSShared"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;NSP_EXPORTS;DEBUG;WIN32_LEAN_AND_MEAN"\r
+                               StringPooling="TRUE"\r
+                               MinimalRebuild="TRUE"\r
+                               ExceptionHandling="FALSE"\r
+                               BasicRuntimeChecks="3"\r
+                               SmallerTypeCheck="TRUE"\r
+                               RuntimeLibrary="1"\r
+                               BufferSecurityCheck="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="4"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="4"\r
+                               CallingConvention="2"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="../DLL/Debug/dnssd.lib ws2_32.lib iphlpapi.lib"\r
+                               OutputFile="$(OutDir)/mdnsNSP.dll"\r
+                               LinkIncremental="2"\r
+                               ModuleDefinitionFile="mdnsNSP.def"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(OutDir)/mdnsNSP.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/mdnsNSP.lib"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               AdditionalIncludeDirectories="../"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory=".\Release\Root\Program Files\bin"\r
+                       IntermediateDirectory=".\Release"\r
+                       ConfigurationType="2"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories=".;../;../../mDNSShared"\r
+                               PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;NSP_EXPORTS;WIN32_LEAN_AND_MEAN"\r
+                               StringPooling="TRUE"\r
+                               MinimalRebuild="TRUE"\r
+                               ExceptionHandling="FALSE"\r
+                               BasicRuntimeChecks="0"\r
+                               SmallerTypeCheck="FALSE"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="4"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="3"\r
+                               CallingConvention="2"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="../DLL/Release/dnssd.lib ws2_32.lib iphlpapi.lib"\r
+                               OutputFile="$(OutDir)/mdnsNSP.dll"\r
+                               LinkIncremental="1"\r
+                               ModuleDefinitionFile="mdnsNSP.def"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="0"\r
+                               EnableCOMDATFolding="0"\r
+                               ImportLibrary="$(IntDir)/mdnsNSP.lib"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               AdditionalIncludeDirectories="../"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">\r
+                       <File\r
+                               RelativePath="..\DebugServices.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\mdnsNSP.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\mdnsNSP.def">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">\r
+                       <File\r
+                               RelativePath="..\CommonServices.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\DebugServices.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\mDNSShared\dns_sd.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\resource.h">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">\r
+                       <File\r
+                               RelativePath=".\mdnsNSP.rc">\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r