From 283ee3ffafe4266617c4a2c641f6e3b35227e7e9 Mon Sep 17 00:00:00 2001 From: Apple Date: Fri, 28 Jan 2005 06:07:55 +0000 Subject: [PATCH] mDNSResponder-98.tar.gz --- Clients/DNSServiceBrowser.m | 5 +- Clients/ExplorerPlugin/About.cpp | 18 + Clients/ExplorerPlugin/About.h | 1 + Clients/ExplorerPlugin/ExplorerBarWindow.cpp | 67 +- Clients/ExplorerPlugin/ExplorerBarWindow.h | 4 + Clients/ExplorerPlugin/ExplorerPlugin.cpp | 62 +- Clients/ExplorerPlugin/ExplorerPlugin.h | 6 + Clients/ExplorerPlugin/ExplorerPlugin.rc | 349 ++-- Clients/ExplorerPlugin/ExplorerPlugin.vcproj | 544 +++--- .../ExplorerPlugin/ExplorerPluginLocRes.rc | 212 +++ .../ExplorerPluginLocRes.vcproj | 178 ++ Clients/ExplorerPlugin/ExplorerPluginRes.rc | 141 ++ .../ExplorerPlugin/ExplorerPluginRes.vcproj | 203 +++ Clients/ExplorerPlugin/Resource.h | 67 +- Clients/ExplorerPlugin/res/globe.bmp | Bin 0 -> 824 bytes Clients/ExplorerPlugin/resource_dll.h | 26 + Clients/ExplorerPlugin/resource_loc_res.h | 32 + Clients/ExplorerPlugin/resource_res.h | 31 + Clients/PrinterSetupWizard/FirstPage.cpp | 18 + Clients/PrinterSetupWizard/FourthPage.cpp | 10 +- Clients/PrinterSetupWizard/FourthPage.h | 5 +- .../PrinterSetupWizard/PrinterSetupWizard.rc | 192 +- .../PrinterSetupWizard.vcproj | 543 +++--- .../PrinterSetupWizardApp.cpp | 104 +- .../PrinterSetupWizardApp.h | 8 +- .../PrinterSetupWizardLocRes.rc | 303 ++++ .../PrinterSetupWizardLocRes.vcproj | 155 ++ .../PrinterSetupWizardRes.rc | 173 ++ .../PrinterSetupWizardRes.vcproj | 185 ++ .../PrinterSetupWizardSheet.cpp | 912 +++------- .../PrinterSetupWizardSheet.h | 97 +- Clients/PrinterSetupWizard/SecondPage.cpp | 1328 ++++++++++++-- Clients/PrinterSetupWizard/SecondPage.h | 158 +- Clients/PrinterSetupWizard/ThirdPage.cpp | 161 +- Clients/PrinterSetupWizard/ThirdPage.h | 16 +- Clients/PrinterSetupWizard/UtilTypes.h | 220 ++- .../res/PrinterSetupWizardLocRes.rc2 | 13 + .../res/PrinterSetupWizardRes.rc2 | 13 + Clients/PrinterSetupWizard/resource.h | 110 +- Clients/PrinterSetupWizard/resource_exe.h | 85 + Clients/PrinterSetupWizard/resource_loc_res.h | 86 + Clients/PrinterSetupWizard/resource_res.h | 85 + Clients/dns-sd.c | 30 +- Makefile | 2 +- mDNSCore/DNSCommon.c | 99 +- mDNSCore/DNSCommon.h | 11 +- mDNSCore/DNSDigest.c | 7 +- mDNSCore/mDNS.c | 1218 ++++++++----- mDNSCore/mDNSDebug.h | 6 + mDNSCore/mDNSEmbeddedAPI.h | 208 ++- mDNSCore/uDNS.c | 1153 +++++++----- mDNSCore/uDNS.h | 9 +- mDNSMacOS9/Mac OS Test Responder.c | 13 +- mDNSMacOS9/Mac OS Test Searcher.c | 9 +- mDNSMacOS9/SubTypeTester.c | 9 +- mDNSMacOS9/mDNSLibrary.c | 16 +- mDNSMacOS9/mDNSLibraryResources.r | 34 +- mDNSMacOS9/mDNSMacOS9.c | 11 +- mDNSMacOSX/LaunchDaemonInfo.plist | 17 + mDNSMacOSX/daemon.c | 302 ++-- mDNSMacOSX/mDNSMacOSX.c | 883 +++++++--- mDNSMacOSX/mDNSMacOSX.h | 6 +- mDNSMacOSX/mDNSResponder.order | 377 ++++ .../mDNSResponder.pbproj/project.pbxproj | 18 +- mDNSPosix/Client.c | 5 +- mDNSPosix/Identify.c | 13 +- mDNSPosix/Makefile | 21 +- mDNSPosix/NetMonitor.c | 21 +- mDNSPosix/PosixDaemon.c | 16 +- mDNSPosix/ProxyResponder.c | 55 +- mDNSPosix/Responder.c | 11 +- mDNSPosix/dnsextd.c | 82 +- mDNSPosix/mDNSPosix.c | 17 +- mDNSPosix/mDNSUNP.h | 5 +- mDNSShared/PlatformCommon.c | 26 +- mDNSShared/PlatformCommon.h | 5 +- mDNSShared/dns_sd.h | 19 +- mDNSShared/dnssd_clientshim.c | 15 +- mDNSShared/dnssd_clientstub.c | 36 +- mDNSShared/dnssd_ipc.c | 5 +- mDNSShared/dnssd_ipc.h | 5 +- mDNSShared/mDNSDebug.c | 9 +- mDNSShared/uds_daemon.c | 918 +++++----- mDNSShared/uds_daemon.h | 5 +- mDNSVxWorks/mDNSVxWorks.c | 6 +- mDNSWindows/DLL.NET/dnssd_NET.h | 5 +- mDNSWindows/DLL.NET/dnssd_NET.rc | 2 +- mDNSWindows/DLL.NET/dnssd_NET.vcproj | 3 +- mDNSWindows/DLL/dll.rc | 2 +- mDNSWindows/DLL/dnssd.vcproj | 357 ++-- mDNSWindows/DNSServices/DNSServices.c | 11 +- mDNSWindows/Java/makefile | 23 +- mDNSWindows/NSPTool/NSPTool.rc | 13 +- mDNSWindows/NSPTool/NSPTool.vcproj | 11 +- mDNSWindows/SystemService/Service.c | 12 +- mDNSWindows/SystemService/Service.rc | 2 +- mDNSWindows/SystemService/Service.vcproj | 405 ++--- mDNSWindows/WinVersRes.h | 26 +- mDNSWindows/dDNS.c | 590 +++++++ mDNSWindows/dDNS.h | 77 + mDNSWindows/isocode.h | 144 ++ mDNSWindows/loclibrary.c | 224 +++ mDNSWindows/loclibrary.h | 63 + mDNSWindows/mDNSWin32.c | 1543 ++++++++++++++--- mDNSWindows/mDNSWin32.h | 40 +- mDNSWindows/mdnsNSP/mdnsNSP.rc | 2 +- mDNSWindows/mdnsNSP/mdnsNSP.vcproj | 321 ++-- 107 files changed, 11677 insertions(+), 4858 deletions(-) create mode 100755 Clients/ExplorerPlugin/ExplorerPluginLocRes.rc create mode 100755 Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj create mode 100755 Clients/ExplorerPlugin/ExplorerPluginRes.rc create mode 100755 Clients/ExplorerPlugin/ExplorerPluginRes.vcproj create mode 100755 Clients/ExplorerPlugin/res/globe.bmp create mode 100755 Clients/ExplorerPlugin/resource_dll.h create mode 100755 Clients/ExplorerPlugin/resource_loc_res.h create mode 100755 Clients/ExplorerPlugin/resource_res.h create mode 100755 Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc create mode 100755 Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj create mode 100755 Clients/PrinterSetupWizard/PrinterSetupWizardRes.rc create mode 100755 Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj create mode 100755 Clients/PrinterSetupWizard/res/PrinterSetupWizardLocRes.rc2 create mode 100755 Clients/PrinterSetupWizard/res/PrinterSetupWizardRes.rc2 create mode 100755 Clients/PrinterSetupWizard/resource_exe.h create mode 100755 Clients/PrinterSetupWizard/resource_loc_res.h create mode 100755 Clients/PrinterSetupWizard/resource_res.h create mode 100644 mDNSMacOSX/LaunchDaemonInfo.plist create mode 100644 mDNSMacOSX/mDNSResponder.order create mode 100755 mDNSWindows/dDNS.c create mode 100755 mDNSWindows/dDNS.h create mode 100755 mDNSWindows/isocode.h create mode 100755 mDNSWindows/loclibrary.c create mode 100755 mDNSWindows/loclibrary.h diff --git a/Clients/DNSServiceBrowser.m b/Clients/DNSServiceBrowser.m index 30db5a8..da42780 100755 --- a/Clients/DNSServiceBrowser.m +++ b/Clients/DNSServiceBrowser.m @@ -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); } diff --git a/Clients/ExplorerPlugin/About.cpp b/Clients/ExplorerPlugin/About.cpp index 37d3281..783a9ce 100644 --- a/Clients/ExplorerPlugin/About.cpp +++ b/Clients/ExplorerPlugin/About.cpp @@ -4,6 +4,7 @@ #include "stdafx.h" #include "ExplorerPlugin.h" #include "About.h" +#include // 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) diff --git a/Clients/ExplorerPlugin/About.h b/Clients/ExplorerPlugin/About.h index f4d0d7e..f25270d 100644 --- a/Clients/ExplorerPlugin/About.h +++ b/Clients/ExplorerPlugin/About.h @@ -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; diff --git a/Clients/ExplorerPlugin/ExplorerBarWindow.cpp b/Clients/ExplorerPlugin/ExplorerBarWindow.cpp index beb0b35..ea9cdc3 100644 --- a/Clients/ExplorerPlugin/ExplorerBarWindow.cpp +++ b/Clients/ExplorerPlugin/ExplorerBarWindow.cpp @@ -23,6 +23,17 @@ 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 + Get bitmaps from non-localizable resource module +Bug #: 3911084 + +Revision 1.13 2005/01/06 21:13:09 shersche + 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. diff --git a/Clients/ExplorerPlugin/ExplorerBarWindow.h b/Clients/ExplorerPlugin/ExplorerBarWindow.h index afa4e99..34a3345 100644 --- a/Clients/ExplorerPlugin/ExplorerBarWindow.h +++ b/Clients/ExplorerPlugin/ExplorerBarWindow.h @@ -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; }; diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.cpp b/Clients/ExplorerPlugin/ExplorerPlugin.cpp index 5de124d..464051a 100644 --- a/Clients/ExplorerPlugin/ExplorerPlugin.cpp +++ b/Clients/ExplorerPlugin/ExplorerPlugin.cpp @@ -23,6 +23,10 @@ Change History (most recent first): $Log: ExplorerPlugin.cpp,v $ +Revision 1.6 2005/01/25 17:56:45 shersche + Load resource DLLs, get icons and bitmaps from resource DLLs +Bug #: 3911084 + Revision 1.5 2004/09/15 10:33:54 shersche 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); } diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.h b/Clients/ExplorerPlugin/ExplorerPlugin.h index 0acca3f..40a709a 100644 --- a/Clients/ExplorerPlugin/ExplorerPlugin.h +++ b/Clients/ExplorerPlugin/ExplorerPlugin.h @@ -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 . @@ -44,3 +47,6 @@ DEFINE_GUID(CLSID_ExplorerBar, extern HINSTANCE gInstance; extern int gDLLRefCount; +extern HINSTANCE GetNonLocalizedResources(); +extern HINSTANCE GetLocalizedResources(); + diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.rc b/Clients/ExplorerPlugin/ExplorerPlugin.rc index 7879e58..88dfeaf 100644 --- a/Clients/ExplorerPlugin/ExplorerPlugin.rc +++ b/Clients/ExplorerPlugin/ExplorerPlugin.rc @@ -1,227 +1,122 @@ -// 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. +// +#include "resource_dll.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_dll.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", MASTER_LEGAL_COPYRIGHT + 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 + +#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 + diff --git a/Clients/ExplorerPlugin/ExplorerPlugin.vcproj b/Clients/ExplorerPlugin/ExplorerPlugin.vcproj index 62f37fc..87f3f8e 100644 --- a/Clients/ExplorerPlugin/ExplorerPlugin.vcproj +++ b/Clients/ExplorerPlugin/ExplorerPlugin.vcproj @@ -1,279 +1,265 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc b/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc new file mode 100755 index 0000000..731a01a --- /dev/null +++ b/Clients/ExplorerPlugin/ExplorerPluginLocRes.rc @@ -0,0 +1,212 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource_loc_res.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_loc_res.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", "DNS-SD Explorer Bar Resource Module" + VALUE "FileVersion", MASTER_PROD_VERS_STR + VALUE "InternalName", "ExplorerPluginLocalized.dll" + VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT + VALUE "OriginalFilename", "ExplorerPluginLocalized.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 "",IDC_ABOUT_BACKGROUND,"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-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.", + 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 + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_CONTEXT_MENU MENU +BEGIN + POPUP "ContextMenu" + BEGIN + MENUITEM "About Rendezvous...", ID_Menu + MENUITEM SEPARATOR + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_ABOUT "About Rendezvous" + IDS_ABOUT_URL "http://www.apple.com/macosx/features/rendezvous" + IDS_NAME "Rendezvous" + IDS_WEB_SITES "Web Sites" + IDS_FTP_SITES "FTP Sites" + IDS_PRINTERS "Printers" + IDS_MDNSRESPONDER_NOT_AVAILABLE "Rendezvous Service Not Available" + IDS_FIREWALL "Check firewall settings" +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 + diff --git a/Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj b/Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj new file mode 100755 index 0000000..5aa578d --- /dev/null +++ b/Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Clients/ExplorerPlugin/ExplorerPluginRes.rc b/Clients/ExplorerPlugin/ExplorerPluginRes.rc new file mode 100755 index 0000000..fb9199d --- /dev/null +++ b/Clients/ExplorerPlugin/ExplorerPluginRes.rc @@ -0,0 +1,141 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource_res.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_res.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", "DNS-SD Explorer Bar Resource Module" + VALUE "FileVersion", MASTER_PROD_VERS_STR + VALUE "InternalName", "ExplorerPluginResources.dll" + VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT + VALUE "OriginalFilename", "ExplorerPluginResources.dll" + VALUE "ProductName", MASTER_PROD_NAME + VALUE "ProductVersion", MASTER_PROD_VERS_STR + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_LOGO BITMAP "res\\logo.bmp" +IDB_ABOUT BITMAP "res\\about.bmp" +IDB_GLOBE BITMAP "res\\globe.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" +#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 + diff --git a/Clients/ExplorerPlugin/ExplorerPluginRes.vcproj b/Clients/ExplorerPlugin/ExplorerPluginRes.vcproj new file mode 100755 index 0000000..31627b1 --- /dev/null +++ b/Clients/ExplorerPlugin/ExplorerPluginRes.vcproj @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Clients/ExplorerPlugin/Resource.h b/Clients/ExplorerPlugin/Resource.h index 2e56708..e6a7b32 100644 --- a/Clients/ExplorerPlugin/Resource.h +++ b/Clients/ExplorerPlugin/Resource.h @@ -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 index 0000000000000000000000000000000000000000..7e4949d1564e45706b661c0accf81b51c01c0e33 GIT binary patch literal 824 zcmbV}>q}E{7{^cfvNzSMq8AZGi1aR#u;@hvNhD%KB^Zg}EhR8#d0FHoa87M$%OqEB zQ@827ApC1M9Cy&v!KLA1wIjm~iv~5og25oLcwDv#ZXPCM#NcMi)h;z+tca@wx`hHPS zlA-SWLfb9(w}+nY>=j9lPnsXH%A*8^X?bpbmZRgIk$pw_GKJ;^PcFcW1XKMb+xu(w z_Ow+M+dtcl2(r+gJXhy~g|^!kRF(*~HCARhK1sRGcvG-zBgJu?f_t>9Kd^m|Ct+zBt?QDA{E>_+pYIwWD%= z@qMe9xxL|yked-Q0Fqd>qoXXdu#8`vu2GHvjNT746bk)SjPNQ7RA1^G(=yBjZ=xpa wnDEDE=GV%CDaH3V8E=3Eb=ZFo_3_y?+{zMeMTwxPc5+yXI-GIl5Df(V2bAAfQUCw| literal 0 HcmV?d00001 diff --git a/Clients/ExplorerPlugin/resource_dll.h b/Clients/ExplorerPlugin/resource_dll.h new file mode 100755 index 0000000..628228d --- /dev/null +++ b/Clients/ExplorerPlugin/resource_dll.h @@ -0,0 +1,26 @@ +//{{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 IDS_FIREWALL 111 +#define IDC_COMPONENT 1001 +#define IDC_LEGAL 1002 +#define IDC_LOGIN_USERNAME_TEXT 1182 +#define IDC_LOGIN_PASSWORD_TEXT 1183 +#define ID_Menu 40001 + +// 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 diff --git a/Clients/ExplorerPlugin/resource_loc_res.h b/Clients/ExplorerPlugin/resource_loc_res.h new file mode 100755 index 0000000..baf2213 --- /dev/null +++ b/Clients/ExplorerPlugin/resource_loc_res.h @@ -0,0 +1,32 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ExplorerPluginLocRes.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 IDS_FIREWALL 111 +#define IDD_ABOUT 118 +#define IDR_CONTEXT_MENU 120 +#define IDD_LOGIN 145 +#define IDC_ABOUT_BACKGROUND 146 +#define IDS_ABOUT 147 +#define IDS_ABOUT_URL 148 +#define IDC_COMPONENT 1001 +#define IDC_LEGAL 1002 +#define IDC_LOGIN_USERNAME_TEXT 1182 +#define IDC_LOGIN_PASSWORD_TEXT 1183 +#define ID_Menu 40001 + +// 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 diff --git a/Clients/ExplorerPlugin/resource_res.h b/Clients/ExplorerPlugin/resource_res.h new file mode 100755 index 0000000..b0217b3 --- /dev/null +++ b/Clients/ExplorerPlugin/resource_res.h @@ -0,0 +1,31 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ExplorerPluginRes.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 IDS_FIREWALL 111 +#define IDB_LOGO 115 +#define IDI_BUTTON_2K 115 +#define IDI_BUTTON_XP 118 +#define IDB_ABOUT 119 +#define IDB_GLOBE 149 +#define IDC_COMPONENT 1001 +#define IDC_LEGAL 1002 +#define IDC_LOGIN_USERNAME_TEXT 1182 +#define IDC_LOGIN_PASSWORD_TEXT 1183 +#define ID_Menu 40001 + +// 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 diff --git a/Clients/PrinterSetupWizard/FirstPage.cpp b/Clients/PrinterSetupWizard/FirstPage.cpp index c71faf5..530b26c 100644 --- a/Clients/PrinterSetupWizard/FirstPage.cpp +++ b/Clients/PrinterSetupWizard/FirstPage.cpp @@ -23,6 +23,10 @@ Change History (most recent first): $Log: FirstPage.cpp,v $ +Revision 1.3 2005/01/25 08:58:08 shersche + Load icons at run-time from resource DLLs +Bug #: 3911084 + Revision 1.2 2004/07/13 20:15:04 shersche Load large font name from resource Bug #: 3726363 @@ -37,6 +41,8 @@ First checked in #include "PrinterSetupWizardApp.h" #include "FirstPage.h" +#include + // 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); diff --git a/Clients/PrinterSetupWizard/FourthPage.cpp b/Clients/PrinterSetupWizard/FourthPage.cpp index c4ccc52..8c330df 100644 --- a/Clients/PrinterSetupWizard/FourthPage.cpp +++ b/Clients/PrinterSetupWizard/FourthPage.cpp @@ -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 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) { diff --git a/Clients/PrinterSetupWizard/FourthPage.h b/Clients/PrinterSetupWizard/FourthPage.h index 78bbf52..b488e20 100644 --- a/Clients/PrinterSetupWizard/FourthPage.h +++ b/Clients/PrinterSetupWizard/FourthPage.h @@ -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; }; diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizard.rc b/Clients/PrinterSetupWizard/PrinterSetupWizard.rc index f099a44..4899ef7 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizard.rc +++ b/Clients/PrinterSetupWizard/PrinterSetupWizard.rc @@ -1,6 +1,6 @@ // Microsoft Visual C++ generated resource script. // -#include "resource.h" +#include "resource_exe.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// @@ -30,7 +30,7 @@ LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT 1 TEXTINCLUDE BEGIN - "resource.h\0" + "resource_exe.h\0" END 2 TEXTINCLUDE @@ -79,131 +79,6 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDR_MAINFRAME ICON "res\\Print.ico" -IDI_INFO ICON "res\\Info.ico" -IDI_PRINTER ICON "res\\NetworkPrinter.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// Bitmap -// - -IDB_WATERMARK BITMAP "res\\watermark.bmp" -IDB_BANNER_ICON BITMAP "res\\banner_icon.bmp" -IDB_ABOUT BITMAP "res\\about.bmp" - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | - WS_SYSMENU -CAPTION "About Printer Setup Wizard" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20 - LTEXT "Printer Setup Wizard Version 1.0",IDC_STATIC,40,10,119, - 8,SS_NOPREFIX - LTEXT "Copyright (C) 2002",IDC_STATIC,40,25,119,8 - DEFPUSHBUTTON "OK",IDOK,178,7,50,16,WS_GROUP -END - -IDD_PRINTERSETUPWIZARD_DIALOG DIALOGEX 0, 0, 320, 200 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | - WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_APPWINDOW -CAPTION "Printer Setup Wizard" -FONT 8, "MS Shell Dlg", 0, 0, 0x1 -BEGIN - DEFPUSHBUTTON "OK",IDOK,263,7,50,16 - PUSHBUTTON "Cancel",IDCANCEL,263,25,50,16 - PUSHBUTTON "Start Wizard",IDC_BUTTON1,100,86,109,35 -END - -IDD_SECOND_PAGE DIALOGEX 0, 0, 290, 154 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION -CAPTION "Rendezvous Printer Wizard" -FONT 8, "MS Shell Dlg", 0, 0, 0x0 -BEGIN - LTEXT "Shared Printers:",IDC_STATIC,3,0,171,8 - CONTROL "",IDC_BROWSE_LIST,"SysTreeView32",TVS_DISABLEDRAGDROP | - TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | WS_BORDER | - WS_TABSTOP,2,11,286,142 -END - -IDD_FIRST_PAGE DIALOGEX 0, 0, 290, 199 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION -CAPTION "Rendezvous Printer Wizard" -FONT 8, "MS Shell Dlg", 0, 0, 0x0 -BEGIN - LTEXT "Welcome to the Rendezvous Printer Setup Wizard",IDC_GREETING, - 114,7,171,46 - LTEXT "Click next to continue.",IDC_STATIC,115,188,143,8 - LTEXT "This wizard helps you connect to a shared printer using Rendezvous. Make sure your printer is turned on and connected to your network.", - IDC_STATIC,146,60,139,62 - ICON IDI_INFO,IDC_STATIC,118,60,21,20,SS_REALSIZEIMAGE, - WS_EX_TRANSPARENT -END - -IDD_THIRD_PAGE DIALOGEX 0, 0, 290, 154 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | - WS_SYSMENU -CAPTION "Rendezvous Printer Wizard" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL "",IDC_PRINTER_MODEL,"SysListView32",LVS_REPORT | - LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | - LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,110,58,178,76 - CONTROL "",IDC_PRINTER_MANUFACTURER,"SysListView32",LVS_REPORT | - LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | - LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,58,105,76 - ICON IDI_PRINTER,IDC_PRINTER_IMAGE,1,0,21,20,SS_REALSIZEIMAGE - LTEXT "",IDC_PRINTER_NAME,40,5,173,8 - LTEXT "The Rendezvous Printer Wizard has auto-selected the following printer settings. Click 'Next' to continue installing this printer.", - IDC_PRINTER_SELECTION_TEXT,40,23,243,26 - CONTROL "Use this printer as the default printer", - IDC_DEFAULT_PRINTER,"Button",BS_AUTOCHECKBOX | - WS_TABSTOP,3,142,224,10 - PUSHBUTTON "Have Disk...",IDC_HAVE_DISK,238,140,50,14 -END - -IDD_FOURTH_PAGE DIALOGEX 0, 0, 290, 199 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION -CAPTION "Rendezvous Printer Wizard" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - LTEXT "Completing the Rendezvous Printer Wizard",IDC_GOODBYE, - 116,7,171,27 - LTEXT "You have successfully completed the Rendezvous Printer Wizard. The printer has the following settings:", - IDC_STATIC,116,42,158,31 - LTEXT "Name:",IDC_STATIC,116,78,22,8 - LTEXT "Manufacturer:",IDC_STATIC,116,91,47,8 - LTEXT "Model:",IDC_STATIC,116,104,22,8 - LTEXT "Port:",IDC_STATIC,116,117,17,8 - LTEXT "Default:",IDC_STATIC,116,130,27,8 - LTEXT "",IDC_PRINTER_NAME,172,79,113,8 - LTEXT "",IDC_PRINTER_MANUFACTURER,172,91,113,8 - LTEXT "",IDC_PRINTER_MODEL,172,103,113,8 - LTEXT "",IDC_PRINTER_PORT,172,116,113,8 - LTEXT "",IDC_PRINTER_DEFAULT,172,130,113,8 - LTEXT "To close this wizard, click Finish.",IDC_STATIC,116,187, - 103,8 -END - -IDD_DIALOG1 DIALOGEX 0, 0, 265, 130 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | - WS_SYSMENU -CAPTION "Dialog" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - CONTROL 138,IDC_STATIC,"Static",SS_BITMAP | SS_REALSIZEIMAGE,0,0, - 265,131 - LTEXT "Static",IDC_STATIC,77,12,19,8 - LTEXT "Static",IDC_STATIC,71,46,19,8 - LTEXT "Static",IDC_STATIC,71,89,19,8 -END - ///////////////////////////////////////////////////////////////////////////// // @@ -231,7 +106,7 @@ BEGIN VALUE "FileDescription", "Rendezvous Printer Wizard" VALUE "FileVersion", MASTER_PROD_VERS_STR VALUE "InternalName", "RendezvousPrinterWizard.exe" - VALUE "LegalCopyright", "Copyright (C) 2003-2004 Apple Computer, Inc." + VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT VALUE "OriginalFilename", "RendezvousPrinterWizard.exe" VALUE "ProductName", MASTER_PROD_NAME VALUE "ProductVersion", MASTER_PROD_VERS_STR @@ -244,34 +119,6 @@ BEGIN END -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_SECOND_PAGE, DIALOG - BEGIN - BOTTOMMARGIN, 153 - END - - IDD_FIRST_PAGE, DIALOG - BEGIN - RIGHTMARGIN, 285 - BOTTOMMARGIN, 196 - END - - IDD_FOURTH_PAGE, DIALOG - BEGIN - RIGHTMARGIN, 285 - BOTTOMMARGIN, 197 - END -END -#endif // APSTUDIO_INVOKED - - ///////////////////////////////////////////////////////////////////////////// // // RT_MANIFEST @@ -286,37 +133,8 @@ IDR_MANIFEST RT_MANIFEST "res\\PrinterSetupWizard.manifes STRINGTABLE BEGIN - IDS_ABOUTBOX "&About Printer Setup Wizard..." - IDS_GOODBYE "Completing the Rendezvous Printer Setup Wizard." - IDS_GREETING "Welcome to the Rendezvous Printer Setup Wizard" - IDS_BROWSE_TITLE "Browse for Rendezvous Printers" - IDS_BROWSE_SUBTITLE "Select the printer you want to use from the list below." - IDS_CAPTION "Rendezvous Printer Wizard" - IDS_GOODBYE_GOOD1 "You have successfully completed the Rendezvous Printer Wizard. The printer has the following settings:" - IDS_SEARCHING "Searching for printers..." - IDS_GOODBYTE_GOOD2 "To close this wizard, click Finish." - IDS_INSTALL_TITLE "Install Rendezvous Printer" - IDS_INSTALL_SUBTITLE "The manufacturer and model determine which printer software to use." -END - -STRINGTABLE -BEGIN - IDS_ERROR_SELECTING_PRINTER_TEXT - "There was an error selecting this printer." - IDS_ERROR_SELECTING_PRINTER_CAPTION "Error" - IDS_INSTALL_ERROR_CAPTION "Error" - IDS_INSTALL_ERROR_MESSAGE - "You do not have sufficient access to your computer to connect to the selected printer." - IDS_MANUFACTURER_HEADING "Manufacturer" - IDS_MODEL_HEADING "Model" - IDS_NO_RENDEZVOUS_PRINTERS "No Rendezvous Printers are available" - IDS_NO_MDNSRESPONDER_SERVICE_TEXT "Rendezvous Service is not available" - IDS_NO_MDNSRESPONDER_SERVICE_CAPTION "Error" - IDS_PRINTER_MATCH_GOOD "The Rendezvous Printer Wizard has auto-selected the following printer settings. Click 'Next' to continue installing this printer." - 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. " - IDS_YES "Yes" - IDS_NO "No" - IDS_LARGE_FONT "MS Sans Serif" + IDS_REINSTALL "Rendezvous Printer Wizard cannot run because some of its required files are missing. Please reinstall Rendezvous Printer Wizard." + IDS_REINSTALL_CAPTION "Rendezvous Printer Wizard" END #endif // English (U.S.) resources diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj b/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj index 280c398..c26dc3e 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj +++ b/Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj @@ -1,269 +1,274 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp index 295b4a9..37b6228 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp @@ -23,6 +23,13 @@ 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 + Load resource DLLs at startup. +Bug #: 3911084 + Revision 1.3 2004/07/13 21:24:23 rpantos Fix for . @@ -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 ); + + AfxSetResourceHandle( g_localizedResources ); // 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 diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardApp.h b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.h index aa3f233..871de5d 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizardApp.h +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardApp.h @@ -23,6 +23,10 @@ Change History (most recent first): $Log: PrinterSetupWizardApp.h,v $ +Revision 1.2 2005/01/25 08:52:55 shersche + 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 index 0000000..521b2ef --- /dev/null +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc @@ -0,0 +1,303 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource_loc_res.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" +#include "WinVersRes.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Russian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +#ifdef _WIN32 +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource_loc_res.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 ""res\\PrinterSetupWizardLocRes.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Russian resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// 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 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "About Printer Setup Wizard" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + ICON 128,IDC_STATIC,11,17,20,20 + LTEXT "Printer Setup Wizard Version 1.0",IDC_STATIC,40,10,119, + 8,SS_NOPREFIX + LTEXT "Copyright (C) 2002",IDC_STATIC,40,25,119,8 + DEFPUSHBUTTON "OK",IDOK,178,7,50,16,WS_GROUP +END + +IDD_PRINTERSETUPWIZARD_DIALOG DIALOGEX 0, 0, 320, 200 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | + WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "Printer Setup Wizard" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,263,7,50,16 + PUSHBUTTON "Cancel",IDCANCEL,263,25,50,16 + PUSHBUTTON "Start Wizard",IDC_BUTTON1,100,86,109,35 +END + +IDD_SECOND_PAGE DIALOGEX 0, 0, 290, 154 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Rendezvous Printer Wizard" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "Shared printers:",IDC_STATIC,3,0,171,8 + CONTROL "",IDC_BROWSE_LIST,"SysTreeView32",TVS_DISABLEDRAGDROP | + TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | WS_BORDER | + WS_TABSTOP,2,11,286,101 + LTEXT "Description:",IDC_DESCRIPTION_LABEL,13,128,39,8 + LTEXT "Location:",IDC_LOCATION_LABEL,13,139,30,8 + GROUPBOX "Printer information",IDC_PRINTER_INFORMATION,2,116,286, + 37 + LTEXT "",IDC_DESCRIPTION_FIELD,57,128,226,8 + LTEXT "",IDC_LOCATION_FIELD,57,139,226,8 +END + +IDD_FIRST_PAGE DIALOGEX 0, 0, 290, 199 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Rendezvous Printer Wizard" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "Welcome to the Rendezvous Printer Setup Wizard", + IDC_GREETING,114,7,171,46 + LTEXT "Click next to continue.",IDC_STATIC,115,188,143,8 + LTEXT "This wizard helps you connect to a shared printer using Rendezvous. Make sure your printer is turned on and connected to your network.", + IDC_STATIC,146,60,139,62 + ICON "",IDC_INFO,118,60,20,20,SS_REALSIZEIMAGE +END + +IDD_THIRD_PAGE DIALOGEX 0, 0, 290, 154 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "Rendezvous Printer Wizard" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_PRINTER_MODEL,"SysListView32",LVS_REPORT | + LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | + LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,110,58,178,76 + CONTROL "",IDC_PRINTER_MANUFACTURER,"SysListView32",LVS_REPORT | + LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | + LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,58,105,76 + ICON 1017,1,0,0,20,27 + LTEXT "",IDC_PRINTER_NAME,40,5,173,8 + LTEXT "The Rendezvous Printer Wizard has auto-selected the following printer settings. Click 'Next' to continue installing this printer.", + IDC_PRINTER_SELECTION_TEXT,40,23,243,26 + CONTROL "Use this printer as the default printer", + IDC_DEFAULT_PRINTER,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,3,142,224,10 + PUSHBUTTON "Have Disk...",IDC_HAVE_DISK,238,140,50,14 +END + +IDD_FOURTH_PAGE DIALOGEX 0, 0, 290, 199 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Rendezvous Printer Wizard" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "Completing the Rendezvous Printer Wizard",IDC_GOODBYE, + 116,7,171,27 + LTEXT "You have successfully completed the Rendezvous Printer Wizard. The printer has the following settings:", + IDC_STATIC,116,42,158,31 + LTEXT "Name:",IDC_STATIC,116,78,22,8 + LTEXT "Manufacturer:",IDC_STATIC,116,91,47,8 + LTEXT "Model:",IDC_STATIC,116,104,22,8 + LTEXT "Protocol:",IDC_STATIC,116,117,38,8 + LTEXT "Default:",IDC_STATIC,116,130,27,8 + LTEXT "",IDC_PRINTER_NAME,172,78,113,8 + LTEXT "",IDC_PRINTER_MANUFACTURER,172,91,113,8 + LTEXT "",IDC_PRINTER_MODEL,172,104,113,8 + LTEXT "",IDC_PRINTER_PROTOCOL,172,117,113,8 + LTEXT "",IDC_PRINTER_DEFAULT,172,130,113,8 + LTEXT "To close this wizard, click Finish.",IDC_STATIC,116,187, + 103,8 +END + +IDD_DIALOG1 DIALOGEX 0, 0, 265, 130 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL 138,IDC_STATIC,"Static",SS_BITMAP | SS_REALSIZEIMAGE,0,0, + 265,131 + LTEXT "Static",IDC_STATIC,77,12,19,8 + LTEXT "Static",IDC_STATIC,71,46,19,8 + LTEXT "Static",IDC_STATIC,71,89,19,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// 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 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "Apple Computer, Inc." + VALUE "FileDescription", "Rendezvous Printer Wizard Resource Module" + VALUE "FileVersion", MASTER_PROD_VERS_STR + VALUE "InternalName", "RendezvousPrinterWizardLocalized.dll" + VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT + VALUE "OriginalFilename", "RendezvousPrinterWizardLocalized.dll" + VALUE "ProductName", MASTER_PROD_NAME + VALUE "ProductVersion", MASTER_PROD_VERS_STR + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_ABOUTBOX "&About Printer Setup Wizard..." + IDS_GOODBYE "Completing the Rendezvous Printer Setup Wizard." + IDS_GREETING "Welcome to the Rendezvous Printer Setup Wizard" + IDS_BROWSE_TITLE "Browse for Rendezvous Printers" + IDS_BROWSE_SUBTITLE "Select the printer you want to use from the list below." + IDS_CAPTION "Rendezvous Printer Wizard" + IDS_GOODBYE_GOOD1 "You have successfully completed the Rendezvous Printer Wizard. The printer has the following settings:" + IDS_SEARCHING "Searching for printers..." + IDS_GOODBYTE_GOOD2 "To close this wizard, click Finish." + IDS_INSTALL_TITLE "Install Rendezvous Printer" + IDS_INSTALL_SUBTITLE "The manufacturer and model determine which printer software to use." +END + +STRINGTABLE +BEGIN + IDS_ERROR_SELECTING_PRINTER_TEXT + "There was an error selecting this printer." + IDS_ERROR_SELECTING_PRINTER_CAPTION "Error" + IDS_INSTALL_ERROR_CAPTION "Error" + IDS_INSTALL_ERROR_MESSAGE + "You do not have sufficient access to your computer to connect to the selected printer." + IDS_MANUFACTURER_HEADING "Manufacturer" + IDS_MODEL_HEADING "Model" + IDS_NO_RENDEZVOUS_PRINTERS "No Rendezvous Printers are available" + IDS_NO_MDNSRESPONDER_SERVICE_TEXT "Rendezvous Service is not available." + IDS_NO_MDNSRESPONDER_SERVICE_CAPTION "Error" + IDS_PRINTER_MATCH_GOOD "The Rendezvous Printer Wizard has auto-selected the following printer settings. Click 'Next' to continue installing this printer." + 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. " + IDS_YES "Yes" + IDS_NO "No" + IDS_LARGE_FONT "MS Sans Serif" + IDS_FIREWALL "Please check firewall setting to ensure the Rendezvous Printer Wizard operates correctly." + IDS_ERROR_CAPTION "Error" +END + +STRINGTABLE +BEGIN + IDS_FIREWALL_CAPTION "Firewall Detected" +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 "res\PrinterSetupWizardLocRes.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj new file mode 100755 index 0000000..e7d0271 --- /dev/null +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardRes.rc b/Clients/PrinterSetupWizard/PrinterSetupWizardRes.rc new file mode 100755 index 0000000..9a38621 --- /dev/null +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardRes.rc @@ -0,0 +1,173 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource_res.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" +#include "WinVersRes.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Russian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +#ifdef _WIN32 +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource_res.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 ""res\\PrinterSetupWizardRes.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Russian resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// 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 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDR_MAINFRAME ICON "res\\Print.ico" +IDI_INFO ICON "res\\Info.ico" +IDI_PRINTER ICON "res\\NetworkPrinter.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_WATERMARK BITMAP "res\\watermark.bmp" +IDB_BANNER_ICON BITMAP "res\\banner_icon.bmp" +IDB_ABOUT BITMAP "res\\about.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + + + +///////////////////////////////////////////////////////////////////////////// +// +// 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 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "Apple Computer, Inc." + VALUE "FileDescription", "Rendezvous Printer Wizard Resource Module" + VALUE "FileVersion", MASTER_PROD_VERS_STR + VALUE "InternalName", "RendezvousPrinterWizardLocalized.dll" + VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT + VALUE "OriginalFilename", "RendezvousPrinterWizardLocalized.dll" + VALUE "ProductName", MASTER_PROD_NAME + VALUE "ProductVersion", MASTER_PROD_VERS_STR + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +#endif // APSTUDIO_INVOKED + + +#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 "res\PrinterSetupWizardRes.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj b/Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj new file mode 100755 index 0000000..f3591f0 --- /dev/null +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp index 02b2952..6b026e1 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp @@ -23,6 +23,23 @@ 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 + + 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 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 ( 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( 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 ); - - // - // 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 ); // - // 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; } diff --git a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h index e1077aa..be4bd6a 100644 --- a/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h +++ b/Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h @@ -23,6 +23,14 @@ 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 + + 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 . @@ -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 PrinterList; - typedef std::list EventHandlerList; - typedef std::list ServiceRefList; - typedef std::map 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." diff --git a/Clients/PrinterSetupWizard/SecondPage.cpp b/Clients/PrinterSetupWizard/SecondPage.cpp index abf4fa0..9e3720a 100644 --- a/Clients/PrinterSetupWizard/SecondPage.cpp +++ b/Clients/PrinterSetupWizard/SecondPage.cpp @@ -23,6 +23,31 @@ 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 + Remove references to description key +Bug #: 3906182 + +Revision 1.5 2004/12/30 01:02:47 shersche + 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 + + 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 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 // 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(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 ); + while ( item ) + { + Printer * printer; + DWORD_PTR data; + + data = m_browseList.GetItemData( item ); + printer = reinterpret_cast(data); + + if ( printer && ( printer->name == inName ) ) + { + return printer; + } + + item = m_browseList.GetNextItem( item, TVGN_NEXT ); + } - psheet = reinterpret_cast(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(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(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(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(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(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); + DDX_Control(pDX, IDC_DESCRIPTION_LABEL, m_descriptionLabel); + DDX_Control(pDX, IDC_DESCRIPTION_FIELD, m_descriptionField); + DDX_Control(pDX, IDC_LOCATION_LABEL, m_locationLabel); + DDX_Control(pDX, IDC_LOCATION_FIELD, m_locationField); +} - 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(GetParent()); - require_action( psheet, exit, err = kUnknownErr ); + require_quiet( psheet, exit ); - Printer * printer; + SetCursor(psheet->GetCursor()); - printer = reinterpret_cast(m_browseList.GetItemData( item ) ); - require_quiet( printer, exit ); +exit: + + return TRUE; +} + + +BOOL +CSecondPage::OnSetActive() +{ + CPrinterSetupWizardSheet * psheet; + Printer * printer; + OSStatus err = kNoErr; + + psheet = reinterpret_cast(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(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 ( 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( 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 ); + + // + // 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( 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(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(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(pNMHDR); + CPrinterSetupWizardSheet * psheet; + int err = 0; + + HTREEITEM item = m_browseList.GetSelectedItem(); + require_quiet( item, exit ); + + psheet = reinterpret_cast(GetParent()); + require_action( psheet, exit, err = kUnknownErr ); + + Printer * printer; + + printer = reinterpret_cast(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 ); + m_descriptionLabel.EnableWindow( state ); + m_descriptionField.EnableWindow( state ); + m_locationLabel.EnableWindow( state ); + m_locationField.EnableWindow( state ); +} + + +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; +} + + diff --git a/Clients/PrinterSetupWizard/SecondPage.h b/Clients/PrinterSetupWizard/SecondPage.h index 45c55c9..9d9c4fb 100644 --- a/Clients/PrinterSetupWizard/SecondPage.h +++ b/Clients/PrinterSetupWizard/SecondPage.h @@ -23,6 +23,21 @@ 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 + 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 + + 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 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 PrinterNameMap; + typedef std::list ServiceRefList; + typedef std::list 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; + +private: + + CStatic m_printerInformation; + CStatic m_descriptionLabel; + CStatic m_descriptionField; + CStatic m_locationLabel; + CStatic m_locationField; }; diff --git a/Clients/PrinterSetupWizard/ThirdPage.cpp b/Clients/PrinterSetupWizard/ThirdPage.cpp index 6828f3c..76978cd 100644 --- a/Clients/PrinterSetupWizard/ThirdPage.cpp +++ b/Clients/PrinterSetupWizard/ThirdPage.cpp @@ -23,6 +23,22 @@ Change History (most recent first): $Log: ThirdPage.cpp,v $ +Revision 1.14 2005/01/25 08:55:54 shersche + 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 + 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 + + 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 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(printer->hostname), printer->portNumber); + + if ( service->type == kPDLServiceType ) + { + printer->portName.Format(L"IP_%s.%d", static_cast(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(service->hostname), service->portNumber, static_cast(q->name) ); + } + else + { + printer->portName.Format(L"LPR_%s.%d", static_cast(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(service->hostname), service->portNumber, static_cast(q->name) ); + } + else + { + printer->portName.Format(L"http://%s:%d/", static_cast(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; } + + // + // + // 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 + + 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); } @@ -1021,6 +1120,7 @@ CThirdPage::OnSetActive() { CPrinterSetupWizardSheet * psheet; Printer * printer; + Service * service; psheet = reinterpret_cast(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(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: diff --git a/Clients/PrinterSetupWizard/ThirdPage.h b/Clients/PrinterSetupWizard/ThirdPage.h index dfdb69d..b775fb8 100644 --- a/Clients/PrinterSetupWizard/ThirdPage.h +++ b/Clients/PrinterSetupWizard/ThirdPage.h @@ -23,6 +23,15 @@ Change History (most recent first): $Log: ThirdPage.h,v $ +Revision 1.3 2005/01/25 08:57:28 shersche + Add m_printerControl member for dynamic loading of icons from resource DLLs +Bug #: 3911084 + +Revision 1.2 2004/12/29 18:53:38 shersche + + 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(); }; diff --git a/Clients/PrinterSetupWizard/UtilTypes.h b/Clients/PrinterSetupWizard/UtilTypes.h index f702ebc..11042dd 100644 --- a/Clients/PrinterSetupWizard/UtilTypes.h +++ b/Clients/PrinterSetupWizard/UtilTypes.h @@ -23,6 +23,21 @@ 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 + Remove references to description key +Bug #: 3906182 + +Revision 1.5 2004/12/29 18:53:38 shersche + + 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 Add moreComing argument to OnAddPrinter and OnRemovePrinter callbacks Bug #: 3796483 @@ -43,45 +58,54 @@ First checked in #pragma once #include +#include #include +#include -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 TextRecord; + + typedef std::list Queues; + typedef std::list Services; typedef std::list 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 index 0000000..27e049a --- /dev/null +++ b/Clients/PrinterSetupWizard/res/PrinterSetupWizardLocRes.rc2 @@ -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 index 0000000..27e049a --- /dev/null +++ b/Clients/PrinterSetupWizard/res/PrinterSetupWizardRes.rc2 @@ -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/resource.h b/Clients/PrinterSetupWizard/resource.h index 8c2a6ca..5d21d40 100644 --- a/Clients/PrinterSetupWizard/resource.h +++ b/Clients/PrinterSetupWizard/resource.h @@ -1,74 +1,38 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by PrinterSetupWizard.rc -// -#define IDR_MANIFEST 1 -#define IDM_ABOUTBOX 0x0010 -#define IDD_ABOUTBOX 100 -#define IDS_ABOUTBOX 101 -#define IDD_PRINTERSETUPWIZARD_DIALOG 102 -#define IDS_GOODBYE 102 -#define IDS_GREETING 103 -#define IDS_BROWSE_TITLE 104 -#define IDS_BROWSE_SUBTITLE 105 -#define IDS_CAPTION 106 -#define IDD_FIRST_PAGE 107 -#define IDS_GOODBYE_GOOD1 107 -#define IDS_SEARCHING 108 -#define IDD_SECOND_PAGE 109 -#define IDS_GOODBYTE_GOOD2 109 -#define IDS_INSTALL_TITLE 110 -#define IDS_INSTALL_SUBTITLE 111 -#define IDS_ERROR_SELECTING_PRINTER_TEXT 112 -#define IDS_ERROR_SELECTING_PRINTER_CAPTION 113 -#define IDS_INSTALL_ERROR_CAPTION 114 -#define IDS_INSTALL_ERROR_MESSAGE 115 -#define IDS_MANUFACTURER_HEADING 116 -#define IDS_MODEL_HEADING 117 -#define IDS_NO_RENDEZVOUS_PRINTERS 118 -#define IDS_NO_MDNSRESPONDER_SERVICE_TEXT 119 -#define IDS_NO_MDNSRESPONDER_SERVICE_CAPTION 120 -#define IDS_PRINTER_MATCH_GOOD 121 -#define IDS_PRINTER_MATCH_BAD 122 -#define IDS_YES 123 -#define IDS_NO 124 -#define IDS_LARGE_FONT 125 -#define IDR_MAINFRAME 128 -#define IDB_BANNER_ICON 129 -#define IDD_THIRD_PAGE 130 -#define IDB_WATERMARK 131 -#define IDD_FOURTH_PAGE 132 -#define IDI_INFO 136 -#define IDB_ABOUT 138 -#define IDD_DIALOG1 139 -#define IDI_ICON2 141 -#define IDI_PRINTER 141 -#define IDC_BUTTON1 1000 -#define IDC_LIST1 1000 -#define IDC_BROWSE_LIST 1000 -#define IDC_RADIO1 1001 -#define IDC_COMBO1 1001 -#define IDC_RADIO2 1002 -#define IDC_GREETING 1003 -#define IDC_CHECK1 1016 -#define IDC_DEFAULT_PRINTER 1016 -#define IDC_PRINTER_IMAGE 1017 -#define IDC_PRINTER_NAME 1018 -#define IDC_PRINTER_MANUFACTURER 1019 -#define IDC_PRINTER_MODEL 1020 -#define IDC_GOODBYE 1021 -#define IDC_PRINTER_PORT 1022 -#define IDC_PRINTER_DEFAULT 1023 -#define IDC_PRINTER_SELECTION_TEXT 1024 -#define IDC_HAVE_DISK 1025 +/* + * Copyright (c) 1997-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 142 -#define _APS_NEXT_COMMAND_VALUE 32771 -#define _APS_NEXT_CONTROL_VALUE 1026 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif + Change History (most recent first): + + */ + + +// Include resources for Wizard app + +#include "resource_exe.h" + +// Include resources for non-localizable resource DLL + +#include "resource_res.h" + +// Include resources for localizable resource DLL + +#include "resource_loc_res.h" diff --git a/Clients/PrinterSetupWizard/resource_exe.h b/Clients/PrinterSetupWizard/resource_exe.h new file mode 100755 index 0000000..c0f5429 --- /dev/null +++ b/Clients/PrinterSetupWizard/resource_exe.h @@ -0,0 +1,85 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by PrinterSetupWizard.rc +// +#define IDR_MANIFEST 1 +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_PRINTERSETUPWIZARD_DIALOG 102 +#define IDS_GOODBYE 102 +#define IDS_GREETING 103 +#define IDS_BROWSE_TITLE 104 +#define IDS_BROWSE_SUBTITLE 105 +#define IDS_CAPTION 106 +#define IDD_FIRST_PAGE 107 +#define IDS_GOODBYE_GOOD1 107 +#define IDS_SEARCHING 108 +#define IDD_SECOND_PAGE 109 +#define IDS_GOODBYTE_GOOD2 109 +#define IDS_INSTALL_TITLE 110 +#define IDS_INSTALL_SUBTITLE 111 +#define IDS_ERROR_SELECTING_PRINTER_TEXT 112 +#define IDS_ERROR_SELECTING_PRINTER_CAPTION 113 +#define IDS_INSTALL_ERROR_CAPTION 114 +#define IDS_INSTALL_ERROR_MESSAGE 115 +#define IDS_MANUFACTURER_HEADING 116 +#define IDS_MODEL_HEADING 117 +#define IDS_NO_RENDEZVOUS_PRINTERS 118 +#define IDS_NO_MDNSRESPONDER_SERVICE_TEXT 119 +#define IDS_NO_MDNSRESPONDER_SERVICE_CAPTION 120 +#define IDS_PRINTER_MATCH_GOOD 121 +#define IDS_PRINTER_MATCH_BAD 122 +#define IDS_YES 123 +#define IDS_NO 124 +#define IDS_LARGE_FONT 125 +#define IDS_FIREWALL 126 +#define IDS_ERROR_CAPTION 127 +#define IDR_MAINFRAME 128 +#define IDS_FIREWALL_CAPTION 128 +#define IDB_BANNER_ICON 129 +#define IDD_THIRD_PAGE 130 +#define IDB_WATERMARK 131 +#define IDD_FOURTH_PAGE 132 +#define IDI_INFO 136 +#define IDB_ABOUT 138 +#define IDD_DIALOG1 139 +#define IDI_ICON2 141 +#define IDI_PRINTER 141 +#define IDS_REINSTALL 142 +#define IDS_REINSTALL_CAPTION 143 +#define IDC_BUTTON1 1000 +#define IDC_LIST1 1000 +#define IDC_BROWSE_LIST 1000 +#define IDC_RADIO1 1001 +#define IDC_COMBO1 1001 +#define IDC_RADIO2 1002 +#define IDC_GREETING 1003 +#define IDC_CHECK1 1016 +#define IDC_DEFAULT_PRINTER 1016 +#define IDC_PRINTER_IMAGE 1017 +#define IDC_PRINTER_NAME 1018 +#define IDC_PRINTER_MANUFACTURER 1019 +#define IDC_PRINTER_MODEL 1020 +#define IDC_GOODBYE 1021 +#define IDC_PRINTER_PORT 1022 +#define IDC_PRINTER_PROTOCOL 1022 +#define IDC_PRINTER_DEFAULT 1023 +#define IDC_PRINTER_SELECTION_TEXT 1024 +#define IDC_HAVE_DISK 1025 +#define IDC_PRINTER_INFORMATION 1026 +#define IDC_LOCATION_LABEL 1029 +#define IDC_DESCRIPTION_FIELD 1030 +#define IDC_LOCATION_FIELD 1032 +#define IDC_DESCRIPTION_LABEL 1033 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 142 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1034 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Clients/PrinterSetupWizard/resource_loc_res.h b/Clients/PrinterSetupWizard/resource_loc_res.h new file mode 100755 index 0000000..7f77da3 --- /dev/null +++ b/Clients/PrinterSetupWizard/resource_loc_res.h @@ -0,0 +1,86 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by PrinterSetupWizardLocRes.rc +// +#define IDR_MANIFEST 1 +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_PRINTERSETUPWIZARD_DIALOG 102 +#define IDS_GOODBYE 102 +#define IDS_GREETING 103 +#define IDS_BROWSE_TITLE 104 +#define IDS_BROWSE_SUBTITLE 105 +#define IDS_CAPTION 106 +#define IDD_FIRST_PAGE 107 +#define IDS_GOODBYE_GOOD1 107 +#define IDS_SEARCHING 108 +#define IDD_SECOND_PAGE 109 +#define IDS_GOODBYTE_GOOD2 109 +#define IDS_INSTALL_TITLE 110 +#define IDS_INSTALL_SUBTITLE 111 +#define IDS_ERROR_SELECTING_PRINTER_TEXT 112 +#define IDS_ERROR_SELECTING_PRINTER_CAPTION 113 +#define IDS_INSTALL_ERROR_CAPTION 114 +#define IDS_INSTALL_ERROR_MESSAGE 115 +#define IDS_MANUFACTURER_HEADING 116 +#define IDS_MODEL_HEADING 117 +#define IDS_NO_RENDEZVOUS_PRINTERS 118 +#define IDS_NO_MDNSRESPONDER_SERVICE_TEXT 119 +#define IDS_NO_MDNSRESPONDER_SERVICE_CAPTION 120 +#define IDS_PRINTER_MATCH_GOOD 121 +#define IDS_PRINTER_MATCH_BAD 122 +#define IDS_YES 123 +#define IDS_NO 124 +#define IDS_LARGE_FONT 125 +#define IDS_FIREWALL 126 +#define IDS_ERROR_CAPTION 127 +#define IDR_MAINFRAME 128 +#define IDS_FIREWALL_CAPTION 128 +#define IDB_BANNER_ICON 129 +#define IDD_THIRD_PAGE 130 +#define IDB_WATERMARK 131 +#define IDD_FOURTH_PAGE 132 +#define IDI_INFO 136 +#define IDB_ABOUT 138 +#define IDD_DIALOG1 139 +#define IDI_ICON2 141 +#define IDI_PRINTER 141 +#define IDS_REINSTALL 142 +#define IDS_REINSTALL_CAPTION 143 +#define IDC_INFO 144 +#define IDC_BUTTON1 1000 +#define IDC_LIST1 1000 +#define IDC_BROWSE_LIST 1000 +#define IDC_RADIO1 1001 +#define IDC_COMBO1 1001 +#define IDC_RADIO2 1002 +#define IDC_GREETING 1003 +#define IDC_CHECK1 1016 +#define IDC_DEFAULT_PRINTER 1016 +#define IDC_PRINTER_IMAGE 1017 +#define IDC_PRINTER_NAME 1018 +#define IDC_PRINTER_MANUFACTURER 1019 +#define IDC_PRINTER_MODEL 1020 +#define IDC_GOODBYE 1021 +#define IDC_PRINTER_PORT 1022 +#define IDC_PRINTER_PROTOCOL 1022 +#define IDC_PRINTER_DEFAULT 1023 +#define IDC_PRINTER_SELECTION_TEXT 1024 +#define IDC_HAVE_DISK 1025 +#define IDC_PRINTER_INFORMATION 1026 +#define IDC_LOCATION_LABEL 1029 +#define IDC_DESCRIPTION_FIELD 1030 +#define IDC_LOCATION_FIELD 1032 +#define IDC_DESCRIPTION_LABEL 1033 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 142 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1034 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Clients/PrinterSetupWizard/resource_res.h b/Clients/PrinterSetupWizard/resource_res.h new file mode 100755 index 0000000..c0f5429 --- /dev/null +++ b/Clients/PrinterSetupWizard/resource_res.h @@ -0,0 +1,85 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by PrinterSetupWizard.rc +// +#define IDR_MANIFEST 1 +#define IDM_ABOUTBOX 0x0010 +#define IDD_ABOUTBOX 100 +#define IDS_ABOUTBOX 101 +#define IDD_PRINTERSETUPWIZARD_DIALOG 102 +#define IDS_GOODBYE 102 +#define IDS_GREETING 103 +#define IDS_BROWSE_TITLE 104 +#define IDS_BROWSE_SUBTITLE 105 +#define IDS_CAPTION 106 +#define IDD_FIRST_PAGE 107 +#define IDS_GOODBYE_GOOD1 107 +#define IDS_SEARCHING 108 +#define IDD_SECOND_PAGE 109 +#define IDS_GOODBYTE_GOOD2 109 +#define IDS_INSTALL_TITLE 110 +#define IDS_INSTALL_SUBTITLE 111 +#define IDS_ERROR_SELECTING_PRINTER_TEXT 112 +#define IDS_ERROR_SELECTING_PRINTER_CAPTION 113 +#define IDS_INSTALL_ERROR_CAPTION 114 +#define IDS_INSTALL_ERROR_MESSAGE 115 +#define IDS_MANUFACTURER_HEADING 116 +#define IDS_MODEL_HEADING 117 +#define IDS_NO_RENDEZVOUS_PRINTERS 118 +#define IDS_NO_MDNSRESPONDER_SERVICE_TEXT 119 +#define IDS_NO_MDNSRESPONDER_SERVICE_CAPTION 120 +#define IDS_PRINTER_MATCH_GOOD 121 +#define IDS_PRINTER_MATCH_BAD 122 +#define IDS_YES 123 +#define IDS_NO 124 +#define IDS_LARGE_FONT 125 +#define IDS_FIREWALL 126 +#define IDS_ERROR_CAPTION 127 +#define IDR_MAINFRAME 128 +#define IDS_FIREWALL_CAPTION 128 +#define IDB_BANNER_ICON 129 +#define IDD_THIRD_PAGE 130 +#define IDB_WATERMARK 131 +#define IDD_FOURTH_PAGE 132 +#define IDI_INFO 136 +#define IDB_ABOUT 138 +#define IDD_DIALOG1 139 +#define IDI_ICON2 141 +#define IDI_PRINTER 141 +#define IDS_REINSTALL 142 +#define IDS_REINSTALL_CAPTION 143 +#define IDC_BUTTON1 1000 +#define IDC_LIST1 1000 +#define IDC_BROWSE_LIST 1000 +#define IDC_RADIO1 1001 +#define IDC_COMBO1 1001 +#define IDC_RADIO2 1002 +#define IDC_GREETING 1003 +#define IDC_CHECK1 1016 +#define IDC_DEFAULT_PRINTER 1016 +#define IDC_PRINTER_IMAGE 1017 +#define IDC_PRINTER_NAME 1018 +#define IDC_PRINTER_MANUFACTURER 1019 +#define IDC_PRINTER_MODEL 1020 +#define IDC_GOODBYE 1021 +#define IDC_PRINTER_PORT 1022 +#define IDC_PRINTER_PROTOCOL 1022 +#define IDC_PRINTER_DEFAULT 1023 +#define IDC_PRINTER_SELECTION_TEXT 1024 +#define IDC_HAVE_DISK 1025 +#define IDC_PRINTER_INFORMATION 1026 +#define IDC_LOCATION_LABEL 1029 +#define IDC_DESCRIPTION_FIELD 1030 +#define IDC_LOCATION_FIELD 1032 +#define IDC_DESCRIPTION_LABEL 1033 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 142 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1034 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Clients/dns-sd.c b/Clients/dns-sd.c index 17c4a76..5c6adac 100644 --- a/Clients/dns-sd.c +++ b/Clients/dns-sd.c @@ -69,6 +69,7 @@ cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT -DNOT_HAVE_SETLINEBUF ws2_32.lib . #include // For strlen(), strcpy(), bzero() #include // For errno, EINTR #include +#include // For u_char #ifdef _WIN32 #include @@ -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> 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; } diff --git a/Makefile b/Makefile index 20adec5..436297d 100644 --- 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) diff --git a/mDNSCore/DNSCommon.c b/mDNSCore/DNSCommon.c index 13319c1..4116c1c 100644 --- a/mDNSCore/DNSCommon.c +++ b/mDNSCore/DNSCommon.c @@ -23,6 +23,34 @@ 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 + CPU Spin in mDNSResponder +GetNextScheduledEvent() needs to check LocalRecordReady() + +Revision 1.81 2004/12/18 03:13:45 cheshire + 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 + 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 + Don't check for Dynamic DNS hostname uniqueness + Revision 1.74 2004/12/09 22:49:15 ksekar 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 diff --git a/mDNSCore/DNSCommon.h b/mDNSCore/DNSCommon.h index 5466501..6a6ae70 100644 --- a/mDNSCore/DNSCommon.h +++ b/mDNSCore/DNSCommon.h @@ -23,6 +23,12 @@ 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 + Don't check for Dynamic DNS hostname uniqueness + Revision 1.28 2004/12/06 21:15:22 ksekar 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 diff --git a/mDNSCore/DNSDigest.c b/mDNSCore/DNSDigest.c index 55e304c..89d7b01 100644 --- a/mDNSCore/DNSDigest.c +++ b/mDNSCore/DNSDigest.c @@ -23,6 +23,9 @@ Change History (most recent first): $Log: DNSDigest.c,v $ +Revision 1.13 2004/12/16 20:12:59 cheshire + Cache memory management improvements + Revision 1.12 2004/12/03 07:20:50 ksekar 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); diff --git a/mDNSCore/mDNS.c b/mDNSCore/mDNS.c index 83f634b..f517066 100755 --- a/mDNSCore/mDNS.c +++ b/mDNSCore/mDNS.c @@ -45,6 +45,85 @@ 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 + Remove mDNSResponder sleep/wake syslog message + +Revision 1.514 2005/01/21 01:33:45 cheshire + Shutdown time regression: mDNSResponder not responding to SIGTERM + +Revision 1.513 2005/01/21 00:07:54 cheshire + 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 + 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 + 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 + CPU Spin in mDNSResponder +Log messages to help catch and report CPU spins + +Revision 1.508 2005/01/18 18:56:32 cheshire + QU responses not promoted to multicast responses when appropriate + +Revision 1.507 2005/01/18 01:12:07 cheshire + 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 + 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 + Low memory support: Provide answers even when we don't have cache space + +Revision 1.502 2004/12/20 18:04:08 cheshire + For now, don't put standard wide-area unicast responses in our main cache + +Revision 1.501 2004/12/19 23:50:18 cheshire + 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 + kDNSServiceInterfaceIndexLocalOnly should return all local records + +Revision 1.499 2004/12/17 23:37:45 cheshire + Guard against repeating wireless dissociation/re-association +(and other repetitive configuration changes) + +Revision 1.498 2004/12/17 05:25:46 cheshire + Shorten DNS-SD queries to avoid NAT bugs + +Revision 1.497 2004/12/17 03:20:58 cheshire + 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 + 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 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; inext = 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; iSubTypes[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; irrcache_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"); diff --git a/mDNSCore/mDNSDebug.h b/mDNSCore/mDNSDebug.h index 8f95d42..11c9737 100755 --- a/mDNSCore/mDNSDebug.h +++ b/mDNSCore/mDNSDebug.h @@ -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 diff --git a/mDNSCore/mDNSEmbeddedAPI.h b/mDNSCore/mDNSEmbeddedAPI.h index ac0215d..6397c1f 100755 --- a/mDNSCore/mDNSEmbeddedAPI.h +++ b/mDNSCore/mDNSEmbeddedAPI.h @@ -60,6 +60,53 @@ 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 + uDNS needs to support subtype registration and browsing + +Revision 1.273 2005/01/19 19:15:31 ksekar +Refinement to - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer + +Revision 1.272 2005/01/18 18:10:55 ksekar + Use 10.4 resolver API to get search domains + +Revision 1.271 2005/01/15 00:56:41 ksekar + Unicast services don't disappear when logging +out of VPN + +Revision 1.270 2005/01/14 18:34:22 ksekar + 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 + NATPMP: handle location changes + +Revision 1.267 2004/12/22 00:13:49 ksekar + Change version, port, and polling interval for LLQ + +Revision 1.266 2004/12/18 03:13:45 cheshire + kDNSServiceInterfaceIndexLocalOnly should return all local records + +Revision 1.265 2004/12/17 23:37:45 cheshire + Guard against repeating wireless dissociation/re-association +(and other repetitive configuration changes) + +Revision 1.264 2004/12/17 05:25:46 cheshire + 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 + Cache memory management improvements + +Revision 1.261 2004/12/14 21:21:20 ksekar + NAT-PMP: Update response format to contain "Seconds Since Boot" + Revision 1.260 2004/12/12 23:51:42 ksekar 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]; }; // *************************************************************************** diff --git a/mDNSCore/uDNS.c b/mDNSCore/uDNS.c index b2f8f3f..c4eda13 100755 --- a/mDNSCore/uDNS.c +++ b/mDNSCore/uDNS.c @@ -23,6 +23,104 @@ 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 + Don't use query ID zero in uDNS queries + +Revision 1.180 2005/01/19 21:01:54 ksekar + uDNS needs to support subtype registration and browsing + +Revision 1.179 2005/01/19 19:15:35 ksekar +Refinement to - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer + +Revision 1.178 2005/01/17 23:47:58 cheshire + 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 + Wide-area services not found on little-endian + +Revision 1.175 2005/01/15 00:56:41 ksekar + Unicast services don't disappear when logging +out of VPN + +Revision 1.174 2005/01/14 18:44:28 ksekar + mDNSResponder is crashing when changing domains + +Revision 1.173 2005/01/14 18:34:22 ksekar + 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 + Clean up syslog messages + +Revision 1.168 2004/12/23 23:22:47 ksekar + Unicast known answers "name" pointers point to garbage stack memory + +Revision 1.167 2004/12/22 22:25:47 ksekar + NATPMP: handle location changes + +Revision 1.166 2004/12/22 00:04:12 ksekar + 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 + Don't update TXT record if service registration fails + +Revision 1.162 2004/12/17 01:29:11 ksekar + 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 + Cache memory management improvements + +Revision 1.159 2004/12/15 02:11:22 ksekar + 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 + Call DeregisterService on nat port map failure + +Revision 1.155 2004/12/14 21:21:20 ksekar + 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 + 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, ®Info->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, ®Info->ns, regInfo->port, -1, GetAuthInfoForZone(u, ®Info->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; } diff --git a/mDNSCore/uDNS.h b/mDNSCore/uDNS.h index 20edb2d..7ae7f3c 100755 --- a/mDNSCore/uDNS.h +++ b/mDNSCore/uDNS.h @@ -23,6 +23,12 @@ 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 + 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 diff --git a/mDNSMacOS9/Mac OS Test Responder.c b/mDNSMacOS9/Mac OS Test Responder.c index cf03862..76a426c 100644 --- a/mDNSMacOS9/Mac OS Test Responder.c +++ b/mDNSMacOS9/Mac OS Test Responder.c @@ -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 + 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); } diff --git a/mDNSMacOS9/Mac OS Test Searcher.c b/mDNSMacOS9/Mac OS Test Searcher.c index f2fb9ce..fd28def 100644 --- a/mDNSMacOS9/Mac OS Test Searcher.c +++ b/mDNSMacOS9/Mac OS Test Searcher.c @@ -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 + Cache memory management improvements + Revision 1.20 2004/10/19 21:33:18 cheshire 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; } diff --git a/mDNSMacOS9/SubTypeTester.c b/mDNSMacOS9/SubTypeTester.c index 7c153a3..2206b22 100644 --- a/mDNSMacOS9/SubTypeTester.c +++ b/mDNSMacOS9/SubTypeTester.c @@ -23,6 +23,9 @@ Change History (most recent first): $Log: SubTypeTester.c,v $ +Revision 1.6 2004/12/16 20:49:35 cheshire + 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)); } diff --git a/mDNSMacOS9/mDNSLibrary.c b/mDNSMacOS9/mDNSLibrary.c index 13dc10a..d385cb4 100644 --- a/mDNSMacOS9/mDNSLibrary.c +++ b/mDNSMacOS9/mDNSLibrary.c @@ -23,6 +23,9 @@ Change History (most recent first): $Log: mDNSLibrary.c,v $ +Revision 1.3 2004/12/16 20:49:35 cheshire + 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); } } diff --git a/mDNSMacOS9/mDNSLibraryResources.r b/mDNSMacOS9/mDNSLibraryResources.r index b699ed5..d69b739 100644 --- a/mDNSMacOS9/mDNSLibraryResources.r +++ b/mDNSMacOS9/mDNSLibraryResources.r @@ -23,6 +23,30 @@ 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/" }; diff --git a/mDNSMacOS9/mDNSMacOS9.c b/mDNSMacOS9/mDNSMacOS9.c index d38facc..61da0a0 100644 --- a/mDNSMacOS9/mDNSMacOS9.c +++ b/mDNSMacOS9/mDNSMacOS9.c @@ -23,6 +23,13 @@ Change History (most recent first): $Log: mDNSMacOS9.c,v $ +Revision 1.43 2004/12/17 23:37:49 cheshire + 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 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 index 0000000..e91b775 --- /dev/null +++ b/mDNSMacOSX/LaunchDaemonInfo.plist @@ -0,0 +1,17 @@ + + + + + Label + com.apple.mDNSResponder + OnDemand + + ProgramArguments + + /usr/sbin/mDNSResponder + -launchdaemon + + ServiceIPC + + + diff --git a/mDNSMacOSX/daemon.c b/mDNSMacOSX/daemon.c index e82657e..d977a4a 100644 --- a/mDNSMacOSX/daemon.c +++ b/mDNSMacOSX/daemon.c @@ -36,6 +36,60 @@ 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 + Name change log messages every time machine boots + +Revision 1.241 2005/01/25 17:28:06 ksekar + 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 - Simplify mDNS_PurgeResultsForDomain logic and move into daemon layer + +Revision 1.237 2005/01/19 03:33:09 cheshire + When changing Computer Name, we drop our own Goobye Packets + +Revision 1.236 2005/01/19 03:16:38 cheshire + CPU Spin in mDNSResponder +Improve detail of "Task Scheduling Error" diagnostic messages + +Revision 1.235 2005/01/15 00:56:41 ksekar + 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 + 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 + 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 + Cache memory management improvements + Revision 1.227 2004/12/10 13:52:57 cheshire 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= 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; diff --git a/mDNSMacOSX/mDNSMacOSX.c b/mDNSMacOSX/mDNSMacOSX.c index eebba79..8a74c6f 100644 --- a/mDNSMacOSX/mDNSMacOSX.c +++ b/mDNSMacOSX/mDNSMacOSX.c @@ -24,6 +24,122 @@ Change History (most recent first): $Log: mDNSMacOSX.c,v $ +Revision 1.294 2005/01/27 21:30:23 cheshire + "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 + Name change log messages every time machine boots + +Revision 1.290 2005/01/25 23:18:30 ksekar +fix for 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 + sa_len not set checking reachability for TCP connections + +Revision 1.286 2005/01/25 02:02:37 cheshire + mDNSResponder leaks +GetSearchDomains() was not calling dns_configuration_free(). + +Revision 1.285 2005/01/22 00:07:54 ksekar + mDNSResponder should look at all browse domains in SCPreferences + +Revision 1.284 2005/01/21 23:07:17 ksekar + 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 + Need a way to turn off domain discovery + +Revision 1.281 2005/01/18 18:10:55 ksekar + 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 + 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 - 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 + Clean up syslog messages + +Revision 1.272 2005/01/07 23:21:42 ksekar + Clean up SCPreferences format + +Revision 1.271 2004/12/20 23:18:12 cheshire + 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 + 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 + 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 + 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 + Shorten DNS-SD queries to avoid NAT bugs + +Revision 1.262 2004/12/17 04:48:32 cheshire + 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 + 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 ) // 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.. -// 3) for each result from (2), register LocalOnly PTR record_browse._dns-sd._udp.local. -> +// 2) for each search domain (from prefs pane), query for b._dns-sd._udp.. +// 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> // 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; diff --git a/mDNSMacOSX/mDNSMacOSX.h b/mDNSMacOSX/mDNSMacOSX.h index 2a81939..0222d04 100644 --- a/mDNSMacOSX/mDNSMacOSX.h +++ b/mDNSMacOSX/mDNSMacOSX.h @@ -23,6 +23,10 @@ Change History (most recent first): $Log: mDNSMacOSX.h,v $ +Revision 1.49 2004/12/17 23:37:47 cheshire + 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 #include #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 index 0000000..62c0240 --- /dev/null +++ b/mDNSMacOSX/mDNSResponder.order @@ -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 diff --git a/mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj b/mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj index 8ba74f8..41f07c3 100644 --- a/mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj +++ b/mDNSMacOSX/mDNSResponder.pbproj/project.pbxproj @@ -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"; }; @@ -318,6 +318,7 @@ 08FB77A3FE84155DC02AAC07, 08FB77A5FE84155DC02AAC07, FF5A0AE705632EA600743C27, + FF5585E507790732008D1C14, ); buildSettings = { FRAMEWORK_SEARCH_PATHS = ""; @@ -332,7 +333,7 @@ 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"; }; @@ -1604,6 +1605,19 @@ 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; diff --git a/mDNSPosix/Client.c b/mDNSPosix/Client.c index ad3480c..7b0d48e 100755 --- a/mDNSPosix/Client.c +++ b/mDNSPosix/Client.c @@ -24,6 +24,9 @@ Change History (most recent first): $Log: Client.c,v $ +Revision 1.15 2004/12/16 20:17:11 cheshire + 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"; diff --git a/mDNSPosix/Identify.c b/mDNSPosix/Identify.c index 27b2505..c1724f2 100644 --- a/mDNSPosix/Identify.c +++ b/mDNSPosix/Identify.c @@ -37,6 +37,9 @@ Change History (most recent first): $Log: Identify.c,v $ +Revision 1.34 2004/12/16 20:17:11 cheshire + 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; } } diff --git a/mDNSPosix/Makefile b/mDNSPosix/Makefile index 1f8b65b..b9ed8ec 100755 --- a/mDNSPosix/Makefile +++ b/mDNSPosix/Makefile @@ -24,6 +24,12 @@ # 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 diff --git a/mDNSPosix/NetMonitor.c b/mDNSPosix/NetMonitor.c index c8aad7b..4fce88d 100644 --- a/mDNSPosix/NetMonitor.c +++ b/mDNSPosix/NetMonitor.c @@ -37,6 +37,9 @@ Change History (most recent first): $Log: NetMonitor.c,v $ +Revision 1.71 2004/12/16 20:17:11 cheshire + 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; ih.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; ih.numAdditionals; i++) diff --git a/mDNSPosix/PosixDaemon.c b/mDNSPosix/PosixDaemon.c index fcb3990..3ebc304 100644 --- a/mDNSPosix/PosixDaemon.c +++ b/mDNSPosix/PosixDaemon.c @@ -28,6 +28,15 @@ 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 + Need a way to turn off domain discovery + +Revision 1.23 2004/12/16 20:17:11 cheshire + 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) diff --git a/mDNSPosix/ProxyResponder.c b/mDNSPosix/ProxyResponder.c index bca7356..f113d65 100644 --- a/mDNSPosix/ProxyResponder.c +++ b/mDNSPosix/ProxyResponder.c @@ -24,6 +24,9 @@ Change History (most recent first): $Log: ProxyResponder.c,v $ +Revision 1.35 2004/12/16 20:17:11 cheshire + Cache memory management improvements + Revision 1.34 2004/12/01 04:27:28 cheshire 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 diff --git a/mDNSPosix/Responder.c b/mDNSPosix/Responder.c index 93b0c81..b54d3a8 100755 --- a/mDNSPosix/Responder.c +++ b/mDNSPosix/Responder.c @@ -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 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; } } diff --git a/mDNSPosix/dnsextd.c b/mDNSPosix/dnsextd.c index 41bc5e7..c9d0c73 100644 --- a/mDNSPosix/dnsextd.c +++ b/mDNSPosix/dnsextd.c @@ -24,6 +24,27 @@ 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 + Change version, port, and polling interval for LLQ + +Revision 1.28 2004/12/17 00:30:00 ksekar + 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 + 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 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 [-vf] [ -s server ] [-k zone keyname secret] ...\n" + fprintf(stderr, "Usage: dnsextd -z [-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); diff --git a/mDNSPosix/mDNSPosix.c b/mDNSPosix/mDNSPosix.c index 5aca8fa..f15a88a 100755 --- a/mDNSPosix/mDNSPosix.c +++ b/mDNSPosix/mDNSPosix.c @@ -37,6 +37,16 @@ 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 + Guard against repeating wireless dissociation/re-association +(and other repetitive configuration changes) + Revision 1.66 2004/12/01 04:27:28 cheshire 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 #include @@ -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) diff --git a/mDNSPosix/mDNSUNP.h b/mDNSPosix/mDNSUNP.h index 45d9235..786fef7 100755 --- a/mDNSPosix/mDNSUNP.h +++ b/mDNSPosix/mDNSUNP.h @@ -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 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 diff --git a/mDNSShared/PlatformCommon.c b/mDNSShared/PlatformCommon.c index 4525eb4..9bee556 100644 --- a/mDNSShared/PlatformCommon.c +++ b/mDNSShared/PlatformCommon.c @@ -24,6 +24,9 @@ Change History (most recent first): $Log: PlatformCommon.c,v $ +Revision 1.4 2005/01/19 19:19:21 ksekar + 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); diff --git a/mDNSShared/PlatformCommon.h b/mDNSShared/PlatformCommon.h index 9e4638b..46a672a 100644 --- a/mDNSShared/PlatformCommon.h +++ b/mDNSShared/PlatformCommon.h @@ -24,6 +24,9 @@ Change History (most recent first): $Log: PlatformCommon.h,v $ +Revision 1.3 2005/01/19 19:19:21 ksekar + Need a way to turn off domain discovery + Revision 1.2 2004/12/01 03:30:29 cheshire 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); diff --git a/mDNSShared/dns_sd.h b/mDNSShared/dns_sd.h index 7d14fca..4f22f67 100755 --- a/mDNSShared/dns_sd.h +++ b/mDNSShared/dns_sd.h @@ -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. diff --git a/mDNSShared/dnssd_clientshim.c b/mDNSShared/dnssd_clientshim.c index 121b0df..7259a9c 100644 --- a/mDNSShared/dnssd_clientshim.c +++ b/mDNSShared/dnssd_clientshim.c @@ -31,6 +31,9 @@ Change History (most recent first): $Log: dnssd_clientshim.c,v $ +Revision 1.8 2004/12/16 20:47:34 cheshire + 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); } diff --git a/mDNSShared/dnssd_clientstub.c b/mDNSShared/dnssd_clientstub.c index d060a66..d06b5d2 100755 --- a/mDNSShared/dnssd_clientstub.c +++ b/mDNSShared/dnssd_clientstub.c @@ -28,6 +28,18 @@ 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 + 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 + 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; diff --git a/mDNSShared/dnssd_ipc.c b/mDNSShared/dnssd_ipc.c index e06737b..6a0236d 100644 --- a/mDNSShared/dnssd_ipc.c +++ b/mDNSShared/dnssd_ipc.c @@ -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; diff --git a/mDNSShared/dnssd_ipc.h b/mDNSShared/dnssd_ipc.h index 60ffc16..ca0014b 100644 --- a/mDNSShared/dnssd_ipc.h +++ b/mDNSShared/dnssd_ipc.h @@ -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. diff --git a/mDNSShared/mDNSDebug.c b/mDNSShared/mDNSDebug.c index dc5ad0f..fcf16ff 100644 --- a/mDNSShared/mDNSDebug.c +++ b/mDNSShared/mDNSDebug.c @@ -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; diff --git a/mDNSShared/uds_daemon.c b/mDNSShared/uds_daemon.c index 7f50d74..e14db7a 100644 --- a/mDNSShared/uds_daemon.c +++ b/mDNSShared/uds_daemon.c @@ -24,6 +24,83 @@ 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 + mDNSResponder leaks sockets for add/update/remove record calls + +Revision 1.159 2005/01/27 01:45:25 cheshire + mDNSResponder should never call exit(1); + +Revision 1.158 2005/01/25 17:28:07 ksekar + 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 - 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 + Unicast services don't disappear when logging +out of VPN + +Revision 1.153 2005/01/14 18:44:28 ksekar + 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 + dnd-sd shows the wrong port numbers + +Revision 1.149 2004/12/20 23:20:35 cheshire + 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 + 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 + 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 + 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) : ""); - 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" : "<>"); 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, diff --git a/mDNSShared/uds_daemon.h b/mDNSShared/uds_daemon.h index 0b9dfab..55688b7 100644 --- a/mDNSShared/uds_daemon.h +++ b/mDNSShared/uds_daemon.h @@ -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 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. diff --git a/mDNSVxWorks/mDNSVxWorks.c b/mDNSVxWorks/mDNSVxWorks.c index c93e9cb..dc116b5 100644 --- a/mDNSVxWorks/mDNSVxWorks.c +++ b/mDNSVxWorks/mDNSVxWorks.c @@ -27,6 +27,10 @@ Change History (most recent first): $Log: mDNSVxWorks.c,v $ +Revision 1.27 2004/12/17 23:37:49 cheshire + Guard against repeating wireless dissociation/re-association +(and other repetitive configuration changes) + Revision 1.26 2004/10/28 02:00:35 cheshire 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; diff --git a/mDNSWindows/DLL.NET/dnssd_NET.h b/mDNSWindows/DLL.NET/dnssd_NET.h index 565286f..312d7b6 100755 --- a/mDNSWindows/DLL.NET/dnssd_NET.h +++ b/mDNSWindows/DLL.NET/dnssd_NET.h @@ -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, diff --git a/mDNSWindows/DLL.NET/dnssd_NET.rc b/mDNSWindows/DLL.NET/dnssd_NET.rc index f3c3dd4..c6340ee 100755 --- a/mDNSWindows/DLL.NET/dnssd_NET.rc +++ b/mDNSWindows/DLL.NET/dnssd_NET.rc @@ -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 diff --git a/mDNSWindows/DLL.NET/dnssd_NET.vcproj b/mDNSWindows/DLL.NET/dnssd_NET.vcproj index f2145d9..719de8d 100755 --- a/mDNSWindows/DLL.NET/dnssd_NET.vcproj +++ b/mDNSWindows/DLL.NET/dnssd_NET.vcproj @@ -82,7 +82,8 @@ AdditionalDependencies="../DLL/Release/dnssd.lib mscoree.lib ws2_32.lib msvcrt.lib" OutputFile="$(OutDir)\dnssd.NET.dll" LinkIncremental="1" - GenerateDebugInformation="TRUE"/> + GenerateDebugInformation="TRUE" + ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mDNSWindows/DNSServices/DNSServices.c b/mDNSWindows/DNSServices/DNSServices.c index a8aedb3..c32ebb0 100755 --- a/mDNSWindows/DNSServices/DNSServices.c +++ b/mDNSWindows/DNSServices/DNSServices.c @@ -23,6 +23,9 @@ Change History (most recent first): $Log: DNSServices.c,v $ +Revision 1.32 2004/12/16 20:13:02 cheshire + Cache memory management improvements + Revision 1.31 2004/10/19 21:33:23 cheshire 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 ); diff --git a/mDNSWindows/Java/makefile b/mDNSWindows/Java/makefile index d787410..1b57da4 100644 --- a/mDNSWindows/Java/makefile +++ b/mDNSWindows/Java/makefile @@ -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 \ diff --git a/mDNSWindows/NSPTool/NSPTool.rc b/mDNSWindows/NSPTool/NSPTool.rc index b75f621..9f39249 100644 --- a/mDNSWindows/NSPTool/NSPTool.rc +++ b/mDNSWindows/NSPTool/NSPTool.rc @@ -8,6 +8,7 @@ // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" +#include "WinVersRes.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS @@ -53,8 +54,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,0,5 - PRODUCTVERSION 1,0,0,5 + FILEVERSION MASTER_PROD_VERS + PRODUCTVERSION MASTER_PROD_VERS FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -71,12 +72,12 @@ BEGIN BEGIN VALUE "CompanyName", "Apple Computer, Inc." VALUE "FileDescription", "NSPTool Application" - VALUE "FileVersion", "1, 0, 0, 5" + VALUE "FileVersion", MASTER_PROD_VERS_STR VALUE "InternalName", "NSPTool" - VALUE "LegalCopyright", "Copyright (C) 2004" + VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT VALUE "OriginalFilename", "NSPTool.exe" - VALUE "ProductName", " NSPTool Application" - VALUE "ProductVersion", "1, 0, 0, 5" + VALUE "ProductName", MASTER_PROD_NAME + VALUE "ProductVersion", MASTER_PROD_VERS_STR END END BLOCK "VarFileInfo" diff --git a/mDNSWindows/NSPTool/NSPTool.vcproj b/mDNSWindows/NSPTool/NSPTool.vcproj index 89ca1fb..7b3fc0e 100644 --- a/mDNSWindows/NSPTool/NSPTool.vcproj +++ b/mDNSWindows/NSPTool/NSPTool.vcproj @@ -54,7 +54,8 @@ + Name="VCResourceCompilerTool" + AdditionalIncludeDirectories="..\"/> + Name="VCResourceCompilerTool" + AdditionalIncludeDirectories="..\"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mDNSWindows/WinVersRes.h b/mDNSWindows/WinVersRes.h index b6edb1e..30d4984 100644 --- a/mDNSWindows/WinVersRes.h +++ b/mDNSWindows/WinVersRes.h @@ -23,6 +23,21 @@ 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 index 0000000..e2e2d58 --- /dev/null +++ b/mDNSWindows/dDNS.c @@ -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 +#include +#include + +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.. +// 3) for each result from (2), register LocalOnly PTR record b._dns-sd._udp.local. -> +// 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 index 0000000..e9d7a36 --- /dev/null +++ b/mDNSWindows/dDNS.h @@ -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 index 0000000..19f8570 --- /dev/null +++ b/mDNSWindows/isocode.h @@ -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 index 0000000..78f16a4 --- /dev/null +++ b/mDNSWindows/loclibrary.c @@ -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 +#include +#include "isocode.h" +#include "loclibrary.h" +#include "Shlwapi.h" +#include +#include +#include + +#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 index 0000000..952dc44 --- /dev/null +++ b/mDNSWindows/loclibrary.h @@ -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_ diff --git a/mDNSWindows/mDNSWin32.c b/mDNSWindows/mDNSWin32.c index 1f48cf7..7d4ea02 100755 --- a/mDNSWindows/mDNSWin32.c +++ b/mDNSWindows/mDNSWin32.c @@ -23,6 +23,32 @@ 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 + 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 + 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 #include #if( !TARGET_OS_WINDOWS_CE ) #include #include + #include #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( ¤t->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( ¤t->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( ¤t->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; +} diff --git a/mDNSWindows/mDNSWin32.h b/mDNSWindows/mDNSWin32.h index 70dbe22..e94150e 100755 --- a/mDNSWindows/mDNSWin32.h +++ b/mDNSWindows/mDNSWin32.h @@ -23,6 +23,13 @@ Change History (most recent first): $Log: mDNSWin32.h,v $ +Revision 1.20 2005/01/25 08:12:52 shersche + 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 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 diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.rc b/mDNSWindows/mdnsNSP/mdnsNSP.rc index e0d4772..4fae1d8 100644 --- a/mDNSWindows/mdnsNSP/mdnsNSP.rc +++ b/mDNSWindows/mdnsNSP/mdnsNSP.rc @@ -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 diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.vcproj b/mDNSWindows/mdnsNSP/mdnsNSP.vcproj index 5e49db5..f8aac54 100644 --- a/mDNSWindows/mdnsNSP/mdnsNSP.vcproj +++ b/mDNSWindows/mdnsNSP/mdnsNSP.vcproj @@ -1,160 +1,161 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 2.47.2