]> git.saurik.com Git - apple/mdnsresponder.git/commitdiff
mDNSResponder-258.13.tar.gz mac-os-x-1065 v258.13
authorApple <opensource@apple.com>
Fri, 8 Oct 2010 23:06:12 +0000 (23:06 +0000)
committerApple <opensource@apple.com>
Fri, 8 Oct 2010 23:06:12 +0000 (23:06 +0000)
319 files changed:
Clients/BonjourExample/BonjourExample.cpp
Clients/BonjourExample/stdafx.cpp
Clients/BonjourExample/stdafx.h
Clients/ClientCommon.c
Clients/ClientCommon.h
Clients/DNS-SD.VisualStudio/dns-sd.sdk.rc [new file with mode: 0755]
Clients/DNS-SD.VisualStudio/dns-sd.sdk.vcproj [new file with mode: 0755]
Clients/DNS-SD.VisualStudio/dns-sd.vcproj
Clients/DNSServiceBrowser.NET/AssemblyInfo.cs
Clients/DNSServiceBrowser.NET/DNSServiceBrowser.cs
Clients/DNSServiceBrowser.VB/DNSServiceBrowser.vb
Clients/DNSServiceBrowser.m
Clients/DNSServiceReg.m
Clients/ExplorerPlugin/ClassFactory.cpp
Clients/ExplorerPlugin/ClassFactory.h
Clients/ExplorerPlugin/ExplorerBar.cpp
Clients/ExplorerPlugin/ExplorerBar.h
Clients/ExplorerPlugin/ExplorerBarWindow.cpp
Clients/ExplorerPlugin/ExplorerBarWindow.h
Clients/ExplorerPlugin/ExplorerPlugin.cpp
Clients/ExplorerPlugin/ExplorerPlugin.def
Clients/ExplorerPlugin/ExplorerPlugin.h
Clients/ExplorerPlugin/ExplorerPlugin.vcproj
Clients/ExplorerPlugin/ExplorerPluginLocRes.rc
Clients/ExplorerPlugin/ExplorerPluginLocRes.vcproj
Clients/ExplorerPlugin/ExplorerPluginRes.vcproj
Clients/ExplorerPlugin/LoginDialog.cpp
Clients/ExplorerPlugin/LoginDialog.h
Clients/ExplorerPlugin/Resource.h
Clients/ExplorerPlugin/StdAfx.cpp
Clients/ExplorerPlugin/StdAfx.h
Clients/FirefoxExtension/CDNSSDService.cpp [new file with mode: 0755]
Clients/FirefoxExtension/CDNSSDService.h [new file with mode: 0755]
Clients/FirefoxExtension/CDNSSDServiceModule.cpp [new file with mode: 0755]
Clients/FirefoxExtension/DNSSDService.sln [new file with mode: 0755]
Clients/FirefoxExtension/FirefoxExtension.rc [new file with mode: 0644]
Clients/FirefoxExtension/FirefoxExtension.vcproj [new file with mode: 0755]
Clients/FirefoxExtension/IDNSSDService.h [new file with mode: 0755]
Clients/FirefoxExtension/IDNSSDService.idl [new file with mode: 0755]
Clients/FirefoxExtension/extension/chrome.manifest [new file with mode: 0755]
Clients/FirefoxExtension/extension/components/IDNSSDService.xpt [new file with mode: 0755]
Clients/FirefoxExtension/extension/content/bonjour4firefox.css [new file with mode: 0755]
Clients/FirefoxExtension/extension/content/bonjour4firefox.png [new file with mode: 0755]
Clients/FirefoxExtension/extension/content/bonjour4firefox.xul [new file with mode: 0755]
Clients/FirefoxExtension/extension/content/browserOverlay.xul [new file with mode: 0755]
Clients/FirefoxExtension/extension/content/listImage.png [new file with mode: 0755]
Clients/FirefoxExtension/extension/content/overlay.js [new file with mode: 0755]
Clients/FirefoxExtension/extension/defaults/preferences/bonjour4firefox.js [new file with mode: 0755]
Clients/FirefoxExtension/extension/install.rdf [new file with mode: 0755]
Clients/FirefoxExtension/extension/locale/en-US/bonjour4firefox.dtd [new file with mode: 0755]
Clients/FirefoxExtension/extension/locale/en-US/bonjour4firefox.properties [new file with mode: 0755]
Clients/FirefoxExtension/extension/readme.txt [new file with mode: 0755]
Clients/FirefoxExtension/extension/skin-darwin/overlay.css [new file with mode: 0644]
Clients/FirefoxExtension/extension/skin-darwin/toolbar-button.png [new file with mode: 0644]
Clients/FirefoxExtension/extension/skin/overlay.css [new file with mode: 0755]
Clients/FirefoxExtension/extension/skin/toolbar-button.png [new file with mode: 0755]
Clients/FirefoxExtension/readme.txt [new file with mode: 0644]
Clients/FirefoxExtension/resource.h [new file with mode: 0644]
Clients/Java/DNSSDUnitTest.java
Clients/Makefile
Clients/PrinterSetupWizard/FirstPage.cpp
Clients/PrinterSetupWizard/FirstPage.h
Clients/PrinterSetupWizard/FourthPage.cpp
Clients/PrinterSetupWizard/FourthPage.h
Clients/PrinterSetupWizard/Logger.cpp
Clients/PrinterSetupWizard/Logger.h
Clients/PrinterSetupWizard/PrinterSetupWizard.rc
Clients/PrinterSetupWizard/PrinterSetupWizard.vcproj
Clients/PrinterSetupWizard/PrinterSetupWizardApp.cpp
Clients/PrinterSetupWizard/PrinterSetupWizardApp.h
Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.rc
Clients/PrinterSetupWizard/PrinterSetupWizardLocRes.vcproj
Clients/PrinterSetupWizard/PrinterSetupWizardRes.rc
Clients/PrinterSetupWizard/PrinterSetupWizardRes.vcproj
Clients/PrinterSetupWizard/PrinterSetupWizardSheet.cpp
Clients/PrinterSetupWizard/PrinterSetupWizardSheet.h
Clients/PrinterSetupWizard/SecondPage.cpp
Clients/PrinterSetupWizard/SecondPage.h
Clients/PrinterSetupWizard/ThirdPage.cpp
Clients/PrinterSetupWizard/ThirdPage.h
Clients/PrinterSetupWizard/UtilTypes.h
Clients/PrinterSetupWizard/res/NetworkPrinter.ico
Clients/PrinterSetupWizard/resource.h
Clients/PrinterSetupWizard/resource_exe.h
Clients/PrinterSetupWizard/resource_loc_res.h
Clients/PrinterSetupWizard/resource_res.h
Clients/PrinterSetupWizard/stdafx.cpp
Clients/PrinterSetupWizard/stdafx.h
Clients/SimpleChat.NET/AssemblyInfo.cs
Clients/SimpleChat.NET/SimpleChat.cs
Clients/SimpleChat.VB/SimpleChat.vb
Clients/dns-sd.c
Clients/mDNSNetMonitor.VisualStudio/mDNSNetMonitor.rc [new file with mode: 0644]
Clients/mDNSNetMonitor.VisualStudio/mDNSNetMonitor.vcproj
Clients/mDNSNetMonitor.VisualStudio/resource.h [new file with mode: 0644]
Makefile
mDNSCore/DNSCommon.c
mDNSCore/DNSCommon.h
mDNSCore/DNSDigest.c
mDNSCore/mDNS.c
mDNSCore/mDNSDebug.h
mDNSCore/mDNSEmbeddedAPI.h
mDNSCore/uDNS.c
mDNSCore/uDNS.h
mDNSMacOS9/CarbonResource.r
mDNSMacOS9/Mac OS Test Responder.c
mDNSMacOS9/Mac OS Test Searcher.c
mDNSMacOS9/Responder.c
mDNSMacOS9/Searcher.c
mDNSMacOS9/SubTypeTester.c
mDNSMacOS9/mDNSLibrary.c
mDNSMacOS9/mDNSLibraryLoader.c
mDNSMacOS9/mDNSLibraryResources.r
mDNSMacOS9/mDNSMacOS9.c
mDNSMacOS9/mDNSMacOS9.h
mDNSMacOS9/mDNSPrefix.h
mDNSMacOSX/DNSServiceDiscoveryDefines.h
mDNSMacOSX/LegacyNATTraversal.c
mDNSMacOSX/PreferencePane/ConfigurationAuthority.c
mDNSMacOSX/PreferencePane/ConfigurationAuthority.h
mDNSMacOSX/PreferencePane/ConfigurationRights.h
mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.h
mDNSMacOSX/PreferencePane/DNSServiceDiscoveryPref.m
mDNSMacOSX/PreferencePane/PrivilegedOperations.c
mDNSMacOSX/PreferencePane/PrivilegedOperations.h
mDNSMacOSX/PreferencePane/ddnswriteconfig.m
mDNSMacOSX/PreferencePane/installtool
mDNSMacOSX/SamplemDNSClient.c
mDNSMacOSX/daemon.c
mDNSMacOSX/helper-entitlements.plist [new file with mode: 0644]
mDNSMacOSX/helper-error.h
mDNSMacOSX/helper-main.c
mDNSMacOSX/helper-server.h
mDNSMacOSX/helper-stubs.c
mDNSMacOSX/helper.c
mDNSMacOSX/helper.h
mDNSMacOSX/helpermsg-types.h
mDNSMacOSX/helpermsg.defs
mDNSMacOSX/mDNSMacOSX.c
mDNSMacOSX/mDNSMacOSX.h
mDNSMacOSX/mDNSResponder.sb
mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
mDNSMacOSX/mDNSResponderHelper.8
mDNSMacOSX/pfkey.c
mDNSMacOSX/safe_vproc.c
mDNSMacOSX/safe_vproc.h
mDNSPosix/Client.c
mDNSPosix/ExampleClientApp.c
mDNSPosix/ExampleClientApp.h
mDNSPosix/Identify.c
mDNSPosix/Makefile
mDNSPosix/NetMonitor.c
mDNSPosix/PosixDaemon.c
mDNSPosix/ProxyResponder.c
mDNSPosix/Responder.c
mDNSPosix/libnss_mdns.8
mDNSPosix/mDNSPosix.c
mDNSPosix/mDNSPosix.h
mDNSPosix/mDNSUNP.c
mDNSPosix/mDNSUNP.h
mDNSPosix/mdnsd.sh
mDNSPosix/nss_mdns.conf.5
mDNSPosix/parselog.py
mDNSResponder.sln
mDNSShared/CommonServices.h
mDNSShared/DebugServices.c
mDNSShared/DebugServices.h
mDNSShared/GenLinkedList.c
mDNSShared/GenLinkedList.h
mDNSShared/Java/BaseListener.java
mDNSShared/Java/BrowseListener.java
mDNSShared/Java/DNSRecord.java
mDNSShared/Java/DNSSD.java
mDNSShared/Java/DNSSDException.java
mDNSShared/Java/DNSSDRecordRegistrar.java
mDNSShared/Java/DNSSDRegistration.java
mDNSShared/Java/DNSSDService.java
mDNSShared/Java/DomainListener.java
mDNSShared/Java/JNISupport.c
mDNSShared/Java/QueryListener.java
mDNSShared/Java/RegisterListener.java
mDNSShared/Java/RegisterRecordListener.java
mDNSShared/Java/ResolveListener.java
mDNSShared/Java/TXTRecord.java
mDNSShared/PlatformCommon.c
mDNSShared/PlatformCommon.h
mDNSShared/dns-sd.1
mDNSShared/dns_sd.h
mDNSShared/dnsextd.8
mDNSShared/dnsextd.c
mDNSShared/dnsextd.h
mDNSShared/dnsextd_lexer.l
mDNSShared/dnsextd_parser.y
mDNSShared/dnssd_clientlib.c
mDNSShared/dnssd_clientshim.c
mDNSShared/dnssd_clientstub.c
mDNSShared/dnssd_ipc.c
mDNSShared/dnssd_ipc.h
mDNSShared/mDNS.1
mDNSShared/mDNSDebug.c
mDNSShared/mDNSResponder.8
mDNSShared/uds_daemon.c
mDNSShared/uds_daemon.h
mDNSVxWorks/mDNSVxWorks.c
mDNSVxWorks/mDNSVxWorks.h
mDNSVxWorks/mDNSVxWorksIPv4Only.c
mDNSVxWorks/mDNSVxWorksIPv4Only.h
mDNSWindows/ControlPanel/BrowsingPage.cpp [new file with mode: 0755]
mDNSWindows/ControlPanel/BrowsingPage.h [new file with mode: 0755]
mDNSWindows/ControlPanel/ConfigDialog.cpp
mDNSWindows/ControlPanel/ConfigDialog.h
mDNSWindows/ControlPanel/ConfigPropertySheet.cpp
mDNSWindows/ControlPanel/ConfigPropertySheet.h
mDNSWindows/ControlPanel/ControlPanel.cpp
mDNSWindows/ControlPanel/ControlPanel.def
mDNSWindows/ControlPanel/ControlPanel.h
mDNSWindows/ControlPanel/ControlPanel.rc
mDNSWindows/ControlPanel/ControlPanel.vcproj
mDNSWindows/ControlPanel/ControlPanelExe.cpp
mDNSWindows/ControlPanel/ControlPanelExe.h
mDNSWindows/ControlPanel/ControlPanelExe.vcproj
mDNSWindows/ControlPanel/ControlPanelLocRes.rc [new file with mode: 0755]
mDNSWindows/ControlPanel/ControlPanelLocRes.vcproj [new file with mode: 0755]
mDNSWindows/ControlPanel/ControlPanelRes.rc [new file with mode: 0755]
mDNSWindows/ControlPanel/ControlPanelRes.vcproj [new file with mode: 0755]
mDNSWindows/ControlPanel/FirstPage.cpp [deleted file]
mDNSWindows/ControlPanel/FirstPage.h [deleted file]
mDNSWindows/ControlPanel/FourthPage.cpp
mDNSWindows/ControlPanel/FourthPage.h
mDNSWindows/ControlPanel/RegistrationPage.cpp [new file with mode: 0755]
mDNSWindows/ControlPanel/RegistrationPage.h [new file with mode: 0755]
mDNSWindows/ControlPanel/SecondPage.cpp
mDNSWindows/ControlPanel/SecondPage.h
mDNSWindows/ControlPanel/ServicesPage.cpp [new file with mode: 0755]
mDNSWindows/ControlPanel/ServicesPage.h [new file with mode: 0755]
mDNSWindows/ControlPanel/SharedSecret.cpp
mDNSWindows/ControlPanel/SharedSecret.h
mDNSWindows/ControlPanel/ThirdPage.cpp [deleted file]
mDNSWindows/ControlPanel/ThirdPage.h [deleted file]
mDNSWindows/ControlPanel/res/EnergySaver.ico [new file with mode: 0755]
mDNSWindows/ControlPanel/res/controlpanel.ico
mDNSWindows/ControlPanel/resource.h
mDNSWindows/ControlPanel/stdafx.cpp
mDNSWindows/ControlPanel/stdafx.h
mDNSWindows/DLL.NET/AssemblyInfo.cpp
mDNSWindows/DLL.NET/PString.h
mDNSWindows/DLL.NET/Stdafx.cpp
mDNSWindows/DLL.NET/Stdafx.h
mDNSWindows/DLL.NET/dnssd_NET.cpp
mDNSWindows/DLL.NET/dnssd_NET.h
mDNSWindows/DLL/dllmain.c
mDNSWindows/DLL/dnssd.def
mDNSWindows/DLL/dnssd.vcproj
mDNSWindows/DLLStub/DLLStub.vcproj
mDNSWindows/DLLX/DLLX.cpp
mDNSWindows/DLLX/DLLX.def
mDNSWindows/DLLX/DLLX.idl
mDNSWindows/DLLX/DNSSDEventManager.cpp
mDNSWindows/DLLX/DNSSDEventManager.h
mDNSWindows/DLLX/DNSSDRecord.cpp
mDNSWindows/DLLX/DNSSDRecord.h
mDNSWindows/DLLX/DNSSDService.cpp
mDNSWindows/DLLX/DNSSDService.h
mDNSWindows/DLLX/StringServices.cpp
mDNSWindows/DLLX/StringServices.h
mDNSWindows/DLLX/TXTRecord.cpp
mDNSWindows/DLLX/TXTRecord.h
mDNSWindows/DLLX/dlldatax.c
mDNSWindows/DLLX/dlldatax.h
mDNSWindows/DLLX/stdafx.h
mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc2
mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp
mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h
mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.cpp
mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.h
mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp
mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.h
mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp
mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.h
mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.cpp
mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.h
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.cpp
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.h
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h
mDNSWindows/Java/Java.vcproj
mDNSWindows/Java/jdns_sd.rc
mDNSWindows/Java/makefile
mDNSWindows/Java/makefile64 [new file with mode: 0644]
mDNSWindows/NSPTool/NSPTool.c
mDNSWindows/NSPTool/Prefix.h
mDNSWindows/PosixCompat.c
mDNSWindows/PosixCompat.h
mDNSWindows/RegNames.h
mDNSWindows/Secret.c
mDNSWindows/Secret.h
mDNSWindows/SystemService/EventLog.mc [new file with mode: 0644]
mDNSWindows/SystemService/Firewall.cpp
mDNSWindows/SystemService/Firewall.h
mDNSWindows/SystemService/Prefix.h
mDNSWindows/SystemService/Service.c
mDNSWindows/SystemService/Service.h
mDNSWindows/SystemService/Service.rc
mDNSWindows/SystemService/Service.vcproj
mDNSWindows/SystemService/main.c
mDNSWindows/VPCDetect.cpp
mDNSWindows/VPCDetect.h
mDNSWindows/WinServices.cpp
mDNSWindows/WinServices.h
mDNSWindows/WinVersRes.h
mDNSWindows/isocode.h
mDNSWindows/loclibrary.c
mDNSWindows/loclibrary.h
mDNSWindows/mDNSWin32.c
mDNSWindows/mDNSWin32.h
mDNSWindows/mdnsNSP/mdnsNSP.c
mDNSWindows/mdnsNSP/mdnsNSP.def

index ff50a3981b2ac492e25d036c3a950838a68d7cde..f517456cfcb7d668544ed0a92c525d88c9706f02 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: BonjourExample.cpp,v $
-Revision 1.2  2006/08/14 23:23:57  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.1  2005/05/20 22:01:01  bradley
-Bonjour for Windows example code to browse for HTTP services and deliver via Window messages.
-
-*/
+ */
 
 #include       "stdafx.h"
 
index c6899cd105fbf5f750c8f2eaba950b0894d10ee3..a28f2b5b2cbd19d1fe3fed27e3db4c4d537d5e36 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: stdafx.cpp,v $
-Revision 1.2  2006/08/14 23:23:57  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.1  2005/05/20 22:01:02  bradley
-Bonjour for Windows example code to browse for HTTP services and deliver via Window messages.
-
-*/
+ */
 
 // Standard source file to build the pre-compiled header.
 
index 461d1193a9c8a898ff7191ffdf30b3f2ae718a6b..2d51905d1552f7975b8351426fcf77c6ebff9f7b 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: stdafx.h,v $
-Revision 1.2  2006/08/14 23:23:57  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.1  2005/05/20 22:01:02  bradley
-Bonjour for Windows example code to browse for HTTP services and deliver via Window messages.
-
-*/
+ */
 
 // Standard Windows pre-compiled header file.
 
index f25fbb6519031b759bda85da22e415ddaa2dc76b..812efbeb4702c51e3225ac61fb3245f22068beed 100644 (file)
  * OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
  * (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-    Change History (most recent first):
-
-$Log: ClientCommon.c,v $
-Revision 1.2  2008/05/08 00:42:03  cheshire
-Removed some unnecessary header files
-
-Revision 1.1  2008/05/08 00:25:48  cheshire
-<rdar://problem/5919272> GetNextLabel insufficiently defensive
-
-
-*/
+ */
 
 #include <ctype.h>
 #include <stdio.h>                     // For stdout, stderr
index 5c2830749f376369fe8c2fe24c74ae8d21207a76..afe5b7a501508074f298050122d3278162d6d05d 100644 (file)
  * OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
  * (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-    Change History (most recent first):
-
-$Log: ClientCommon.h,v $
-Revision 1.1  2008/05/08 00:25:48  cheshire
-<rdar://problem/5919272> GetNextLabel insufficiently defensive
-
-
-*/
+ */
 
 extern const char *GetNextLabel(const char *cstr, char label[64]);
diff --git a/Clients/DNS-SD.VisualStudio/dns-sd.sdk.rc b/Clients/DNS-SD.VisualStudio/dns-sd.sdk.rc
new file mode 100755 (executable)
index 0000000..9274716
--- /dev/null
@@ -0,0 +1,102 @@
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+    "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+    "#include ""afxres.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+    "\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION 1,0,0,0\r
+ PRODUCTVERSION 1,0,0,0\r
+ FILEFLAGSMASK 0x17L\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x1L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+        BLOCK "040904b0"\r
+        BEGIN\r
+            VALUE "CompanyName", "Apple Inc."\r
+            VALUE "FileDescription", "Bonjour Console Utility"\r
+            VALUE "FileVersion", "1.0.0.0"\r
+            VALUE "InternalName", "dns-sd.exe"\r
+            VALUE "LegalCopyright", "Copyright (C) 2010 Apple Inc."\r
+            VALUE "OriginalFilename", "dns-sd.exe"\r
+            VALUE "ProductName", "Bonjour"\r
+            VALUE "ProductVersion", "1.0.0.0"\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+        VALUE "Translation", 0x409, 1200\r
+    END\r
+END\r
+\r
+#endif    // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
+\r
diff --git a/Clients/DNS-SD.VisualStudio/dns-sd.sdk.vcproj b/Clients/DNS-SD.VisualStudio/dns-sd.sdk.vcproj
new file mode 100755 (executable)
index 0000000..41daa81
--- /dev/null
@@ -0,0 +1,408 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="dns-sd"\r
+       ProjectGUID="{AA230639-E115-4A44-AA5A-44A61235BA50}"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+               <Platform\r
+                       Name="x64"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="$(BONJOUR_SDK_HOME)/Include"\r
+                               PreprocessorDefinitions="WIN32;_WIN32;_DEBUG;_CONSOLE;NOT_HAVE_GETOPT;NOT_HAVE_SETLINEBUF;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               AssemblerListingLocation="$(IntDir)\"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               AdditionalIncludeDirectories="../../mDNSWindows"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
+                               AdditionalDependencies="&quot;$(BONJOUR_SDK_HOME)/Lib/$(PlatformName)/dnssd.lib&quot; ws2_32.lib"\r
+                               OutputFile="$(OutDir)/dns-sd.exe"\r
+                               LinkIncremental="2"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/dns-sd.pdb"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                               AdditionalManifestFiles="DNS-SD.manifest"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Debug|x64"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               TargetEnvironment="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="$(BONJOUR_SDK_HOME)/Include"\r
+                               PreprocessorDefinitions="WIN32;_WIN32;_DEBUG;_CONSOLE;NOT_HAVE_GETOPT;NOT_HAVE_SETLINEBUF;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               AssemblerListingLocation="$(IntDir)\"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               AdditionalIncludeDirectories="../../mDNSWindows"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
+                               AdditionalDependencies="&quot;$(BONJOUR_SDK_HOME)/Lib/$(PlatformName)/dnssd.lib&quot; ws2_32.lib"\r
+                               OutputFile="$(OutDir)/dns-sd.exe"\r
+                               LinkIncremental="2"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/dns-sd.pdb"\r
+                               SubSystem="1"\r
+                               TargetMachine="17"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                               AdditionalManifestFiles="DNS-SD64.manifest"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="2"\r
+                               InlineFunctionExpansion="1"\r
+                               OmitFramePointers="true"\r
+                               AdditionalIncludeDirectories="$(BONJOUR_SDK_HOME)/Include"\r
+                               PreprocessorDefinitions="WIN32;_WIN32;NDEBUG;_CONSOLE;NOT_HAVE_GETOPT;NOT_HAVE_SETLINEBUF;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
+                               StringPooling="true"\r
+                               RuntimeLibrary="0"\r
+                               EnableFunctionLevelLinking="true"\r
+                               UsePrecompiledHeader="0"\r
+                               AssemblerListingLocation="$(IntDir)\"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               AdditionalIncludeDirectories="../../mDNSWindows"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
+                               AdditionalDependencies="&quot;$(BONJOUR_SDK_HOME)/Lib/$(PlatformName)/dnssd.lib&quot; ws2_32.lib"\r
+                               OutputFile="$(OutDir)/dns-sd.exe"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                               AdditionalManifestFiles="DNS-SD.manifest"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                               CommandLine=""\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|x64"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               TargetEnvironment="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="2"\r
+                               InlineFunctionExpansion="1"\r
+                               OmitFramePointers="true"\r
+                               AdditionalIncludeDirectories="$(BONJOUR_SDK_HOME)/Include"\r
+                               PreprocessorDefinitions="WIN32;_WIN32;NDEBUG;_CONSOLE;NOT_HAVE_GETOPT;NOT_HAVE_SETLINEBUF;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
+                               StringPooling="true"\r
+                               RuntimeLibrary="0"\r
+                               EnableFunctionLevelLinking="true"\r
+                               UsePrecompiledHeader="0"\r
+                               AssemblerListingLocation="$(IntDir)\"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               AdditionalIncludeDirectories="../../mDNSWindows"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
+                               AdditionalDependencies="&quot;$(BONJOUR_SDK_HOME)/Lib/$(PlatformName)/dnssd.lib&quot; ws2_32.lib"\r
+                               OutputFile="$(OutDir)/dns-sd.exe"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="17"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                               AdditionalManifestFiles="DNS-SD64.manifest"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                               CommandLine=""\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\ClientCommon.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\dns-sd.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\ClientCommon.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="resource.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+                       >\r
+                       <File\r
+                               RelativePath="dns-sd.rc"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
index db1a499b53fb91dd77fb0ba5bb82e37f892ba167..58e79e46a7c83b31a809b4562767c58fd89886c9 100755 (executable)
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;            mkdir &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\C&quot;               mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\C&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                           &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\dns-sd.c&quot;                                                            &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\C&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;            mkdir &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\C&quot;               mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\C&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\CS&quot;           mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\CS&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\CS\DNSServiceBrowser&quot; mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\CS\DNSServiceBrowser&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\CS\SimpleChat&quot;               mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\CS\SimpleChat&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\VB&quot;             mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\VB&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\VB\DNSServiceBrowser&quot; mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\VB\DNSServiceBrowser&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\VB\DNSServiceBrowser\My Project&quot; mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\VB\DNSServiceBrowser\My Project&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\VB\SimpleChat&quot;               mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\VB\SimpleChat&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                           &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\dns-sd.c&quot;                                                            &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\C&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\ClientCommon.c&quot;                                             &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\C&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\ClientCommon.h&quot;                                             &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\C&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)resource.h&quot;                                                             &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\C&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)DNS-SD.manifest&quot;                                                 &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\C&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)DNS-SD64.manifest&quot;                                             &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\C&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)dns-sd.sdk.rc&quot;                                                        &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\C&quot;&#x0D;&#x0A;move /Y &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\C\dns-sd.sdk.rc&quot; &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\C\dns-sd.rc&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)dns-sd.sdk.vcproj&quot;                                                &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\C&quot;&#x0D;&#x0A;move /Y &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\C\dns-sd.sdk.vcproj&quot; &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\C\dns-sd.vcproj&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\DNSServiceBrowser.NET\App.ico&quot;                  &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\CS\DNSServiceBrowser&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\DNSServiceBrowser.NET\AssemblyInfo.cs&quot;                  &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\CS\DNSServiceBrowser&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\DNSServiceBrowser.NET\DNSServiceBrowser.NET.csproj&quot;                  &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\CS\DNSServiceBrowser&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\DNSServiceBrowser.NET\DNSServiceBrowser.cs&quot;                  &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\CS\DNSServiceBrowser&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\DNSServiceBrowser.NET\DNSServiceBrowser.resx&quot;                  &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\CS\DNSServiceBrowser&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\SimpleChat.NET\App.ico&quot;                  &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\CS\SimpleChat&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\SimpleChat.NET\AssemblyInfo.cs&quot;                  &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\CS\SimpleChat&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\SimpleChat.NET\SimpleChat.NET.csproj&quot;                  &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\CS\SimpleChat&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\SimpleChat.NET\SimpleChat.cs&quot;                  &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\CS\SimpleChat&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\SimpleChat.NET\SimpleChat.resx&quot;                  &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\CS\SimpleChat&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\DNSServiceBrowser.VB\DNSServiceBrowser.Designer.vb&quot;  &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\VB\DNSServiceBrowser&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\DNSServiceBrowser.VB\DNSServiceBrowser.VB.vbproj&quot;   &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\VB\DNSServiceBrowser&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\DNSServiceBrowser.VB\DNSServiceBrowser.resx&quot;   &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\VB\DNSServiceBrowser&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\DNSServiceBrowser.VB\DNSServiceBrowser.vb&quot;   &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\VB\DNSServiceBrowser&quot;&#x0D;&#x0A;xcopy /E/Y &quot;$(ProjectDir)..\DNSServiceBrowser.VB\My Project&quot;                      &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\VB\DNSServiceBrowser\My Project&quot;&#x0D;&#x0A;xcopy /E/Y &quot;$(ProjectDir)..\SimpleChat.VB&quot;                                               &quot;$(DSTROOT)\Program Files\Bonjour SDK\Samples\VB\SimpleChat&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
                <Configuration\r
index 588f438d4c5fe8659711d865eea603e51bf5bacc..1b3661cc89cf2bd7949e97c752711502f97a2278 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
  * See the License for the specific language governing permissions and\r
  * limitations under the License.\r
-\r
-    Change History (most recent first):\r
-    \r
-$Log: AssemblyInfo.cs,v $
-Revision 1.2  2006/08/14 23:23:58  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.1  2004/07/19 07:54:24  shersche
-Initial revision
-\r
-\r
-*/\r
+ */\r
 \r
 using System.Reflection;\r
 using System.Runtime.CompilerServices;\r
index c86b45e356d335e64f46007fee3423674bc398d2..18aa3e71280c0d6623722d77d7dd5928dcccad9a 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: DNSServiceBrowser.cs,v $
-Revision 1.8  2009/06/02 18:49:23  herscher
-<rdar://problem/3948252> Update the .NET code to use the new Bonjour COM component
-
-Revision 1.7  2006/08/14 23:23:58  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.6  2005/02/10 22:35:06  cheshire
-<rdar://problem/3727944> Update name
-
-Revision 1.5  2004/09/21 16:26:58  shersche
-Check to make sure browse list selected item is not null before resolving
-Submitted by: prepin@gmail.com
-
-Revision 1.4  2004/09/13 19:38:17  shersche
-Changed code to reflect namespace and type changes to dnssd.NET library
-
-Revision 1.3  2004/09/11 00:38:14  shersche
-DNSService APIs now assume port in host format. Check for null text record in resolve callback.
-
-Revision 1.2  2004/07/22 23:15:25  shersche
-Fix service names for teleport, tftp, and bootps
-
-Revision 1.1  2004/07/19 07:54:24  shersche
-Initial revision
-
-
-
-*/
+ */
 
 using System;
 using System.Drawing;
index 1e7a7ae8b281f27394d4bbba7af0aee8f9c7c00f..dbbced9d436d8ceaaa38a7580535f58b8151006b 100644 (file)
@@ -1,3 +1,19 @@
+'\r
+' Copyright (c) 2010 Apple Inc. All rights reserved.\r
+'\r
+' Licensed under the Apache License, Version 2.0 (the "License");\r
+' you may not use this file except in compliance with the License.\r
+' You may obtain a copy of the License at\r
+' \r
+'     http://www.apache.org/licenses/LICENSE-2.0\r
+' \r
+' Unless required by applicable law or agreed to in writing, software\r
+' distributed under the License is distributed on an "AS IS" BASIS,\r
+' WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+' See the License for the specific language governing permissions and\r
+' limitations under the License.\r
+'\r
+\r
 Public Class DNSServiceBrowser\r
     Public WithEvents MyEventManager As New Bonjour.DNSSDEventManager\r
 \r
index ac4f1ab8b09967b419220abdfc4209c1bc4d6818..b4e041404112379c9aa6aa5b03dde0d9ca4c8827 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: DNSServiceBrowser.m,v $
-Revision 1.35  2006/11/27 08:27:49  mkrochma
-Fix a crashing bug
-
-Revision 1.34  2006/11/24 05:41:07  mkrochma
-More cleanup and more service types
-
-Revision 1.33  2006/11/24 01:34:24  mkrochma
-Display interface index and query for IPv6 addresses even when there's no IPv4
-
-Revision 1.32  2006/11/24 00:25:31  mkrochma
-<rdar://problem/4084652> Tools: DNS Service Browser contains some bugs
-
-Revision 1.31  2006/08/14 23:23:55  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-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
-
-Revision 1.28  2004/05/18 23:51:26  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
-
-Revision 1.27  2003/11/19 18:49:48  rpantos
-<rdar://problem/3282283> couple of little tweaks to previous checkin
-
-Revision 1.26  2003/11/07 19:35:20  rpantos
-<rdar://problem/3282283> Display multiple IP addresses. Connect using host rather than IP addr.
-
-Revision 1.25  2003/10/29 05:16:54  rpantos
-Checkpoint: transition from DNSServiceDiscovery.h to dns_sd.h
-
-Revision 1.24  2003/10/28 02:25:45  rpantos
-<rdar://problem/3282283> Cancel pending resolve when focus changes or service disappears.
-
-Revision 1.23  2003/10/28 01:29:15  rpantos
-<rdar://problem/3282283> Restructure a bit to make arrow keys work & views behave better.
-
-Revision 1.22  2003/10/28 01:23:27  rpantos
-<rdar://problem/3282283> Bail if mDNS cannot be initialized at startup.
-
-Revision 1.21  2003/10/28 01:19:45  rpantos
-<rdar://problem/3282283> Do not put a trailing '.' on service names. Handle PATH for HTTP txtRecords.
-
-Revision 1.20  2003/10/28 01:13:49  rpantos
-<rdar://problem/3282283> Remove filter when displaying browse results.
-
-Revision 1.19  2003/10/28 01:10:14  rpantos
-<rdar://problem/3282283> Change 'compare' to 'caseInsensitiveCompare' to fix sort order.
-
-Revision 1.18  2003/08/12 19:55:07  cheshire
-Update to APSL 2.0
-
-*/
+ */
 
 #import <Cocoa/Cocoa.h>
 #include <sys/types.h>
@@ -209,6 +151,9 @@ InterfaceIndexToName(uint32_t interface, char *interfaceName)
     } else if (interface == kDNSServiceInterfaceIndexLocalOnly) {
         // Only available locally on this machine.
         strlcpy(interfaceName, "local", IF_NAMESIZE);
+    } else if (interface == kDNSServiceInterfaceIndexP2P) {
+        // Peer-to-peer.
+        strlcpy(interfaceName, "p2p", IF_NAMESIZE);
     } else {
         // Converts interface index to interface name.
         if_indextoname(interface, interfaceName);
index 49e0c36ddb942a2667dc70e9baf7b1279fed6cc4..3f2620fe38fc24b084741faba7dfc80fdba694f1 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: DNSServiceReg.m,v $
-Revision 1.16  2006/08/14 23:23:55  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.15  2004/06/05 02:01:08  cheshire
-Move DNSServiceRegistration from mDNSMacOSX directory to Clients directory
-
-Revision 1.14  2004/03/04 19:20:23  cheshire
-Remove invalid UTF-8 character
-
-Revision 1.13  2003/08/12 19:55:07  cheshire
-Update to APSL 2.0
-
  */
 
 #include "dns_sd.h"
index f77e1826a2cbc583487ecc0ce6542dbe54f72087..e578e23935f5f3d941da87e8f3e141ab4313363f 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: ClassFactory.cpp,v $
-Revision 1.3  2006/08/14 23:24:00  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:21  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:34:59  rpantos
-Move to Clients from mDNSWindows
-
-Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
-
 */
 
 #include       "StdAfx.h"
index f5fe9d59c148df1dcff33cddb50c37a403d3d70c..5eb4bbd0b1730a39082afb2a45abd308e336d0bc 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: ClassFactory.h,v $
-Revision 1.3  2006/08/14 23:24:00  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:21  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:34:59  rpantos
-Move to Clients from mDNSWindows
-
-Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
-
-*/
+ */
 
 #ifndef __CLASS_FACTORY__
 #define __CLASS_FACTORY__
index 3aea9a299561b7e467fffc58277f52bfcf70de5d..644515fe464cf444b2f16f60a6db87b639e25dee 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: ExplorerBar.cpp,v $
-Revision 1.5  2009/03/30 18:44:53  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.4  2006/08/14 23:24:00  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2004/07/26 05:44:08  shersche
-remove extraneous debug statement
-
-Revision 1.2  2004/07/13 21:24:21  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:34:59  rpantos
-Move to Clients from mDNSWindows
-
-Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
-
-*/
+ */
 
 #include       "StdAfx.h"
 
index 988f8c3977d400612949a9966baf030cfea28a33..d1a84444fb1e2306655b96b141a465834fc836e8 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: ExplorerBar.h,v $
-Revision 1.4  2009/03/30 18:46:13  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.3  2006/08/14 23:24:00  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:21  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:34:59  rpantos
-Move to Clients from mDNSWindows
-
-Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
-
-*/
+ */
 
 #ifndef        __EXPLORER_BAR__
 #define        __EXPLORER_BAR__
index 7b5b2ea401070dbae06902e4c46bb727fe993747..5e0692aa2476bbc9473319812b84f3ee5e1e8f23 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: ExplorerBarWindow.cpp,v $
-Revision 1.23  2009/03/30 18:47:40  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.22  2006/08/14 23:24:00  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.21  2005/04/06 01:13:07  shersche
-<rdar://problem/4066195> Use the product icon instead of globe icon for 'About' link.
-
-Revision 1.20  2005/03/18 02:43:02  shersche
-<rdar://problem/4046443> Use standard IE website icon for 'About Bonjour', only using globe icon if standard icon cannot be loaded
-
-Revision 1.19  2005/03/16 03:46:27  shersche
-<rdar://problem/4045657> Use Bonjour icon for all discovered sites
-
-Revision 1.18  2005/02/26 01:24:05  shersche
-Remove display lines in tree control
-
-Revision 1.17  2005/02/25 19:57:30  shersche
-<rdar://problem/4023323> Remove FTP browsing from plugin
-
-Revision 1.16  2005/02/08 23:31:06  shersche
-Move "About ..." item underneath WebSites, change icons for discovered sites and "About ..." item
-
-Revision 1.15  2005/01/27 22:38:27  shersche
-add About item to tree list
-
-Revision 1.14  2005/01/25 17:55:39  shersche
-<rdar://problem/3911084> Get bitmaps from non-localizable resource module
-Bug #: 3911084
-
-Revision 1.13  2005/01/06 21:13:09  shersche
-<rdar://problem/3796779> Handle kDNSServiceErr_Firewall return codes
-Bug #: 3796779
-
-Revision 1.12  2004/10/26 00:56:03  cheshire
-Use "#if 0" instead of commenting out code
-
-Revision 1.11  2004/10/18 23:49:17  shersche
-<rdar://problem/3841564> Remove trailing dot from hostname, because some flavors of Windows have difficulty parsing hostnames with a trailing dot.
-Bug #: 3841564
-
-Revision 1.10  2004/09/02 02:18:58  cheshire
-Minor textual cleanup to improve readability
-
-Revision 1.9  2004/09/02 02:11:56  cheshire
-<rdar://problem/3783611> Fix incorrect testing of MoreComing flag
-
-Revision 1.8  2004/07/26 05:47:31  shersche
-use TXTRecord APIs, fix bug in locating service to be removed
-
-Revision 1.7  2004/07/22 16:08:20  shersche
-clean up debug print statements, re-enable code inadvertently commented out
-
-Revision 1.6  2004/07/22 05:27:20  shersche
-<rdar://problem/3735827> Check to make sure error isn't WSAEWOULDBLOCK when canceling browse
-Bug #: 3735827
-
-Revision 1.5  2004/07/20 06:49:18  shersche
-clean up socket handling code
-
-Revision 1.4  2004/07/13 21:24:21  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.3  2004/06/27 14:59:59  shersche
-reference count service info to handle multi-homed hosts
-
-Revision 1.2  2004/06/23 16:09:34  shersche
-Add the resolve DNSServiceRef to list of extant refs.  This fixes the "doesn't resolve when double clicking" problem
-
-Submitted by: Scott Herscher
-
-Revision 1.1  2004/06/18 04:34:59  rpantos
-Move to Clients from mDNSWindows
-
-Revision 1.5  2004/04/15 01:00:05  bradley
-Removed support for automatically querying for A/AAAA records when resolving names. Platforms
-without .local name resolving support will need to manually query for A/AAAA records as needed.
-
-Revision 1.4  2004/04/09 21:03:15  bradley
-Changed port numbers to use network byte order for consistency with other platforms.
-
-Revision 1.3  2004/04/08 09:43:43  bradley
-Changed callback calling conventions to __stdcall so they can be used with C# delegates.
-
-Revision 1.2  2004/02/21 04:36:19  bradley
-Enable dot local name lookups now that the NSP is being installed.
-
-Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
-
-*/
+ */
 
 #include       "StdAfx.h"
 
@@ -234,6 +138,9 @@ int ExplorerBarWindow::OnCreate( LPCREATESTRUCT inCreateStruct )
        
        ServiceHandlerEntry *           e;
        
+       s.LoadString( IDS_ABOUT );
+       m_about = mTree.InsertItem( s, 0, 0 );
+
        // Web Site Handler
        
        e = new ServiceHandlerEntry;
@@ -245,9 +152,6 @@ int ExplorerBarWindow::OnCreate( LPCREATESTRUCT inCreateStruct )
        e->needsLogin           = false;
        mServiceHandlers.Add( e );
 
-       s.LoadString( IDS_ABOUT );
-       m_about = mTree.InsertItem( s, 0, 0 );
-
        err = DNSServiceBrowse( &e->ref, 0, 0, e->type, NULL, BrowseCallBack, e );
        require_noerr( err, exit );
 
@@ -256,6 +160,25 @@ int        ExplorerBarWindow::OnCreate( LPCREATESTRUCT inCreateStruct )
 
        m_serviceRefs.push_back(e->ref);
 
+#if defined( _BROWSE_FOR_HTTPS_ )
+       e = new ServiceHandlerEntry;
+       check( e );
+       e->type                         = "_https._tcp";
+       e->urlScheme            = "https://";
+       e->ref                          = NULL;
+       e->obj                          = this;
+       e->needsLogin           = false;
+       mServiceHandlers.Add( e );
+
+       err = DNSServiceBrowse( &e->ref, 0, 0, e->type, NULL, BrowseCallBack, e );
+       require_noerr( err, exit );
+
+       err = WSAAsyncSelect((SOCKET) DNSServiceRefSockFD(e->ref), m_hWnd, WM_PRIVATE_SERVICE_EVENT, FD_READ|FD_CLOSE);
+       require_noerr( err, exit );
+
+       m_serviceRefs.push_back(e->ref);
+#endif
+       
        m_imageList.Create( 16, 16, ILC_MASK | ILC_COLOR16, 2, 0);
 
        bitmap.Attach( ::LoadBitmap( GetNonLocalizedResources(), MAKEINTRESOURCE( IDB_LOGO ) ) );
index 0bbbcae1b25c2eec44e99d6bd7879348988df62a..cda61ec661b88fdd12dfaa3e5738e2e48df28cc3 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: ExplorerBarWindow.h,v $
-Revision 1.9  2009/03/30 18:49:15  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.8  2006/08/14 23:24:00  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.7  2005/02/25 19:57:30  shersche
-<rdar://problem/4023323> Remove FTP browsing from plugin
-
-Revision 1.6  2005/01/27 22:27:03  shersche
-Add m_about member for "About ..." tree item
-
-Revision 1.5  2004/07/26 05:47:31  shersche
-use TXTRecord APIs, fix bug in locating service to be removed
-
-Revision 1.4  2004/07/20 06:49:18  shersche
-clean up socket handling code
-
-Revision 1.3  2004/07/13 21:24:21  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.2  2004/06/27 14:59:59  shersche
-reference count service info to handle multi-homed hosts
-
-Revision 1.1  2004/06/18 04:34:59  rpantos
-Move to Clients from mDNSWindows
-
-Revision 1.3  2004/04/15 01:00:05  bradley
-Removed support for automatically querying for A/AAAA records when resolving names. Platforms
-without .local name resolving support will need to manually query for A/AAAA records as needed.
-
-Revision 1.2  2004/04/08 09:43:43  bradley
-Changed callback calling conventions to __stdcall so they can be used with C# delegates.
-
-Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
-
-*/
+ */
 
 #ifndef        __EXPLORER_BAR_WINDOW__
 #define        __EXPLORER_BAR_WINDOW__
index b83dac843a0a3856374f3efc54c2d757aaa1ded6..fb1b7c2429273c7fef436766dcf6f07bd9ea4f32 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: ExplorerPlugin.cpp,v $
-Revision 1.10  2009/03/30 18:51:04  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.9  2006/08/14 23:24:00  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.8  2005/06/30 18:01:54  shersche
-<rdar://problem/4130635> Cause IE to rebuild cache so we don't have to reboot following an install.
-
-Revision 1.7  2005/02/23 02:00:45  shersche
-<rdar://problem/4014479> Delete all the registry entries when component is unregistered
-
-Revision 1.6  2005/01/25 17:56:45  shersche
-<rdar://problem/3911084> Load resource DLLs, get icons and bitmaps from resource DLLs
-Bug #: 3911084
-
-Revision 1.5  2004/09/15 10:33:54  shersche
-<rdar://problem/3721611> Install XP toolbar button (8 bit mask) if running on XP platform, otherwise install 1 bit mask toolbar button
-Bug #: 3721611
-
-Revision 1.4  2004/07/13 21:24:21  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.3  2004/06/26 14:12:07  shersche
-Register the toolbar button
-
-Revision 1.2  2004/06/24 20:09:39  shersche
-Change text
-Submitted by: herscher
-
-Revision 1.1  2004/06/18 04:34:59  rpantos
-Move to Clients from mDNSWindows
-
-Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
-
-*/
+ */
 
 #include       "StdAfx.h"
 
index acef773ff9b3443c6cf5201908506700f8b42e91..8b931d1028f2fd3d3ec64afdd4fca94d8970c270 100644 (file)
 ; See the License for the specific language governing permissions and
 ; limitations under the License.
 ;
-;      Change History (most recent first):
-;    
-; $Log: ExplorerPlugin.def,v $
-; Revision 1.3  2006/08/14 23:24:00  cheshire
-; Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-;
-; Revision 1.2  2004/07/13 21:24:21  rpantos
-; Fix for <rdar://problem/3701120>.
-;
-; Revision 1.1  2004/06/18 04:34:59  rpantos
-; Move to Clients from mDNSWindows
-;
-; Revision 1.1  2004/01/30 03:01:56  bradley
-; Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
-;
-;
 
 LIBRARY                ExplorerPlugin
 
index 307c99a57999ee03a6a26ecb0d4174fca84880b8..9b87d970785e0653d83a89ca40725bc2044cb4f7 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: ExplorerPlugin.h,v $
-Revision 1.5  2009/03/30 18:52:02  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.4  2006/08/14 23:24:00  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2005/01/25 18:35:38  shersche
-Declare APIs for obtaining handles to resource modules
-
-Revision 1.2  2004/07/13 21:24:21  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:34:59  rpantos
-Move to Clients from mDNSWindows
-
-Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
-
-*/
+ */
 
 #pragma once
 
index 78e74436c44aab24ee9d444ec74bbfcf5cb7e555..c157cfb29c6b39c733ac2e3a06c1f3e63fab2832 100644 (file)
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                  &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                  &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
                <Configuration\r
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                  &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                  &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
        </Configurations>\r
index b17cf3bfb98c5dd4a0b158bcb6ebb55f60267814..9f4c4f5bfd0087ef313d4288d587334e8fe34cf8 100755 (executable)
@@ -131,7 +131,7 @@ BEGIN
     CONTROL         "",IDC_COMPONENT_VERSION,"Static",\r
                     SS_SIMPLE | WS_GROUP,142,10,122,8\r
     LTEXT           "Copyright (c) 2004-2007 Apple Inc. All rights reserved. Apple and the Apple logo are trademarks of Apple Inc., registered in the U.S. and other countries.",\r
-                    IDC_LEGAL,92,31,123,50,0,WS_EX_RTLREADING\r
+                    IDC_LEGAL,92,31,123,50,0\r
 END\r
 \r
 \r
index 54b03923593dc9b54fff8a3a42c4971710f646b2..f354cf2a4e8cfbf6b82bd4ca2c23e9105b8f2593 100755 (executable)
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources\en.lproj&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources\en.lproj&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                                          &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources\en.lproj&quot;&#x0D;&#x0A;:END"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ExplorerPlugin.Resources\en.lproj&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ExplorerPlugin.Resources\en.lproj&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                                          &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ExplorerPlugin.Resources\en.lproj&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
                <Configuration\r
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources\en.lproj&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources\en.lproj&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                                          &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources\en.lproj&quot;&#x0D;&#x0A;:END"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ExplorerPlugin.Resources\en.lproj&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ExplorerPlugin.Resources\en.lproj&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                                          &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ExplorerPlugin.Resources\en.lproj&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
        </Configurations>\r
index 3c73311f1636cb9b884852e61b879150a2d7f559..6b940ac864528b4e0569f43199f52780bdfd46e5 100755 (executable)
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                            &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources&quot;&#x0D;&#x0A;:END"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ExplorerPlugin.Resources&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ExplorerPlugin.Resources&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                            &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ExplorerPlugin.Resources&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
                <Configuration\r
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                            &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\ExplorerPlugin.Resources&quot;&#x0D;&#x0A;:END"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ExplorerPlugin.Resources&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ExplorerPlugin.Resources&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                            &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ExplorerPlugin.Resources&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
        </Configurations>\r
                        Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest"\r
                        >\r
                        <File\r
-                               RelativePath="res\about.bmp"\r
+                               RelativePath=".\about.bmp"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\about.bmp"\r
+                               RelativePath="res\about.bmp"\r
                                >\r
                        </File>\r
                        <File\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath="res\logo.bmp"\r
+                               RelativePath=".\logo.bmp"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\logo.bmp"\r
+                               RelativePath="res\logo.bmp"\r
                                >\r
                        </File>\r
                        <File\r
index c2afe223d4014d67e90fa07fc9cd8991e97c7b6c..a2cc89ef6e39a1fcdfef419d04d9823a4eefe297 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: LoginDialog.cpp,v $
-Revision 1.3  2006/08/14 23:24:00  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:21  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:34:59  rpantos
-Move to Clients from mDNSWindows
-
-Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
-
-*/
+ */
 
 #include       <assert.h>
 #include       <stdlib.h>
index 0f7bee6725315d90b0749fff4dbef0a7bf55e92b..e53beb6bbfd1ec470953d018b6081ed09f9585d6 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: LoginDialog.h,v $
-Revision 1.3  2006/08/14 23:24:00  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:21  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:34:59  rpantos
-Move to Clients from mDNSWindows
-
-Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
-
-*/
+ */
 
 #ifndef        __LOGIN_DIALOG__
 #define        __LOGIN_DIALOG__
index 9b1f0abe49bc84a423a0f1212567b0769891c957..7235f38c0b9f403fb9f1154109d536fefe242df7 100644 (file)
@@ -13,9 +13,6 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
  */
 
 // Include the core resources
index 1d644951dc0988733c544bdfcb3f925b29f62843..768fa3f91528cae8997dfa483a56159dccf808c7 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: StdAfx.cpp,v $
-Revision 1.3  2006/08/14 23:24:00  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:21  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:34:59  rpantos
-Move to Clients from mDNSWindows
-
-Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
-
-*/
+ */
 
 #include       "StdAfx.h"
index 7976129032d14d1a6c5765adb07abc311dbba9c8..69e8216b7d64496ec34ebe8c2b52e0554b9b87ed 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: StdAfx.h,v $
-Revision 1.4  2006/08/14 23:24:00  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2005/10/19 19:50:34  herscher
-Workaround a bug in the latest Microsoft Platform SDK when compiling C++ files that include (directly or indirectly) <WspiApi.h>
-
-Revision 1.2  2004/07/13 21:24:21  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:34:59  rpantos
-Move to Clients from mDNSWindows
-
-Revision 1.1  2004/01/30 03:01:56  bradley
-Explorer Plugin to browse for DNS-SD advertised Web and FTP servers from within Internet Explorer.
-
-*/
+ */
 
 #ifndef __STDAFX__
 #define __STDAFX__
diff --git a/Clients/FirefoxExtension/CDNSSDService.cpp b/Clients/FirefoxExtension/CDNSSDService.cpp
new file mode 100755 (executable)
index 0000000..ae57da9
--- /dev/null
@@ -0,0 +1,394 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CDNSSDService.h"
+#include "nsThreadUtils.h"
+#include "nsIEventTarget.h"
+#include "private/pprio.h"
+#include <string>
+#include <stdio.h>
+
+
+NS_IMPL_ISUPPORTS2(CDNSSDService, IDNSSDService, nsIRunnable)
+
+CDNSSDService::CDNSSDService()
+:
+       m_master( 1 ),
+       m_threadPool( NULL ),
+       m_mainRef( NULL ),
+       m_subRef( NULL ),
+       m_listener( NULL ),
+       m_fileDesc( NULL ),
+       m_job( NULL )
+{
+       nsresult err;
+
+       if ( DNSServiceCreateConnection( &m_mainRef ) != kDNSServiceErr_NoError )
+       {
+               err = NS_ERROR_FAILURE;
+               goto exit;
+       }
+
+       if ( ( m_fileDesc = PR_ImportTCPSocket( DNSServiceRefSockFD( m_mainRef ) ) ) == NULL )
+       {
+               err = NS_ERROR_FAILURE;
+               goto exit;
+       }
+
+       if ( ( m_threadPool = PR_CreateThreadPool( 1, 1, 8192 ) ) == NULL )
+       {
+               err = NS_ERROR_FAILURE;
+               goto exit;
+       }
+       
+       err = SetupNotifications();
+
+exit:
+
+       if ( err != NS_OK )
+       {
+               Cleanup();
+       }
+}
+
+
+CDNSSDService::CDNSSDService( DNSServiceRef ref, nsISupports * listener )
+:
+       m_master( 0 ),
+       m_threadPool( NULL ),
+       m_mainRef( ref ),
+       m_subRef( ref ),
+       m_listener( listener ),
+       m_fileDesc( NULL ),
+       m_job( NULL )
+{
+}
+
+
+CDNSSDService::~CDNSSDService()
+{
+       Cleanup();
+}
+
+
+void
+CDNSSDService::Cleanup()
+{
+       if ( m_master )
+       {
+               if ( m_job )
+               {
+                       PR_CancelJob( m_job );
+                       m_job = NULL;
+               }
+
+               if ( m_threadPool != NULL )
+               {       
+                       PR_ShutdownThreadPool( m_threadPool );
+                       m_threadPool = NULL;
+               }
+       
+               if ( m_fileDesc != NULL )
+               {
+                       PR_Close( m_fileDesc );
+                       m_fileDesc = NULL;
+               }
+
+               if ( m_mainRef )
+               {
+                       DNSServiceRefDeallocate( m_mainRef );
+                       m_mainRef = NULL;
+               }
+       }
+       else
+       {
+               if ( m_subRef )
+               {
+                       DNSServiceRefDeallocate( m_subRef );
+                       m_subRef = NULL;
+               }
+       }
+}
+
+
+nsresult
+CDNSSDService::SetupNotifications()
+{
+       NS_PRECONDITION( m_threadPool != NULL, "m_threadPool is NULL" );
+       NS_PRECONDITION( m_fileDesc != NULL, "m_fileDesc is NULL" );
+       NS_PRECONDITION( m_job == NULL, "m_job is not NULL" );
+
+       m_iod.socket    = m_fileDesc;
+       m_iod.timeout   = PR_INTERVAL_MAX;
+       m_job                   = PR_QueueJob_Read( m_threadPool, &m_iod, Read, this, PR_FALSE );       
+       return ( m_job ) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+
+/* IDNSSDService browse (in long interfaceIndex, in AString regtype, in AString domain, in IDNSSDBrowseListener listener); */
+NS_IMETHODIMP
+CDNSSDService::Browse(PRInt32 interfaceIndex, const nsAString & regtype, const nsAString & domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM)
+{
+       CDNSSDService   *       service = NULL;
+       DNSServiceErrorType dnsErr      = 0;
+       nsresult                        err             = 0;
+
+       *_retval = NULL;
+       
+       if ( !m_mainRef )
+       {
+               err = NS_ERROR_NOT_AVAILABLE;
+               goto exit;
+       }
+
+       try
+       {
+               service = new CDNSSDService( m_mainRef, listener );
+       }
+       catch ( ... )
+       {
+               service = NULL;
+       }
+       
+       if ( service == NULL )
+       {
+               err = NS_ERROR_FAILURE;
+               goto exit;
+       }
+       
+       dnsErr = DNSServiceBrowse( &service->m_subRef, kDNSServiceFlagsShareConnection, interfaceIndex, NS_ConvertUTF16toUTF8( regtype ).get(), NS_ConvertUTF16toUTF8( domain ).get(), ( DNSServiceBrowseReply ) BrowseReply, service );
+       
+       if ( dnsErr != kDNSServiceErr_NoError )
+       {
+               err = NS_ERROR_FAILURE;
+               goto exit;
+       }
+       
+       listener->AddRef();
+       service->AddRef();
+       *_retval = service;
+       err = NS_OK;
+       
+exit:
+
+       if ( err && service )
+       {
+               delete service;
+               service = NULL;
+       }
+       
+       return err;
+}
+
+
+/* IDNSSDService resolve (in long interfaceIndex, in AString name, in AString regtype, in AString domain, in IDNSSDResolveListener listener); */
+NS_IMETHODIMP
+CDNSSDService::Resolve(PRInt32 interfaceIndex, const nsAString & name, const nsAString & regtype, const nsAString & domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM)
+{
+    CDNSSDService      *       service;
+       DNSServiceErrorType dnsErr;
+       nsresult                        err;
+
+       *_retval = NULL;
+       
+       if ( !m_mainRef )
+       {
+               err = NS_ERROR_NOT_AVAILABLE;
+               goto exit;
+       }
+
+       try
+       {
+               service = new CDNSSDService( m_mainRef, listener );
+       }
+       catch ( ... )
+       {
+               service = NULL;
+       }
+       
+       if ( service == NULL )
+       {
+               err = NS_ERROR_FAILURE;
+               goto exit;
+       }
+
+       dnsErr = DNSServiceResolve( &service->m_subRef, kDNSServiceFlagsShareConnection, interfaceIndex, NS_ConvertUTF16toUTF8( name ).get(), NS_ConvertUTF16toUTF8( regtype ).get(), NS_ConvertUTF16toUTF8( domain ).get(), ( DNSServiceResolveReply ) ResolveReply, service );
+       
+       if ( dnsErr != kDNSServiceErr_NoError )
+       {
+               err = NS_ERROR_FAILURE;
+               goto exit;
+       }
+       
+       listener->AddRef();
+       service->AddRef();
+       *_retval = service;
+       err = NS_OK;
+       
+exit:
+       
+       if ( err && service )
+       {
+               delete service;
+               service = NULL;
+       }
+       
+       return err;
+}
+
+
+/* void stop (); */
+NS_IMETHODIMP
+CDNSSDService::Stop()
+{
+    if ( m_subRef )
+       {
+               DNSServiceRefDeallocate( m_subRef );
+               m_subRef = NULL;
+       }
+       
+       return NS_OK;
+}
+
+
+void
+CDNSSDService::Read( void * arg )
+{
+       NS_PRECONDITION( arg != NULL, "arg is NULL" );
+       
+       NS_DispatchToMainThread( ( CDNSSDService* ) arg );
+}
+
+
+NS_IMETHODIMP
+CDNSSDService::Run()
+{
+       nsresult err = NS_OK;
+       
+       NS_PRECONDITION( m_mainRef != NULL, "m_mainRef is NULL" );
+
+       m_job = NULL;
+
+       if ( PR_Available( m_fileDesc ) > 0 )
+       {
+               if ( DNSServiceProcessResult( m_mainRef ) != kDNSServiceErr_NoError )
+               {
+                       err = NS_ERROR_FAILURE;
+               }
+       }
+
+       if ( !err )
+       {
+               err = SetupNotifications();
+       }
+       
+       return err;
+}
+
+
+void DNSSD_API
+CDNSSDService::BrowseReply
+               (
+               DNSServiceRef           sdRef,
+               DNSServiceFlags         flags,
+               uint32_t                        interfaceIndex,
+               DNSServiceErrorType     errorCode,
+               const char              *       serviceName,
+               const char              *       regtype,
+               const char              *       replyDomain,
+               void                    *       context
+               )
+{
+       CDNSSDService * self = ( CDNSSDService* ) context;
+
+       // This should never be NULL, but let's be defensive.
+       
+       if ( self != NULL )
+       {
+               IDNSSDBrowseListener * listener = ( IDNSSDBrowseListener* ) self->m_listener;
+
+               // Same for this
+
+               if ( listener != NULL )
+               {
+                       listener->OnBrowse( self, ( flags & kDNSServiceFlagsAdd ) ? PR_TRUE : PR_FALSE, interfaceIndex, errorCode, NS_ConvertUTF8toUTF16( serviceName ), NS_ConvertUTF8toUTF16( regtype ), NS_ConvertUTF8toUTF16( replyDomain ) );
+               }
+       }
+}
+
+
+void DNSSD_API
+CDNSSDService::ResolveReply
+               (
+               DNSServiceRef                   sdRef,
+               DNSServiceFlags                 flags,
+               uint32_t                                interfaceIndex,
+               DNSServiceErrorType             errorCode,
+               const char                      *       fullname,
+               const char                      *       hosttarget,
+               uint16_t                                port,
+               uint16_t                                txtLen,
+               const unsigned char     *       txtRecord,
+               void                            *       context
+               )
+{
+       CDNSSDService * self = ( CDNSSDService* ) context;
+       
+       // This should never be NULL, but let's be defensive.
+       
+       if ( self != NULL )
+       {
+               IDNSSDResolveListener * listener = ( IDNSSDResolveListener* ) self->m_listener;
+               
+               // Same for this
+
+               if ( listener != NULL )
+               {
+                       std::string             path = "";
+                       const void      *       value = NULL;
+                       uint8_t                 valueLen = 0;
+
+                       value = TXTRecordGetValuePtr( txtLen, txtRecord, "path", &valueLen );
+                       
+                       if ( value && valueLen )
+                       {
+                               char * temp;
+                               
+                               temp = new char[ valueLen + 2 ];
+                               
+                               if ( temp )
+                               {
+                                       char * dst = temp;
+
+                                       memset( temp, 0, valueLen + 2 );
+
+                                       if ( ( ( char* ) value )[ 0 ] != '/' )
+                                       {
+                                               *dst++ = '/';
+                                       }
+
+                                       memcpy( dst, value, valueLen );
+                                       path = temp;
+                                       delete [] temp;
+                               }
+                       }
+
+                       listener->OnResolve( self, interfaceIndex, errorCode, NS_ConvertUTF8toUTF16( fullname ), NS_ConvertUTF8toUTF16( hosttarget ) , ntohs( port ), NS_ConvertUTF8toUTF16( path.c_str() ) );
+               }
+       }
+}
+
diff --git a/Clients/FirefoxExtension/CDNSSDService.h b/Clients/FirefoxExtension/CDNSSDService.h
new file mode 100755 (executable)
index 0000000..f22ee7b
--- /dev/null
@@ -0,0 +1,104 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef _CDNSSDSERVICE_H
+#define _CDNSSDSERVICE_H
+
+#include "IDNSSDService.h"
+#include "nsCOMPtr.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIThread.h"
+#include "nsIRunnable.h"
+#include "prtpool.h"
+#include <dns_sd.h>
+#include <stdio.h>
+#include <string>
+
+
+#define CDNSSDSERVICE_CONTRACTID "@apple.com/DNSSDService;1"
+#define CDNSSDSERVICE_CLASSNAME "CDNSSDService"
+#define CDNSSDSERVICE_CID { 0x944ED267, 0x465A, 0x4989, { 0x82, 0x72, 0x7E, 0xE9, 0x28, 0x6C, 0x99, 0xA5 } }
+
+
+/* Header file */
+class CDNSSDService : public IDNSSDService, nsIRunnable
+{
+public:
+       NS_DECL_ISUPPORTS
+       NS_DECL_IDNSSDSERVICE
+       NS_DECL_NSIRUNNABLE
+
+       CDNSSDService();
+       CDNSSDService( DNSServiceRef mainRef, nsISupports * listener );
+
+       virtual ~CDNSSDService();
+       
+private:
+
+       static void DNSSD_API
+       BrowseReply
+               (
+               DNSServiceRef           sdRef,
+               DNSServiceFlags         flags,
+               uint32_t                        interfaceIndex,
+               DNSServiceErrorType     errorCode,
+               const char              *       serviceName,
+               const char              *       regtype,
+               const char              *       replyDomain,
+               void                    *       context
+               );
+               
+       static void DNSSD_API
+       ResolveReply
+               (
+               DNSServiceRef                   sdRef,
+               DNSServiceFlags                 flags,
+               uint32_t                                interfaceIndex,
+               DNSServiceErrorType             errorCode,
+               const char                      *       fullname,
+               const char                      *       hosttarget,
+               uint16_t                                port,
+               uint16_t                                txtLen,
+               const unsigned char     *       txtRecord,
+               void                            *       context
+               );
+               
+       static void
+       Read
+               (
+               void * arg
+               );
+               
+       nsresult
+       SetupNotifications();
+       
+       void
+       Cleanup();
+
+       char                            m_master;
+       PRThreadPool    *       m_threadPool;
+       DNSServiceRef           m_mainRef;
+       DNSServiceRef           m_subRef;
+       nsISupports             *       m_listener;
+       PRFileDesc              *       m_fileDesc;
+       PRJobIoDesc                     m_iod;
+       PRJob                   *       m_job;
+};
+
+
+#endif
diff --git a/Clients/FirefoxExtension/CDNSSDServiceModule.cpp b/Clients/FirefoxExtension/CDNSSDServiceModule.cpp
new file mode 100755 (executable)
index 0000000..3833c5a
--- /dev/null
@@ -0,0 +1,37 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "nsIGenericFactory.h"
+#include "CDNSSDService.h"
+
+NS_COM_GLUE nsresult
+NS_NewGenericModule2(nsModuleInfo const *info, nsIModule* *result);
+
+NS_GENERIC_FACTORY_CONSTRUCTOR(CDNSSDService)
+
+static nsModuleComponentInfo components[] =
+{
+    {
+       CDNSSDSERVICE_CLASSNAME, 
+       CDNSSDSERVICE_CID,
+       CDNSSDSERVICE_CONTRACTID,
+       CDNSSDServiceConstructor,
+    }
+};
+
+NS_IMPL_NSGETMODULE("CDNSSDServiceModule", components) 
+
diff --git a/Clients/FirefoxExtension/DNSSDService.sln b/Clients/FirefoxExtension/DNSSDService.sln
new file mode 100755 (executable)
index 0000000..68534f4
--- /dev/null
@@ -0,0 +1,20 @@
+\r
+Microsoft Visual Studio Solution File, Format Version 9.00\r
+# Visual Studio 2005\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DNSSDService", "DNSSDService.vcproj", "{7826EA27-D4CC-4FAA-AD23-DF813823227B}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Debug|Win32 = Debug|Win32\r
+               Release|Win32 = Release|Win32\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Win32.Build.0 = Debug|Win32\r
+               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Win32.ActiveCfg = Release|Win32\r
+               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Win32.Build.0 = Release|Win32\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/Clients/FirefoxExtension/FirefoxExtension.rc b/Clients/FirefoxExtension/FirefoxExtension.rc
new file mode 100644 (file)
index 0000000..998e5e9
--- /dev/null
@@ -0,0 +1,102 @@
+// 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""\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION MASTER_PROD_VERS
+ PRODUCTVERSION MASTER_PROD_VERS
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName", MASTER_COMPANY_NAME
+            VALUE "FileDescription", "Firefox Extension Library"
+            VALUE "FileVersion", MASTER_PROD_VERS_STR
+            VALUE "InternalName", "DNSSDService.dll"
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
+            VALUE "OriginalFilename", "DNSSDService.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.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/Clients/FirefoxExtension/FirefoxExtension.vcproj b/Clients/FirefoxExtension/FirefoxExtension.vcproj
new file mode 100755 (executable)
index 0000000..352fdd6
--- /dev/null
@@ -0,0 +1,282 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="FirefoxExtension"\r
+       ProjectGUID="{7826EA27-D4CC-4FAA-AD23-DF813823227B}"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"\r
+                       UseOfMFC="0"\r
+                       ATLMinimizesCRunTimeLibraryUsage="false"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               MkTypLibCompatible="true"\r
+                               SuppressStartupBanner="true"\r
+                               TargetEnvironment="1"\r
+                               TypeLibraryName=".\$(OutDir)\DNSSDService.tlb"\r
+                               HeaderFileName=""\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="2"\r
+                               InlineFunctionExpansion="1"\r
+                               AdditionalIncludeDirectories="..\..\mDNSShared;&quot;$(SRCROOT)\AppleInternal\XULRunner\include\xpcom&quot;;&quot;$(SRCROOT)\AppleInternal\XULRunner\include\nspr&quot;;&quot;$(SRCROOT)\AppleInternal\XULRunner\include\string&quot;;&quot;$(SRCROOT)\AppleInternal\XULRunner\include\pref&quot;;&quot;$(SRCROOT)\AppleInternal\XULRunner\sdk\include&quot;"\r
+                               PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_USRDLL;DNSSDSERVICE_EXPORTS;XP_WIN;XP_WIN32"\r
+                               StringPooling="true"\r
+                               RuntimeLibrary="0"\r
+                               EnableFunctionLevelLinking="true"\r
+                               PrecompiledHeaderFile=""\r
+                               AssemblerListingLocation="$(IntDir)\"\r
+                               ObjectFile="$(IntDir)\"\r
+                               ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
+                               WarningLevel="3"\r
+                               SuppressStartupBanner="true"\r
+                               ForcedIncludeFiles=""\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories="../../mDNSWindows"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
+                               AdditionalDependencies="$(SRCROOT)\AppleInternal\XULRunner\lib\nspr4.lib $(SRCROOT)\AppleInternal\XULRunner\lib\xpcom.lib $(SRCROOT)\AppleInternal\XULRunner\lib\xpcomglue_s.lib ws2_32.lib ../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib"\r
+                               OutputFile="$(OutDir)\DNSSDService.dll"\r
+                               LinkIncremental="1"\r
+                               SuppressStartupBanner="true"\r
+                               AdditionalLibraryDirectories=""\r
+                               ProgramDatabaseFile=".\$(OutDir)/DNSSDService.pdb"\r
+                               ImportLibrary=".\$(OutDir)/DNSSDService.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                               SuppressStartupBanner="true"\r
+                               OutputFile=".\$(OutDir)\DNSSDService.bsc"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                               CommandLine="xcopy /I/Y $(PlatformName)\$(ConfigurationName)\DNSSDService.dll extension\platform\WINNT\components&#x0D;&#x0A;if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\FirefoxExtension&quot;                      mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\FirefoxExtension&quot;&#x0D;&#x0A;xcopy /E/I/Y &quot;extension&quot;                                 &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\FirefoxExtension&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"\r
+                       UseOfMFC="0"\r
+                       ATLMinimizesCRunTimeLibraryUsage="false"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               MkTypLibCompatible="true"\r
+                               SuppressStartupBanner="true"\r
+                               TargetEnvironment="1"\r
+                               TypeLibraryName=".\$(OutDir)\DNSSDService.tlb"\r
+                               HeaderFileName=""\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="..\..\mDNSShared;&quot;$(SRCROOT)\AppleInternal\XULRunner\include\xpcom&quot;;&quot;$(SRCROOT)\AppleInternal\XULRunner\include\nspr&quot;;&quot;$(SRCROOT)\AppleInternal\XULRunner\include\string&quot;;&quot;$(SRCROOT)\AppleInternal\XULRunner\include\pref&quot;;&quot;$(SRCROOT)\AppleInternal\XULRunner\sdk\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;DNSSDSERVICE_EXPORTS;XP_WIN;XP_WIN32"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               PrecompiledHeaderFile=""\r
+                               AssemblerListingLocation="$(IntDir)\"\r
+                               ObjectFile="$(IntDir)\"\r
+                               ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
+                               WarningLevel="3"\r
+                               SuppressStartupBanner="true"\r
+                               DebugInformationFormat="3"\r
+                               ForcedIncludeFiles=""\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories="../../mDNSWindows"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
+                               AdditionalDependencies="$(SRCROOT)\AppleInternal\XULRunner\lib\nspr4.lib $(SRCROOT)\AppleInternal\XULRunner\lib\xpcom.lib $(SRCROOT)\AppleInternal\XULRunner\lib\xpcomglue_s.lib ws2_32.lib ../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib"\r
+                               OutputFile="$(OutDir)\DNSSDService.dll"\r
+                               LinkIncremental="2"\r
+                               SuppressStartupBanner="true"\r
+                               AdditionalLibraryDirectories=""\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile=".\$(OutDir)\DNSSDService.pdb"\r
+                               ImportLibrary=".\$(OutDir)/DNSSDService.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                               SuppressStartupBanner="true"\r
+                               OutputFile=".\$(OutDir)\DNSSDService.bsc"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                               CommandLine="xcopy /I/Y $(PlatformName)\$(ConfigurationName)\DNSSDService.dll extension\platform\WINNT\components"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\CDNSSDService.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\CDNSSDServiceModule.cpp"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\CDNSSDService.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\IDNSSDService.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="IDL"\r
+                       Filter="idl"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\IDNSSDService.idl"\r
+                               >\r
+                               <FileConfiguration\r
+                                       Name="Release|Win32"\r
+                                       >\r
+                                       <Tool\r
+                                               Name="VCCustomBuildTool"\r
+                                       />\r
+                               </FileConfiguration>\r
+                               <FileConfiguration\r
+                                       Name="Debug|Win32"\r
+                                       >\r
+                                       <Tool\r
+                                               Name="VCCustomBuildTool"\r
+                                       />\r
+                               </FileConfiguration>\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\FirefoxExtension.rc"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/Clients/FirefoxExtension/IDNSSDService.h b/Clients/FirefoxExtension/IDNSSDService.h
new file mode 100755 (executable)
index 0000000..fc7408f
--- /dev/null
@@ -0,0 +1,263 @@
+/*\r
+ * DO NOT EDIT.  THIS FILE IS GENERATED FROM IDNSSDService.idl\r
+ */\r
+\r
+#ifndef __gen_IDNSSDService_h__\r
+#define __gen_IDNSSDService_h__\r
+\r
+\r
+#ifndef __gen_nsISupports_h__\r
+#include "nsISupports.h"\r
+#endif\r
+\r
+/* For IDL files that don't want to include root IDL files. */\r
+#ifndef NS_NO_VTABLE\r
+#define NS_NO_VTABLE\r
+#endif\r
+class IDNSSDService; /* forward declaration */\r
+\r
+\r
+/* starting interface:    IDNSSDBrowseListener */\r
+#define IDNSSDBROWSELISTENER_IID_STR "27346495-a1ed-458a-a5bc-587df9a26b4f"\r
+\r
+#define IDNSSDBROWSELISTENER_IID \\r
+  {0x27346495, 0xa1ed, 0x458a, \\r
+    { 0xa5, 0xbc, 0x58, 0x7d, 0xf9, 0xa2, 0x6b, 0x4f }}\r
+\r
+class NS_NO_VTABLE NS_SCRIPTABLE IDNSSDBrowseListener : public nsISupports {\r
+ public: \r
+\r
+  NS_DECLARE_STATIC_IID_ACCESSOR(IDNSSDBROWSELISTENER_IID)\r
+\r
+  /* void onBrowse (in IDNSSDService service, in boolean add, in long interfaceIndex, in long error, in AString serviceName, in AString regtype, in AString domain); */\r
+  NS_SCRIPTABLE NS_IMETHOD OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString & serviceName, const nsAString & regtype, const nsAString & domain) = 0;\r
+\r
+};\r
+\r
+  NS_DEFINE_STATIC_IID_ACCESSOR(IDNSSDBrowseListener, IDNSSDBROWSELISTENER_IID)\r
+\r
+/* Use this macro when declaring classes that implement this interface. */\r
+#define NS_DECL_IDNSSDBROWSELISTENER \\r
+  NS_SCRIPTABLE NS_IMETHOD OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString & serviceName, const nsAString & regtype, const nsAString & domain); \r
+\r
+/* Use this macro to declare functions that forward the behavior of this interface to another object. */\r
+#define NS_FORWARD_IDNSSDBROWSELISTENER(_to) \\r
+  NS_SCRIPTABLE NS_IMETHOD OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString & serviceName, const nsAString & regtype, const nsAString & domain) { return _to OnBrowse(service, add, interfaceIndex, error, serviceName, regtype, domain); } \r
+\r
+/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */\r
+#define NS_FORWARD_SAFE_IDNSSDBROWSELISTENER(_to) \\r
+  NS_SCRIPTABLE NS_IMETHOD OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString & serviceName, const nsAString & regtype, const nsAString & domain) { return !_to ? NS_ERROR_NULL_POINTER : _to->OnBrowse(service, add, interfaceIndex, error, serviceName, regtype, domain); } \r
+\r
+#if 0\r
+/* Use the code below as a template for the implementation class for this interface. */\r
+\r
+/* Header file */\r
+class _MYCLASS_ : public IDNSSDBrowseListener\r
+{\r
+public:\r
+  NS_DECL_ISUPPORTS\r
+  NS_DECL_IDNSSDBROWSELISTENER\r
+\r
+  _MYCLASS_();\r
+\r
+private:\r
+  ~_MYCLASS_();\r
+\r
+protected:\r
+  /* additional members */\r
+};\r
+\r
+/* Implementation file */\r
+NS_IMPL_ISUPPORTS1(_MYCLASS_, IDNSSDBrowseListener)\r
+\r
+_MYCLASS_::_MYCLASS_()\r
+{\r
+  /* member initializers and constructor code */\r
+}\r
+\r
+_MYCLASS_::~_MYCLASS_()\r
+{\r
+  /* destructor code */\r
+}\r
+\r
+/* void onBrowse (in IDNSSDService service, in boolean add, in long interfaceIndex, in long error, in AString serviceName, in AString regtype, in AString domain); */\r
+NS_IMETHODIMP _MYCLASS_::OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString & serviceName, const nsAString & regtype, const nsAString & domain)\r
+{\r
+    return NS_ERROR_NOT_IMPLEMENTED;\r
+}\r
+\r
+/* End of implementation class template. */\r
+#endif\r
+\r
+\r
+/* starting interface:    IDNSSDResolveListener */\r
+#define IDNSSDRESOLVELISTENER_IID_STR "6620e18f-47f3-47c6-941f-126a5fd4fcf7"\r
+\r
+#define IDNSSDRESOLVELISTENER_IID \\r
+  {0x6620e18f, 0x47f3, 0x47c6, \\r
+    { 0x94, 0x1f, 0x12, 0x6a, 0x5f, 0xd4, 0xfc, 0xf7 }}\r
+\r
+class NS_NO_VTABLE NS_SCRIPTABLE IDNSSDResolveListener : public nsISupports {\r
+ public: \r
+\r
+  NS_DECLARE_STATIC_IID_ACCESSOR(IDNSSDRESOLVELISTENER_IID)\r
+\r
+  /* void onResolve (in IDNSSDService service, in long interfaceIndex, in long error, in AString fullname, in AString host, in short port, in AString path); */\r
+  NS_SCRIPTABLE NS_IMETHOD OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString & fullname, const nsAString & host, PRInt16 port, const nsAString & path) = 0;\r
+\r
+};\r
+\r
+  NS_DEFINE_STATIC_IID_ACCESSOR(IDNSSDResolveListener, IDNSSDRESOLVELISTENER_IID)\r
+\r
+/* Use this macro when declaring classes that implement this interface. */\r
+#define NS_DECL_IDNSSDRESOLVELISTENER \\r
+  NS_SCRIPTABLE NS_IMETHOD OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString & fullname, const nsAString & host, PRInt16 port, const nsAString & path); \r
+\r
+/* Use this macro to declare functions that forward the behavior of this interface to another object. */\r
+#define NS_FORWARD_IDNSSDRESOLVELISTENER(_to) \\r
+  NS_SCRIPTABLE NS_IMETHOD OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString & fullname, const nsAString & host, PRInt16 port, const nsAString & path) { return _to OnResolve(service, interfaceIndex, error, fullname, host, port, path); } \r
+\r
+/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */\r
+#define NS_FORWARD_SAFE_IDNSSDRESOLVELISTENER(_to) \\r
+  NS_SCRIPTABLE NS_IMETHOD OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString & fullname, const nsAString & host, PRInt16 port, const nsAString & path) { return !_to ? NS_ERROR_NULL_POINTER : _to->OnResolve(service, interfaceIndex, error, fullname, host, port, path); } \r
+\r
+#if 0\r
+/* Use the code below as a template for the implementation class for this interface. */\r
+\r
+/* Header file */\r
+class _MYCLASS_ : public IDNSSDResolveListener\r
+{\r
+public:\r
+  NS_DECL_ISUPPORTS\r
+  NS_DECL_IDNSSDRESOLVELISTENER\r
+\r
+  _MYCLASS_();\r
+\r
+private:\r
+  ~_MYCLASS_();\r
+\r
+protected:\r
+  /* additional members */\r
+};\r
+\r
+/* Implementation file */\r
+NS_IMPL_ISUPPORTS1(_MYCLASS_, IDNSSDResolveListener)\r
+\r
+_MYCLASS_::_MYCLASS_()\r
+{\r
+  /* member initializers and constructor code */\r
+}\r
+\r
+_MYCLASS_::~_MYCLASS_()\r
+{\r
+  /* destructor code */\r
+}\r
+\r
+/* void onResolve (in IDNSSDService service, in long interfaceIndex, in long error, in AString fullname, in AString host, in short port, in AString path); */\r
+NS_IMETHODIMP _MYCLASS_::OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString & fullname, const nsAString & host, PRInt16 port, const nsAString & path)\r
+{\r
+    return NS_ERROR_NOT_IMPLEMENTED;\r
+}\r
+\r
+/* End of implementation class template. */\r
+#endif\r
+\r
+\r
+/* starting interface:    IDNSSDService */\r
+#define IDNSSDSERVICE_IID_STR "3a3539ff-f8d8-40b4-8d02-5ea73c51fa12"\r
+\r
+#define IDNSSDSERVICE_IID \\r
+  {0x3a3539ff, 0xf8d8, 0x40b4, \\r
+    { 0x8d, 0x02, 0x5e, 0xa7, 0x3c, 0x51, 0xfa, 0x12 }}\r
+\r
+class NS_NO_VTABLE NS_SCRIPTABLE IDNSSDService : public nsISupports {\r
+ public: \r
+\r
+  NS_DECLARE_STATIC_IID_ACCESSOR(IDNSSDSERVICE_IID)\r
+\r
+  /* IDNSSDService browse (in long interfaceIndex, in AString regtype, in AString domain, in IDNSSDBrowseListener listener); */\r
+  NS_SCRIPTABLE NS_IMETHOD Browse(PRInt32 interfaceIndex, const nsAString & regtype, const nsAString & domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM) = 0;\r
+\r
+  /* IDNSSDService resolve (in long interfaceIndex, in AString name, in AString regtype, in AString domain, in IDNSSDResolveListener listener); */\r
+  NS_SCRIPTABLE NS_IMETHOD Resolve(PRInt32 interfaceIndex, const nsAString & name, const nsAString & regtype, const nsAString & domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM) = 0;\r
+\r
+  /* void stop (); */\r
+  NS_SCRIPTABLE NS_IMETHOD Stop(void) = 0;\r
+\r
+};\r
+\r
+  NS_DEFINE_STATIC_IID_ACCESSOR(IDNSSDService, IDNSSDSERVICE_IID)\r
+\r
+/* Use this macro when declaring classes that implement this interface. */\r
+#define NS_DECL_IDNSSDSERVICE \\r
+  NS_SCRIPTABLE NS_IMETHOD Browse(PRInt32 interfaceIndex, const nsAString & regtype, const nsAString & domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM); \\r
+  NS_SCRIPTABLE NS_IMETHOD Resolve(PRInt32 interfaceIndex, const nsAString & name, const nsAString & regtype, const nsAString & domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM); \\r
+  NS_SCRIPTABLE NS_IMETHOD Stop(void); \r
+\r
+/* Use this macro to declare functions that forward the behavior of this interface to another object. */\r
+#define NS_FORWARD_IDNSSDSERVICE(_to) \\r
+  NS_SCRIPTABLE NS_IMETHOD Browse(PRInt32 interfaceIndex, const nsAString & regtype, const nsAString & domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM) { return _to Browse(interfaceIndex, regtype, domain, listener, _retval); } \\r
+  NS_SCRIPTABLE NS_IMETHOD Resolve(PRInt32 interfaceIndex, const nsAString & name, const nsAString & regtype, const nsAString & domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM) { return _to Resolve(interfaceIndex, name, regtype, domain, listener, _retval); } \\r
+  NS_SCRIPTABLE NS_IMETHOD Stop(void) { return _to Stop(); } \r
+\r
+/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */\r
+#define NS_FORWARD_SAFE_IDNSSDSERVICE(_to) \\r
+  NS_SCRIPTABLE NS_IMETHOD Browse(PRInt32 interfaceIndex, const nsAString & regtype, const nsAString & domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM) { return !_to ? NS_ERROR_NULL_POINTER : _to->Browse(interfaceIndex, regtype, domain, listener, _retval); } \\r
+  NS_SCRIPTABLE NS_IMETHOD Resolve(PRInt32 interfaceIndex, const nsAString & name, const nsAString & regtype, const nsAString & domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM) { return !_to ? NS_ERROR_NULL_POINTER : _to->Resolve(interfaceIndex, name, regtype, domain, listener, _retval); } \\r
+  NS_SCRIPTABLE NS_IMETHOD Stop(void) { return !_to ? NS_ERROR_NULL_POINTER : _to->Stop(); } \r
+\r
+#if 0\r
+/* Use the code below as a template for the implementation class for this interface. */\r
+\r
+/* Header file */\r
+class _MYCLASS_ : public IDNSSDService\r
+{\r
+public:\r
+  NS_DECL_ISUPPORTS\r
+  NS_DECL_IDNSSDSERVICE\r
+\r
+  _MYCLASS_();\r
+\r
+private:\r
+  ~_MYCLASS_();\r
+\r
+protected:\r
+  /* additional members */\r
+};\r
+\r
+/* Implementation file */\r
+NS_IMPL_ISUPPORTS1(_MYCLASS_, IDNSSDService)\r
+\r
+_MYCLASS_::_MYCLASS_()\r
+{\r
+  /* member initializers and constructor code */\r
+}\r
+\r
+_MYCLASS_::~_MYCLASS_()\r
+{\r
+  /* destructor code */\r
+}\r
+\r
+/* IDNSSDService browse (in long interfaceIndex, in AString regtype, in AString domain, in IDNSSDBrowseListener listener); */\r
+NS_IMETHODIMP _MYCLASS_::Browse(PRInt32 interfaceIndex, const nsAString & regtype, const nsAString & domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM)\r
+{\r
+    return NS_ERROR_NOT_IMPLEMENTED;\r
+}\r
+\r
+/* IDNSSDService resolve (in long interfaceIndex, in AString name, in AString regtype, in AString domain, in IDNSSDResolveListener listener); */\r
+NS_IMETHODIMP _MYCLASS_::Resolve(PRInt32 interfaceIndex, const nsAString & name, const nsAString & regtype, const nsAString & domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM)\r
+{\r
+    return NS_ERROR_NOT_IMPLEMENTED;\r
+}\r
+\r
+/* void stop (); */\r
+NS_IMETHODIMP _MYCLASS_::Stop()\r
+{\r
+    return NS_ERROR_NOT_IMPLEMENTED;\r
+}\r
+\r
+/* End of implementation class template. */\r
+#endif\r
+\r
+\r
+#endif /* __gen_IDNSSDService_h__ */\r
diff --git a/Clients/FirefoxExtension/IDNSSDService.idl b/Clients/FirefoxExtension/IDNSSDService.idl
new file mode 100755 (executable)
index 0000000..d0f62c8
--- /dev/null
@@ -0,0 +1,50 @@
+/* -*- Mode: C; tab-width: 4 -*-\r
+ *\r
+ * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#include "nsISupports.idl"\r
+\r
+interface IDNSSDService;\r
+\r
+\r
+[scriptable, function, uuid(27346495-A1ED-458A-A5BC-587DF9A26B4F)]\r
+interface IDNSSDBrowseListener : nsISupports\r
+{\r
+       void\r
+       onBrowse( in IDNSSDService service, in boolean add, in long interfaceIndex, in long error, in AString serviceName, in AString regtype, in AString domain );\r
+};\r
+\r
+\r
+[scriptable, function, uuid(6620E18F-47F3-47C6-941F-126A5FD4FCF7)]\r
+interface IDNSSDResolveListener : nsISupports\r
+{\r
+       void\r
+       onResolve( in IDNSSDService service, in long interfaceIndex, in long error, in AString fullname, in AString host, in short port, in AString path );\r
+};\r
+\r
+\r
+[scriptable, uuid(3A3539FF-F8D8-40B4-8D02-5EA73C51FA12)]\r
+interface IDNSSDService : nsISupports\r
+{\r
+       IDNSSDService\r
+       browse( in long interfaceIndex, in AString regtype, in AString domain, in IDNSSDBrowseListener listener );\r
+\r
+       IDNSSDService\r
+       resolve( in long interfaceIndex, in AString name, in AString regtype, in AString domain, in IDNSSDResolveListener listener );\r
+\r
+       void\r
+       stop();\r
+};\r
diff --git a/Clients/FirefoxExtension/extension/chrome.manifest b/Clients/FirefoxExtension/extension/chrome.manifest
new file mode 100755 (executable)
index 0000000..f1daf86
--- /dev/null
@@ -0,0 +1,6 @@
+content        bonjour4firefox content/
+locale bonjour4firefox en-US   locale/en-US/
+skin   bonjour4firefox classic/1.0     skin/ 
+skin   bonjour4firefox classic/1.0 skin-darwin/ os=darwin
+overlay        chrome://browser/content/browser.xul    chrome://bonjour4firefox/content/browserOverlay.xul
+style  chrome://global/content/customizeToolbar.xul    chrome://bonjour4firefox/skin/overlay.css
diff --git a/Clients/FirefoxExtension/extension/components/IDNSSDService.xpt b/Clients/FirefoxExtension/extension/components/IDNSSDService.xpt
new file mode 100755 (executable)
index 0000000..bfda3e5
Binary files /dev/null and b/Clients/FirefoxExtension/extension/components/IDNSSDService.xpt differ
diff --git a/Clients/FirefoxExtension/extension/content/bonjour4firefox.css b/Clients/FirefoxExtension/extension/content/bonjour4firefox.css
new file mode 100755 (executable)
index 0000000..2e7eb2c
--- /dev/null
@@ -0,0 +1,16 @@
+tree.sidebar-placesTree treechildren::-moz-tree-row(selected)
+{
+       background-color: #6f81a9;
+       background-image: url("chrome://browser/skin/places/selected-gradient.png");
+       background-repeat: repeat-x;
+       background-position: bottom left;
+       border-top: 1px solid #979797;
+}
+
+
+tree.sidebar-placesTree treechildren::-moz-tree-separator
+{
+       border-top: 1px solid #505d6d;
+       margin: 0 10px;
+}
+
diff --git a/Clients/FirefoxExtension/extension/content/bonjour4firefox.png b/Clients/FirefoxExtension/extension/content/bonjour4firefox.png
new file mode 100755 (executable)
index 0000000..baf8b21
Binary files /dev/null and b/Clients/FirefoxExtension/extension/content/bonjour4firefox.png differ
diff --git a/Clients/FirefoxExtension/extension/content/bonjour4firefox.xul b/Clients/FirefoxExtension/extension/content/bonjour4firefox.xul
new file mode 100755 (executable)
index 0000000..7fd0392
--- /dev/null
@@ -0,0 +1,222 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
+<?xml-stylesheet href="browseList.css"?>
+<!DOCTYPE page SYSTEM "chrome://bonjour4firefox/locale/bonjour4firefox.dtd">
+       <page
+               orient="vertical"
+        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        style="background-color: transparent !important; -moz-appearance: none !important;"
+               onload="BonjourBrowser.init()"
+               onunload="BonjourBrowser.cleanup()">
+               
+
+       <menupopup id="targetmenu">
+        <menuitem label="&bonjour4firefoxSidebarOpenDefault.label;" value="current"/>
+        <menuitem label="&bonjour4firefoxSidebarOpenTab.label;" value="tab"/>
+        <menuitem label="&bonjour4firefoxSidebarOpenWindow.label;" value="window"/>
+       </menupopup>
+
+       <tree id="treeBrowseList" flex="1" class="sidebar-placesTree" hidecolumnpicker="true">
+               <treecols hide="true">
+                       <treecol id="title" flex="1" primary="true" hideheader="true"/>
+        </treecols>
+
+        <treechildren class="sidebar-placesTreechildren" context="targetmenu" flex="1" id="treeChildrenBrowseList">
+                       <treeitem>
+                               <treerow>
+                                       <treecell src="chrome://bonjour4firefox/content/bonjour4firefox.png" label="About Bonjour"/>
+                               </treerow>
+                       </treeitem>
+               </treechildren>
+       </tree>
+
+       <script><![CDATA[
+
+               var BonjourBrowser =
+               {
+                       Service: null,
+                       Browse: null,
+                       BrowseListener: null,
+                       Resolve: null,
+                       ResolveListener: null,
+
+                       init: function()
+                       {
+                               document.getElementById("treeChildrenBrowseList").addEventListener( "click", this.listListener, false );
+
+                               try
+                               {
+                               netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+                                       const cid = "@apple.com/DNSSDService;1";
+                               Service = Components.classes[cid].createInstance();
+                                       Service = Service.QueryInterface(Components.interfaces.IDNSSDService);
+                               }
+                               catch (err)
+                               {
+                               alert(err);
+                               return;
+                       }
+
+                               BrowseListener = this.browseListener;
+                               ResolveListener = this.resolveListener;
+
+                               try
+                               {
+                                       Browse = Service.browse(0, "_http._tcp", "", BrowseListener );
+                               }
+                               catch ( err )
+                               {
+                                       alert( err );
+                                       return;
+                               }
+                       },
+
+                       cleanup: function()
+                       {
+                               if ( Browse != null )
+                               {
+                                       Browse.stop();
+                                       Browse = null;
+                               }
+                       },
+
+
+                       browseListener: function( service, add, interfaceIndex, error, serviceName, regtype, domain )
+                       {
+                               if ( error == 0 )
+                               {
+                                       // First see if we can look this guy up
+
+                                       var treeView = document.getElementById( 'treeChildrenBrowseList' );
+                                       var treeItem = null;
+
+                                       for ( i = 1; i < treeView.childNodes.length; i++ )
+                                       {
+                                               var ti = treeView.childNodes[ i ];
+                                               var tr = ti.childNodes[ 0 ];
+                                               var tc = tr.childNodes[ 0 ];
+
+                                               if ( tc.getAttribute( 'label' ) == serviceName )
+                                               {
+                                                       treeItem = ti;
+                                                       break;
+                                               }
+                                       }
+       
+                                       if ( add )
+                                       {
+                                               // If we've already seen this guy, then bump up his reference count
+
+                                               if ( treeItem )
+                                               {
+                                                       var refcnt = treeItem.getUserData( 'refcnt' );
+                                                       refcnt++;
+                                               }
+                                               else
+                                               {
+                                                       var newTreeItem = document.createElement('treeitem');
+                                                       var newTreeRow = document.createElement('treerow');
+                                                       newTreeRow.setAttribute( 'properties', 'bonjourRow' );
+                                                       var newTreeCell = document.createElement('treecell');
+                                       newTreeCell.setAttribute( 'label', serviceName );
+                                                       newTreeCell.setAttribute( 'src', 'chrome://bonjour4firefox/content/bonjour4firefox.png' );
+                               
+                                                       newTreeItem.appendChild( newTreeRow );
+                                                       newTreeRow.appendChild( newTreeCell );
+                                                       newTreeItem.setUserData( 'interfaceIndex', interfaceIndex, null );
+                                       newTreeItem.setUserData( 'serviceName', serviceName, null );
+                                                       newTreeItem.setUserData( 'regtype', regtype, null );
+                                                       newTreeItem.setUserData( 'domain', domain, null );
+                                                       newTreeItem.setUserData( 'refcnt', 1, null );
+
+                                                       // Insert in alphabetical order
+
+                                                       var insertBefore = null;
+
+                                                       for ( i = 1; i < treeView.childNodes.length; i++ )
+                                                       {
+                                                               var ti = treeView.childNodes[ i ];
+                                                               var tr = ti.childNodes[ 0 ];
+                                                               var tc = tr.childNodes[ 0 ];
+               
+                                                               if ( serviceName.toLowerCase() < tc.getAttribute( 'label' ).toLowerCase() )
+                                                               {
+                                                                       insertBefore = ti;
+                                                                       break;
+                                                               }
+                                               }
+       
+                                                       if ( insertBefore != null )
+                                                       {
+                                                               treeView.insertBefore( newTreeItem, insertBefore );
+                                                       }
+                                                       else
+                                                       {
+                                                               treeView.appendChild( newTreeItem );
+                                                       }
+                                               }
+                                       }
+                                       else if ( treeItem )
+                                       {
+                                               var refcnt = treeItem.getUserData( 'refcnt' );
+                                               
+                                               if ( --refcnt == 0 )
+                                               {
+                                                       treeView.removeChild( treeItem );
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       alert( 'There was an error browsing for websites: ' + error );
+                               }
+                       },
+
+                       listListener: function( event )
+                       {
+                               var treeBrowseList = document.getElementById( 'treeBrowseList' );
+
+                               if ( treeBrowseList.currentIndex == 0 )
+                               {
+                                       window._content.location="http://www.apple.com/bonjour";
+                               }
+                               else
+                               {
+                                       var item = treeBrowseList.view.getItemAtIndex(treeBrowseList.currentIndex);
+
+                                       var interfaceIndex = item.getUserData("interfaceIndex");
+                                       var serviceName = item.getUserData("serviceName");
+                                       var regtype = item.getUserData("regtype");
+                                       var domain = item.getUserData("domain");
+
+                                       try
+                                       {
+                                               Resolve = Service.resolve( interfaceIndex, serviceName, regtype, domain, ResolveListener );
+                                       }
+                                       catch ( err )
+                                       {
+                                               alert( err );
+                                               return;
+                                       }
+                               }
+                       },
+
+                       resolveListener: function( service, interfaceIndex, error, fullname, host, port, path )
+                       {
+                               if ( error == 0 )
+                               {
+                                       window._content.location='http://' + host + ':' + port + path;
+                               }
+                               else
+                               {
+                                       alert( 'There was an error resolving ' + fullname );
+                               }
+
+                               Resolve.stop();
+                       },
+               };
+
+       ]]></script>
+</page>
diff --git a/Clients/FirefoxExtension/extension/content/browserOverlay.xul b/Clients/FirefoxExtension/extension/content/browserOverlay.xul
new file mode 100755 (executable)
index 0000000..3b4d668
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet href="chrome://bonjour4firefox/skin/overlay.css" type="text/css"?>
+<!DOCTYPE overlay SYSTEM "chrome://bonjour4firefox/locale/bonjour4firefox.dtd">
+<overlay id="bonjour4firefox-overlay"
+         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+       <script src="overlay.js"/>
+       <stringbundleset id="stringbundleset">
+       <stringbundle id="bonjour4firefox-strings" src="chrome://bonjour4firefox/locale/bonjour4firefox.properties"/>
+       </stringbundleset>
+
+       <menupopup id="viewSidebarMenu">
+               <menuitem observes="viewBonjour4FirefoxSidebar"/>
+       </menupopup>
+
+       <toolbarpalette id="BrowserToolbarPalette">
+               <toolbarbutton id="bonjour4firefox-toolbar-button"
+               label="&bonjour4firefoxToolbar.label;"
+               tooltiptext="&bonjour4firefoxToolbar.tooltip;"
+               oncommand="toggleSidebar('viewBonjour4FirefoxSidebar');"
+               class="toolbarbutton-1 chromeclass-toolbar-additional"/>
+       </toolbarpalette>
+
+       <broadcasterset id="mainBroadcasterSet">
+               <broadcaster id="viewBonjour4FirefoxSidebar"
+                       autoCheck="false"
+                       label="Bonjour"
+                       type="checkbox" group="sidebar"
+                       sidebarurl="chrome://bonjour4firefox/content/bonjour4firefox.xul"
+                       sidebartitle="&bonjour4firefox.label;"
+                       oncommand="toggleSidebar('viewBonjour4FirefoxSidebar');"/>
+       </broadcasterset>
+</overlay>
diff --git a/Clients/FirefoxExtension/extension/content/listImage.png b/Clients/FirefoxExtension/extension/content/listImage.png
new file mode 100755 (executable)
index 0000000..278efe3
Binary files /dev/null and b/Clients/FirefoxExtension/extension/content/listImage.png differ
diff --git a/Clients/FirefoxExtension/extension/content/overlay.js b/Clients/FirefoxExtension/extension/content/overlay.js
new file mode 100755 (executable)
index 0000000..f989caa
--- /dev/null
@@ -0,0 +1,21 @@
+var bonjour4firefox = 
+{
+       onLoad: function()
+       {
+       // initialization code
+       this.initialized = true;
+       this.strings = document.getElementById("bonjour4firefox-strings");
+       },
+       onMenuItemCommand: function(e)
+       {
+       var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
+               promptService.alert(window, this.strings.getString("helloMessageTitle"), this.strings.getString("helloMessage"));
+       },
+       onToolbarButtonCommand: function(e)
+       {
+       // just reuse the function above.  you can change this, obviously!
+       bonjour4firefox.onMenuItemCommand(e);
+       }
+};
+
+window.addEventListener("load", function(e) { bonjour4firefox.onLoad(e); }, false);
diff --git a/Clients/FirefoxExtension/extension/defaults/preferences/bonjour4firefox.js b/Clients/FirefoxExtension/extension/defaults/preferences/bonjour4firefox.js
new file mode 100755 (executable)
index 0000000..2965608
--- /dev/null
@@ -0,0 +1,2 @@
+// See http://kb.mozillazine.org/Localize_extension_descriptions
+pref("extensions.bonjour4firefox@apple.com.description", "chrome://bonjour4firefox/locale/bonjour4firefox.properties");
diff --git a/Clients/FirefoxExtension/extension/install.rdf b/Clients/FirefoxExtension/extension/install.rdf
new file mode 100755 (executable)
index 0000000..f977a0c
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>bonjour4firefox@apple.com</em:id>
+    <em:name>Bonjour Extension for Firefox</em:name>
+    <em:version>1.0</em:version>
+    <em:creator>Apple Inc.</em:creator>
+    <em:description>Bonjour Browsing Extension for Firefox</em:description>
+    <em:iconURL>chrome://bonjour4firefox/content/bonjour4firefox.png</em:iconURL>
+    <em:targetApplication>
+      <Description>
+        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- firefox -->
+        <em:minVersion>3.5</em:minVersion>
+        <em:maxVersion>3.6.*</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+  </Description>
+</RDF>
diff --git a/Clients/FirefoxExtension/extension/locale/en-US/bonjour4firefox.dtd b/Clients/FirefoxExtension/extension/locale/en-US/bonjour4firefox.dtd
new file mode 100755 (executable)
index 0000000..2e133f9
--- /dev/null
@@ -0,0 +1,6 @@
+<!ENTITY bonjour4firefox.label "Bonjour">
+<!ENTITY bonjour4firefoxToolbar.label "Bonjour">
+<!ENTITY bonjour4firefoxToolbar.tooltip "Display Bonjour enabled websites">
+<!ENTITY bonjour4firefoxSidebarOpenDefault.label "Open in current window">
+<!ENTITY bonjour4firefoxSidebarOpenTab.label "Open in new tab">
+<!ENTITY bonjour4firefoxSidebarOpenWindow.label "Open in new window">
diff --git a/Clients/FirefoxExtension/extension/locale/en-US/bonjour4firefox.properties b/Clients/FirefoxExtension/extension/locale/en-US/bonjour4firefox.properties
new file mode 100755 (executable)
index 0000000..afed1ab
--- /dev/null
@@ -0,0 +1,4 @@
+helloMessage=Hello World!
+helloMessageTitle=Hello
+prefMessage=Int Pref Value: %d
+extensions.bonjour4firefox.description=Bonjour Browsing Extension for Firefox
diff --git a/Clients/FirefoxExtension/extension/readme.txt b/Clients/FirefoxExtension/extension/readme.txt
new file mode 100755 (executable)
index 0000000..71f1edc
--- /dev/null
@@ -0,0 +1,21 @@
+This extension was generated by the Extension Wizard at
+http://ted.mielczarek.org/code/mozilla/extensionwiz/ .
+This extension is compatible only with Firefox 1.5 and
+above.  Most of the files in this package are based on
+the 'helloworld' extension from the Mozillazine Knowledge Base.
+
+You can build an XPI for installation by running the
+build.sh script located in this folder.  For development
+you should do the following:
+  1. Unzip the entire contents of this package to somewhere,
+              e.g, c:\dev or /home/user/dev
+  2. Put the full path to the folder (e.g. c:\dev\bonjour4firefox on
+     Windows, /home/user/dev/bonjour4firefox on Linux) in a file named
+     bonjour4firefox@apple.com and copy that file to
+     [your profile folder]\extensions\
+  3. Restart Firefox.
+
+For more information, see the Mozillazine Knowledge Base:
+http://kb.mozillazine.org/Getting_started_with_extension_development
+
+-Ted Mielczarek <ted.mielczarek@gmail.com>
diff --git a/Clients/FirefoxExtension/extension/skin-darwin/overlay.css b/Clients/FirefoxExtension/extension/skin-darwin/overlay.css
new file mode 100644 (file)
index 0000000..e78635b
--- /dev/null
@@ -0,0 +1,17 @@
+#bonjour4firefox-hello
+{
+  color: red ! important;
+}
+#bonjour4firefox-toolbar-button
+{
+  list-style-image: url("chrome://bonjour4firefox/skin/toolbar-button.png");
+  -moz-image-region: rect(0px 36px 23px 0px);
+}
+#bonjour4firefox-toolbar-button[disabled="true"]
+{
+  -moz-image-region: rect(23px 36px 46px 0px);
+}
+#bonjour4firefox-toolbar-button:hover:active
+{
+  -moz-image-region: rect(46px 36px 69px 0px);
+}
diff --git a/Clients/FirefoxExtension/extension/skin-darwin/toolbar-button.png b/Clients/FirefoxExtension/extension/skin-darwin/toolbar-button.png
new file mode 100644 (file)
index 0000000..2bd6c9d
Binary files /dev/null and b/Clients/FirefoxExtension/extension/skin-darwin/toolbar-button.png differ
diff --git a/Clients/FirefoxExtension/extension/skin/overlay.css b/Clients/FirefoxExtension/extension/skin/overlay.css
new file mode 100755 (executable)
index 0000000..b192b52
--- /dev/null
@@ -0,0 +1,21 @@
+#bonjour4firefox-hello
+{
+  color: black ! important;
+}
+#bonjour4firefox-toolbar-button
+{
+  list-style-image: url("chrome://bonjour4firefox/skin/toolbar-button.png");
+  -moz-image-region: rect(0px 24px 24px 0px);
+}
+#bonjour4firefox-toolbar-button:hover
+{
+  -moz-image-region: rect(24px 24px 48px  0px);
+}
+[iconsize="small"] #bonjour4firefox-toolbar-button
+{
+  -moz-image-region: rect( 0px 40px 16px 24px);
+}
+[iconsize="small"] #bonjour4firefox-toolbar-button:hover
+{
+  -moz-image-region: rect(24px 40px 40px 24px);
+}
diff --git a/Clients/FirefoxExtension/extension/skin/toolbar-button.png b/Clients/FirefoxExtension/extension/skin/toolbar-button.png
new file mode 100755 (executable)
index 0000000..d99a0c9
Binary files /dev/null and b/Clients/FirefoxExtension/extension/skin/toolbar-button.png differ
diff --git a/Clients/FirefoxExtension/readme.txt b/Clients/FirefoxExtension/readme.txt
new file mode 100644 (file)
index 0000000..f898f33
--- /dev/null
@@ -0,0 +1,16 @@
+Building the Bonjour Firefox Extension on Windows
+
+There is a Visual Studio 2005 project file that will build the extension correctly as long as the Visual Studio environment is setup correctly.  This code was built against the 1.9 version of the XULRunner SDK.  The Visual Studio environment should be modified to add the include and lib paths of the XULRunner SDK.  Specifically, the following include paths should be added to VC++ include directories:
+
+…\xulrunner-sdk\include\xpcom
+…\xulrunner-sdk\include\nspr
+…\xulrunner-sdk\include\string
+…\xulrunner-sdk\include\pref
+…\xulrunner-sdk\sdk\include
+
+The following path should be added to VC++ lib directories:
+
+…\xulrunner-sdk\lib
+
+After the code has been built, it can be installed like any other Firefox extension.  Please consult Firefox extension documentation for more information on how to package and install Firefox extensions.
+
diff --git a/Clients/FirefoxExtension/resource.h b/Clients/FirefoxExtension/resource.h
new file mode 100644 (file)
index 0000000..a723410
--- /dev/null
@@ -0,0 +1,27 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by FirefoxExtension.rc
+//
+#define IDS_PROJNAME                    100
+#define IDR_WMDMLOGGER                  101
+#define IDS_LOG_SEV_INFO                201
+#define IDS_LOG_SEV_WARN                202
+#define IDS_LOG_SEV_ERROR               203
+#define IDS_LOG_DATETIME                204
+#define IDS_LOG_SRCNAME                 205
+#define IDS_DEF_LOGFILE                 301
+#define IDS_DEF_MAXSIZE                 302
+#define IDS_DEF_SHRINKTOSIZE            303
+#define IDS_DEF_LOGENABLED              304
+#define IDS_MUTEX_TIMEOUT               401
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        201
+#define _APS_NEXT_COMMAND_VALUE         32768
+#define _APS_NEXT_CONTROL_VALUE         201
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
index 121ff61acf035cd180388f13b7920743e4ba13e1..2b1839a03fc83cc791366cdd5931951af49b1752 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: DNSSDUnitTest.java,v $
-Revision 1.6  2006/08/14 23:24:07  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.5  2006/06/20 23:01:58  rpantos
-<rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
-
-Revision 1.4  2004/08/04 01:07:43  rpantos
-Update unit test for <rdar://problems/3731579&3731582>.
-
-Revision 1.3  2004/05/26 01:41:58  cheshire
-Pass proper flags to DNSSD.enumerateDomains
-
-Revision 1.2  2004/04/30 21:53:34  rpantos
-Change line endings for CVS.
-
-Revision 1.1  2004/04/30 16:29:35  rpantos
-First checked in.
-
-       DNSSDUnitTest is a simple program that exercises parts of the DNSSD API.
+ *
+ * DNSSDUnitTest is a simple program that exercises parts of the DNSSD API.
  */
 
 import com.apple.dnssd.*;
index 9703ced3b71e50600a0d9d5588c8ed64cf20b43c..ce0b5f0c6f0e6e36e53a0eca057016b05c161c78 100755 (executable)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# $Log: Makefile,v $
-# Revision 1.12  2008/09/05 17:37:08  cheshire
-# Need to include ClientCommon.c when building dns-sd
-#
-# Revision 1.11  2007/05/29 19:57:33  cheshire
-# Use "-Wall" for stricter compiler warnings
-#
-# Revision 1.10  2006/09/21 00:56:37  cheshire
-# <rdar://problem/4245577> Need 64-bit version of dns-sd command-line tool
-# Add in missing "build/" in targets line for builds other than OS X
-#
-# Revision 1.9  2006/09/18 18:55:39  cheshire
-# <rdar://problem/4245577> Need 64-bit version of dns-sd command-line tool
-#
-# Revision 1.8  2006/08/14 23:23:55  cheshire
-# Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-#
-# Revision 1.7  2006/01/06 01:06:17  cheshire
-# <rdar://problem/3978979> Compile library and client programs in one pass
-#
-# Revision 1.6  2004/09/24 21:15:26  cheshire
-# <rdar://problem/3724985> Library "libmdns" misnamed; should be "libdns_sd"
-#
-# Revision 1.5  2004/09/02 17:32:45  cheshire
-# Look for headers in ../mDNSShared before we go to /usr/include
-#
-# Revision 1.4  2004/05/21 17:25:56  cheshire
-# Fixes to make sample client work on Linux
-#
-# Revision 1.3  2004/03/12 08:05:32  cheshire
-# Add a "make clean" target
-#
-# Revision 1.2  2004/02/11 20:59:26  cheshire
-# Fix Makefile so it creates the "build" directory if necessary
-#
-# Revision 1.1  2004/02/06 03:19:09  cheshire
-# Check in code to make command-line "dns-sd" testing tool
-#
-#
 # Notes:
 # $@ means "The file name of the target of the rule"
 # $< means "The name of the first prerequisite"
index 8d4b881ff65f4cc1c93cd19b0b26d54d6f625252..a4e6e43d11631dcbf92fad29751843cd6ae38674 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: FirstPage.cpp,v $
-Revision 1.6  2006/08/14 23:24:09  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.5  2005/07/07 17:53:20  shersche
-Fix problems associated with the CUPS printer workaround fix.
-
-Revision 1.4  2005/03/16 01:41:29  shersche
-<rdar://problem/3989644> Remove info icon from first page
-
-Revision 1.3  2005/01/25 08:58:08  shersche
-<rdar://problem/3911084> Load icons at run-time from resource DLLs
-Bug #: 3911084
-
-Revision 1.2  2004/07/13 20:15:04  shersche
-<rdar://problem/3726363> Load large font name from resource
-Bug #: 3726363
-
-Revision 1.1  2004/06/18 04:36:57  rpantos
-First checked in
-
-
-*/
+ */
 
 #include "stdafx.h"
 #include "PrinterSetupWizardApp.h"
index c7c96f421478336d162bff9cc817018138c7c31b..78fa77b11d7477c61853ba517bc4b2b388f8f5e2 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: FirstPage.h,v $
-Revision 1.3  2006/08/14 23:24:09  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2005/07/07 17:53:20  shersche
-Fix problems associated with the CUPS printer workaround fix.
-
-Revision 1.1  2004/06/18 04:36:57  rpantos
-First checked in
-
-
-*/
+ */
 
 #pragma once
 #include "afxwin.h"
index 66e514572b1060e08be662d062dcb890030f908d..3817246ed5fddc9cca3bde8a0cc114a1ff20ea2f 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: FourthPage.cpp,v $
-Revision 1.8  2006/08/14 23:24:09  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.7  2005/07/07 17:53:20  shersche
-Fix problems associated with the CUPS printer workaround fix.
-
-Revision 1.6  2005/02/08 21:45:06  shersche
-<rdar://problem/3947490> Default to Generic PostScript or PCL if unable to match driver
-
-Revision 1.5  2005/01/06 08:17:08  shersche
-Display the selected protocol ("Raw", "LPR", "IPP") rather than the port name
-
-Revision 1.4  2004/07/13 20:15:04  shersche
-<rdar://problem/3726363> Load large font name from resource
-Bug #: 3726363
-
-Revision 1.3  2004/07/12 06:59:03  shersche
-<rdar://problem/3723695> Use resource strings for Yes/No
-Bug #: 3723695
-
-Revision 1.2  2004/06/26 23:27:12  shersche
-support for installing multiple printers of the same name
-
-Revision 1.1  2004/06/18 04:36:57  rpantos
-First checked in
-
-
-*/
+ */
 
 #include "stdafx.h"
 #include "PrinterSetupWizardApp.h"
 #include "PrinterSetupWizardSheet.h"
 #include "FourthPage.h"
 
+#if !defined( PBS_MARQUEE )
+#      define PBS_MARQUEE  0x08
+#endif
+
+#if !defined( PBM_SETMARQUEE )
+#      define PBM_SETMARQUEE WM_USER + 10
+#endif
+
+
 
 // CFourthPage dialog
 
@@ -96,7 +74,23 @@ END_MESSAGE_MAP()
 OSStatus 
 CFourthPage::OnInitPage()
 {
-       return kNoErr;
+       CWnd * window; 
+       OSStatus err = kNoErr;
+
+       window = GetDlgItem( IDC_INSTALLING );
+       require_action( window, exit, err = kUnknownErr );
+       window->ShowWindow( SW_HIDE );
+
+       window = GetDlgItem( IDC_PROGRESS );
+       require_action( window, exit, err = kUnknownErr );
+       SetWindowLong( *window, GWL_STYLE, GetWindowLong( *window, GWL_STYLE ) | PBS_MARQUEE );
+       SetWindowLongPtr( *window, GWL_STYLE, GetWindowLongPtr( *window, GWL_STYLE ) | PBS_MARQUEE );
+       window->SendMessage( ( UINT ) PBM_SETMARQUEE, ( WPARAM ) FALSE,( LPARAM ) 35 );
+       window->ShowWindow( SW_HIDE );
+
+exit:
+
+       return err;
 }
 
 
@@ -166,3 +160,53 @@ exit:
 
        return CPropertyPage::OnKillActive();
 }
+
+
+BOOL
+CFourthPage::StartActivityIndicator()
+{
+       CWnd * window; 
+       BOOL ok = TRUE;
+
+       window = GetDlgItem( IDC_COMPLETE1 );
+       require_action( window, exit, ok = FALSE );
+       window->ShowWindow( SW_HIDE );
+
+       window = GetDlgItem( IDC_COMPLETE2 );
+       require_action( window, exit, ok = FALSE );
+       window->ShowWindow( SW_HIDE );
+
+       window = GetDlgItem( IDC_INSTALLING );
+       require_action( window, exit, ok = FALSE );
+       window->ShowWindow( SW_SHOW );
+
+       window = GetDlgItem( IDC_PROGRESS );
+       require_action( window, exit, ok = FALSE );
+       window->SendMessage( ( UINT ) PBM_SETMARQUEE, ( WPARAM ) TRUE,( LPARAM ) 50 );
+       window->ShowWindow( SW_SHOW );
+
+exit:
+
+       return ok;
+}
+
+
+BOOL
+CFourthPage::StopActivityIndicator()
+{
+       CWnd * window; 
+       BOOL ok = TRUE;
+
+       window = GetDlgItem( IDC_INSTALLING );
+       require_action( window, exit, ok = FALSE );
+       window->ShowWindow( SW_HIDE );
+
+       window = GetDlgItem( IDC_PROGRESS );
+       require_action( window, exit, ok = FALSE );
+       window->SendMessage( ( UINT ) PBM_SETMARQUEE, ( WPARAM ) FALSE,( LPARAM ) 35 );
+       window->ShowWindow( SW_HIDE );
+
+exit:
+
+       return ok;
+}
index fc7205958e34bb3d079a096bf591dd9ff8d8b022..9150df2aaf9c8eeffddfafe62f1923bce4334dff 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: FourthPage.h,v $
-Revision 1.4  2006/08/14 23:24:09  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2005/07/07 17:53:20  shersche
-Fix problems associated with the CUPS printer workaround fix.
-
-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
-
-
-*/
+ */
 
 #pragma once
 #include "afxwin.h"
@@ -52,6 +35,9 @@ public:
        virtual BOOL OnSetActive();
        virtual BOOL OnKillActive();
 
+       BOOL StartActivityIndicator();
+       BOOL StopActivityIndicator();
+
 protected:
        virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 
index c5ffabf9cec53cda330b6baa85671e604a860a07..3385d31cd742bafd25bfa7a67404afb26c1bd132 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: Logger.cpp,v $
-Revision 1.3  2009/06/11 23:32:12  herscher
-<rdar://problem/4458913> Follow the app data folder naming convention of Safari/iTunes on Windows
-
-Revision 1.2  2009/06/11 23:11:53  herscher
-<rdar://problem/4458913> Log to user's app data folder
-
-Revision 1.1  2009/06/11 22:27:14  herscher
-<rdar://problem/4458913> Add comprehensive logging during printer installation process.
-
  */
 
 #include "stdafx.h"
index c74c315f952478e245bcbd0fa45ae65e8a81e154..a715132f8e976e5e62d4c9f94f04c560fc7605e7 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: Logger.h,v $
-Revision 1.1  2009/06/11 22:27:15  herscher
-<rdar://problem/4458913> Add comprehensive logging during printer installation process.
-
-
  */
 
 #ifndef _Logger_h
index d57bed5d771a82b5bec3b9cb86a4419abd641543..88b1379564eefdcef24ea9a1fe57de222ef16325 100644 (file)
@@ -78,7 +78,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 \r
 // Icon with lowest ID value placed first to ensure application icon\r
 // remains consistent on all systems.\r
-IDR_MAINFRAME           ICON                    "res\\Print.ico"\r
+IDR_MAINFRAME           ICON                    "res\\NetworkPrinter.ico"\r
 \r
 /////////////////////////////////////////////////////////////////////////////\r
 //\r
index da149696b81ac0f7108af34ec583387d8153c47b..f570ab675a509c7771c3ba654653b4c6d8f159eb 100644 (file)
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                  &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                  &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
                <Configuration\r
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                  &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                  &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
        </Configurations>\r
                                RelativePath="res\NetworkPrinter.ico"\r
                                >\r
                        </File>\r
-                       <File\r
-                               RelativePath="res\Print.ico"\r
-                               >\r
-                       </File>\r
                        <File\r
                                RelativePath="res\PrinterSetupWizard.manifest"\r
                                >\r
index c811e7efc98df68af1e10d766c81f79e77edaa6e..d2a896d0d41673818bc47a8963fc8912736c8f97 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: PrinterSetupWizardApp.cpp,v $
-Revision 1.10  2009/05/26 05:38:18  herscher
-<rdar://problem/6123821> use HeapSetInformation(HeapEnableTerminationOnCorruption) in dns-sd.exe and PrinterWizard.exe
-
-Revision 1.9  2006/08/14 23:24:09  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.8  2005/04/13 17:43:39  shersche
-<rdar://problem/4081448> Change "PrinterWizard.dll" to "PrinterWizardResources.dll"
-
-Revision 1.7  2005/02/15 07:50:09  shersche
-<rdar://problem/4007151> Update name
-
-Revision 1.6  2005/02/10 22:35:10  cheshire
-<rdar://problem/3727944> Update name
-
-Revision 1.5  2005/01/25 18:30:02  shersche
-Fix call to PathForResource() by passing in NULL as first parameter.
-
-Revision 1.4  2005/01/25 08:54:41  shersche
-<rdar://problem/3911084> Load resource DLLs at startup.
-Bug #: 3911084
-
-Revision 1.3  2004/07/13 21:24:23  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.2  2004/06/24 20:12:08  shersche
-Clean up source code
-Submitted by: herscher
-
-Revision 1.1  2004/06/18 04:36:57  rpantos
-First checked in
-
-
-*/
+ */
 
 #include "stdafx.h"
 #include "PrinterSetupWizardApp.h"
index 08a182945290ea1698368983a01e930c81fd0ecc..4daba1220e5e65f744f277f57c56450d6484e5e9 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: PrinterSetupWizardApp.h,v $
-Revision 1.3  2006/08/14 23:24:09  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2005/01/25 08:52:55  shersche
-<rdar://problem/3911084> Add APIs to return localizable and non-localizable resource DLL handles
-Bug #: 3911084
-
-Revision 1.1  2004/06/18 04:36:57  rpantos
-First checked in
-
-
-*/
+ */
 
 #pragma once
 
index a07023e447b42e0866c28e0c48cf271012341eb5..198890fdefbf2f5e766e1810065d582cf9c51fe6 100755 (executable)
@@ -171,8 +171,10 @@ BEGIN
     LTEXT           "",IDC_PRINTER_MODEL,172,104,113,8\r
     LTEXT           "",IDC_PRINTER_PROTOCOL,172,117,113,8\r
     LTEXT           "",IDC_PRINTER_DEFAULT,172,130,113,8\r
-    LTEXT           "To complete the installation, click Finish.",IDC_STATIC,116,180,171,8\r
-    LTEXT           "To change these settings, click Back.",IDC_STATIC,116,190,171,8\r
+    LTEXT           "To complete the installation, click Finish.",IDC_COMPLETE1,116,180,171,8\r
+    LTEXT           "To change these settings, click Back.",IDC_COMPLETE2,116,190,171,8\r
+       LTEXT                   "Please wait a few moments while the Bonjour Printer Wizard installs the printer.",IDC_INSTALLING,116,170,171,31\r
+       CONTROL                 "",IDC_PROGRESS,"msctls_progress32",WS_BORDER,116,190,165,8\r
 END\r
 \r
 IDD_DIALOG1 DIALOGEX 0, 0, 265, 130\r
index 062778630d2ded13875e56747b4d9f43859ac646..3b3c68f96bbdac784e7385025ffe1be356173194 100755 (executable)
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources\en.lproj&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources\en.lproj&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                                         &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources\en.lproj&quot;&#x0D;&#x0A;:END"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)\PrinterWizard.Resources\en.lproj&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)\PrinterWizard.Resources\en.lproj&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                                         &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)\PrinterWizard.Resources\en.lproj&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
                <Configuration\r
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources\en.lproj&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources\en.lproj&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                                         &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources\en.lproj&quot;&#x0D;&#x0A;:END"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)\PrinterWizard.Resources\en.lproj&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)\PrinterWizard.Resources\en.lproj&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                                         &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)\PrinterWizard.Resources\en.lproj&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
        </Configurations>\r
index 9e9e30f3d53ce1fa4cacacb1e1b1b7ea27cd7679..067aabfeb6fa131bba2cfc5b75ba88be23b135e1 100755 (executable)
@@ -78,7 +78,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 \r
 // Icon with lowest ID value placed first to ensure application icon\r
 // remains consistent on all systems.\r
-IDR_MAINFRAME           ICON                    "res\\Print.ico"\r
+IDR_MAINFRAME           ICON                    "res\\NetworkPrinter.ico"\r
 IDI_INFO                ICON                    "res\\Info.ico"\r
 IDI_PRINTER             ICON                    "res\\NetworkPrinter.ico"\r
 \r
index 31c30c61677481eeb093cc566912dc23faa28493..07d05f0784f0c85d4b2805493a94e2e63a986e16 100755 (executable)
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                           &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources&quot;&#x0D;&#x0A;:END"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)\PrinterWizard.Resources&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)\PrinterWizard.Resources&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                           &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)\PrinterWizard.Resources&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
                <Configuration\r
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                           &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)\PrinterWizard.Resources&quot;&#x0D;&#x0A;:END"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)\PrinterWizard.Resources&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)\PrinterWizard.Resources&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                           &quot;$(DSTROOT)\Program Files\Bonjour Print Services\$(PlatformName)\PrinterWizard.Resources&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
        </Configurations>\r
                                RelativePath=".\res\NetworkPrinter.ico"\r
                                >\r
                        </File>\r
-                       <File\r
-                               RelativePath=".\res\Print.ico"\r
-                               >\r
-                       </File>\r
                        <File\r
                                RelativePath=".\res\Printer.bmp"\r
                                >\r
                        </File>\r
-                       <File\r
-                               RelativePath=".\res\Printer.ico"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\res\Printer2.ico"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="res\PrinterSetupWizard.ico"\r
-                               >\r
-                       </File>\r
                        <File\r
                                RelativePath="PrinterSetupWizardRes.rc"\r
                                >\r
index 565c6ea6789d14f03e0a1053ae5cb2c6b3deed22..07e9ca061763889a06c68794934d87a048233318 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: PrinterSetupWizardSheet.cpp,v $
-Revision 1.40  2009/06/18 18:05:50  herscher
-<rdar://problem/4694554> Eliminate the first screen of Printer Wizard and maybe combine others ("I'm Feeling Lucky")
-
-Revision 1.39  2009/06/11 22:27:16  herscher
-<rdar://problem/4458913> Add comprehensive logging during printer installation process.
-
-Revision 1.38  2009/05/27 04:49:02  herscher
-<rdar://problem/4417884> Consider setting DoubleSpool for LPR queues to improve compatibility
-
-Revision 1.37  2009/03/30 19:17:37  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/6141389> Printer Wizard crashes on launch when Bonjour Service isn't running
-<rdar://problem/5258789> Buffer overflow in PrinterWizard when printer dns hostname is too long
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.36  2008/10/23 22:33:23  cheshire
-Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
-
-Revision 1.35  2006/08/14 23:24:09  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.34  2005/10/05 17:32:51  herscher
-<rdar://problem/4141221> Use a case insensitive compare operation to check whether a printer with the same name has already been installed.
-
-Revision 1.33  2005/07/11 20:17:15  shersche
-<rdar://problem/4124524> UI fixes associated with CUPS printer workaround fix.
-
-Revision 1.32  2005/07/07 17:53:20  shersche
-Fix problems associated with the CUPS printer workaround fix.
-
-Revision 1.31  2005/06/30 18:02:54  shersche
-<rdar://problem/4124524> Workaround for Mac OS X Printer Sharing bug
-
-Revision 1.30  2005/04/13 17:46:22  shersche
-<rdar://problem/4082122> Generic PCL not selected when printers advertise multiple text records
-
-Revision 1.29  2005/02/14 20:48:37  shersche
-<rdar://problem/4003710> Default pdl key to "application/postscript"
-
-Revision 1.28  2005/02/14 20:37:53  shersche
-<rdar://problem/4003944> Populate comment field with the model name that users see in the wizard UI.
-
-Revision 1.27  2005/02/09 05:04:03  shersche
-<rdar://problem/3946587> Use TXTRecordGetValuePtr() API in ParseTextRecord
-
-Revision 1.26  2005/02/08 21:45:06  shersche
-<rdar://problem/3947490> Default to Generic PostScript or PCL if unable to match driver
-
-Revision 1.25  2005/02/08 18:54:17  shersche
-<rdar://problem/3987680> Default queue name is "lp" when rp key is not specified.
-
-Revision 1.24  2005/02/01 02:15:55  shersche
-<rdar://problem/3946587> Use TXTRecord parsing APIs in ParseTextRecord
-
-Revision 1.23  2005/01/31 23:54:30  shersche
-<rdar://problem/3947508> Start browsing when printer wizard starts. Move browsing logic from CSecondPage object to CPrinterSetupWizardSheet object.
-
-Revision 1.22  2005/01/25 18:49:43  shersche
-Get icon resources from resource DLL
-
-Revision 1.21  2005/01/10 01:09:32  shersche
-Use the "note" key to populate pLocation field when setting up printer
-
-Revision 1.20  2005/01/03 19:05:01  shersche
-Store pointer to instance of wizard sheet so that print driver install thread sends a window message to the correct window
-
-Revision 1.19  2004/12/31 07:23:53  shersche
-Don't modify the button setting in SetSelectedPrinter()
-
-Revision 1.18  2004/12/29 18:53:38  shersche
-<rdar://problem/3725106>
-<rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
-Bug #: 3725106, 3737413
-
-Revision 1.17  2004/10/12 18:02:53  shersche
-<rdar://problem/3764873> Escape '/', '@', '"' characters in printui command.
-Bug #: 3764873
-
-Revision 1.16  2004/09/13 21:27:22  shersche
-<rdar://problem/3796483> Pass the moreComing flag to OnAddPrinter and OnRemovePrinter callbacks
-Bug #: 3796483
-
-Revision 1.15  2004/09/11 05:59:06  shersche
-<rdar://problem/3785766> Fix code that generates unique printer names based on currently installed printers
-Bug #: 3785766
-
-Revision 1.14  2004/09/02 01:57:58  cheshire
-<rdar://problem/3783611> Fix incorrect testing of MoreComing flag
-
-Revision 1.13  2004/07/26 21:06:29  shersche
-<rdar://problem/3739200> Removing trailing '.' in hostname
-Bug #: 3739200
-
-Revision 1.12  2004/07/13 21:24:23  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.11  2004/06/28 00:51:47  shersche
-Move call to EnumPrinters out of browse callback into standalone function
-
-Revision 1.10  2004/06/27 23:06:47  shersche
-code cleanup, make sure EnumPrinters returns non-zero value
-
-Revision 1.9  2004/06/27 15:49:31  shersche
-clean up some cruft in the printer browsing code
-
-Revision 1.8  2004/06/27 08:04:51  shersche
-copy selected printer to prevent printer being deleted out from under
-
-Revision 1.7  2004/06/26 23:27:12  shersche
-support for installing multiple printers of the same name
-
-Revision 1.6  2004/06/26 21:22:39  shersche
-handle spaces in file names
-
-Revision 1.5  2004/06/26 03:19:57  shersche
-clean up warning messages
-
-Submitted by: herscher
-
-Revision 1.4  2004/06/25 02:26:52  shersche
-Normalize key fields in text record entries
-Submitted by: herscher
-
-Revision 1.3  2004/06/24 20:12:07  shersche
-Clean up source code
-Submitted by: herscher
-
-Revision 1.2  2004/06/23 17:58:21  shersche
-<rdar://problem/3701837> eliminated memory leaks on exit
-<rdar://problem/3701926> installation of a printer that is already installed results in a no-op
-Bug #: 3701837, 3701926
-Submitted by: herscher
-
-Revision 1.1  2004/06/18 04:36:57  rpantos
-First checked in
-
-
-*/
+ */
 
 #include "stdafx.h"
 #include "PrinterSetupWizardApp.h"
@@ -166,6 +25,7 @@ First checked in
 #include <winspool.h>
 #include <tcpxcv.h>
 #include <string>
+#include <shlwapi.h>
 
 // unreachable code
 #pragma warning(disable:4702)
@@ -176,10 +36,59 @@ First checked in
 #      include <process.h>
 #endif
 
+
+#if defined( UNICODE ) || defined( _UNICODE )
+#      define GetEnv   _wgetenv
+#else
+#      define GetEnv   getenv
+#endif
+
+static TCHAR*
+g_printerDriverFiles[] =               // Printer driver files
+{
+       TEXT( "ps5ui.dll" ),
+       TEXT( "pscript.hlp" ),
+       TEXT( "pscript.ntf" ),
+       TEXT( "pscript5.dll" ),
+       TEXT( "cups6.ini" ),
+       TEXT( "cupsui6.dll" ),
+       TEXT( "cupsps6.dll" )
+};
+
+
 // Private Messages
 
 #define WM_SOCKET_EVENT                ( WM_USER + 0x100 )
 #define WM_PROCESS_EVENT       ( WM_USER + 0x101 )
+\r
+
+static BOOL\r
+Is64BitWindows()\r
+{\r
+#if defined(_WIN64)\r
+       return TRUE;  // 64-bit programs run only on Win64\r
+#else\r
+       typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)( HANDLE, PBOOL );\r
+       LPFN_ISWOW64PROCESS fnIsWow64Process;\r
+       BOOL bIsWow64 = FALSE;\r
+\r
+    fnIsWow64Process = ( LPFN_ISWOW64PROCESS ) GetProcAddress( GetModuleHandle( TEXT( "kernel32" ) ), "IsWow64Process" );\r
+  \r
+    if ( fnIsWow64Process != NULL )\r
+    {\r
+               BOOL ok;\r
+\r
+        ok = fnIsWow64Process( GetCurrentProcess(), &bIsWow64 );\r
+\r
+               if ( !ok )\r
+               {\r
+                       bIsWow64 = FALSE;\r
+               }\r
+       }\r
+\r
+       return bIsWow64;\r
+#endif\r
+}\r
 
 
 // CPrinterSetupWizardSheet
@@ -311,80 +220,96 @@ OSStatus
 CPrinterSetupWizardSheet::InstallPrinter(Printer * printer)
 {
        Logger          log;
-       Service *       service;
+       CUPSLibrary     cupsLib;
+       Service *       service         = NULL;
        BOOL            ok;
        OSStatus        err = 0;
 
        service = printer->services.front();
        check( service );
 
-       //
-       // if the driver isn't installed, then install it
-       //
-
-       if ( !printer->driverInstalled )
+       if ( printer->isCUPSPrinter && cupsLib.IsInstalled() )
+       {
+               err = InstallPrinterCUPS( printer, service, cupsLib );
+               require_noerr( err, exit );
+       }
+       else
        {
-               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_with_log( log, "_beginthreadex_compat()", err, exit );
-                       
                //
-               // go modal
+               // if the driver isn't installed, then install it
                //
-               while (!m_driverThreadFinished)
+
+               if ( !printer->driverInstalled )
                {
-                       MSG msg;
-       
-                       GetMessage( &msg, m_hWnd, 0, 0 );
-                       TranslateMessage(&msg);
-                       DispatchMessage(&msg);
-               }
+                       DWORD           dwResult;
+                       HANDLE          hThread;
+                       unsigned        threadID;
 
-               //
-               // Wait until child process exits.
-               //
-               dwResult = WaitForSingleObject( hThread, INFINITE );
-               err = translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr );
-               require_noerr_with_log( log, "WaitForSingleObject()", err, exit );
+                       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_with_log( log, "_beginthreadex_compat()", err, exit );
+                               
+                       //
+                       // go modal
+                       //
+                       while (!m_driverThreadFinished)
+                       {
+                               MSG msg;
+               
+                               GetMessage( &msg, m_hWnd, 0, 0 );
+                               TranslateMessage(&msg);
+                               DispatchMessage(&msg);
+                       }
 
-               //
-               // check the return value of thread
-               //
-               require_noerr_with_log( log, "thread exit code", m_driverThreadExitCode, exit );
+                       //
+                       // Wait until child process exits.
+                       //
+                       dwResult = WaitForSingleObject( hThread, INFINITE );
+                       err = translate_errno( dwResult == WAIT_OBJECT_0, errno_compat(), err = kUnknownErr );
+                       require_noerr_with_log( log, "WaitForSingleObject()", err, exit );
 
-               //
-               // now we know that the driver was successfully installed
-               //
-               printer->driverInstalled = true;
-       }
+                       //
+                       // check the return value of thread
+                       //
+                       require_noerr_with_log( log, "thread exit code", m_driverThreadExitCode, exit );
 
-       if ( service->type == kPDLServiceType )
-       {
-               err = InstallPrinterPDLAndLPR( printer, service, PROTOCOL_RAWTCP_TYPE, log );
-               require_noerr_with_log( log, "InstallPrinterPDLAndLPR()", err, exit );
-       }
-       else if ( service->type == kLPRServiceType )
-       {
-               err = InstallPrinterPDLAndLPR( printer, service, PROTOCOL_LPR_TYPE, log );
-               require_noerr_with_log( log, "InstallPrinterPDLAndLPR()", err, exit );
-       }
-       else if ( service->type == kIPPServiceType )
-       {
-               err = InstallPrinterIPP( printer, service, log );
-               require_noerr_with_log( log, "InstallPrinterIPP()", err, exit );
-       }
-       else
-       {
-               require_action_with_log( log, ( service->type == kPDLServiceType ) || ( service->type == kLPRServiceType ) || ( service->type == kIPPServiceType ), exit, err = kUnknownErr );
+                       //
+                       // now we know that the driver was successfully installed
+                       //
+                       printer->driverInstalled = true;
+               }
+
+               if ( service->type == kPDLServiceType )
+               {
+                       err = InstallPrinterPort( printer, service, PROTOCOL_RAWTCP_TYPE, log );
+                       require_noerr_with_log( log, "InstallPrinterPort()", err, exit );
+                       err = InstallPrinterPDLAndLPR( printer, service, log );
+                       require_noerr_with_log( log, "InstallPrinterPDLAndLPR()", err, exit );
+               }
+               else if ( service->type == kLPRServiceType )
+               {
+                       err = InstallPrinterPort( printer, service, PROTOCOL_LPR_TYPE, log );
+                       require_noerr_with_log( log, "InstallPrinterPort()", err, exit );
+                       err = InstallPrinterPDLAndLPR( printer, service, log );
+                       require_noerr_with_log( log, "InstallPrinterPDLAndLPR()", err, exit );
+               }
+               else if ( service->type == kIPPServiceType )
+               {
+                       // There's no need to install a printer port for IPP printers, because
+                       // the call to AddPrinter() will do that for us.
+
+                       err = InstallPrinterIPP( printer, service, log );
+                       require_noerr_with_log( log, "InstallPrinterIPP()", err, exit );
+               }
+               else
+               {
+                       require_action_with_log( log, ( service->type == kPDLServiceType ) || ( service->type == kLPRServiceType ) || ( service->type == kIPPServiceType ), exit, err = kUnknownErr );
+               }
        }
 
        printer->installed = true;
@@ -406,23 +331,23 @@ exit:
 
 
 OSStatus
-CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * service, DWORD protocol, Logger & log )
+CPrinterSetupWizardSheet::InstallPrinterPort( Printer * printer, Service * service, DWORD protocol, Logger & log )
 {
        PRINTER_DEFAULTS        printerDefaults =       { NULL,  NULL, SERVER_ACCESS_ADMINISTER };
+       PORT_DATA_1                     portData;
        DWORD                           dwStatus;
        DWORD                           cbInputData             =       100;
        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);
+       ZeroMemory(&portData, sizeof(PORT_DATA_1));
+
+       require_action_with_log( log, wcslen(printer->portName) < sizeof_array(portData.sztPortName), exit, err = kSizeErr );
+       wcscpy_s(portData.sztPortName, printer->portName);
 
        q = service->queues.front();
        check( q );
@@ -444,14 +369,6 @@ CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * s
        }
 
        require_action_with_log( log, pOutputData, exit, err = kNoMemoryErr );
-       
-       //
-       // setup the port
-       //
-       ZeroMemory(&portData, sizeof(PORT_DATA_1));
-
-       require_action_with_log( log, wcslen(printer->portName) < sizeof_array(portData.sztPortName), exit, err = kSizeErr );
-       wcscpy_s(portData.sztPortName, printer->portName);
        
        portData.dwPortNumber   =       service->portNumber;
        portData.dwVersion              =       1;
@@ -460,7 +377,7 @@ CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * s
        portData.dwProtocol     = protocol;
        portData.cbSize         = sizeof PORT_DATA_1;
        portData.dwReserved     = 0L;
-       
+
        require_action_with_log( log, wcslen(q->name) < sizeof_array(portData.sztQueue), exit, err = kSizeErr );
        wcscpy_s(portData.sztQueue, q->name);
 
@@ -471,6 +388,36 @@ CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * s
        err = translate_errno( ok, errno_compat(), kUnknownErr );
        require_noerr_with_log( log, "XcvData()", err, exit );
 
+exit:
+
+       if (hXcv != NULL)
+       {
+               ClosePrinter(hXcv);
+       }
+
+       if (pOutputData != NULL)
+       {
+               delete [] pOutputData;
+       }
+
+       return err;
+}
+
+
+OSStatus
+CPrinterSetupWizardSheet::InstallPrinterPDLAndLPR(Printer * printer, Service * service, Logger & log )
+{
+       PRINTER_INFO_2          pInfo;
+       HANDLE                          hPrinter = NULL;
+       Queue                   *       q;
+       OSStatus                        err;
+
+       check(printer != NULL);
+       check(printer->installed == false);
+
+       q = service->queues.front();
+       check( q );
+
        //
        // add the printer
        //
@@ -507,16 +454,6 @@ exit:
                ClosePrinter(hPrinter);
        }
 
-       if (hXcv != NULL)
-       {
-               ClosePrinter(hXcv);
-       }
-
-       if (pOutputData != NULL)
-       {
-               delete [] pOutputData;
-       }
-
        return err;
 }
 
@@ -561,6 +498,217 @@ exit:
 }
 
 
+OSStatus
+CPrinterSetupWizardSheet::InstallPrinterCUPS(Printer * printer, Service * service, CUPSLibrary & cupsLib )
+{
+       OSStatus err = kNoErr;
+
+       check( printer );
+       check( service );
+       check( cupsLib.IsInstalled() );
+
+       err = InstallPrinterCUPS( printer, service, cupsLib, TEXT( "Windows NT x86" ) );
+       require_noerr( err, exit );
+
+       if ( Is64BitWindows() )
+       {
+               err = InstallPrinterCUPS( printer, service, cupsLib, TEXT( "Windows x64" ) );
+               require_noerr( err, exit );
+       }
+
+exit:
+
+       return err;
+}
+
+
+OSStatus
+CPrinterSetupWizardSheet::InstallPrinterCUPS(Printer * printer, Service * service, CUPSLibrary & cupsLib, TCHAR * env )
+{
+       
+       Queue           *       q;
+       CString                 ppdfile;                                // PPD file for printer drivers
+       TCHAR                   driverdir[1024];                // Directory for driver files
+       DWORD                   needed;                                 // Bytes needed
+       DRIVER_INFO_3   driverinfo;                             // Driver information
+       PRINTER_INFO_2  printerinfo;                    // Printer information
+       HANDLE                  printerHandle = NULL;   // Handle to printer
+       CString                 filename;                               // Driver filename
+       CString                 dependentFiles;                 // List of dependent files
+       CString                 portName;                               // Port Name
+       int                             bytes;                                  // Bytes copied
+       TCHAR                   datadir[ MAX_PATH ];    // Driver files location
+       CFile                   in;                                             // Input file
+       CFile                   out;                                    // Output file
+       void            *       http;                                   // Connection to server
+       char                    buffer[4096];                   // Copy/error buffer
+       CString                 platform;
+       char                    hostname[ 1024 ];
+       CString                 dest;
+       char                    destANSI[ 1024 ];
+       int                             i;
+       DWORD                   num;
+       OSStatus                err     = 0;
+       BOOL                    ok;
+
+       check( printer );
+       check( service );
+       check( cupsLib.IsInstalled() );
+       check( env );
+
+       // What do we do here for multiple queues?
+       q = service->queues.front();
+       require_action( q != NULL, exit, err = kUnknownErr );
+
+       num = GetModuleFileName( NULL, datadir, MAX_PATH );
+       err = translate_errno( num > 0, GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+       ok = PathRemoveFileSpec( datadir );
+       require_action( ok, exit, err = kUnknownErr );
+
+       ok = GetPrinterDriverDirectory(NULL, env, 1, ( LPBYTE ) driverdir, sizeof( driverdir ), &needed );
+       err = translate_errno( ok, GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
+       platform = env;
+       platform = platform.Right( 3 );
+
+       // Append the supported banner pages to the PPD file...
+       err = StringObjectToUTF8String( service->hostname, hostname, sizeof( hostname ) );
+       require_noerr( err, exit );
+       http = cupsLib.httpConnectEncrypt( hostname, service->portNumber, cupsLib.cupsEncryption() );
+       err = translate_errno( http != NULL, errno, kUnknownErr );
+       require_noerr( err, exit );
+
+       if ( ( service->portNumber == 443 ) || ( cupsLib.cupsEncryption() >= HTTP_ENCRYPT_REQUIRED ) )
+       {
+               // This forces the use the https: URLs below...
+               cupsLib.cupsSetEncryption( HTTP_ENCRYPT_ALWAYS );
+       }
+
+       // Strip the leading "printers/" or "classes/" from the beginning
+       // of the name
+
+       dest = q->name;
+       dest.Replace( TEXT( "printers/" ), TEXT( "" ) );
+       dest.Replace( TEXT( "classes/" ), TEXT( "" ) );
+
+       err = StringObjectToUTF8String( dest, destANSI, sizeof( destANSI ) );
+       require_noerr( err, exit );
+
+       // Get the PPD file...
+       for ( i = 0; i < 10; i++ )
+       {
+               char ppdfileANSI[ 1024 ];
+
+               if ( cupsLib.cupsAdminCreateWindowsPPD( http, destANSI, ppdfileANSI, sizeof( ppdfileANSI ) ) )
+               {
+                       err = UTF8StringToStringObject( ppdfileANSI, ppdfile );
+                       require_noerr( err, exit );
+                       break;
+               }
+       }
+
+       err = translate_errno( i < 10, errno, kUnknownErr );
+       require_noerr( err, exit );
+
+       // Copy the PPD file to the Windows driver directory...
+       filename.Format( TEXT( "%s/%s.ppd" ), driverdir, dest );
+
+       ok = in.Open( ppdfile, CFile::modeRead | CFile::typeBinary );
+       translate_errno( ok, GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
+       ok = out.Open( filename, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary );
+       translate_errno( ok, GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
+       while ( ( bytes = in.Read( buffer, sizeof(buffer) ) ) > 0 )
+       {
+               out.Write(buffer, bytes );
+       }
+
+       in.Close();
+       out.Close();
+
+       // Cleanup temp file...
+       CFile::Remove( ppdfile );
+
+       // Copy the driver files to the driver directory...
+       for ( i = 0; i < ( sizeof( g_printerDriverFiles ) / sizeof( g_printerDriverFiles[0] ) ); i++ )
+       {
+               filename.Format( TEXT( "%s/drivers/%s/%s" ), datadir, platform, g_printerDriverFiles[i]);
+       
+               ok = in.Open(filename, CFile::modeRead | CFile::typeBinary );
+               err = translate_errno( ok, GetLastError(), kUnknownErr );
+               require_noerr( err, exit );
+
+               filename.Format( TEXT( "%s/%s" ), driverdir, g_printerDriverFiles[i] );
+               ok = out.Open(filename, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary );
+               err = translate_errno( ok, errno, kUnknownErr );
+
+               while ( ( bytes = in.Read(buffer, sizeof( buffer ) ) ) > 0 )
+               {
+                       out.Write( buffer, bytes );
+               }
+
+               in.Close();
+               out.Close();
+       }
+
+       // Do the Windows system calls needed to add the printer driver...
+       filename.Format( TEXT( "%s.ppd" ), dest);
+       dependentFiles.Format( TEXT( "pscript5.dll%c" ) TEXT( "%s.ppd%c" ) TEXT( "ps5ui.dll%c" ) TEXT( "pscript.hlp%c" ) TEXT( "pscript.ntf%c" ) TEXT( "cups6.ini%c" ) TEXT( "cupsps6.dll%c" ) TEXT( "cupsui6.dll%c" ), 0, dest, 0, 0, 0, 0, 0, 0, 0);
+
+       driverinfo.cVersion         = 3;
+       driverinfo.pName            = printer->actualName.GetBuffer();
+       driverinfo.pEnvironment     = env;
+       driverinfo.pDriverPath      = TEXT( "pscript5.dll" );
+       driverinfo.pDataFile        = filename.GetBuffer();
+       driverinfo.pConfigFile      = TEXT( "ps5ui.dll" );
+       driverinfo.pHelpFile        = TEXT( "pscript.hlp" );
+       driverinfo.pDependentFiles  = dependentFiles.GetBuffer();
+       driverinfo.pMonitorName     = NULL;
+       driverinfo.pDefaultDataType = TEXT( "raw" );
+
+       ok = AddPrinterDriverEx(NULL, 3, (LPBYTE) &driverinfo, APD_COPY_ALL_FILES );
+       err = translate_errno( ok, GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
+       // See if the printer has already been added?
+       if ( OpenPrinter( printer->actualName.GetBuffer(), &printerHandle, NULL ) )
+    {
+               // Printer already exists, so we are done now...
+               goto exit;
+    }
+
+    // Add the printer using the HTTP/IPP port...
+       portName.Format( TEXT( "%s://%s:%d/printers/%s" ), cupsLib.cupsEncryption() == HTTP_ENCRYPT_ALWAYS ? TEXT( "https" ) : TEXT( "http" ), service->hostname.GetBuffer(), service->portNumber, dest );
+
+    memset(&printerinfo, 0, sizeof(printerinfo));
+    printerinfo.pPrinterName   = printer->actualName.GetBuffer();
+    printerinfo.pPortName              = portName.GetBuffer();
+    printerinfo.pDriverName            = printer->actualName.GetBuffer();
+    printerinfo.Attributes             = PRINTER_ATTRIBUTE_NETWORK | PRINTER_ATTRIBUTE_LOCAL;
+       printerinfo.pComment            = q->description.GetBuffer();
+       printerinfo.pLocation           = q->location.GetBuffer();
+       printerinfo.pPrintProcessor = TEXT( "winprint" );
+
+    printerHandle = AddPrinter( NULL, 2, (LPBYTE) &printerinfo );
+       err = translate_errno( printerHandle, GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
+exit:
+
+       if ( printerHandle != NULL )
+       {
+               ClosePrinter( printerHandle );
+               printerHandle = NULL;
+       }
+
+       return err;
+}
+
 BEGIN_MESSAGE_MAP(CPrinterSetupWizardSheet, CPropertySheet)
 ON_MESSAGE( WM_SOCKET_EVENT, OnSocketEvent )
 ON_MESSAGE( WM_PROCESS_EVENT, OnProcessEvent )
@@ -596,7 +744,7 @@ BOOL CPrinterSetupWizardSheet::OnCommand(WPARAM wParam, LPARAM lParam)
 BOOL CPrinterSetupWizardSheet::OnInitDialog()
 {
        OSStatus err;
-       
+
        CPropertySheet::OnInitDialog();
 
        err = StartBrowse();
@@ -678,18 +826,34 @@ CPrinterSetupWizardSheet::OnContextMenu(CWnd * pWnd, CPoint pos)
 void
 CPrinterSetupWizardSheet::OnOK()
 {
+       CWnd * window;
+       OSStatus err;
+
        check ( m_selectedPrinter != NULL );
 
        SetWizardButtons( PSWIZB_DISABLEDFINISH );
 
-       if ( InstallPrinter( m_selectedPrinter ) != kNoErr )
+       window = GetDlgItem( IDCANCEL );
+       if ( window )
+       {
+               window->EnableWindow( FALSE );
+       }
+
+       m_pgFourth.StartActivityIndicator();
+       
+       err = InstallPrinter( m_selectedPrinter );
+
+       m_pgFourth.StopActivityIndicator();
+
+       if ( err != kNoErr )
        {
                CString caption;
                CString message;
 
                caption.LoadString(IDS_INSTALL_ERROR_CAPTION);
+               caption.AppendFormat( TEXT( " (%d)" ), err );
                message.LoadString(IDS_INSTALL_ERROR_MESSAGE);
-
                MessageBox(message, caption, MB_OK|MB_ICONEXCLAMATION);
        }
 
@@ -850,7 +1014,7 @@ CPrinterSetupWizardSheet::OnBrowse(
        OSStatus                                                err = kNoErr;
 
        require_noerr( inErrorCode, exit );
-       
+
        self = reinterpret_cast <CPrinterSetupWizardSheet*>( inContext );
        require_quiet( self, exit );
 
@@ -868,12 +1032,25 @@ CPrinterSetupWizardSheet::OnBrowse(
 
        if ( inFlags & kDNSServiceFlagsAdd )
        {
-               if (printer == NULL)
-               {
-                       // If not, then create a new one
+               BOOL newPrinter = FALSE;
 
+               if ( !printer )
+               {
                        printer = self->OnAddPrinter( inInterfaceIndex, inName, inType, inDomain, moreComing );
                        require_action( printer, exit, err = kUnknownErr );
+                       newPrinter = TRUE;
+               }
+               
+               // If we're looking at the browse list on page 2, then we need to call
+               // CPage2::OnAddPrinter() regardless of whether we've seen the printer
+               // or not because the moreComing flag might have changed from a previous
+               // call. If we only call CPage2::OnAddPrinter() when there's a new printer,
+               // we might not correctly update our UI, so if we've seen the printer before,
+               // call OnAddPrinter with a NULL parameter.
+
+               if ( self->GetActivePage() == &self->m_pgSecond )
+               {
+                       self->m_pgSecond.OnAddPrinter( newPrinter ? printer : NULL, moreComing );
                }
 
                if ( !service )
@@ -1126,6 +1303,7 @@ CPrinterSetupWizardSheet::OnAddPrinter(
        DEBUG_UNUSED( inInterfaceIndex );
        DEBUG_UNUSED( inType );
        DEBUG_UNUSED( inDomain );
+       DEBUG_UNUSED( moreComing );
 
        try
        {
@@ -1183,11 +1361,6 @@ CPrinterSetupWizardSheet::OnAddPrinter(
 
        m_printers.push_back( printer );
 
-       if ( GetActivePage() == &m_pgSecond )
-       {
-               m_pgSecond.OnAddPrinter( printer, moreComing );
-       }
-
 exit:
 
        return printer;
@@ -1685,7 +1858,7 @@ CPrinterSetupWizardSheet::ParseTextRecord( Service * service, Queue * q, uint16_
 
        if ( TXTRecordContainsKey( inTXTSize, inTXT, "printer-state" ) || TXTRecordContainsKey( inTXTSize, inTXT, "printer-type" ) )
        {
-               service->printer->isSharedFromOSX = true;
+               service->printer->isCUPSPrinter = true;
        }
 
 exit:
index 5e2306b0534fd5a89f791e8bfa9d4b333a3fe1fc..91ed39d572146e0185f11d10036a470756931533 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: PrinterSetupWizardSheet.h,v $
-Revision 1.14  2009/06/11 22:27:16  herscher
-<rdar://problem/4458913> Add comprehensive logging during printer installation process.
-
-Revision 1.13  2009/03/30 19:18:49  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.12  2006/08/14 23:24:09  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.11  2005/10/05 17:32:51  herscher
-<rdar://problem/4141221> Use a case insensitive compare operation to check whether a printer with the same name has already been installed.
-
-Revision 1.10  2005/07/07 17:53:19  shersche
-Fix problems associated with the CUPS printer workaround fix.
-
-Revision 1.9  2005/04/13 17:46:22  shersche
-<rdar://problem/4082122> Generic PCL not selected when printers advertise multiple text records
-
-Revision 1.8  2005/02/08 18:53:33  shersche
-Remove qtotalDefined parameter from ParseTextRecord()
-
-Revision 1.7  2005/01/31 23:54:29  shersche
-<rdar://problem/3947508> Start browsing when printer wizard starts. Move browsing logic from CSecondPage object to CPrinterSetupWizardSheet object.
-
-Revision 1.6  2005/01/03 19:05:01  shersche
-Store pointer to instance of wizard sheet so that print driver install thread sends a window message to the correct window
-
-Revision 1.5  2004/12/29 18:53:38  shersche
-<rdar://problem/3725106>
-<rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
-Bug #: 3725106, 3737413
-
-Revision 1.4  2004/07/13 21:24:23  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.3  2004/06/28 00:51:47  shersche
-Move call to EnumPrinters out of browse callback into standalone function
-
-Revision 1.2  2004/06/24 20:12:07  shersche
-Clean up source code
-Submitted by: herscher
-
-Revision 1.1  2004/06/18 04:36:57  rpantos
-First checked in
-
-
-*/
+ */
 
 #pragma once
 
 
-#include "firstpage.h"
 #include "secondpage.h"
 #include "thirdpage.h"
 #include "fourthpage.h"
@@ -156,7 +104,6 @@ public:
 
 protected:
        DECLARE_MESSAGE_MAP()
-       CFirstPage              m_pgFirst;
        CSecondPage             m_pgSecond;
        CThirdPage              m_pgThird;
        CFourthPage             m_pgFourth;
@@ -169,6 +116,69 @@ protected:
 
 private:
 
+       // This is from <cups/http.h>
+       typedef enum http_encryption_e          /**** HTTP encryption values ****/
+       {
+               HTTP_ENCRYPT_IF_REQUESTED,              /* Encrypt if requested (TLS upgrade) */
+               HTTP_ENCRYPT_NEVER,                     /* Never encrypt */
+               HTTP_ENCRYPT_REQUIRED,          /* Encryption is required (TLS upgrade) */
+               HTTP_ENCRYPT_ALWAYS                     /* Always encrypt (SSL) */
+       } http_encryption_t;
+
+       typedef void*                           ( *httpConnectEncryptFunc )( const char* host, int port, http_encryption_t encryption );
+       typedef http_encryption_t       ( *cupsEncryptionFunc )( void );
+       typedef void                            ( *cupsSetEncryptionFunc )( http_encryption_t e );
+       typedef char*                           ( *cupsAdminCreateWindowsPPDFunc )( void * http, const char *dest, char *buffer, int bufsize );
+
+       class CUPSLibrary
+       {
+       public:
+
+               CUPSLibrary()
+                       :
+                       httpConnectEncrypt( NULL ),
+                       cupsEncryption( NULL ),
+                       cupsSetEncryption( NULL ),
+                       cupsAdminCreateWindowsPPD( NULL ),
+                       library( NULL )
+               {
+#if defined( LIBCUPS_ENABLED )
+                       if ( ( library = LoadLibrary( TEXT( "libcups2.dll" ) ) ) != NULL )
+                       {
+                               httpConnectEncrypt = ( httpConnectEncryptFunc ) GetProcAddress( library, "httpConnectEncrypt" );
+                               cupsEncryption = ( cupsEncryptionFunc ) GetProcAddress( library, "cupsEncryption" );
+                               cupsSetEncryption = ( cupsSetEncryptionFunc ) GetProcAddress( library, "cupsSetEncryption" );
+                               cupsAdminCreateWindowsPPD = ( cupsAdminCreateWindowsPPDFunc ) GetProcAddress( library, "cupsAdminCreateWindowsPPD" );
+                       }
+#endif
+               }
+
+               ~CUPSLibrary()
+               {
+                       if ( library )
+                       {
+                               FreeLibrary( library );
+                               library = NULL;
+                       }
+               }
+
+               BOOL
+               IsInstalled()
+               {
+                       return ( ( httpConnectEncrypt != NULL ) && ( cupsEncryption != NULL ) && ( cupsSetEncryption != NULL ) && ( cupsAdminCreateWindowsPPD != NULL ) );
+               }
+
+               httpConnectEncryptFunc                  httpConnectEncrypt;
+               cupsEncryptionFunc                              cupsEncryption;
+               cupsSetEncryptionFunc                   cupsSetEncryption;
+               cupsAdminCreateWindowsPPDFunc   cupsAdminCreateWindowsPPD;
+
+       private:
+
+               HMODULE                                                 library;
+       };
+
+
        static void DNSSD_API
        OnBrowse(
                DNSServiceRef                   inRef,
@@ -273,10 +283,19 @@ private:
        InstallPrinter(Printer * printer);
 
        OSStatus
-       InstallPrinterPDLAndLPR(Printer * printer, Service * service, DWORD protocol, Logger & log);
+       InstallPrinterPort( Printer * printer, Service * service, DWORD protocol, Logger & log );
+
+       OSStatus
+       InstallPrinterPDLAndLPR(Printer * printer, Service * service, Logger & log);
 
        OSStatus
        InstallPrinterIPP(Printer * printer, Service * service, Logger & log);
+       
+       OSStatus
+       InstallPrinterCUPS( Printer * printer, Service * service, CUPSLibrary & cupsLib );
+
+       OSStatus
+       InstallPrinterCUPS(Printer * printer, Service * service, CUPSLibrary & cupsLib, TCHAR * env );
 
        static unsigned WINAPI
        InstallDriverThread( LPVOID inParam );
index 4bed3f713f7612de3e761e1b5b10ae01f014670f..35bbefafa351dfbe5002eaf7ca2fd6780ea0f224 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: SecondPage.cpp,v $
-Revision 1.20  2009/06/18 18:05:50  herscher
-<rdar://problem/4694554> Eliminate the first screen of Printer Wizard and maybe combine others ("I'm Feeling Lucky")
-
-Revision 1.19  2006/08/14 23:24:09  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.18  2005/07/20 17:44:54  shersche
-<rdar://problem/4124524> UI fixes for CUPS workaround
-
-Revision 1.17  2005/07/11 20:17:15  shersche
-<rdar://problem/4124524> UI fixes associated with CUPS printer workaround fix.
-
-Revision 1.16  2005/07/07 17:53:20  shersche
-Fix problems associated with the CUPS printer workaround fix.
-
-Revision 1.15  2005/04/13 17:46:22  shersche
-<rdar://problem/4082122> Generic PCL not selected when printers advertise multiple text records
-
-Revision 1.14  2005/03/20 20:08:37  shersche
-<rdar://problem/4055670> Second screen should not select a printer by default
-
-Revision 1.13  2005/02/15 07:50:10  shersche
-<rdar://problem/4007151> Update name
-
-Revision 1.12  2005/02/10 22:35:11  cheshire
-<rdar://problem/3727944> Update name
-
-Revision 1.11  2005/01/31 23:54:30  shersche
-<rdar://problem/3947508> Start browsing when printer wizard starts. Move browsing logic from CSecondPage object to CPrinterSetupWizardSheet object.
-
-Revision 1.10  2005/01/20 19:54:38  shersche
-Fix parse error when text record is NULL
-
-Revision 1.9  2005/01/06 08:13:50  shersche
-Don't use moreComing flag to determine number of text record, disregard queue name if qtotal isn't defined, don't disregard queue name if "rp" is the only key specified
-
-Revision 1.8  2005/01/04 21:09:14  shersche
-Fix problems in parsing text records. Fix problems in remove event handling. Ensure that the same service can't be resolved more than once.
-
-Revision 1.7  2004/12/31 07:25:27  shersche
-Tidy up printer management, and fix memory leaks when hitting 'Cancel'
-
-Revision 1.6  2004/12/30 01:24:02  shersche
-<rdar://problem/3906182> Remove references to description key
-Bug #: 3906182
-
-Revision 1.5  2004/12/30 01:02:47  shersche
-<rdar://problem/3734478> Add Printer information box that displays description and location information when printer name is selected
-Bug #: 3734478
-
-Revision 1.4  2004/12/29 18:53:38  shersche
-<rdar://problem/3725106>
-<rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
-Bug #: 3725106, 3737413
-
-Revision 1.3  2004/09/13 21:26:15  shersche
-<rdar://problem/3796483> Use the moreComing flag to determine whether drawing should take place in OnAddPrinter and OnRemovePrinter callbacks
-Bug #: 3796483
-
-Revision 1.2  2004/06/26 03:19:57  shersche
-clean up warning messages
-
-Submitted by: herscher
-
-Revision 1.1  2004/06/18 04:36:57  rpantos
-First checked in
-
-
-*/
+ */
 
 #include "stdafx.h"
 #include "PrinterSetupWizardApp.h"
@@ -203,6 +131,7 @@ CSecondPage::OnSetActive()
 {
        CPrinterSetupWizardSheet        *       psheet;
        Printer                                         *       printer;
+       CWnd                                            *       pWnd;
        Printers::iterator                              it;
        OSStatus                                                err = kNoErr;
        BOOL                                                    b;
@@ -244,6 +173,13 @@ CSecondPage::OnSetActive()
                ::SetFocus( m_browseList );
        }
 
+       // Hide the back button
+       pWnd = ((CPropertySheet*)GetParent())->GetDlgItem(ID_WIZBACK);\r
+       if ( pWnd != NULL )\r
+       {\r
+               pWnd->ShowWindow(SW_HIDE);\r
+       }
+
 exit:
 
        return b;
@@ -253,13 +189,21 @@ exit:
 BOOL
 CSecondPage::OnKillActive()
 {
-       CPrinterSetupWizardSheet * psheet;
+       CPrinterSetupWizardSheet        * psheet;
+       CWnd                                            * pWnd;
 
        psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
        require_quiet( psheet, exit );   
    
        psheet->SetLastPage(this);
 
+       // Show the back button
+       pWnd = ((CPropertySheet*)GetParent())->GetDlgItem(ID_WIZBACK);\r
+       if ( pWnd != NULL )\r
+       {\r
+               pWnd->ShowWindow(SW_SHOW);\r
+       }
+
 exit:
 
        return CPropertyPage::OnKillActive();
@@ -290,36 +234,39 @@ CSecondPage::OnAddPrinter(
 
        psheet = reinterpret_cast<CPrinterSetupWizardSheet*>(GetParent());
        require_quiet( psheet, exit );
-       
-       selectedPrinter = psheet->GetSelectedPrinter();
 
-       printer->item = m_browseList.InsertItem(printer->displayName);
+       if ( printer )
+       {
+               selectedPrinter = psheet->GetSelectedPrinter();
+
+               printer->item = m_browseList.InsertItem(printer->displayName);
 
-       m_browseList.SetItemData( printer->item, (DWORD_PTR) printer );
+               m_browseList.SetItemData( printer->item, (DWORD_PTR) printer );
 
-       m_browseList.SortChildren(TVI_ROOT);
+               m_browseList.SortChildren(TVI_ROOT);
 
-       //
-       // 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);
-       }
+               //
+               // 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);
+               }
 
-       if ( !selectedPrinter )
-       {
-               psheet->SetSelectedPrinter( printer );
-               m_browseList.SelectItem( printer->item );
-               ::SetFocus( m_browseList );
+               if ( !selectedPrinter )
+               {
+                       psheet->SetSelectedPrinter( printer );
+                       m_browseList.SelectItem( printer->item );
+                       ::SetFocus( m_browseList );
+               }
        }
 
 exit:
@@ -350,25 +297,28 @@ CSecondPage::OnRemovePrinter(
 
        m_browseList.SetRedraw(FALSE);
 
-       //
-       // 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 ( printer )
        {
                //
-               // if we're the only thing in the list, then redisplay
-               // it with the no printers message
+               // check to make sure if we're the only item in the control...i.e.
+               // the list size is 1.
                //
-               InitBrowseList();
+               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 printers message
+                       //
+                       InitBrowseList();
+               }
        }
 
 exit:
index b857334fd08a47c13b8ee984a92ce2a0112317ae..c9c614d26315f4321aab187647eaa48f229908e3 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: SecondPage.h,v $
-Revision 1.9  2006/08/14 23:24:09  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.8  2005/03/20 20:08:37  shersche
-<rdar://problem/4055670> Second screen should not select a printer by default
-
-Revision 1.7  2005/01/31 23:54:30  shersche
-<rdar://problem/3947508> Start browsing when printer wizard starts. Move browsing logic from CSecondPage object to CPrinterSetupWizardSheet object.
-
-Revision 1.6  2005/01/04 21:09:14  shersche
-Fix problems in parsing text records. Fix problems in remove event handling. Ensure that the same service can't be resolved more than once.
-
-Revision 1.5  2004/12/31 07:25:27  shersche
-Tidy up printer management, and fix memory leaks when hitting 'Cancel'
-
-Revision 1.4  2004/12/30 01:02:46  shersche
-<rdar://problem/3734478> Add Printer information box that displays description and location information when printer name is selected
-Bug #: 3734478
-
-Revision 1.3  2004/12/29 18:53:38  shersche
-<rdar://problem/3725106>
-<rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
-Bug #: 3725106, 3737413
-
-Revision 1.2  2004/09/13 21:23:42  shersche
-<rdar://problem/3796483> Add moreComing argument to OnAddPrinter and OnRemovePrinter callbacks
-Bug #: 3796483
-
-Revision 1.1  2004/06/18 04:36:57  rpantos
-First checked in
-
-
-*/
+ */
 
 #pragma once
 
index deca4dfc53536b0539aa915d142f2907980bb101..4bd88e55462549a6d4f8f7f1e99b7a372fde7166 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: ThirdPage.cpp,v $
-Revision 1.42  2009/07/07 22:04:55  herscher
-<rdar://problem/4176343> LOC Impact: Need custom text when selecting the wrong printer driver
-
-Revision 1.41  2009/06/18 18:05:50  herscher
-<rdar://problem/4694554> Eliminate the first screen of Printer Wizard and maybe combine others ("I'm Feeling Lucky")
-
-Revision 1.40  2009/05/29 20:43:36  herscher
-<rdar://problem/6928136> Printer Wizard doesn't work correctly in Windows 7 64 bit
-
-Revision 1.39  2009/05/27 06:25:49  herscher
-<rdar://problem/4176334> Need error dialog when selecting bad INF file
-
-Revision 1.38  2009/05/27 04:59:57  herscher
-<rdar://problem/4517393> COMPATIBILITY WITH HP CLJ4700
-<rdar://problem/6142138> Compatibility with Samsung print driver files
-
-Revision 1.37  2007/06/08 06:30:26  herscher
-<rdar://problem/5257700> Fix uninitialized pointers when detecting generic PCL and PS drivers
-
-Revision 1.36  2007/06/06 20:39:10  cheshire
-<rdar://problem/5254377> Printer Setup Wizard started crashing in Bonjour104A8, after update to Visual Studio 2005
-
-Revision 1.35  2007/06/06 20:08:01  cheshire
-<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
-AutoScroll model list as well as manufacturer list
-
-Revision 1.34  2007/06/06 19:53:48  cheshire
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.33  2007/04/20 22:58:10  herscher
-<rdar://problem/4826126> mDNS: Printer Wizard doesn't offer generic HP printers or generic PS support on Vista RC2
-
-Revision 1.32  2007/04/13 23:42:20  herscher
-<rdar://problem/4580061> mDNS: Printers added using Bonjour should be set as the default printer.
-
-Revision 1.31  2007/04/13 21:38:46  herscher
-<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
-
-Revision 1.30  2007/04/13 20:23:40  herscher
-Fixed mistake in previous checkin that reverted license text for this file
-
-Revision 1.29  2007/04/13 18:10:24  herscher
-<rdar://problem/4496652> mDNS: Don't allow user to choose non-working driver
-
-Revision 1.28  2006/08/14 23:24:09  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.27  2005/10/05 21:41:45  herscher
-<rdar://problem/4190104> Use "application/octet-stream" to determine if CUPS shared queue supports raw
-
-Revision 1.26  2005/07/11 20:17:15  shersche
-<rdar://problem/4124524> UI fixes associated with CUPS printer workaround fix.
-
-Revision 1.25  2005/07/07 17:53:20  shersche
-Fix problems associated with the CUPS printer workaround fix.
-
-Revision 1.24  2005/06/30 18:02:54  shersche
-<rdar://problem/4124524> Workaround for Mac OS X Printer Sharing bug
-
-Revision 1.23  2005/04/18 02:33:47  shersche
-<rdar://problem/4091216> Default printer option cannot be deselected
-
-Revision 1.22  2005/04/13 17:46:22  shersche
-<rdar://problem/4082122> Generic PCL not selected when printers advertise multiple text records
-
-Revision 1.21  2005/03/30 02:09:55  shersche
-Auto-resize the column width to account for differing fonts and font sizes
-
-Revision 1.20  2005/03/05 02:27:45  shersche
-<rdar://problem/4030388> Generic drivers don't do color
-
-Revision 1.19  2005/02/23 02:08:51  shersche
-<rdar://problem/4012275> If we can't match the manufacturer, and select a generic printer, then show all the manufacturers in the manufacturer pane, not just "Generic".
-
-Revision 1.18  2005/02/15 07:02:51  shersche
-<rdar://problem/4003724> Display different UI text when generic printer drivers are selected
-
-Revision 1.17  2005/02/08 21:45:06  shersche
-<rdar://problem/3947490> Default to Generic PostScript or PCL if unable to match driver
-
-Revision 1.16  2005/02/08 18:56:03  shersche
-Fix generated IPP url so that it doesn't add "/printers" string
-
-Revision 1.15  2005/02/01 01:44:07  shersche
-Load ntprint.inf at startup.  This will cause the wizard to take a second or two longer to come up, but will eliminate the pause when auto-selecting the print drivers.
-
-Revision 1.14  2005/01/25 08:55:54  shersche
-<rdar://problem/3911084> Load icons at run-time from resource DLL
-Bug #: 3911084
-
-Revision 1.13  2005/01/06 08:15:45  shersche
-Append queue name to end of LPR port name, correctly build port name when queue name is absent
-
-Revision 1.12  2005/01/05 01:06:12  shersche
-<rdar://problem/3841218> Strip the first substring off the product key if an initial match can't be found with the whole product key.
-Bug #: 3841218
-
-Revision 1.11  2004/12/29 18:53:38  shersche
-<rdar://problem/3725106>
-<rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
-Bug #: 3725106, 3737413
-
-Revision 1.10  2004/10/11 22:55:34  shersche
-<rdar://problem/3827624> Use the IP port number when deriving the printer port name.
-Bug #: 3827624
-
-Revision 1.9  2004/06/27 23:08:00  shersche
-code cleanup, make sure EnumPrintDrivers returns non-zero value, ignore comments in inf files
-
-Revision 1.8  2004/06/27 08:06:45  shersche
-Parse [Strings] section of inf file
-
-Revision 1.7  2004/06/26 04:00:05  shersche
-fix warnings compiling in debug mode
-Submitted by: herscher
-
-Revision 1.6  2004/06/26 03:19:57  shersche
-clean up warning messages
-
-Submitted by: herscher
-
-Revision 1.5  2004/06/25 05:06:02  shersche
-Trim whitespace from key/value pairs when parsing inf files
-Submitted by: herscher
-
-Revision 1.4  2004/06/25 02:44:13  shersche
-Tweaked code to handle Xerox Phaser printer identification
-Submitted by: herscher
-
-Revision 1.3  2004/06/25 02:27:58  shersche
-Do a CListCtrl::FindItem() before calling CListCtrl::SetItemState().
-Submitted by: herscher
-
-Revision 1.2  2004/06/23 18:09:23  shersche
-Normalize tag names when parsing inf files.
-Submitted by: herscher
-
-Revision 1.1  2004/06/18 04:36:58  rpantos
-First checked in
-*/
+ */
 
 #include "stdafx.h"
 #include "PrinterSetupWizardApp.h"
@@ -281,32 +138,27 @@ exit:
        return;
 }
 
-CThirdPage::~CThirdPage()
+
+void
+CThirdPage::FreeManufacturers( Manufacturers & manufacturers )
 {
-       //
-       // clean up all the printer manufacturers
-       //
-       while (m_manufacturers.size())
+       for ( Manufacturers::iterator it = manufacturers.begin(); it != manufacturers.end(); it++ )
        {
-               Manufacturers::iterator iter = m_manufacturers.begin();
-
-               while (iter->second->models.size())
+               for ( Models::iterator it2 = it->second->models.begin(); it2 != it->second->models.end(); it2++ )
                {
-                       Models::iterator it = iter->second->models.begin();
-
-                       Model * model = *it;
-
-                       delete model;
-
-                       iter->second->models.erase(it);
+                       delete *it2;
                }
 
-               delete iter->second;
-
-               m_manufacturers.erase(iter);
+               delete it->second;
        }
 }
 
+
+CThirdPage::~CThirdPage()
+{
+       FreeManufacturers( m_manufacturers );
+}
+
 // ----------------------------------------------------
 // SelectMatch
 //
@@ -380,6 +232,8 @@ CThirdPage::SelectMatch(Manufacturers & manufacturers, Printer * printer, Servic
 void
 CThirdPage::CopyPrinterSettings( Printer * printer, Service * service, Manufacturer * manufacturer, Model * model )
 {
+       DWORD portNameLen;
+
        printer->manufacturer           =       manufacturer->name;
        printer->displayModelName       =       model->displayName;
        printer->modelName                      =       model->name;
@@ -423,6 +277,18 @@ CThirdPage::CopyPrinterSettings( Printer * printer, Service * service, Manufactu
 
                service->protocol = L"IPP";
        }
+
+       // If it's not an IPP printr, truncate the portName so that it's valid
+
+       if ( service->type != kIPPServiceType )
+       {
+               portNameLen = printer->portName.GetLength() + 1;
+               
+               if ( portNameLen > MAX_PORTNAME_LEN )
+               {
+                       printer->portName.Delete( MAX_PORTNAME_LEN - 1, ( portNameLen - MAX_PORTNAME_LEN ) );
+               }
+       }
 }
 
 // --------------------------------------------------------
@@ -1111,7 +977,7 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print
                                useCUPSWorkaround = false;
                        }
 
-                       if ( useCUPSWorkaround && printer->isSharedFromOSX && hasGenericDriver )
+                       if ( useCUPSWorkaround && printer->isCUPSPrinter && hasGenericDriver )
                        {
                                //
                                // <rdar://problem/4496652> mDNS: Don't allow user to choose non-working driver
@@ -1121,6 +987,8 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print
                                LoadGenericPrintDriverDefs( genericManufacturers );
 
                                SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel );
+
+                               FreeManufacturers( genericManufacturers );
                        }
                        else
                        {
@@ -1142,7 +1010,7 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print
        }
        else if ( MatchGeneric( manufacturers, printer, service, &genericManufacturer, &genericModel ) )
        {
-               if ( printer->isSharedFromOSX )
+               if ( printer->isCUPSPrinter )
                {
                        //
                        // <rdar://problem/4496652> mDNS: Don't allow user to choose non-working driver
@@ -1154,6 +1022,8 @@ OSStatus CThirdPage::MatchPrinter(Manufacturers & manufacturers, Printer * print
                        SelectMatch( genericManufacturers, printer, service, genericManufacturer, genericModel );
                        
                        text.LoadString(IDS_PRINTER_MATCH_GOOD);
+
+                       FreeManufacturers( genericManufacturers );
                }
                else
                {
@@ -1690,6 +1560,7 @@ void CThirdPage::OnBnClickedHaveDisk()
 
 exit:
 
+       FreeManufacturers( manufacturers );
        return;
 }
 
index cb929d43274f15798eb753cc228d1e091bc32474..63ad256ef3f69ce1466fb3721767c288b3ae760c 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: ThirdPage.h,v $
-Revision 1.10  2009/05/29 20:43:37  herscher
-<rdar://problem/6928136> Printer Wizard doesn't work correctly in Windows 7 64 bit
-
-Revision 1.9  2007/04/13 23:42:20  herscher
-<rdar://problem/4580061> mDNS: Printers added using Bonjour should be set as the default printer.
-
-Revision 1.8  2007/04/13 21:38:46  herscher
-<rdar://problem/4528853> mDNS: When auto-highlighting items in lists, scroll list so highlighted item is in the middle
-
-Revision 1.7  2007/04/13 20:18:30  herscher
-<rdar://problem/4189721> mDNS: Epson shows up twice in the list
-
-Revision 1.6  2006/08/14 23:24:09  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.5  2005/07/07 17:53:20  shersche
-Fix problems associated with the CUPS printer workaround fix.
-
-Revision 1.4  2005/02/08 21:45:06  shersche
-<rdar://problem/3947490> Default to Generic PostScript or PCL if unable to match driver
-
-Revision 1.3  2005/01/25 08:57:28  shersche
-<rdar://problem/3911084> Add m_printerControl member for dynamic loading of icons from resource DLLs
-Bug #: 3911084
-
-Revision 1.2  2004/12/29 18:53:38  shersche
-<rdar://problem/3725106>
-<rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
-Bug #: 3725106, 3737413
-
-Revision 1.1  2004/06/18 04:36:58  rpantos
-First checked in
-
-
-*/
+ */
 
 #pragma once
 #include "afxcmn.h"
@@ -162,6 +124,8 @@ private:
        //
        void                            AutoScroll(CListCtrl & list, int nIndex);
 
+       void                            FreeManufacturers( Manufacturers & manufacturers );
+
        Manufacturers           m_manufacturers;
 
        CListCtrl                       m_manufacturerListCtrl;
index 41a3251c3c54b2f575ca6b9073ca178c4a58f757..084832c48ecf738123f08f7665b54a51c346d305 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: UtilTypes.h,v $
-Revision 1.18  2009/05/29 20:43:37  herscher
-<rdar://problem/6928136> Printer Wizard doesn't work correctly in Windows 7 64 bit
-
-Revision 1.17  2009/05/27 04:59:57  herscher
-<rdar://problem/4517393> COMPATIBILITY WITH HP CLJ4700
-<rdar://problem/6142138> Compatibility with Samsung print driver files
-
-Revision 1.16  2007/04/20 22:58:10  herscher
-<rdar://problem/4826126> mDNS: Printer Wizard doesn't offer generic HP printers or generic PS support on Vista RC2
-
-Revision 1.15  2006/08/14 23:24:09  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.14  2005/06/30 18:02:54  shersche
-<rdar://problem/4124524> Workaround for Mac OS X Printer Sharing bug
-
-Revision 1.13  2005/04/13 17:46:22  shersche
-<rdar://problem/4082122> Generic PCL not selected when printers advertise multiple text records
-
-Revision 1.12  2005/03/16 03:12:28  shersche
-<rdar://problem/4050504> Generic PCL driver isn't selected correctly on Win2K
-
-Revision 1.11  2005/03/05 02:27:46  shersche
-<rdar://problem/4030388> Generic drivers don't do color
-
-Revision 1.10  2005/02/08 21:45:06  shersche
-<rdar://problem/3947490> Default to Generic PostScript or PCL if unable to match driver
-
-Revision 1.9  2005/02/01 01:16:12  shersche
-Change window owner from CSecondPage to CPrinterSetupWizardSheet
-
-Revision 1.8  2005/01/06 08:18:26  shersche
-Add protocol field to service, add EmptyQueues() function to service
-
-Revision 1.7  2005/01/04 21:07:29  shersche
-add description member to service object.  this member corresponds to the 'ty' key in a printer text record
-
-Revision 1.6  2004/12/30 01:24:02  shersche
-<rdar://problem/3906182> Remove references to description key
-Bug #: 3906182
-
-Revision 1.5  2004/12/29 18:53:38  shersche
-<rdar://problem/3725106>
-<rdar://problem/3737413> Added support for LPR and IPP protocols as well as support for obtaining multiple text records. Reorganized and simplified codebase.
-Bug #: 3725106, 3737413
-
-Revision 1.4  2004/09/13 21:22:44  shersche
-<rdar://problem/3796483> Add moreComing argument to OnAddPrinter and OnRemovePrinter callbacks
-Bug #: 3796483
-
-Revision 1.3  2004/06/26 23:27:12  shersche
-support for installing multiple printers of the same name
-
-Revision 1.2  2004/06/25 02:25:59  shersche
-Remove item field from manufacturer and model structures
-Submitted by: herscher
-
-Revision 1.1  2004/06/18 04:36:58  rpantos
-First checked in
-
-
-*/
+ */
 
 #pragma once
 
@@ -154,7 +89,7 @@ namespace PrinterSetupWizard
                // This let's us know that this printer was discovered via OSX Printer Sharing.
                // We use this knowledge to workaround a problem with OS X Printer sharing.
 
-               bool                    isSharedFromOSX;
+               bool                    isCUPSPrinter;
                
                //
                // state
@@ -243,7 +178,7 @@ namespace PrinterSetupWizard
        inline
        Printer::Printer()
        :
-               isSharedFromOSX( false )
+               isCUPSPrinter( false )
        {
        }
 
index b737f473253cde006f562cdca30f025db8646439..d2926def9fd33facc991557dc86f18de1042289a 100644 (file)
Binary files a/Clients/PrinterSetupWizard/res/NetworkPrinter.ico and b/Clients/PrinterSetupWizard/res/NetworkPrinter.ico differ
index a44c06f84ceb44069073773a62adc33630394274..a76320495c099ba0242e52d7c04c8ce9f0b9724b 100644 (file)
@@ -13,9 +13,6 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
  * See the License for the specific language governing permissions and\r
  * limitations under the License.\r
-\r
-    Change History (most recent first):\r
-\r
  */\r
     \r
 \r
index bb2faaf6369ebd193895bc5c459445541cba72d1..ac510b33336c6e7536daf9624090d145f9999d36 100755 (executable)
 #define IDC_DESCRIPTION_FIELD           1030\r
 #define IDC_LOCATION_FIELD              1032\r
 #define IDC_DESCRIPTION_LABEL           1033\r
+#define IDC_COMPLETE1                                  1034\r
+#define IDC_COMPLETE2                                  1035\r
+#define IDC_INSTALLING                                 1036\r
+#define IDC_PROGRESS                                   1037\r
 \r
 // Next default values for new objects\r
-// \r
+//\r
 #ifdef APSTUDIO_INVOKED\r
 #ifndef APSTUDIO_READONLY_SYMBOLS\r
 #define _APS_NEXT_RESOURCE_VALUE        142\r
index 3aac90d8e72c3ccac93eb82521cc758315783848..c6a2c81c576183d468cabe7c6fd4e45889c48ef3 100755 (executable)
 #define IDC_DESCRIPTION_FIELD           1030\r
 #define IDC_LOCATION_FIELD              1032\r
 #define IDC_DESCRIPTION_LABEL           1033\r
+#define IDC_COMPLETE1                                  1034\r
+#define IDC_COMPLETE2                                  1035\r
+#define IDC_INSTALLING                                 1036\r
+#define IDC_PROGRESS                                   1037\r
 \r
 // Next default values for new objects\r
 // \r
index bb2faaf6369ebd193895bc5c459445541cba72d1..1845b124542db793a55581a8e4d52f7bdbf8e493 100755 (executable)
 #define IDC_DESCRIPTION_FIELD           1030\r
 #define IDC_LOCATION_FIELD              1032\r
 #define IDC_DESCRIPTION_LABEL           1033\r
+#define IDC_COMPLETE1                                  1034\r
+#define IDC_COMPLETE2                                  1035\r
+#define IDC_INSTALLING                                 1036\r
+#define IDC_PROGRESS                                   1037\r
 \r
 // Next default values for new objects\r
 // \r
index 548f66f8e676e1934d83fed1d2daea8222d0982e..e05ec3d102540f453e9220be593ddbbc1995fd52 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: stdafx.cpp,v $
-Revision 1.2  2006/08/14 23:24:09  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.1  2004/06/18 04:36:58  rpantos
-First checked in
-
-
-*/
+ */
 
 #include "stdafx.h"
 
index e1ecec8a160d94a09cac0b09ae3e6c0f5cde4f71..7c08a296a2521dd32e24a273a490296891fb818a 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: stdafx.h,v $
-Revision 1.3  2006/08/14 23:24:09  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2005/10/19 19:50:35  herscher
-Workaround a bug in the latest Microsoft Platform SDK when compiling C++ files that include (directly or indirectly) <WspiApi.h>
-
-Revision 1.1  2004/06/18 04:36:58  rpantos
-First checked in
-
-
-*/
+ */
 
 #pragma once
 
index 4fc7745be319c594084a13d1bf5a7c6051e5b302..1b3661cc89cf2bd7949e97c752711502f97a2278 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
  * See the License for the specific language governing permissions and\r
  * limitations under the License.\r
-\r
-    Change History (most recent first):\r
-    \r
-$Log: AssemblyInfo.cs,v $
-Revision 1.2  2006/08/14 23:24:21  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.1  2004/07/19 07:57:08  shersche
-Initial revision
-\r
-\r
-\r
-*/\r
+ */\r
 \r
 using System.Reflection;\r
 using System.Runtime.CompilerServices;\r
index cdfdad3ca54b2ce339e0e9098981896bc6f5519c..32191cbe819b009215150764eb410acf6967addc 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: SimpleChat.cs,v $
-Revision 1.7  2009/06/04 20:21:19  herscher
-<rdar://problem/3948252> Update code to work with DNSSD COM component
-
-Revision 1.6  2006/08/14 23:24:21  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.5  2004/09/13 19:37:42  shersche
-Change code to reflect namespace and type changes to dnssd.NET library
-
-Revision 1.4  2004/09/11 05:42:56  shersche
-don't reset SelectedIndex in OnRemove
-
-Revision 1.3  2004/09/11 00:38:58  shersche
-DNSService APIs now expect port in host format
-
-Revision 1.2  2004/07/19 22:08:53  shersche
-Fixed rdata->int conversion problem in QueryRecordReply
-
-Revision 1.1  2004/07/19 07:57:08  shersche
-Initial revision
-
-
-
-*/
+ */
 
 using System;
 using System.Drawing;
@@ -65,19 +38,31 @@ namespace SimpleChat.NET
                private System.Windows.Forms.ComboBox   comboBox1;
                private System.Windows.Forms.TextBox    textBox2;
                private System.Windows.Forms.Button     button1;
-               private System.Windows.Forms.Label      label1;\r
-        private Bonjour.DNSSDEventManager       m_eventManager = null;\r
-        private Bonjour.DNSSDService            m_service = null;\r
-        private Bonjour.DNSSDService            m_registrar = null;\r
-        private Bonjour.DNSSDService            m_browser = null;\r
+               private System.Windows.Forms.Label      label1;
+
+        private Bonjour.DNSSDEventManager       m_eventManager = null;
+
+        private Bonjour.DNSSDService            m_service = null;
+
+        private Bonjour.DNSSDService            m_registrar = null;
+
+        private Bonjour.DNSSDService            m_browser = null;
+
         private Bonjour.DNSSDService            m_resolver = null;
-               private String                                          m_name;\r
-        private Socket                          m_socket = null;\r
-        private const int                       BUFFER_SIZE = 1024;\r
-        public byte[]                           m_buffer = new byte[BUFFER_SIZE];\r
-        public bool                             m_complete = false;\r
-        public StringBuilder                    m_sb = new StringBuilder();\r
-        delegate void                           ReadMessageCallback(String data);\r
+               private String                                          m_name;
+
+        private Socket                          m_socket = null;
+
+        private const int                       BUFFER_SIZE = 1024;
+
+        public byte[]                           m_buffer = new byte[BUFFER_SIZE];
+
+        public bool                             m_complete = false;
+
+        public StringBuilder                    m_sb = new StringBuilder();
+
+        delegate void                           ReadMessageCallback(String data);
+
         ReadMessageCallback                     m_readMessageCallback;
                /// <summary>
                /// Required designer variable.
@@ -89,29 +74,52 @@ namespace SimpleChat.NET
                //
                // Called by DNSServices core as a result of Register()
                // call
-               //\r
-\r
-        public void\r
-        ServiceRegistered\r
-                    (\r
-                    DNSSDService service,\r
-                    DNSSDFlags flags,\r
-                    String name,\r
-                    String regType,\r
-                    String domain\r
-                    )\r
-        {\r
-            m_name = name;\r
-\r
-            try\r
-            {\r
-                m_browser = m_service.Browse(0, 0, "_p2pchat._udp", null, m_eventManager);\r
-            }\r
-            catch\r
-            {\r
-                MessageBox.Show("Browse Failed", "Error");\r
-                Application.Exit();\r
-            }\r
+               //
+
+
+
+        public void
+
+        ServiceRegistered
+
+                    (
+
+                    DNSSDService service,
+
+                    DNSSDFlags flags,
+
+                    String name,
+
+                    String regType,
+
+                    String domain
+
+                    )
+
+        {
+
+            m_name = name;
+
+
+
+            try
+
+            {
+
+                m_browser = m_service.Browse(0, 0, "_p2pchat._udp", null, m_eventManager);
+
+            }
+
+            catch
+
+            {
+
+                MessageBox.Show("Browse Failed", "Error");
+
+                Application.Exit();
+
+            }
+
         }
 
                //
@@ -130,52 +138,97 @@ namespace SimpleChat.NET
                     String          regType,
                     String          domain
                                    )
-               {\r
-            if (serviceName != m_name)\r
-            {\r
-                PeerData peer = new PeerData();\r
-\r
-                peer.InterfaceIndex = ifIndex;\r
-                peer.Name = serviceName;\r
-                peer.Type = regType;\r
-                peer.Domain = domain;\r
-                peer.Address = null;\r
-\r
-                comboBox1.Items.Add(peer);\r
-\r
-                if (comboBox1.Items.Count == 1)\r
-                {\r
-                    comboBox1.SelectedIndex = 0;\r
-                }\r
+               {
+
+            if (serviceName != m_name)
+
+            {
+
+                PeerData peer = new PeerData();
+
+
+
+                peer.InterfaceIndex = ifIndex;
+
+                peer.Name = serviceName;
+
+                peer.Type = regType;
+
+                peer.Domain = domain;
+
+                peer.Address = null;
+
+
+
+                comboBox1.Items.Add(peer);
+
+
+
+                if (comboBox1.Items.Count == 1)
+
+                {
+
+                    comboBox1.SelectedIndex = 0;
+
+                }
+
             }
-               }\r
-\r
-        //\r
-        // ServiceLost\r
-        //\r
-        // Called by DNSServices core as a result of a Browse call\r
-        //\r
-\r
-        public void\r
-        ServiceLost\r
-                    (\r
-                    DNSSDService sref,\r
-                    DNSSDFlags flags,\r
-                    uint ifIndex,\r
-                    String serviceName,\r
-                    String regType,\r
-                    String domain\r
-                    )\r
-        {\r
-            PeerData peer = new PeerData();\r
-\r
-            peer.InterfaceIndex = ifIndex;\r
-            peer.Name = serviceName;\r
-            peer.Type = regType;\r
-            peer.Domain = domain;\r
-            peer.Address = null;\r
-\r
-            comboBox1.Items.Remove(peer);\r
+               }
+
+
+
+        //
+
+        // ServiceLost
+
+        //
+
+        // Called by DNSServices core as a result of a Browse call
+
+        //
+
+
+
+        public void
+
+        ServiceLost
+
+                    (
+
+                    DNSSDService sref,
+
+                    DNSSDFlags flags,
+
+                    uint ifIndex,
+
+                    String serviceName,
+
+                    String regType,
+
+                    String domain
+
+                    )
+
+        {
+
+            PeerData peer = new PeerData();
+
+
+
+            peer.InterfaceIndex = ifIndex;
+
+            peer.Name = serviceName;
+
+            peer.Type = regType;
+
+            peer.Domain = domain;
+
+            peer.Address = null;
+
+
+
+            comboBox1.Items.Remove(peer);
+
         }
 
                //
@@ -184,34 +237,61 @@ namespace SimpleChat.NET
                // Called by DNSServices core as a result of DNSService.Resolve()
                // call
                //
-\r
-        public void\r
-        ServiceResolved\r
-                    (\r
-                    DNSSDService sref,\r
-                    DNSSDFlags flags,\r
-                    uint ifIndex,\r
-                    String fullName,\r
-                    String hostName,\r
-                    ushort port,\r
-                    TXTRecord txtRecord\r
+
+
+        public void
+
+        ServiceResolved
+
+                    (
+
+                    DNSSDService sref,
+
+                    DNSSDFlags flags,
+
+                    uint ifIndex,
+
+                    String fullName,
+
+                    String hostName,
+
+                    ushort port,
+
+                    TXTRecord txtRecord
+
                     )
-               {\r
-            m_resolver.Stop();\r
-            m_resolver = null;\r
-\r
-            PeerData peer = (PeerData)comboBox1.SelectedItem;\r
-\r
-            peer.Port = port;\r
-\r
-            try\r
-            {\r
-                m_resolver = m_service.QueryRecord(0, ifIndex, hostName, DNSSDRRType.kDNSSDType_A, DNSSDRRClass.kDNSSDClass_IN, m_eventManager );\r
-            }\r
-            catch\r
-            {\r
-                MessageBox.Show("QueryRecord Failed", "Error");\r
-                Application.Exit();\r
+               {
+
+            m_resolver.Stop();
+
+            m_resolver = null;
+
+
+
+            PeerData peer = (PeerData)comboBox1.SelectedItem;
+
+
+
+            peer.Port = port;
+
+
+
+            try
+
+            {
+
+                m_resolver = m_service.QueryRecord(0, ifIndex, hostName, DNSSDRRType.kDNSSDType_A, DNSSDRRClass.kDNSSDClass_IN, m_eventManager );
+
+            }
+
+            catch
+
+            {
+
+                MessageBox.Show("QueryRecord Failed", "Error");
+
+                Application.Exit();
+
             }
                }
 
@@ -234,51 +314,91 @@ namespace SimpleChat.NET
             Object          rdata,
             uint            ttl
             )
-        {\r
-            m_resolver.Stop();\r
-            m_resolver = null;\r
-\r
-            PeerData peer = (PeerData) comboBox1.SelectedItem;\r
+        {
+
+            m_resolver.Stop();
+
+            m_resolver = null;
+
+
+
+            PeerData peer = (PeerData) comboBox1.SelectedItem;
+
 
                        uint bits = BitConverter.ToUInt32( (Byte[])rdata, 0);
                        System.Net.IPAddress address = new System.Net.IPAddress(bits);
 
             peer.Address = address;
-               }\r
-\r
-        public void\r
-        OperationFailed\r
-                    (\r
-                    DNSSDService service,\r
-                    DNSSDError error\r
-                    )\r
-        {\r
-            MessageBox.Show("Operation returned an error code " + error, "Error");\r
-        }\r
-\r
-        //\r
-        // OnReadMessage\r
-        //\r
-        // Called when there is data to be read on a socket\r
-        //\r
-        // This is called (indirectly) from OnReadSocket()\r
-        //\r
-        private void\r
-        OnReadMessage\r
-                (\r
-                String msg\r
-                )\r
-        {\r
-            int rgb = 0;\r
-\r
-            for (int i = 0; i < msg.Length && msg[i] != ':'; i++)\r
-            {\r
-                rgb = rgb ^ ((int)msg[i] << (i % 3 + 2) * 8);\r
-            }\r
-\r
-            Color color = Color.FromArgb(rgb & 0x007F7FFF);\r
-            richTextBox1.SelectionColor = color;\r
-            richTextBox1.AppendText(msg + Environment.NewLine);\r
+               }
+
+
+
+        public void
+
+        OperationFailed
+
+                    (
+
+                    DNSSDService service,
+
+                    DNSSDError error
+
+                    )
+
+        {
+
+            MessageBox.Show("Operation returned an error code " + error, "Error");
+
+        }
+
+
+
+        //
+
+        // OnReadMessage
+
+        //
+
+        // Called when there is data to be read on a socket
+
+        //
+
+        // This is called (indirectly) from OnReadSocket()
+
+        //
+
+        private void
+
+        OnReadMessage
+
+                (
+
+                String msg
+
+                )
+
+        {
+
+            int rgb = 0;
+
+
+
+            for (int i = 0; i < msg.Length && msg[i] != ':'; i++)
+
+            {
+
+                rgb = rgb ^ ((int)msg[i] << (i % 3 + 2) * 8);
+
+            }
+
+
+
+            Color color = Color.FromArgb(rgb & 0x007F7FFF);
+
+            richTextBox1.SelectionColor = color;
+
+            richTextBox1.AppendText(msg + Environment.NewLine);
+
         }
 
                //
@@ -317,24 +437,42 @@ namespace SimpleChat.NET
                        //
                        // Required for Windows Form Designer support
                        //
-                       InitializeComponent();\r
-\r
-            try\r
-            {\r
-                m_service = new DNSSDService();\r
-            }\r
-            catch\r
-            {\r
-                MessageBox.Show("Bonjour Service is not available", "Error");\r
-                Application.Exit();\r
-            }\r
-\r
-            m_eventManager = new DNSSDEventManager();\r
-            m_eventManager.ServiceRegistered += new _IDNSSDEvents_ServiceRegisteredEventHandler(this.ServiceRegistered);\r
-            m_eventManager.ServiceFound += new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound);\r
-            m_eventManager.ServiceLost += new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost);\r
-            m_eventManager.ServiceResolved += new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved);\r
-            m_eventManager.QueryRecordAnswered += new _IDNSSDEvents_QueryRecordAnsweredEventHandler(this.QueryAnswered);\r
+                       InitializeComponent();
+
+
+
+            try
+
+            {
+
+                m_service = new DNSSDService();
+
+            }
+
+            catch
+
+            {
+
+                MessageBox.Show("Bonjour Service is not available", "Error");
+
+                Application.Exit();
+
+            }
+
+
+
+            m_eventManager = new DNSSDEventManager();
+
+            m_eventManager.ServiceRegistered += new _IDNSSDEvents_ServiceRegisteredEventHandler(this.ServiceRegistered);
+
+            m_eventManager.ServiceFound += new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound);
+
+            m_eventManager.ServiceLost += new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost);
+
+            m_eventManager.ServiceResolved += new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved);
+
+            m_eventManager.QueryRecordAnswered += new _IDNSSDEvents_QueryRecordAnsweredEventHandler(this.QueryAnswered);
+
             m_eventManager.OperationFailed += new _IDNSSDEvents_OperationFailedEventHandler(this.OperationFailed);
 
                        m_readMessageCallback = new ReadMessageCallback(OnReadMessage);
@@ -365,17 +503,28 @@ namespace SimpleChat.NET
                                if (m_browser != null)
                                {
                                        m_browser.Stop();
-                               }\r
-\r
-                if (m_resolver != null)\r
-                {\r
-                    m_resolver.Stop();\r
-                }\r
-\r
-                m_eventManager.ServiceFound -= new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound);\r
-                m_eventManager.ServiceLost -= new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost);\r
-                m_eventManager.ServiceResolved -= new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved);\r
-                m_eventManager.QueryRecordAnswered -= new _IDNSSDEvents_QueryRecordAnsweredEventHandler(this.QueryAnswered);\r
+                               }
+
+
+
+                if (m_resolver != null)
+
+                {
+
+                    m_resolver.Stop();
+
+                }
+
+
+
+                m_eventManager.ServiceFound -= new _IDNSSDEvents_ServiceFoundEventHandler(this.ServiceFound);
+
+                m_eventManager.ServiceLost -= new _IDNSSDEvents_ServiceLostEventHandler(this.ServiceLost);
+
+                m_eventManager.ServiceResolved -= new _IDNSSDEvents_ServiceResolvedEventHandler(this.ServiceResolved);
+
+                m_eventManager.QueryRecordAnswered -= new _IDNSSDEvents_QueryRecordAnsweredEventHandler(this.QueryAnswered);
+
                 m_eventManager.OperationFailed -= new _IDNSSDEvents_OperationFailedEventHandler(this.OperationFailed);
                        }
                        base.Dispose( disposing );
@@ -517,8 +666,10 @@ namespace SimpleChat.NET
 
                        Byte[] bytes = Encoding.UTF8.GetBytes(message);
 
-            IPEndPoint endPoint = new IPEndPoint( peer.Address, peer.Port );\r
-\r
+            IPEndPoint endPoint = new IPEndPoint( peer.Address, peer.Port );
+
+
+
             m_socket.SendTo(bytes, endPoint);
 
                        richTextBox1.SelectionColor = Color.Black;
@@ -558,54 +709,103 @@ namespace SimpleChat.NET
                                Application.Exit();
                        }
                }
-       }\r
-\r
-    //\r
-    // PeerData\r
-    //\r
-    // Holds onto the information associated with a peer on the network\r
-    //\r
-    public class PeerData\r
-    {\r
-        public uint InterfaceIndex;\r
-        public String Name;\r
-        public String Type;\r
-        public String Domain;\r
-        public IPAddress Address;\r
-        public int Port;\r
-\r
-        public override String\r
-        ToString()\r
-        {\r
-            return Name;\r
-        }\r
-\r
-        public override bool\r
-        Equals(object other)\r
-        {\r
-            bool result = false;\r
-\r
-            if (other != null)\r
-            {\r
-                if ((object)this == other)\r
-                {\r
-                    result = true;\r
-                }\r
-                else if (other is PeerData)\r
-                {\r
-                    PeerData otherPeerData = (PeerData)other;\r
-\r
-                    result = (this.Name == otherPeerData.Name);\r
-                }\r
-            }\r
-\r
-            return result;\r
-        }\r
-\r
-        public override int\r
-        GetHashCode()\r
-        {\r
-            return Name.GetHashCode();\r
-        }\r
+       }
+
+
+
+    //
+
+    // PeerData
+
+    //
+
+    // Holds onto the information associated with a peer on the network
+
+    //
+
+    public class PeerData
+
+    {
+
+        public uint InterfaceIndex;
+
+        public String Name;
+
+        public String Type;
+
+        public String Domain;
+
+        public IPAddress Address;
+
+        public int Port;
+
+
+
+        public override String
+
+        ToString()
+
+        {
+
+            return Name;
+
+        }
+
+
+
+        public override bool
+
+        Equals(object other)
+
+        {
+
+            bool result = false;
+
+
+
+            if (other != null)
+
+            {
+
+                if ((object)this == other)
+
+                {
+
+                    result = true;
+
+                }
+
+                else if (other is PeerData)
+
+                {
+
+                    PeerData otherPeerData = (PeerData)other;
+
+
+
+                    result = (this.Name == otherPeerData.Name);
+
+                }
+
+            }
+
+
+
+            return result;
+
+        }
+
+
+
+        public override int
+
+        GetHashCode()
+
+        {
+
+            return Name.GetHashCode();
+
+        }
+
     };
 }
index bcf5ef0e9323dfd80a26732aa6bb56ced5a93dac..04a7d806131e27eb4b155e9c39afb29289a0edd6 100644 (file)
@@ -1,3 +1,18 @@
+'\r
+' Copyright (c) 2010 Apple Inc. All rights reserved.\r
+'\r
+' Licensed under the Apache License, Version 2.0 (the "License");\r
+' you may not use this file except in compliance with the License.\r
+' You may obtain a copy of the License at\r
+' \r
+'     http://www.apache.org/licenses/LICENSE-2.0\r
+' \r
+' Unless required by applicable law or agreed to in writing, software\r
+' distributed under the License is distributed on an "AS IS" BASIS,\r
+' WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+' See the License for the specific language governing permissions and\r
+' limitations under the License.\r
+'\r
 \r
 Imports System.Net\r
 Imports System.Net.Sockets\r
index b9455525d4e931f189da15115b615bb768ec7ce2..c1c5d27f9a5d4ac9e1f35702338a0c8a0abb1bbd 100644 (file)
@@ -152,6 +152,15 @@ cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT ws2_32.lib ..\mDNSWindows\DLL\Rele
                return name;
                }
 
+       static size_t _sa_len(const struct sockaddr *addr)
+               {
+               if (addr->sa_family == AF_INET) return (sizeof(struct sockaddr_in));
+               else if (addr->sa_family == AF_INET6) return (sizeof(struct sockaddr_in6));
+               else return (sizeof(struct sockaddr));
+               }
+
+#   define SA_LEN(addr) (_sa_len(addr))
+
 #else
        #include <unistd.h>                     // For getopt() and optind
        #include <netdb.h>                      // For getaddrinfo()
@@ -161,14 +170,18 @@ cl dns-sd.c -I../mDNSShared -DNOT_HAVE_GETOPT ws2_32.lib ..\mDNSWindows\DLL\Rele
        #include <arpa/inet.h>          // For inet_addr()
        #include <net/if.h>                     // For if_nametoindex()
        static const char kFilePathSep = '/';
+       #define SA_LEN(addr) ((addr)->sa_len)
 #endif
 
 #if (TEST_NEW_CLIENTSTUB && !defined(__APPLE_API_PRIVATE))
 #define __APPLE_API_PRIVATE 1
 #endif
 
+// DNSServiceSetDispatchQueue is not supported on 10.6 & prior
+#if ! TEST_NEW_CLIENTSTUB && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ - (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ % 10) <= 1060)
+#undef _DNS_SD_LIBDISPATCH
+#endif
 #include "dns_sd.h"
-
 #include "ClientCommon.h"
 
 #if TEST_NEW_CLIENTSTUB
@@ -204,12 +217,24 @@ static char myhinfoX[ 9] = "\003Mac\004OS X";
 static char updatetest[3] = "\002AA";
 static char bigNULL[8192];     // 8K is maximum rdata we support
 
+#if _DNS_SD_LIBDISPATCH
+dispatch_queue_t main_queue;
+dispatch_source_t timer_source;
+#endif
+
 // Note: the select() implementation on Windows (Winsock2) fails with any timeout much larger than this
 #define LONG_TIME 100000000
 
 static volatile int stopNow = 0;
 static volatile int timeOut = LONG_TIME;
 
+#if _DNS_SD_LIBDISPATCH
+#define EXIT_IF_LIBDISPATCH_FATAL_ERROR(E) \
+       if (main_queue && (E) == kDNSServiceErr_ServiceNotRunning) { fprintf(stderr, "Error code %d\n", (E)); exit(0); }
+#else
+#define EXIT_IF_LIBDISPATCH_FATAL_ERROR(E)
+#endif
+
 //*************************************************************************************************************
 // Supporting Utility Functions
 
@@ -319,6 +344,7 @@ static void DNSSD_API enum_reply(DNSServiceRef sdref, const DNSServiceFlags flag
        (void)sdref;        // Unused
        (void)ifIndex;      // Unused
        (void)context;      // Unused
+       EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
 
        // 1. Print the header
        if (num_printed++ == 0) printf("Timestamp     Recommended %s domain\n", operation == 'E' ? "Registration" : "Browsing");
@@ -451,6 +477,7 @@ static void DNSSD_API zonedata_browse(DNSServiceRef sdref, const DNSServiceFlags
 
        (void)sdref;        // Unused
        (void)context;      // Unused
+       EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
 
        if (!(flags & kDNSServiceFlagsAdd)) return;
        if (errorCode) { printf("Error code %d\n", errorCode); return; }
@@ -466,6 +493,8 @@ static void DNSSD_API browse_reply(DNSServiceRef sdref, const DNSServiceFlags fl
        char *op = (flags & kDNSServiceFlagsAdd) ? "Add" : "Rmv";
        (void)sdref;        // Unused
        (void)context;      // Unused
+       EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
+
        if (num_printed++ == 0) printf("Timestamp     A/R Flags if %-25s %-25s %s\n", "Domain", "Service Type", "Instance Name");
        printtimestamp();
        if (errorCode) printf("Error code %d\n", errorCode);
@@ -520,11 +549,13 @@ static void DNSSD_API resolve_reply(DNSServiceRef sdref, const DNSServiceFlags f
        (void)sdref;        // Unused
        (void)ifIndex;      // Unused
        (void)context;      // Unused
+       EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
 
-       printtimestamp();
-       if (errorCode) printf("Error code %d\n", errorCode);
+       if (errorCode)
+               printf("Error code %d\n", errorCode);
        else
                {
+               printtimestamp();
                printf("%s can be reached at %s:%u (interface %d)", fullname, hosttarget, PortAsNumber, ifIndex);
                if (flags) printf(" Flags: %X", flags);
                // Don't show degenerate TXT records containing nothing but a single empty string
@@ -579,6 +610,11 @@ static void myTimerCallBack(void)
                        err = DNSServiceAddRecord(client, &record, 0, kDNSServiceType_NULL, sizeof(bigNULL), &bigNULL[0], 0);
                        if (err) printf("Failed: %d\n", err); else printf("Succeeded\n");
                        timeOut = LONG_TIME;
+#if _DNS_SD_LIBDISPATCH
+                       if (timer_source)
+                               dispatch_source_set_timer(timer_source, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)timeOut * NSEC_PER_SEC),
+                                       (uint64_t)timeOut * NSEC_PER_SEC, 0);
+#endif
                        }
                        break;
                }
@@ -596,6 +632,7 @@ static void DNSSD_API reg_reply(DNSServiceRef sdref, const DNSServiceFlags flags
        (void)sdref;    // Unused
        (void)flags;    // Unused
        (void)context;  // Unused
+       EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
 
        printtimestamp();
        printf("Got a reply for service %s.%s%s: ", name, regtype, domain);
@@ -604,7 +641,15 @@ static void DNSSD_API reg_reply(DNSServiceRef sdref, const DNSServiceFlags flags
                {
                if (flags & kDNSServiceFlagsAdd) printf("Name now registered and active\n"); 
                else printf("Name registration removed\n"); 
-               if (operation == 'A' || operation == 'U' || operation == 'N') timeOut = 5;
+               if (operation == 'A' || operation == 'U' || operation == 'N')
+                       {
+                       timeOut = 5;
+#if _DNS_SD_LIBDISPATCH
+                       if (timer_source)
+                               dispatch_source_set_timer(timer_source, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)timeOut * NSEC_PER_SEC),
+                                       (uint64_t)timeOut * NSEC_PER_SEC, 0);
+#endif
+                       }
                }
        else if (errorCode == kDNSServiceErr_NameConflict)
                {
@@ -641,6 +686,7 @@ static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags,
        (void)ifIndex;  // Unused
        (void)ttl;      // Unused
        (void)context;  // Unused
+       EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
 
        if (num_printed++ == 0) printf("Timestamp     A/R Flags if %-30s%4s%4s Rdata\n", "Name", "T", "C");
        printtimestamp();
@@ -705,9 +751,10 @@ static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags,
 static void DNSSD_API port_mapping_create_reply(DNSServiceRef sdref, DNSServiceFlags flags, uint32_t ifIndex, DNSServiceErrorType errorCode, uint32_t publicAddress, uint32_t protocol, uint16_t privatePort, uint16_t publicPort, uint32_t ttl, void *context)
        {
        (void)sdref;       // Unused
-       (void)context;     // Unused
        (void)flags;       // Unused
-       
+       (void)context;     // Unused
+       EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
+
        if (num_printed++ == 0) printf("Timestamp     if   %-20s %-15s %-15s %-15s %-6s\n", "External Address", "Protocol", "Internal Port", "External Port", "TTL");
        printtimestamp();
        if (errorCode && errorCode != kDNSServiceErr_DoubleNAT) printf("Error code %d\n", errorCode);
@@ -719,7 +766,8 @@ static void DNSSD_API port_mapping_create_reply(DNSServiceRef sdref, DNSServiceF
                snprintf(addr, sizeof(addr), "%d.%d.%d.%d", digits[0], digits[1], digits[2], digits[3]);
                printf("%-4d %-20s %-15d %-15d %-15d %-6d%s\n", ifIndex, addr, protocol, ntohs(privatePort), ntohs(publicPort), ttl, errorCode == kDNSServiceErr_DoubleNAT ? " Double NAT" : "");
                }
-       fflush(stdout);
+
+       if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
        }
 #endif
 
@@ -730,7 +778,8 @@ static void DNSSD_API addrinfo_reply(DNSServiceRef sdref, DNSServiceFlags flags,
        char addr[256] = "";
        (void) sdref;
        (void) context;
-       
+       EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
+
        if (num_printed++ == 0) printf("Timestamp     A/R Flags if %-25s %-44s %s\n", "Hostname", "Address", "TTL");
        printtimestamp();
 
@@ -767,6 +816,26 @@ static void DNSSD_API addrinfo_reply(DNSServiceRef sdref, DNSServiceFlags flags,
 // The main test function
 
 static void HandleEvents(void)
+#if _DNS_SD_LIBDISPATCH
+       {
+       main_queue = dispatch_get_main_queue();
+       if (client)  DNSServiceSetDispatchQueue(client, main_queue);
+       if (client_pa)  DNSServiceSetDispatchQueue(client_pa, main_queue);
+       if (operation == 'A' || operation == 'U' || operation == 'N')
+               {
+               timer_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, main_queue);
+               if (timer_source)
+                       {
+                       // Start the timer "timeout" seconds into the future and repeat it every "timeout" seconds
+                       dispatch_source_set_timer(timer_source, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)timeOut * NSEC_PER_SEC),
+                               (uint64_t)timeOut * NSEC_PER_SEC, 0);
+                       dispatch_source_set_event_handler(timer_source, ^{myTimerCallBack();});
+                       dispatch_resume(timer_source);
+                       }
+               }
+       dispatch_main();
+       }
+#else
        {
        int dns_sd_fd  = client    ? DNSServiceRefSockFD(client   ) : -1;
        int dns_sd_fd2 = client_pa ? DNSServiceRefSockFD(client_pa) : -1;
@@ -809,6 +878,7 @@ static void HandleEvents(void)
                        }
                }
        }
+#endif
 
 static int getfirstoption(int argc, char **argv, const char *optstr, int *pOptInd)
 // Return the recognized option in optstr and the option index of the next arg.
@@ -840,9 +910,10 @@ static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordR
        char *name = (char *)context;
        
        (void)service;  // Unused
-       (void)rec;      // Unused
+       (void)rec;              // Unused
        (void)flags;    // Unused
-       
+       EXIT_IF_LIBDISPATCH_FATAL_ERROR(errorCode);
+
        printtimestamp();
        printf("Got a reply for record %s: ", name);
 
@@ -854,28 +925,26 @@ static void DNSSD_API MyRegisterRecordCallback(DNSServiceRef service, DNSRecordR
                }
        if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
        // DNSServiceRemoveRecord(service, rec, 0); to test record removal
-       }
 
-static unsigned long getip(const char *const name)
-       {
-       unsigned long ip = 0;
-       struct addrinfo hints;
-       struct addrinfo *addrs = NULL;
-
-       memset(&hints, 0, sizeof(hints));
-       hints.ai_family = AF_INET;
-       
-       if (getaddrinfo(name, NULL, &hints, &addrs) == 0)
+#if 0  // To test updating of individual records registered via DNSServiceRegisterRecord
+       if (!errorCode)
                {
-               ip = ((struct sockaddr_in*) addrs->ai_addr)->sin_addr.s_addr;
+               int x = 0x11111111;
+               printf("Updating\n");
+               DNSServiceUpdateRecord(service, rec, 0, sizeof(x), &x, 0);
                }
+#endif
 
-       if (addrs)
-               {
-               freeaddrinfo(addrs);
-               }
+       if (!(flags & kDNSServiceFlagsMoreComing)) fflush(stdout);
+       }
 
-       return(ip);
+static void getip(const char *const name, struct sockaddr_storage *result)
+       {
+       struct addrinfo *addrs = NULL;
+       int err = getaddrinfo(name, NULL, NULL, &addrs);
+       if (err) fprintf(stderr, "getaddrinfo error %d for %s", err, name);
+       else memcpy(result, addrs->ai_addr, SA_LEN(addrs->ai_addr));
+       if (addrs) freeaddrinfo(addrs);
        }
 
 static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef sdref, const char *host, const char *ip)
@@ -884,10 +953,15 @@ static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef sdref, const
        // On the Win32 platform, WinSock must be initialized for getip() to succeed.
        // Any DNSService* call will initialize WinSock for us, so we make sure
        // DNSServiceCreateConnection() is called before getip() is.
-       unsigned long addr = getip(ip);
-       return(DNSServiceRegisterRecord(sdref, &record, kDNSServiceFlagsUnique, opinterface, host,
-               kDNSServiceType_A, kDNSServiceClass_IN, sizeof(addr), &addr, 240, MyRegisterRecordCallback, (void*)host));
-       // Note, should probably add support for creating proxy AAAA records too, one day
+       struct sockaddr_storage hostaddr;
+       getip(ip, &hostaddr);
+       if (hostaddr.ss_family == AF_INET)
+               return(DNSServiceRegisterRecord(sdref, &record, kDNSServiceFlagsUnique, opinterface, host,
+                       kDNSServiceType_A,    kDNSServiceClass_IN,  4, &((struct sockaddr_in *)&hostaddr)->sin_addr,  240, MyRegisterRecordCallback, (void*)host));
+       else if (hostaddr.ss_family == AF_INET6)
+               return(DNSServiceRegisterRecord(sdref, &record, kDNSServiceFlagsUnique, opinterface, host,
+                       kDNSServiceType_AAAA, kDNSServiceClass_IN, 16, &((struct sockaddr_in6*)&hostaddr)->sin6_addr, 240, MyRegisterRecordCallback, (void*)host));
+       else return(kDNSServiceErr_BadParam);
        }
 
 #define HexVal(X) ( ((X) >= '0' && (X) <= '9') ? ((X) - '0'     ) :  \
@@ -981,6 +1055,14 @@ int main(int argc, char **argv)
                printf("Using LocalOnly\n");
                }
 
+       if (argc > 1 && (!strcmp(argv[1], "-p2p") || !strcmp(argv[1], "-P2P")))
+               {
+               argc--;
+               argv++;
+               opinterface = kDNSServiceInterfaceIndexP2P;
+               printf("Using P2P\n");
+               }
+
        if (argc > 2 && !strcmp(argv[1], "-i"))
                {
                opinterface = if_nametoindex(argv[2]);
@@ -991,7 +1073,7 @@ int main(int argc, char **argv)
                }
 
        if (argc < 2) goto Fail;        // Minimum command line is the command name and one argument
-       operation = getfirstoption(argc, argv, "EFBZLRPQCAUNTMISV"
+       operation = getfirstoption(argc, argv, "EFBZLRPQqCAUNTMISV"
                                                                #if HAS_NAT_PMP_API
                                                                        "X"
                                                                #endif
@@ -1063,10 +1145,12 @@ int main(int argc, char **argv)
                                        //DNSServiceRemoveRecord(client_pa, record, 0);
                                        break;
 
+               case 'q':
                case 'Q':
                case 'C':       {
                                        uint16_t rrtype, rrclass;
                                        DNSServiceFlags flags = kDNSServiceFlagsReturnIntermediates;
+                                       if (operation == 'q') flags |= kDNSServiceFlagsSuppressUnusable;
                                        if (argc < opi+1) goto Fail;
                                        rrtype = (argc <= opi+1) ? kDNSServiceType_A  : GetRRType(argv[opi+1]);
                                        rrclass = (argc <= opi+2) ? kDNSServiceClass_IN : atoi(argv[opi+2]);
@@ -1145,7 +1229,7 @@ int main(int argc, char **argv)
 #endif
 
                case 'S':       {
-                                       Opaque16 registerPort = { { 0x23, 0x45 } };
+                                       Opaque16 registerPort = { { 0x23, 0x45 } };             // 9029 decimal
                                        unsigned char txtrec[16] = "\xF" "/path=test.html";
                                        DNSRecordRef rec;
                                        unsigned char nulrec[4] = "1234";
diff --git a/Clients/mDNSNetMonitor.VisualStudio/mDNSNetMonitor.rc b/Clients/mDNSNetMonitor.VisualStudio/mDNSNetMonitor.rc
new file mode 100644 (file)
index 0000000..2c0b25c
--- /dev/null
@@ -0,0 +1,103 @@
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+#include "WinVersRes.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+    "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+    "#include ""afxres.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+    "\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION MASTER_PROD_VERS\r
+ PRODUCTVERSION MASTER_PROD_VERS\r
+ FILEFLAGSMASK 0x17L\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x1L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+        BLOCK "040904b0"\r
+        BEGIN\r
+            VALUE "CompanyName", MASTER_COMPANY_NAME\r
+            VALUE "FileDescription", "Bonjour Network Utility"\r
+            VALUE "FileVersion", MASTER_PROD_VERS_STR\r
+            VALUE "InternalName", "mDNSNetMonitor.exe"\r
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
+            VALUE "OriginalFilename", "mDNSNetMonitor.exe"\r
+            VALUE "ProductName", MASTER_PROD_NAME\r
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+        VALUE "Translation", 0x409, 1200\r
+    END\r
+END\r
+\r
+#endif    // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
+\r
index 85ede41c9cf08823d95de35f77d5ccf235ade95b..122889c1de034634b5d1d28a86940afff8362cd6 100755 (executable)
                        />\r
                        <Tool\r
                                Name="VCResourceCompilerTool"\r
+                               AdditionalIncludeDirectories="../../mDNSWindows"\r
                        />\r
                        <Tool\r
                                Name="VCPreLinkEventTool"\r
                        />\r
                        <Tool\r
                                Name="VCLinkerTool"\r
+                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
                                AdditionalDependencies="ws2_32.lib iphlpapi.lib crypt32.lib netapi32.lib powrprof.lib"\r
                                LinkIncremental="2"\r
                                GenerateDebugInformation="true"\r
                        />\r
                        <Tool\r
                                Name="VCResourceCompilerTool"\r
+                               AdditionalIncludeDirectories="../../mDNSWindows"\r
                        />\r
                        <Tool\r
                                Name="VCPreLinkEventTool"\r
                        />\r
                        <Tool\r
                                Name="VCLinkerTool"\r
+                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
                                AdditionalDependencies="ws2_32.lib iphlpapi.lib crypt32.lib netapi32.lib powrprof.lib"\r
                                LinkIncremental="1"\r
                                GenerateDebugInformation="true"\r
                                RelativePath="..\..\mDNSWindows\Secret.c"\r
                                >\r
                        </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSWindows\SystemService\Service.c"\r
-                               >\r
-                       </File>\r
                        <File\r
                                RelativePath="..\..\mDNSCore\uDNS.c"\r
                                >\r
                        Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"\r
                        UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
                        >\r
+                       <File\r
+                               RelativePath=".\mDNSNetMonitor.rc"\r
+                               >\r
+                       </File>\r
                </Filter>\r
        </Files>\r
        <Globals>\r
diff --git a/Clients/mDNSNetMonitor.VisualStudio/resource.h b/Clients/mDNSNetMonitor.VisualStudio/resource.h
new file mode 100644 (file)
index 0000000..e978f9e
--- /dev/null
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Visual C++ generated include file.\r
+// Used by mDNSNetMonitor.rc\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE        101\r
+#define _APS_NEXT_COMMAND_VALUE         40001\r
+#define _APS_NEXT_CONTROL_VALUE         1001\r
+#define _APS_NEXT_SYMED_VALUE           101\r
+#endif\r
+#endif\r
index 04462ee4fe59c1fade9fb697b43cd69f64b2c311..d112435da49d027b4245796a8d1e95a0115d4833 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@
 
 include /Developer/Makefiles/pb_makefiles/platform.make
 
-MVERS = "mDNSResponder-214.3.2"
+MVERS = "mDNSResponder-258.13"
 
 DDNSWRITECONFIG = "$(DSTROOT)/Library/Application Support/Bonjour/ddnswriteconfig"
 
@@ -35,7 +35,7 @@ installsrc:
        ditto . "$(SRCROOT)"
 
 installhdrs::
-       cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild installhdrs OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS)
+       cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild installhdrs OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) -target SystemLibraries
 
 clean::
        echo clean
index a866aa60669030e29c84838d822ee7cc161f0044..bb7a082a02d5baad4bf40ad1ee544daf01a50ad9 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: DNSCommon.c,v $
-Revision 1.252  2009/06/27 00:27:03  cheshire
-<rdar://problem/6959273> mDNSResponder taking up 13% CPU with 400 KBps incoming bonjour requests
-Removed overly-complicate and ineffective multi-packet known-answer snooping code
-(Bracketed it with "#if ENABLE_MULTI_PACKET_QUERY_SNOOPING" for now; will delete actual code later)
-
-Revision 1.251  2009/05/19 23:40:37  cheshire
-<rdar://problem/6903507> Sleep Proxy: Retransmission logic not working reliably on quiet networks
-Added m->NextScheduledSPRetry timer for scheduling Sleep Proxy registration retries
-
-Revision 1.250  2009/05/01 21:28:33  cheshire
-<rdar://problem/6721680> AppleConnectAgent's reachability checks delay sleep by 30 seconds
-No longer suspend network operations after we've acknowledged that the machine is going to sleep,
-because other software may not have yet acknowledged the sleep event, and may be still trying
-to do unicast DNS queries or other Bonjour operations.
-
-Revision 1.249  2009/04/24 00:29:20  cheshire
-<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
-Added support for generating/parsing/displaying NSEC records
-
-Revision 1.248  2009/04/23 22:11:16  cheshire
-Minor cleanup in debugging checks in GetLargeResourceRecord
-
-Revision 1.247  2009/04/21 23:36:25  cheshire
-<rdar://problem/6814427> Remove unused kDNSType_MAC
-
-Revision 1.246  2009/04/21 01:00:19  cheshire
-Fixed typo in previous checkin
-
-Revision 1.245  2009/04/21 00:57:23  cheshire
-<rdar://problem/6810410> Off-by-one error in putDomainNameAsLabels()
-If just writing one-byte root label, make sure we have space for that
-
-Revision 1.244  2009/04/11 00:19:30  jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.243  2009/04/01 17:50:10  mcguire
-cleanup mDNSRandom
-
-Revision 1.242  2009/03/26 04:01:55  jessic2
-<rdar://problem/6613786> MessageTracer: Log service types longer than 14 characters and service types with underscores
-
-Revision 1.241  2009/03/18 20:50:08  cheshire
-<rdar://problem/6650064> uDNS: Reverse lookup of own IP address takes way too long, sometimes forever
-
-Revision 1.240  2009/03/18 20:41:04  cheshire
-Added definition of the all-ones mDNSOpaque16 ID
-
-Revision 1.239  2009/03/06 23:51:50  mcguire
-Fix broken build by defining DiscardPort
-
-Revision 1.238  2009/03/04 00:40:13  cheshire
-Updated DNS server error codes to be more consistent with definitions at
-<http://www.iana.org/assignments/dns-parameters>
-
-Revision 1.237  2009/03/03 23:04:43  cheshire
-For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC)
-
-Revision 1.236  2009/03/03 22:51:53  cheshire
-<rdar://problem/6504236> Sleep Proxy: Waking on same network but different interface will cause conflicts
-
-Revision 1.235  2009/02/07 05:55:44  cheshire
-Only pay attention to m->DelaySleep when it's nonzero
-
-Revision 1.234  2009/02/07 02:52:52  cheshire
-<rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
-Pay attention to m->DelaySleep when computing next task time
-
-Revision 1.233  2009/01/30 23:50:31  cheshire
-Added LastLabel() routine to get the last label of a domainname
-
-Revision 1.232  2009/01/15 00:22:48  mcguire
-<rdar://problem/6437092> NAT-PMP: mDNSResponder needs to listen on 224.0.0.1:5350/UDP with REUSEPORT
-
-Revision 1.231  2008/12/12 01:24:06  cheshire
-Updated GetNextScheduledEvent() to pay attention to m->SPSProxyListChanged
-
-Revision 1.230  2008/12/10 01:55:54  cheshire
-Renamed "Max" macro to avoid conflict with another "Max" macro on ARMv5
-
-Revision 1.229  2008/11/27 01:28:45  cheshire
-For display purposes, show sleep sequence number as unsigned
-
-Revision 1.228  2008/11/26 20:57:37  cheshire
-For consistency with other similar macros, renamed mdnsIsDigit/mdnsIsLetter/mdnsValidHostChar
-to mDNSIsDigit/mDNSIsLetter/mDNSValidHostChar
-
-Revision 1.227  2008/11/26 20:28:05  cheshire
-Added new SSHPort constant
-
-Revision 1.226  2008/11/16 16:55:51  cheshire
-Updated debugging messages
-
-Revision 1.225  2008/11/14 21:56:31  cheshire
-Moved debugging routine ShowTaskSchedulingError() from daemon.c into DNSCommon.c
-
-Revision 1.224  2008/11/14 02:20:03  cheshire
-Include m->NextScheduledSPS in task scheduling calculations
-
-Revision 1.223  2008/11/14 01:19:03  cheshire
-Initialize TimeRcvd and TimeExpire fields in AuthRecord_struct
-
-Revision 1.222  2008/11/14 00:00:53  cheshire
-After client machine wakes up, Sleep Proxy machine need to remove any records
-it was temporarily holding as proxy for that client
-
-Revision 1.221  2008/11/13 19:06:02  cheshire
-Added code to put, get, and display rdataOPT properly
-
-Revision 1.220  2008/11/06 01:08:11  mcguire
-Fix compiler warning about discarding const
-
-Revision 1.219  2008/11/04 23:06:50  cheshire
-Split RDataBody union definition into RDataBody and RDataBody2, and removed
-SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord
-
-Revision 1.218  2008/11/04 22:21:44  cheshire
-Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord
-
-Revision 1.217  2008/11/04 22:13:43  cheshire
-Made RDataBody parameter to GetRRDisplayString_rdb "const"
-
-Revision 1.216  2008/11/04 20:06:19  cheshire
-<rdar://problem/6186231> Change MAX_DOMAIN_NAME to 256
-
-Revision 1.215  2008/10/23 23:54:35  cheshire
-Added missing "const" in declaration
-
-Revision 1.214  2008/10/23 22:25:55  cheshire
-Renamed field "id" to more descriptive "updateid"
-
-Revision 1.213  2008/10/22 01:01:52  cheshire
-Added onesEthAddr constant, used for sending ARP broadcasts
-
-Revision 1.212  2008/10/14 21:52:18  cheshire
-Added support for putting/getting/printing kDNSType_MAC
-
-Revision 1.211  2008/10/09 22:36:08  cheshire
-Now that we have Sleep Proxy Server, can't suppress normal scheduling logic while going to sleep
-
-Revision 1.210  2008/10/08 01:03:52  cheshire
-Change GetFirstActiveInterface() so the NetworkInterfaceInfo it returns is not "const"
-Added mDNS_SetupQuestion() convenience function
-
-Revision 1.209  2008/09/23 04:13:30  cheshire
-<rdar://problem/6238774> Remove "local" from the end of _services._dns-sd._udp PTR records
-Removed old special-case Bonjour Browser hack that is no longer needed
-
-Revision 1.208  2008/09/23 02:33:56  cheshire
-<rdar://problem/4738033> uDNS: Should not compress SRV rdata in uDNS packets
-
-Revision 1.207  2008/09/23 02:30:07  cheshire
-Get rid of PutResourceRecordCappedTTL()
-
-Revision 1.206  2008/09/23 02:26:09  cheshire
-Don't need to export putEmptyResourceRecord (it's only used from DNSCommon.c)
-
-Revision 1.205  2008/09/23 02:21:00  cheshire
-Don't need to force setting of rrclass in PutResourceRecordTTLWithLimit() now that putLLQ() sets it correctly
-
-Revision 1.204  2008/08/29 19:03:05  cheshire
-<rdar://problem/6185645> Off-by-one error in putDomainNameAsLabels()
-
-Revision 1.203  2008/08/13 00:47:53  mcguire
-Handle failures when packet logging
-
-Revision 1.202  2008/08/13 00:32:48  mcguire
-refactor to use SwapDNSHeaderBytes instead of swapping manually
-
-Revision 1.201  2008/07/24 20:23:03  cheshire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-
-Revision 1.200  2008/07/18 00:07:50  cheshire
-<rdar://problem/5904999> Log a message for applications that register service types longer than 14 characters
-
-Revision 1.199  2008/03/14 19:58:38  mcguire
-<rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
-Make sure we add the record when sending LLQ refreshes
-
-Revision 1.198  2008/03/07 23:29:24  cheshire
-Fixed cosmetic byte order display issue in DumpPacket output
-
-Revision 1.197  2008/03/05 22:51:29  mcguire
-<rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
-Even further refinements
-
-Revision 1.196  2008/03/05 22:01:53  cheshire
-<rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
-Now that we optionally add the HINFO record, when rewriting the header fields into network byte
-order, we need to use our updated msg->h.numAdditionals, not the stack variable numAdditionals
-
-Revision 1.195  2008/03/05 19:06:30  mcguire
-<rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
-further refinements
-
-Revision 1.194  2008/03/05 00:26:06  cheshire
-<rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
-
-Revision 1.193  2007/12/17 23:42:36  cheshire
-Added comments about DNSDigest_SignMessage()
-
-Revision 1.192  2007/12/17 21:24:09  cheshire
-<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
-We suspend sending of mDNS queries responses when going to sleep, so calculate GetNextScheduledEvent() time accordingly
-
-Revision 1.191  2007/12/14 00:59:36  cheshire
-<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
-While going to sleep, don't block event scheduling
-
-Revision 1.190  2007/12/13 20:20:17  cheshire
-Minor efficiency tweaks -- converted IdenticalResourceRecord, IdenticalSameNameRecord, and
-SameRData from functions to macros, which allows the code to be inlined (the compiler can't
-inline a function defined in a different compilation unit) and therefore optimized better.
-
-Revision 1.189  2007/12/13 00:17:32  cheshire
-RDataHashValue was not calculating hash value reliably for RDATA types that have 'holes' in the
-in-memory representation (particularly SOA was affected by this, resulting in multiple duplicate
-cache entities for the same SOA record, because they had erroneously different rdatahash values).
-
-Revision 1.188  2007/12/13 00:13:03  cheshire
-Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody
-
-Revision 1.187  2007/12/08 00:35:20  cheshire
-<rdar://problem/5636422> Updating TXT records is too slow
-m->SuppressSending should not suppress all activity, just mDNS Query/Probe/Response
-
-Revision 1.186  2007/11/15 22:52:29  cheshire
-<rdar://problem/5589039> ERROR: mDNSPlatformWriteTCP - send Broken pipe
-
-Revision 1.185  2007/10/10 20:22:03  cheshire
-Added sanity checks in mDNSSendDNSMessage -- we've seen crashes in DNSDigest_SignMessage
-apparently caused by trying to sign zero-length messages
-
-Revision 1.184  2007/10/05 17:56:07  cheshire
-Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
-
-Revision 1.183  2007/10/02 18:33:46  cheshire
-Improved GetRRDisplayString to show all constituent strings within a text record
-(up to the usual MaxMsg 120-character limit)
-
-Revision 1.182  2007/10/01 19:45:01  cheshire
-<rdar://problem/5514859> BTMM: Sometimes Back to My Mac autotunnel registrations are malformed
-
-Revision 1.181  2007/10/01 18:36:53  cheshire
-Yet another fix to finally get the DumpPacket RCODE display right
-
-Revision 1.180  2007/09/29 21:30:38  cheshire
-In DumpPacket/DumpRecords, show an error line if we run out of packet data
-
-Revision 1.179  2007/09/29 20:44:56  cheshire
-Fix error in DumpPacket where it was not displaying the RCODE field properly
-
-Revision 1.178  2007/09/27 21:11:44  cheshire
-Fixed spelling mistake: ROCDE -> RCODE
-
-Revision 1.177  2007/09/27 18:51:26  cheshire
-Improved DumpPacket to use "Zone/Prerequisites/Updates" nomenclature when displaying a DNS Update packet
-
-Revision 1.176  2007/09/27 17:53:37  cheshire
-Add display of RCODE and flags in DumpPacket output
-
-Revision 1.175  2007/09/26 22:26:40  cheshire
-Also show DNS query/response ID in DumpPacket output
-
-Revision 1.174  2007/09/26 16:36:02  cheshire
-In DumpPacket output, begin header line with "-- " to make it visually stand out better
-
-Revision 1.173  2007/09/26 00:49:46  cheshire
-Improve packet logging to show sent and received packets,
-transport protocol (UDP/TCP/TLS) and source/destination address:port
-
-Revision 1.172  2007/09/21 23:14:39  cheshire
-<rdar://problem/5498009> BTMM: Need to log updates and query packet contents in verbose debug mode
-Changed DumpRecords to use LargeCacheRecord on the stack instead of the shared m->rec storage,
-to eliminate "GetLargeResourceRecord: m->rec appears to be already in use" warnings
-
-Revision 1.171  2007/09/21 21:12:36  cheshire
-<rdar://problem/5498009> BTMM: Need to log updates and query packet contents
-
-Revision 1.170  2007/09/07 21:16:58  cheshire
-Add new symbol "NATPMPAnnouncementPort" (5350)
-
-Revision 1.169  2007/08/30 00:31:20  cheshire
-Improve "locking failure" debugging messages to show function name using __func__ macro
-
-Revision 1.168  2007/08/28 23:58:42  cheshire
-Rename HostTarget -> AutoTarget
-
-Revision 1.167  2007/08/10 23:10:05  vazquez
-<rdar://problem/5389850> mDNS: Reverse lookups of IPv6 link-local addresses always fail
-
-Revision 1.166  2007/08/01 16:09:13  cheshire
-Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
-
-Revision 1.165  2007/08/01 00:04:13  cheshire
-<rdar://problem/5261696> Crash in tcpKQSocketCallback
-Half-open TCP connections were not being cancelled properly
-
-Revision 1.164  2007/07/27 20:48:43  cheshire
-In DumpRecords(), include record TTL in output
-
-Revision 1.163  2007/07/16 20:10:11  vazquez
-<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
-Added SSDP port number
-
-Revision 1.162  2007/07/10 01:59:33  cheshire
-<rdar://problem/3557903> Performance: Core code will not work on platforms with small stacks
-Fixed GetPktLease to use shared m->rec instead of putting LargeCacheRecord on the stack
-
-Revision 1.161  2007/07/06 18:56:26  cheshire
-Check m->NextScheduledNATOp in GetNextScheduledEvent()
-
-Revision 1.160  2007/06/29 00:06:42  vazquez
-<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-
-Revision 1.159  2007/06/28 21:17:17  cheshire
-Rename "m->nextevent" as more informative "m->NextuDNSEvent"
-
-Revision 1.158  2007/05/25 00:25:43  cheshire
-<rdar://problem/5227737> Need to enhance putRData to output all current known types
-
-Revision 1.157  2007/05/23 00:32:15  cheshire
-Don't treat uDNS responses as an entire RRSet (kDNSRecordTypePacketUniqueMask)
-when received in a truncated UDP response
-
-Revision 1.156  2007/05/15 00:29:00  cheshire
-Print «ZERO ADDRESS» for %#a with a zero mDNSAddr
-
-Revision 1.155  2007/05/07 22:07:47  cheshire
-<rdar://problem/4738025> Enhance GetLargeResourceRecord to decompress more record types
-
-Revision 1.154  2007/05/04 20:19:53  cheshire
-Improve DumpPacket() output
-
-Revision 1.153  2007/05/01 21:46:31  cheshire
-Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them
-
-Revision 1.152  2007/04/27 19:28:01  cheshire
-Any code that calls StartGetZoneData needs to keep a handle to the structure, so
-it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
--- it would start a query and then quickly cancel it, and then when
-StartGetZoneData completed, it had a dangling pointer and crashed.)
-
-Revision 1.151  2007/04/26 13:35:25  cheshire
-Add kDNSType_SOA case in SameRDataBody, and a comment in GetLargeResourceRecord about why this is important
-
-Revision 1.150  2007/04/24 00:17:33  cheshire
-Made LocateLLQOptData guard against packets with bogus numAdditionals value
-
-Revision 1.149  2007/04/23 21:43:00  cheshire
-Remove debugging check
-
-Revision 1.148  2007/04/23 04:55:29  cheshire
-Add some defensive null pointer checks
-
-Revision 1.147  2007/04/22 20:18:10  cheshire
-Add comment about mDNSRandom()
-
-Revision 1.146  2007/04/22 06:02:02  cheshire
-<rdar://problem/4615977> Query should immediately return failure when no server
-
-Revision 1.145  2007/04/20 21:17:24  cheshire
-For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
-
-Revision 1.144  2007/04/19 18:02:43  cheshire
-<rdar://problem/5140504> Unicast DNS response records should tagged with kDNSRecordTypePacketUnique bit
-
-Revision 1.143  2007/04/16 21:53:49  cheshire
-Improve display of negative cache entries
-
-Revision 1.142  2007/04/05 22:55:35  cheshire
-<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
-
-Revision 1.141  2007/04/04 01:33:11  cheshire
-<rdar://problem/5075200> DNSServiceAddRecord is failing to advertise NULL record
-Overly defensive code was zeroing too much of the AuthRecord structure
-
-Revision 1.140  2007/04/03 19:37:58  cheshire
-Rename mDNSAddrIsv4Private() to more precise mDNSAddrIsRFC1918()
-
-Revision 1.139  2007/04/03 19:18:39  cheshire
-Use mDNSSameIPv4Address (and similar) instead of accessing internal fields directly
-
-Revision 1.138  2007/03/28 21:14:08  cheshire
-The rrclass field of an OPT pseudo-RR holds the sender's UDP payload size
-
-Revision 1.137  2007/03/28 20:59:26  cheshire
-<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
-
-Revision 1.136  2007/03/28 15:56:37  cheshire
-<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
-
-Revision 1.135  2007/03/28 01:20:05  cheshire
-<rdar://problem/4883206> Improve/create logging for secure browse
-
-Revision 1.134  2007/03/27 23:25:35  cheshire
-Fix error caching SOA records
-(cache entry was size of wire-format packed data, not size of in-memory structure)
-
-Revision 1.133  2007/03/26 22:55:45  cheshire
-Add OPT and TSIG to list of types DNSTypeName() knows about
-
-Revision 1.132  2007/03/22 18:31:48  cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.131  2007/03/21 21:55:20  cheshire
-<rdar://problem/5069688> Hostname gets ; or : which are illegal characters
-Error in AppendLabelSuffix() for numbers close to the 32-bit limit
-
-Revision 1.130  2007/03/21 19:23:37  cheshire
-<rdar://problem/5076826> jmDNS advertised garbage that shows up weird in Safari
-Make check less strict so we don't break Bonjour Browser
-
-Revision 1.129  2007/03/21 01:00:45  cheshire
-<rdar://problem/5076826> jmDNS advertised garbage that shows up weird in Safari
-DeconstructServiceName() needs to be more defensive about what it considers legal
-
-Revision 1.128  2007/03/21 00:30:02  cheshire
-<rdar://problem/4789455> Multiple errors in DNameList-related code
-
-Revision 1.127  2007/03/20 17:07:15  cheshire
-Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-
-Revision 1.126  2007/03/10 03:26:44  cheshire
-<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
-
-Revision 1.125  2007/03/07 00:08:58  cheshire
-<rdar://problem/4347550> Don't allow hyphens at start of service type
-
-Revision 1.124  2007/01/19 18:04:05  cheshire
-For naming consistency, use capital letters for RR types: rdataOpt should be rdataOPT
-
-Revision 1.123  2007/01/10 22:45:51  cheshire
-Cast static strings to "(const domainname*)", not "(domainname*)"
-
-Revision 1.122  2007/01/06 00:47:35  cheshire
-Improve GetRRDisplayString to indicate when record has zero-length rdata
-
-Revision 1.121  2007/01/05 08:30:39  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.120  2007/01/05 05:23:00  cheshire
-Zero DNSQuestion structure in getQuestion (specifically, need TargetQID to be zero'd)
-
-Revision 1.119  2007/01/05 04:30:16  cheshire
-Change a couple of "(domainname *)" casts to "(const domainname *)"
-
-Revision 1.118  2007/01/04 20:21:59  cheshire
-<rdar://problem/4720673> uDNS: Need to start caching unicast records
-Don't return multicast answers in response to unicast questions
-
-Revision 1.117  2006/12/22 20:59:49  cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.116  2006/12/21 00:04:07  cheshire
-To be defensive, put a mDNSPlatformMemZero() at the start of mDNS_SetupResourceRecord()
-
-Revision 1.115  2006/12/20 04:07:34  cheshire
-Remove uDNS_info substructure from AuthRecord_struct
-
-Revision 1.114  2006/12/19 22:40:04  cheshire
-Fix compiler warnings
-
-Revision 1.113  2006/12/19 02:21:08  cheshire
-Delete spurious spaces
-
-Revision 1.112  2006/12/15 20:42:10  cheshire
-<rdar://problem/4769083> ValidateRData() should be stricter about malformed MX and SRV records
-Additional defensive coding in GetLargeResourceRecord() to reject apparently-valid
-rdata that actually runs past the end of the received packet data.
-
-Revision 1.111  2006/12/15 19:09:57  cheshire
-<rdar://problem/4769083> ValidateRData() should be stricter about malformed MX and SRV records
-Made DomainNameLength() more defensive by adding a limit parameter, so it can be
-safely used to inspect potentially malformed data received from external sources.
-Without this, a domain name that starts off apparently valid, but extends beyond the end of
-the received packet data, could have appeared valid if the random bytes are already in memory
-beyond the end of the packet just happened to have reasonable values (e.g. all zeroes).
-
-Revision 1.110  2006/11/18 05:01:30  cheshire
-Preliminary support for unifying the uDNS and mDNS code,
-including caching of uDNS answers
-
-Revision 1.109  2006/11/10 00:54:14  cheshire
-<rdar://problem/4816598> Changing case of Computer Name doesn't work
-
-Revision 1.108  2006/10/05 23:11:18  cheshire
-<rdar://problem/4769083> ValidateRData() should be stricter about malformed MX and SRV records
-
-Revision 1.107  2006/09/15 21:20:14  cheshire
-Remove uDNS_info substructure from mDNS_struct
-
-Revision 1.106  2006/08/14 23:24:22  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.105  2006/07/15 02:01:28  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Fix broken "empty string" browsing
-
-Revision 1.104  2006/07/05 23:09:13  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
-
-Revision 1.103  2006/06/29 07:42:14  cheshire
-<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
-
-Revision 1.102  2006/06/22 19:49:11  cheshire
-Added (commented out) definitions for the LLMNR UDP port and multicast addresses
-
-Revision 1.101  2006/06/15 21:35:15  cheshire
-Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants
-from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code
-
-Revision 1.100  2006/06/08 22:58:46  cheshire
-<rdar://problem/4335605> IPv6 link-local address prefix is FE80::/10, not FE80::/16
-
-Revision 1.99  2006/05/18 01:32:33  cheshire
-<rdar://problem/4472706> iChat: Lost connection with Bonjour
-(mDNSResponder insufficiently defensive against malformed browsing PTR responses)
-
-Revision 1.98  2006/03/19 17:00:58  cheshire
-Define symbol MaxMsg instead of using hard-coded constant value '80'
-
-Revision 1.97  2006/03/18 21:47:56  cheshire
-<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-
-Revision 1.96  2006/03/10 21:51:42  cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-Split out SameRDataBody() into a separate routine so it can be called from other code
-
-Revision 1.95  2006/03/08 22:43:11  cheshire
-Use "localdomain" symbol instead of literal string
-
-Revision 1.94  2006/03/02 21:59:55  cheshire
-<rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
-Improve sanity checks & debugging support in GetLargeResourceRecord()
-
-Revision 1.93  2006/03/02 20:30:47  cheshire
-Improved GetRRDisplayString to also show priority, weight, and port for SRV records
-
-*/
+ */
 
 // Set mDNS_InstantiateInlines to tell mDNSEmbeddedAPI.h to instantiate inline functions, if necessary
 #define mDNS_InstantiateInlines 1
@@ -580,21 +35,11 @@ Improved GetRRDisplayString to also show priority, weight, and port for SRV reco
 #pragma mark - Program Constants
 #endif
 
-mDNSexport const mDNSIPPort      zeroIPPort        = { { 0 } };
-mDNSexport const mDNSv4Addr      zerov4Addr        = { { 0 } };
-mDNSexport const mDNSv6Addr      zerov6Addr        = { { 0 } };
-mDNSexport const mDNSEthAddr     zeroEthAddr       = { { 0 } };
-mDNSexport const mDNSv4Addr      onesIPv4Addr      = { { 255, 255, 255, 255 } };
-mDNSexport const mDNSv6Addr      onesIPv6Addr      = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } };
-mDNSexport const mDNSAddr        zeroAddr          = { mDNSAddrType_None, {{{ 0 }}} };
-mDNSexport const mDNSEthAddr     onesEthAddr       = { { 255, 255, 255, 255, 255, 255 } };
-
-mDNSexport const OwnerOptData    zeroOwner         = { 0, 0, { { 0 } }, { { 0 } }, { { 0 } } };
-
 mDNSexport const mDNSInterfaceID mDNSInterface_Any       = 0;
-mDNSexport const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)-1;
+mDNSexport const mDNSInterfaceID mDNSInterfaceMark       = (mDNSInterfaceID)-1;
 mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)-2;
 mDNSexport const mDNSInterfaceID mDNSInterface_Unicast   = (mDNSInterfaceID)-3;
+mDNSexport const mDNSInterfaceID mDNSInterface_P2P       = (mDNSInterfaceID)-4;
 
 // Note: Microsoft's proposed "Link Local Multicast Name Resolution Protocol" (LLMNR) is essentially a limited version of
 // Multicast DNS, using the same packet formats, naming syntax, and record types as Multicast DNS, but on a different UDP
@@ -630,12 +75,26 @@ mDNSexport const mDNSIPPort MulticastDNSPort       = { { MulticastDNSPortAsNumbe
 mDNSexport const mDNSIPPort LoopbackIPCPort        = { { LoopbackIPCPortAsNumber        >> 8, LoopbackIPCPortAsNumber        & 0xFF } };
 mDNSexport const mDNSIPPort PrivateDNSPort         = { { PrivateDNSPortAsNumber         >> 8, PrivateDNSPortAsNumber         & 0xFF } };
 
-mDNSexport const mDNSv4Addr AllDNSAdminGroup   = { { 239, 255, 255, 251 } };
-mDNSexport const mDNSv4Addr AllSystemsMcast    = { { 224,   0,   0,   1 } }; // For NAT-PMP Annoucements
-mDNSexport const mDNSAddr   AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224,   0,   0, 251 } } } };
-//mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224,   0,   0, 252 } } } }; // LLMNR
-mDNSexport const mDNSAddr   AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } };
-//mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x01,0x00,0x03 } } } }; // LLMNR
+mDNSexport const OwnerOptData    zeroOwner         = { 0, 0, { { 0 } }, { { 0 } }, { { 0 } } };
+
+mDNSexport const mDNSIPPort      zeroIPPort        = { { 0 } };
+mDNSexport const mDNSv4Addr      zerov4Addr        = { { 0 } };
+mDNSexport const mDNSv6Addr      zerov6Addr        = { { 0 } };
+mDNSexport const mDNSEthAddr     zeroEthAddr       = { { 0 } };
+mDNSexport const mDNSv4Addr      onesIPv4Addr      = { { 255, 255, 255, 255 } };
+mDNSexport const mDNSv6Addr      onesIPv6Addr      = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } };
+mDNSexport const mDNSEthAddr     onesEthAddr       = { { 255, 255, 255, 255, 255, 255 } };
+mDNSexport const mDNSAddr        zeroAddr          = { mDNSAddrType_None, {{{ 0 }}} };
+
+mDNSexport const mDNSv4Addr  AllDNSAdminGroup   = { { 239, 255, 255, 251 } };
+mDNSexport const mDNSv4Addr  AllHosts_v4        = { { 224,   0,   0,   1 } }; // For NAT-PMP Annoucements
+mDNSexport const mDNSv6Addr  AllHosts_v6        = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01 } };
+mDNSexport const mDNSv6Addr  NDP_prefix         = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01, 0xFF,0x00,0x00,0xFB } }; // FF02:0:0:0:0:1:FF00::/104
+mDNSexport const mDNSEthAddr AllHosts_v6_Eth    = { { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 } };
+mDNSexport const mDNSAddr    AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224,   0,   0, 251 } } } };
+//mDNSexport const mDNSAddr  AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224,   0,   0, 252 } } } }; // LLMNR
+mDNSexport const mDNSAddr    AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } };
+//mDNSexport const mDNSAddr  AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x01,0x00,0x03 } } } }; // LLMNR
 
 mDNSexport const mDNSOpaque16 zeroID          = { { 0, 0 } };
 mDNSexport const mDNSOpaque16 onesID          = { { 255, 255 } };
@@ -786,7 +245,7 @@ mDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RD
                                                        break;
 
                case kDNSType_NSEC: {
-                                                       int i;
+                                                       mDNSu16 i;
                                                        for (i=0; i<255; i++)
                                                                if (rd->nsec.bitmap[i>>3] & (128 >> (i&7)))
                                                                        length += mDNS_snprintf(buffer+length, RemSpc, "%s ", DNSTypeName(i));
@@ -1277,16 +736,16 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
 
        src = type->c;                                                                          // Put the service type into the domain name
        len = *src;
-       if (len < 2 || len > 15)
+       if (len < 2 || len > 16)
                {
-               LogMsg("Bad service type in %#s.%##s%##s Application protocol name must be underscore plus 1-14 characters. "
+               LogMsg("Bad service type in %#s.%##s%##s Application protocol name must be underscore plus 1-15 characters. "
                        "See <http://www.dns-sd.org/ServiceTypes.html>", name->c, type->c, domain->c);
 #if APPLE_OSX_mDNSResponder
                ConvertDomainNameToCString(type, typeBuf);
                mDNSASLLog(mDNSNULL, "serviceType.nameTooLong", "noop", typeBuf, "");
 #endif
                }
-       if (len < 2 || len >= 0x40 || (len > 15 && !SameDomainName(domain, &localdomain))) return(mDNSNULL);
+       if (len < 2 || len >= 0x40 || (len > 16 && !SameDomainName(domain, &localdomain))) return(mDNSNULL);
        if (src[1] != '_') { errormsg = "Application protocol name must begin with underscore"; goto fail; }
        for (i=2; i<=len; i++)
                {
@@ -1545,6 +1004,7 @@ mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mD
        rr->resrec.rrtype            = rrtype;
        rr->resrec.rrclass           = kDNSClass_IN;
        rr->resrec.rroriginalttl     = ttl;
+       rr->resrec.rDNSServer            = mDNSNULL;
 //     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
@@ -1586,8 +1046,6 @@ mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mD
        rr->Private           = 0;
        rr->updateid          = zeroID;
        rr->zone              = rr->resrec.name;
-       rr->UpdateServer      = zeroAddr;
-       rr->UpdatePort        = zeroIPPort;
        rr->nta               = mDNSNULL;
        rr->tcp               = mDNSNULL;
        rr->OrigRData         = 0;
@@ -1596,6 +1054,9 @@ mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mD
        rr->InFlightRDLen     = 0;
        rr->QueuedRData       = 0;
        rr->QueuedRDLen       = 0;      
+       mDNSPlatformMemZero(&rr->NATinfo, sizeof(rr->NATinfo));
+       rr->SRVChanged = mDNSfalse;
+       rr->mState = mergeState_Zero;
 
        rr->namestorage.c[0]  = 0;              // MUST be set by client before calling mDNS_Register()
        }
@@ -1612,6 +1073,7 @@ mDNSexport void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID I
        q->ExpectUnique        = (qtype != kDNSType_PTR);
        q->ForceMCast          = mDNSfalse;
        q->ReturnIntermed      = mDNSfalse;
+       q->SuppressUnusable    = mDNSfalse;
        q->QuestionCallback    = callback;
        q->QuestionContext     = context;
        }
@@ -1670,7 +1132,7 @@ mDNSexport mDNSu32 RDataHashValue(const ResourceRecord *const rr)
 
 // r1 has to be a full ResourceRecord including rrtype and rdlength
 // r2 is just a bare RDataBody, which MUST be the same rrtype and rdlength as r1
-mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2)
+mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2, DomainNameComparisonFn *samename)
        {
        const RDataBody2 *const b1 = (RDataBody2 *)r1->rdata->u.data;
        const RDataBody2 *const b2 = (RDataBody2 *)r2;
@@ -1686,26 +1148,26 @@ mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBod
                                                                                                b1->soa.retry    == b2->soa.retry              &&
                                                                                                b1->soa.expire   == b2->soa.expire             &&
                                                                                                b1->soa.min      == b2->soa.min                &&
-                                                                                               SameDomainName(&b1->soa.mname, &b2->soa.mname) &&
-                                                                                               SameDomainName(&b1->soa.rname, &b2->soa.rname));
+                                                                                               samename(&b1->soa.mname, &b2->soa.mname) &&
+                                                                                               samename(&b1->soa.rname, &b2->soa.rname));
 
                case kDNSType_MX:
                case kDNSType_AFSDB:
                case kDNSType_RT:
                case kDNSType_KX:       return(mDNSBool)(       b1->mx.preference == b2->mx.preference &&
-                                                                                               SameDomainName(&b1->mx.exchange, &b2->mx.exchange));
+                                                                                               samename(&b1->mx.exchange, &b2->mx.exchange));
 
-               case kDNSType_RP:       return(mDNSBool)(       SameDomainName(&b1->rp.mbox, &b2->rp.mbox) &&
-                                                                                               SameDomainName(&b1->rp.txt,  &b2->rp.txt));
+               case kDNSType_RP:       return(mDNSBool)(       samename(&b1->rp.mbox, &b2->rp.mbox) &&
+                                                                                               samename(&b1->rp.txt,  &b2->rp.txt));
 
                case kDNSType_PX:       return(mDNSBool)(       b1->px.preference == b2->px.preference          &&
-                                                                                               SameDomainName(&b1->px.map822,  &b2->px.map822) &&
-                                                                                               SameDomainName(&b1->px.mapx400, &b2->px.mapx400));
+                                                                                               samename(&b1->px.map822,  &b2->px.map822) &&
+                                                                                               samename(&b1->px.mapx400, &b2->px.mapx400));
 
                case kDNSType_SRV:      return(mDNSBool)(       b1->srv.priority == b2->srv.priority       &&
                                                                                                b1->srv.weight   == b2->srv.weight         &&
                                                                                                mDNSSameIPPort(b1->srv.port, b2->srv.port) &&
-                                                                                               SameDomainName(&b1->srv.target, &b2->srv.target));
+                                                                                               samename(&b1->srv.target, &b2->srv.target));
 
                case kDNSType_OPT:      return mDNSfalse;       // OPT is a pseudo-RR container structure; makes no sense to compare
 
@@ -1728,6 +1190,9 @@ mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr
                q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
                rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
 
+       // Resource record received via unicast, the DNSServer entries should match ?
+       if (!rr->InterfaceID && rr->rDNSServer != q->qDNSServer) return(mDNSfalse);
+
        // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question
        if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
 
@@ -1744,7 +1209,14 @@ mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr
                q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
                rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
 
-       // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question
+       // Resource record received via unicast, the DNSServer entries should match ?
+       if (!rr->InterfaceID && rr->rDNSServer != q->qDNSServer) return(mDNSfalse);
+
+       // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question.
+       // This also covers the case where the ResourceRecord is mDNSInterface_LocalOnly and the question is expecting a unicast
+       // DNS response. We don't want a local process to be able to create a fake LocalOnly address record for "www.bigbank.com"
+       // which would then cause other applications (e.g. Safari) to connect to the wrong address. If we decide to support this later,
+       // the restrictions need to be at least as strict as the restrictions on who can edit /etc/hosts and put fake addresses there.
        if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
 
        // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
@@ -1760,6 +1232,11 @@ mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr,
                q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
                rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
 
+       // Resource record received via unicast, the DNSServer entries should match ?
+       // Note that Auth Records are normally setup with NULL InterfaceID and
+       // both the DNSServers are assumed to be NULL in that case
+       if (!rr->InterfaceID && rr->rDNSServer != q->qDNSServer) return(mDNSfalse);
+
        // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question
        if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
 
@@ -1768,6 +1245,20 @@ mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr,
        return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
        }
 
+// This is called only when the caller knows that it is a Unicast Resource Record and it is a Unicast Question
+// and hence we don't need InterfaceID checks like above. Though this may not be a big optimization, the main
+// reason we need this is that we can't compare DNSServers between the question and the resource record because
+// the resource record may not be completely initialized e.g., mDNSCoreReceiveResponse
+mDNSexport mDNSBool UnicastResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
+       {
+       // RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
+       if (!RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
+
+       if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
+
+       return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
+       }
+
 mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate)
        {
        const RDataBody2 *const rd = (RDataBody2 *)rr->rdata->u.data;
@@ -1818,10 +1309,11 @@ mDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate
                                                        for (i=sizeof(rdataNSEC); i>0; i--) if (rd->nsec.bitmap[i-1]) break;
                                                        // For our simplified use of NSEC synthetic records:
                                                        // nextname is always the record's own name,
-                                                       // the block number is always 0,
-                                                       // the count byte is a value in the range 1-32,
-                                                       // followed by the 1-32 data bytes
-                                                       return((estimate ? 1 : DomainNameLength(rr->name)) + 2 + i);
+                                                       // and if we have at least one record type that exists,
+                                                       //  - the block number is always 0,
+                                                       //  - the count byte is a value in the range 1-32,
+                                                       //  - followed by the 1-32 data bytes
+                                                       return(mDNSu16)((estimate ? 2 : DomainNameLength(rr->name)) + (i ? (2 + i) : 0));
                                                        }
 
                default:                        debugf("Warning! Don't know how to get length of resource type %d", rr->rrtype);
@@ -2106,7 +1598,7 @@ mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNS
                                                                {
                                                                const int space = DNSOpt_Data_Space(opt);
                                                                ptr = putVal16(ptr, opt->opt);
-                                                               ptr = putVal16(ptr, space - 4);
+                                                               ptr = putVal16(ptr, (mDNSu16)space - 4);
                                                                switch (opt->opt)
                                                                        {
                                                                        case kDNSOpt_LLQ:
@@ -2151,10 +1643,13 @@ mDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNS
                                                        for (i=sizeof(rdataNSEC); i>0; i--) if (rdb->nsec.bitmap[i-1]) break;
                                                        ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
                                                        if (!ptr) return(mDNSNULL);
-                                                       if (ptr + 2 + i > limit) return(mDNSNULL);
-                                                       *ptr++ = 0;
-                                                       *ptr++ = i;
-                                                       for (j=0; j<i; j++) *ptr++ = rdb->nsec.bitmap[j];
+                                                       if (i)          // Only put a block if at least one type exists for this name
+                                                               {
+                                                               if (ptr + 2 + i > limit) return(mDNSNULL);
+                                                               *ptr++ = 0;
+                                                               *ptr++ = (mDNSu8)i;
+                                                               for (j=0; j<i; j++) *ptr++ = rdb->nsec.bitmap[j];
+                                                               }
                                                        return ptr;
                                                        }
 
@@ -2192,6 +1687,8 @@ mDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *
        ptr[5] = (mDNSu8)((ttl >> 16) &  0xFF);
        ptr[6] = (mDNSu8)((ttl >>  8) &  0xFF);
        ptr[7] = (mDNSu8)( ttl        &  0xFF);
+       // ptr[8] and ptr[9] filled in *after* we find out how much space the rdata takes
+       
        endofrdata = putRData(rdatacompressionbase, ptr+10, limit, rr);
        if (!endofrdata) { verbosedebugf("Ran out of space in PutResourceRecord for %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype)); return(mDNSNULL); }
 
@@ -2267,9 +1764,19 @@ mDNSexport mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecor
        return ptr;
        }
 
-mDNSexport mDNSu8 *putDeleteRRSet(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype)
+// for dynamic updates
+mDNSexport mDNSu8 *putDeletionRecordWithLimit(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr, mDNSu8 *limit)
+       {
+       // deletion: specify record w/ TTL 0, class NONE
+       const mDNSu16 origclass = rr->rrclass;
+       rr->rrclass = kDNSClass_NONE;
+       ptr = PutResourceRecordTTLWithLimit(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0, limit);
+       rr->rrclass = origclass;
+       return ptr;
+       }
+
+mDNSexport mDNSu8 *putDeleteRRSetWithLimit(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype, mDNSu8 *limit)
        {
-       const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
        mDNSu16 class = kDNSQClass_ANY;
        
        ptr = putDomainNameAsLabels(msg, ptr, limit, name);
@@ -2320,7 +1827,22 @@ mDNSexport mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease)
        return end;
        }
 
-mDNSexport mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end, DomainAuthInfo *authInfo)
+// for dynamic updates
+mDNSexport mDNSu8 *putUpdateLeaseWithLimit(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease, mDNSu8 *limit)
+       {
+       AuthRecord rr;
+       mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, mDNSNULL, mDNSNULL);
+       rr.resrec.rrclass    = NormalMaxDNSMessageData;
+       rr.resrec.rdlength   = sizeof(rdataOPT);        // One option in this OPT record
+       rr.resrec.rdestimate = sizeof(rdataOPT);
+       rr.resrec.rdata->u.opt[0].opt           = kDNSOpt_Lease;
+       rr.resrec.rdata->u.opt[0].u.updatelease = lease;
+       end = PutResourceRecordTTLWithLimit(msg, end, &msg->h.numAdditionals, &rr.resrec, 0, limit);
+       if (!end) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTLWithLimit"); return mDNSNULL; }
+       return end;
+       }
+
+mDNSexport mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end, DomainAuthInfo *authInfo, mDNSu8 *limit)
        {
        if (authInfo && authInfo->AutoTunnel)
                {
@@ -2337,7 +1859,7 @@ mDNSexport mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *
                mDNSPlatformMemCopy(h, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]);
                hinfo.resrec.rdlength   = len;
                hinfo.resrec.rdestimate = len;
-               newptr = PutResourceRecord(msg, end, &msg->h.numAdditionals, &hinfo.resrec);
+               newptr = PutResourceRecordTTLWithLimit(msg, end, &msg->h.numAdditionals, &hinfo.resrec, 0, limit);
                return newptr;
                }
        else
@@ -2474,13 +1996,6 @@ mDNSexport const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8
        return(ptr + pktrdlength);
        }
 
-mDNSlocal mDNSu16 getVal16(const mDNSu8 **ptr)
-       {
-       mDNSu16 val = (mDNSu16)(((mDNSu16)(*ptr)[0]) << 8 | (*ptr)[1]);
-       *ptr += sizeof(mDNSOpaque16);
-       return val;
-       }
-
 mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr,
     const mDNSu8 *end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *const largecr)
        {
@@ -2502,7 +2017,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
        rr->NextInKAList      = mDNSNULL;
        rr->TimeRcvd          = m ? m->timenow : 0;
        rr->DelayDelivery     = 0;
-       rr->NextRequiredQuery = m ? m->timenow : 0;             // Will be updated to the real value when we call SetNextCacheCheckTime()
+       rr->NextRequiredQuery = m ? m->timenow : 0;             // Will be updated to the real value when we call SetNextCacheCheckTimeForRecord()
        rr->LastUsed          = m ? m->timenow : 0;
        rr->CRActiveQuestion  = mDNSNULL;
        rr->UnansweredQueries = 0;
@@ -2516,8 +2031,11 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
        rr->NextInCFList      = mDNSNULL;
 
        rr->resrec.InterfaceID       = InterfaceID;
-       ptr = getDomainName(msg, ptr, end, &largecr->namestorage);
+       rr->resrec.rDNSServer = mDNSNULL;
+
+       ptr = getDomainName(msg, ptr, end, &largecr->namestorage);              // Will bail out correctly if ptr is NULL
        if (!ptr) { debugf("GetLargeResourceRecord: Malformed RR name"); return(mDNSNULL); }
+       rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
 
        if (ptr + 10 > end) { debugf("GetLargeResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
 
@@ -2553,7 +2071,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
                rr->resrec.rdlength = 0;
        else switch (rr->resrec.rrtype)
                {
-               case kDNSType_A:        if (pktrdlength != sizeof(mDNSv4Addr)) return(mDNSNULL);
+               case kDNSType_A:        if (pktrdlength != sizeof(mDNSv4Addr)) goto fail;
                                                        rdb->ipv4.b[0] = ptr[0];
                                                        rdb->ipv4.b[1] = ptr[1];
                                                        rdb->ipv4.b[2] = ptr[2];
@@ -2564,21 +2082,21 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
                case kDNSType_CNAME:
                case kDNSType_PTR:
                case kDNSType_DNAME:ptr = getDomainName(msg, ptr, end, &rdb->name);
-                                                       if (ptr != end) { debugf("GetLargeResourceRecord: Malformed CNAME/PTR RDATA name"); return(mDNSNULL); }
+                                                       if (ptr != end) { debugf("GetLargeResourceRecord: Malformed CNAME/PTR RDATA name"); goto fail; }
                                                        //debugf("%##s PTR %##s rdlen %d", rr->resrec.name.c, rdb->name.c, pktrdlength);
                                                        break;
 
                case kDNSType_SOA:  ptr = getDomainName(msg, ptr, end, &rdb->soa.mname);
-                                                       if (!ptr)              { debugf("GetLargeResourceRecord: Malformed SOA RDATA mname"); return mDNSNULL; }
+                                                       if (!ptr)              { debugf("GetLargeResourceRecord: Malformed SOA RDATA mname"); goto fail; }
                                                        ptr = getDomainName(msg, ptr, end, &rdb->soa.rname);
-                                                       if (!ptr)              { debugf("GetLargeResourceRecord: Malformed SOA RDATA rname"); return mDNSNULL; }
-                                       if (ptr + 0x14 != end) { debugf("GetLargeResourceRecord: Malformed SOA RDATA");       return mDNSNULL; }
-                                       rdb->soa.serial  = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]);
-                                       rdb->soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]);
-                                       rdb->soa.retry   = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]);
-                                       rdb->soa.expire  = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]);
-                                       rdb->soa.min     = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]);
-                                       break;
+                                                       if (!ptr)              { debugf("GetLargeResourceRecord: Malformed SOA RDATA rname"); goto fail; }
+                                                       if (ptr + 0x14 != end) { debugf("GetLargeResourceRecord: Malformed SOA RDATA");       goto fail; }
+                                                       rdb->soa.serial  = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]);
+                                                       rdb->soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]);
+                                                       rdb->soa.retry   = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]);
+                                                       rdb->soa.expire  = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]);
+                                                       rdb->soa.min     = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]);
+                                                       break;
 
                case kDNSType_NULL:
                case kDNSType_HINFO:
@@ -2591,7 +2109,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
                                                                {
                                                                debugf("GetLargeResourceRecord: %s rdata size (%d) exceeds storage (%d)",
                                                                        DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
-                                                               return(mDNSNULL);
+                                                               goto fail;
                                                                }
                                                        rr->resrec.rdlength = pktrdlength;
                                                        mDNSPlatformMemCopy(rdb->data, ptr, pktrdlength);
@@ -2600,38 +2118,38 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
                case kDNSType_MX:
                case kDNSType_AFSDB:
                case kDNSType_RT:
-               case kDNSType_KX:       if (pktrdlength < 3) return(mDNSNULL);  // Preference + domainname
+               case kDNSType_KX:       if (pktrdlength < 3) goto fail; // Preference + domainname
                                                        rdb->mx.preference = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
                                                        ptr = getDomainName(msg, ptr+2, end, &rdb->mx.exchange);
-                                                       if (ptr != end) { debugf("GetLargeResourceRecord: Malformed MX name"); return(mDNSNULL); }
+                                                       if (ptr != end) { debugf("GetLargeResourceRecord: Malformed MX name"); goto fail; }
                                                        //debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rdb->srv.target.c, pktrdlength);
                                                        break;
 
                case kDNSType_RP:       ptr = getDomainName(msg, ptr, end, &rdb->rp.mbox);      // Domainname + domainname
-                                                       if (!ptr)       { debugf("GetLargeResourceRecord: Malformed RP mbox"); return mDNSNULL; }
+                                                       if (!ptr)       { debugf("GetLargeResourceRecord: Malformed RP mbox"); goto fail; }
                                                        ptr = getDomainName(msg, ptr, end, &rdb->rp.txt);
-                                                       if (ptr != end) { debugf("GetLargeResourceRecord: Malformed RP txt"); return mDNSNULL; }
+                                                       if (ptr != end) { debugf("GetLargeResourceRecord: Malformed RP txt"); goto fail; }
                                                        break;
 
-               case kDNSType_PX:       if (pktrdlength < 4) return(mDNSNULL);  // Preference + domainname + domainname
+               case kDNSType_PX:       if (pktrdlength < 4) goto fail; // Preference + domainname + domainname
                                                        rdb->px.preference = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
                                                        ptr = getDomainName(msg, ptr, end, &rdb->px.map822);
-                                                       if (!ptr)       { debugf("GetLargeResourceRecord: Malformed PX map822"); return mDNSNULL; }
+                                                       if (!ptr)       { debugf("GetLargeResourceRecord: Malformed PX map822"); goto fail; }
                                                        ptr = getDomainName(msg, ptr, end, &rdb->px.mapx400);
-                                                       if (ptr != end) { debugf("GetLargeResourceRecord: Malformed PX mapx400"); return mDNSNULL; }
+                                                       if (ptr != end) { debugf("GetLargeResourceRecord: Malformed PX mapx400"); goto fail; }
                                                        break;
 
-               case kDNSType_AAAA:     if (pktrdlength != sizeof(mDNSv6Addr)) return(mDNSNULL);
+               case kDNSType_AAAA:     if (pktrdlength != sizeof(mDNSv6Addr)) goto fail;
                                                        mDNSPlatformMemCopy(&rdb->ipv6, ptr, sizeof(rdb->ipv6));
                                                        break;
 
-               case kDNSType_SRV:      if (pktrdlength < 7) return(mDNSNULL);  // Priority + weight + port + domainname
+               case kDNSType_SRV:      if (pktrdlength < 7) goto fail; // Priority + weight + port + domainname
                                                        rdb->srv.priority = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
                                                        rdb->srv.weight   = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
                                                        rdb->srv.port.b[0] = ptr[4];
                                                        rdb->srv.port.b[1] = ptr[5];
                                                        ptr = getDomainName(msg, ptr+6, end, &rdb->srv.target);
-                                                       if (ptr != end) { debugf("GetLargeResourceRecord: Malformed SRV RDATA name"); return(mDNSNULL); }
+                                                       if (ptr != end) { debugf("GetLargeResourceRecord: Malformed SRV RDATA name"); goto fail; }
                                                        //debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rdb->srv.target.c, pktrdlength);
                                                        break;
 
@@ -2640,49 +2158,60 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
                                                        rr->resrec.rdlength = 0;
                                                        while (ptr < end && (mDNSu8 *)(opt+1) < &rr->resrec.rdata->u.data[MaximumRDSize])
                                                                {
-                                                               if (ptr + 4 > end) { LogMsg("GetLargeResourceRecord: OPT RDATA ptr + 4 > end"); return(mDNSNULL); }
-                                                               opt->opt    = getVal16(&ptr);
-                                                               opt->optlen = getVal16(&ptr);
-                                                               if (!ValidDNSOpt(opt)) { LogMsg("GetLargeResourceRecord: opt %d optlen %d wrong", opt->opt, opt->optlen); return(mDNSNULL); }
-                                                               if (ptr + opt->optlen > end) { LogMsg("GetLargeResourceRecord: ptr + opt->optlen > end"); return(mDNSNULL); }
-                                                               switch(opt->opt)
+                                                               const rdataOPT *const currentopt = opt;
+                                                               if (ptr + 4 > end) { LogInfo("GetLargeResourceRecord: OPT RDATA ptr + 4 > end"); goto fail; }
+                                                               opt->opt    = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
+                                                               opt->optlen = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
+                                                               ptr += 4;
+                                                               if (ptr + opt->optlen > end) { LogInfo("GetLargeResourceRecord: ptr + opt->optlen > end"); goto fail; }
+                                                               switch (opt->opt)
                                                                        {
                                                                        case kDNSOpt_LLQ:
-                                                                               opt->u.llq.vers  = getVal16(&ptr);
-                                                                               opt->u.llq.llqOp = getVal16(&ptr);
-                                                                               opt->u.llq.err   = getVal16(&ptr);
-                                                                               mDNSPlatformMemCopy(opt->u.llq.id.b, ptr, 8);
-                                                                               ptr += 8;
-                                                                               opt->u.llq.llqlease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
-                                                                               if (opt->u.llq.llqlease > 0x70000000UL / mDNSPlatformOneSecond)
-                                                                                       opt->u.llq.llqlease = 0x70000000UL / mDNSPlatformOneSecond;
-                                                                               ptr += sizeof(mDNSOpaque32);
+                                                                               if (opt->optlen == DNSOpt_LLQData_Space - 4)
+                                                                                       {
+                                                                                       opt->u.llq.vers  = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
+                                                                                       opt->u.llq.llqOp = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
+                                                                                       opt->u.llq.err   = (mDNSu16)((mDNSu16)ptr[4] <<  8 | ptr[5]);
+                                                                                       mDNSPlatformMemCopy(opt->u.llq.id.b, ptr+6, 8);
+                                                                                       opt->u.llq.llqlease = (mDNSu32) ((mDNSu32)ptr[14] << 24 | (mDNSu32)ptr[15] << 16 | (mDNSu32)ptr[16] << 8 | ptr[17]);
+                                                                                       if (opt->u.llq.llqlease > 0x70000000UL / mDNSPlatformOneSecond)
+                                                                                               opt->u.llq.llqlease = 0x70000000UL / mDNSPlatformOneSecond;
+                                                                                       opt++;
+                                                                                       }
                                                                                break;
                                                                        case kDNSOpt_Lease:
-                                                                               opt->u.updatelease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
-                                                                               if (opt->u.updatelease > 0x70000000UL / mDNSPlatformOneSecond)
-                                                                                       opt->u.updatelease = 0x70000000UL / mDNSPlatformOneSecond;
-                                                                               ptr += sizeof(mDNSs32);
+                                                                               if (opt->optlen == DNSOpt_LeaseData_Space - 4)
+                                                                                       {
+                                                                                       opt->u.updatelease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
+                                                                                       if (opt->u.updatelease > 0x70000000UL / mDNSPlatformOneSecond)
+                                                                                               opt->u.updatelease = 0x70000000UL / mDNSPlatformOneSecond;
+                                                                                       opt++;
+                                                                                       }
                                                                                break;
                                                                        case kDNSOpt_Owner:
-                                                                               opt->u.owner.vers = ptr[0];
-                                                                               opt->u.owner.seq  = ptr[1];
-                                                                               mDNSPlatformMemCopy(opt->u.owner.HMAC.b, ptr+2, 6);             // 6-byte MAC address
-                                                                               mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+2, 6);             // 6-byte MAC address
-                                                                               opt->u.owner.password = zeroEthAddr;
-                                                                               if (opt->optlen >= DNSOpt_OwnerData_ID_Wake_Space-4)
+                                                                               if (ValidOwnerLength(opt->optlen))
                                                                                        {
-                                                                                       mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+8, 6);     // 6-byte MAC address
-                                                                                       if (opt->optlen > DNSOpt_OwnerData_ID_Wake_Space-4)
-                                                                                               mDNSPlatformMemCopy(opt->u.owner.password.b, ptr+14, opt->optlen - (DNSOpt_OwnerData_ID_Wake_Space-4));
+                                                                                       opt->u.owner.vers = ptr[0];
+                                                                                       opt->u.owner.seq  = ptr[1];
+                                                                                       mDNSPlatformMemCopy(opt->u.owner.HMAC.b, ptr+2, 6);             // 6-byte MAC address
+                                                                                       mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+2, 6);             // 6-byte MAC address
+                                                                                       opt->u.owner.password = zeroEthAddr;
+                                                                                       if (opt->optlen >= DNSOpt_OwnerData_ID_Wake_Space-4)
+                                                                                               {
+                                                                                               mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+8, 6);     // 6-byte MAC address
+                                                                                               // This mDNSPlatformMemCopy is safe because the ValidOwnerLength(opt->optlen) check above
+                                                                                               // ensures that opt->optlen is no more than DNSOpt_OwnerData_ID_Wake_PW6_Space - 4
+                                                                                               if (opt->optlen > DNSOpt_OwnerData_ID_Wake_Space-4)
+                                                                                                       mDNSPlatformMemCopy(opt->u.owner.password.b, ptr+14, opt->optlen - (DNSOpt_OwnerData_ID_Wake_Space-4));
+                                                                                               }
+                                                                                       opt++;
                                                                                        }
-                                                                               ptr += opt->optlen;
                                                                                break;
                                                                        }
-                                                               opt++;  // increment pointer into rdatabody
+                                                               ptr += currentopt->optlen;
                                                                }
-                                                       rr->resrec.rdlength = (mDNSu8*)opt - rr->resrec.rdata->u.data;
-                                                       if (ptr != end) { LogMsg("GetLargeResourceRecord: Malformed OptRdata"); return(mDNSNULL); }
+                                                       rr->resrec.rdlength = (mDNSu16)((mDNSu8*)opt - rr->resrec.rdata->u.data);
+                                                       if (ptr != end) { LogInfo("GetLargeResourceRecord: Malformed OptRdata"); goto fail; }
                                                        break;
                                                        }
 
@@ -2690,13 +2219,16 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
                                                        unsigned int i, j;
                                                        domainname d;
                                                        ptr = getDomainName(msg, ptr, end, &d);         // Ignored for our simplified use of NSEC synthetic records
-                                                       if (!ptr) { debugf("GetLargeResourceRecord: Malformed NSEC nextname"); return mDNSNULL; }
-                                                       if (*ptr++ != 0) { debugf("GetLargeResourceRecord: We only handle block zero NSECs"); return mDNSNULL; }
-                                                       i = *ptr++;
-                                                       if (i < 1 || i > sizeof(rdataNSEC)) { debugf("GetLargeResourceRecord: invalid block length %d", i); return mDNSNULL; }
+                                                       if (!ptr) { LogInfo("GetLargeResourceRecord: Malformed NSEC nextname"); goto fail; }
                                                        mDNSPlatformMemZero(rdb->nsec.bitmap, sizeof(rdb->nsec.bitmap));
-                                                       for (j=0; j<i; j++) rdb->nsec.bitmap[j] = *ptr++;
-                                                       if (ptr != end) { LogMsg("GetLargeResourceRecord: Malformed NSEC"); return(mDNSNULL); }
+                                                       if (ptr < end)
+                                                               {
+                                                               if (*ptr++ != 0) { debugf("GetLargeResourceRecord: We only handle block zero NSECs"); goto fail; }
+                                                               i = *ptr++;
+                                                               if (i > sizeof(rdataNSEC)) { debugf("GetLargeResourceRecord: invalid block length %d", i); goto fail; }
+                                                               for (j=0; j<i; j++) rdb->nsec.bitmap[j] = *ptr++;
+                                                               }
+                                                       if (ptr != end) { debugf("GetLargeResourceRecord: Malformed NSEC"); goto fail; }
                                                        break;
                                                        }
 
@@ -2704,7 +2236,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
                                                                {
                                                                debugf("GetLargeResourceRecord: rdata %d (%s) size (%d) exceeds storage (%d)",
                                                                        rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
-                                                               return(mDNSNULL);
+                                                               goto fail;
                                                                }
                                                        debugf("GetLargeResourceRecord: Warning! Reading resource type %d (%s) as opaque data",
                                                                rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype));
@@ -2718,12 +2250,20 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
                                                        break;
                }
 
-       rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
        SetNewRData(&rr->resrec, mDNSNULL, 0);          // Sets rdlength, rdestimate, rdatahash for us
 
        // Success! Now fill in RecordType to show this record contains valid data
        rr->resrec.RecordType = RecordType;
        return(end);
+
+fail:
+       // If we were unable to parse the rdata in this record, we indicate that by
+       // returing a 'kDNSRecordTypePacketNegative' record with rdlength set to zero
+       rr->resrec.RecordType = kDNSRecordTypePacketNegative;
+       rr->resrec.rdlength   = 0;
+       rr->resrec.rdestimate = 0;
+       rr->resrec.rdatahash  = 0;
+       return(end);
        }
 
 mDNSexport const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
@@ -2807,7 +2347,7 @@ mDNSexport const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const
        if (ptr)
                {
                ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
-               if (ptr) return(&m->rec.r.resrec.rdata->u.opt[0]);
+               if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative) return(&m->rec.r.resrec.rdata->u.opt[0]);
                }
        return(mDNSNULL);
        }
@@ -2933,6 +2473,7 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
        mStatus status = mStatus_NoError;
        const mDNSu16 numAdditionals = msg->h.numAdditionals;
        mDNSu8 *newend;
+       mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
 
        // Zero-length message data is okay (e.g. for a DNS Update ack, where all we need is an ID and an error code
        if (end < msg->data || end - msg->data > AbsoluteMaxDNSMessageData)
@@ -2941,8 +2482,8 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
                return mStatus_BadParamErr;
                }
 
-       newend = putHINFO(m, msg, end, authInfo);
-       if (!newend) LogMsg("mDNSSendDNSMessage: putHINFO failed"); // Not fatal
+       newend = putHINFO(m, msg, end, authInfo, limit);
+       if (!newend) LogMsg("mDNSSendDNSMessage: putHINFO failed msg %p end %p, limit %p", msg->data, end, limit); // Not fatal
        else end = newend;
        
        // Put all the integer values in IETF byte-order (MSB first, LSB second)
@@ -2988,7 +2529,7 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
 #pragma mark - RR List Management & Task Management
 #endif
 
-mDNSexport void mDNS_Lock_(mDNS *const m)
+mDNSexport void mDNS_Lock_(mDNS *const m, const char * const functionname)
        {
        // MUST grab the platform lock FIRST!
        mDNSPlatformLock(m);
@@ -2997,26 +2538,26 @@ mDNSexport void mDNS_Lock_(mDNS *const m)
        // However, when we call a client callback mDNS_busy is one, and we increment mDNS_reentrancy too
        // If that client callback does mDNS API calls, mDNS_reentrancy and mDNS_busy will both be one
        // If mDNS_busy != mDNS_reentrancy that's a bad sign
-#if ForceAlerts
        if (m->mDNS_busy != m->mDNS_reentrancy)
                {
-               LogMsg("mDNS_Lock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+               LogMsg("%s: mDNS_Lock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", functionname, m->mDNS_busy, m->mDNS_reentrancy);
+#if ForceAlerts
                *(long*)0 = 0;
-               }
 #endif
+               }
 
        // If this is an initial entry into the mDNSCore code, set m->timenow
        // else, if this is a re-entrant entry into the mDNSCore code, m->timenow should already be set
        if (m->mDNS_busy == 0)
                {
                if (m->timenow)
-                       LogMsg("mDNS_Lock: m->timenow already set (%ld/%ld)", m->timenow, mDNS_TimeNow_NoLock(m));
+                       LogMsg("%s: mDNS_Lock: m->timenow already set (%ld/%ld)", functionname, m->timenow, mDNS_TimeNow_NoLock(m));
                m->timenow = mDNS_TimeNow_NoLock(m);
                if (m->timenow == 0) m->timenow = 1;
                }
        else if (m->timenow == 0)
                {
-               LogMsg("mDNS_Lock: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy);
+               LogMsg("%s: mDNS_Lock: m->mDNS_busy is %ld but m->timenow not set", functionname, m->mDNS_busy);
                m->timenow = mDNS_TimeNow_NoLock(m);
                if (m->timenow == 0) m->timenow = 1;
                }
@@ -3024,7 +2565,7 @@ mDNSexport void mDNS_Lock_(mDNS *const m)
        if (m->timenow_last - m->timenow > 0)
                {
                m->timenow_adjust += m->timenow_last - m->timenow;
-               LogMsg("mDNSPlatformRawTime went backwards by %ld ticks; setting correction factor to %ld", m->timenow_last - m->timenow, m->timenow_adjust);
+               LogMsg("%s: mDNSPlatformRawTime went backwards by %ld ticks; setting correction factor to %ld", functionname, m->timenow_last - m->timenow, m->timenow_adjust);
                m->timenow = m->timenow_last;
                }
        m->timenow_last = m->timenow;
@@ -3033,6 +2574,14 @@ mDNSexport void mDNS_Lock_(mDNS *const m)
        m->mDNS_busy++;
        }
 
+mDNSlocal AuthRecord *AnyLocalRecordReady(const mDNS *const m)
+       {
+       AuthRecord *rr;
+       for (rr = m->NewLocalRecords; rr; rr = rr->next)
+               if (LocalRecordReady(rr)) return rr;
+       return mDNSNULL;
+       }
+
 mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
        {
        mDNSs32 e = m->timenow + 0x78000000;
@@ -3042,18 +2591,22 @@ 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->NewLocalRecords && LocalRecordReady(m->NewLocalRecords)) return(m->timenow);
-       if (m->SPSProxyListChanged)                                     return(m->timenow);
+       if (m->NewLocalOnlyQuestions)                     return(m->timenow);
+       if (m->NewLocalRecords && AnyLocalRecordReady(m)) return(m->timenow);
+       if (m->SPSProxyListChanged)                       return(m->timenow);
+       if (m->LocalRemoveEvents)                         return(m->timenow);
+
 #ifndef UNICAST_DISABLED
        if (e - m->NextuDNSEvent         > 0) e = m->NextuDNSEvent;
        if (e - m->NextScheduledNATOp    > 0) e = m->NextScheduledNATOp;
+       if (m->NextSRVUpdate && e - m->NextSRVUpdate > 0) e = m->NextSRVUpdate;
 #endif
+
        if (e - m->NextCacheCheck        > 0) e = m->NextCacheCheck;
        if (e - m->NextScheduledSPS      > 0) e = m->NextScheduledSPS;
        // NextScheduledSPRetry only valid when DelaySleep not set
        if (!m->DelaySleep && m->SleepLimit && e - m->NextScheduledSPRetry > 0) e = m->NextScheduledSPRetry;
-       if (m->DelaySleep && e - m->DelaySleep           > 0) e = m->DelaySleep;
+       if (m->DelaySleep && e - m->DelaySleep > 0) e = m->DelaySleep;
 
        if (m->SuppressSending)
                {
@@ -3085,56 +2638,67 @@ mDNSexport void ShowTaskSchedulingError(mDNS *const m)
                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->NewLocalRecords)
+               {
+               AuthRecord *rr = AnyLocalRecordReady(m);
+               if (rr) LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m, rr));
+               }
+
+       if (m->SPSProxyListChanged) LogMsg("Task Scheduling Error: SPSProxyListChanged");
+       if (m->LocalRemoveEvents)   LogMsg("Task Scheduling Error: LocalRemoveEvents");
 
        if (m->timenow - m->NextScheduledEvent    >= 0)
                LogMsg("Task Scheduling Error: m->NextScheduledEvent %d",    m->timenow - m->NextScheduledEvent);
-       if (m->SuppressSending && m->timenow - m->SuppressSending >= 0)
-               LogMsg("Task Scheduling Error: m->SuppressSending %d",       m->timenow - m->SuppressSending);
-       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);
+
+#ifndef UNICAST_DISABLED
+       if (m->timenow - m->NextuDNSEvent         >= 0)
+               LogMsg("Task Scheduling Error: m->NextuDNSEvent %d",         m->timenow - m->NextuDNSEvent);
        if (m->timenow - m->NextScheduledNATOp    >= 0)
                LogMsg("Task Scheduling Error: m->NextScheduledNATOp %d",    m->timenow - m->NextScheduledNATOp);
+       if (m->NextSRVUpdate && m->timenow - m->NextSRVUpdate >= 0)
+               LogMsg("Task Scheduling Error: m->NextSRVUpdate %d",         m->timenow - m->NextSRVUpdate);
+#endif
+
+       if (m->timenow - m->NextCacheCheck        >= 0)
+               LogMsg("Task Scheduling Error: m->NextCacheCheck %d",        m->timenow - m->NextCacheCheck);
        if (m->timenow - m->NextScheduledSPS      >= 0)
                LogMsg("Task Scheduling Error: m->NextScheduledSPS %d",      m->timenow - m->NextScheduledSPS);
        if (!m->DelaySleep && m->SleepLimit && m->timenow - m->NextScheduledSPRetry >= 0)
                LogMsg("Task Scheduling Error: m->NextScheduledSPRetry %d",  m->timenow - m->NextScheduledSPRetry);
        if (m->DelaySleep && m->timenow - m->DelaySleep >= 0)
                LogMsg("Task Scheduling Error: m->DelaySleep %d",            m->timenow - m->DelaySleep);
-#ifndef UNICAST_DISABLED
-       if (m->timenow - m->NextuDNSEvent         >= 0)
-               LogMsg("Task Scheduling Error: NextuDNSEvent %d",            m->timenow - m->NextuDNSEvent);
-#endif
+
+       if (m->SuppressSending && m->timenow - m->SuppressSending >= 0)
+               LogMsg("Task Scheduling Error: m->SuppressSending %d",       m->timenow - m->SuppressSending);
+       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(m);
        }
 
-mDNSexport void mDNS_Unlock_(mDNS *const m)
+mDNSexport void mDNS_Unlock_(mDNS *const m, const char * const functionname)
        {
        // Decrement mDNS_busy
        m->mDNS_busy--;
        
        // Check for locking failures
-#if ForceAlerts
        if (m->mDNS_busy != m->mDNS_reentrancy)
                {
-               LogMsg("mDNS_Unlock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+               LogMsg("%s: mDNS_Unlock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", functionname, m->mDNS_busy, m->mDNS_reentrancy);
+#if ForceAlerts
                *(long*)0 = 0;
-               }
 #endif
+               }
 
        // If this is a final exit from the mDNSCore code, set m->NextScheduledEvent and clear m->timenow
        if (m->mDNS_busy == 0)
                {
                m->NextScheduledEvent = GetNextScheduledEvent(m);
-               if (m->timenow == 0) LogMsg("mDNS_Unlock: ERROR! m->timenow aready zero");
+               if (m->timenow == 0) LogMsg("%s: mDNS_Unlock: ERROR! m->timenow aready zero", functionname);
                m->timenow = 0;
                }
 
@@ -3311,7 +2875,7 @@ mDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt
                                                        break;
        
                                case 'p' :      F.havePrecision = F.lSize = 1;
-                                                       F.precision = 8;
+                                                       F.precision = sizeof(void*) * 2;        // 8 characters on 32-bit; 16 characters on 64-bit
                                case 'X' :      digits = "0123456789ABCDEF";
                                                        goto hexadecimal;
                                case 'x' :      digits = "0123456789abcdef";
index b097680de2609fa21145425e6d3dc9ad64216ba8..401d57102d640e098a7e6505a9276af7d2a95987 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: DNSCommon.h,v $
-svn merge: Revision 1.75  2009/07/21 23:35:01  cheshire
-<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
-Added PutRR_OS macros to put a ResourceRecord while taking into account the space needed to add an OWNER option at the end
-
-Revision 1.73  2009/04/24 00:28:05  cheshire
-<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
-Added definitions for RRTypeAnswersQuestionType/RRAssertsNonexistence/AnyTypeRecordAnswersQuestion
-
-Revision 1.72  2009/04/01 21:12:56  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-
-Revision 1.71  2009/04/01 17:50:10  mcguire
-cleanup mDNSRandom
-
-Revision 1.70  2009/03/04 00:40:12  cheshire
-Updated DNS server error codes to be more consistent with definitions at
-<http://www.iana.org/assignments/dns-parameters>
-
-Revision 1.69  2008/11/26 20:57:37  cheshire
-For consistency with other similar macros, renamed mdnsIsDigit/mdnsIsLetter/mdnsValidHostChar
-to mDNSIsDigit/mDNSIsLetter/mDNSValidHostChar
-
-Revision 1.68  2008/11/14 21:56:31  cheshire
-Moved debugging routine ShowTaskSchedulingError() from daemon.c into DNSCommon.c
-
-Revision 1.67  2008/11/13 19:05:09  cheshire
-Added definition of LocateOptRR()
-
-Revision 1.66  2008/10/22 19:56:54  cheshire
-Removed unused SameRData() macro -- it duplicates the functionality of IdenticalSameNameRecord()
-
-Revision 1.65  2008/10/20 15:39:20  cheshire
-Group "#define PutResourceRecord ..." with related definitions
-
-Revision 1.64  2008/10/08 01:03:33  cheshire
-Change GetFirstActiveInterface() so the NetworkInterfaceInfo it returns is not "const"
-
-Revision 1.63  2008/09/23 02:30:07  cheshire
-Get rid of PutResourceRecordCappedTTL()
-
-Revision 1.62  2008/09/23 02:26:09  cheshire
-Don't need to export putEmptyResourceRecord (it's only used from DNSCommon.c)
-
-Revision 1.61  2008/08/13 00:47:53  mcguire
-Handle failures when packet logging
-
-Revision 1.60  2008/07/24 20:23:03  cheshire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-
-Revision 1.59  2008/03/14 19:58:38  mcguire
-<rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
-Make sure we add the record when sending LLQ refreshes
-
-Revision 1.58  2008/03/06 21:26:10  cheshire
-Moved duplicated STRINGIFY macro from individual C files to DNSCommon.h
-
-Revision 1.57  2007/12/13 20:20:17  cheshire
-Minor efficiency tweaks -- converted IdenticalResourceRecord, IdenticalSameNameRecord, and
-SameRData from functions to macros, which allows the code to be inlined (the compiler can't
-inline a function defined in a different compilation unit) and therefore optimized better.
-
-Revision 1.56  2007/12/13 00:13:03  cheshire
-Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody
-
-Revision 1.55  2007/12/13 00:09:28  cheshire
-For completeness added MX, AFSDB, RT, KX to list of RRTYPES that are considered to have a target domainname in their rdata
-
-Revision 1.54  2007/10/05 17:56:10  cheshire
-Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
-
-Revision 1.53  2007/09/27 17:42:49  cheshire
-Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
-
-Revision 1.52  2007/09/26 00:49:46  cheshire
-Improve packet logging to show sent and received packets,
-transport protocol (UDP/TCP/TLS) and source/destination address:port
-
-Revision 1.51  2007/09/21 21:12:36  cheshire
-<rdar://problem/5498009> BTMM: Need to log updates and query packet contents
-
-Revision 1.50  2007/09/20 01:12:06  cheshire
-Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files
-
-Revision 1.49  2007/08/30 00:31:20  cheshire
-Improve "locking failure" debugging messages to show function name using __func__ macro
-
-Revision 1.48  2007/05/25 00:25:44  cheshire
-<rdar://problem/5227737> Need to enhance putRData to output all current known types
-
-Revision 1.47  2007/05/01 21:46:31  cheshire
-Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them
-
-Revision 1.46  2007/04/22 20:18:10  cheshire
-Add comment about mDNSRandom()
-
-Revision 1.45  2007/04/22 06:02:02  cheshire
-<rdar://problem/4615977> Query should immediately return failure when no server
-
-Revision 1.44  2007/03/28 01:20:05  cheshire
-<rdar://problem/4883206> Improve/create logging for secure browse
-
-Revision 1.43  2007/03/20 17:07:15  cheshire
-Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-
-Revision 1.42  2007/03/10 03:26:44  cheshire
-<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
-
-Revision 1.41  2007/01/18 23:18:17  cheshire
-Source code tidying: Delete extraneous white space
-
-Revision 1.40  2007/01/05 08:30:40  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.39  2007/01/04 21:45:20  cheshire
-Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
-to do additional lock sanity checking around callback invocations
-
-Revision 1.38  2006/12/22 20:59:49  cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.37  2006/08/14 23:24:22  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.36  2006/07/05 22:56:07  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
-
-Revision 1.35  2006/06/29 07:42:14  cheshire
-<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
-
-Revision 1.34  2006/03/18 21:47:56  cheshire
-<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-
-Revision 1.33  2006/03/10 21:51:41  cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-Split out SameRDataBody() into a separate routine so it can be called from other code
-
-*/
+ */
 
 #ifndef __DNSCOMMON_H_
 #define __DNSCOMMON_H_
@@ -258,7 +115,7 @@ extern const domainname *SkipLeadingLabels(const domainname *d, int skip);
 extern mDNSu32 TruncateUTF8ToLength(mDNSu8 *string, mDNSu32 length, mDNSu32 max);
 extern mDNSBool LabelContainsSuffix(const domainlabel *const name, const mDNSBool RichText);
 extern mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText);
-extern void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText);
+extern void AppendLabelSuffix(domainlabel *const name, mDNSu32 val, const mDNSBool RichText);
 #define ValidateDomainName(N) (DomainNameLength(N) <= MAX_DOMAIN_NAME)
 
 // ***************************************************************************
@@ -287,7 +144,7 @@ extern void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText)
        (r1)->namehash  == (r2)->namehash    && \
        (r1)->rdlength  == (r2)->rdlength    && \
        (r1)->rdatahash == (r2)->rdatahash   && \
-       SameRDataBody((r1), &(r2)->rdata->u) && \
+       SameRDataBody((r1), &(r2)->rdata->u, SameDomainName) && \
        SameDomainName((r1)->name, (r2)->name))
 
 #define IdenticalSameNameRecord(r1,r2) ( \
@@ -295,18 +152,19 @@ extern void AppendLabelSuffix(domainlabel *name, mDNSu32 val, mDNSBool RichText)
        (r1)->rrclass   == (r2)->rrclass     && \
        (r1)->rdlength  == (r2)->rdlength    && \
        (r1)->rdatahash == (r2)->rdatahash   && \
-       SameRDataBody((r1), &(r2)->rdata->u))
+       SameRDataBody((r1), &(r2)->rdata->u, SameDomainName))
 
 // A given RRType answers a QuestionType if RRType is CNAME, or types match, or QuestionType is ANY,
 // or the RRType is NSEC and positively asserts the nonexistence of the type being requested
-#define RRTypeAnswersQuestionType(R,T) ((R)->rrtype == kDNSType_CNAME || (R)->rrtype == (T) || (T) == kDNSQType_ANY || RRAssertsNonexistence((R),(T)))
+#define RRTypeAnswersQuestionType(R,Q) ((R)->rrtype == kDNSType_CNAME || (R)->rrtype == (Q) || (Q) == kDNSQType_ANY || RRAssertsNonexistence((R),(Q)))
 #define RRAssertsNonexistence(R,T) ((R)->rrtype == kDNSType_NSEC && (T) < kDNSQType_ANY && !((R)->rdata->u.nsec.bitmap[(T)>>3] & (128 >> ((T)&7))))
 
 extern mDNSu32 RDataHashValue(const ResourceRecord *const rr);
-extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2);
+extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2, DomainNameComparisonFn *samename);
 extern mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
 extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
 extern mDNSBool AnyTypeRecordAnswersQuestion (const ResourceRecord *const rr, const DNSQuestion *const q);
+extern mDNSBool UnicastResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
 extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate);
 extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd);
 
@@ -315,7 +173,7 @@ extern mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, cons
        ((RR)->rrtype == kDNSType_MX || (RR)->rrtype == kDNSType_AFSDB || (RR)->rrtype == kDNSType_RT  || (RR)->rrtype == kDNSType_KX   ) ? &(RR)->rdata->u.mx.exchange : \
        ((RR)->rrtype == kDNSType_SRV                                  ) ? &(RR)->rdata->u.srv.target : mDNSNULL )
 
-#define LocalRecordReady(X) ((X)->resrec.RecordType != kDNSRecordTypeUnique && (X)->resrec.RecordType != kDNSRecordTypeDeregistering)
+#define LocalRecordReady(X) ((X)->resrec.RecordType != kDNSRecordTypeUnique)
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -352,13 +210,15 @@ extern mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr,
 
 extern mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass);
 extern mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, const domainname *zone, mDNSOpaque16 zoneClass);
-extern mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *end);
+extern mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *const msg, mDNSu8 *const ptr, mDNSu8 *const end);
 extern mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr);
-extern mDNSu8 *putDeleteRRSet(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype);
+extern mDNSu8 *putDeletionRecordWithLimit(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr, mDNSu8 *limit);
+extern mDNSu8 *putDeleteRRSetWithLimit(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype, mDNSu8 *limit);
 extern mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name);
 extern mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease);
+extern mDNSu8 *putUpdateLeaseWithLimit(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease, mDNSu8 *limit);
 
-extern mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end, DomainAuthInfo *authInfo);
+extern mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *ptr, DomainAuthInfo *authInfo, mDNSu8 *limit);
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -374,7 +234,7 @@ extern const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *pt
        domainname *const name);
 extern const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end);
 extern const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage * const msg, const mDNSu8 *ptr,
-    const mDNSu8 * end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *largecr);
+    const mDNSu8 * end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *const largecr);
 extern const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end);
 extern const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID,
        DNSQuestion *question);
@@ -404,20 +264,16 @@ extern mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *
 #endif
 
 extern void ShowTaskSchedulingError(mDNS *const m);
-extern void mDNS_Lock_(mDNS *const m);
-extern void mDNS_Unlock_(mDNS *const m);
+extern void mDNS_Lock_(mDNS *const m, const char * const functionname);
+extern void mDNS_Unlock_(mDNS *const m, const char * const functionname);
 
 #if defined(_WIN32)
  #define __func__ __FUNCTION__
 #endif
 
-#define mDNS_Lock(X) do { \
-       if ((X)->mDNS_busy != (X)->mDNS_reentrancy) LogMsg("%s: mDNS_Lock locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, (X)->mDNS_busy, (X)->mDNS_reentrancy); \
-       mDNS_Lock_(X); } while (0)
+#define mDNS_Lock(X) mDNS_Lock_((X), __func__)
 
-#define mDNS_Unlock(X) do { mDNS_Unlock_(X); \
-       if ((X)->mDNS_busy != (X)->mDNS_reentrancy) LogMsg("%s: mDNS_Unlock locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, (X)->mDNS_busy, (X)->mDNS_reentrancy); \
-       } while (0)
+#define mDNS_Unlock(X) mDNS_Unlock_((X), __func__)
 
 #define mDNS_DropLockBeforeCallback() do { m->mDNS_reentrancy++; \
        if (m->mDNS_busy != m->mDNS_reentrancy) LogMsg("%s: Locking Failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", __func__, m->mDNS_busy, m->mDNS_reentrancy); \
index d83e6355d648a98953f204b28618b5d15207ca41..d3d0a5cdf7cfeef9776b518a5cc202e4cacb90c0 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: DNSDigest.c,v $
-Revision 1.26  2008/10/10 23:21:51  mcguire
-fixed typo in original MD5 source reference
-
-Revision 1.25  2007/12/17 23:48:29  cheshire
-DNSDigest_SignMessage doesn't need to return a result -- it already updates the 'end' parameter
-
-Revision 1.24  2007/11/30 23:03:51  cheshire
-Fixes for EFI: Use "mDNSPlatformMemCopy" instead of assuming existence of "memcpy"
-
-Revision 1.23  2007/09/21 21:12:36  cheshire
-DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter
-
-Revision 1.22  2007/04/22 06:02:02  cheshire
-<rdar://problem/4615977> Query should immediately return failure when no server
-
-Revision 1.21  2007/03/22 18:31:48  cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.20  2006/12/22 20:59:49  cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.19  2006/12/21 00:06:07  cheshire
-Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us
-
-Revision 1.18  2006/12/19 22:41:21  cheshire
-Fix compiler warnings
-
-Revision 1.17  2006/08/14 23:24:22  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.16  2006/07/05 23:05:15  cheshire
-<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-Add DNSDigest_VerifyMessage() function
-
-Revision 1.15  2006/06/20 04:12:30  cheshire
-<rdar://problem/4490961> DNS Update broken
-
-Revision 1.14  2006/02/25 23:12:07  cheshire
-<rdar://problem/4427969> Fix to avoid code generation warning/error on FreeBSD 7
-
-Revision 1.13  2004/12/16 20:12:59  cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.12  2004/12/03 07:20:50  ksekar
-<rdar://problem/3674208> Wide-Area: Registration of large TXT record fails
-
-Revision 1.11  2004/12/02 01:10:27  cheshire
-Fix to compile cleanly on 64-bit x86
-
-Revision 1.10  2004/11/01 20:36:04  ksekar
-<rdar://problem/3802395> mDNSResponder should not receive Keychain Notifications
-
-Revision 1.9  2004/10/26 09:00:12  cheshire
-Save a few bytes by creating HMAC_MD5_AlgName as a C string instead of a 256-byte object
-
-Revision 1.8  2004/09/17 01:08:48  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.7  2004/08/15 18:36:38  cheshire
-Don't use strcpy() and strlen() on "struct domainname" objects;
-use AssignDomainName() and DomainNameLength() instead
-(A "struct domainname" is a collection of packed pascal strings, not a C string.)
-
-Revision 1.6  2004/06/02 00:17:46  ksekar
-Referenced original OpenSSL license headers in source file description.
-
-Revision 1.5  2004/05/20 18:37:37  cheshire
-Fix compiler warnings
-
-Revision 1.4  2004/04/22 20:28:20  cheshire
-Use existing facility of PutResourceRecordTTL() to update count field for us
-
-Revision 1.3  2004/04/22 03:05:28  cheshire
-kDNSClass_ANY should be kDNSQClass_ANY
-
-Revision 1.2  2004/04/15 00:51:28  bradley
-Minor tweaks for Windows and C++ builds. Added casts for signed/unsigned integers and 64-bit pointers.
-Prefix some functions with mDNS to avoid conflicts. Disable benign warnings on Microsoft compilers.
-
-Revision 1.1  2004/04/14 23:09:28  ksekar
-Support for TSIG signed dynamic updates.
-
-
-
-*/
+ */
 
 
 #ifdef __cplusplus
@@ -524,12 +432,17 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num);
    *
    *                                   <appro@fy.chalmers.se>
    */
+  /*
+   * LLVM is more strict about compatibility of types between input & output constraints,
+   * but we want these to be rotations of 32 bits, not 64, so we explicitly drop the
+   * most significant bytes by casting to an unsigned int.
+   */
 #  if defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__)
 #   define ROTATE(a,n) ({ register unsigned int ret;   \
                                asm (                   \
                                "roll %1,%0"            \
                                : "=r"(ret)             \
-                               : "I"(n), "0"(a)        \
+                               : "I"(n), "0"((unsigned int)a)  \
                                : "cc");                \
                           ret;                         \
                        })
index 8bf8a3278064e69a9177685e155c5720061bcd6d..3b69ecc49a1daaf14d8cc9081738500b4ad7eccc 100755 (executable)
  * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
  * understand why variable y is not of type "char*" just proves the point that poor code
  * layout leads people to unfortunate misunderstandings about how the C language really works.)
-
-    Change History (most recent first):
-
-$Log: mDNS.c,v $
-Revision 1.977  2009/07/23 23:30:01  cheshire
-<rdar://problem/7086623> Sleep Proxy: Ten-second maintenance wake not long enough to reliably get network connectivity
-
-Revision 1.976  2009/07/23 09:15:06  cheshire
-<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
-Fixed silly mistake in checkin 1.974 that broke SendResponses
-
-Revision 1.975  2009/07/21 23:46:19  cheshire
-Improved "DNS Message too short" syslog debugging message
-
-Revision 1.974  2009/07/21 23:41:05  cheshire
-<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
-Fixed silly mistake in checkin 1.974 that broke SendResponses
-
-svn merge: Revision 1.974  2009/07/21 23:41:05  cheshire
-<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
-Another refinement: When building a response packet, if we're going to add an OWNER option at the end,
-reserve enough bytes to ensure that we'll be able to do that
-
-svn merge: Revision 1.973  2009/07/16 00:34:18  cheshire
-<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
-Additional refinement: If we didn't register with a Sleep Proxy when going to sleep,
-we don't need to include our OWNER option in our packets when we re-awaken
-
-svn merge: Revision 1.972  2009/07/16 00:12:23  cheshire
-<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
-Additional fixes: Only add and send OWNER option if we were already going to send a non-empty packet anyway
-
-svn merge: Revision 1.971  2009/07/15 23:35:40  cheshire
-<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
-
-Revision 1.970.2.1  2009/07/23 23:36:04  cheshire
-<rdar://problem/7086623> Sleep Proxy: Ten-second maintenance wake not long enough to reliably get network connectivity
-
-Revision 1.970  2009/07/11 01:59:27  cheshire
-<rdar://problem/6613674> Sleep Proxy: Add support for using sleep proxy in local network interface hardware
-When going to sleep, try calling ActivateLocalProxy before registering with remote sleep proxy
-
-Revision 1.969  2009/06/30 21:18:19  cheshire
-<rdar://problem/7020041> Plugging and unplugging the power cable shouldn't cause a network change event
-Additional fixes:
-1. Made mDNS_ActivateNetWake_internal and mDNS_DeactivateNetWake_internal more defensive against bad parameters
-2. mDNS_DeactivateNetWake_internal also needs to stop any outstanding Sleep Proxy resolve operations
-
-Revision 1.968  2009/06/29 23:51:09  cheshire
-<rdar://problem/6690034> Can't bind to Active Directory
-
-Revision 1.967  2009/06/27 00:25:27  cheshire
-<rdar://problem/6959273> mDNSResponder taking up 13% CPU with 400 KBps incoming bonjour requests
-Removed overly-complicate and ineffective multi-packet known-answer snooping code
-(Bracketed it with "#if ENABLE_MULTI_PACKET_QUERY_SNOOPING" for now; will delete actual code later)
-
-Revision 1.966  2009/06/26 01:55:55  cheshire
-<rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
-Additional refinements -- except for the case of explicit queries for record types we don't have (for names we own),
-add additional NSEC records only when there's space to do that without having to generate an additional packet
-
-Revision 1.965  2009/06/24 22:14:21  cheshire
-<rdar://problem/6911445> Plugging and unplugging the power cable shouldn't cause a network change event
-
-Revision 1.964  2009/06/03 23:07:13  cheshire
-<rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
-Large records were not being added in cases where an NSEC record was also required
-
-Revision 1.963  2009/05/28 00:39:19  cheshire
-<rdar://problem/6926465> Sleep is delayed by 10 seconds if BTMM is on
-After receiving confirmation of wide-area record deletion, need to schedule another evaluation of whether we're ready to sleep yet
-
-Revision 1.962  2009/05/19 23:40:37  cheshire
-<rdar://problem/6903507> Sleep Proxy: Retransmission logic not working reliably on quiet networks
-Added m->NextScheduledSPRetry timer for scheduling Sleep Proxy registration retries
-
-Revision 1.961  2009/05/19 23:00:43  cheshire
-Improved comments and debugging messages
-
-Revision 1.960  2009/05/13 17:25:33  mkrochma
-<rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
-Sleep proxy client should only look for services being advertised via Multicast
-
-Revision 1.959  2009/05/12 23:10:31  cheshire
-<rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
-Make new routine mDNSCoreHaveAdvertisedServices so daemon.c can tell whether it needs to schedule a maintenance wake
-
-Revision 1.958  2009/05/12 19:19:20  cheshire
-<rdar://problem/6879925> Sleep Proxy delays sleep by ten seconds when logged in to VPN
-
-Revision 1.957  2009/05/07 23:56:25  cheshire
-<rdar://problem/6601427> Retransmit and retry Sleep Proxy Server requests
-To get negative answers for our AAAA query we need to set the ReturnIntermed flag on the NetWakeResolve question
-
-Revision 1.956  2009/05/07 23:46:27  cheshire
-<rdar://problem/6601427> Retransmit and retry Sleep Proxy Server requests
-
-Revision 1.955  2009/05/07 23:40:54  cheshire
-Minor code rearrangement in preparation for upcoming changes
-
-Revision 1.954  2009/05/01 21:28:34  cheshire
-<rdar://problem/6721680> AppleConnectAgent's reachability checks delay sleep by 30 seconds
-No longer suspend network operations after we've acknowledged that the machine is going to sleep,
-because other software may not have yet acknowledged the sleep event, and may be still trying
-to do unicast DNS queries or other Bonjour operations.
-
-Revision 1.953  2009/05/01 19:17:35  cheshire
-<rdar://problem/6501561> Sleep Proxy: Reduce the frequency of maintenance wakes: ODD, fans, power
-
-Revision 1.952  2009/05/01 19:16:45  mcguire
-<rdar://problem/6846322> Crash: mDNS_vsnprintf + 1844
-
-Revision 1.951  2009/04/28 23:48:19  jessic2
-<rdar://problem/6830541> regservice_callback: instance->request is NULL 0
-
-Revision 1.950  2009/04/25 01:17:10  mcguire
-Fix spurious TCP connect failures uncovered by <rdar://problem/6729406> PPP doesn't automatically reconnect on wake from sleep
-
-Revision 1.949  2009/04/25 01:11:02  mcguire
-Refactor: create separate function: RestartRecordGetZoneData
-
-Revision 1.948  2009/04/24 21:25:16  cheshire
-<rdar://problem/6601002> Special case Net Assistant port so Apple Remote Desktop doesn't wake up every machine on the network
-
-Revision 1.947  2009/04/24 19:41:12  mcguire
-<rdar://problem/6791775> 4 second delay in DNS response
-
-Revision 1.946  2009/04/24 19:28:39  mcguire
-<rdar://problem/6791775> 4 second delay in DNS response
-
-Revision 1.945  2009/04/24 00:30:30  cheshire
-<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
-Added code to generate and process NSEC records
-
-Revision 1.944  2009/04/23 22:06:29  cheshire
-Added CacheRecord and InterfaceID parameters to MakeNegativeCacheRecord, in preparation for:
-<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
-
-Revision 1.943  2009/04/22 01:19:56  jessic2
-<rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32
-
-Revision 1.942  2009/04/21 02:13:29  cheshire
-<rdar://problem/5270176> Local hostname changed even though there really isn't a name conflict
-Made code less susceptible to being tricked by stale packets echoed back from the network.
-
-Revision 1.941  2009/04/15 22:22:23  mcguire
-<rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
-Additional fix: protect against deref of NULL
-
-Revision 1.940  2009/04/15 20:42:51  mcguire
-<rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
-
-Revision 1.939  2009/04/11 00:19:32  jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.938  2009/04/06 23:44:57  cheshire
-<rdar://problem/6757838> mDNSResponder thrashing kernel lock in the UDP close path, hurting SPECweb performance
-
-Revision 1.937  2009/04/04 00:14:49  mcguire
-fix logging in BeginSleepProcessing
-
-Revision 1.936  2009/04/04 00:10:59  mcguire
-don't ignore m->SystemWakeOnLANEnabled when going to sleep
-
-Revision 1.935  2009/04/01 17:50:11  mcguire
-cleanup mDNSRandom
-
-Revision 1.934  2009/03/27 17:17:58  cheshire
-Improved "Ignoring suspect uDNS response" debugging message
-
-Revision 1.933  2009/03/21 02:40:21  cheshire
-<rdar://problem/6704514> uDNS: Need to create negative cache entries for "local" SOA
-
-Revision 1.932  2009/03/20 23:53:03  jessic2
-<rdar://problem/6646228> SIGHUP should restart all in-progress queries
-
-Revision 1.931  2009/03/18 19:08:15  cheshire
-Show old/new sleep sequence numbers in logical order
-
-Revision 1.930  2009/03/17 23:40:45  cheshire
-For now only try the highest-ranked Sleep Proxy; fixed come compiler warnings
-
-Revision 1.929  2009/03/17 21:55:56  cheshire
-Fixed mistake in logic for decided when we're ready to go to sleep
-
-Revision 1.928  2009/03/17 19:48:12  cheshire
-<rdar://problem/6688927> Don't cache negative unicast answers for Multicast DNS names
-
-Revision 1.927  2009/03/17 01:22:56  cheshire
-<rdar://problem/6601427> Sleep Proxy: Retransmit and retry Sleep Proxy Server requests
-Initial support for resolving up to three Sleep Proxies in parallel
-
-Revision 1.926  2009/03/17 01:05:07  mcguire
-<rdar://problem/6657640> Reachability fixes on DNS config change
-
-Revision 1.925  2009/03/13 01:35:36  mcguire
-<rdar://problem/6657640> Reachability fixes on DNS config change
-
-Revision 1.924  2009/03/10 23:45:20  cheshire
-Added comments explaining usage of SetSPSProxyListChanged()
-
-Revision 1.923  2009/03/09 21:53:02  cheshire
-<rdar://problem/6650479> Sleep Proxy: Need to stop proxying when it sees an ARP probe from the client
-
-Revision 1.922  2009/03/09 21:30:17  cheshire
-Improved some LogSPS messages; made RestartProbing() subroutine
-
-Revision 1.921  2009/03/06 22:53:31  cheshire
-Don't bother registering with Sleep Proxy if we have no advertised services
-
-Revision 1.920  2009/03/06 20:08:55  cheshire
-<rdar://problem/6601429> Sleep Proxy: Return error responses to clients
-
-Revision 1.919  2009/03/05 21:54:43  cheshire
-Improved "Sleep Proxy Server started / stopped" message
-
-Revision 1.918  2009/03/04 01:37:14  cheshire
-<rdar://problem/6601428> Limit maximum number of records that a Sleep Proxy Server will accept
-
-Revision 1.917  2009/03/03 23:14:25  cheshire
-Got rid of code duplication by making subroutine "SetupOwnerOpt"
-
-Revision 1.916  2009/03/03 23:04:43  cheshire
-For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC)
-
-Revision 1.915  2009/03/03 22:51:53  cheshire
-<rdar://problem/6504236> Sleep Proxy: Waking on same network but different interface will cause conflicts
-
-Revision 1.914  2009/03/03 00:46:09  cheshire
-Additional debugging information in ResolveSimultaneousProbe
-
-Revision 1.913  2009/02/27 03:08:47  cheshire
-<rdar://problem/6547720> Crash while shutting down when "local" is in the user's DNS searchlist
-
-Revision 1.912  2009/02/27 02:31:28  cheshire
-Improved "Record not found in list" debugging message
-
-Revision 1.911  2009/02/21 01:42:11  cheshire
-Updated log messages
-
-Revision 1.910  2009/02/19 01:50:53  cheshire
-Converted some LogInfo messages to LogSPS
-
-Revision 1.909  2009/02/14 00:04:59  cheshire
-Left-justify interface names
-
-Revision 1.908  2009/02/13 19:40:07  cheshire
-Improved alignment of LogSPS messages
-
-Revision 1.907  2009/02/13 18:16:05  cheshire
-Fixed some compile warnings
-
-Revision 1.906  2009/02/13 06:10:17  cheshire
-Convert LogOperation messages to LogInfo
-
-Revision 1.905  2009/02/12 20:57:24  cheshire
-Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
-
-Revision 1.904  2009/02/11 02:37:29  cheshire
-m->p->SystemWakeForNetworkAccessEnabled renamed to m->SystemWakeOnLANEnabled
-Moved code to send goodbye packets from mDNSCoreMachineSleep into BeginSleepProcessing,
-so that it happens correctly even when we delay re-sleep due to a very short wakeup.
-
-Revision 1.903  2009/02/09 23:34:31  cheshire
-Additional logging for debugging unknown packets
-
-Revision 1.902  2009/02/07 05:57:01  cheshire
-Fixed debugging log message
-
-Revision 1.901  2009/02/07 02:57:31  cheshire
-<rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
-
-Revision 1.900  2009/02/02 21:29:24  cheshire
-<rdar://problem/4786302> Implement logic to determine when to send dot-local lookups via Unicast
-If Negative response for our special Microsoft Active Directory "local SOA" check has no
-SOA record in the authority section, assume we should cache the negative result for 24 hours
-
-Revision 1.899  2009/01/31 00:37:50  cheshire
-When marking cache records for deletion in response to a uDNS response,
-make sure InterfaceID matches (i.e. it should be NULL for a uDNS cache record)
-
-Revision 1.898  2009/01/30 23:49:20  cheshire
-Exclude mDNSInterface_Unicast from "InterfaceID ... not currently found" test
-
-Revision 1.897  2009/01/30 22:04:49  cheshire
-Workaround to reduce load on root name servers when caching the SOA record for "."
-
-Revision 1.896  2009/01/30 22:00:05  cheshire
-Made mDNS_StartQuery_internal pay attention to mDNSInterface_Unicast
-
-Revision 1.895  2009/01/30 17:46:39  cheshire
-Improved debugging messages for working out why spurious name conflicts are happening
-
-Revision 1.894  2009/01/30 00:22:09  cheshire
-<rdar://problem/6540743> No announcement after probing & no conflict notice
-
-Revision 1.893  2009/01/29 22:27:03  mcguire
-<rdar://problem/6407429> Cleanup: Logs about Unknown DNS packet type 5450
-
-Revision 1.892  2009/01/24 01:38:23  cheshire
-Fixed error in logic for targeted queries
-
-Revision 1.891  2009/01/22 02:14:25  cheshire
-<rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
-
-Revision 1.890  2009/01/22 00:45:02  cheshire
-Improved SPS debugging log messages; we are eligible to start answering ARP requests
-after we send our first announcement, not after we send our last probe
-
-Revision 1.889  2009/01/21 03:43:56  mcguire
-<rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore
-
-Revision 1.888  2009/01/20 00:27:43  mcguire
-<rdar://problem/6305725> when removing a uDNS record, if a dup exists, copy information to it
-
-Revision 1.887  2009/01/17 05:14:37  cheshire
-Convert SendQueries Probe messages to LogSPS messages
-
-Revision 1.886  2009/01/17 03:43:09  cheshire
-Added SPSLogging switch to facilitate Sleep Proxy Server debugging
-
-Revision 1.885  2009/01/16 22:44:18  cheshire
-<rdar://problem/6402123> Sleep Proxy: Begin ARP Announcements sooner
-
-Revision 1.884  2009/01/16 21:43:52  cheshire
-Let InitializeLastAPTime compute the correct interval, instead of having it passed in as a parameter
-
-Revision 1.883  2009/01/16 21:11:18  cheshire
-When purging expired Sleep Proxy records, need to check DuplicateRecords list too
-
-Revision 1.882  2009/01/16 19:54:28  cheshire
-Use symbols "SleepProxyServiceType" and "localdomain" instead of literal strings
-
-Revision 1.881  2009/01/14 01:38:38  mcguire
-<rdar://problem/6492710> Write out DynamicStore per-interface SleepProxyServer info
-
-Revision 1.880  2009/01/10 01:51:19  cheshire
-q->CurrentAnswers not being incremented/decremented when answering a question with a local AuthRecord
-
-Revision 1.879  2009/01/10 01:43:52  cheshire
-Changed misleading function name 'AnsweredLOQ' to more informative 'AnsweredLocalQ'
-
-Revision 1.878  2009/01/10 01:38:10  cheshire
-Changed misleading function name 'AnswerLocalOnlyQuestionWithResourceRecord' to more informative 'AnswerLocalQuestionWithLocalAuthRecord'
-
-Revision 1.877  2009/01/10 01:36:08  cheshire
-Changed misleading function name 'AnswerLocalOnlyQuestions' to more informative 'AnswerAllLocalQuestionsWithLocalAuthRecord'
-
-Revision 1.876  2009/01/09 22:56:06  cheshire
-Don't touch rr after calling mDNS_Deregister_internal -- the memory may have been free'd
-
-Revision 1.875  2009/01/09 22:54:46  cheshire
-When tranferring record from DuplicateRecords list to ResourceRecords list,
-need to copy across state of 'Answered Local-Only-Questions' flag
-
-Revision 1.874  2009/01/07 23:07:24  cheshire
-<rdar://problem/6479416> SPS Client not canceling outstanding resolve call before sleeping
-
-Revision 1.873  2008/12/17 00:18:59  mkrochma
-Change some LogMsg to LogOperation before submitting
-
-Revision 1.872  2008/12/12 01:30:40  cheshire
-Update platform-layer BPF filters when we add or remove AddressProxy records
-
-Revision 1.871  2008/12/10 02:25:31  cheshire
-Minor fixes to use of LogClientOperations symbol
-
-Revision 1.870  2008/12/10 02:11:41  cheshire
-ARMv5 compiler doesn't like uncommented stuff after #endif
-
-Revision 1.869  2008/12/05 02:35:24  mcguire
-<rdar://problem/6107390> Write to the DynamicStore when a Sleep Proxy server is available on the network
-
-Revision 1.868  2008/12/04 21:08:51  mcguire
-<rdar://problem/6116863> mDNS: Provide mechanism to disable Multicast advertisements
-
-Revision 1.867  2008/11/26 21:19:36  cheshire
-<rdar://problem/6374334> Sleeping Server should choose the best Sleep Proxy by using advertised metrics
-
-Revision 1.866  2008/11/26 20:32:46  cheshire
-<rdar://problem/6374328> Sleep Proxy: Advertise BSP metrics in service name
-Update advertised name when Sleep Proxy "intent" metric changes
-
-Revision 1.865  2008/11/26 19:49:25  cheshire
-Record originally-requested port in sr->NATinfo.IntPort
-
-Revision 1.864  2008/11/26 19:02:37  cheshire
-Don't answer ARP Probes from owner machine as it wakes up and rejoins the network
-
-Revision 1.863  2008/11/26 03:59:03  cheshire
-Wait 30 seconds before starting ARP Announcements
-
-Revision 1.862  2008/11/25 23:43:07  cheshire
-<rdar://problem/5745355> Crashes at ServiceRegistrationGotZoneData + 397
-Made code more defensive to guard against ServiceRegistrationGotZoneData being called with invalid ServiceRecordSet object
-
-Revision 1.861  2008/11/25 22:46:30  cheshire
-For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta"
-
-Revision 1.860  2008/11/25 05:07:15  cheshire
-<rdar://problem/6374328> Advertise Sleep Proxy metrics in service name
-
-Revision 1.859  2008/11/20 02:07:56  cheshire
-<rdar://problem/6387470> Refresh our NAT mappings on wake from sleep
-
-Revision 1.858  2008/11/20 01:38:36  cheshire
-For consistency with other parts of the code, changed code to only check
-that the first 4 bytes of MAC address are zero, not the whole 6 bytes.
-
-Revision 1.857  2008/11/14 22:55:18  cheshire
-Fixed log messages
-
-Revision 1.856  2008/11/14 21:08:28  cheshire
-Only put owner option in query packet if we have a non-zero MAC address to put
-Only process owner options in received query packets if the MAC address in the option is non-zero
-
-Revision 1.855  2008/11/14 02:29:54  cheshire
-If Sleep Proxy client fails to renew proxy records before they expire, remove them from our m->ResourceRecords list
-
-Revision 1.854  2008/11/14 00:00:53  cheshire
-After client machine wakes up, Sleep Proxy machine need to remove any records
-it was temporarily holding as proxy for that client
-
-Revision 1.853  2008/11/13 19:07:30  cheshire
-Added code to put OPT record, containing owner and lease lifetime, into SPS registration packet
-
-Revision 1.852  2008/11/12 23:23:11  cheshire
-Before waking a host, check to see if it has an SRV record advertising
-a service on the port in question, and if not, don't bother waking it.
-
-Revision 1.851  2008/11/12 01:54:15  cheshire
-<rdar://problem/6338021> Add domain back to end of _services._dns-sd._udp PTR records
-It turns out it is beneficial to have the domain on the end, because it allows better name compression
-
-Revision 1.850  2008/11/11 01:56:57  cheshire
-Improved name conflict log messages
-
-Revision 1.849  2008/11/06 23:50:43  cheshire
-Allow plain (non-SYN) ssh data packets to wake sleeping host
-
-Revision 1.848  2008/11/05 02:40:28  mkrochma
-Change mDNS_SetFQDN syslog mesage to debugf
-
-Revision 1.847  2008/11/04 23:06:50  cheshire
-Split RDataBody union definition into RDataBody and RDataBody2, and removed
-SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord
-
-Revision 1.846  2008/11/04 22:21:44  cheshire
-Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord
-
-Revision 1.845  2008/11/03 23:52:05  cheshire
-Improved ARP debugging messages to differentiate ARP Announcements from Requests
-
-Revision 1.844  2008/10/31 23:43:51  cheshire
-Fixed compile error in Posix build
-
-Revision 1.843  2008/10/31 22:55:04  cheshire
-Initial support for structured SPS names
-
-Revision 1.842  2008/10/30 00:12:07  cheshire
-Fixed spin when PutSPSRec fails to put a record because it's too big to fit
-
-Revision 1.841  2008/10/29 23:23:38  cheshire
-Refined cache size reporting to go in steps of 1000 when number is above 1000
-
-Revision 1.840  2008/10/29 21:34:10  cheshire
-Removed some old debugging messages
-
-Revision 1.839  2008/10/29 21:31:32  cheshire
-Five seconds not always enough time for machine to go to sleep -- increased to ten seconds
-
-Revision 1.838  2008/10/28 18:30:37  cheshire
-Added debugging message in mDNSCoreReceiveRawPacket
-
-Revision 1.837  2008/10/24 23:58:05  cheshire
-Wake up for Back to My Mac IPSEC packets, except NAT keepalive packets
-
-Revision 1.836  2008/10/24 23:18:18  cheshire
-If we have a Sleep Proxy Server, don't remove service registrations from the DNS server
-
-Revision 1.835  2008/10/24 23:07:59  cheshire
-Wake SPS client if we receive conflicting mDNS respoonse (record with same name as one of our unique records, but different rdata)
-
-Revision 1.834  2008/10/24 23:03:24  cheshire
-Wake SPS client if we receive a conflicting ARP (some other machine claiming to own that IP address)
-
-Revision 1.833  2008/10/24 23:01:26  cheshire
-To reduce spurious wakeups for now, we'll only wake for incoming TCP SYN packets
-
-Revision 1.832  2008/10/24 22:58:24  cheshire
-For now, since we don't get IPv6 ND or data packets, don't advertise AAAA records for our SPS clients
-
-Revision 1.831  2008/10/24 22:50:41  cheshire
-When waking SPS client, include interface name in syslog message
-
-Revision 1.830  2008/10/24 20:50:34  cheshire
-Use "#if USE_SEPARATE_UDNS_SERVICE_LIST" instead of "#if defined(USE_SEPARATE_UDNS_SERVICE_LIST)"
-
-Revision 1.829  2008/10/23 23:55:57  cheshire
-Fixed some missing "const" declarations
-
-Revision 1.828  2008/10/23 22:25:56  cheshire
-Renamed field "id" to more descriptive "updateid"
-
-Revision 1.827  2008/10/23 03:06:25  cheshire
-Fixed "Waking host" log message
-
-Revision 1.826  2008/10/22 23:21:30  cheshire
-Make sure we have enough bytes before reading into the transport-level header
-
-Revision 1.825  2008/10/22 22:31:53  cheshire
-Log SYN/FIN/RST bits from TCP header, and don't wake for FIN/RST
-
-Revision 1.824  2008/10/22 20:00:31  cheshire
-If we ourselves go to sleep, stop advertising sleep proxy service, then re-advertise after we wake up
-
-Revision 1.823  2008/10/22 19:55:35  cheshire
-Miscellaneous fixes; renamed FindFirstAnswerInCache to FindSPSInCache
-
-Revision 1.822  2008/10/22 01:41:39  cheshire
-Set question->ThisQInterval back to -1 after we cancel our NetWakeResolve
-
-Revision 1.821  2008/10/22 01:12:53  cheshire
-Answer ARP Requests for any IP address we're proxying for
-
-Revision 1.820  2008/10/21 01:11:11  cheshire
-Added mDNSCoreReceiveRawPacket for handling raw packets received by platform layer
-
-Revision 1.819  2008/10/20 22:16:27  cheshire
-Updated comments; increased cache shedding threshold from 3000 to 4000
-
-Revision 1.818  2008/10/16 22:01:54  cheshire
-Fix last checkin: Should be "ar->resrec.rdata->u.data", not "ar->resrec.rdata.u.data"
-
-Revision 1.817  2008/10/16 21:40:49  cheshire
-Need to set ar->resrec.rdlength correctly before calling mDNS_Register_internal()
-
-Revision 1.816  2008/10/15 23:12:36  cheshire
-On receiving SPS registration from client, broadcast ARP Announcements claiming ownership of that IP address
-
-Revision 1.815  2008/10/15 20:46:38  cheshire
-When transferring records to SPS, include Lease Option
-
-Revision 1.814  2008/10/15 19:51:27  cheshire
-Change "NOTE:" to "Note:" so that BBEdit 9 stops putting those lines into the funtion popup menu
-
-Revision 1.813  2008/10/15 00:09:23  cheshire
-When acting as Sleep Proxy Server, handle DNS Updates received from SPS clients on the network
-
-Revision 1.812  2008/10/15 00:01:40  cheshire
-When going to sleep, discover and resolve SPS, and if successful, transfer records to it
-
-Revision 1.811  2008/10/14 23:51:57  cheshire
-Created new routine GetRDLengthMem() to compute the in-memory storage requirements for particular rdata
-
-Revision 1.810  2008/10/14 21:37:55  cheshire
-Removed unnecessary m->BeSleepProxyServer variable
-
-Revision 1.809  2008/10/10 23:45:48  cheshire
-For ForceMCast records, SetTargetToHostName should use the dot-local multicast hostname,
-not a wide-area unicast hostname
-
-Revision 1.808  2008/10/09 18:59:19  cheshire
-Added NetWakeResolve code, removed unused m->SendDeregistrations and m->SendImmediateAnswers
-
-Revision 1.807  2008/10/07 15:56:58  cheshire
-Fixed "unused variable" warnings in non-debug builds
-
-Revision 1.806  2008/10/04 00:53:37  cheshire
-On interfaces that support Wake-On-LAN, browse to discover Sleep Proxy Servers
-
-Revision 1.805  2008/10/03 18:17:28  cheshire
-<rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
-Update advertised Sleep Proxy Server name if user changes computer name
-
-Revision 1.804  2008/10/03 01:26:06  mcguire
-<rdar://problem/6266145> mDNS_FinalExit failed to send goodbye for duplicate uDNS records
-Put back Duplicate Record check
-
-Revision 1.803  2008/10/02 23:38:56  mcguire
-<rdar://problem/6266145> mDNS_FinalExit failed to send goodbye for duplicate uDNS records
-
-Revision 1.802  2008/10/02 23:13:48  cheshire
-<rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
-Need to drop lock before calling "mDNSCoreBeSleepProxyServer(m, mDNSfalse);"
-
-Revision 1.801  2008/10/02 22:51:04  cheshire
-<rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
-Added mDNSCoreBeSleepProxyServer() routine to start and stop Sleep Proxy Service
-
-Revision 1.800  2008/10/02 22:13:15  cheshire
-<rdar://problem/6230680> 100ms delay on shutdown
-Additional refinement: Also need to clear m->SuppressSending
-
-Revision 1.799  2008/09/29 20:12:37  cheshire
-Rename 'AnswerLocalQuestions' to more descriptive 'AnswerLocalOnlyQuestions' and 'AnsweredLocalQ' to 'AnsweredLOQ'
-
-Revision 1.798  2008/09/26 19:53:14  cheshire
-Fixed locking error: should not call mDNS_Deregister_internal within "mDNS_DropLock" section
-
-Revision 1.797  2008/09/25 20:40:59  cheshire
-<rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
-In mDNS_SetFQDN, need to update all AutoTarget SRV records, even if m->MulticastHostname hasn't changed
-
-Revision 1.796  2008/09/25 20:17:10  cheshire
-<rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
-Added defensive code to make sure *all* records of a ServiceRecordSet have
-completed deregistering before we pass on the mStatus_MemFree message
-
-Revision 1.795  2008/09/25 00:30:11  cheshire
-<rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
-
-Revision 1.794  2008/09/24 23:48:05  cheshire
-Don't need to pass whole ServiceRecordSet reference to GetServiceTarget;
-it only needs to access the embedded SRV member of the set
-
-Revision 1.793  2008/09/23 04:11:53  cheshire
-<rdar://problem/6238774> Remove "local" from the end of _services._dns-sd._udp PTR records
-
-Revision 1.792  2008/09/23 02:30:07  cheshire
-Get rid of PutResourceRecordCappedTTL()
-
-Revision 1.791  2008/09/20 00:34:21  mcguire
-<rdar://problem/6129039> BTMM: Add support for WANPPPConnection
-
-Revision 1.790  2008/09/18 22:46:34  cheshire
-<rdar://problem/6230680> 100ms delay on shutdown
-
-Revision 1.789  2008/09/18 06:15:06  mkrochma
-<rdar://problem/6117156> Cleanup: mDNSResponder logging debugging information to console
-
-Revision 1.788  2008/09/16 21:11:41  cheshire
-<rdar://problem/6223969> mDNS: Duplicate TXT record queries being produced by iPhone Remote
-
-Revision 1.787  2008/09/05 22:53:24  cheshire
-Improve "How is rr->resrec.rroriginalttl <= SecsSinceRcvd" debugging message
-
-Revision 1.786  2008/09/05 22:23:28  cheshire
-Moved initialization of "question->LocalSocket" to more logical place
-
-Revision 1.785  2008/08/14 19:20:55  cheshire
-<rdar://problem/6143846> Negative responses over TCP incorrectly rejected
-
-Revision 1.784  2008/08/13 00:47:53  mcguire
-Handle failures when packet logging
-
-Revision 1.783  2008/07/25 07:09:51  mcguire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-
-Revision 1.782  2008/07/24 20:23:03  cheshire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-
-Revision 1.781  2008/07/18 21:37:35  mcguire
-<rdar://problem/5736845> BTMM: alternate SSDP queries between multicast & unicast
-
-Revision 1.780  2008/07/18 02:24:36  cheshire
-<rdar://problem/6041178> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response
-Additional fix: Don't want to do the ReconfirmAntecedents() stuff if q->RequestUnicast is set (that indicates
-we're still on our first or second query after an interface registration or wake from sleep).
-
-Revision 1.779  2008/07/18 01:05:23  cheshire
-<rdar://problem/6041178> Only trigger reconfirm on hostname if both A and AAAA query fail to elicit a response
-
-Revision 1.778  2008/06/26 17:24:11  mkrochma
-<rdar://problem/5450912> BTMM: Stop listening on UDP 5351 for NAT Status Announcements
-
-Revision 1.777  2008/06/19 01:20:48  mcguire
-<rdar://problem/4206534> Use all configured DNS servers
-
-Revision 1.776  2008/04/17 20:14:14  cheshire
-<rdar://problem/5870023> CurrentAnswers/LargeAnswers/UniqueAnswers counter mismatch
-
-Revision 1.775  2008/03/26 01:53:34  mcguire
-<rdar://problem/5820489> Can't resolve via uDNS when an interface is specified
-
-Revision 1.774  2008/03/17 17:46:08  mcguire
-When activating an LLQ, reset all the important state and destroy any tcp connection,
-so that everything will be restarted as if the question had just been asked.
-Also reset servPort, so that the SOA query will be re-issued.
-
-Revision 1.773  2008/03/14 22:52:36  mcguire
-<rdar://problem/5321824> write status to the DS
-Update status when any unicast LLQ is started
-
-Revision 1.772  2008/03/06 02:48:34  mcguire
-<rdar://problem/5321824> write status to the DS
-
-Revision 1.771  2008/02/26 22:04:44  cheshire
-<rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
-Additional fixes -- should not be calling uDNS_CheckCurrentQuestion on a
-question while it's still in our 'm->NewQuestions' section of the list
-
-Revision 1.770  2008/02/22 23:09:02  cheshire
-<rdar://problem/5338420> BTMM: Not processing additional records
-Refinements:
-1. Check rdatahash == namehash, to skip expensive SameDomainName check when possible
-2. Once we decide a record is acceptable, we can break out of the loop
-
-Revision 1.769  2008/02/22 00:00:19  cheshire
-<rdar://problem/5338420> BTMM: Not processing additional records
-
-Revision 1.768  2008/02/19 23:26:50  cheshire
-<rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
-
-Revision 1.767  2007/12/22 02:25:29  cheshire
-<rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
-
-Revision 1.766  2007/12/15 01:12:27  cheshire
-<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
-
-Revision 1.765  2007/12/15 00:18:51  cheshire
-Renamed question->origLease to question->ReqLease
-
-Revision 1.764  2007/12/14 00:49:53  cheshire
-Fixed crash in mDNS_StartExit -- the service deregistration loop needs to use
-the CurrentServiceRecordSet mechanism to guard against services being deleted,
-just like the record deregistration loop uses m->CurrentRecord.
-
-Revision 1.763  2007/12/13 20:20:17  cheshire
-Minor efficiency tweaks -- converted IdenticalResourceRecord, IdenticalSameNameRecord, and
-SameRData from functions to macros, which allows the code to be inlined (the compiler can't
-inline a function defined in a different compilation unit) and therefore optimized better.
-
-Revision 1.762  2007/12/13 00:13:03  cheshire
-Simplified RDataHashValue to take a single ResourceRecord pointer, instead of separate rdlength and RDataBody
-
-Revision 1.761  2007/12/13 00:03:31  cheshire
-Improved efficiency in IdenticalResourceRecord() by doing SameRData() check before SameDomainName() check
-
-Revision 1.760  2007/12/08 00:36:19  cheshire
-<rdar://problem/5636422> Updating TXT records is too slow
-Remove unnecessary delays on announcing record updates, and on processing them on reception
-
-Revision 1.759  2007/12/07 22:41:29  cheshire
-<rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
-Further refinements -- records on the DuplicateRecords list were getting missed on shutdown
-
-Revision 1.758  2007/12/07 00:45:57  cheshire
-<rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
-
-Revision 1.757  2007/12/06 00:22:27  mcguire
-<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
-
-Revision 1.756  2007/12/05 01:52:30  cheshire
-<rdar://problem/5624763> BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname
-Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to)
-
-Revision 1.755  2007/12/03 23:36:45  cheshire
-<rdar://problem/5623140> mDNSResponder unicast DNS improvements
-Need to check GetServerForName() result is non-null before dereferencing pointer
-
-Revision 1.754  2007/12/01 01:21:27  jgraessley
-<rdar://problem/5623140> mDNSResponder unicast DNS improvements
-
-Revision 1.753  2007/12/01 00:44:15  cheshire
-Fixed compile warnings, e.g. declaration of 'rr' shadows a previous local
-
-Revision 1.752  2007/11/14 01:10:51  cheshire
-Fixed LogOperation() message wording
-
-Revision 1.751  2007/10/30 23:49:41  cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-LLQ state was not being transferred properly between duplicate questions
-
-Revision 1.750  2007/10/29 23:58:52  cheshire
-<rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
-Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet
-
-Revision 1.749  2007/10/29 21:28:36  cheshire
-Change "Correcting TTL" log message to LogOperation to suppress it in customer build
-
-Revision 1.748  2007/10/29 20:02:50  cheshire
-<rdar://problem/5526813> BTMM: Wide-area records being announced via multicast
-
-Revision 1.747  2007/10/26 22:53:50  cheshire
-Made mDNS_Register_internal and mDNS_Deregister_internal use AuthRecord_uDNS macro
-instead of replicating the logic in both places
-
-Revision 1.746  2007/10/25 22:48:50  cheshire
-Added LogOperation message saying when we restart GetZoneData for record and service registrations
-
-Revision 1.745  2007/10/25 20:48:47  cheshire
-For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
-
-Revision 1.744  2007/10/25 20:06:14  cheshire
-Don't try to do SOA queries using private DNS (TLS over TCP) queries
-
-Revision 1.743  2007/10/25 00:12:46  cheshire
-<rdar://problem/5496734> BTMM: Need to retry registrations after failures
-Retrigger service registrations whenever a new network interface is added
-
-Revision 1.742  2007/10/24 22:40:06  cheshire
-Renamed: RecordRegistrationCallback          -> RecordRegistrationGotZoneData
-Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
-
-Revision 1.741  2007/10/24 00:50:29  cheshire
-<rdar://problem/5496734> BTMM: Need to retry registrations after failures
-Retrigger record registrations whenever a new network interface is added
-
-Revision 1.740  2007/10/23 00:38:03  cheshire
-When sending uDNS cache expiration query, need to increment rr->UnansweredQueries
-or code will spin sending the same cache expiration query repeatedly
-
-Revision 1.739  2007/10/22 23:46:41  cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-Need to clear question->nta pointer after calling CancelGetZoneData()
-
-Revision 1.738  2007/10/19 22:08:49  cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-Additional fixes and refinements
-
-Revision 1.737  2007/10/18 23:06:42  cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-Additional fixes and refinements
-
-Revision 1.736  2007/10/18 20:23:17  cheshire
-Moved SuspendLLQs into mDNS.c, since it's only called from one place
-
-Revision 1.735  2007/10/18 00:12:34  cheshire
-Fixed "unused variable" compiler warning
-
-Revision 1.734  2007/10/17 22:49:54  cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-
-Revision 1.733  2007/10/17 22:37:23  cheshire
-<rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
-
-Revision 1.732  2007/10/17 21:53:51  cheshire
-Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
-
-Revision 1.731  2007/10/17 18:37:50  cheshire
-<rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
-Further refinement: pre-increment m->CurrentRecord before calling mDNS_Deregister_internal()
-
-Revision 1.730  2007/10/16 21:16:07  cheshire
-<rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
-
-Revision 1.729  2007/10/05 17:56:10  cheshire
-Move CountLabels and SkipLeadingLabels to DNSCommon.c so they're callable from other files
-
-Revision 1.728  2007/10/04 23:18:14  cheshire
-<rdar://problem/5523706> mDNSResponder flooding DNS servers with unreasonable query level
-
-Revision 1.727  2007/10/04 22:51:57  cheshire
-Added debugging LogOperation message to show when we're sending cache expiration queries
-
-Revision 1.726  2007/10/03 00:14:24  cheshire
-Removed write to null to generate stack trace for SetNextQueryTime locking failure
-
-Revision 1.725  2007/10/02 21:11:08  cheshire
-<rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
-
-Revision 1.724  2007/10/02 20:10:23  cheshire
-Additional debugging checks on shutdown -- list all records we didn't send a goodbye for, not just the first one
-
-Revision 1.723  2007/10/02 19:56:54  cheshire
-<rdar://problem/5518310> Double-dispose causes crash changing Dynamic DNS hostname
-
-Revision 1.722  2007/10/01 22:59:46  cheshire
-<rdar://problem/5516303> mDNSResponder did not shut down after 20 seconds
-Need to shut down NATTraversals on exit
-
-Revision 1.721  2007/10/01 18:42:07  cheshire
-To make packet logs appear in a more intuitive order, dump received packets *before* handling them, not after
-
-Revision 1.720  2007/09/29 20:40:19  cheshire
-<rdar://problem/5513378> Crash in ReissueBlockedQuestions
-
-Revision 1.719  2007/09/27 22:23:56  cheshire
-<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
-Need to clear m->rec.r.resrec.RecordType after we've finished using m->rec
-
-Revision 1.718  2007/09/27 22:02:33  cheshire
-<rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
-
-Revision 1.717  2007/09/27 21:21:39  cheshire
-Export CompleteDeregistration so it's callable from other files
-
-Revision 1.716  2007/09/27 02:12:21  cheshire
-Updated GrantCacheExtensions degugging message to show new record lifetime
-
-Revision 1.715  2007/09/27 01:20:06  cheshire
-<rdar://problem/5500077> BTMM: Need to refresh LLQs based on lease life and not TTL of response
-
-Revision 1.714  2007/09/27 00:37:01  cheshire
-<rdar://problem/4947392> BTMM: Use SOA to determine TTL for negative answers
-
-Revision 1.713  2007/09/27 00:25:39  cheshire
-Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
-<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
-
-Revision 1.712  2007/09/26 23:16:58  cheshire
-<rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
-
-Revision 1.711  2007/09/26 22:06:02  cheshire
-<rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
-
-Revision 1.710  2007/09/26 00:49:46  cheshire
-Improve packet logging to show sent and received packets,
-transport protocol (UDP/TCP/TLS) and source/destination address:port
-
-Revision 1.709  2007/09/21 21:12:36  cheshire
-<rdar://problem/5498009> BTMM: Need to log updates and query packet contents
-
-Revision 1.708  2007/09/20 23:13:37  cheshire
-<rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
-Additional fix: If we have no DNS servers at all, then immediately purge all unicast cache records (including for LLQs)
-
-Revision 1.707  2007/09/20 02:29:37  cheshire
-<rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
-
-Revision 1.706  2007/09/20 01:13:19  cheshire
-Export CacheGroupForName so it's callable from other files
-
-Revision 1.705  2007/09/20 01:12:06  cheshire
-Moved HashSlot(X) from mDNS.c to DNSCommon.h so it's usable in other files
-
-Revision 1.704  2007/09/19 22:47:25  cheshire
-<rdar://problem/5490182> Memory corruption freeing a "no such service" service record
-
-Revision 1.703  2007/09/14 01:46:59  cheshire
-Fix Posix build (#ifdef _LEGACY_NAT_TRAVERSAL_ section included a closing curly brace it should not have)
-
-Revision 1.702  2007/09/13 22:06:46  cheshire
-<rdar://problem/5480643> Tully's Free WiFi: DNS fails
-Need to accept DNS responses where the query ID field matches, even if the source address does not
-
-Revision 1.701  2007/09/12 23:22:32  cheshire
-<rdar://problem/5476979> Only accept NAT Port Mapping packets from our default gateway
-
-Revision 1.700  2007/09/12 23:03:08  cheshire
-<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
-
-Revision 1.699  2007/09/12 22:19:28  cheshire
-<rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
-
-Revision 1.698  2007/09/12 22:13:27  cheshire
-Remove DynDNSHostNames cleanly on shutdown
-
-Revision 1.697  2007/09/12 01:44:47  cheshire
-<rdar://problem/5475938> Eliminate "Correcting TTL" syslog messages for unicast DNS records
-
-Revision 1.696  2007/09/12 01:26:08  cheshire
-Initialize LastNATReplyLocalTime to timenow, so that gateway uptime checks work more reliably
-
-Revision 1.695  2007/09/11 19:19:16  cheshire
-Correct capitalization of "uPNP" to "UPnP"
-
-Revision 1.694  2007/09/10 22:06:51  cheshire
-Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
-
-Revision 1.693  2007/09/07 22:24:36  vazquez
-<rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
-
-Revision 1.692  2007/09/07 00:12:09  cheshire
-<rdar://problem/5466010> Unicast DNS changes broke efficiency fix 3928456
-
-Revision 1.691  2007/09/05 22:25:01  vazquez
-<rdar://problem/5400521> update_record mDNSResponder leak
-
-Revision 1.690  2007/09/05 21:48:01  cheshire
-<rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
-Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code needs
-to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
-otherwise those records will expire and vanish from the cache.
-
-Revision 1.689  2007/09/05 02:29:06  cheshire
-<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
-Additional fixes to code implementing "NoAnswer" logic
-
-Revision 1.688  2007/08/31 22:56:39  cheshire
-<rdar://problem/5407080> BTMM: TTLs incorrect on cached BTMM records
-
-Revision 1.687  2007/08/31 19:53:14  cheshire
-<rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
-If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
-
-Revision 1.686  2007/08/30 00:01:56  cheshire
-Added comment about SetTargetToHostName()
-
-Revision 1.685  2007/08/29 01:19:24  cheshire
-<rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
-Set AutoTarget to Target_AutoHostAndNATMAP for non-AutoTunnel wide-area services
-
-Revision 1.684  2007/08/28 23:58:42  cheshire
-Rename HostTarget -> AutoTarget
-
-Revision 1.683  2007/08/28 23:53:21  cheshire
-Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
-
-Revision 1.682  2007/08/27 20:28:19  cheshire
-Improve "suspect uDNS response" log message
-
-Revision 1.681  2007/08/24 23:37:23  cheshire
-Added debugging message to show when ExtraResourceRecord callback gets invoked
-
-Revision 1.680  2007/08/24 00:15:19  cheshire
-Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
-
-Revision 1.679  2007/08/23 21:47:09  vazquez
-<rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
-make sure we clean up port mappings on base stations by sending a lease value of 0,
-and only send NAT-PMP packets on private networks; also save some memory by
-not using packet structs in NATTraversals.
-
-Revision 1.678  2007/08/01 16:09:13  cheshire
-Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
-
-Revision 1.677  2007/08/01 01:58:24  cheshire
-Added RecordType sanity check in mDNS_Register_internal
-
-Revision 1.676  2007/08/01 00:04:13  cheshire
-<rdar://problem/5261696> Crash in tcpKQSocketCallback
-Half-open TCP connections were not being cancelled properly
-
-Revision 1.675  2007/07/31 02:28:35  vazquez
-<rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
-
-Revision 1.674  2007/07/31 01:57:23  cheshire
-Adding code to respect TTL received in uDNS responses turned out to
-expose other problems; backing out change for now.
-
-Revision 1.673  2007/07/30 23:31:26  cheshire
-Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
-
-Revision 1.672  2007/07/28 01:25:56  cheshire
-<rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
-
-Revision 1.671  2007/07/27 22:32:54  cheshire
-When processing TTLs in uDNS responses, we'll currently impose a minimum effective TTL
-of 2 seconds, or other stuff breaks (e.g. we end up making a negative cache entry).
-
-Revision 1.670  2007/07/27 20:54:43  cheshire
-Fixed code to respect real record TTL received in uDNS responses
-
-Revision 1.669  2007/07/27 20:09:32  cheshire
-Don't need to dump out all received mDNS packets; they're easily viewed using mDNSNetMonitor
-
-Revision 1.668  2007/07/27 19:58:47  cheshire
-Use symbolic names QC_add and QC_rmv instead of mDNStrue/mDNSfalse
-
-Revision 1.667  2007/07/27 19:52:10  cheshire
-Don't increment m->rrcache_active for no-cache add events
-
-Revision 1.666  2007/07/27 19:30:39  cheshire
-Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
-to properly reflect tri-state nature of the possible responses
-
-Revision 1.665  2007/07/27 18:44:01  cheshire
-Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
-
-Revision 1.664  2007/07/27 18:38:56  cheshire
-Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
-
-Revision 1.663  2007/07/25 03:05:02  vazquez
-Fixes for:
-<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
-<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
-and a myriad of other security problems
-
-Revision 1.662  2007/07/24 20:22:46  cheshire
-Make sure all fields of main mDNS object are initialized correctly
-
-Revision 1.661  2007/07/21 00:54:45  cheshire
-<rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
-
-Revision 1.660  2007/07/20 20:00:45  cheshire
-"Legacy Browse" is better called "Automatic Browse"
-
-Revision 1.659  2007/07/20 00:54:18  cheshire
-<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-
-Revision 1.658  2007/07/18 02:28:57  cheshire
-Don't set AutoTunnel settings in uDNS_RegisterService; should be done in GetServiceTarget
-
-Revision 1.657  2007/07/18 00:57:10  cheshire
-<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
-Only need to call AddNewClientTunnel() for IPv6 addresses
-
-Revision 1.656  2007/07/16 23:54:48  cheshire
-<rdar://problem/5338850> Crash when removing or changing DNS keys
-
-Revision 1.655  2007/07/16 20:11:37  vazquez
-<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
-Init LNT stuff and handle SSDP packets
-
-Revision 1.654  2007/07/12 23:30:23  cheshire
-Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
-
-Revision 1.653  2007/07/12 02:51:27  cheshire
-<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
-
-Revision 1.652  2007/07/11 23:43:42  cheshire
-Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
-
-Revision 1.651  2007/07/11 22:44:40  cheshire
-<rdar://problem/5328801> SIGHUP should purge the cache
-
-Revision 1.650  2007/07/11 21:34:09  cheshire
-<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
-Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName/mDNS_RemoveDynDNSHostName
-
-Revision 1.649  2007/07/11 02:52:52  cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-In uDNS_RegisterService, set HostTarget for AutoTunnel services
-
-Revision 1.648  2007/07/09 23:48:12  cheshire
-Add parentheses around bitwise operation for clarity
-
-Revision 1.647  2007/07/06 21:17:55  cheshire
-Initialize m->retryGetAddr to timenow + 0x78000000;
-
-Revision 1.646  2007/07/06 18:55:49  cheshire
-Initialize m->NextScheduledNATOp
-
-Revision 1.645  2007/06/29 22:55:54  cheshire
-Move declaration of DNSServer *s; Fixed incomplete comment.
-
-Revision 1.644  2007/06/29 00:07:29  vazquez
-<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-
-Revision 1.643  2007/06/20 01:10:12  cheshire
-<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-
-Revision 1.642  2007/06/15 21:54:50  cheshire
-<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
-
-Revision 1.641  2007/05/25 00:30:24  cheshire
-When checking for duplicate questions, make sure privacy (or not) status, and long-lived (or not)
-status matches. This is particularly important when doing a private query for an SOA record,
-which will result in a call StartGetZoneData which does a non-private query for the same SOA record.
-If the latter is tagged as a duplicate of the former, then we have deadlock, and neither will complete.
-
-Revision 1.640  2007/05/25 00:25:44  cheshire
-<rdar://problem/5227737> Need to enhance putRData to output all current known types
-
-Revision 1.639  2007/05/23 00:51:33  cheshire
-Increase threshold for shedding cache records from 512 to 3000. The 512 figure was calculated when
-each cache entry took about 700 bytes; now they're only 164 bytes. Also, machines have more RAM these
-days, and there are more services being advertised using DNS-SD, so it makes sense to cache more.
-
-Revision 1.638  2007/05/23 00:43:16  cheshire
-If uDNS UDP response has TC (truncated) bit set, don't interpret it as being the entire RRSet
-
-Revision 1.637  2007/05/14 23:53:00  cheshire
-Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c
-
-Revision 1.636  2007/05/10 23:27:15  cheshire
-Update mDNS_Deregister_internal debugging messages
-
-Revision 1.635  2007/05/07 20:43:45  cheshire
-<rdar://problem/4241419> Reduce the number of queries and announcements
-
-Revision 1.634  2007/05/04 22:09:08  cheshire
-Only do "restarting exponential backoff sequence" for mDNS questions
-In mDNS_RegisterInterface, only retrigger mDNS questions
-In uDNS_SetupDNSConfig, use ActivateUnicastQuery() instead of just setting q->ThisQInterval directly
-
-Revision 1.633  2007/05/04 21:45:12  cheshire
-Get rid of unused q->RestartTime; Get rid of uDNS_Close (synonym for uDNS_Sleep)
-
-Revision 1.632  2007/05/04 20:20:50  cheshire
-<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
-Need to set srs->nta = mDNSNULL; when regState_NoTarget
-
-Revision 1.631  2007/05/04 00:39:42  cheshire
-<rdar://problem/4410011> Eliminate looping SOA lookups
-When creating a cascade of negative SOA cache entries, CacheGroup pointer cg needs to be updated
-each time round the loop to reference the right CacheGroup for each newly fabricated SOA name
-
-Revision 1.630  2007/05/03 22:40:38  cheshire
-<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
-
-Revision 1.629  2007/05/03 00:15:51  cheshire
-<rdar://problem/4410011> Eliminate looping SOA lookups
-
-Revision 1.628  2007/05/02 22:21:33  cheshire
-<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
-
-Revision 1.627  2007/04/30 19:29:13  cheshire
-Fix display of port number in "Updating DNS Server" message
-
-Revision 1.626  2007/04/30 04:21:13  cheshire
-Can't safely call AnswerLocalQuestions() from within mDNS_Deregister() -- need to defer it until mDNS_Execute time
-
-Revision 1.625  2007/04/28 01:34:21  cheshire
-Fixed crashing bug: We need to update rr->CRActiveQuestion pointers for *all* questions
-(Code was explicitly ignoring wide-area unicast questions, leading to stale pointers and crashes)
-
-Revision 1.624  2007/04/27 21:04:30  cheshire
-On network configuration change, need to call uDNS_RegisterSearchDomains
-
-Revision 1.623  2007/04/27 19:28:01  cheshire
-Any code that calls StartGetZoneData needs to keep a handle to the structure, so
-it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
--- it would start a query and then quickly cancel it, and then when
-StartGetZoneData completed, it had a dangling pointer and crashed.)
-
-Revision 1.622  2007/04/26 16:09:22  cheshire
-mDNS_StopQueryWithRemoves should ignore kDNSRecordTypePacketNegative records
-
-Revision 1.621  2007/04/26 15:43:22  cheshire
-Make sure DNSServer *s is non-null before using value in LogOperation
-
-Revision 1.620  2007/04/26 13:11:05  cheshire
-Fixed crash when logging out of VPN
-
-Revision 1.619  2007/04/26 00:35:15  cheshire
-<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
-Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
-inside the firewall may give answers where a public one gives none, and vice versa.)
-
-Revision 1.618  2007/04/25 19:26:01  cheshire
-m->NextScheduledQuery was getting set too early in SendQueries()
-Improved "SendQueries didn't send all its queries" debugging message
-
-Revision 1.617  2007/04/25 17:48:22  cheshire
-Update debugging message
-
-Revision 1.616  2007/04/25 16:38:32  cheshire
-If negative cache entry already exists, reactivate it instead of creating a new one
-
-Revision 1.615  2007/04/25 02:14:38  cheshire
-<rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
-Additional fixes to make LLQs work properly
-
-Revision 1.614  2007/04/23 21:52:45  cheshire
-<rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
-
-Revision 1.613  2007/04/23 04:58:20  cheshire
-<rdar://problem/5072548> Crash when setting extremely large TXT records
-
-Revision 1.612  2007/04/22 20:39:38  cheshire
-<rdar://problem/4633194> Add 20 to 120ms random delay to browses
-
-Revision 1.611  2007/04/22 18:16:29  cheshire
-Removed incorrect ActiveQuestion(q) check that was preventing suspended questions from getting reactivated
-
-Revision 1.610  2007/04/22 06:02:02  cheshire
-<rdar://problem/4615977> Query should immediately return failure when no server
-
-Revision 1.609  2007/04/20 21:17:24  cheshire
-For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
-
-Revision 1.608  2007/04/20 19:45:31  cheshire
-In LogClientOperations mode, dump out unknown DNS packets in their entirety
-
-Revision 1.607  2007/04/19 23:56:25  cheshire
-Don't do cache-flush processing for LLQ answers
-
-Revision 1.606  2007/04/19 22:50:53  cheshire
-<rdar://problem/4246187> Identical client queries should reference a single shared core query
-
-Revision 1.605  2007/04/19 20:06:41  cheshire
-Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
-
-Revision 1.604  2007/04/19 18:03:04  cheshire
-Add "const" declaration
-
-Revision 1.603  2007/04/06 21:00:25  cheshire
-Fix log message typo
-
-Revision 1.602  2007/04/05 22:55:35  cheshire
-<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
-
-Revision 1.601  2007/04/04 21:48:52  cheshire
-<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
-
-Revision 1.600  2007/04/04 01:31:33  cheshire
-Improve debugging message
-
-Revision 1.599  2007/04/04 00:03:26  cheshire
-<rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
-
-Revision 1.598  2007/04/03 19:43:16  cheshire
-Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
-
-Revision 1.597  2007/03/31 00:32:32  cheshire
-After skipping OPT and TSIG, clear m->rec.r.resrec.RecordType
-
-Revision 1.596  2007/03/28 20:59:26  cheshire
-<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
-
-Revision 1.595  2007/03/26 23:48:16  cheshire
-<rdar://problem/4848295> Advertise model information via Bonjour
-Refinements to reduce unnecessary transmissions of the DeviceInfo TXT record
-
-Revision 1.594  2007/03/26 23:05:05  cheshire
-<rdar://problem/5089257> Don't cache TSIG records
-
-Revision 1.593  2007/03/23 17:40:08  cheshire
-<rdar://problem/4060169> Bug when auto-renaming Computer Name after name collision
-
-Revision 1.592  2007/03/22 18:31:48  cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.591  2007/03/22 00:49:19  cheshire
-<rdar://problem/4848295> Advertise model information via Bonjour
-
-Revision 1.590  2007/03/21 23:05:59  cheshire
-Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
-
-Revision 1.589  2007/03/20 15:37:19  cheshire
-Delete unnecessary log message
-
-Revision 1.588  2007/03/20 00:24:44  cheshire
-<rdar://problem/4175213> Should deliver "name registered" callback slightly *before* announcing PTR record
-
-Revision 1.587  2007/03/16 22:10:56  cheshire
-<rdar://problem/4471307> mDNS: Query for *either* type A or AAAA should return both types
-
-Revision 1.586  2007/03/10 03:26:44  cheshire
-<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
-
-Revision 1.585  2007/03/10 02:02:58  cheshire
-<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
-Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
-
-Revision 1.584  2007/02/28 01:51:27  cheshire
-Added comment about reverse-order IP address
-
-Revision 1.583  2007/01/27 03:19:33  cheshire
-Need to initialize question->sock
-
-Revision 1.582  2007/01/25 00:40:16  cheshire
-Unified CNAME-following functionality into cache management code (which means CNAME-following
-should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
-
-Revision 1.581  2007/01/23 02:56:11  cheshire
-Store negative results in the cache, instead of generating them out of pktResponseHndlr()
-
-Revision 1.580  2007/01/19 21:17:33  cheshire
-StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
-
-Revision 1.579  2007/01/19 18:39:10  cheshire
-Fix a bunch of parameters that should have been declared "const"
-
-Revision 1.578  2007/01/10 22:51:57  cheshire
-<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
-
-Revision 1.577  2007/01/10 02:05:21  cheshire
-Delay uDNS_SetupDNSConfig() until *after* the platform layer
-has set up the interface list and security credentials
-
-Revision 1.576  2007/01/09 02:40:57  cheshire
-uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
-moved it to mDNS_Init() in mDNS.c (core code)
-
-Revision 1.575  2007/01/09 00:17:25  cheshire
-Improve "ERROR m->CurrentRecord already set" debugging messages
-
-Revision 1.574  2007/01/05 08:30:41  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.573  2007/01/05 06:34:03  cheshire
-Improve "ERROR m->CurrentQuestion already set" debugging messages
-
-Revision 1.572  2007/01/04 23:11:11  cheshire
-<rdar://problem/4720673> uDNS: Need to start caching unicast records
-When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
-
-Revision 1.571  2007/01/04 21:45:20  cheshire
-Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
-to do additional lock sanity checking around callback invocations
-
-Revision 1.570  2007/01/04 20:57:47  cheshire
-Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
-
-Revision 1.569  2007/01/04 20:27:27  cheshire
-Change a LogMsg() to debugf()
-
-Revision 1.568  2007/01/04 02:39:53  cheshire
-<rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
-
-Revision 1.567  2006/12/21 00:01:37  cheshire
-Tidy up code alignment
-
-Revision 1.566  2006/12/20 04:07:34  cheshire
-Remove uDNS_info substructure from AuthRecord_struct
-
-Revision 1.565  2006/12/19 22:49:23  cheshire
-Remove uDNS_info substructure from ServiceRecordSet_struct
-
-Revision 1.564  2006/12/19 02:38:20  cheshire
-Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
-
-Revision 1.563  2006/12/19 02:18:48  cheshire
-Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
-
-Revision 1.562  2006/12/16 01:58:31  cheshire
-<rdar://problem/4720673> uDNS: Need to start caching unicast records
-
-Revision 1.561  2006/12/01 07:38:53  herscher
-Only perform cache workaround fix if query is wide-area
-
-Revision 1.560  2006/11/30 23:07:56  herscher
-<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
-
-Revision 1.559  2006/11/27 08:20:57  cheshire
-Preliminary support for unifying the uDNS and mDNS code, including caching of uDNS answers
-
-Revision 1.558  2006/11/10 07:44:03  herscher
-<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
-
-Revision 1.557  2006/11/10 01:12:51  cheshire
-<rdar://problem/4829718> Incorrect TTL corrections
-
-Revision 1.556  2006/11/10 00:54:14  cheshire
-<rdar://problem/4816598> Changing case of Computer Name doesn't work
-
-Revision 1.555  2006/10/30 20:03:37  cheshire
-<rdar://problem/4456945> After service restarts on different port, for a few seconds DNS-SD may return stale port number
-
-Revision 1.554  2006/10/20 05:35:04  herscher
-<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
-
-Revision 1.553  2006/10/05 03:42:43  herscher
-Remove embedded uDNS_info struct in DNSQuestion_struct
-
-Revision 1.552  2006/09/15 21:20:15  cheshire
-Remove uDNS_info substructure from mDNS_struct
-
-Revision 1.551  2006/08/14 23:24:22  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.550  2006/07/27 17:58:34  cheshire
-Improved text of "SendQueries didn't send all its queries; will try again" debugging message
-
-Revision 1.549  2006/07/20 22:07:31  mkrochma
-<rdar://problem/4633196> Wide-area browsing is currently broken in TOT
-More fixes for uninitialized variables
-
-Revision 1.548  2006/07/20 19:30:19  mkrochma
-<rdar://problem/4633196> Wide-area browsing sometimes doesn't work in TOT
-
-Revision 1.547  2006/07/15 02:31:30  cheshire
-<rdar://problem/4630812> Suppress log messages for certain old devices with inconsistent TXT RRSet TTLs
-
-Revision 1.546  2006/07/07 01:09:09  cheshire
-<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
-
-Revision 1.545  2006/07/05 23:10:30  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
-
-Revision 1.544  2006/06/29 07:42:14  cheshire
-<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
-
-Revision 1.543  2006/06/29 01:38:43  cheshire
-<rdar://problem/4605285> Only request unicast responses on wake from sleep and network connection
-
-Revision 1.542  2006/06/27 23:40:29  cheshire
-Fix typo in comment: mis-spelled "compile"
-
-Revision 1.541  2006/06/27 19:46:24  cheshire
-Updated comments and debugging messages
-
-Revision 1.540  2006/06/15 21:35:16  cheshire
-Move definitions of mDNS_vsnprintf, mDNS_SetupResourceRecord, and some constants
-from mDNS.c to DNSCommon.c, so they can be accessed from dnsextd code
-
-Revision 1.539  2006/06/08 23:45:46  cheshire
-Change SimultaneousProbe messages from debugf() to LogOperation()
-
-Revision 1.538  2006/03/19 17:13:06  cheshire
-<rdar://problem/4483117> Need faster purging of stale records
-Shorten kDefaultReconfirmTimeForNoAnswer to five seconds
-and reconfirm whole chain of antecedents ot once
-
-Revision 1.537  2006/03/19 02:00:07  cheshire
-<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-
-Revision 1.536  2006/03/08 23:29:53  cheshire
-<rdar://problem/4468716> Improve "Service Renamed" log message
-
-Revision 1.535  2006/03/02 20:41:17  cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-Minor code tidying and comments to reduce the risk of similar programming errors in future
-
-Revision 1.534  2006/03/02 03:25:46  cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
-
-Revision 1.533  2006/02/26 00:54:41  cheshire
-Fixes to avoid code generation warning/error on FreeBSD 7
-
-*/
+ */
 
 #include "DNSCommon.h"                  // Defines general DNS untility routines
 #include "uDNS.h"                                              // Defines entry points into unicast-specific routines
@@ -1542,9 +54,27 @@ Fixes to avoid code generation warning/error on FreeBSD 7
        #pragma warning(disable:4706)
 #endif
 
+#if APPLE_OSX_mDNSResponder
+
+#include <WebFilterDNS/WebFilterDNS.h>
+
+#if ! NO_WCF
+WCFConnection *WCFConnectionNew(void) __attribute__((weak_import));
+void WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import));
+
+// Do we really need to define a macro for "if"?
+#define CHECK_WCF_FUNCTION(X) if (X)
+#endif // ! NO_WCF
+
+#else
+
+#define NO_WCF 1
+#endif // APPLE_OSX_mDNSResponder
+
 // Forward declarations
 mDNSlocal void BeginSleepProcessing(mDNS *const m);
 mDNSlocal void RetrySPSRegistrations(mDNS *const m);
+mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *EthAddr, mDNSOpaque48 *password);
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -1579,9 +109,6 @@ mDNSexport const char *const mDNS_DomainTypeNames[] =
 #pragma mark - General Utility Functions
 #endif
 
-#define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
-#define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - ((Q)->LastQTime + (Q)->ThisQInterval) >= 0)
-
 mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
        {
        if (m->mDNS_busy != m->mDNS_reentrancy+1)
@@ -1593,14 +120,12 @@ mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
 
        if (ActiveQuestion(q))
                {
-               mDNSs32 sendtime = q->LastQTime + q->ThisQInterval;
-
-               // Don't allow sendtime to be earlier than SuppressStdPort53Queries
-               if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && m->SuppressStdPort53Queries && (sendtime - m->SuppressStdPort53Queries < 0))
-                       sendtime = m->SuppressStdPort53Queries;
-
-               if (m->NextScheduledQuery - sendtime > 0)
-                       m->NextScheduledQuery = sendtime;
+               // Depending on whether this is a multicast or unicast question we want to set either:
+               // m->NextScheduledQuery = NextQSendTime(q) or
+               // m->NextuDNSEvent      = NextQSendTime(q)
+               mDNSs32 *const timer = mDNSOpaque16IsZero(q->TargetQID) ? &m->NextScheduledQuery : &m->NextuDNSEvent;
+               if (*timer - NextQSendTime(q) > 0)
+                       *timer = NextQSendTime(q);
                }
        }
 
@@ -1618,7 +143,7 @@ mDNSlocal CacheGroup *CacheGroupForRecord(const mDNS *const m, const mDNSu32 slo
        return(CacheGroupForName(m, slot, rr->namehash, rr->name));
        }
 
-mDNSlocal mDNSBool AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
+mDNSexport mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
        {
        NetworkInterfaceInfo *intf;
 
@@ -1664,6 +189,14 @@ mDNSexport char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID Interfa
 // Used by AnswerAllLocalQuestionsWithLocalAuthRecord() and AnswerNewLocalOnlyQuestion()
 mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, DNSQuestion *q, AuthRecord *rr, QC_result AddRecord)
        {
+       // We should not be delivering results for record types Unregistered, Deregistering, and (unverified) Unique
+       if (!(rr->resrec.RecordType & kDNSRecordTypeActiveMask))
+               {
+               LogMsg("AnswerLocalQuestionWithLocalAuthRecord: *NOT* delivering %s event for local record type %X %s",
+                       AddRecord ? "Add" : "Rmv", rr->resrec.RecordType, ARDisplayString(m, rr));
+               return;
+               }
+
        // 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->AnsweredLocalQ = mDNStrue;
        mDNS_DropLockBeforeCallback();          // Allow client to legally make mDNS API calls from the callback
@@ -1675,15 +208,22 @@ mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, DNSQuestion
        mDNS_ReclaimLockAfterCallback();        // Decrement mDNS_reentrancy to block mDNS API calls again
        }
 
-// When a new local AuthRecord is created or deleted, AnswerAllLocalQuestionsWithLocalAuthRecord() runs though
-// all our local questions (both LocalOnlyQuestions and mDNSInterface_Any questions) 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()
+// When a new local AuthRecord is created or deleted, AnswerAllLocalQuestionsWithLocalAuthRecord()
+// delivers the appropriate add/remove events to listening questions:
+// 1. It runs though all our LocalOnlyQuestions delivering answers as appropriate,
+//    stopping if it reaches a NewLocalOnlyQuestion -- brand-new questions are handled by AnswerNewLocalOnlyQuestion().
+// 2. If the AuthRecord is marked mDNSInterface_LocalOnly or mDNSInterface_P2P, then it also runs though
+//    our main question list, delivering answers to mDNSInterface_Any questions as appropriate,
+//    stopping if it reaches a NewQuestion -- brand-new questions are handled by AnswerNewQuestion().
+//
+// AnswerAllLocalQuestionsWithLocalAuthRecord is used by the m->NewLocalRecords loop in mDNS_Execute(),
+// and by mDNS_Deregister_internal()
+
 mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
        {
        if (m->CurrentQuestion)
-               LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+               LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)",
+                       m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
 
        m->CurrentQuestion = m->LocalOnlyQuestions;
        while (m->CurrentQuestion && m->CurrentQuestion != m->NewLocalOnlyQuestions)
@@ -1694,8 +234,8 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec
                        AnswerLocalQuestionWithLocalAuthRecord(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)
+       // If this AuthRecord is marked LocalOnly or P2P, then we want to deliver it to all local 'mDNSInterface_Any' questions
+       if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->resrec.InterfaceID == mDNSInterface_P2P)
                {
                m->CurrentQuestion = m->Questions;
                while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
@@ -1732,6 +272,12 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec
 
 #define InitialAnnounceCount ((mDNSu8)8)
 
+// For goodbye packets we set the count to 3, and for wakeups we set it to 18
+// (which will be up to 15 wakeup attempts over the course of 30 seconds,
+// and then if the machine fails to wake, 3 goodbye packets).
+#define GoodbyeCount ((mDNSu8)3)
+#define WakeupCount ((mDNSu8)18)
+
 // Note that the announce intervals use exponential backoff, doubling each time. The probe intervals do not.
 // This means that because the announce interval is doubled after sending the first packet, the first
 // observed on-the-wire inter-packet interval between announcements is actually one second.
@@ -1740,9 +286,9 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec
 #define DefaultAnnounceIntervalForTypeShared (mDNSPlatformOneSecond/2)
 #define DefaultAnnounceIntervalForTypeUnique (mDNSPlatformOneSecond/2)
 
-#define DefaultAPIntervalForRecordType(X)  ((X) & (kDNSRecordTypeAdvisory | kDNSRecordTypeShared     ) ? DefaultAnnounceIntervalForTypeShared : \
-                                                                                       (X) & (kDNSRecordTypeUnique                              ) ? DefaultProbeIntervalForTypeUnique    : \
-                                                                                       (X) & (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique) ? DefaultAnnounceIntervalForTypeUnique : 0)
+#define DefaultAPIntervalForRecordType(X)  ((X) & kDNSRecordTypeActiveSharedMask ? DefaultAnnounceIntervalForTypeShared : \
+                                                                                       (X) & kDNSRecordTypeUnique           ? DefaultProbeIntervalForTypeUnique    : \
+                                                                                       (X) & kDNSRecordTypeActiveUniqueMask ? DefaultAnnounceIntervalForTypeUnique : 0)
 
 #define TimeToAnnounceThisRecord(RR,time) ((RR)->AnnounceCount && (time) - ((RR)->LastAPTime + (RR)->ThisAPInterval) >= 0)
 #define TimeToSendThisRecord(RR,time) ((TimeToAnnounceThisRecord(RR,time) || (RR)->ImmedAnswer) && ResourceRecordIsValidAnswer(RR))
@@ -1826,11 +372,21 @@ mDNSlocal void SetNextAnnounceProbeTime(mDNS *const m, const AuthRecord *const r
        {
        if (rr->resrec.RecordType == kDNSRecordTypeUnique)
                {
-               //LogMsg("ProbeCount %d Next %ld %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
+               if ((rr->LastAPTime + rr->ThisAPInterval) - m->timenow > mDNSPlatformOneSecond * 10)
+                       {
+                       LogMsg("SetNextAnnounceProbeTime: ProbeCount %d Next in %d %s", rr->ProbeCount, (rr->LastAPTime + rr->ThisAPInterval) - m->timenow, ARDisplayString(m, rr));
+                       LogMsg("SetNextAnnounceProbeTime: m->SuppressProbes %d m->timenow %d diff %d", m->SuppressProbes, m->timenow, m->SuppressProbes - m->timenow);
+                       }
                if (m->NextScheduledProbe - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
                        m->NextScheduledProbe = (rr->LastAPTime + rr->ThisAPInterval);
+               // Some defensive code:
+               // If (rr->LastAPTime + rr->ThisAPInterval) happens to be far in the past, we don't want to allow
+               // NextScheduledProbe to be set excessively in the past, because that can cause bad things to happen.
+               // See: <rdar://problem/7795434> mDNS: Sometimes advertising stops working and record interval is set to zero
+               if (m->NextScheduledProbe - m->timenow < 0)
+                       m->NextScheduledProbe = m->timenow;
                }
-       else if (rr->AnnounceCount && ResourceRecordIsValidAnswer(rr))
+       else if (rr->AnnounceCount && (ResourceRecordIsValidAnswer(rr) || rr->resrec.RecordType == kDNSRecordTypeDeregistering))
                {
                if (m->NextScheduledResponse - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
                        m->NextScheduledResponse = (rr->LastAPTime + rr->ThisAPInterval);
@@ -1842,47 +398,62 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
        // For reverse-mapping Sleep Proxy PTR records, probe interval is one second
        rr->ThisAPInterval = rr->AddressProxy.type ? mDNSPlatformOneSecond : DefaultAPIntervalForRecordType(rr->resrec.RecordType);
 
-       // To allow us to aggregate probes when a group of services are registered together,
-       // the first probe is delayed 1/4 second. This means the common-case behaviour is:
-       // 1/4 second wait; probe
-       // 1/4 second wait; probe
-       // 1/4 second wait; probe
-       // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered)
+       // * If this is a record type that's going to probe, then we use the m->SuppressProbes time.
+       // * Otherwise, if it's not going to probe, but m->SuppressProbes is set because we have other
+       //   records that are going to probe, then we delay its first announcement so that it will
+       //   go out synchronized with the first announcement for the other records that *are* probing.
+       //   This is a minor performance tweak that helps keep groups of related records synchronized together.
+       //   The addition of "interval / 2" is to make sure that, in the event that any of the probes are
+       //   delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete.
+       //   When the probing is complete and those records begin to announce, these records will also be picked up and accelerated,
+       //   because they will meet the criterion of being at least half-way to their scheduled announcement time.
+       // * If it's not going to probe and m->SuppressProbes is not already set then we should announce immediately.
 
        if (rr->ProbeCount)
                {
                // If we have no probe suppression time set, or it is in the past, set it now
                if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0)
                        {
-                       m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique);
+                       // To allow us to aggregate probes when a group of services are registered together,
+                       // the first probe is delayed 1/4 second. This means the common-case behaviour is:
+                       // 1/4 second wait; probe
+                       // 1/4 second wait; probe
+                       // 1/4 second wait; probe
+                       // 1/4 second wait; announce (i.e. service is normally announced exactly one second after being registered)
+                       m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2));
+
                        // If we already have a *probe* scheduled to go out sooner, then use that time to get better aggregation
                        if (m->SuppressProbes - m->NextScheduledProbe >= 0)
-                               m->SuppressProbes = m->NextScheduledProbe;
+                               m->SuppressProbes = NonZeroTime(m->NextScheduledProbe);
+                       if (m->SuppressProbes - m->timenow < 0)         // Make sure we don't set m->SuppressProbes excessively in the past
+                               m->SuppressProbes = m->timenow;
+
                        // If we already have a *query* scheduled to go out sooner, then use that time to get better aggregation
                        if (m->SuppressProbes - m->NextScheduledQuery >= 0)
-                               m->SuppressProbes = m->NextScheduledQuery;
+                               m->SuppressProbes = NonZeroTime(m->NextScheduledQuery);
+                       if (m->SuppressProbes - m->timenow < 0)         // Make sure we don't set m->SuppressProbes excessively in the past
+                               m->SuppressProbes = m->timenow;
+
+                       // except... don't expect to be able to send before the m->SuppressSending timer fires
+                       if (m->SuppressSending && m->SuppressProbes - m->SuppressSending < 0)
+                               m->SuppressProbes = NonZeroTime(m->SuppressSending);
+
+                       if (m->SuppressProbes - m->timenow > mDNSPlatformOneSecond * 8)
+                               {
+                               LogMsg("InitializeLastAPTime ERROR m->SuppressProbes %d m->NextScheduledProbe %d m->NextScheduledQuery %d m->SuppressSending %d %d",
+                                       m->SuppressProbes     - m->timenow,
+                                       m->NextScheduledProbe - m->timenow,
+                                       m->NextScheduledQuery - m->timenow,
+                                       m->SuppressSending,
+                                       m->SuppressSending    - m->timenow);
+                               m->SuppressProbes = NonZeroTime(m->timenow + DefaultProbeIntervalForTypeUnique/2 + mDNSRandom(DefaultProbeIntervalForTypeUnique/2));
+                               }
                        }
+               rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval;
                }
-
-       rr->LastAPTime      = m->SuppressProbes - rr->ThisAPInterval;
-       // Set LastMCTime to now, to inhibit multicast responses
-       // (no need to send additional multicast responses when we're announcing anyway)
-       rr->LastMCTime      = m->timenow;
-       rr->LastMCInterface = mDNSInterfaceMark;
-       
-       // If this is a record type that's not going to probe, then delay its first announcement so that
-       // it will go out synchronized with the first announcement for the other records that *are* probing.
-       // This is a minor performance tweak that helps keep groups of related records synchronized together.
-       // The addition of "interval / 2" is to make sure that, in the event that any of the probes are
-       // delayed by a few milliseconds, this announcement does not inadvertently go out *before* the probing is complete.
-       // When the probing is complete and those records begin to announce, these records will also be picked up and accelerated,
-       // because they will meet the criterion of being at least half-way to their scheduled announcement time.
-       if (rr->resrec.RecordType != kDNSRecordTypeUnique)
-               rr->LastAPTime += DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2;
-
-       // The exception is unique records that have already been verified and are just being updated
-       // via mDNS_Update() -- for these we want to announce the new value immediately, without delay.
-       if (rr->resrec.RecordType == kDNSRecordTypeVerified)
+       else if (m->SuppressProbes && m->SuppressProbes - m->timenow >= 0)
+               rr->LastAPTime = m->SuppressProbes - rr->ThisAPInterval + DefaultProbeIntervalForTypeUnique * DefaultProbeCountForTypeUnique + rr->ThisAPInterval / 2;
+       else
                rr->LastAPTime = m->timenow - rr->ThisAPInterval;
 
        // For reverse-mapping Sleep Proxy PTR records we don't want to start probing instantly -- we
@@ -1893,13 +464,50 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
        // (depending on the OS and networking stack it's using) that it might interpret it as a conflict and change its IP address.
        if (rr->AddressProxy.type) rr->LastAPTime = m->timenow;
 
-       // For now, since we don't yet handle IPv6 ND or data packets, we send deletions for our SPS clients' AAAA records
-       if (rr->WakeUp.HMAC.l[0] && rr->resrec.rrtype == kDNSType_AAAA)
-               rr->LastAPTime = m->timenow - rr->ThisAPInterval + mDNSPlatformOneSecond * 10;
+       // Unsolicited Neighbor Advertisements (RFC 2461 Section 7.2.6) give us fast address cache updating,
+       // but some older IPv6 clients get confused by them, so for now we don't send them. Without Unsolicited
+       // Neighbor Advertisements we have to rely on Neighbor Unreachability Detection instead, which is slower.
+       // Given this, we'll do our best to wake for existing IPv6 connections, but we don't want to encourage
+       // new ones for sleeping clients, so we'll we send deletions for our SPS clients' AAAA records.
+       if (m->KnownBugs & mDNS_KnownBug_LimitedIPv6)
+               if (rr->WakeUp.HMAC.l[0] && rr->resrec.rrtype == kDNSType_AAAA)
+                       rr->LastAPTime = m->timenow - rr->ThisAPInterval + mDNSPlatformOneSecond * 10;
+       
+       // Set LastMCTime to now, to inhibit multicast responses
+       // (no need to send additional multicast responses when we're announcing anyway)
+       rr->LastMCTime      = m->timenow;
+       rr->LastMCInterface = mDNSInterfaceMark;
        
        SetNextAnnounceProbeTime(m, rr);
        }
 
+mDNSlocal const domainname *SetUnicastTargetToHostName(mDNS *const m, AuthRecord *rr)
+       {
+       const domainname *target;
+       if (rr->AutoTarget)
+               {
+               // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other
+               // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate,
+               // with the port number in our advertised SRV record automatically tracking the external mapped port.
+               DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
+               if (!AuthInfo || !AuthInfo->AutoTunnel) rr->AutoTarget = Target_AutoHostAndNATMAP;
+               }
+
+       target = GetServiceTarget(m, rr);
+       if (!target || target->c[0] == 0)
+               {
+               // defer registration until we've got a target
+               LogInfo("SetUnicastTargetToHostName No target for %s", ARDisplayString(m, rr));
+               rr->state = regState_NoTarget;
+               return mDNSNULL;
+               }
+       else
+               {
+               LogInfo("SetUnicastTargetToHostName target %##s for resource record %s", target->c, ARDisplayString(m,rr));
+               return target;
+               }
+       }
+
 // Right now this only applies to mDNS (.local) services where the target host is always m->MulticastHostname
 // Eventually we should unify this with GetServiceTarget() in uDNS.c
 mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
@@ -1907,12 +515,13 @@ mDNSlocal void SetTargetToHostName(mDNS *const m, AuthRecord *const rr)
        domainname *const target = GetRRDomainNameTarget(&rr->resrec);
        const domainname *newname = &m->MulticastHostname;
 
-       if (!target) debugf("SetTargetToHostName: Don't know how to set the target of rrtype %d", rr->resrec.rrtype);
+       if (!target) LogInfo("SetTargetToHostName: Don't know how to set the target of rrtype %s", DNSTypeName(rr->resrec.rrtype));
 
-       if (!(rr->ForceMCast || rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(&rr->namestorage)))
+       if (!(rr->ForceMCast || rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->resrec.InterfaceID == mDNSInterface_P2P || IsLocalDomain(&rr->namestorage)))
                {
-               const domainname *const n = GetServiceTarget(m, rr);
+               const domainname *const n = SetUnicastTargetToHostName(m, rr);
                if (n) newname = n;
+               else { target->c[0] = 0; SetNewRData(&rr->resrec, mDNSNULL, 0); return; }
                }
 
        if (target && SameDomainName(target, newname))
@@ -1952,21 +561,86 @@ mDNSlocal void AcknowledgeRecord(mDNS *const m, AuthRecord *const rr)
                rr->RecordCallback(m, rr, mStatus_NoError);
                mDNS_ReclaimLockAfterCallback();        // Decrement mDNS_reentrancy to block mDNS API calls again
                }
-       }
+       }
+
+mDNSexport void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr)
+       {
+       // Make sure that we don't activate the SRV record and associated service records, if it is in
+       // NoTarget state. First time when a service is being instantiated, SRV record may be in NoTarget state.
+       // We should not activate any of the other reords (PTR, TXT) that are part of the service. When
+       // the target becomes available, the records will be reregistered.
+       if (rr->resrec.rrtype != kDNSType_SRV)
+               {
+               AuthRecord *srvRR = mDNSNULL;
+               if (rr->resrec.rrtype == kDNSType_PTR)
+                       srvRR = rr->Additional1;
+               else if (rr->resrec.rrtype == kDNSType_TXT)
+                       srvRR = rr->DependentOn;
+               if (srvRR)
+                       {
+                       if (srvRR->resrec.rrtype != kDNSType_SRV)
+                               {
+                               LogMsg("ActivateUnicastRegistration: ERROR!! Resource record %s wrong, expecting SRV type", ARDisplayString(m, srvRR));
+                               }
+                       else
+                               {
+                               LogInfo("ActivateUnicastRegistration: Found Service Record %s in state %d for %##s (%s)",
+                                       ARDisplayString(m, srvRR), srvRR->state, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+                               rr->state = srvRR->state;
+                               }
+                       }
+               }
 
-mDNSlocal void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr)
-       {
+       if (rr->state == regState_NoTarget)
+               {
+               LogInfo("ActivateUnicastRegistration record %s in regState_NoTarget, not activating", ARDisplayString(m, rr));
+               return;
+               }
+       // When we wake up from sleep, we call ActivateUnicastRegistration. It is possible that just before we went to sleep,
+       // the service/record was being deregistered. In that case, we should not try to register again. For the cases where
+       // the records are deregistered due to e.g., no target for the SRV record, we would have returned from above if it
+       // was already in NoTarget state. If it was in the process of deregistration but did not complete fully before we went
+       // to sleep, then it is okay to start in Pending state as we will go back to NoTarget state if we don't have a target.
+       if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
+               {
+               LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to DeregPending", ARDisplayString(m, rr), rr->state);
+               rr->state = regState_DeregPending;
+               }
+       else
+               {
+               LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to Pending", ARDisplayString(m, rr), rr->state);
+               rr->state = regState_Pending;
+               }
        rr->ProbeCount     = 0;
        rr->AnnounceCount  = 0;
-       rr->ThisAPInterval = 5 * mDNSPlatformOneSecond;         // After doubling, first retry will happen after ten seconds
+       rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
        rr->LastAPTime     = m->timenow - rr->ThisAPInterval;
-       rr->state = regState_FetchingZoneData;
-       rr->uselease = mDNStrue;
-       }
-
-// Two records qualify to be local duplicates if the RecordTypes are the same, or if one is Unique and the other Verified
+       rr->expire         = 0; // Forget about all the leases, start fresh
+       rr->uselease       = mDNStrue;
+       rr->updateid       = zeroID;
+       rr->SRVChanged     = mDNSfalse;
+       rr->updateError    = mStatus_NoError;
+       // RestartRecordGetZoneData calls this function whenever a new interface gets registered with core.
+       // The records might already be registered with the server and hence could have NAT state.
+       if (rr->NATinfo.clientContext)
+               {
+               mDNS_StopNATOperation_internal(m, &rr->NATinfo);
+               rr->NATinfo.clientContext = mDNSNULL;
+               }
+       if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; }
+       if (rr->tcp) { DisposeTCPConn(rr->tcp);       rr->tcp = mDNSNULL; }
+       if (m->NextuDNSEvent - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
+               m->NextuDNSEvent = (rr->LastAPTime + rr->ThisAPInterval);
+       }
+
+// Two records qualify to be local duplicates if:
+// (a) the RecordTypes are the same, or
+// (b) one is Unique and the other Verified
+// (c) either is in the process of deregistering
 #define RecordLDT(A,B) ((A)->resrec.RecordType == (B)->resrec.RecordType || \
-       ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified))
+       ((A)->resrec.RecordType | (B)->resrec.RecordType) == (kDNSRecordTypeUnique | kDNSRecordTypeVerified) || \
+       ((A)->resrec.RecordType == kDNSRecordTypeDeregistering || (B)->resrec.RecordType == kDNSRecordTypeDeregistering))
+
 #define RecordIsLocalDuplicate(A,B) \
        ((A)->resrec.InterfaceID == (B)->resrec.InterfaceID && RecordLDT((A),(B)) && IdenticalResourceRecord(&(A)->resrec, &(B)->resrec))
 
@@ -1979,7 +653,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        AuthRecord **d = &m->DuplicateRecords;
 
        if ((mDNSs32)rr->resrec.rroriginalttl <= 0)
-               { LogMsg("mDNS_Register_internal: TTL must be 1 - 0x7FFFFFFF %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
+               { LogMsg("mDNS_Register_internal: TTL %X should be 1 - 0x7FFFFFFF %s", rr->resrec.rroriginalttl, ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
 
        if (!rr->resrec.RecordType)
                { LogMsg("mDNS_Register_internal: RecordType must be non-zero %s", ARDisplayString(m, rr)); return(mStatus_BadParamErr); }
@@ -1990,7 +664,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        if (m->DivertMulticastAdvertisements && !AuthRecord_uDNS(rr))
                {
                mDNSInterfaceID previousID = rr->resrec.InterfaceID;
-               if (rr->resrec.InterfaceID == mDNSInterface_Any) rr->resrec.InterfaceID = mDNSInterface_LocalOnly;
+               if (rr->resrec.InterfaceID == mDNSInterface_Any || rr->resrec.InterfaceID == mDNSInterface_P2P) rr->resrec.InterfaceID = mDNSInterface_LocalOnly;
                if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
                        {
                        NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
@@ -2028,7 +702,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
                }
 
        // If this resource record is referencing a specific interface, make sure it exists
-       if (rr->resrec.InterfaceID && rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
+       if (rr->resrec.InterfaceID && rr->resrec.InterfaceID != mDNSInterface_LocalOnly && rr->resrec.InterfaceID != mDNSInterface_P2P)
                {
                NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
                if (!intf)
@@ -2094,8 +768,6 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        rr->Private           = 0;
        rr->updateid          = zeroID;
        rr->zone              = rr->resrec.name;
-       rr->UpdateServer      = zeroAddr;
-       rr->UpdatePort        = zeroIPPort;
        rr->nta               = mDNSNULL;
        rr->tcp               = mDNSNULL;
        rr->OrigRData         = 0;
@@ -2112,8 +784,26 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
 //     rr->resrec.rroriginalttl     = already set in mDNS_SetupResourceRecord
 //     rr->resrec.rdata             = MUST be set by client, unless record type is CNAME or PTR and rr->HostTarget is set
 
+       // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
+       // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
+       // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
+       if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; }
+
        if (rr->AutoTarget)
+               {
                SetTargetToHostName(m, rr);     // Also sets rdlength and rdestimate for us, and calls InitializeLastAPTime();
+#ifndef UNICAST_DISABLED
+               // If we have no target record yet, SetTargetToHostName will set rr->state == regState_NoTarget
+               // In this case we leave the record half-formed in the list, and later we'll remove it from the list and re-add it properly.
+               if (rr->state == regState_NoTarget)
+                       {
+                       // Initialize the target so that we don't crash while logging etc.
+                       domainname *tar = GetRRDomainNameTarget(&rr->resrec);
+                       if (tar) tar->c[0] = 0;
+                       LogInfo("mDNS_Register_internal: record %s in NoTarget state", ARDisplayString(m, rr));
+                       }
+#endif
+               }
        else
                {
                rr->resrec.rdlength   = GetRDLength(&rr->resrec, mDNSfalse);
@@ -2123,11 +813,6 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        if (!ValidateDomainName(rr->resrec.name))
                { LogMsg("Attempt to register record with invalid name: %s", ARDisplayString(m, rr)); return(mStatus_Invalid); }
 
-       // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
-       // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
-       // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
-       if (rr->resrec.rrtype == kDNSType_TXT && rr->resrec.rdlength == 0) { rr->resrec.rdlength = 1; rr->resrec.rdata->u.txt.c[0] = 0; }
-
        // 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); }
@@ -2135,7 +820,7 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
        rr->resrec.namehash   = DomainNameHashValue(rr->resrec.name);
        rr->resrec.rdatahash  = target ? DomainNameHashValue(target) : RDataHashValue(&rr->resrec);
        
-       if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
+       if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->resrec.InterfaceID == mDNSInterface_P2P)
                {
                // If this is supposed to be unique, make sure we don't have any name conflicts
                if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
@@ -2153,17 +838,41 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
                                rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
                                rr->resrec.rroriginalttl = 0;
                                rr->ImmedAnswer          = mDNSInterfaceMark;
+                               m->LocalRemoveEvents     = mDNStrue;
                                m->NextScheduledResponse = m->timenow;
                                }
                        }
                }
 
+       // For uDNS records, we don't support duplicate checks at this time
+#ifndef UNICAST_DISABLED
+       if (AuthRecord_uDNS(rr))
+               {
+               if (!m->NewLocalRecords) m->NewLocalRecords = rr;
+               // When we called SetTargetToHostName, it may have caused mDNS_Register_internal to be re-entered, appending new
+               // records to the list, so we now need to update p to advance to the new end to the list before appending our new record.
+               // Note that for AutoTunnel this should never happen, but this check makes the code future-proof.
+               while (*p) p=&(*p)->next;
+               *p = rr;
+               if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
+               rr->ProbeCount    = 0;
+               rr->AnnounceCount = 0;
+               if (rr->state != regState_NoTarget) ActivateUnicastRegistration(m, rr);
+               return(mStatus_NoError);                        // <--- Note: For unicast records, code currently bails out at this point
+               }
+#endif
+
        // 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;
+       for (r = m->ResourceRecords; r; r=r->next)
+               if (RecordIsLocalDuplicate(r, rr))
+                       {
+                       if (r->resrec.RecordType == kDNSRecordTypeDeregistering) r->AnnounceCount = 0;
+                       else break;
+                       }
        
        if (r)
                {
-               debugf("Adding to duplicate list %p %s", rr, ARDisplayString(m,rr));
+               debugf("mDNS_Register_internal:Adding to duplicate list %s", ARDisplayString(m,rr));
                *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.
@@ -2174,25 +883,21 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
                }
        else
                {
-               debugf("Adding to active record list %p %s", rr, ARDisplayString(m,rr));
+               debugf("mDNS_Register_internal: Adding to active record list %s", ARDisplayString(m,rr));
                if (!m->NewLocalRecords) m->NewLocalRecords = rr;
                *p = rr;
                }
 
-       if (!AuthRecord_uDNS(rr))
+       if (!AuthRecord_uDNS(rr))       // This check is superfluous, given that for unicast records we (currently) bail out above
                {
                // For records that are not going to probe, acknowledge them right away
                if (rr->resrec.RecordType != kDNSRecordTypeUnique && rr->resrec.RecordType != kDNSRecordTypeDeregistering)
                        AcknowledgeRecord(m, rr);
+
+               // Adding a record may affect whether or not we should sleep
+               mDNS_UpdateAllowSleep(m);
                }
-#ifndef UNICAST_DISABLED
-       else
-               {
-               if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
-               ActivateUnicastRegistration(m, rr);
-               }
-#endif
-       
+
        return(mStatus_NoError);
        }
 
@@ -2218,10 +923,11 @@ mDNSlocal void RecordProbeFailure(mDNS *const m, const AuthRecord *const rr)
 mDNSlocal void CompleteRDataUpdate(mDNS *const m, AuthRecord *const rr)
        {
        RData *OldRData = rr->resrec.rdata;
+       mDNSu16 OldRDLen = rr->resrec.rdlength;
        SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);        // Update our rdata
        rr->NewRData = mDNSNULL;                                                                        // Clear the NewRData pointer ...
        if (rr->UpdateCallback)
-               rr->UpdateCallback(m, rr, OldRData);                                    // ... and let the client know
+               rr->UpdateCallback(m, rr, OldRData, OldRDLen);                  // ... and let the client know
        }
 
 // Note: mDNS_Deregister_internal can call a user callback, which may change the record list and/or question list.
@@ -2253,7 +959,7 @@ mDNSexport 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)",
+                               debugf("mDNS_Register_internal: 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...
@@ -2272,8 +978,6 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
                                dup->LastAPTime      = rr->LastAPTime;
                                dup->LastMCTime      = rr->LastMCTime;
                                dup->LastMCInterface = rr->LastMCInterface;
-                               dup->UpdateServer    = rr->UpdateServer;
-                               dup->UpdatePort      = rr->UpdatePort;
                                dup->Private         = rr->Private;
                                dup->state           = rr->state;
                                rr->RequireGoodbye = mDNSfalse;
@@ -2288,7 +992,7 @@ mDNSexport 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)",
+               if (*p) debugf("mDNS_Deregister_internal: Deleting DuplicateRecord %p %##s (%s)",
                        rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
                }
 
@@ -2315,25 +1019,66 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
        // actual goodbye packets.
        
 #ifndef UNICAST_DISABLED
-       if (AuthRecord_uDNS(rr) && rr->RequireGoodbye)
-               {
-               if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
-               rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
-               uDNS_DeregisterRecord(m, rr);
-               // At this point unconditionally we bail out
-               // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration,
-               // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration
-               // process and will complete asynchronously. Either way we don't need to do anything more here.
-               return(mStatus_NoError);
+       if (AuthRecord_uDNS(rr))
+               {
+               if (rr->RequireGoodbye)
+                       {
+                       if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
+                       rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
+                       m->LocalRemoveEvents     = mDNStrue;
+                       uDNS_DeregisterRecord(m, rr);
+                       // At this point unconditionally we bail out
+                       // Either uDNS_DeregisterRecord will have completed synchronously, and called CompleteDeregistration,
+                       // which calls us back here with RequireGoodbye set to false, or it will have initiated the deregistration
+                       // process and will complete asynchronously. Either way we don't need to do anything more here.
+                       return(mStatus_NoError);
+                       }
+               // Sometimes the records don't complete proper deregistration i.e., don't wait for a response
+               // from the server. In that case, if the records have been part of a group update, clear the
+               // state here. Some recors e.g., AutoTunnel gets reused without ever being completely initialized
+               rr->updateid = zeroID;
+
+               // We defer cleaning up NAT state only after sending goodbyes. This is important because
+               // RecordRegistrationGotZoneData guards against creating NAT state if clientContext is non-NULL.
+               // This happens today when we turn on/off interface where we get multiple network transitions
+               // and RestartRecordGetZoneData triggers re-registration of the resource records even though
+               // they may be in Registered state which causes NAT information to be setup multiple times. Defering
+               // the cleanup here keeps clientContext non-NULL and hence prevents that. Note that cleaning up
+               // NAT state here takes care of the case where we did not send goodbyes at all.
+               if (rr->NATinfo.clientContext)
+                       {
+                       mDNS_StopNATOperation_internal(m, &rr->NATinfo);
+                       rr->NATinfo.clientContext = mDNSNULL;
+                       }
+               if (rr->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; }
+               if (rr->tcp) { DisposeTCPConn(rr->tcp);       rr->tcp = mDNSNULL; }
                }
 #endif // UNICAST_DISABLED
 
-       if (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ))
+       if      (RecordType == kDNSRecordTypeUnregistered)
+               LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m, rr));
+       else if (RecordType == kDNSRecordTypeDeregistering)
                {
-               verbosedebugf("mDNS_Deregister_internal: Sending deregister for %s", ARDisplayString(m, rr));
+               LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m, rr));
+               return(mStatus_BadReferenceErr);
+               }
+
+       // <rdar://problem/7457925> Local-only questions don't get remove events for unique records
+       // We may want to consider changing this code so that we generate local-only question "rmv"
+       // events (and maybe goodbye packets too) for unique records as well as for shared records
+       // Note: If we change the logic for this "if" statement, need to ensure that the code in
+       // CompleteDeregistration() sets the appropriate state variables to gaurantee that "else"
+       // clause will execute here and the record will be cut from the list.
+       if (rr->WakeUp.HMAC.l[0] ||
+               (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ)))
+               {
+               verbosedebugf("mDNS_Deregister_internal: Starting deregistration for %s", ARDisplayString(m, rr));
                rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
                rr->resrec.rroriginalttl = 0;
-               rr->ImmedAnswer          = mDNSInterfaceMark;
+               rr->AnnounceCount        = rr->WakeUp.HMAC.l[0] ? WakeupCount : (drt == mDNS_Dereg_rapid) ? 1 : GoodbyeCount;
+               rr->ThisAPInterval       = mDNSPlatformOneSecond * 2;
+               rr->LastAPTime           = m->timenow - rr->ThisAPInterval;
+               m->LocalRemoveEvents     = mDNStrue;
                if (m->NextScheduledResponse - (m->timenow + mDNSPlatformOneSecond/10) >= 0)
                        m->NextScheduledResponse = (m->timenow + mDNSPlatformOneSecond/10);
                }
@@ -2345,15 +1090,12 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
                if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next;
                rr->next = mDNSNULL;
 
-               if      (RecordType == kDNSRecordTypeUnregistered)
-                       LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeUnregistered", ARDisplayString(m, rr));
-               else if (RecordType == kDNSRecordTypeDeregistering)
-                       LogMsg("mDNS_Deregister_internal: %s already marked kDNSRecordTypeDeregistering", ARDisplayString(m, rr));
-               else
-                       {
-                       verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr));
-                       rr->resrec.RecordType = kDNSRecordTypeUnregistered;
-                       }
+               // Should we generate local remove events here?
+               // i.e. something like:
+               // if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; }
+
+               verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr));
+               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)",
@@ -2362,8 +1104,6 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
                // 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->nta) { CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; }
-               if (rr->tcp) { DisposeTCPConn(rr->tcp);       rr->tcp = mDNSNULL; }
 
                // 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.
@@ -2372,6 +1112,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
                if (drt != mDNS_Dereg_conflict)
                        {
                        mDNS_DropLockBeforeCallback();          // Allow client to legally make mDNS API calls from the callback
+                       LogInfo("mDNS_Deregister_internal: mStatus_MemFree for %s", ARDisplayString(m, rr));
                        if (rr->RecordCallback)
                                rr->RecordCallback(m, rr, mStatus_MemFree);                     // MUST NOT touch rr after this
                        mDNS_ReclaimLockAfterCallback();        // Decrement mDNS_reentrancy to block mDNS API calls again
@@ -2394,6 +1135,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
                                }
                        }
                }
+       mDNS_UpdateAllowSleep(m);
        return(mStatus_NoError);
        }
 
@@ -2530,22 +1272,29 @@ mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const d
                        rr->NR_AdditionalTo = mDNSNULL;
                        }
 
-               if (m->omsg.h.numAnswers) mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSNULL);
+               if (m->omsg.h.numAnswers)
+                       mDNSSendDNSMessage(m, &m->omsg, responseptr, mDNSInterface_Any, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSNULL);
                }
        }
 
+// CompleteDeregistration guarantees that on exit the record will have been cut from the m->ResourceRecords list
+// and the client's mStatus_MemFree callback will have been invoked
 mDNSexport void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
        {
+       LogInfo("CompleteDeregistration: called for Resource record %s", ARDisplayString(m, rr));
        // Clearing rr->RequireGoodbye signals mDNS_Deregister_internal() that
        // it should go ahead and immediately dispose of this registration
        rr->resrec.RecordType = kDNSRecordTypeShared;
        rr->RequireGoodbye    = mDNSfalse;
+       rr->WakeUp.HMAC       = zeroEthAddr;
        if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; }
        mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);             // Don't touch rr after this
        }
 
-// Note: DiscardDeregistrations calls mDNS_Deregister_internal which can call a user callback, which may change
-// the record list and/or question list.
+// DiscardDeregistrations is used on shutdown and sleep to discard (forcibly and immediately)
+// any deregistering records that remain in the m->ResourceRecords list.
+// DiscardDeregistrations calls mDNS_Deregister_internal 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 DiscardDeregistrations(mDNS *const m)
        {
@@ -2556,7 +1305,7 @@ mDNSlocal void DiscardDeregistrations(mDNS *const m)
        while (m->CurrentRecord)
                {
                AuthRecord *rr = m->CurrentRecord;
-               if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
+               if (!AuthRecord_uDNS(rr) && rr->resrec.RecordType == kDNSRecordTypeDeregistering)
                        CompleteDeregistration(m, rr);          // Don't touch rr after this
                else
                        m->CurrentRecord = rr->next;
@@ -2573,7 +1322,7 @@ mDNSlocal mStatus GetLabelDecimalValue(const mDNSu8 *const src, mDNSu8 *dst)
                val = val * 10 + src[i] - '0';
                }
        if (val > 255) return(mStatus_Invalid);
-       *dst = val;
+       *dst = (mDNSu8)val;
        return(mStatus_NoError);
        }
 
@@ -2613,7 +1362,7 @@ mDNSlocal mStatus GetIPv6FromName(mDNSAddr *const a, const domainname *const nam
                n = (const domainname *)(n->c + 2);
 
                if (l<0 || h<0) return mStatus_Invalid;
-               a->ip.v6.b[15-i] = (h << 4) | l;
+               a->ip.v6.b[15-i] = (mDNSu8)((h << 4) | l);
                }
 
        a->type = mDNSAddrType_IPv6;
@@ -2633,7 +1382,7 @@ mDNSlocal mDNSs32 ReverseMapDomainType(const domainname *const name)
        }
 
 mDNSlocal void SendARP(mDNS *const m, const mDNSu8 op, const AuthRecord *const rr,
-       const mDNSu8 *const spa, const mDNSu8 *const tha, const mDNSu8 *const tpa, const mDNSu8 *const dst)
+       const mDNSv4Addr *const spa, const mDNSEthAddr *const tha, const mDNSv4Addr *const tpa, const mDNSEthAddr *const dst)
        {
        int i;
        mDNSu8 *ptr = m->omsg.data;
@@ -2641,10 +1390,10 @@ mDNSlocal void SendARP(mDNS *const m, const mDNSu8 op, const AuthRecord *const r
        if (!intf) { LogMsg("SendARP: No interface with InterfaceID %p found %s", rr->resrec.InterfaceID, ARDisplayString(m,rr)); return; }
 
        // 0x00 Destination address
-       for (i=0; i<6; i++) *ptr++ = dst[i];
+       for (i=0; i<6; i++) *ptr++ = dst->b[i];
 
-       // 0x06 Source address (we just use zero -- driver/hardware will fill in real interface address)
-       for (i=0; i<6; i++) *ptr++ = 0x0;
+       // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us)
+       for (i=0; i<6; i++) *ptr++ = intf->MAC.b[0];
 
        // 0x0C ARP Ethertype (0x0806)
        *ptr++ = 0x08; *ptr++ = 0x06;
@@ -2660,18 +1409,131 @@ mDNSlocal void SendARP(mDNS *const m, const mDNSu8 op, const AuthRecord *const r
        for (i=0; i<6; i++) *ptr++ = intf->MAC.b[i];
 
        // 0x1C Sender protocol address
-       for (i=0; i<4; i++) *ptr++ = spa[i];
+       for (i=0; i<4; i++) *ptr++ = spa->b[i];
 
        // 0x20 Target hardware address
-       for (i=0; i<6; i++) *ptr++ = tha[i];
+       for (i=0; i<6; i++) *ptr++ = tha->b[i];
 
        // 0x26 Target protocol address
-       for (i=0; i<4; i++) *ptr++ = tpa[i];
+       for (i=0; i<4; i++) *ptr++ = tpa->b[i];
 
        // 0x2A Total ARP Packet length 42 bytes
        mDNSPlatformSendRawPacket(m->omsg.data, ptr, rr->resrec.InterfaceID);
        }
 
+mDNSlocal mDNSu16 CheckSum(const void *const data, mDNSs32 length, mDNSu32 sum)
+       {
+       const mDNSu16 *ptr = data;
+       while (length > 0) { length -= 2; sum += *ptr++; }
+       sum = (sum & 0xFFFF) + (sum >> 16);
+       sum = (sum & 0xFFFF) + (sum >> 16);
+       return(sum != 0xFFFF ? sum : 0);
+       }
+
+mDNSlocal mDNSu16 IPv6CheckSum(const mDNSv6Addr *const src, const mDNSv6Addr *const dst, const mDNSu8 protocol, const void *const data, const mDNSu32 length)
+       {
+       IPv6PseudoHeader ph;
+       ph.src = *src;
+       ph.dst = *dst;
+       ph.len.b[0] = length >> 24;
+       ph.len.b[1] = length >> 16;
+       ph.len.b[2] = length >> 8;
+       ph.len.b[3] = length;
+       ph.pro.b[0] = 0;
+       ph.pro.b[1] = 0;
+       ph.pro.b[2] = 0;
+       ph.pro.b[3] = protocol;
+       return CheckSum(&ph, sizeof(ph), CheckSum(data, length, 0));
+       }
+
+mDNSlocal void SendNDP(mDNS *const m, const mDNSu8 op, const mDNSu8 flags, const AuthRecord *const rr,
+       const mDNSv6Addr *const spa, const mDNSEthAddr *const tha, const mDNSv6Addr *const tpa, const mDNSEthAddr *const dst)
+       {
+       int i;
+       mDNSOpaque16 checksum;
+       mDNSu8 *ptr = m->omsg.data;
+       // Some recipient hosts seem to ignore Neighbor Solicitations if the IPv6-layer destination address is not the
+       // appropriate IPv6 solicited node multicast address, so we use that IPv6-layer destination address, even though
+       // at the Ethernet-layer we unicast the packet to the intended target, to avoid wasting network bandwidth.
+       const mDNSv6Addr mc = { { 0xFF,0x02,0x00,0x00, 0,0,0,0, 0,0,0,1, 0xFF,tpa->b[0xD],tpa->b[0xE],tpa->b[0xF] } };
+       const mDNSv6Addr *const v6dst = (op == NDP_Sol) ? &mc : tpa;
+       NetworkInterfaceInfo *intf = FirstInterfaceForID(m, rr->resrec.InterfaceID);
+       if (!intf) { LogMsg("SendNDP: No interface with InterfaceID %p found %s", rr->resrec.InterfaceID, ARDisplayString(m,rr)); return; }
+
+       // 0x00 Destination address
+       for (i=0; i<6; i++) *ptr++ = dst->b[i];
+       // Right now we only send Neighbor Solicitations to verify whether the host we're proxying for has gone to sleep yet.
+       // Since we know who we're looking for, we send it via Ethernet-layer unicast, rather than bothering every host on the
+       // link with a pointless link-layer multicast.
+       // Should we want to send traditional Neighbor Solicitations in the future, where we really don't know in advance what
+       // Ethernet-layer address we're looking for, we'll need to send to the appropriate Ethernet-layer multicast address:
+       // *ptr++ = 0x33;
+       // *ptr++ = 0x33;
+       // *ptr++ = 0xFF;
+       // *ptr++ = tpa->b[0xD];
+       // *ptr++ = tpa->b[0xE];
+       // *ptr++ = tpa->b[0xF];
+
+       // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us)
+       for (i=0; i<6; i++) *ptr++ = (tha ? *tha : intf->MAC).b[i];
+
+       // 0x0C IPv6 Ethertype (0x86DD)
+       *ptr++ = 0x86; *ptr++ = 0xDD;
+
+       // 0x0E IPv6 header
+       *ptr++ = 0x60; *ptr++ = 0x00; *ptr++ = 0x00; *ptr++ = 0x00;             // Version, Traffic Class, Flow Label
+       *ptr++ = 0x00; *ptr++ = 0x20;                                                                   // Length
+       *ptr++ = 0x3A;                                                                                                  // Protocol == ICMPv6
+       *ptr++ = 0xFF;                                                                                                  // Hop Limit
+
+       // 0x16 Sender IPv6 address
+       for (i=0; i<16; i++) *ptr++ = spa->b[i];
+
+       // 0x26 Destination IPv6 address
+       for (i=0; i<16; i++) *ptr++ = v6dst->b[i];
+
+       // 0x36 NDP header
+       *ptr++ = op;                                    // 0x87 == Neighbor Solicitation, 0x88 == Neighbor Advertisement
+       *ptr++ = 0x00;                                  // Code
+       *ptr++ = 0x00; *ptr++ = 0x00;   // Checksum placeholder (0x38, 0x39)
+       *ptr++ = flags;
+       *ptr++ = 0x00; *ptr++ = 0x00; *ptr++ = 0x00;
+
+       if (op == NDP_Sol)      // Neighbor Solicitation. The NDP "target" is the address we seek.
+               {
+               // 0x3E NDP target.
+               for (i=0; i<16; i++) *ptr++ = tpa->b[i];
+               // 0x4E Source Link-layer Address
+               // <http://www.ietf.org/rfc/rfc2461.txt>
+               // MUST NOT be included when the source IP address is the unspecified address.
+               // Otherwise, on link layers that have addresses this option MUST be included
+               // in multicast solicitations and SHOULD be included in unicast solicitations.
+               if (!mDNSIPv6AddressIsZero(*spa))
+                       {
+                       *ptr++ = NDP_SrcLL;     // Option Type 1 == Source Link-layer Address
+                       *ptr++ = 0x01;          // Option length 1 (in units of 8 octets)
+                       for (i=0; i<6; i++) *ptr++ = (tha ? *tha : intf->MAC).b[i];
+                       }
+               }
+       else                    // Neighbor Advertisement. The NDP "target" is the address we're giving information about.
+               {
+               // 0x3E NDP target.
+               for (i=0; i<16; i++) *ptr++ = spa->b[i];
+               // 0x4E Target Link-layer Address
+               *ptr++ = NDP_TgtLL;     // Option Type 2 == Target Link-layer Address
+               *ptr++ = 0x01;          // Option length 1 (in units of 8 octets)
+               for (i=0; i<6; i++) *ptr++ = (tha ? *tha : intf->MAC).b[i];
+               }
+
+       // 0x4E or 0x56 Total NDP Packet length 78 or 86 bytes
+       m->omsg.data[0x13] = ptr - &m->omsg.data[0x36];         // Compute actual length
+       checksum.NotAnInteger = ~IPv6CheckSum(spa, v6dst, 0x3A, &m->omsg.data[0x36], m->omsg.data[0x13]);
+       m->omsg.data[0x38] = checksum.b[0];
+       m->omsg.data[0x39] = checksum.b[1];
+
+       mDNSPlatformSendRawPacket(m->omsg.data, ptr, rr->resrec.InterfaceID);
+       }
+
 mDNSlocal void SetupOwnerOpt(const mDNS *const m, const NetworkInterfaceInfo *const intf, rdataOPT *const owner)
        {
        owner->u.owner.vers     = 0;
@@ -2743,30 +1605,61 @@ mDNSlocal void SendResponses(mDNS *const m)
        for (rr = m->ResourceRecords; rr; rr=rr->next)
                {
                while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
-               if (TimeToAnnounceThisRecord(rr, m->timenow) && ResourceRecordIsValidAnswer(rr))
+               if (TimeToAnnounceThisRecord(rr, m->timenow))
                        {
-                       if (rr->AddressProxy.type)
+                       if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
                                {
-                               rr->AnnounceCount--;
-                               rr->ThisAPInterval *= 2;
-                               rr->LastAPTime = m->timenow;
-                               if (rr->AddressProxy.type == mDNSAddrType_IPv4)
+                               if (!rr->WakeUp.HMAC.l[0])
                                        {
-                                       LogSPS("ARP Announcement %d Capturing traffic for H-MAC %.6a I-MAC %.6a %s", rr->AnnounceCount, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m,rr));
-                                       SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
+                                       if (rr->AnnounceCount) rr->ImmedAnswer = mDNSInterfaceMark;             // Send goodbye packet on all interfaces
                                        }
-                               else if (rr->AddressProxy.type == mDNSAddrType_IPv6)
+                               else
                                        {
-                                       //LogSPS("NDP Announcement %d %s", rr->AnnounceCount, ARDisplayString(m,rr));
-                                       //SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
+                                       LogSPS("SendResponses: Sending wakeup %2d for %.6a %s", rr->AnnounceCount-3, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
+                                       SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password);
+                                       for (r2 = rr; r2; r2=r2->next)
+                                               if (r2->AnnounceCount && r2->resrec.InterfaceID == rr->resrec.InterfaceID && mDNSSameEthAddress(&r2->WakeUp.IMAC, &rr->WakeUp.IMAC))
+                                                       {
+                                                       // For now we only want to send a single Unsolicited Neighbor Advertisement restoring the address to the original
+                                                       // owner, because these packets can cause some IPv6 stacks to falsely conclude that there's an address conflict.
+                                                       if (r2->AddressProxy.type == mDNSAddrType_IPv6 && r2->AnnounceCount == WakeupCount)
+                                                               {
+                                                               LogSPS("NDP Announcement %2d Releasing traffic for H-MAC %.6a I-MAC %.6a %s",
+                                                                       r2->AnnounceCount-3, &r2->WakeUp.HMAC, &r2->WakeUp.IMAC, ARDisplayString(m,r2));
+                                                               SendNDP(m, NDP_Adv, NDP_Override, r2, &r2->AddressProxy.ip.v6, &r2->WakeUp.IMAC, &AllHosts_v6, &AllHosts_v6_Eth);
+                                                               }
+                                                       r2->LastAPTime = m->timenow;
+                                                       if (--r2->AnnounceCount <= GoodbyeCount) r2->WakeUp.HMAC = zeroEthAddr;
+                                                       }
                                        }
                                }
-                       else
+                       else if (ResourceRecordIsValidAnswer(rr))
                                {
-                               rr->ImmedAnswer = mDNSInterfaceMark;            // Send on all interfaces
-                               if (maxExistingAnnounceInterval < rr->ThisAPInterval)
-                                       maxExistingAnnounceInterval = rr->ThisAPInterval;
-                               if (rr->UpdateBlocked) rr->UpdateBlocked = 0;
+                               if (rr->AddressProxy.type)
+                                       {
+                                       rr->AnnounceCount--;
+                                       rr->ThisAPInterval *= 2;
+                                       rr->LastAPTime = m->timenow;
+                                       if (rr->AddressProxy.type == mDNSAddrType_IPv4)
+                                               {
+                                               LogSPS("ARP Announcement %2d Capturing traffic for H-MAC %.6a I-MAC %.6a %s",
+                                                       rr->AnnounceCount, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m,rr));
+                                               SendARP(m, 1, rr, &rr->AddressProxy.ip.v4, &zeroEthAddr, &rr->AddressProxy.ip.v4, &onesEthAddr);
+                                               }
+                                       else if (rr->AddressProxy.type == mDNSAddrType_IPv6)
+                                               {
+                                               LogSPS("NDP Announcement %2d Capturing traffic for H-MAC %.6a I-MAC %.6a %s",
+                                                       rr->AnnounceCount, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m,rr));
+                                               SendNDP(m, NDP_Adv, NDP_Override, rr, &rr->AddressProxy.ip.v6, mDNSNULL, &AllHosts_v6, &AllHosts_v6_Eth);
+                                               }
+                                       }
+                               else
+                                       {
+                                       rr->ImmedAnswer = mDNSInterfaceMark;            // Send on all interfaces
+                                       if (maxExistingAnnounceInterval < rr->ThisAPInterval)
+                                               maxExistingAnnounceInterval = rr->ThisAPInterval;
+                                       if (rr->UpdateBlocked) rr->UpdateBlocked = 0;
+                                       }
                                }
                        }
                }
@@ -2846,7 +1739,8 @@ mDNSlocal void SendResponses(mDNS *const m)
                        if (TimeToAnnounceThisRecord(rr, m->timenow + rr->ThisAPInterval/2))
                                {
                                rr->AnnounceCount--;
-                               rr->ThisAPInterval *= 2;
+                               if (rr->resrec.RecordType != kDNSRecordTypeDeregistering)
+                                       rr->ThisAPInterval *= 2;
                                rr->LastAPTime = m->timenow;
                                debugf("Announcing %##s (%s) %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->AnnounceCount);
                                }
@@ -2884,50 +1778,44 @@ mDNSlocal void SendResponses(mDNS *const m)
                        {
                        if (rr->SendRNow == intf->InterfaceID)
                                {
+                               RData  *OldRData    = rr->resrec.rdata;
+                               mDNSu16 oldrdlength = rr->resrec.rdlength;
+                               mDNSu8 active = (mDNSu8)
+                                       (rr->resrec.RecordType != kDNSRecordTypeDeregistering &&
+                                       (m->SleepState != SleepState_Sleeping || intf->SPSAddr[0].type || intf->SPSAddr[1].type || intf->SPSAddr[2].type));
                                newptr = mDNSNULL;
-                               if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
-                                       {
-                                       newptr = PutRR_OS_TTL(responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
-                                       if (newptr) { responseptr = newptr; numDereg++; }
-                                       }
-                               else if (rr->NewRData && !m->SleepState)                                        // If we have new data for this record
+                               if (rr->NewRData && active)
                                        {
-                                       RData *OldRData     = rr->resrec.rdata;
-                                       mDNSu16 oldrdlength = rr->resrec.rdlength;
                                        // See if we should send a courtesy "goodbye" for the old data before we replace it.
-                                       if (ResourceRecordIsValidAnswer(rr) && rr->RequireGoodbye)
+                                       if (ResourceRecordIsValidAnswer(rr) && rr->resrec.RecordType == kDNSRecordTypeShared && rr->RequireGoodbye)
                                                {
                                                newptr = PutRR_OS_TTL(responseptr, &m->omsg.h.numAnswers, &rr->resrec, 0);
                                                if (newptr) { responseptr = newptr; numDereg++; rr->RequireGoodbye = mDNSfalse; }
+                                               else continue; // If this packet is already too full to hold the goodbye for this record, skip it for now and we'll retry later
                                                }
-                                       // Now try to see if we can fit the update in the same packet (not fatal if we can't)
                                        SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
-                                       if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
-                                               rr->resrec.rrclass |= kDNSClass_UniqueRRSet;            // Temporarily set the cache flush bit so PutResourceRecord will set it
-                                       newptr = PutRR_OS(responseptr, &m->omsg.h.numAnswers, &rr->resrec);
-                                       rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;                   // Make sure to clear cache flush bit back to normal state
-                                       if (newptr) { responseptr = newptr; rr->RequireGoodbye = mDNStrue; }
-                                       SetNewRData(&rr->resrec, OldRData, oldrdlength);
                                        }
-                               else
+                               
+                               if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
+                                       rr->resrec.rrclass |= kDNSClass_UniqueRRSet;            // Temporarily set the cache flush bit so PutResourceRecord will set it
+                               newptr = PutRR_OS_TTL(responseptr, &m->omsg.h.numAnswers, &rr->resrec, active ? rr->resrec.rroriginalttl : 0);
+                               rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;                   // Make sure to clear cache flush bit back to normal state
+                               if (newptr)
                                        {
-                                       mDNSu8 active = (m->SleepState != SleepState_Sleeping || intf->SPSAddr[0].type || intf->SPSAddr[1].type || intf->SPSAddr[2].type);
-                                       if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
-                                               rr->resrec.rrclass |= kDNSClass_UniqueRRSet;            // Temporarily set the cache flush bit so PutResourceRecord will set it
-                                       newptr = PutRR_OS_TTL(responseptr, &m->omsg.h.numAnswers, &rr->resrec, active ? rr->resrec.rroriginalttl : 0);
-                                       rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;                   // Make sure to clear cache flush bit back to normal state
-                                       if (newptr)
-                                               {
-                                               responseptr = newptr;
-                                               rr->RequireGoodbye = active;
-                                               if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++;
-                                               }
-
-                                       // The first time through (pktcount==0), if this record is verified unique
-                                       // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too.
-                                       if (!pktcount && active && rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->SendNSECNow) rr->SendNSECNow = mDNSInterfaceMark;
+                                       responseptr = newptr;
+                                       rr->RequireGoodbye = active;
+                                       if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) numDereg++;
+                                       else if (rr->LastAPTime == m->timenow) numAnnounce++; else numAnswer++;
                                        }
 
+                               if (rr->NewRData && active)
+                                       SetNewRData(&rr->resrec, OldRData, oldrdlength);
+
+                               // The first time through (pktcount==0), if this record is verified unique
+                               // (i.e. typically A, AAAA, SRV, TXT and reverse-mapping PTR), set the flag to add an NSEC too.
+                               if (!pktcount && active && (rr->resrec.RecordType & kDNSRecordTypeActiveUniqueMask) && !rr->SendNSECNow)
+                                       rr->SendNSECNow = mDNSInterfaceMark;
+
                                if (newptr)             // If succeeded in sending, advance to next interface
                                        {
                                        // If sending on all interfaces, go to next interface; else we're finished now
@@ -2964,8 +1852,9 @@ mDNSlocal void SendResponses(mDNS *const m)
                                        else if (newptr)                                                // Else, try to add it if we can
                                                {
                                                // The first time through (pktcount==0), if this record is verified unique
-                                               // (i.e. typically A, AAAA, SRV and TXT), set the flag to add an NSEC too.
-                                               if (!pktcount && rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->SendNSECNow) rr->SendNSECNow = mDNSInterfaceMark;
+                                               // (i.e. typically A, AAAA, SRV, TXT and reverse-mapping PTR), set the flag to add an NSEC too.
+                                               if (!pktcount && (rr->resrec.RecordType & kDNSRecordTypeActiveUniqueMask) && !rr->SendNSECNow)
+                                                       rr->SendNSECNow = mDNSInterfaceMark;
 
                                                if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
                                                        rr->resrec.rrclass |= kDNSClass_UniqueRRSet;    // Temporarily set the cache flush bit so PutResourceRecord will set it
@@ -2987,6 +1876,9 @@ mDNSlocal void SendResponses(mDNS *const m)
                                        }
 
                // Third Pass. Add NSEC records, if there's space.
+               // When we're generating an NSEC record in response to a specify query for that type
+               // (recognized by rr->SendNSECNow == intf->InterfaceID) we should really put the NSEC in the Answer Section,
+               // not Additional Section, but for now it's easier to handle both cases in this Additional Section loop here.
                for (rr = m->ResourceRecords; rr; rr=rr->next)
                        if (rr->SendNSECNow == mDNSInterfaceMark || rr->SendNSECNow == intf->InterfaceID)
                                {
@@ -3034,9 +1926,13 @@ mDNSlocal void SendResponses(mDNS *const m)
                                opt.resrec.rdestimate = sizeof(rdataOPT);
                                SetupOwnerOpt(m, intf, &opt.resrec.rdata->u.opt[0]);
                                newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAdditionals, &opt.resrec);
-                               if (newptr) { responseptr = newptr; LogSPS("SendResponses put %s", ARDisplayString(m, &opt)); }
-                               else LogMsg("SendResponses: How did we fail to have space for the OPT record (%d/%d/%d/%d) %s",
-                                       m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt));
+                               if (newptr) { responseptr = newptr; LogSPS("SendResponses put   %s", ARDisplayString(m, &opt)); }
+                               else if (m->omsg.h.numAnswers + m->omsg.h.numAuthorities + m->omsg.h.numAdditionals == 1)
+                                       LogSPS("SendResponses: No space in packet for Owner OPT record (%d/%d/%d/%d) %s",
+                                               m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt));
+                               else
+                                       LogMsg("SendResponses: How did we fail to have space for Owner OPT record (%d/%d/%d/%d) %s",
+                                               m->omsg.h.numQuestions, m->omsg.h.numAnswers, m->omsg.h.numAuthorities, m->omsg.h.numAdditionals, ARDisplayString(m, &opt));
                                }
 
                        debugf("SendResponses: Sending %d Deregistration%s, %d Announcement%s, %d Answer%s, %d Additional%s on %p",
@@ -3076,17 +1972,20 @@ mDNSlocal void SendResponses(mDNS *const m)
 
                if (rr->SendRNow)
                        {
-                       if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly)
-                               LogMsg("SendResponses: No active interface to send: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr));
+                       if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly && rr->resrec.InterfaceID != mDNSInterface_P2P)
+                               LogMsg("SendResponses: No active interface %p to send: %p %02X %s", rr->SendRNow, rr->resrec.InterfaceID, rr->resrec.RecordType, ARDisplayString(m, rr));
                        rr->SendRNow = mDNSNULL;
                        }
 
-               if (rr->ImmedAnswer)
+               if (rr->ImmedAnswer || rr->resrec.RecordType == kDNSRecordTypeDeregistering)
                        {
                        if (rr->NewRData) CompleteRDataUpdate(m, rr);   // Update our rdata, clear the NewRData pointer, and return memory to the client
        
-                       if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
-                               CompleteDeregistration(m, rr);          // Don't touch rr after this
+                       if (rr->resrec.RecordType == kDNSRecordTypeDeregistering && rr->AnnounceCount == 0)
+                               {
+                               // For Unicast, when we get the response from the server, we will call CompleteDeregistration
+                               if (!AuthRecord_uDNS(rr)) CompleteDeregistration(m, rr);                // Don't touch rr after this
+                               }
                        else
                                {
                                rr->ImmedAnswer  = mDNSNULL;
@@ -3112,20 +2011,27 @@ mDNSlocal void SendResponses(mDNS *const m)
 // 5. For records with rroriginalttl set to zero, that means we really want to delete them immediately
 //    (we have a new record with DelayDelivery set, waiting for the old record to go away before we can notify clients).
 #define CacheCheckGracePeriod(RR) (                                                   \
-       ((RR)->DelayDelivery                           ) ? (mDNSPlatformOneSecond/10)   : \
        ((RR)->CRActiveQuestion == mDNSNULL            ) ? (60 * mDNSPlatformOneSecond) : \
        ((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50)            : \
        ((RR)->resrec.rroriginalttl > 10               ) ? (mDNSPlatformOneSecond)      : \
        ((RR)->resrec.rroriginalttl > 0                ) ? (mDNSPlatformOneSecond/10)   : 0)
 
-// Note: MUST call SetNextCacheCheckTime any time we change:
+#define NextCacheCheckEvent(RR) ((RR)->NextRequiredQuery + CacheCheckGracePeriod(RR))
+
+mDNSexport void ScheduleNextCacheCheckTime(mDNS *const m, const mDNSu32 slot, const mDNSs32 event)
+       {
+       if (m->rrcache_nextcheck[slot] - event > 0)
+               m->rrcache_nextcheck[slot] = event;
+       if (m->NextCacheCheck          - event > 0)
+               m->NextCacheCheck          = event;
+       }
+
+// Note: MUST call SetNextCacheCheckTimeForRecord any time we change:
 // rr->TimeRcvd
 // rr->resrec.rroriginalttl
 // rr->UnansweredQueries
 // rr->CRActiveQuestion
-// Also, any time we set rr->DelayDelivery we should call SetNextCacheCheckTime to ensure m->NextCacheCheck is set if necessary
-// Clearing rr->DelayDelivery does not require a call to SetNextCacheCheckTime
-mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr)
+mDNSlocal void SetNextCacheCheckTimeForRecord(mDNS *const m, CacheRecord *const rr)
        {
        rr->NextRequiredQuery = RRExpireTime(rr);
 
@@ -3135,17 +2041,11 @@ 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 CacheCheckGracePeriod %d ticks",
-                       rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype),
-                       (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr));
+               verbosedebugf("SetNextCacheCheckTimeForRecord: NextRequiredQuery in %ld sec CacheCheckGracePeriod %d ticks for %s",
+                       (rr->NextRequiredQuery - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m,rr));
                }
 
-       if (m->NextCacheCheck - (rr->NextRequiredQuery + CacheCheckGracePeriod(rr)) > 0)
-               m->NextCacheCheck = (rr->NextRequiredQuery + CacheCheckGracePeriod(rr));
-       
-       if (rr->DelayDelivery)
-               if (m->NextCacheCheck - rr->DelayDelivery > 0)
-                       m->NextCacheCheck = rr->DelayDelivery;
+       ScheduleNextCacheCheckTime(m, HashSlot(rr->resrec.name), NextCacheCheckEvent(rr));
        }
 
 #define kMinimumReconfirmTime                     ((mDNSu32)mDNSPlatformOneSecond *  5)
@@ -3170,7 +2070,7 @@ mDNSlocal mStatus mDNS_Reconfirm_internal(mDNS *const m, CacheRecord *const rr,
                interval += m->RandomReconfirmDelay % ((interval/3) + 1);
                rr->TimeRcvd          = m->timenow - (mDNSs32)interval * 3;
                rr->resrec.rroriginalttl     = (interval * 4 + mDNSPlatformOneSecond - 1) / mDNSPlatformOneSecond;
-               SetNextCacheCheckTime(m, rr);
+               SetNextCacheCheckTimeForRecord(m, rr);
                }
        debugf("mDNS_Reconfirm_internal:%6ld ticks to go for %s %p",
                RRExpireTime(rr) - m->timenow, CRDisplayString(m, rr), rr->CRActiveQuestion);
@@ -3204,12 +2104,19 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer
 
                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->resrec.RecordType & kDNSRecordTypeUniqueMask) &&          // which is a shared (i.e. not unique) record type
                                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
                                SameNameRecordAnswersQuestion(&rr->resrec, q) &&                        // which answers our question
                                rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >                            // and its half-way-to-expiry time is at least 1 second away
                                                                                                mDNSPlatformOneSecond)          // (also ensures we never include goodbye records with TTL=1)
                                {
+                               // We don't want to include unique records in the Known Answer section. The Known Answer section
+                               // is intended to suppress floods of shared-record replies from many other devices on the network.
+                               // That concept really does not apply to unique records, and indeed if we do send a query for
+                               // which we have a unique record already in our cache, then including that unique record as a
+                               // Known Answer, so as to suppress the only answer we were expecting to get, makes little sense.
+
                                *ka = rr;       // Link this record into our known answer chain
                                ka = &rr->NextInKAList;
                                // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
@@ -3240,7 +2147,7 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, DNSMessage *query, mDNSu8 **quer
                                        {
                                        rr->UnansweredQueries++;                                                                // indicate that we're expecting a response
                                        rr->LastUnansweredTime = m->timenow;
-                                       SetNextCacheCheckTime(m, rr);
+                                       SetNextCacheCheckTimeForRecord(m, rr);
                                        }
 
                return(mDNStrue);
@@ -3422,219 +2329,217 @@ mDNSlocal void SendQueries(mDNS *const m)
        CacheRecord *KnownAnswerList = mDNSNULL;
 
        // 1. If time for a query, work out what we need to do
-       if (m->timenow - m->NextScheduledQuery >= 0)
-               {
-               CacheRecord *rr;
 
-               // 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
-               FORALL_CACHERECORDS(slot, cg, rr)
-                       if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
-                               if (m->timenow + TicksTTL(rr)/50 - rr->NextRequiredQuery >= 0)
-                                       {
-                                       debugf("Sending %d%% cache expiration query for %s", 80 + 5 * rr->UnansweredQueries, CRDisplayString(m, rr));
-                                       q = rr->CRActiveQuestion;
-                                       ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(rr)/20, rr->resrec.InterfaceID);
-                                       // For uDNS queries (TargetQID non-zero) we adjust LastQTime,
-                                       // and bump UnansweredQueries so that we don't spin trying to send the same cache expiration query repeatedly
-                                       if      (q->Target.type)                        q->SendQNow = mDNSInterfaceMark;        // If targeted query, mark it
-                                       else if (!mDNSOpaque16IsZero(q->TargetQID))     { q->LastQTime = m->timenow - q->ThisQInterval; rr->UnansweredQueries++; }
-                                       else if (q->SendQNow == mDNSNULL)               q->SendQNow = rr->resrec.InterfaceID;
-                                       else if (q->SendQNow != rr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark;
-                                       }
+       // 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
+       FORALL_CACHERECORDS(slot, cg, cr)
+               if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries)
+                       if (m->timenow + TicksTTL(cr)/50 - cr->NextRequiredQuery >= 0)
+                               {
+                               debugf("Sending %d%% cache expiration query for %s", 80 + 5 * cr->UnansweredQueries, CRDisplayString(m, cr));
+                               q = cr->CRActiveQuestion;
+                               ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(cr)/20, cr->resrec.InterfaceID);
+                               // For uDNS queries (TargetQID non-zero) we adjust LastQTime,
+                               // and bump UnansweredQueries so that we don't spin trying to send the same cache expiration query repeatedly
+                               if      (q->Target.type)                        q->SendQNow = mDNSInterfaceMark;        // If targeted query, mark it
+                               else if (!mDNSOpaque16IsZero(q->TargetQID))     { q->LastQTime = m->timenow - q->ThisQInterval; cr->UnansweredQueries++; }
+                               else if (q->SendQNow == mDNSNULL)               q->SendQNow = cr->resrec.InterfaceID;
+                               else if (q->SendQNow != cr->resrec.InterfaceID) q->SendQNow = mDNSInterfaceMark;
+                               }
 
-               if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
-                       m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it
-                       
-               // Scan our list of questions to see which:
-               //     *WideArea*  queries need to be sent
-               //     *unicast*   queries need to be sent
-               //     *multicast* queries we're definitely going to send
-               if (m->CurrentQuestion)
-                       LogMsg("SendQueries ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
-               m->CurrentQuestion = m->Questions;
-               while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
+       // Scan our list of questions to see which:
+       //     *WideArea*  queries need to be sent
+       //     *unicast*   queries need to be sent
+       //     *multicast* queries we're definitely going to send
+       if (m->CurrentQuestion)
+               LogMsg("SendQueries ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+       m->CurrentQuestion = m->Questions;
+       while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
+               {
+               q = m->CurrentQuestion;
+               if (q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
                        {
-                       q = m->CurrentQuestion;
-                       if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID)) uDNS_CheckCurrentQuestion(m);
-                       else if (mDNSOpaque16IsZero(q->TargetQID) && q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
-                               {
-                               mDNSu8       *qptr        = m->omsg.data;
-                               const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
+                       mDNSu8       *qptr        = m->omsg.data;
+                       const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
 
-                               // If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion), we'll try again next time
-                               if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
-                               if (q->LocalSocket)
-                                       {
-                                       InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags);
-                                       qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass);
-                                       mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, q->LocalSocket, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL);
-                                       q->ThisQInterval    *= QuestionIntervalStep;
-                                       }
-                               if (q->ThisQInterval > MaxQuestionInterval)
-                                       q->ThisQInterval = MaxQuestionInterval;
-                               q->LastQTime         = m->timenow;
-                               q->LastQTxTime       = m->timenow;
-                               q->RecentAnswerPkts  = 0;
-                               q->SendQNow          = mDNSNULL;
-                               q->ExpectUnicastResp = NonZeroTime(m->timenow);
-                               }
-                       else if (mDNSOpaque16IsZero(q->TargetQID) && !q->Target.type && TimeToSendThisQuestion(q, m->timenow))
+                       // If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion), we'll try again next time
+                       if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
+                       if (q->LocalSocket)
                                {
-                               //LogInfo("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
-                               q->SendQNow = mDNSInterfaceMark;                // Mark this question for sending on all interfaces
-                               if (maxExistingQuestionInterval < q->ThisQInterval)
-                                       maxExistingQuestionInterval = q->ThisQInterval;
+                               InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags);
+                               qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass);
+                               mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, q->LocalSocket, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL);
+                               q->ThisQInterval    *= QuestionIntervalStep;
                                }
-                       // If m->CurrentQuestion wasn't modified out from under us, advance it now
-                       // We can't do this at the start of the loop because uDNS_CheckCurrentQuestion() depends on having
-                       // m->CurrentQuestion point to the right question
-                       if (q == m->CurrentQuestion) m->CurrentQuestion = m->CurrentQuestion->next;
-                       }
-               m->CurrentQuestion = mDNSNULL;
+                       if (q->ThisQInterval > MaxQuestionInterval)
+                               q->ThisQInterval = MaxQuestionInterval;
+                       q->LastQTime         = m->timenow;
+                       q->LastQTxTime       = m->timenow;
+                       q->RecentAnswerPkts  = 0;
+                       q->SendQNow          = mDNSNULL;
+                       q->ExpectUnicastResp = NonZeroTime(m->timenow);
+                       }
+               else if (mDNSOpaque16IsZero(q->TargetQID) && !q->Target.type && TimeToSendThisQuestion(q, m->timenow))
+                       {
+                       //LogInfo("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - NextQSendTime(q));
+                       q->SendQNow = mDNSInterfaceMark;                // Mark this question for sending on all interfaces
+                       if (maxExistingQuestionInterval < q->ThisQInterval)
+                               maxExistingQuestionInterval = q->ThisQInterval;
+                       }
+               // If m->CurrentQuestion wasn't modified out from under us, advance it now
+               // We can't do this at the start of the loop because uDNS_CheckCurrentQuestion() depends on having
+               // m->CurrentQuestion point to the right question
+               if (q == m->CurrentQuestion) m->CurrentQuestion = m->CurrentQuestion->next;
+               }
+       while (m->CurrentQuestion)
+               {
+               LogInfo("SendQueries question loop 1: Skipping NewQuestion %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+               m->CurrentQuestion = m->CurrentQuestion->next;
+               }
+       m->CurrentQuestion = mDNSNULL;
 
-               // 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
-               // Note: Don't set NextScheduledQuery until here, because uDNS_CheckCurrentQuestion in the loop above can add new questions to the list,
-               // which causes NextScheduledQuery to get (incorrectly) set to m->timenow. Setting it here is the right place, because the very
-               // next thing we do is scan the list and call SetNextQueryTime() for every question we find, so we know we end up with the right value.
-               m->NextScheduledQuery = m->timenow + 0x78000000;
-               for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
-                       {
-                       if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow ||
-                               (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q))))
+       // 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
+       // Note: Don't set NextScheduledQuery until here, because uDNS_CheckCurrentQuestion in the loop above can add new questions to the list,
+       // which causes NextScheduledQuery to get (incorrectly) set to m->timenow. Setting it here is the right place, because the very
+       // next thing we do is scan the list and call SetNextQueryTime() for every question we find, so we know we end up with the right value.
+       m->NextScheduledQuery = m->timenow + 0x78000000;
+       for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
+               {
+               if (mDNSOpaque16IsZero(q->TargetQID) && (q->SendQNow ||
+                       (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q))))
+                       {
+                       // If at least halfway to next query time, advance to next interval
+                       // If less than halfway to next query time, then
+                       // treat this as logically a repeat of the last transmission, without advancing the interval
+                       if (m->timenow - (q->LastQTime + (q->ThisQInterval/2)) >= 0)
                                {
-                               // If at least halfway to next query time, advance to next interval
-                               // If less than halfway to next query time, then
-                               // treat this as logically a repeat of the last transmission, without advancing the interval
-                               if (m->timenow - (q->LastQTime + q->ThisQInterval/2) >= 0)
+                               //LogInfo("Accelerating %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - NextQSendTime(q));
+                               q->SendQNow = mDNSInterfaceMark;        // Mark this question for sending on all interfaces
+                               debugf("SendQueries: %##s (%s) next interval %d seconds RequestUnicast = %d",
+                                       q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval / InitialQuestionInterval, q->RequestUnicast);
+                               q->ThisQInterval *= QuestionIntervalStep;
+                               if (q->ThisQInterval > MaxQuestionInterval)
+                                       q->ThisQInterval = MaxQuestionInterval;
+                               else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * QuestionIntervalStep3 && !q->RequestUnicast &&
+                                               !(RRTypeIsAddressType(q->qtype) && CacheHasAddressTypeForName(m, &q->qname, q->qnamehash)))
                                        {
-                                       //LogInfo("Accelerating %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - (q->LastQTime + q->ThisQInterval));
-                                       q->SendQNow = mDNSInterfaceMark;        // Mark this question for sending on all interfaces
-                                       debugf("SendQueries: %##s (%s) next interval %d seconds RequestUnicast = %d",
-                                               q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval / InitialQuestionInterval, q->RequestUnicast);
-                                       q->ThisQInterval *= QuestionIntervalStep;
-                                       if (q->ThisQInterval > MaxQuestionInterval)
-                                               q->ThisQInterval = MaxQuestionInterval;
-                                       else if (q->CurrentAnswers == 0 && q->ThisQInterval == InitialQuestionInterval * QuestionIntervalStep3 && !q->RequestUnicast &&
-                                                       !(RRTypeIsAddressType(q->qtype) && CacheHasAddressTypeForName(m, &q->qname, q->qnamehash)))
-                                               {
-                                               // Generally don't need to log this.
-                                               // It's not especially noteworthy if a query finds no results -- this usually happens for domain
-                                               // enumeration queries in the LL subdomain (e.g. "db._dns-sd._udp.0.0.254.169.in-addr.arpa")
-                                               // and when there simply happen to be no instances of the service the client is looking
-                                               // for (e.g. iTunes is set to look for RAOP devices, and the current network has none).
-                                               debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents",
-                                                       q->qname.c, DNSTypeName(q->qtype));
-                                               // Sending third query, and no answers yet; time to begin doubting the source
-                                               ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0);
-                                               }
+                                       // Generally don't need to log this.
+                                       // It's not especially noteworthy if a query finds no results -- this usually happens for domain
+                                       // enumeration queries in the LL subdomain (e.g. "db._dns-sd._udp.0.0.254.169.in-addr.arpa")
+                                       // and when there simply happen to be no instances of the service the client is looking
+                                       // for (e.g. iTunes is set to look for RAOP devices, and the current network has none).
+                                       debugf("SendQueries: Zero current answers for %##s (%s); will reconfirm antecedents",
+                                               q->qname.c, DNSTypeName(q->qtype));
+                                       // Sending third query, and no answers yet; time to begin doubting the source
+                                       ReconfirmAntecedents(m, &q->qname, q->qnamehash, 0);
                                        }
+                               }
 
-                               // Mark for sending. (If no active interfaces, then don't even try.)
-                               q->SendOnAll = (q->SendQNow == mDNSInterfaceMark);
-                               if (q->SendOnAll)
-                                       {
-                                       q->SendQNow  = !intf ? mDNSNULL : (q->InterfaceID) ? q->InterfaceID : intf->InterfaceID;
-                                       q->LastQTime = m->timenow;
-                                       }
+                       // Mark for sending. (If no active interfaces, then don't even try.)
+                       q->SendOnAll = (q->SendQNow == mDNSInterfaceMark);
+                       if (q->SendOnAll)
+                               {
+                               q->SendQNow  = !intf ? mDNSNULL : (q->InterfaceID) ? q->InterfaceID : intf->InterfaceID;
+                               q->LastQTime = m->timenow;
+                               }
 
-                               // If we recorded a duplicate suppression for this question less than half an interval ago,
-                               // then we consider it recent enough that we don't need to do an identical query ourselves.
-                               ExpireDupSuppressInfo(q->DupSuppress, m->timenow - q->ThisQInterval/2);
+                       // If we recorded a duplicate suppression for this question less than half an interval ago,
+                       // then we consider it recent enough that we don't need to do an identical query ourselves.
+                       ExpireDupSuppressInfo(q->DupSuppress, m->timenow - q->ThisQInterval/2);
 
-                               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);
+                       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
+               // We don't need to consider NewQuestions here because for those we'll set m->NextScheduledQuery in AnswerNewQuestion
+               SetNextQueryTime(m,q);
                }
 
        // 2. Scan our authoritative RR list to see what probes we might need to send
-       if (m->timenow - m->NextScheduledProbe >= 0)
-               {
-               m->NextScheduledProbe = m->timenow + 0x78000000;
 
-               if (m->CurrentRecord)
-                       LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
-               m->CurrentRecord = m->ResourceRecords;
-               while (m->CurrentRecord)
+       m->NextScheduledProbe = m->timenow + 0x78000000;
+
+       if (m->CurrentRecord)
+               LogMsg("SendQueries ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
+       m->CurrentRecord = m->ResourceRecords;
+       while (m->CurrentRecord)
+               {
+               ar = m->CurrentRecord;
+               m->CurrentRecord = ar->next;
+               if (!AuthRecord_uDNS(ar) && ar->resrec.RecordType == kDNSRecordTypeUnique)      // For all records that are still probing...
                        {
-                       AuthRecord *rr = m->CurrentRecord;
-                       m->CurrentRecord = rr->next;
-                       if (!AuthRecord_uDNS(rr) && rr->resrec.RecordType == kDNSRecordTypeUnique)      // For all records that are still probing...
+                       // 1. If it's not reached its probe time, just make sure we update m->NextScheduledProbe correctly
+                       if (m->timenow - (ar->LastAPTime + ar->ThisAPInterval) < 0)
                                {
-                               // 1. If it's not reached its probe time, just make sure we update m->NextScheduledProbe correctly
-                               if (m->timenow - (rr->LastAPTime + rr->ThisAPInterval) < 0)
+                               SetNextAnnounceProbeTime(m, ar);
+                               }
+                       // 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly
+                       else if (ar->ProbeCount)
+                               {
+                               if (ar->AddressProxy.type == mDNSAddrType_IPv4)
                                        {
-                                       SetNextAnnounceProbeTime(m, rr);
+                                       LogSPS("SendQueries ARP Probe %d %s %s", ar->ProbeCount, InterfaceNameForID(m, ar->resrec.InterfaceID), ARDisplayString(m,ar));
+                                       SendARP(m, 1, ar, &zerov4Addr, &zeroEthAddr, &ar->AddressProxy.ip.v4, &ar->WakeUp.IMAC);
                                        }
-                               // 2. else, if it has reached its probe time, mark it for sending and then update m->NextScheduledProbe correctly
-                               else if (rr->ProbeCount)
+                               else if (ar->AddressProxy.type == mDNSAddrType_IPv6)
                                        {
-                                       if (rr->AddressProxy.type == mDNSAddrType_IPv4)
-                                               {
-                                               char *ifname = InterfaceNameForID(m, rr->resrec.InterfaceID);
-                                               if (!ifname) ifname = "<NULL InterfaceID>";
-                                               LogSPS("SendQueries ARP Probe %d %s %s", rr->ProbeCount, ifname, ARDisplayString(m,rr));
-                                               SendARP(m, 1, rr, zerov4Addr.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, rr->WakeUp.IMAC.b);
-                                               }
-                                       else if (rr->AddressProxy.type == mDNSAddrType_IPv6)
-                                               {
-                                               //LogSPS("SendQueries NDP Probe %d %s", rr->ProbeCount, ARDisplayString(m,rr));
-                                               //SendARP(m, 1, rr, rr->AddressProxy.ip.v4.b, zeroEthAddr.b, rr->AddressProxy.ip.v4.b, onesEthAddr.b);
-                                               }
-                                       // Mark for sending. (If no active interfaces, then don't even try.)
-                                       rr->SendRNow   = (!intf || rr->WakeUp.HMAC.l[0]) ? mDNSNULL : rr->resrec.InterfaceID ? rr->resrec.InterfaceID : intf->InterfaceID;
-                                       rr->LastAPTime = m->timenow;
-                                       // When we have a late conflict that resets a record to probing state we use a special marker value greater
-                                       // than DefaultProbeCountForTypeUnique. Here we detect that state and reset rr->ProbeCount back to the right value.
-                                       if (rr->ProbeCount > DefaultProbeCountForTypeUnique)
-                                               rr->ProbeCount = DefaultProbeCountForTypeUnique;
-                                       rr->ProbeCount--;
-                                       SetNextAnnounceProbeTime(m, rr);
-                                       if (rr->ProbeCount == 0)
-                                               {
-                                               // If this is the last probe for this record, then see if we have any matching records
-                                               // on our duplicate list which should similarly have their ProbeCount cleared to zero...
-                                               AuthRecord *r2;
-                                               for (r2 = m->DuplicateRecords; r2; r2=r2->next)
-                                                       if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, rr))
-                                                               r2->ProbeCount = 0;
-                                               // ... then acknowledge this record to the client.
-                                               // We do this optimistically, just as we're about to send the third probe.
-                                               // This helps clients that both advertise and browse, and want to filter themselves
-                                               // from the browse results list, because it helps ensure that the registration
-                                               // confirmation will be delivered 1/4 second *before* the browse "add" event.
-                                               // A potential downside is that we could deliver a registration confirmation and then find out
-                                               // moments later that there's a name conflict, but applications have to be prepared to handle
-                                               // late conflicts anyway (e.g. on connection of network cable, etc.), so this is nothing new.
-                                               if (!rr->Acknowledged) AcknowledgeRecord(m, rr);
-                                               }
+                                       LogSPS("SendQueries NDP Probe %d %s %s", ar->ProbeCount, InterfaceNameForID(m, ar->resrec.InterfaceID), ARDisplayString(m,ar));
+                                       // IPv6 source = zero
+                                       // No target hardware address
+                                       // IPv6 target address is address we're probing
+                                       // Ethernet destination address is Ethernet interface address of the Sleep Proxy client we're probing
+                                       SendNDP(m, NDP_Sol, 0, ar, &zerov6Addr, mDNSNULL, &ar->AddressProxy.ip.v6, &ar->WakeUp.IMAC);
                                        }
-                               // else, if it has now finished probing, move it to state Verified,
-                               // and update m->NextScheduledResponse so it will be announced
-                               else
+                               // Mark for sending. (If no active interfaces, then don't even try.)
+                               ar->SendRNow   = (!intf || ar->WakeUp.HMAC.l[0]) ? mDNSNULL : ar->resrec.InterfaceID ? ar->resrec.InterfaceID : intf->InterfaceID;
+                               ar->LastAPTime = m->timenow;
+                               // When we have a late conflict that resets a record to probing state we use a special marker value greater
+                               // than DefaultProbeCountForTypeUnique. Here we detect that state and reset ar->ProbeCount back to the right value.
+                               if (ar->ProbeCount > DefaultProbeCountForTypeUnique)
+                                       ar->ProbeCount = DefaultProbeCountForTypeUnique;
+                               ar->ProbeCount--;
+                               SetNextAnnounceProbeTime(m, ar);
+                               if (ar->ProbeCount == 0)
                                        {
-                                       if (!rr->Acknowledged) AcknowledgeRecord(m, rr);        // Defensive, just in case it got missed somehow
-                                       rr->resrec.RecordType     = kDNSRecordTypeVerified;
-                                       rr->ThisAPInterval = DefaultAnnounceIntervalForTypeUnique;
-                                       rr->LastAPTime     = m->timenow - DefaultAnnounceIntervalForTypeUnique;
-                                       SetNextAnnounceProbeTime(m, rr);
+                                       // If this is the last probe for this record, then see if we have any matching records
+                                       // on our duplicate list which should similarly have their ProbeCount cleared to zero...
+                                       AuthRecord *r2;
+                                       for (r2 = m->DuplicateRecords; r2; r2=r2->next)
+                                               if (r2->resrec.RecordType == kDNSRecordTypeUnique && RecordIsLocalDuplicate(r2, ar))
+                                                       r2->ProbeCount = 0;
+                                       // ... then acknowledge this record to the client.
+                                       // We do this optimistically, just as we're about to send the third probe.
+                                       // This helps clients that both advertise and browse, and want to filter themselves
+                                       // from the browse results list, because it helps ensure that the registration
+                                       // confirmation will be delivered 1/4 second *before* the browse "add" event.
+                                       // A potential downside is that we could deliver a registration confirmation and then find out
+                                       // moments later that there's a name conflict, but applications have to be prepared to handle
+                                       // late conflicts anyway (e.g. on connection of network cable, etc.), so this is nothing new.
+                                       if (!ar->Acknowledged) AcknowledgeRecord(m, ar);
                                        }
                                }
+                       // else, if it has now finished probing, move it to state Verified,
+                       // and update m->NextScheduledResponse so it will be announced
+                       else
+                               {
+                               if (!ar->Acknowledged) AcknowledgeRecord(m, ar);        // Defensive, just in case it got missed somehow
+                               ar->resrec.RecordType     = kDNSRecordTypeVerified;
+                               ar->ThisAPInterval = DefaultAnnounceIntervalForTypeUnique;
+                               ar->LastAPTime     = m->timenow - DefaultAnnounceIntervalForTypeUnique;
+                               SetNextAnnounceProbeTime(m, ar);
+                               }
                        }
-               m->CurrentRecord = m->DuplicateRecords;
-               while (m->CurrentRecord)
-                       {
-                       AuthRecord *rr = m->CurrentRecord;
-                       m->CurrentRecord = rr->next;
-                       if (rr->resrec.RecordType == kDNSRecordTypeUnique && rr->ProbeCount == 0 && !rr->Acknowledged)
-                               AcknowledgeRecord(m, rr);
-                       }
+               }
+       m->CurrentRecord = m->DuplicateRecords;
+       while (m->CurrentRecord)
+               {
+               ar = m->CurrentRecord;
+               m->CurrentRecord = ar->next;
+               if (ar->resrec.RecordType == kDNSRecordTypeUnique && ar->ProbeCount == 0 && !ar->Acknowledged)
+                       AcknowledgeRecord(m, ar);
                }
 
        // 3. Now we know which queries and probes we're sending,
@@ -3642,7 +2547,6 @@ mDNSlocal void SendQueries(mDNS *const m)
        while (intf)
                {
                const int OwnerRecordSpace = (m->AnnounceOwner && intf->MAC.l[0]) ? DNSOpt_Header_Space + DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC) : 0;
-               AuthRecord *rr;
                mDNSu8 *queryptr = m->omsg.data;
                InitializeDNSMessage(&m->omsg.h, zeroID, QueryFlags);
                if (KnownAnswerList) verbosedebugf("SendQueries:   KnownAnswerList set... Will continue from previous packet");
@@ -3669,23 +2573,23 @@ mDNSlocal void SendQueries(mDNS *const m)
                                }
 
                        // Put probe questions in this packet
-                       for (rr = m->ResourceRecords; rr; rr=rr->next)
-                               if (rr->SendRNow == intf->InterfaceID)
+                       for (ar = m->ResourceRecords; ar; ar=ar->next)
+                               if (ar->SendRNow == intf->InterfaceID)
                                        {
-                                       mDNSBool ucast = (rr->ProbeCount >= DefaultProbeCountForTypeUnique-1) && m->CanReceiveUnicastOn5353;
+                                       mDNSBool ucast = (ar->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);
                                        // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
-                                       mDNSu32 forecast = answerforecast + 12 + rr->resrec.rdestimate;
-                                       mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit - forecast, rr->resrec.name, kDNSQType_ANY, (mDNSu16)(rr->resrec.rrclass | ucbit));
+                                       mDNSu32 forecast = answerforecast + 12 + ar->resrec.rdestimate;
+                                       mDNSu8 *newptr = putQuestion(&m->omsg, queryptr, limit - forecast, ar->resrec.name, kDNSQType_ANY, (mDNSu16)(ar->resrec.rrclass | ucbit));
                                        if (newptr)
                                                {
                                                queryptr       = newptr;
                                                answerforecast = forecast;
-                                               rr->SendRNow = (rr->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
-                                               rr->IncludeInProbe = mDNStrue;
+                                               ar->SendRNow = (ar->resrec.InterfaceID) ? mDNSNULL : GetNextActiveInterfaceID(intf);
+                                               ar->IncludeInProbe = mDNStrue;
                                                verbosedebugf("SendQueries:   Put Question %##s (%s) probecount %d",
-                                                       rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->ProbeCount);
+                                                       ar->resrec.name->c, DNSTypeName(ar->resrec.rrtype), ar->ProbeCount);
                                                }
                                        }
                        }
@@ -3716,13 +2620,13 @@ mDNSlocal void SendQueries(mDNS *const m)
                                }
                        }
 
-               for (rr = m->ResourceRecords; rr; rr=rr->next)
-                       if (rr->IncludeInProbe)
+               for (ar = m->ResourceRecords; ar; ar=ar->next)
+                       if (ar->IncludeInProbe)
                                {
-                               mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, &rr->resrec);
-                               rr->IncludeInProbe = mDNSfalse;
+                               mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, &ar->resrec);
+                               ar->IncludeInProbe = mDNSfalse;
                                if (newptr) queryptr = newptr;
-                               else LogMsg("SendQueries:   How did we fail to have space for the Update record %s", ARDisplayString(m,rr));
+                               else LogMsg("SendQueries:   How did we fail to have space for the Update record %s", ARDisplayString(m,ar));
                                }
 
                if (queryptr > m->omsg.data)
@@ -3779,8 +2683,8 @@ mDNSlocal void SendQueries(mDNS *const m)
        for (ar = m->ResourceRecords; ar; ar=ar->next)
                if (ar->SendRNow)
                        {
-                       if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly)
-                               LogMsg("SendQueries: No active interface to send: %s", ARDisplayString(m, ar));
+                       if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly && ar->resrec.InterfaceID != mDNSInterface_P2P)
+                               LogMsg("SendQueries: No active interface %p to send probe: %p %s", ar->SendRNow, ar->resrec.InterfaceID, ARDisplayString(m, ar));
                        ar->SendRNow = mDNSNULL;
                        }
 
@@ -3790,12 +2694,13 @@ mDNSlocal void SendQueries(mDNS *const m)
        // state machine ticking over we just pretend we did so.
        // If the interface does not come back in time, the cache record will expire naturally
        FORALL_CACHERECORDS(slot, cg, cr)
-               if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries && m->timenow - cr->NextRequiredQuery >= 0)
-                       {
-                       cr->UnansweredQueries++;
-                       cr->CRActiveQuestion->SendQNow = mDNSNULL;
-                       SetNextCacheCheckTime(m, cr);
-                       }
+               if (cr->CRActiveQuestion && cr->UnansweredQueries < MaxUnansweredQueries)
+                       if (m->timenow + TicksTTL(cr)/50 - cr->NextRequiredQuery >= 0)
+                               {
+                               cr->UnansweredQueries++;
+                               cr->CRActiveQuestion->SendQNow = mDNSNULL;
+                               SetNextCacheCheckTimeForRecord(m, cr);
+                               }
 
        // 4c. Debugging check: Make sure we sent all our planned questions
        // Do this AFTER the lingering cache records check above, because that will prevent spurious warnings for questions
@@ -3803,7 +2708,9 @@ mDNSlocal void SendQueries(mDNS *const m)
        for (q = m->Questions; q; q=q->next)
                if (q->SendQNow)
                        {
-                       LogMsg("SendQueries: No active interface to send: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+                       DNSQuestion *x;
+                       for (x = m->NewQuestions; x; x=x->next) if (x == q) break;      // Check if this question is a NewQuestion
+                       LogMsg("SendQueries: No active interface %p to send %s question: %p %##s (%s)", q->SendQNow, x ? "new" : "old", q->InterfaceID, q->qname.c, DNSTypeName(q->qtype));
                        q->SendQNow = mDNSNULL;
                        }
        }
@@ -3812,14 +2719,14 @@ mDNSlocal void SendWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAdd
        {
        int i, j;
        mDNSu8 *ptr = m->omsg.data;
-
-       if (!InterfaceID) { LogMsg("SendWakeup: No InterfaceID specified"); return; }
+       NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
+       if (!intf) { LogMsg("SendARP: No interface with InterfaceID %p found", InterfaceID); return; }
 
        // 0x00 Destination address
        for (i=0; i<6; i++) *ptr++ = EthAddr->b[i];
 
-       // 0x06 Source address (we just use zero -- BPF will fill in real interface address)
-       for (i=0; i<6; i++) *ptr++ = 0x0;
+       // 0x06 Source address (Note: Since we don't currently set the BIOCSHDRCMPLT option, BPF will fill in the real interface address for us)
+       for (i=0; i<6; i++) *ptr++ = intf->MAC.b[0];
 
        // 0x0C Ethertype (0x0842)
        *ptr++ = 0x08;
@@ -3860,7 +2767,10 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
        DNSQuestion *const q = m->CurrentQuestion;
        mDNSBool followcname = rr->resrec.RecordType != kDNSRecordTypePacketNegative && AddRecord &&
                                                        rr->resrec.rrtype == kDNSType_CNAME && q->qtype != kDNSType_CNAME;
-       verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s", q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, CRDisplayString(m, rr));
+       verbosedebugf("AnswerCurrentQuestionWithResourceRecord:%4lu %s TTL %d %s",
+               q->CurrentAnswers, AddRecord ? "Add" : "Rmv", rr->resrec.rroriginalttl, CRDisplayString(m, rr));
+
+       if (QuerySuppressed(q)) return;
 
        // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue)
        // may be called twice, once when the record is received, and again when it's time to notify local clients.
@@ -3870,9 +2780,10 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
        if (AddRecord == QC_add && !q->DuplicateOf && rr->CRActiveQuestion != q)
                {
                if (!rr->CRActiveQuestion) m->rrcache_active++; // If not previously active, increment rrcache_active count
-               debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr));
+               debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion from %p to %p for cache record %s, CurrentAnswer %d",
+                       rr->CRActiveQuestion, q, CRDisplayString(m,rr), q->CurrentAnswers);
                rr->CRActiveQuestion = q;                                               // We know q is non-null
-               SetNextCacheCheckTime(m, rr);
+               SetNextCacheCheckTimeForRecord(m, rr);
                }
 
        // If this is:
@@ -3907,52 +2818,136 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
                if (q->qtype != kDNSType_NSEC && RRAssertsNonexistence(&rr->resrec, q->qtype))
                        {
                        CacheRecord neg;
-                       MakeNegativeCacheRecord(m, &neg, &q->qname, q->qnamehash, q->qtype, q->qclass, 1, rr->resrec.InterfaceID);
+                       MakeNegativeCacheRecord(m, &neg, &q->qname, q->qnamehash, q->qtype, q->qclass, 1, rr->resrec.InterfaceID, q->qDNSServer);
                        q->QuestionCallback(m, q, &neg.resrec, AddRecord);
                        }
-               else
-                       q->QuestionCallback(m, q, &rr->resrec, AddRecord);
-               mDNS_ReclaimLockAfterCallback();        // Decrement mDNS_reentrancy to block mDNS API calls again
-               }
-       // Note: Proceed with caution here because client callback function is allowed to do anything,
-       // including starting/stopping queries, registering/deregistering records, etc.
-
-       if (followcname && m->CurrentQuestion == q && q->CNAMEReferrals < 10)
-               {
-               const mDNSu32 c = q->CNAMEReferrals + 1;
-               // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect,
-               // and track CNAMEs coming and going, we should really create a subordinate query here,
-               // which we would subsequently cancel and retract if the CNAME referral record were removed.
-               // In reality this is such a corner case we'll ignore it until someone actually needs it.
-               LogInfo("AnswerCurrentQuestionWithResourceRecord: following CNAME referral for %s", CRDisplayString(m, rr));
-               
-               // If this query is a duplicate of another query, UpdateQuestionDuplicates called from
-               // mDNS_StopQuery_internal copies the value of CNAMEReferrals from this query to the other
-               // query on the Questions list. By setting the new value before calling mDNS_StopQuery_internal,
-               // we ensure that the duplicate question gets a hgigher value and eventually the check for 10 above
-               // would be true. Otherwise, the two queries would end up as active questions
-               // sending mDNSResponder in an infinite loop e.g., Two queries starting off unique but receives
-               // a CNAME response that refers to itself (test IN CNAME test) which makes it a duplicate of
-               // one another. This fix now will make sure that stop at the 10th iteration. 
-               //
-               // Though CNAME records that refer to itself are not added anymore in mDNSCoreReceiveResponse, this fix is
-               // still needed to catch the cases where the CNAME referral spans across multiple records with a potential
-               // cycle in it which in turn can make multiple queries duplicate of each other
-               
-               q->CNAMEReferrals = c;  
-               mDNS_StopQuery_internal(m, q);                                                          // Stop old query
-               AssignDomainName(&q->qname, &rr->resrec.rdata->u.name);         // Update qname
-               q->qnamehash = DomainNameHashValue(&q->qname);                          // and namehash
-               mDNS_StartQuery_internal(m, q);                                                         // start new query
-               q->CNAMEReferrals = c;                                                                          // and keep count of how many times we've done this
+               else
+                       q->QuestionCallback(m, q, &rr->resrec, AddRecord);
+               mDNS_ReclaimLockAfterCallback();        // Decrement mDNS_reentrancy to block mDNS API calls again
+               }
+       // Note: Proceed with caution here because client callback function is allowed to do anything,
+       // including starting/stopping queries, registering/deregistering records, etc.
+
+       if (followcname && m->CurrentQuestion == q)
+               {
+               const mDNSBool selfref = SameDomainName(&q->qname, &rr->resrec.rdata->u.name);
+               if (q->CNAMEReferrals >= 10 || selfref)
+                       LogMsg("AnswerCurrentQuestionWithResourceRecord: %p %##s (%s) NOT following CNAME referral %d%s for %s",
+                               q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, selfref ? " (Self-Referential)" : "", CRDisplayString(m, rr));
+               else
+                       {
+                       const mDNSu32 c = q->CNAMEReferrals + 1;                // Stash a copy of the new q->CNAMEReferrals value
+
+                       // The SameDomainName check above is to ignore bogus CNAME records that point right back at
+                       // themselves. Without that check we can get into a case where we have two duplicate questions,
+                       // A and B, and when we stop question A, UpdateQuestionDuplicates copies the value of CNAMEReferrals
+                       // from A to B, and then A is re-appended to the end of the list as a duplicate of B (because
+                       // the target name is still the same), and then when we stop question B, UpdateQuestionDuplicates
+                       // copies the B's value of CNAMEReferrals back to A, and we end up not incrementing CNAMEReferrals
+                       // for either of them. This is not a problem for CNAME loops of two or more records because in
+                       // those cases the newly re-appended question A has a different target name and therefore cannot be
+                       // a duplicate of any other question ('B') which was itself a duplicate of the previous question A.
+
+                       // Right now we just stop and re-use the existing query. If we really wanted to be 100% perfect,
+                       // and track CNAMEs coming and going, we should really create a subordinate query here,
+                       // which we would subsequently cancel and retract if the CNAME referral record were removed.
+                       // In reality this is such a corner case we'll ignore it until someone actually needs it.
+                       LogInfo("AnswerCurrentQuestionWithResourceRecord: %p %##s (%s) following CNAME referral %d for %s",
+                               q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, CRDisplayString(m, rr));
+
+                       mDNS_StopQuery_internal(m, q);                                                          // Stop old query
+                       AssignDomainName(&q->qname, &rr->resrec.rdata->u.name);         // Update qname
+                       q->qnamehash = DomainNameHashValue(&q->qname);                          // and namehash
+                       mDNS_StartQuery_internal(m, q);                                                         // start new query
+                       // Record how many times we've done this. We need to do this *after* mDNS_StartQuery_internal,
+                       // because mDNS_StartQuery_internal re-initializes CNAMEReferrals to zero
+                       q->CNAMEReferrals = c;
+                       }
+               }
+       }
+
+// New Questions are answered through AnswerNewQuestion. But there may not have been any
+// matching cache records for the questions when it is called. There are two possibilities.
+//
+// 1) There are no cache records
+// 2) There are cache records but the DNSServers between question and cache record don't match.
+//
+// In the case of (1), where there are no cache records and later we add them when we get a response,
+// CacheRecordAdd/CacheRecordDeferredAdd will take care of adding the cache and delivering the ADD
+// events to the application. If we already have a cache entry, then no ADD events are delivered
+// unless the RDATA has changed
+//
+// In the case of (2) where we had the cache records and did not answer because of the DNSServer mismatch,
+// we need to answer them whenever we change the DNSServer.  But we can't do it at the instant the DNSServer
+// changes because when we do the callback, the question can get deleted and the calling function would not
+// know how to handle it. So, we run this function from mDNS_Execute to handle DNSServer changes on the
+// question
+
+mDNSlocal void AnswerQuestionsForDNSServerChanges(mDNS *const m)
+       {
+       DNSQuestion *q;
+       DNSQuestion *qnext;
+       CacheRecord *rr;
+       mDNSu32 slot;
+       CacheGroup *cg;
+
+       if (m->CurrentQuestion)
+               LogMsg("AnswerQuestionsForDNSServerChanges: ERROR m->CurrentQuestion already set: %##s (%s)",
+                               m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+
+       for (q = m->Questions; q && q != m->NewQuestions; q = qnext)
+               {
+               qnext = q->next;
+
+               // multicast or DNSServers did not change.
+               if (mDNSOpaque16IsZero(q->TargetQID)) continue;
+               if (!q->deliverAddEvents) continue;
+
+               // We are going to look through the cache for this question since it changed
+               // its DNSserver last time. Reset it so that we don't call them again. Calling
+               // them again will deliver duplicate events to the application
+               q->deliverAddEvents = mDNSfalse;
+               if (QuerySuppressed(q)) continue;
+               m->CurrentQuestion = q;
+               slot = HashSlot(&q->qname);
+               cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+               for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+                       {
+                       if (SameNameRecordAnswersQuestion(&rr->resrec, q))
+                               {
+                               LogInfo("AnswerQuestionsForDNSServerChanges: Calling AnswerCurrentQuestionWithResourceRecord for question %p %##s using resource record %s",
+                                       q, q->qname.c, CRDisplayString(m, rr));
+                               // When this question penalizes a DNS server and has no more DNS servers to pick, we normally
+                               // deliver a negative cache response and suspend the question for 60 seconds (see uDNS_CheckCurrentQuestion).
+                               // But sometimes we may already find the negative cache entry and deliver that here as the process
+                               // of changing DNS servers. When the cache entry is about to expire, we will resend the question and
+                               // that time, we need to make sure that we have a valid DNS server. Otherwise, we will deliver
+                               // a negative cache response without trying the server.
+                               if (!q->qDNSServer && !q->DuplicateOf && rr->resrec.RecordType == kDNSRecordTypePacketNegative)
+                                       {
+                                       DNSQuestion *qptr;
+                                       SetValidDNSServers(m, q);
+                                       q->qDNSServer = GetServerForQuestion(m, q);
+                                       for (qptr = q->next ; qptr; qptr = qptr->next)
+                                               if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; }
+                                       }
+                               q->CurrentAnswers++;
+                               if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
+                               if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
+                               AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
+                               if (m->CurrentQuestion != q) break;             // If callback deleted q, then we're finished here
+                               }
+                       }
                }
+               m->CurrentQuestion = mDNSNULL;
        }
 
 mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
        {
-       rr->DelayDelivery = 0;          // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
+       rr->DelayDelivery = 0;
        if (m->CurrentQuestion)
-               LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+               LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)",
+                       m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
        m->CurrentQuestion = m->Questions;
        while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
                {
@@ -3980,7 +2975,7 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *c
        else return(0);
        }
 
-// CacheRecordAdd is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
+// CacheRecordAdd is only called from CreateNewCacheEntry, *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 into our cache
@@ -4017,8 +3012,10 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
                                        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 %#a:%d question %p", rr, rr->resrec.name->c,
+                               DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl, rr->resrec.rDNSServer ?
+                               &rr->resrec.rDNSServer->addr : mDNSNULL, mDNSVal16(rr->resrec.rDNSServer ?
+                               rr->resrec.rDNSServer->port : zeroIPPort), q);
                        q->CurrentAnswers++;
                        q->unansweredQueries = 0;
                        if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
@@ -4051,7 +3048,7 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
                m->CurrentQuestion = mDNSNULL;
                }
 
-       SetNextCacheCheckTime(m, rr);
+       SetNextCacheCheckTimeForRecord(m, rr);
        }
 
 // NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
@@ -4095,7 +3092,8 @@ mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
 mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
        {
        if (m->CurrentQuestion)
-               LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+               LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)",
+                       m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
        m->CurrentQuestion = m->Questions;
 
        // We stop when we get to NewQuestions -- for new questions their CurrentAnswers/LargeAnswers/UniqueAnswers counters
@@ -4103,14 +3101,31 @@ mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
        while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
                {
                DNSQuestion *q = m->CurrentQuestion;
-               if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+               // When a question enters suppressed state, we generate RMV events and generate a negative
+               // response. A cache may be present that answers this question e.g., cache entry generated
+               // before the question became suppressed. We need to skip the suppressed questions here as
+               // the RMV event has already been generated.
+               if (!QuerySuppressed(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
                        {
                        verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr));
                        q->FlappingInterface1 = mDNSNULL;
                        q->FlappingInterface2 = mDNSNULL;
+               
+                       // When a question changes DNS server, it is marked with deliverAddEvents if we find any
+                       // cache entry corresponding to the new DNS server. Before we deliver the ADD event, the
+                       // cache entry may be removed in which case CurrentAnswers can be zero.
+                       if (q->deliverAddEvents && !q->CurrentAnswers)
+                               {
+                               LogInfo("CacheRecordRmv: Question %p %##s (%s) deliverAddEvents set, DNSServer %#a:%d",
+                                       q, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL,
+                                       mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort));
+                               m->CurrentQuestion = q->next;
+                               continue;
+                               }
                        if (q->CurrentAnswers == 0)
-                               LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?",
-                                       q, q->qname.c, DNSTypeName(q->qtype));
+                               LogMsg("CacheRecordRmv ERROR!!: How can CurrentAnswers already be zero for %p %##s (%s) DNSServer %#a:%d",
+                                       q, q->qname.c, DNSTypeName(q->qtype), q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL,
+                                       mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort));
                        else
                                {
                                q->CurrentAnswers--;
@@ -4170,7 +3185,7 @@ mDNSlocal void ReleaseCacheRecord(mDNS *const m, CacheRecord *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, CacheGroup *const cg)
+mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGroup *const cg)
        {
        CacheRecord **rp = &cg->members;
 
@@ -4188,6 +3203,20 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg)
                                m->timenow - rr->TimeRcvd, rr->resrec.rroriginalttl, rr->CRActiveQuestion, CRDisplayString(m, rr));
                        if (rr->CRActiveQuestion)       // If this record has one or more active questions, tell them it's going away
                                {
+                               DNSQuestion *q = rr->CRActiveQuestion;
+                               // When a cache record is about to expire, we expect to do four queries at 80-82%, 85-87%, 90-92% and
+                               // then 95-97% of the TTL. If the DNS server does not respond, then we will remove the cache entry
+                               // before we pick a new DNS server. As the question interval is set to MaxQuestionInterval, we may
+                               // not send out a query anytime soon. Hence, we need to reset the question interval. If this is
+                               // a normal deferred ADD case, then AnswerCurrentQuestionWithResourceRecord will reset it to
+                               // MaxQuestionInterval. If we have inactive questions referring to negative cache entries,
+                               // don't ressurect them as they will deliver duplicate "No such Record" ADD events
+                               if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && ActiveQuestion(q))
+                                       {
+                                       q->ThisQInterval = InitialQuestionInterval;
+                                       q->LastQTime     = m->timenow - q->ThisQInterval;
+                                       SetNextQueryTime(m, q);
+                                       }
                                CacheRecordRmv(m, rr);
                                m->rrcache_active--;
                                }
@@ -4195,6 +3224,7 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg)
                        }
                else                                                    // else, not expired; see if we need to query
                        {
+                       // If waiting to delay delivery, do nothing until then
                        if (rr->DelayDelivery && rr->DelayDelivery - m->timenow > 0)
                                event = rr->DelayDelivery;
                        else
@@ -4203,13 +3233,13 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg)
                                if (rr->CRActiveQuestion && rr->UnansweredQueries < MaxUnansweredQueries)
                                        {
                                        if (m->timenow - rr->NextRequiredQuery < 0)             // If not yet time for next query
-                                               event = rr->NextRequiredQuery;                          // then just record when we want the next query
+                                               event = NextCacheCheckEvent(rr);                        // then just record when we want the next query
                                        else                                                                                    // else trigger our question to go out now
                                                {
                                                // Set NextScheduledQuery to timenow so that SendQueries() will run.
                                                // SendQueries() will see that we have records close to expiration, and send FEQs for them.
                                                m->NextScheduledQuery = m->timenow;
-                                               // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTime(),
+                                               // After sending the query we'll increment UnansweredQueries and call SetNextCacheCheckTimeForRecord(),
                                                // which will correctly update m->NextCacheCheck for us.
                                                event = m->timenow + 0x3FFFFFFF;
                                                }
@@ -4217,8 +3247,8 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg)
                                }
                        verbosedebugf("CheckCacheExpiration:%6d %5d %s",
                                (event - m->timenow) / mDNSPlatformOneSecond, CacheCheckGracePeriod(rr), CRDisplayString(m, rr));
-                       if (m->NextCacheCheck - (event + CacheCheckGracePeriod(rr)) > 0)
-                               m->NextCacheCheck = (event + CacheCheckGracePeriod(rr));
+                       if (m->rrcache_nextcheck[slot] - event > 0)
+                               m->rrcache_nextcheck[slot] = event;
                        rp = &rr->next;
                        }
                }
@@ -4227,18 +3257,48 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, CacheGroup *const cg)
        m->lock_rrcache = 0;
        }
 
+// Caller should hold the lock
+mDNSlocal void AnswerSuppressUnusableQuestion(mDNS *const m, DNSQuestion *q)
+       {
+       LogInfo("AnswerSuppressUnusableQuestion: Generating negative response for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+       if (!m->CurrentQuestion) LogMsg("AnswerSuppressUnusableQuestion: ERROR!! CurrentQuestion not set");
+
+       MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, mDNSNULL);
+       AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache);
+       if (m->CurrentQuestion == q) q->ThisQInterval = 0;                              // Deactivate this question
+       // Don't touch the question after this
+       m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
+       }
+
 mDNSlocal void AnswerNewQuestion(mDNS *const m)
        {
        mDNSBool ShouldQueryImmediately = mDNStrue;
-       DNSQuestion *q = m->NewQuestions;               // Grab the question we're going to answer
+       DNSQuestion *const q = m->NewQuestions;         // Grab the question we're going to answer
        const mDNSu32 slot = HashSlot(&q->qname);
        CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
 
        verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 
-       if (cg) CheckCacheExpiration(m, cg);
-       m->NewQuestions = q->next;                              // Advance NewQuestions to the next *after* calling CheckCacheExpiration();
-
+       if (cg) CheckCacheExpiration(m, slot, cg);
+       if (m->NewQuestions != q) { LogInfo("AnswerNewQuestion: Question deleted while doing CheckCacheExpiration"); goto exit; }
+       m->NewQuestions = q->next;
+       // Advance NewQuestions to the next *after* calling CheckCacheExpiration, because if we advance it first
+       // then CheckCacheExpiration may give this question add/remove callbacks, and it's not yet ready for that.
+       //
+       // Also, CheckCacheExpiration() calls CacheRecordDeferredAdd() and CacheRecordRmv(), which invoke
+       // client callbacks, which may delete their own or any other question. Our mechanism for detecting
+       // whether our current m->NewQuestions question got deleted by one of these callbacks is to store the
+       // value of m->NewQuestions in 'q' before calling CheckCacheExpiration(), and then verify afterwards
+       // that they're still the same. If m->NewQuestions has changed (because mDNS_StopQuery_internal
+       // advanced it), that means the question was deleted, so we no longer need to worry about answering
+       // it (and indeed 'q' is now a dangling pointer, so dereferencing it at all would be bad, and the
+       // values we computed for slot and cg are now stale and relate to a question that no longer exists).
+       //
+       // We can't use the usual m->CurrentQuestion mechanism for this because  CacheRecordDeferredAdd() and
+       // CacheRecordRmv() both use that themselves when walking the list of (non-new) questions generating callbacks.
+       // Fortunately mDNS_StopQuery_internal auto-advances both m->CurrentQuestion *AND* m->NewQuestions when
+       // deleting a question, so luckily we have an easy alternative way of detecting if our question got deleted.
+       
        if (m->lock_rrcache) LogMsg("AnswerNewQuestion ERROR! Cache already locked!");
        // This should be safe, because calling the client's question callback may cause the
        // question list to be modified, but should not ever cause the rrcache list to be modified.
@@ -4246,21 +3306,23 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
        // be advanced, and we'll exit out of the loop
        m->lock_rrcache = 1;
        if (m->CurrentQuestion)
-               LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+               LogMsg("AnswerNewQuestion ERROR m->CurrentQuestion already set: %##s (%s)",
+                       m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
        m->CurrentQuestion = q;         // Indicate which question we're answering, so we'll know if it gets deleted
 
        if (q->NoAnswer == NoAnswer_Fail)
                {
                LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-               MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any);
+               MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, q->qDNSServer);
                q->NoAnswer = NoAnswer_Normal;          // Temporarily turn off answer suppression
                AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache);
                q->NoAnswer = NoAnswer_Fail;            // Restore NoAnswer state
                m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
                }
+       if (m->CurrentQuestion != q) { LogInfo("AnswerNewQuestion: Question deleted while generating NoAnswer_Fail response"); goto exit; }
 
        // If 'mDNSInterface_Any' question, see if we want to tell it about LocalOnly records
-       if (m->CurrentQuestion == q && q->InterfaceID == mDNSInterface_Any)
+       if (q->InterfaceID == mDNSInterface_Any)
                {
                if (m->CurrentRecord)
                        LogMsg("AnswerNewQuestion ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
@@ -4269,7 +3331,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
                        {
                        AuthRecord *rr = m->CurrentRecord;
                        m->CurrentRecord = rr->next;
-                       if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly)
+                       if (rr->resrec.InterfaceID == mDNSInterface_LocalOnly || rr->resrec.InterfaceID == mDNSInterface_P2P)
                                if (ResourceRecordAnswersQuestion(&rr->resrec, q))
                                        {
                                        AnswerLocalQuestionWithLocalAuthRecord(m, q, rr, mDNStrue);
@@ -4278,10 +3340,12 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
                        }
                m->CurrentRecord = mDNSNULL;
                }
+       if (m->CurrentQuestion != q) { LogInfo("AnswerNewQuestion: Question deleted while while giving LocalOnly record answers"); goto exit; }
 
-       if (m->CurrentQuestion != q) debugf("AnswerNewQuestion: question deleted while giving LocalOnly record answers");
-
-       if (m->CurrentQuestion == q)
+       // If we are not supposed to answer this question, generate a negative response.
+       // Temporarily suspend the SuppressQuery so that AnswerCurrentQuestionWithResourceRecord can answer the question
+       if (QuerySuppressed(q)) { q->SuppressQuery = mDNSfalse; AnswerSuppressUnusableQuestion(m, q); q->SuppressQuery = mDNStrue; }
+       else
                {
                CacheRecord *rr;
                for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
@@ -4309,10 +3373,11 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
                        else if (RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
                                ShouldQueryImmediately = mDNSfalse;
                }
+       // We don't use LogInfo for this "Question deleted" message because it happens so routinely that
+       // it's not remotely remarkable, and therefore unlikely to be of much help tracking down bugs.
+       if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving cache answers"); goto exit; }
 
-       if (m->CurrentQuestion != q) debugf("AnswerNewQuestion: question deleted while giving cache answers");
-
-       if (m->CurrentQuestion == q && ShouldQueryImmediately && ActiveQuestion(q))
+       if (ShouldQueryImmediately && ActiveQuestion(q))
                {
                debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
                q->ThisQInterval  = InitialQuestionInterval;
@@ -4324,11 +3389,16 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
                                m->RandomQueryDelay = (mDNSPlatformOneSecond + mDNSRandom(mDNSPlatformOneSecond*5) - 1) / 50 + 1;
                        q->LastQTime += m->RandomQueryDelay;
                        }
-
-               if (m->NextScheduledQuery - (q->LastQTime + q->ThisQInterval) > 0)
-                       m->NextScheduledQuery = (q->LastQTime + q->ThisQInterval);
                }
 
+       // IN ALL CASES make sure that m->NextScheduledQuery is set appropriately.
+       // In cases where m->NewQuestions->DelayAnswering is set, we may have delayed generating our
+       // answers for this question until *after* its scheduled transmission time, in which case
+       // m->NextScheduledQuery may now be set to 'never', and in that case -- even though we're *not* doing
+       // ShouldQueryImmediately -- we still need to make sure we set m->NextScheduledQuery correctly.
+       SetNextQueryTime(m,q);
+
+exit:
        m->CurrentQuestion = mDNSNULL;
        m->lock_rrcache = 0;
        }
@@ -4343,7 +3413,8 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
        debugf("AnswerNewLocalOnlyQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 
        if (m->CurrentQuestion)
-               LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+               LogMsg("AnswerNewLocalOnlyQuestion ERROR m->CurrentQuestion already set: %##s (%s)",
+                       m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
        m->CurrentQuestion = q;         // Indicate which question we're answering, so we'll know if it gets deleted
 
        if (m->CurrentRecord)
@@ -4506,7 +3577,7 @@ mDNSexport void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr)
        rr->TimeRcvd          = m->timenow - mDNSPlatformOneSecond * 60;
        rr->UnansweredQueries = MaxUnansweredQueries;
        rr->resrec.rroriginalttl     = 0;
-       SetNextCacheCheckTime(m, rr);
+       SetNextCacheCheckTimeForRecord(m, rr);
        }
 
 mDNSexport mDNSs32 mDNS_TimeNow(const mDNS *const m)
@@ -4539,24 +3610,26 @@ mDNSlocal void CheckProxyRecords(mDNS *const m, AuthRecord *list)
        while (m->CurrentRecord)
                {
                AuthRecord *rr = m->CurrentRecord;
-               if (rr->WakeUp.HMAC.l[0])
+               if (rr->resrec.RecordType != kDNSRecordTypeDeregistering && rr->WakeUp.HMAC.l[0])
                        {
-                       if (m->timenow - rr->TimeExpire < 0)            // If proxy record not expired yet, update m->NextScheduledSPS
+                       // If m->SPSSocket is NULL that means we're not acting as a sleep proxy any more,
+                       // so we need to cease proxying for *all* records we may have, expired or not.
+                       if (m->SPSSocket && m->timenow - rr->TimeExpire < 0)    // If proxy record not expired yet, update m->NextScheduledSPS
                                {
                                if (m->NextScheduledSPS - rr->TimeExpire > 0)
                                        m->NextScheduledSPS = rr->TimeExpire;
                                }
-                       else                                                                            // else proxy record expired, so remove it
+                       else                                                                                                    // else proxy record expired, so remove it
                                {
-                               LogSPS("mDNS_Execute: Removing %d H-MAC %.6a I-MAC %.6a %d %s",
+                               LogSPS("CheckProxyRecords: Removing %d H-MAC %.6a I-MAC %.6a %d %s",
                                        m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, ARDisplayString(m, rr));
                                SetSPSProxyListChanged(rr->resrec.InterfaceID);
                                mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
                                // Don't touch rr after this -- memory may have been free'd
                                }
                        }
-               // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal,
-               // because the list may have been changed in that call.
+               // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because
+               // new records could have been added to the end of the list as a result of that call.
                if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
                        m->CurrentRecord = rr->next;
                }
@@ -4569,14 +3642,16 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
        if (m->timenow - m->NextScheduledEvent >= 0)
                {
                int i;
-
-               // If there are DNS servers that will come out of the Penalty box, we should do that now
-               // so that any questions that we send below can start using that
-               ResetDNSServerPenalties(m);
+               AuthRecord *head, *tail;
 
                verbosedebugf("mDNS_Execute");
+
                if (m->CurrentQuestion)
-                       LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+                       LogMsg("mDNS_Execute: ERROR m->CurrentQuestion already set: %##s (%s)",
+                               m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+       
+               if (m->CurrentRecord)
+                       LogMsg("mDNS_Execute: ERROR m->CurrentRecord already set: %s", ARDisplayString(m, m->CurrentRecord));
        
                // 1. If we're past the probe suppression time, we can clear it
                if (m->SuppressProbes && m->timenow - m->SuppressProbes >= 0) m->SuppressProbes = 0;
@@ -4587,18 +3662,29 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
                // 3. Purge our cache of stale old records
                if (m->rrcache_size && m->timenow - m->NextCacheCheck >= 0)
                        {
-                       mDNSu32 slot;
+                       mDNSu32 slot, numchecked = 0;
                        m->NextCacheCheck = m->timenow + 0x3FFFFFFF;
                        for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
                                {
-                               CacheGroup **cp = &m->rrcache_hash[slot];
-                               while (*cp)
+                               if (m->timenow - m->rrcache_nextcheck[slot] >= 0)
                                        {
-                                       CheckCacheExpiration(m, *cp);
-                                       if ((*cp)->members) cp=&(*cp)->next;
-                                       else ReleaseCacheGroup(m, cp);
+                                       CacheGroup **cp = &m->rrcache_hash[slot];
+                                       m->rrcache_nextcheck[slot] = m->timenow + 0x3FFFFFFF;
+                                       while (*cp)
+                                               {
+                                               debugf("m->NextCacheCheck %4d Slot %3d %##s", numchecked, slot, *cp ? (*cp)->name : (domainname*)"\x04NULL");
+                                               numchecked++;
+                                               CheckCacheExpiration(m, slot, *cp);
+                                               if ((*cp)->members) cp=&(*cp)->next;
+                                               else ReleaseCacheGroup(m, cp);
+                                               }
                                        }
+                               // Even if we didn't need to actually check this slot yet, still need to
+                               // factor its nextcheck time into our overall NextCacheCheck value
+                               if (m->NextCacheCheck - m->rrcache_nextcheck[slot] > 0)
+                                       m->NextCacheCheck = m->rrcache_nextcheck[slot];
                                }
+                       debugf("m->NextCacheCheck %4d checked, next in %d", numchecked, m->NextCacheCheck - m->timenow);
                        }
        
                if (m->timenow - m->NextScheduledSPS >= 0)
@@ -4630,19 +3716,89 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
                        AnswerNewQuestion(m);
                        }
                if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewQuestion exceeded loop limit");
+
+               // Make sure we deliver *all* local RMV events, and clear the corresponding rr->AnsweredLocalQ flags, *before*
+               // we begin generating *any* new ADD events in the m->NewLocalOnlyQuestions and m->NewLocalRecords loops below.
+               for (i=0; i<1000 && m->LocalRemoveEvents; i++)
+                       {
+                       m->LocalRemoveEvents = mDNSfalse;
+                       m->CurrentRecord = m->ResourceRecords;
+                       while (m->CurrentRecord)
+                               {
+                               AuthRecord *rr = m->CurrentRecord;
+                               if (rr->AnsweredLocalQ && rr->resrec.RecordType == kDNSRecordTypeDeregistering)
+                                       {
+                                       debugf("mDNS_Execute: Generating local RMV events for %s", ARDisplayString(m, rr));
+                                       rr->resrec.RecordType = kDNSRecordTypeShared;
+                                       AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse);
+                                       if (m->CurrentRecord == rr)     // If rr still exists in list, restore its state now
+                                               {
+                                               rr->resrec.RecordType = kDNSRecordTypeDeregistering;
+                                               rr->AnsweredLocalQ = mDNSfalse;
+                                               }
+                                       }
+                               if (m->CurrentRecord == rr)             // If m->CurrentRecord was not auto-advanced, do it ourselves now
+                                       m->CurrentRecord = rr->next;
+                               }
+                       }
+               if (i >= 1000) LogMsg("mDNS_Execute: m->LocalRemoveEvents exceeded loop limit");
                
                for (i=0; m->NewLocalOnlyQuestions && i<1000; i++) AnswerNewLocalOnlyQuestion(m);
                if (i >= 1000) LogMsg("mDNS_Execute: AnswerNewLocalOnlyQuestion exceeded loop limit");
 
-               for (i=0; i<1000 && m->NewLocalRecords && LocalRecordReady(m->NewLocalRecords); i++)
+               head = tail = mDNSNULL;
+               for (i=0; i<1000 && m->NewLocalRecords && m->NewLocalRecords != head; i++)
                        {
                        AuthRecord *rr = m->NewLocalRecords;
                        m->NewLocalRecords = m->NewLocalRecords->next;
-                       AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue);
+                       if (LocalRecordReady(rr))
+                               {
+                               debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr));
+                               AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue);
+                               }
+                       else if (!rr->next)
+                               {
+                               // If we have just one record that is not ready, we don't have to unlink and
+                               // reinsert. As the NewLocalRecords will be NULL for this case, the loop will
+                               // terminate and set the NewLocalRecords to rr.
+                               debugf("mDNS_Execute: Just one LocalAuthRecord %s, breaking out of the loop early", ARDisplayString(m, rr));
+                               if (head != mDNSNULL || m->NewLocalRecords != mDNSNULL)
+                                       LogMsg("mDNS_Execute: ERROR!!: head %p, NewLocalRecords %p", head, m->NewLocalRecords);
+                                       
+                               head = rr;
+                               }
+                       else
+                               {
+                               AuthRecord **p = &m->ResourceRecords;   // Find this record in our list of active records
+                               debugf("mDNS_Execute: Skipping LocalAuthRecord %s", ARDisplayString(m, rr));
+                               // if this is the first record we are skipping, move to the end of the list.
+                               // if we have already skipped records before, append it at the end.
+                               while (*p && *p != rr) p=&(*p)->next;
+                               if (*p) *p = rr->next;                                  // Cut this record from the list
+                               else { LogMsg("mDNS_Execute: ERROR!! Cannot find record %s in ResourceRecords list", ARDisplayString(m, rr)); break; }
+                               if (!head)
+                                       {
+                                       while (*p) p=&(*p)->next;
+                                       *p = rr;
+                                       head = tail = rr;
+                                       }
+                               else
+                                       {
+                                       tail->next = rr;
+                                       tail = rr;
+                                       }
+                               rr->next = mDNSNULL;
+                               }
                        }
-               if (i >= 1000) LogMsg("mDNS_Execute: AnswerForNewLocalRecords exceeded loop limit");
+               m->NewLocalRecords = head;
+               debugf("mDNS_Execute: Setting NewLocalRecords to %s", (head ? ARDisplayString(m, head) : "NULL"));
+
+               if (i >= 1000) LogMsg("mDNS_Execute: m->NewLocalRecords exceeded loop limit");
 
-               // 5. See what packets we need to send
+               // 5. Some questions may have picked a new DNS server and the cache may answer these questions now.
+               AnswerQuestionsForDNSServerChanges(m);
+
+               // 6. See what packets we need to send
                if (m->mDNSPlatformStatus != mStatus_NoError || (m->SleepState == SleepState_Sleeping))
                        DiscardDeregistrations(m);
                if (m->mDNSPlatformStatus == mStatus_NoError && (m->SuppressSending == 0 || m->timenow - m->SuppressSending >= 0))
@@ -4655,7 +3811,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
                        // Finally, we send responses, including the previously mentioned records that just completed probing.
                        m->SuppressSending = 0;
        
-                       // 6. Send Query packets. This may cause some probing records to advance to announcing state
+                       // 7. Send Query packets. This may cause some probing records to advance to announcing state
                        if (m->timenow - m->NextScheduledQuery >= 0 || m->timenow - m->NextScheduledProbe >= 0) SendQueries(m);
                        if (m->timenow - m->NextScheduledQuery >= 0)
                                {
@@ -4664,7 +3820,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
                                        m->timenow, m->NextScheduledQuery, m->timenow - m->NextScheduledQuery);
                                m->NextScheduledQuery = m->timenow + mDNSPlatformOneSecond;
                                for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
-                                       if (ActiveQuestion(q) && q->LastQTime + q->ThisQInterval - m->timenow <= 0)
+                                       if (ActiveQuestion(q) && m->timenow - NextQSendTime(q) >= 0)
                                                LogMsg("mDNS_Execute: SendQueries didn't send %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
                                }
                        if (m->timenow - m->NextScheduledProbe >= 0)
@@ -4674,7 +3830,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
                                m->NextScheduledProbe = m->timenow + mDNSPlatformOneSecond;
                                }
        
-                       // 7. Send Response packets, including probing records just advanced to announcing state
+                       // 8. Send Response packets, including probing records just advanced to announcing state
                        if (m->timenow - m->NextScheduledResponse >= 0) SendResponses(m);
                        if (m->timenow - m->NextScheduledResponse >= 0)
                                {
@@ -4686,6 +3842,12 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
                // Clear RandomDelay values, ready to pick a new different value next time
                m->RandomQueryDelay     = 0;
                m->RandomReconfirmDelay = 0;
+
+#ifndef UNICAST_DISABLED
+               if (m->NextSRVUpdate && m->timenow - m->NextSRVUpdate >= 0) UpdateAllSRVRecords(m);
+               if (m->timenow - m->NextScheduledNATOp >= 0) CheckNATMappings(m);
+               if (m->timenow - m->NextuDNSEvent >= 0) uDNS_Tasks(m);
+#endif
                }
 
        // Note about multi-threaded systems:
@@ -4708,9 +3870,6 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
        // callback function should call mDNS_Execute() (and ignore the return value, which may already be stale
        // by the time it gets to the timer callback function).
 
-#ifndef UNICAST_DISABLED
-       uDNS_Execute(m);
-#endif
        mDNS_Unlock(m);         // Calling mDNS_Unlock is what gives m->NextScheduledEvent its new value
        return(m->NextScheduledEvent);
        }
@@ -4738,8 +3897,11 @@ mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question,
        // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the
        // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel.
        // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then
-       // returns results for both at the same time.
-       if (RRTypeIsAddressType(question->qtype) && question->AuthInfo && question->AuthInfo->AutoTunnel && question->QuestionCallback != AutoTunnelCallback)
+       // returns results for both at the same time. If we are looking for the _autotunnel6 record, then skip this logic
+       // as this would trigger looking up _autotunnel6._autotunnel6 and end up failing the original query.
+
+       if (RRTypeIsAddressType(question->qtype) && PrivateQuery(question) &&
+               !SameDomainLabel(question->qname.c, (const mDNSu8 *)"\x0c_autotunnel6")&& question->QuestionCallback != AutoTunnelCallback)
                {
                question->NoAnswer = NoAnswer_Suspended;
                AddNewClientTunnel(m, question);
@@ -4750,7 +3912,8 @@ mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question,
        if (!question->DuplicateOf)
                {
                debugf("ActivateUnicastQuery: %##s %s%s%s",
-                       question->qname.c, DNSTypeName(question->qtype), question->AuthInfo ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : "");
+                       question->qname.c, DNSTypeName(question->qtype), PrivateQuery(question) ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : "");
+               question->CNAMEReferrals = 0;
                if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
                if (question->LongLived)
                        {
@@ -4775,13 +3938,14 @@ mDNSexport void mDNSCoreRestartQueries(mDNS *const m)
 #ifndef UNICAST_DISABLED
        // Retrigger all our uDNS questions
        if (m->CurrentQuestion)
-               LogMsg("mDNSCoreRestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+               LogMsg("mDNSCoreRestartQueries: ERROR m->CurrentQuestion already set: %##s (%s)",
+                       m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
        m->CurrentQuestion = m->Questions;
        while (m->CurrentQuestion)
                {
                q = m->CurrentQuestion;
                m->CurrentQuestion = m->CurrentQuestion->next;
-               if (!mDNSOpaque16IsZero(q->TargetQID)) ActivateUnicastQuery(m, q, mDNStrue);
+               if (!mDNSOpaque16IsZero(q->TargetQID) && ActiveQuestion(q)) ActivateUnicastQuery(m, q, mDNStrue);
                }
 #endif
 
@@ -4804,6 +3968,53 @@ mDNSexport void mDNSCoreRestartQueries(mDNS *const m)
 #pragma mark - Power Management (Sleep/Wake)
 #endif
 
+mDNSexport void mDNS_UpdateAllowSleep(mDNS *const m)
+       {
+#ifndef IDLESLEEPCONTROL_DISABLED
+       mDNSBool allowSleep = mDNStrue;
+       
+       if (m->SystemSleepOnlyIfWakeOnLAN)
+               {
+               // Don't sleep if we are a proxy for any services
+               if (m->ProxyRecords)
+                       {
+                       allowSleep = mDNSfalse;
+                       LogInfo("Sleep disabled because we are proxying %d records", m->ProxyRecords);
+                       }
+
+               if (allowSleep && mDNSCoreHaveAdvertisedMulticastServices(m))
+                       {
+                       // Scan the list of active interfaces
+                       NetworkInterfaceInfo *intf;
+                       for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
+                               {
+                               if (intf->McastTxRx)
+                                       {
+                                       // Disallow sleep if this interface doesn't support NetWake
+                                       if (!intf->NetWake)
+                                               {
+                                               allowSleep = mDNSfalse;
+                                               LogInfo("Sleep disabled because %s does not support NetWake", intf->ifname);
+                                               break;
+                                               }
+
+                                       // Disallow sleep if there is no sleep proxy server
+                                       if (FindSPSInCache1(m, &intf->NetWakeBrowse, mDNSNULL, mDNSNULL) == mDNSNULL)
+                                               {
+                                               allowSleep = mDNSfalse;
+                                               LogInfo("Sleep disabled because %s has no sleep proxy", intf->ifname);
+                                               break;
+                                               }
+                                       }
+                               }
+                       }
+#endif /* !defined(IDLESLEEPCONTROL_DISABLED) */
+               }
+       
+       // Call the platform code to enable/disable sleep
+       mDNSPlatformSetAllowSleep(m, allowSleep);
+       }
+
 mDNSlocal void SendSPSRegistration(mDNS *const m, NetworkInterfaceInfo *intf, const mDNSOpaque16 id)
        {
        const int optspace = DNSOpt_Header_Space + DNSOpt_LeaseData_Space + DNSOpt_Owner_Space(&m->PrimaryMAC, &intf->MAC);
@@ -4933,20 +4144,19 @@ mDNSlocal void RetrySPSRegistrations(mDNS *const m)
 mDNSlocal void NetWakeResolve(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
        NetworkInterfaceInfo *intf = (NetworkInterfaceInfo *)question->QuestionContext;
-       int sps = question - intf->NetWakeResolve;
+       int sps = (int)(question - intf->NetWakeResolve);
        (void)m;                        // Unused
        LogSPS("NetWakeResolve: SPS: %d Add: %d %s", sps, AddRecord, RRDisplayString(m, answer));
 
        if (!AddRecord) return;                                                                                         // Don't care about REMOVE events
        if (answer->rrtype != question->qtype) return;                                          // Don't care about CNAMEs
 
-       // if (answer->rrtype == kDNSType_AAAA) return; // To test failing to resolve sleep proxy's address
-
-       mDNS_StopQuery(m, question);
-       question->ThisQInterval = -1;
+       // if (answer->rrtype == kDNSType_AAAA && sps == 0) return;     // To test failing to resolve sleep proxy's address
 
        if (answer->rrtype == kDNSType_SRV)
                {
+               // 1. Got the SRV record; now look up the target host's IPv6 link-local address
+               mDNS_StopQuery(m, question);
                intf->SPSPort[sps] = answer->rdata->u.srv.port;
                AssignDomainName(&question->qname, &answer->rdata->u.srv.target);
                question->qtype = kDNSType_AAAA;
@@ -4954,20 +4164,28 @@ mDNSlocal void NetWakeResolve(mDNS *const m, DNSQuestion *question, const Resour
                }
        else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == sizeof(mDNSv6Addr) && mDNSv6AddressIsLinkLocal(&answer->rdata->u.ipv6))
                {
+               // 2. Got the target host's IPv6 link-local address; record address and initiate an SPS registration if appropriate
+               mDNS_StopQuery(m, question);
+               question->ThisQInterval = -1;
                intf->SPSAddr[sps].type = mDNSAddrType_IPv6;
                intf->SPSAddr[sps].ip.v6 = answer->rdata->u.ipv6;
                mDNS_Lock(m);
                if (sps == intf->NextSPSAttempt/3) SendSPSRegistration(m, intf, zeroID);        // If we're ready for this result, use it now
                mDNS_Unlock(m);
                }
-       else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == 0)      // If negative answer for IPv6, look for IPv4 addresses instead
+       else if (answer->rrtype == kDNSType_AAAA && answer->rdlength == 0)
                {
+               // 3. Got negative response -- target host apparently has IPv6 disabled -- so try looking up the target host's IPv4 address(es) instead
+               mDNS_StopQuery(m, question);
                LogSPS("NetWakeResolve: SPS %d %##s has no IPv6 address, will try IPv4 instead", sps, question->qname.c);
                question->qtype = kDNSType_A;
                mDNS_StartQuery(m, question);
                }
        else if (answer->rrtype == kDNSType_A && answer->rdlength == sizeof(mDNSv4Addr))
                {
+               // 4. Got an IPv4 address for the target host; record address and initiate an SPS registration if appropriate
+               mDNS_StopQuery(m, question);
+               question->ThisQInterval = -1;
                intf->SPSAddr[sps].type = mDNSAddrType_IPv4;
                intf->SPSAddr[sps].ip.v4 = answer->rdata->u.ipv4;
                mDNS_Lock(m);
@@ -4991,9 +4209,8 @@ mDNSlocal void SendSleepGoodbyes(mDNS *const m)
        m->SleepState = SleepState_Sleeping;
 
 #ifndef UNICAST_DISABLED
-       SleepServiceRegistrations(m);
        SleepRecordRegistrations(m);    // If we have no SPS, need to deregister our uDNS records
-#endif
+#endif /* UNICAST_DISABLED */
 
        // Mark all the records we need to deregister and send them
        for (rr = m->ResourceRecords; rr; rr=rr->next)
@@ -5032,7 +4249,7 @@ mDNSlocal void BeginSleepProcessing(mDNS *const m)
                                {
                                FindSPSInCache(m, &intf->NetWakeBrowse, sps);
                                if (!sps[0]) LogSPS("BeginSleepProcessing: %-6s %#a No Sleep Proxy Server found (Next Browse Q in %d, interval %d)",
-                                       intf->ifname, &intf->ip, intf->NetWakeBrowse.LastQTime + intf->NetWakeBrowse.ThisQInterval - m->timenow, intf->NetWakeBrowse.ThisQInterval);
+                                       intf->ifname, &intf->ip, NextQSendTime(&intf->NetWakeBrowse) - m->timenow, intf->NetWakeBrowse.ThisQInterval);
                                else
                                        {
                                        int i;
@@ -5078,12 +4295,11 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
        {
        AuthRecord *rr;
 
-       mDNS_Lock(m);
-
        LogSPS("%s (old state %d) at %ld", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow);
 
        if (sleep && !m->SleepState)            // Going to sleep
                {
+               mDNS_Lock(m);
                // If we're going to sleep, need to stop advertising that we're a Sleep Proxy Server
                if (m->SPSSocket)
                        {
@@ -5099,20 +4315,25 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
                        {
                        // If we just woke up moments ago, allow ten seconds for networking to stabilize before going back to sleep
                        LogSPS("mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m->DelaySleep - m->timenow);
-                       m->SleepLimit = m->DelaySleep + mDNSPlatformOneSecond * 10;
+                       m->SleepLimit = NonZeroTime(m->DelaySleep + mDNSPlatformOneSecond * 10);
                        }
                else
                        {
                        m->DelaySleep = 0;
-                       m->SleepLimit = m->timenow + mDNSPlatformOneSecond * 10;
+                       m->SleepLimit = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 10);
                        BeginSleepProcessing(m);
                        }
 
 #ifndef UNICAST_DISABLED
                SuspendLLQs(m);
+#endif
+               mDNS_Unlock(m);
+               // RemoveAutoTunnel6Record needs to be called outside the lock, as it grabs the lock also.
+#if APPLE_OSX_mDNSResponder
+               RemoveAutoTunnel6Record(m);
 #endif
                LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m->SleepState,
-                       m->SleepState == SleepState_Transferring ? "Transferring" : 
+                       m->SleepState == SleepState_Transferring ? "Transferring" :
                        m->SleepState == SleepState_Sleeping     ? "Sleeping"     : "?", m->SleepSeqNum);
                }
        else if (!sleep)                // Waking up
@@ -5122,6 +4343,10 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
                CacheRecord *cr;
                NetworkInterfaceInfo *intf;
 
+               mDNS_Lock(m);
+               // Reset SleepLimit back to 0 now that we're awake again.
+               m->SleepLimit = 0;
+
                // If we were previously sleeping, but now we're not, increment m->SleepSeqNum to indicate that we're entering a new period of wakefulness
                if (m->SleepState != SleepState_Awake)
                        {
@@ -5141,10 +4366,8 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
 
                if (m->SPSState == 3)
                        {
-                       mDNS_DropLockBeforeCallback();          // mDNS_DeregisterService expects to be called without the lock held, so we emulate that here
                        m->SPSState = 0;
-                       mDNSCoreBeSleepProxyServer(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower);
-                       mDNS_ReclaimLockAfterCallback();
+                       mDNSCoreBeSleepProxyServer_internal(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower);
                        }
 
                // In case we gave up waiting and went to sleep before we got an ack from the Sleep Proxy,
@@ -5159,10 +4382,9 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
 
                // and reactivtate service registrations
                m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
-               LogInfo("WakeServiceRegistrations %d %d", m->timenow, m->NextSRVUpdate);
+               LogInfo("mDNSCoreMachineSleep waking: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
 
                // 2. Re-validate our cache records
-               m->NextCacheCheck  = m->timenow;
                FORALL_CACHERECORDS(slot, cg, cr)
                        mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForWake);
 
@@ -5177,6 +4399,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
                                if (rr->resrec.RecordType == kDNSRecordTypeVerified && !rr->DependentOn) rr->resrec.RecordType = kDNSRecordTypeUnique;
                                rr->ProbeCount     = DefaultProbeCountForRecordType(rr->resrec.RecordType);
                                rr->AnnounceCount  = InitialAnnounceCount;
+                               rr->SendNSECNow    = mDNSNULL;
                                InitializeLastAPTime(m, rr);
                                }
 
@@ -5184,22 +4407,20 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
                // We don't want to have to assume that all hardware can necessarily keep accurate
                // track of passage of time while asleep, so on wake we refresh our NAT mappings
                // We typically wake up with no interfaces active, so there's no need to rush to try to find our external address.
-               // When we get a DHCP address and mDNS_SetPrimaryInterfaceInfo is called, we'll then set m->retryGetAddr
-               // to immediately request our external address from the NAT gateway.
+               // When we get a network configuration change, mDNSMacOSXNetworkChanged calls uDNS_SetupDNSConfig, which calls
+               // mDNS_SetPrimaryInterfaceInfo, which then sets m->retryGetAddr to immediately request our external address from the NAT gateway.
                m->retryIntervalGetAddr = NATMAP_INIT_RETRY;
                m->retryGetAddr         = m->timenow + mDNSPlatformOneSecond * 5;
                LogInfo("mDNSCoreMachineSleep: retryGetAddr in %d %d", m->retryGetAddr - m->timenow, m->timenow);
                RecreateNATMappings(m);
+               mDNS_Unlock(m);
                }
-
-       mDNS_Unlock(m);
        }
 
 mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now)
        {
        DNSQuestion *q;
        AuthRecord *rr;
-       ServiceRecordSet *srs;
        NetworkInterfaceInfo *intf;
 
        mDNS_Lock(m);
@@ -5217,9 +4438,10 @@ mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now)
                        {
                        if (now - intf->NextSPSAttemptTime >= 0)
                                {
-                               LogSPS("ReadyForSleep retrying SPS %s %d", intf->ifname, intf->NextSPSAttempt);
+                               LogSPS("mDNSCoreReadyForSleep: retrying for %s SPS %d try %d",
+                                       intf->ifname, intf->NextSPSAttempt/3, intf->NextSPSAttempt);
                                SendSPSRegistration(m, intf, zeroID);
-                               // Don't need to "goto notready" here, becase if we do still have record registrations
+                               // Don't need to "goto notready" here, because if we do still have record registrations
                                // that have not been acknowledged yet, we'll catch that in the record list scan below.
                                }
                        else
@@ -5229,35 +4451,40 @@ mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now)
 
        // Scan list of interfaces, and see if we're still waiting for any sleep proxy resolves to complete
        for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
-               if (intf->NetWakeResolve[0].ThisQInterval >= 0)
+               {
+               int sps = (intf->NextSPSAttempt == 0) ? 0 : (intf->NextSPSAttempt-1)/3;
+               if (intf->NetWakeResolve[sps].ThisQInterval >= 0)
                        {
-                       LogSPS("ReadyForSleep waiting for SPS Resolve %s %##s (%s)", intf->ifname, intf->NetWakeResolve[0].qname.c, DNSTypeName(intf->NetWakeResolve[0].qtype));
+                       LogSPS("mDNSCoreReadyForSleep: waiting for SPS Resolve %s %##s (%s)",
+                               intf->ifname, intf->NetWakeResolve[sps].qname.c, DNSTypeName(intf->NetWakeResolve[sps].qtype));
                        goto spsnotready;
                        }
+               }
 
        // Scan list of registered records
        for (rr = m->ResourceRecords; rr; rr = rr->next)
                if (!AuthRecord_uDNS(rr))
                        if (!mDNSOpaque16IsZero(rr->updateid))
-                               { LogSPS("ReadyForSleep waiting for SPS Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto spsnotready; }
+                               { LogSPS("mDNSCoreReadyForSleep: waiting for SPS Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto spsnotready; }
 
        // Scan list of private LLQs, and make sure they've all completed their handshake with the server
        for (q = m->Questions; q; q = q->next)
                if (!mDNSOpaque16IsZero(q->TargetQID) && q->LongLived && q->ReqLease == 0 && q->tcp)
                        {
-                       LogSPS("ReadyForSleep waiting for LLQ %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+                       LogSPS("mDNSCoreReadyForSleep: waiting for LLQ %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
                        goto notready;
                        }
 
        // Scan list of registered records
        for (rr = m->ResourceRecords; rr; rr = rr->next)
                if (AuthRecord_uDNS(rr))
+                       {
                        if (rr->state == regState_Refresh && rr->tcp)
-                               { LogSPS("ReadyForSleep waiting for Record Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; }
-
-       // Scan list of registered services
-       for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next)
-               if (srs->state == regState_NoTarget && srs->tcp) goto notready;
+                               { LogSPS("mDNSCoreReadyForSleep: waiting for Record Update ID %d %s", mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; }
+                       #if APPLE_OSX_mDNSResponder
+                       if (!RecordReadyForSleep(m, rr)) { LogSPS("mDNSCoreReadyForSleep: waiting for %s", ARDisplayString(m, rr)); goto notready; }
+                       #endif
+                       }
 
        mDNS_Unlock(m);
        return mDNStrue;
@@ -5273,7 +4500,8 @@ spsnotready:
                for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
                        if (intf->NetWakeBrowse.ThisQInterval >= 0)
                                {
-                               LogSPS("ReadyForSleep mDNS_DeactivateNetWake %s %##s (%s)", intf->ifname, intf->NetWakeResolve[0].qname.c, DNSTypeName(intf->NetWakeResolve[0].qtype));
+                               LogSPS("ReadyForSleep mDNS_DeactivateNetWake %s %##s (%s)",
+                                       intf->ifname, intf->NetWakeResolve[0].qname.c, DNSTypeName(intf->NetWakeResolve[0].qtype));
                                mDNS_DeactivateNetWake_internal(m, intf);
                                }
 
@@ -5369,7 +4597,7 @@ mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const m
        // ***
        if (LegacyQuery)
                {
-               maxttl = 10;
+               maxttl = kStaticCacheTTL;
                for (i=0; i<query->h.numQuestions; i++)                                         // For each question...
                        {
                        DNSQuestion q;
@@ -5541,7 +4769,7 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q
                {
                ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
                if (!ptr) break;
-               if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
+               if (m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
                        {
                        FoundUpdate = mDNStrue;
                        if (PacketRRConflict(m, our, &m->rec.r))
@@ -5552,11 +4780,11 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q
                                if (result)
                                        {
                                        const char *const msg = (result < 0) ? "lost:" : (result > 0) ? "won: " : "tie: ";
-                                       LogMsg("ResolveSimultaneousProbe: Pkt Record:        %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
-                                       LogMsg("ResolveSimultaneousProbe: Our Record %d %s %08lX %s",   our->ProbeCount, msg, our->resrec.rdatahash, ARDisplayString(m, our));
+                                       LogMsg("ResolveSimultaneousProbe: %p Pkt Record:        %08lX %s", q->InterfaceID, m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
+                                       LogMsg("ResolveSimultaneousProbe: %p Our Record %d %s %08lX %s", our->resrec.InterfaceID, our->ProbeCount, msg, our->resrec.rdatahash, ARDisplayString(m, our));
                                        }
                                // If we lost the tie-break for simultaneous probes, we don't immediately give up, because we might be seeing stale packets on the network.
-                               // Instead we pause for one second, to give the other host (if real) a change to establish its name, and then try probing again.
+                               // Instead we pause for one second, to give the other host (if real) a chance to establish its name, and then try probing again.
                                // If there really is another live host out there with the same name, it will answer our probes and we'll then rename.
                                if (result < 0)
                                        {
@@ -5570,8 +4798,8 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q
 #if 0
                        else
                                {
-                               LogMsg("ResolveSimultaneousProbe: Pkt Record:      %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
-                               LogMsg("ResolveSimultaneousProbe: Our Record ign:  %08lX %s", our->resrec.rdatahash,     ARDisplayString(m, our));
+                               LogMsg("ResolveSimultaneousProbe: %p Pkt Record:        %08lX %s", q->InterfaceID, m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
+                               LogMsg("ResolveSimultaneousProbe: %p Our Record %d ign:  %08lX %s", our->resrec.InterfaceID, our->ProbeCount, our->resrec.rdatahash, ARDisplayString(m, our));
                                }
 #endif
                        }
@@ -5588,14 +4816,47 @@ mDNSlocal CacheRecord *FindIdenticalRecordInCache(const mDNS *const m, const Res
        mDNSu32 slot = HashSlot(pktrr->name);
        CacheGroup *cg = CacheGroupForRecord(m, slot, pktrr);
        CacheRecord *rr;
+       mDNSBool match;
        for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
-               if (pktrr->InterfaceID == rr->resrec.InterfaceID && IdenticalSameNameRecord(pktrr, &rr->resrec)) break;
+               {
+               match = !pktrr->InterfaceID ? pktrr->rDNSServer == rr->resrec.rDNSServer : pktrr->InterfaceID == rr->resrec.InterfaceID;
+               if (match && IdenticalSameNameRecord(pktrr, &rr->resrec)) break;
+               }
        return(rr);
        }
 
+// Called from mDNSCoreReceiveUpdate when we get a sleep proxy registration request,
+// to check our lists and discard any stale duplicates of this record we already have
+mDNSlocal void ClearIdenticalProxyRecords(mDNS *const m, const OwnerOptData *const owner, AuthRecord *const thelist)
+       {
+       if (m->CurrentRecord)
+               LogMsg("ClearIdenticalProxyRecords ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
+       m->CurrentRecord = thelist;
+       while (m->CurrentRecord)
+               {
+               AuthRecord *const rr = m->CurrentRecord;
+               if (m->rec.r.resrec.InterfaceID == rr->resrec.InterfaceID && mDNSSameEthAddress(&owner->HMAC, &rr->WakeUp.HMAC))
+                       if (IdenticalResourceRecord(&rr->resrec, &m->rec.r.resrec))
+                               {
+                               LogSPS("ClearIdenticalProxyRecords: Removing %3d H-MAC %.6a I-MAC %.6a %d %d %s",
+                                       m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, owner->seq, ARDisplayString(m, rr));
+                               rr->WakeUp.HMAC = zeroEthAddr;  // Clear HMAC so that mDNS_Deregister_internal doesn't waste packets trying to wake this host
+                               rr->RequireGoodbye = mDNSfalse; // and we don't want to send goodbye for it
+                               mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
+                               SetSPSProxyListChanged(m->rec.r.resrec.InterfaceID);
+                               }
+               // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because
+               // new records could have been added to the end of the list as a result of that call.
+               if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
+                       m->CurrentRecord = rr->next;
+               }
+       }
+
 // Called from ProcessQuery when we get an mDNS packet with an owner record in it
 mDNSlocal void ClearProxyRecords(mDNS *const m, const OwnerOptData *const owner, AuthRecord *const thelist)
        {
+       if (m->CurrentRecord)
+               LogMsg("ClearProxyRecords ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
        m->CurrentRecord = thelist;
        while (m->CurrentRecord)
                {
@@ -5603,13 +4864,28 @@ mDNSlocal void ClearProxyRecords(mDNS *const m, const OwnerOptData *const owner,
                if (m->rec.r.resrec.InterfaceID == rr->resrec.InterfaceID && mDNSSameEthAddress(&owner->HMAC, &rr->WakeUp.HMAC))
                        if (owner->seq != rr->WakeUp.seq || m->timenow - rr->TimeRcvd > mDNSPlatformOneSecond * 60)
                                {
-                               LogSPS("ClearProxyRecords: Removing %3d H-MAC %.6a I-MAC %.6a %d %d %s",
-                                       m->ProxyRecords, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, owner->seq, ARDisplayString(m, rr));
+                               if (rr->AddressProxy.type == mDNSAddrType_IPv6)
+                                       {
+                                       // We don't do this here because we know that the host is waking up at this point, so we don't send
+                                       // Unsolicited Neighbor Advertisements -- even Neighbor Advertisements agreeing with what the host should be
+                                       // saying itself -- because it can cause some IPv6 stacks to falsely conclude that there's an address conflict.
+                                       #if MDNS_USE_Unsolicited_Neighbor_Advertisements
+                                       LogSPS("NDP Announcement -- Releasing traffic for H-MAC %.6a I-MAC %.6a %s",
+                                               &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m,rr));
+                                       SendNDP(m, NDP_Adv, NDP_Override, rr, &rr->AddressProxy.ip.v6, &rr->WakeUp.IMAC, &AllHosts_v6, &AllHosts_v6_Eth);
+                                       #endif
+                                       }
+                               LogSPS("ClearProxyRecords: Removing %3d AC %2d %02X H-MAC %.6a I-MAC %.6a %d %d %s",
+                                       m->ProxyRecords, rr->AnnounceCount, rr->resrec.RecordType,
+                                       &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, rr->WakeUp.seq, owner->seq, ARDisplayString(m, rr));
+                               if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) rr->resrec.RecordType = kDNSRecordTypeShared;
+                               rr->WakeUp.HMAC = zeroEthAddr;  // Clear HMAC so that mDNS_Deregister_internal doesn't waste packets trying to wake this host
+                               rr->RequireGoodbye = mDNSfalse; // and we don't want to send goodbye for it, since real host is now back and functional
                                mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
                                SetSPSProxyListChanged(m->rec.r.resrec.InterfaceID);
                                }
-               // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal,
-               // because the list may have been changed in that call.
+               // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because
+               // new records could have been added to the end of the list as a result of that call.
                if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
                        m->CurrentRecord = rr->next;
                }
@@ -5620,7 +4896,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    = srcaddr && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
+       mDNSBool      FromLocalSubnet    = srcaddr && mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr);
        AuthRecord   *ResponseRecords    = mDNSNULL;
        AuthRecord  **nrp                = &ResponseRecords;
        CacheRecord  *ExpectedAnswers    = mDNSNULL;                    // Records in our cache we expect to see updated
@@ -5641,7 +4917,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
        if (ptr)
                {
                ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAdd, &m->rec);
-               if (m->rec.r.resrec.rrtype == kDNSType_OPT)
+               if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_OPT)
                        {
                        const rdataOPT *opt;
                        const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
@@ -5726,10 +5002,10 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                                                else if (!rr->NR_AnswerTo) rr->NR_AnswerTo = LegacyQuery ? ptr : (mDNSu8*)~1;
                                                }
                                        }
-                               else if (rr->resrec.RecordType == kDNSRecordTypeVerified)
+                               else if ((rr->resrec.RecordType & kDNSRecordTypeActiveUniqueMask) && ResourceRecordIsValidAnswer(rr))
                                        {
                                        // If we don't have any answers for this question, but we do own another record with the same name,
-                                       // then mark it to generate an NSEC record on this interface
+                                       // then we'll want to mark it to generate an NSEC record on this interface
                                        if (!NSECAnswer) NSECAnswer = rr;
                                        }
                                }
@@ -5824,70 +5100,72 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                CacheRecord *ourcacherr;
                ptr = GetLargeResourceRecord(m, query, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &m->rec);
                if (!ptr) goto exit;
-
-               // See if this Known-Answer suppresses any of our currently planned answers
-               for (rr=ResponseRecords; rr; rr=rr->NextResponse)
-                       if (MustSendRecord(rr) && ShouldSuppressKnownAnswer(&m->rec.r, rr))
-                               { rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
-
-               // See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression)
-               for (rr=m->ResourceRecords; rr; rr=rr->next)
+               if (m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative)
                        {
-                       // If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression
-                       if (rr->ImmedAnswer == InterfaceID && ShouldSuppressKnownAnswer(&m->rec.r, rr))
+                       // See if this Known-Answer suppresses any of our currently planned answers
+                       for (rr=ResponseRecords; rr; rr=rr->NextResponse)
+                               if (MustSendRecord(rr) && ShouldSuppressKnownAnswer(&m->rec.r, rr))
+                                       { rr->NR_AnswerTo = mDNSNULL; rr->NR_AdditionalTo = mDNSNULL; }
+       
+                       // See if this Known-Answer suppresses any previously scheduled answers (for multi-packet KA suppression)
+                       for (rr=m->ResourceRecords; rr; rr=rr->next)
                                {
-                               if (srcaddr->type == mDNSAddrType_IPv4)
+                               // If we're planning to send this answer on this interface, and only on this interface, then allow KA suppression
+                               if (rr->ImmedAnswer == InterfaceID && ShouldSuppressKnownAnswer(&m->rec.r, rr))
                                        {
-                                       if (mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = zerov4Addr;
-                                       }
-                               else if (srcaddr->type == mDNSAddrType_IPv6)
-                                       {
-                                       if (mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = zerov6Addr;
-                                       }
-                               if (mDNSIPv4AddressIsZero(rr->v4Requester) && mDNSIPv6AddressIsZero(rr->v6Requester))
-                                       {
-                                       rr->ImmedAnswer  = mDNSNULL;
-                                       rr->ImmedUnicast = mDNSfalse;
-#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
-                                       LogMsg("Suppressed after%4d: %s", m->timenow - rr->ImmedAnswerMarkTime, ARDisplayString(m, rr));
-#endif
+                                       if (srcaddr->type == mDNSAddrType_IPv4)
+                                               {
+                                               if (mDNSSameIPv4Address(rr->v4Requester, srcaddr->ip.v4)) rr->v4Requester = zerov4Addr;
+                                               }
+                                       else if (srcaddr->type == mDNSAddrType_IPv6)
+                                               {
+                                               if (mDNSSameIPv6Address(rr->v6Requester, srcaddr->ip.v6)) rr->v6Requester = zerov6Addr;
+                                               }
+                                       if (mDNSIPv4AddressIsZero(rr->v4Requester) && mDNSIPv6AddressIsZero(rr->v6Requester))
+                                               {
+                                               rr->ImmedAnswer  = mDNSNULL;
+                                               rr->ImmedUnicast = mDNSfalse;
+       #if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
+                                               LogMsg("Suppressed after%4d: %s", m->timenow - rr->ImmedAnswerMarkTime, ARDisplayString(m, rr));
+       #endif
+                                               }
                                        }
                                }
-                       }
-
-               ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec);
-
-#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
-               // See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always,
-               // even if the TC bit is not set (the TC bit will *not* be set in the *last* packet of a multi-packet KA list).
-               if (ourcacherr && ourcacherr->MPExpectingKA && m->timenow - ourcacherr->MPLastUnansweredQT < mDNSPlatformOneSecond)
-                       {
-                       ourcacherr->MPUnansweredKA++;
-                       ourcacherr->MPExpectingKA = mDNSfalse;
-                       }
-#endif
-
-               // Having built our ExpectedAnswers list from the questions in this packet, we then remove
-               // any records that are suppressed by the Known Answer list in this packet.
-               eap = &ExpectedAnswers;
-               while (*eap)
-                       {
-                       CacheRecord *cr = *eap;
-                       if (cr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &cr->resrec))
-                               { *eap = cr->NextInKAList; cr->NextInKAList = mDNSNULL; }
-                       else eap = &cr->NextInKAList;
-                       }
-               
-               // See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query.
-               if (!ourcacherr)
-                       {
-                       dqp = &DupQuestions;
-                       while (*dqp)
+       
+                       ourcacherr = FindIdenticalRecordInCache(m, &m->rec.r.resrec);
+       
+       #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
+                       // See if this Known-Answer suppresses any answers we were expecting for our cache records. We do this always,
+                       // even if the TC bit is not set (the TC bit will *not* be set in the *last* packet of a multi-packet KA list).
+                       if (ourcacherr && ourcacherr->MPExpectingKA && m->timenow - ourcacherr->MPLastUnansweredQT < mDNSPlatformOneSecond)
+                               {
+                               ourcacherr->MPUnansweredKA++;
+                               ourcacherr->MPExpectingKA = mDNSfalse;
+                               }
+       #endif
+       
+                       // Having built our ExpectedAnswers list from the questions in this packet, we then remove
+                       // any records that are suppressed by the Known Answer list in this packet.
+                       eap = &ExpectedAnswers;
+                       while (*eap)
+                               {
+                               CacheRecord *cr = *eap;
+                               if (cr->resrec.InterfaceID == InterfaceID && IdenticalResourceRecord(&m->rec.r.resrec, &cr->resrec))
+                                       { *eap = cr->NextInKAList; cr->NextInKAList = mDNSNULL; }
+                               else eap = &cr->NextInKAList;
+                               }
+                       
+                       // See if this Known-Answer is a surprise to us. If so, we shouldn't suppress our own query.
+                       if (!ourcacherr)
                                {
-                               DNSQuestion *q = *dqp;
-                               if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
-                                       { *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; }
-                               else dqp = &q->NextInDQList;
+                               dqp = &DupQuestions;
+                               while (*dqp)
+                                       {
+                                       DNSQuestion *q = *dqp;
+                                       if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
+                                               { *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; }
+                                       else dqp = &q->NextInDQList;
+                                       }
                                }
                        }
                m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
@@ -6038,7 +5316,7 @@ exit:
                                        debugf("ProcessQuery: (!TC) UAQ %lu MPQ %lu MPKA %lu %s",
                                                cr->UnansweredQueries, cr->MPUnansweredQ, cr->MPUnansweredKA, CRDisplayString(m, cr));
 #endif
-                               SetNextCacheCheckTime(m, cr);
+                               SetNextCacheCheckTimeForRecord(m, cr);
                                }
 
                // If we've seen multiple unanswered queries for this record,
@@ -6106,27 +5384,27 @@ mDNSlocal void mDNSCoreReceiveQuery(mDNS *const m, const DNSMessage *const msg,
        {
        mDNSu8    *responseend = mDNSNULL;
        mDNSBool   QueryWasLocalUnicast = srcaddr && dstaddr &&
-               !mDNSAddrIsDNSMulticast(dstaddr) && AddressIsLocalSubnet(m, InterfaceID, srcaddr);
+               !mDNSAddrIsDNSMulticast(dstaddr) && mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr);
        
        if (!InterfaceID && dstaddr && mDNSAddrIsDNSMulticast(dstaddr))
                {
                LogMsg("Ignoring Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
-                       "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s (Multicast, but no InterfaceID)",
+                       "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes (Multicast, but no InterfaceID)",
                        srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
-                       msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", " : "s,",
-                       msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", " : "s,",
+                       msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", "   : "s,",
+                       msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", "   : "s,",
                        msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y,  " : "ies,",
-                       msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
+                       msg->h.numAdditionals, msg->h.numAdditionals == 1 ? " "    : "s", end - msg->data);
                return;
                }
 
        verbosedebugf("Received Query from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
-               "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
+               "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes",
                srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
-               msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", " : "s,",
-               msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", " : "s,",
+               msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", "   : "s,",
+               msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", "   : "s,",
                msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y,  " : "ies,",
-               msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
+               msg->h.numAdditionals, msg->h.numAdditionals == 1 ? " "    : "s", end - msg->data);
        
        responseend = ProcessQuery(m, msg, end, srcaddr, InterfaceID,
                !mDNSSameIPPort(srcport, MulticastDNSPort), mDNSAddrIsDNSMulticast(dstaddr), QueryWasLocalUnicast, &m->omsg);
@@ -6159,50 +5437,70 @@ struct UDPSocket_struct
        mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
        };
 
-mDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSIPPort port, const mDNSOpaque16 id, const DNSQuestion *const question)
+mDNSlocal DNSQuestion *ExpectingUnicastResponseForQuestion(const mDNS *const m, const mDNSIPPort port, const mDNSOpaque16 id, const DNSQuestion *const question, mDNSBool tcp)
        {
        DNSQuestion *q;
        for (q = m->Questions; q; q=q->next)
-               if (q->LocalSocket &&
-                       mDNSSameIPPort  (q->LocalSocket->port, port)     &&
+               {
+               if (!tcp && !q->LocalSocket) continue;
+               if (mDNSSameIPPort(tcp ? q->tcpSrcPort : q->LocalSocket->port, port)     &&
                        mDNSSameOpaque16(q->TargetQID,         id)       &&
                        q->qtype                  == question->qtype     &&
                        q->qclass                 == question->qclass    &&
                        q->qnamehash              == question->qnamehash &&
                        SameDomainName(&q->qname, &question->qname))
                        return(q);
+               }
        return(mDNSNULL);
        }
 
-mDNSlocal mDNSBool ExpectingUnicastResponseForRecord(mDNS *const m, const mDNSAddr *const srcaddr, const mDNSBool SrcLocal, const mDNSIPPort port, const mDNSOpaque16 id, const CacheRecord *const rr)
+mDNSlocal DNSQuestion *ExpectingUnicastResponseForRecord(mDNS *const m,
+       const mDNSAddr *const srcaddr, const mDNSBool SrcLocal, const mDNSIPPort port, const mDNSOpaque16 id, const CacheRecord *const rr, mDNSBool tcp)
        {
        DNSQuestion *q;
        (void)id;
        (void)srcaddr;
+
+       // Unicast records have zero as InterfaceID
+       if (rr->resrec.InterfaceID) return mDNSNULL;
+
        for (q = m->Questions; q; q=q->next)
-               if (!q->DuplicateOf && ResourceRecordAnswersQuestion(&rr->resrec, q))
+               {
+               if (!q->DuplicateOf && UnicastResourceRecordAnswersQuestion(&rr->resrec, q))
                        {
                        if (!mDNSOpaque16IsZero(q->TargetQID))
                                {
                                debugf("ExpectingUnicastResponseForRecord msg->h.id %d q->TargetQID %d for %s", mDNSVal16(id), mDNSVal16(q->TargetQID), CRDisplayString(m, rr));
+
                                if (mDNSSameOpaque16(q->TargetQID, id))
                                        {
-                                       if (q->LocalSocket && mDNSSameIPPort(q->LocalSocket->port, port)) return(mDNStrue);
+                                       mDNSIPPort srcp;
+                                       if (!tcp)
+                                               {
+                                               srcp = q->LocalSocket ? q->LocalSocket->port : zeroIPPort;
+                                               }
+                                       else
+                                               {
+                                               srcp = q->tcpSrcPort;
+                                               }
+                                       if (mDNSSameIPPort(srcp, port)) return(q);
+                                       
                                //      if (mDNSSameAddress(srcaddr, &q->Target))                   return(mDNStrue);
                                //      if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking
                                //      if (TrustedSource(m, srcaddr))                              return(mDNStrue);
                                        LogInfo("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a:%d] from %#a:%d %s",
-                                               q->qname.c, DNSTypeName(q->qtype), &q->Target, mDNSVal16(q->LocalSocket ? q->LocalSocket->port : zeroIPPort), srcaddr, mDNSVal16(port), CRDisplayString(m, rr));
-                                       return(mDNSfalse);
+                                               q->qname.c, DNSTypeName(q->qtype), &q->Target, mDNSVal16(srcp), srcaddr, mDNSVal16(port), CRDisplayString(m, rr));
+                                       return(mDNSNULL);
                                        }
                                }
                        else
                                {
                                if (SrcLocal && q->ExpectUnicastResp && (mDNSu32)(m->timenow - q->ExpectUnicastResp) < (mDNSu32)(mDNSPlatformOneSecond*2))
-                                       return(mDNStrue);
+                                       return(q);
                                }
                        }
-       return(mDNSfalse);
+               }
+       return(mDNSNULL);
        }
 
 // Certain data types need more space for in-memory storage than their in-packet rdlength would imply
@@ -6221,7 +5519,7 @@ mDNSlocal mDNSu16 GetRDLengthMem(const ResourceRecord *const rr)
                }
        }
 
-mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg)
+mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg, mDNSs32 delay)
        {
        CacheRecord *rr = mDNSNULL;
        mDNSu16 RDLength = GetRDLengthMem(&m->rec.r.resrec);
@@ -6238,8 +5536,9 @@ mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, C
                {
                RData *saveptr = rr->resrec.rdata;              // Save the rr->resrec.rdata pointer
                *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
+               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
+               rr->DelayDelivery = delay;
 
                // If this is an oversized record with external storage allocated, copy rdata to external storage
                if      (rr->resrec.rdata == (RData*)&rr->smallrdatastorage && RDLength > InlineCacheRDSize)
@@ -6252,15 +5551,8 @@ mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, C
                rr->next = mDNSNULL;                                    // Clear 'next' pointer
                *(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 == kDNSRecordTypePacketNegative)
-                       rr->DelayDelivery = NonZeroTime(m->timenow);
-               else if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask &&                      // If marked unique,
-                       rr->resrec.rdata->MaxRDLength != 0)                                                                             // and non-negative, assume we may have
-                       rr->DelayDelivery = NonZeroTime(m->timenow + mDNSPlatformOneSecond);    // to delay delivery of this 'add' event
-               else
-                       rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot);
 
-               CacheRecordAdd(m, rr);  // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
+               CacheRecordAdd(m, rr);  // CacheRecordAdd calls SetNextCacheCheckTimeForRecord(m, rr); for us
                }
        return(rr);
        }
@@ -6275,7 +5567,7 @@ mDNSlocal void RefreshCacheRecord(mDNS *const m, CacheRecord *rr, mDNSu32 ttl)
        rr->MPUnansweredKA    = 0;
        rr->MPExpectingKA     = mDNSfalse;
 #endif
-       SetNextCacheCheckTime(m, rr);
+       SetNextCacheCheckTimeForRecord(m, rr);
        }
 
 mDNSexport void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease)
@@ -6319,7 +5611,14 @@ mDNSlocal mDNSu32 GetEffectiveTTL(const uDNS_LLQType LLQType, mDNSu32 ttl)               // T
                // For mDNS, TTL zero means "delete this record"
                // For uDNS, TTL zero means: this data is true at this moment, but don't cache it.
                // For the sake of network efficiency, we impose a minimum effective TTL of 15 seconds.
-               // If we allow a TTL of less than 2 seconds things really break (e.g. we end up making a negative cache entry).
+               // This means that we'll do our 80, 85, 90, 95% queries at 12.00, 12.75, 13.50, 14.25 seconds
+               // respectively, and then if we get no response, delete the record from the cache at 15 seconds.
+               // This gives the server up to three seconds to respond between when we send our 80% query at 12 seconds
+               // and when we delete the record at 15 seconds. Allowing cache lifetimes less than 15 seconds would
+               // (with the current code) result in the server having even less than three seconds to respond
+               // before we deleted the record and reported a "remove" event to any active questions.
+               // Furthermore, with the current code, if we were to allow a TTL of less than 2 seconds
+               // then things really break (e.g. we end up making a negative cache entry).
                // In the future we may want to revisit this and consider properly supporting non-cached (TTL=0) uDNS answers.
                if (ttl < 15) ttl = 15;
                }
@@ -6340,8 +5639,9 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
        {
        int i;
        mDNSBool ResponseMCast    = dstaddr && mDNSAddrIsDNSMulticast(dstaddr);
-       mDNSBool ResponseSrcLocal = !srcaddr || AddressIsLocalSubnet(m, InterfaceID, srcaddr);
-       uDNS_LLQType LLQType      = uDNS_recvLLQResponse(m, response, end, srcaddr, srcport);
+       mDNSBool ResponseSrcLocal = !srcaddr || mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr);
+       DNSQuestion *llqMatch = mDNSNULL;
+       uDNS_LLQType LLQType      = uDNS_recvLLQResponse(m, response, end, srcaddr, srcport, &llqMatch);
 
        // "(CacheRecord*)1" is a special (non-zero) end-of-list marker
        // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
@@ -6356,14 +5656,15 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
        int firstadditional = firstauthority  + response->h.numAuthorities;
        int totalrecords    = firstadditional + response->h.numAdditionals;
        const mDNSu8 *ptr   = response->data;
+       DNSServer *uDNSServer = mDNSNULL;
 
        debugf("Received Response from %#-15a addressed to %#-15a on %p with "
-               "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s LLQType %d",
+               "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes LLQType %d",
                srcaddr, dstaddr, InterfaceID,
-               response->h.numQuestions,   response->h.numQuestions   == 1 ? ", " : "s,",
-               response->h.numAnswers,     response->h.numAnswers     == 1 ? ", " : "s,",
+               response->h.numQuestions,   response->h.numQuestions   == 1 ? ", "   : "s,",
+               response->h.numAnswers,     response->h.numAnswers     == 1 ? ", "   : "s,",
                response->h.numAuthorities, response->h.numAuthorities == 1 ? "y,  " : "ies,",
-               response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s", LLQType);
+               response->h.numAdditionals, response->h.numAdditionals == 1 ? " "    : "s", end - response->data, LLQType);
 
        // According to RFC 2181 <http://www.ietf.org/rfc/rfc2181.txt>
        //    When a DNS client receives a reply with TC
@@ -6407,7 +5708,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                        {
                        DNSQuestion q, *qptr = mDNSNULL;
                        ptr = getQuestion(response, ptr, end, InterfaceID, &q);
-                       if (ptr && (!dstaddr || (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q))))
+                       if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr)))
                                {
                                if (!failure)
                                        {
@@ -6415,7 +5716,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                        const mDNSu32 slot = HashSlot(&q.qname);
                                        CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname);
                                        for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
-                                               if (q.InterfaceID == rr->resrec.InterfaceID && SameNameRecordAnswersQuestion(&rr->resrec, &q))
+                                               if (SameNameRecordAnswersQuestion(&rr->resrec, qptr))
                                                        {
                                                        debugf("uDNS marking %p %##s (%s) %p %s", q.InterfaceID, q.qname.c, DNSTypeName(q.qtype),
                                                                rr->resrec.InterfaceID, CRDisplayString(m, rr));
@@ -6428,8 +5729,8 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                        {
                                        if (qptr)
                                                {
-                                               LogInfo("Server %p responded with code %d to query %##s (%s)", qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype));
-                                               PenalizeDNSServer(m, qptr, mDNSfalse);
+                                               LogInfo("mDNSCoreReceiveResponse: Server %p responded with code %d to query %##s (%s)", qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype));
+                                               PenalizeDNSServer(m, qptr);
                                                }
                                        returnEarly = mDNStrue;
                                        }
@@ -6460,19 +5761,34 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                        (i < firstadditional) ? (mDNSu8)kDNSRecordTypePacketAuth : (mDNSu8)kDNSRecordTypePacketAdd;
                ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, RecordType, &m->rec);
                if (!ptr) goto exit;            // Break out of the loop and clean up our CacheFlushRecords list before exiting
+               if (m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative) { m->rec.r.resrec.RecordType = 0; continue; }
 
                // Don't want to cache OPT or TSIG pseudo-RRs
-               if (m->rec.r.resrec.rrtype == kDNSType_OPT || m->rec.r.resrec.rrtype == kDNSType_TSIG)
-                       { m->rec.r.resrec.RecordType = 0; continue; }
-                       
+               if (m->rec.r.resrec.rrtype == kDNSType_TSIG) { m->rec.r.resrec.RecordType = 0; continue; }
+               if (m->rec.r.resrec.rrtype == kDNSType_OPT)
+                       {
+                       const rdataOPT *opt;
+                       const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
+                       // Find owner sub-option(s). We verify that the MAC is non-zero, otherwise we could inadvertently
+                       // delete all our own AuthRecords (which are identified by having zero MAC tags on them).
+                       for (opt = &m->rec.r.resrec.rdata->u.opt[0]; opt < e; opt++)
+                               if (opt->opt == kDNSOpt_Owner && opt->u.owner.vers == 0 && opt->u.owner.HMAC.l[0])
+                                       {
+                                       ClearProxyRecords(m, &opt->u.owner, m->DuplicateRecords);
+                                       ClearProxyRecords(m, &opt->u.owner, m->ResourceRecords);
+                                       }
+                       m->rec.r.resrec.RecordType = 0;
+                       continue;
+                       }
+
                // if a CNAME record points to itself, then don't add it to the cache
                if ((m->rec.r.resrec.rrtype == kDNSType_CNAME) && SameDomainName(m->rec.r.resrec.name, &m->rec.r.resrec.rdata->u.name))
-                       { 
+                       {
                        LogInfo("mDNSCoreReceiveResponse: CNAME loop domain name %##s", m->rec.r.resrec.name->c);
-                       m->rec.r.resrec.RecordType = 0; 
-                       continue; 
+                       m->rec.r.resrec.RecordType = 0;
+                       continue;
                        }
-               
+
                // When we receive uDNS LLQ responses, we assume a long cache lifetime --
                // In the case of active LLQs, we'll get remove events when the records actually do go away
                // In the case of polling LLQs, we assume the record remains valid until the next poll
@@ -6481,7 +5797,57 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
 
                // If response was not sent via LL multicast,
                // then see if it answers a recent query of ours, which would also make it acceptable for caching.
-               if (!AcceptableResponse) AcceptableResponse = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, dstport, response->h.id, &m->rec.r);
+               if (!ResponseMCast)
+                       {
+                       if (LLQType)
+                               {
+                               // For Long Lived queries that are both sent over UDP and Private TCP, LLQType is set.
+                               // Even though it is AcceptableResponse, we need a matching DNSServer pointer for the
+                               // queries to get ADD/RMV events. To lookup the question, we can't use
+                               // ExpectingUnicastResponseForRecord as the port numbers don't match. uDNS_recvLLQRespose
+                               // has already matched the question using the 64 bit Id in the packet and we use that here.
+
+                               if (llqMatch != mDNSNULL) m->rec.r.resrec.rDNSServer = uDNSServer = llqMatch->qDNSServer;
+                               }
+                       else if (!AcceptableResponse || !dstaddr)
+                               {
+                               // For responses that come over TCP (Responses that can't fit within UDP) or TLS (Private queries
+                               // that are not long lived e.g., AAAA lookup in a Private domain), it is indicated by !dstaddr.
+                               // Even though it is AcceptableResponse, we still need a DNSServer pointer for the resource records that
+                               // we create.
+
+                               DNSQuestion *q = ExpectingUnicastResponseForRecord(m, srcaddr, ResponseSrcLocal, dstport, response->h.id, &m->rec.r, !dstaddr);
+
+                               // Intialize the DNS server on the resource record which will now filter what questions we answer with
+                               // this record.
+                               //
+                               // We could potentially lookup the DNS server based on the source address, but that may not work always
+                               // and that's why ExpectingUnicastResponseForRecord does not try to verify whether the response came
+                               // from the DNS server that queried. We follow the same logic here. If we can find a matching quetion based
+                               // on the "id" and "source port", then this response answers the question and assume the response
+                               // came from the same DNS server that we sent the query to.
+
+                               if (q != mDNSNULL)
+                                       {
+                                       AcceptableResponse = mDNStrue;
+                                       if (!InterfaceID)
+                                               {
+                                               debugf("mDNSCoreReceiveResponse: InterfaceID %p %##s (%s)", q->InterfaceID, q->qname.c, DNSTypeName(q->qtype));
+                                               m->rec.r.resrec.rDNSServer = uDNSServer = q->qDNSServer;
+                                               }
+                                       }
+                               else
+                                       {
+                                       // If we can't find a matching question, we need to see whether we have seen records earlier that matched
+                                       // the question. The code below does that. So, make this record unacceptable for now
+                                       if (!InterfaceID)
+                                               {
+                                               debugf("mDNSCoreReceiveResponse: Can't find question for record name %##s", m->rec.r.resrec.name->c);
+                                               AcceptableResponse = mDNSfalse;
+                                               }
+                                       }
+                               }
+                       }
 
                // 1. Check that this packet resource record does not conflict with any of ours
                if (mDNSOpaque16IsZero(response->h.id) && m->rec.r.resrec.rrtype != kDNSType_NSEC)
@@ -6585,15 +5951,26 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                        for (cr = CacheFlushRecords; cr != (CacheRecord*)1; cr = cr->NextInCFList)
                                {
                                domainname *target = GetRRDomainNameTarget(&cr->resrec);
+                               // When we issue a query for A record, the response might contain both a CNAME and A records. Only the CNAME would
+                               // match the question and we already created a cache entry in the previous pass of this loop. Now when we process
+                               // the A record, it does not match the question because the record name here is the CNAME. Hence we try to
+                               // match with the previous records to make it an AcceptableResponse. We have to be careful about setting the
+                               // DNSServer value that we got in the previous pass. This can happen for other record types like SRV also.
+
                                if (target && cr->resrec.rdatahash == m->rec.r.resrec.namehash && SameDomainName(target, m->rec.r.resrec.name))
-                                       { AcceptableResponse = mDNStrue; break; }
+                                       {
+                                       debugf("mDNSCoreReceiveResponse: Found a matching entry for %##s in the CacheFlushRecords", m->rec.r.resrec.name->c);
+                                       AcceptableResponse = mDNStrue;
+                                       m->rec.r.resrec.rDNSServer = uDNSServer;
+                                       break;
+                                       }
                                }
                        }
 
                // 2. See if we want to add this packet resource record to our cache
                // We only try to cache answers if we have a cache to put them in
                // Also, we ignore any apparent attempts at cache poisoning unicast to us that do not answer any outstanding active query
-               if (!AcceptableResponse) debugf("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m, &m->rec.r));
+               if (!AcceptableResponse) LogInfo("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m, &m->rec.r));
                if (m->rrcache_size && AcceptableResponse)
                        {
                        const mDNSu32 slot = HashSlot(m->rec.r.resrec.name);
@@ -6603,13 +5980,13 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                        // 2a. Check if this packet resource record is already in our cache
                        for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
                                {
+                               mDNSBool match = !InterfaceID ? m->rec.r.resrec.rDNSServer == rr->resrec.rDNSServer : rr->resrec.InterfaceID == InterfaceID;
                                // If we found this exact resource record, refresh its TTL
-                               if (rr->resrec.InterfaceID == InterfaceID && IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec))
+                               if (match && IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec))
                                        {
                                        if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
                                                verbosedebugf("Found record size %5d interface %p already in cache: %s",
                                                        m->rec.r.resrec.rdlength, InterfaceID, CRDisplayString(m, &m->rec.r));
-                                       rr->TimeRcvd  = m->timenow;
                                        
                                        if (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask)
                                                {
@@ -6626,14 +6003,20 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                                        }
                                                }
 
-                                       if (!mDNSPlatformMemSame(m->rec.r.resrec.rdata->u.data, rr->resrec.rdata->u.data, m->rec.r.resrec.rdlength))
+                                       if (!SameRDataBody(&m->rec.r.resrec, &rr->resrec.rdata->u, SameDomainNameCS))
                                                {
                                                // If the rdata of the packet record differs in name capitalization from the record in our cache
                                                // then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get
                                                // a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one.
+                                               // <rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
                                                rr->resrec.rroriginalttl = 0;
+                                               rr->TimeRcvd = m->timenow;
                                                rr->UnansweredQueries = MaxUnansweredQueries;
-                                               SetNextCacheCheckTime(m, rr);
+                                               SetNextCacheCheckTimeForRecord(m, rr);
+                                               LogInfo("Discarding due to domainname case change old: %s", CRDisplayString(m,rr));
+                                               LogInfo("Discarding due to domainname case change new: %s", CRDisplayString(m,&m->rec.r));
+                                               LogInfo("Discarding due to domainname case change in %d slot %3d in %d %d",
+                                                       NextCacheCheckEvent(rr) - m->timenow, slot, m->rrcache_nextcheck[slot] - m->timenow, m->NextCacheCheck - m->timenow);
                                                // DO NOT break out here -- we want to continue as if we never found it
                                                }
                                        else if (m->rec.r.resrec.rroriginalttl > 0)
@@ -6654,8 +6037,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                                        {
                                                        for (q = m->Questions; q; q=q->next)
                                                                {
-
-                                                               if (!q->DuplicateOf && !q->LongLived && 
+                                                               if (!q->DuplicateOf && !q->LongLived &&
                                                                        ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
                                                                        {
                                                                        q->LastQTime        = m->timenow;
@@ -6664,8 +6046,8 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                                                        q->ThisQInterval    = MaxQuestionInterval;
                                                                        q->RequestUnicast   = mDNSfalse;
                                                                        q->unansweredQueries = 0;
-                                                                       debugf("mDNSCoreReceiveResponse: Set MaxQuestionInterval for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-                                                                       break;
+                                                                       debugf("mDNSCoreReceiveResponse: Set MaxQuestionInterval for %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+                                                                       break;          // Why break here? Aren't there other questions we might want to look at?-- SC July 2010
                                                                        }
                                                                }
                                                        }
@@ -6678,10 +6060,17 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                                // out one second into the future. Also, we set UnansweredQueries to MaxUnansweredQueries.
                                                // Otherwise, we'll do final queries for this record at 80% and 90% of its apparent
                                                // lifetime (800ms and 900ms from now) which is a pointless waste of network bandwidth.
+                                               // If record's current expiry time is more than a second from now, we set it to expire in one second.
+                                               // If the record is already going to expire in less than one second anyway, we leave it alone --
+                                               // we don't want to let the goodbye packet *extend* the record's lifetime in our cache.
                                                debugf("DE for %s", CRDisplayString(m, rr));
-                                               rr->resrec.rroriginalttl = 1;
-                                               rr->UnansweredQueries = MaxUnansweredQueries;
-                                               SetNextCacheCheckTime(m, rr);
+                                               if (RRExpireTime(rr) - m->timenow > mDNSPlatformOneSecond)
+                                                       {
+                                                       rr->resrec.rroriginalttl = 1;
+                                                       rr->TimeRcvd = m->timenow;
+                                                       rr->UnansweredQueries = MaxUnansweredQueries;
+                                                       SetNextCacheCheckTimeForRecord(m, rr);
+                                                       }
                                                break;
                                                }
                                        }
@@ -6691,9 +6080,19 @@ 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 = CreateNewCacheEntry(m, slot, cg);
-                               if (rr && (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) && LLQType != uDNS_LLQ_Events)
-                                       { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
+                               const mDNSBool AddToCFList = (m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) && (LLQType != uDNS_LLQ_Events);
+                               const mDNSs32 delay = AddToCFList ? NonZeroTime(m->timenow + mDNSPlatformOneSecond) :
+                                       CheckForSoonToExpireRecords(m, m->rec.r.resrec.name, m->rec.r.resrec.namehash, slot);
+                               // If unique, assume we may have to delay delivery of this 'add' event.
+                               // Below, where we walk the CacheFlushRecords list, we either call CacheRecordDeferredAdd()
+                               // to immediately to generate answer callbacks, or we call ScheduleNextCacheCheckTime()
+                               // to schedule an mDNS_Execute task at the appropriate time.
+                               rr = CreateNewCacheEntry(m, slot, cg, delay);
+                               if (rr)
+                                       {
+                                       if (AddToCFList) { *cfp = rr; cfp = &rr->NextInCFList; *cfp = (CacheRecord*)1; }
+                                       else if (rr->DelayDelivery) ScheduleNextCacheCheckTime(m, slot, rr->DelayDelivery);
+                                       }
                                }
                        }
                m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
@@ -6726,7 +6125,9 @@ exit:
                // To avoid this, we need to ensure that the cache flushing operation will only act to
                // *decrease* a record's remaining lifetime, never *increase* it.
                for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next)
-                       if (r1->resrec.InterfaceID == r2->resrec.InterfaceID &&
+                       // For Unicast (null InterfaceID) the DNSservers should also match
+                       if ((r1->resrec.InterfaceID == r2->resrec.InterfaceID) &&
+                               (r1->resrec.InterfaceID || (r1->resrec.rDNSServer == r2->resrec.rDNSServer)) &&
                                r1->resrec.rrtype      == r2->resrec.rrtype &&
                                r1->resrec.rrclass     == r2->resrec.rrclass)
                                {
@@ -6736,7 +6137,7 @@ exit:
                                        {
                                        // If we find mismatched TTLs in an RRSet, correct them.
                                        // We only do this for records with a TTL of 2 or higher. It's possible to have a
-                                       // goodbye announcement with the cache flush bit set (or a case change on record rdata,
+                                       // goodbye announcement with the cache flush bit set (or a case-change on record rdata,
                                        // which we treat as a goodbye followed by an addition) and in that case it would be
                                        // inappropriate to synchronize all the other records to a TTL of 0 (or 1).
                                        // We suppress the message for the specific case of correcting from 240 to 60 for type TXT,
@@ -6757,7 +6158,8 @@ exit:
                                        }
                                else                            // else, if record is old, mark it to be flushed
                                        {
-                                       verbosedebugf("Cache flush %p X %p %s", r1, r2, CRDisplayString(m, r2));
+                                       verbosedebugf("Cache flush new %p age %d expire in %d %s", r1, m->timenow - r1->TimeRcvd, RRExpireTime(r1) - m->timenow, CRDisplayString(m, r1));
+                                       verbosedebugf("Cache flush old %p age %d expire in %d %s", r2, m->timenow - r2->TimeRcvd, RRExpireTime(r2) - m->timenow, CRDisplayString(m, r2));
                                        // 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:
@@ -6774,12 +6176,13 @@ exit:
                                        // If a record is deleted twice, first with an explicit DE record, then a second time by virtue of the cache
                                        // flush bit on the new record replacing it, then we allow the record to be deleted immediately, without the usual
                                        // one-second grace period. This improves responsiveness for mDNS_Update(), as used for things like iChat status updates.
-                                       if (r2->TimeRcvd == m->timenow && r2->resrec.rroriginalttl <= 1 && r2->UnansweredQueries == MaxUnansweredQueries)
+                                       // <rdar://problem/5636422> Updating TXT records is too slow
+                                       // We check for "rroriginalttl == 1" because we want to include records tagged by the "packet TTL is zero" check above,
+                                       // which sets rroriginalttl to 1, but not records tagged by the rdata case-change check, which sets rroriginalttl to 0.
+                                       if (r2->TimeRcvd == m->timenow && r2->resrec.rroriginalttl == 1 && r2->UnansweredQueries == MaxUnansweredQueries)
                                                {
-                                               debugf("Cache flush for DE record %s", CRDisplayString(m, r2));
+                                               LogInfo("Cache flush for DE record %s", CRDisplayString(m, r2));
                                                r2->resrec.rroriginalttl = 0;
-                                               m->NextCacheCheck = m->timenow;
-                                               m->NextScheduledEvent = m->timenow;
                                                }
                                        else if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
                                                {
@@ -6792,13 +6195,15 @@ exit:
                                                // that we marked for deletion via an explicit DE record
                                                }
                                        }
-                               SetNextCacheCheckTime(m, r2);
+                               SetNextCacheCheckTimeForRecord(m, r2);
                                }
+
                if (r1->DelayDelivery)  // If we were planning to delay delivery of this record, see if we still need to
                        {
-                       // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
                        r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, slot);
+                       // If no longer delaying, deliver answer now, else schedule delivery for the appropriate time
                        if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1);
+                       else ScheduleNextCacheCheckTime(m, slot, r1->DelayDelivery);
                        }
                }
 
@@ -6807,8 +6212,9 @@ exit:
        for (i = 0; i < response->h.numQuestions && ptr && ptr < end; i++)
                {
                DNSQuestion q;
+               DNSQuestion *qptr = mDNSNULL;
                ptr = getQuestion(response, ptr, end, InterfaceID, &q);
-               if (ptr && (!dstaddr || ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q)))
+               if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr)))
                        {
                        // When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft
                        // Active Directory sites) we don't want to waste memory making negative cache entries for all the unicast answers.
@@ -6821,17 +6227,17 @@ exit:
                        // in conflict with the mDNS spec, because that spec says, "Multicast DNS Zones have no SOA record," so it's okay to cache
                        // negative answers for "local. SOA" from a uDNS server, because the mDNS spec already says that such records do not exist :-)
                        if (!InterfaceID && q.qtype != kDNSType_SOA && IsLocalDomain(&q.qname))
-                               LogInfo("Not generating negative cache entry for %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
+                               LogInfo("Skipping check to see if we need to generate a negative cache entry for %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
                        else
                                {
                                CacheRecord *rr, *neg = mDNSNULL;
                                mDNSu32 slot = HashSlot(&q.qname);
                                CacheGroup *cg = CacheGroupForName(m, slot, q.qnamehash, &q.qname);
                                for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
-                                       if (SameNameRecordAnswersQuestion(&rr->resrec, &q))
+                                       if (SameNameRecordAnswersQuestion(&rr->resrec, qptr))
                                                {
                                                // 1. If we got a fresh answer to this query, then don't need to generate a negative entry
-                                               if (rr->TimeRcvd + TicksTTL(rr) - m->timenow > 0) break;
+                                               if (RRExpireTime(rr) - m->timenow > 0) break;
                                                // 2. If we already had a negative entry, keep track of it so we can resurrect it instead of creating a new one
                                                if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) neg = rr;
                                                }
@@ -6857,7 +6263,7 @@ exit:
                                        if (response->h.numAuthorities && (ptr = LocateAuthorities(response, end)) != mDNSNULL)
                                                {
                                                ptr = GetLargeResourceRecord(m, response, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
-                                               if (ptr && m->rec.r.resrec.rrtype == kDNSType_SOA)
+                                               if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_SOA)
                                                        {
                                                        const rdataSOA *const soa = (const rdataSOA *)m->rec.r.resrec.rdata->u.data;
                                                        mDNSu32 ttl_s = soa->min;
@@ -6909,8 +6315,8 @@ exit:
                                        else while (1)
                                                {
                                                debugf("mDNSCoreReceiveResponse making negative cache entry TTL %d for %##s (%s)", negttl, name->c, DNSTypeName(q.qtype));
-                                               MakeNegativeCacheRecord(m, &m->rec.r, name, hash, q.qtype, q.qclass, negttl, mDNSInterface_Any);
-                                               CreateNewCacheEntry(m, slot, cg);
+                                               MakeNegativeCacheRecord(m, &m->rec.r, name, hash, q.qtype, q.qclass, negttl, mDNSInterface_Any, qptr->qDNSServer);
+                                               CreateNewCacheEntry(m, slot, cg, 0);    // We never need any delivery delay for these generated negative cache records
                                                m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
                                                if (!repeat) break;
                                                repeat--;
@@ -6925,6 +6331,20 @@ exit:
                }
        }
 
+mDNSlocal void ScheduleWakeupForList(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *e, AuthRecord *const thelist)
+       {
+       AuthRecord *rr;
+       for (rr = thelist; rr; rr=rr->next)
+               if (rr->resrec.InterfaceID == InterfaceID && rr->resrec.RecordType != kDNSRecordTypeDeregistering && mDNSSameEthAddress(&rr->WakeUp.HMAC, e))
+                       mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
+       }
+
+mDNSlocal void ScheduleWakeup(mDNS *const m, mDNSInterfaceID InterfaceID, mDNSEthAddr *e)
+       {
+       ScheduleWakeupForList(m, InterfaceID, e, m->DuplicateRecords);
+       ScheduleWakeupForList(m, InterfaceID, e, m->ResourceRecords);
+       }
+
 mDNSlocal void SPSRecordCallback(mDNS *const m, AuthRecord *const ar, mStatus result)
        {
        if (result && result != mStatus_MemFree)
@@ -6932,15 +6352,15 @@ mDNSlocal void SPSRecordCallback(mDNS *const m, AuthRecord *const ar, mStatus re
 
        if (result == mStatus_NameConflict)
                {
-               char *ifname = InterfaceNameForID(m, ar->resrec.InterfaceID);
-               if (!ifname) ifname = "<NULL InterfaceID>";
-               LogMsg("Received Conflicting mDNS -- waking %s %.6a %s", ifname, &ar->WakeUp.HMAC, ARDisplayString(m, ar));
+               LogMsg("Received Conflicting mDNS -- waking %s %.6a %s", InterfaceNameForID(m, ar->resrec.InterfaceID), &ar->WakeUp.HMAC, ARDisplayString(m, ar));
                SendWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.IMAC, &ar->WakeUp.password);
+               ScheduleWakeup(m, ar->resrec.InterfaceID, &ar->WakeUp.HMAC);
                }
        else if (result == mStatus_MemFree)
                {
                m->ProxyRecords--;
                mDNSPlatformMemFree(ar);
+               mDNS_UpdateAllowSleep(m);
                }
        }
 
@@ -6957,12 +6377,12 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
        const mDNSu8 *ptr;
 
        LogSPS("Received Update from %#-15a:%-5d to %#-15a:%-5d on 0x%p with "
-               "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
+               "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes",
                srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), InterfaceID,
-               msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", " : "s,",
-               msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", " : "s,",
+               msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", "   : "s,",
+               msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", "   : "s,",
                msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y,  " : "ies,",
-               msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
+               msg->h.numAdditionals, msg->h.numAdditionals == 1 ? " "    : "s", end - msg->data);
 
        if (!InterfaceID || !m->SPSSocket || !mDNSSameIPPort(dstport, m->SPSSocket->port)) return;
 
@@ -6973,7 +6393,7 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
        if (ptr)
                {
                ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
-               if (ptr && m->rec.r.resrec.rrtype == kDNSType_OPT)
+               if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_OPT)
                        {
                        const rdataOPT *o;
                        const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
@@ -7024,7 +6444,7 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
                for (i = 0; i < msg->h.mDNS_numUpdates && ptr && ptr < end; i++)
                        {
                        ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
-                       if (ptr)
+                       if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative)
                                {
                                mDNSu16 RDLengthMem = GetRDLengthMem(&m->rec.r.resrec);
                                AuthRecord *ar = mDNSPlatformMemAllocate(sizeof(AuthRecord) - sizeof(RDataBody) + RDLengthMem);
@@ -7033,12 +6453,15 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
                                        {
                                        mDNSu8 RecordType = m->rec.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask ? kDNSRecordTypeUnique : kDNSRecordTypeShared;
                                        m->rec.r.resrec.rrclass &= ~kDNSClass_UniqueRRSet;
+                                       ClearIdenticalProxyRecords(m, &owner, m->DuplicateRecords);     // Make sure we don't have any old stale duplicates of this record
+                                       ClearIdenticalProxyRecords(m, &owner, m->ResourceRecords);
                                        mDNS_SetupResourceRecord(ar, mDNSNULL, InterfaceID, m->rec.r.resrec.rrtype, m->rec.r.resrec.rroriginalttl, RecordType, SPSRecordCallback, ar);
                                        AssignDomainName(&ar->namestorage, m->rec.r.resrec.name);
                                        ar->resrec.rdlength = GetRDLength(&m->rec.r.resrec, mDNSfalse);
                                        ar->resrec.rdata->MaxRDLength = RDLengthMem;
                                        mDNSPlatformMemCopy(ar->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, RDLengthMem);
-                                       ar->WakeUp = owner;
+                                       ar->ForceMCast = mDNStrue;
+                                       ar->WakeUp     = owner;
                                        if (m->rec.r.resrec.rrtype == kDNSType_PTR)
                                                {
                                                mDNSs32 t = ReverseMapDomainType(m->rec.r.resrec.name);
@@ -7052,9 +6475,15 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
                                        if (m->NextScheduledSPS - ar->TimeExpire > 0)
                                                m->NextScheduledSPS = ar->TimeExpire;
                                        mDNS_Register_internal(m, ar);
-                                       // For now, since we don't get IPv6 ND or data packets, we don't advertise AAAA records for our SPS clients
-                                       if (ar->resrec.rrtype == kDNSType_AAAA) ar->resrec.rroriginalttl = 0;
+                                       // Unsolicited Neighbor Advertisements (RFC 2461 Section 7.2.6) give us fast address cache updating,
+                                       // but some older IPv6 clients get confused by them, so for now we don't send them. Without Unsolicited
+                                       // Neighbor Advertisements we have to rely on Neighbor Unreachability Detection instead, which is slower.
+                                       // Given this, we'll do our best to wake for existing IPv6 connections, but we don't want to encourage
+                                       // new ones for sleeping clients, so we'll we send deletions for our SPS clients' AAAA records.
+                                       if (m->KnownBugs & mDNS_KnownBug_LimitedIPv6)
+                                               if (ar->resrec.rrtype == kDNSType_AAAA) ar->resrec.rroriginalttl = 0;
                                        m->ProxyRecords++;
+                                       mDNS_UpdateAllowSleep(m);
                                        LogSPS("SPS Registered %4d %X %s", m->ProxyRecords, RecordType, ARDisplayString(m,ar));
                                        }
                                }
@@ -7092,7 +6521,7 @@ mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg
                if (ptr)
                        {
                        ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
-                       if (ptr && m->rec.r.resrec.rrtype == kDNSType_OPT)
+                       if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_OPT)
                                {
                                const rdataOPT *o;
                                const rdataOPT *const e = (const rdataOPT *)&m->rec.r.resrec.rdata->u.data[m->rec.r.resrec.rdlength];
@@ -7122,7 +6551,7 @@ mDNSlocal void mDNSCoreReceiveUpdateR(mDNS *const m, const DNSMessage *const msg
        }
 
 mDNSexport void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr,
-       const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds, mDNSInterfaceID InterfaceID)
+       const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds, mDNSInterfaceID InterfaceID, DNSServer *dnsserver)
        {
        if (cr == &m->rec.r && m->rec.r.resrec.RecordType)
                {
@@ -7135,6 +6564,7 @@ mDNSexport void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr,
        // Create empty resource record
        cr->resrec.RecordType    = kDNSRecordTypePacketNegative;
        cr->resrec.InterfaceID   = InterfaceID;
+       cr->resrec.rDNSServer    = dnsserver;
        cr->resrec.name          = name;        // Will be updated to point to cg->name when we call CreateNewCacheEntry
        cr->resrec.rrtype        = rrtype;
        cr->resrec.rrclass       = rrclass;
@@ -7280,6 +6710,14 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, void *const pkt, const mDNSu8 *co
 // and we have a key for company.com, so we try to locate the private query server for company.com, which necessarily entails
 // doing a standard DNS query for the _dns-query-tls._tcp SRV record for company.com. If we make the latter (public) query
 // a duplicate of the former (private) query, then it will block forever waiting for an answer that will never come.
+//
+// We keep SuppressUnusable questions separate so that we can return a quick response to them and not get blocked behind
+// the queries that are not marked SuppressUnusable. But if the query is not suppressed, they are treated the same as
+// non-SuppressUnusable questions. This should be fine as the goal of SuppressUnusable is to return quickly only if it
+// is suppressed. If it is not suppressed, we do try all the DNS servers for valid answers like any other question.
+// The main reason for this design is that cache entries point to a *single* question and that question is responsible
+// for keeping the cache fresh as long as it is active. Having multiple active question for a single cache entry
+// breaks this design principle.
 
 // If IsLLQ(Q) is true, it means the question is both:
 // (a) long-lived and
@@ -7301,6 +6739,7 @@ mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuest
                        q->qclass     == question->qclass       &&                      // class,
                        IsLLQ(q)      == IsLLQ(question)        &&                      // and long-lived status matches
                        (!q->AuthInfo || question->AuthInfo)    &&                      // to avoid deadlock, don't make public query dup of a private one
+                       (q->SuppressQuery == question->SuppressQuery) &&        // Questions that are suppressed/not suppressed
                        q->qnamehash  == question->qnamehash    &&
                        SameDomainName(&q->qname, &question->qname))            // and name
                        return(q);
@@ -7329,7 +6768,10 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi
                                q->servAddr          = question->servAddr;
                                q->servPort          = question->servPort;
                                q->qDNSServer        = question->qDNSServer;
+                               q->validDNSServers   = question->validDNSServers;
                                q->unansweredQueries = question->unansweredQueries;
+                               q->noServerResponse  = question->noServerResponse;
+                               q->triedAllServersOnce = question->triedAllServersOnce;
 
                                q->TargetQID         = question->TargetQID;
                                q->LocalSocket       = question->LocalSocket;
@@ -7378,7 +6820,8 @@ mDNSinline mDNSs32 PenaltyTimeForServer(mDNS *m, DNSServer *server)
                        // This should always be a positive value between 0 and DNSSERVER_PENALTY_TIME
                        // If it does not get reset in ResetDNSServerPenalties for some reason, we do it
                        // here
-                       LogMsg("PenaltyTimeForServer: PenaltyTime negative %d, (server penaltyTime %d, timenow %d) resetting the penalty", ptime, server->penaltyTime, m->timenow);
+                       LogMsg("PenaltyTimeForServer: PenaltyTime negative %d, (server penaltyTime %d, timenow %d) resetting the penalty",
+                               ptime, server->penaltyTime, m->timenow);
                        server->penaltyTime = 0;
                        ptime = 0;
                        }
@@ -7386,61 +6829,6 @@ mDNSinline mDNSs32 PenaltyTimeForServer(mDNS *m, DNSServer *server)
        return ptime;
        }
 
-// Return the next server to "prev" if it is a match and unpenalized
-mDNSlocal DNSServer *GetNextUnPenalizedServer(mDNS *m, DNSServer *prev)
-       {
-       int curmatchlen = -1;
-       DNSServer *curr = m->DNSServers;
-
-       if (prev == mDNSNULL) return mDNSNULL;
-
-       while (curr != mDNSNULL && curr != prev)
-               curr = curr->next;
-
-       if (curr == mDNSNULL)
-               return mDNSNULL;
-
-
-       // We need to set the curmatchlen as though we are walking the list
-       // from the beginning. Otherwise, we may not pick the best match.
-       // For example, if we are looking up xxx.com, and we used the "xxx.com"
-       // entry the previous time and the next one is "com", we should not pick
-       // "com" now
-       curmatchlen = CountLabels(&curr->domain);
-       curr = curr->next;
-       while (curr != mDNSNULL)
-               {
-               int scount = CountLabels(&curr->domain);
-
-               // Should not be delete because it is marked temporarily for cleaning up
-               // entries during configuration change and we pass NULL as the last argument
-               // to GetServerForName 
-               if (curr->flags & DNSServer_FlagDelete)
-                       {
-                       LogInfo("GetServerForName: DNS Server is marked delete, cannot happen");
-                       curr = curr->next;
-                       continue;
-                       }
-
-
-               debugf("GetNextUnPenalizedServer: Address %#a (Domain %##s), PenaltyTime(abs) %d, PenaltyTime(rel) %d", &curr->addr, curr->domain.c, curr->penaltyTime, PenaltyTimeForServer(m,curr));
-
-               // Note the "==" in comparing scount and curmatchlen. When we picked a match
-               // for the question the first time, we already made sure that prev is the best match.
-               // Any other match is as good if we can find another entry with same number of
-               // labels. There can't be better matches that have more labels, because
-               // we would have picked that in the first place. Also we don't care what the
-               // name in the question is as we picked the best server for the question first
-               // time and the domain name is in prev now
-
-               if ((curr->penaltyTime == 0) && (scount == curmatchlen) && SameDomainName(&prev->domain, &curr->domain))
-                               return curr;
-               curr = curr->next;
-               }
-       return mDNSNULL;
-       }
-
-
 //Checks to see whether the newname is a better match for the name, given the best one we have
 //seen so far (given in bestcount).
 //Returns -1 if the newname is not a better match
@@ -7463,7 +6851,7 @@ mDNSlocal int BetterMatchForName(const domainname *name, int namecount, const do
        // If we find a match and the number of labels is more than bestcount, then we
        // return 1 so that the caller can pick this over the old one.
        //
-       // NOTE: newcount can either be equal or greater than bestcount beause of the
+       // Note: newcount can either be equal or greater than bestcount beause of the
        // check above.
 
        if (SameDomainName(SkipLeadingLabels(name, namecount - newcount), newname))
@@ -7472,26 +6860,76 @@ mDNSlocal int BetterMatchForName(const domainname *name, int namecount, const do
                return -1;
        }
 
+// Sets all the Valid DNS servers for a question
+mDNSexport void SetValidDNSServers(mDNS *m, DNSQuestion *question)
+       {
+       DNSServer *curmatch = mDNSNULL;
+       int bestmatchlen = -1, namecount = CountLabels(&question->qname);
+       DNSServer *curr;
+       int bettermatch, currcount;
+       int index = 0;
+
+       question->validDNSServers = zeroOpaque64;
+       for (curr = m->DNSServers; curr; curr = curr->next)
+               {
+               debugf("SetValidDNSServers: Parsing DNS server Address %#a (Domain %##s), Scope: %d", &curr->addr, curr->domain.c, curr->scoped);
+               // skip servers that will soon be deleted
+               if (curr->flags & DNSServer_FlagDelete)
+                       { debugf("SetValidDNSServers: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scoped); continue; }
+
+               currcount = CountLabels(&curr->domain);
+               if ((!curr->scoped && (!question->InterfaceID || (question->InterfaceID == mDNSInterface_Unicast))) || (curr->interface == question->InterfaceID))
+                       {
+                       bettermatch = BetterMatchForName(&question->qname, namecount, &curr->domain, currcount, bestmatchlen);
+
+                       // If we found a better match (bettermatch == 1) then clear all the bits
+                       // corresponding to the old DNSServers that we have may set before and start fresh.
+                       // If we find an equal match, then include that DNSServer also by setting the corresponding
+                       // bit
+                       if ((bettermatch == 1) || (bettermatch == 0))
+                               {
+                               curmatch = curr;
+                               bestmatchlen = currcount;
+                               if (bettermatch) { debugf("SetValidDNSServers: Resetting all the bits"); question->validDNSServers = zeroOpaque64; }
+                               debugf("SetValidDNSServers: Setting the bit for DNS server Address %#a (Domain %##s), Scoped:%d index %d", &curr->addr, curr->domain.c, curr->scoped, index);
+                               bit_set_opaque64(question->validDNSServers, index);
+                               }
+                       }
+               index++;
+               }
+       question->noServerResponse = 0;
+       debugf("SetValidDNSServers: ValidDNSServer bits  0x%x%x for question %p %##s (%s)",
+               question->validDNSServers.l[1], question->validDNSServers.l[0], question, question->qname.c, DNSTypeName(question->qtype));
+       }
+
 // Get the Best server that matches a name. If you find penalized servers, look for the one
 // that will come out of the penalty box soon
-mDNSlocal DNSServer *GetAnyBestServer(mDNS *m, const domainname *name)
+mDNSlocal DNSServer *GetBestServer(mDNS *m, const domainname *name, mDNSInterfaceID InterfaceID, mDNSOpaque64 validBits, int *selected, mDNSBool nameMatch)
        {
        DNSServer *curmatch = mDNSNULL;
        int bestmatchlen = -1, namecount = name ? CountLabels(name) : 0;
        DNSServer *curr;
-       mDNSs32 bestPenaltyTime;
-       int bettermatch;
+       mDNSs32 bestPenaltyTime, currPenaltyTime;
+       int bettermatch, currcount;
+       int index = 0;
+       int currindex = -1;
 
-       bestmatchlen = -1;
+       debugf("GetBestServer: ValidDNSServer bits  0x%x%x", validBits.l[1], validBits.l[0]);
        bestPenaltyTime = DNSSERVER_PENALTY_TIME + 1;
        for (curr = m->DNSServers; curr; curr = curr->next)
                {
-               int currcount = CountLabels(&curr->domain);
-               mDNSs32 currPenaltyTime = PenaltyTimeForServer(m, curr);
+               // skip servers that will soon be deleted
+               if (curr->flags & DNSServer_FlagDelete)
+                       { debugf("GetBestServer: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scoped); continue; }
 
-               debugf("GetAnyBestServer: Address %#a (Domain %##s), PenaltyTime(abs) %d, PenaltyTime(rel) %d",
-                       &curr->addr, curr->domain.c, curr->penaltyTime, currPenaltyTime);
+               // Check if this is a valid DNSServer
+               if (!bit_get_opaque64(validBits, index)) { debugf("GetBestServer: continuing for index %d", index); index++; continue; }
 
+               currcount = CountLabels(&curr->domain);
+               currPenaltyTime = PenaltyTimeForServer(m, curr);
+
+               debugf("GetBestServer: Address %#a (Domain %##s), PenaltyTime(abs) %d, PenaltyTime(rel) %d",
+                       &curr->addr, curr->domain.c, curr->penaltyTime, currPenaltyTime);
 
                // If there are multiple best servers for a given question, we will pick the first one
                // if none of them are penalized. If some of them are penalized in that list, we pick
@@ -7499,65 +6937,104 @@ mDNSlocal DNSServer *GetAnyBestServer(mDNS *m, const domainname *name)
                // "currPenaltyTime < bestPenaltyTime" check lets us either pick the first best server
                // in the list when there are no penalized servers and least one among them
                // when there are some penalized servers
-
-               if (!(curr->flags & DNSServer_FlagDelete))
-                       {
-
-                       bettermatch = BetterMatchForName(name, namecount, &curr->domain, currcount, bestmatchlen);
+               //
+               // Notes on InterfaceID matching:
+               //
+               // 1) A DNSServer entry may have an InterfaceID but the scoped flag may not be set. This
+               // is the old way of specifying an InterfaceID option for DNSServer. We recoginize these
+               // entries by "scoped" being false. These are like any other unscoped entries except that
+               // if it is picked e.g., domain match, when the packet is sent out later, the packet will
+               // be sent out on that interface. Theese entries can be matched by either specifying a
+               // zero InterfaceID or non-zero InterfaceID on the question. Specifying an InterfaceID on
+               // the question will cause an extra check on matching the InterfaceID on the question
+               // against the DNSServer.
+               // 
+               // 2) A DNSServer may also have both scoped set and InterfaceID non-NULL. This
+               // is the new way of specifying an InterfaceID option for DNSServer. These will be considered
+               // only when the question has non-zero interfaceID.
+
+               if ((!curr->scoped && !InterfaceID) || (curr->interface == InterfaceID))
+                       {
+
+                       // If we know that all the names are already equally good matches, then skip calling BetterMatchForName.
+                       // This happens when we initially walk all the DNS servers and set the validity bit on the question.
+                       // Actually we just need PenaltyTime match, but for the sake of readability we just skip the expensive
+                       // part and still do some redundant steps e.g., InterfaceID match
+
+                       if (nameMatch) bettermatch = BetterMatchForName(name, namecount, &curr->domain, currcount, bestmatchlen);
+                       else bettermatch = 0;
 
                        // If we found a better match (bettermatch == 1) then we don't need to
                        // compare penalty times. But if we found an equal match, then we compare
                        // the penalty times to pick a better match
 
                        if ((bettermatch == 1) || ((bettermatch == 0) && currPenaltyTime < bestPenaltyTime))
-                               { curmatch = curr; bestmatchlen = currcount; bestPenaltyTime = currPenaltyTime;}
+                               { currindex = index; curmatch = curr; bestmatchlen = currcount; bestPenaltyTime = currPenaltyTime; }
                        }
+               index++;
                }
-
+       if (selected) *selected = currindex;
        return curmatch;
        }
 
-// Look up a DNS Server, matching by name in split-dns configurations.
-mDNSexport DNSServer *GetServerForName(mDNS *m, const domainname *name, DNSServer *prev)
+// Look up a DNS Server, matching by name and InterfaceID
+mDNSexport DNSServer *GetServerForName(mDNS *m, const domainname *name, mDNSInterfaceID InterfaceID)
+    {
+       DNSServer *curmatch = mDNSNULL;
+       char *ifname = mDNSNULL;        // for logging purposes only
+       mDNSOpaque64 allValid;
+
+       if ((InterfaceID == mDNSInterface_Unicast) || (InterfaceID == mDNSInterface_LocalOnly))
+               InterfaceID = mDNSNULL;
+
+       if (InterfaceID) ifname = InterfaceNameForID(m, InterfaceID);
+
+       // By passing in all ones, we make sure that every DNS server is considered
+       allValid.l[0] = allValid.l[1] = 0xFFFFFFFF;
+
+       curmatch = GetBestServer(m, name, InterfaceID, allValid, mDNSNULL, mDNStrue);
+
+       if (curmatch != mDNSNULL)
+               LogInfo("GetServerForName: DNS server %#a:%d (Penalty Time Left %d) (Scope %s:%p) found for name %##s", &curmatch->addr,
+                   mDNSVal16(curmatch->port), (curmatch->penaltyTime ? (curmatch->penaltyTime - m->timenow) : 0), ifname ? ifname : "None",
+               InterfaceID, name);
+       else
+               LogInfo("GetServerForName: no DNS server (Scope %s:%p) found for name %##s", ifname ? ifname : "None", InterfaceID, name);
+
+       return(curmatch);
+       }
+
+// Look up a DNS Server for a question within its valid DNSServer bits
+mDNSexport DNSServer *GetServerForQuestion(mDNS *m, DNSQuestion *question)
     {
        DNSServer *curmatch = mDNSNULL;
+       char *ifname = mDNSNULL;        // for logging purposes only
+       mDNSInterfaceID InterfaceID = question->InterfaceID;
+       const domainname *name = &question->qname;
+       int currindex;
 
-       // prev is the previous DNS server used by some question
-       if (prev != mDNSNULL)
+       if ((InterfaceID == mDNSInterface_Unicast) || (InterfaceID == mDNSInterface_LocalOnly))
+               InterfaceID = mDNSNULL;
+
+       if (InterfaceID) ifname = InterfaceNameForID(m, InterfaceID);
+
+       if (!mDNSOpaque64IsZero(&question->validDNSServers))
                {
-               curmatch = GetNextUnPenalizedServer(m, prev);
-               if (curmatch != mDNSNULL) 
-                       {
-                       LogInfo("GetServerForName: Good DNS server %#a:%d (Penalty Time Left %d) found", &curmatch->addr,
-                           mDNSVal16(curmatch->port), (curmatch->penaltyTime ? (curmatch->penaltyTime - m->timenow) : 0));
-                       return curmatch;
-                       }
+               curmatch = GetBestServer(m, name, InterfaceID, question->validDNSServers, &currindex, mDNSfalse);
+               if (currindex != -1) bit_clr_opaque64(question->validDNSServers, currindex);
                }
-       
-       // We are here for many reasons.
-       //
-       // 1. We are looking up the DNS server first time for this question
-       // 2. We reached the end of list looking for unpenalized servers
-       //
-       // In the case of (1) we want to find the best match for the name. If nothing is penalized,
-       // we want the first one in the list. If some are penalized, we want the one that will get
-       // out of penalty box sooner
-       //
-       // In the case of (2) we want to select the first server that matches the name if StrictUnicastOrdering
-       // is TRUE. As penaltyTime is zero for all of them in that case, we automatically achieve that below.
-       // If StrictUnicastOrdering is FALSE, we want to pick the least penalized server in the list
 
-       curmatch = GetAnyBestServer(m, name);
-
-       if (curmatch != mDNSNULL) 
-               LogInfo("GetServerForName: DNS server %#a:%d (Penalty Time Left %d) found", &curmatch->addr,
-                   mDNSVal16(curmatch->port), (curmatch->penaltyTime ? (curmatch->penaltyTime - m->timenow) : 0));
+       if (curmatch != mDNSNULL)
+               LogInfo("GetServerForQuestion: %p DNS server %#a:%d (Penalty Time Left %d) (Scope %s:%p) found for name %##s (%s)", question, &curmatch->addr,
+                   mDNSVal16(curmatch->port), (curmatch->penaltyTime ? (curmatch->penaltyTime - m->timenow) : 0), ifname ? ifname : "None",
+               InterfaceID, name, DNSTypeName(question->qtype));
        else
-               LogInfo("GetServerForName: no DNS server found");
+               LogInfo("GetServerForQuestion: %p no DNS server (Scope %s:%p) found for name %##s (%s)", question, ifname ? ifname : "None", InterfaceID, name, DNSTypeName(question->qtype));
 
        return(curmatch);
        }
 
+
 #define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
        (mDNSSameIPPort((Q)->TargetPort, UnicastDNSPort) || mDNSSameIPPort((Q)->TargetPort, MulticastDNSPort)))
 
@@ -7567,7 +7044,7 @@ mDNSlocal void LLQNATCallback(mDNS *m, NATTraversalInfo *n)
        DNSQuestion *q;
        (void)n;    // Unused
        mDNS_Lock(m);
-       LogInfo("LLQNATCallback external address:port %.4a:%u", &n->ExternalAddress, mDNSVal16(n->ExternalPort));
+       LogInfo("LLQNATCallback external address:port %.4a:%u, NAT result %d", &n->ExternalAddress, mDNSVal16(n->ExternalPort), n->Result);
        for (q = m->Questions; q; q=q->next)
                if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived)
                        startLLQHandshake(m, q);        // If ExternalPort is zero, will do StartLLQPolling instead
@@ -7577,6 +7054,212 @@ mDNSlocal void LLQNATCallback(mDNS *m, NATTraversalInfo *n)
        mDNS_Unlock(m);
        }
 
+mDNSlocal mDNSBool ShouldSuppressQuery(mDNS *const m, domainname *qname, mDNSu16 qtype, mDNSInterfaceID InterfaceID)
+       {
+       NetworkInterfaceInfo *i;
+       mDNSs32 iptype;
+       DomainAuthInfo *AuthInfo;
+
+       if (qtype == kDNSType_A) iptype = mDNSAddrType_IPv4;
+       else if (qtype == kDNSType_AAAA) iptype = mDNSAddrType_IPv6;
+       else { LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, not A/AAAA type", qname, DNSTypeName(qtype)); return mDNSfalse; }
+
+       // We still want the ability to be able to listen to the local services and hence
+       // don't fail .local requests. We always have a loopback interface which we don't
+       // check here.
+       if (IsLocalDomain(qname)) { LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, Local question", qname, DNSTypeName(qtype)); return mDNSfalse; }
+
+       // Skip Private domains as we have special addresses to get the hosts in the Private domain
+       AuthInfo = GetAuthInfoForName_internal(m, qname);
+       if (AuthInfo && !AuthInfo->deltime && AuthInfo->AutoTunnel)
+               { LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, Private Domain", qname, DNSTypeName(qtype)); return mDNSfalse; }
+
+       // Match on Type, Address and InterfaceID
+       //
+       // Check whether we are looking for a name that ends in .local, then presence of a link-local
+       // address on the interface is sufficient.
+       for (i = m->HostInterfaces; i; i = i->next)
+               {
+               if (i->ip.type != iptype) continue;
+
+               if (!InterfaceID || (InterfaceID == mDNSInterface_LocalOnly) || (InterfaceID == mDNSInterface_P2P) ||
+                       (i->InterfaceID == InterfaceID))
+                       {
+                       if (iptype == mDNSAddrType_IPv4 && !mDNSv4AddressIsLoopback(&i->ip.ip.v4) && !mDNSv4AddressIsLinkLocal(&i->ip.ip.v4))
+                               {
+                               LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, Local Address %.4a found", qname, DNSTypeName(qtype),
+                                       &i->ip.ip.v4);
+                               return mDNSfalse;
+                               }
+                       else if (iptype == mDNSAddrType_IPv6 &&
+                               !mDNSv6AddressIsLoopback(&i->ip.ip.v6) &&
+                               !mDNSv6AddressIsLinkLocal(&i->ip.ip.v6) &&
+                               !mDNSSameIPv6Address(i->ip.ip.v6, m->AutoTunnelHostAddr) &&
+                               !mDNSSameIPv6Address(i->ip.ip.v6, m->AutoTunnelRelayAddr))
+                               {
+                               LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, Local Address %.16a found", qname, DNSTypeName(qtype),
+                                       &i->ip.ip.v6);
+                               return mDNSfalse;
+                               }
+                       }
+               }
+       LogInfo("ShouldSuppressQuery: Query suppressed for %##s, qtype %s, because no matching interface found", qname, DNSTypeName(qtype));
+       return mDNStrue;
+       }
+
+mDNSlocal void CheckSuppressedCurrentQuestion(mDNS *const m, DNSQuestion *q)
+       {
+       CacheRecord *rr;
+       mDNSu32 slot;
+       CacheGroup *cg;
+
+       // Temporarily turn off suppression so that AnswerCurrentQuestionWithResourceRecord
+       // can answer the question
+       q->SuppressQuery = mDNSfalse;
+       slot = HashSlot(&q->qname);
+       cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+       for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+               {
+               // Don't deliver RMV events for negative records
+               if (rr->resrec.RecordType == kDNSRecordTypePacketNegative)
+                       {
+                       LogInfo("CheckSuppressedCurrentQuestion: CacheRecord %s Suppressing RMV events for question %p %##s (%s), CRActiveQuestion %p, CurrentAnswers %d",
+                               CRDisplayString(m, rr), q, q->qname.c, DNSTypeName(q->qtype), rr->CRActiveQuestion, q->CurrentAnswers);
+                       continue;
+                       }
+
+               if (SameNameRecordAnswersQuestion(&rr->resrec, q))
+                       {
+                       LogInfo("CheckSuppressedCurrentQuestion: Calling AnswerCurrentQuestionWithResourceRecord (RMV) for question %##s using resource record %s",
+                               q->qname.c, CRDisplayString(m, rr));
+
+                       q->CurrentAnswers--;
+                       if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
+                       if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
+
+                       if (rr->CRActiveQuestion == q)
+                               {
+                               DNSQuestion *qptr;
+                               // If this was the active question for this cache entry, it was the one that was
+                               // responsible for keeping the cache entry fresh when the cache entry was reaching
+                               // its expiry. We need to handover the responsibility to someone else. Otherwise,
+                               // when the cache entry is about to expire, we won't find an active question
+                               // (pointed by CRActiveQuestion) to refresh the cache.
+                               for (qptr = m->Questions; qptr; qptr=qptr->next)
+                                       if (ActiveQuestion(qptr) && ResourceRecordAnswersQuestion(&rr->resrec, qptr))
+                                               break;
+
+                               if (qptr)
+                                       LogInfo("CheckSuppressedCurrentQuestion: Updating CRActiveQuestion to %p for cache record %s, "
+                                               "Original question CurrentAnswers %d, new question CurrentAnswers %d, SuppressUnusable %d, SuppressQuery %d",
+                                               qptr, CRDisplayString(m,rr), q->CurrentAnswers, qptr->CurrentAnswers, qptr->SuppressUnusable, qptr->SuppressQuery);
+
+                               rr->CRActiveQuestion = qptr;            // Question used to be active; new value may or may not be null
+                               if (!qptr) m->rrcache_active--; // If no longer active, decrement rrcache_active count
+                               }
+                       AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv);
+                       if (m->CurrentQuestion != q) break;             // If callback deleted q, then we're finished here
+                       }
+               }
+               if (m->CurrentQuestion == q) q->SuppressQuery = mDNStrue;
+       }
+
+mDNSlocal mDNSBool IsQuestionNew(mDNS *const m, DNSQuestion *question)
+       {
+       DNSQuestion *q;
+       for (q = m->NewQuestions; q; q = q->next)
+               if (q == question) return mDNStrue;
+       return mDNSfalse;
+       }
+
+// The caller should hold the lock
+mDNSexport void CheckSuppressUnusableQuestions(mDNS *const m)
+       {
+       DNSQuestion *q, *qnext;
+       DNSQuestion *restart = mDNSNULL;
+
+       // We look through all questions including new questions. During network change events,
+       // we potentially restart questions here in this function that ends up as new questions,
+       // which may be suppressed at this instance. Before it is handled we get another network
+       // event that changes the status e.g., address becomes available. If we did not process
+       // new questions, we would never change its SuppressQuery status.
+       for (q = m->Questions; q ; q = qnext)
+               {
+               qnext = q->next;
+               if (!mDNSOpaque16IsZero(q->TargetQID) && q->SuppressUnusable)
+                       {
+                       mDNSBool old = q->SuppressQuery;
+                       q->SuppressQuery = ShouldSuppressQuery(m, &q->qname, q->qtype, q->InterfaceID);
+                       if (q->SuppressQuery != old)
+                               {
+                               if (q->SuppressQuery)
+                                       {
+                                       // Previously it was not suppressed, Generate RMV events for the ADDs that we might have delivered before
+                                       // followed by a negative cache response
+                                       if (m->CurrentQuestion)
+                                               LogMsg("CheckSuppressUnusableQuestions: ERROR m->CurrentQuestion already set: %##s (%s)",
+                                                       m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+
+                                       // If it is a new question, we have not delivered any ADD events yet. So, don't deliver RMV events.
+                                       if (!IsQuestionNew(m, q))
+                                               {
+                                               m->CurrentQuestion = q;
+                                               CheckSuppressedCurrentQuestion(m, q);
+                                               if (m->CurrentQuestion != q)
+                                                       {
+                                                       m->CurrentQuestion = mDNSNULL;
+                                                       LogInfo("CheckSuppressUnusableQuestions: Question deleted while giving RMV events");
+                                                       continue;
+                                                       }
+                                               m->CurrentQuestion = mDNSNULL;
+                                               }
+                                       else { debugf("CheckSuppressUnusableQuestion: Question %p %##s (%s) is a new question", q, q->qname.c, DNSTypeName(q->qtype)); }
+                                       }
+
+                               // There are two cases here.
+                               //
+                               // 1. Previously it was suppressed and now it is not suppressed, restart the question so
+                               // that it will start as a new question. Note that we can't just call ActivateUnicastQuery
+                               // because when we get the response, if we had entries in the cache already, it will not answer
+                               // this question if the cache entry did not change. Hence, we need to restart
+                               // the query so that it can be answered from the cache.
+                               //
+                               // 2. Previously it was not suppressed and now it is suppressed. We need to restart the questions
+                               // so that we redo the duplicate checks in mDNS_StartQuery_internal. A SuppressUnusable question
+                               // is a duplicate of non-SuppressUnusable question if it is not suppressed (SuppressQuery is false).
+                               // A SuppressUnusable question is not a duplicate of non-SuppressUnusable question if it is suppressed
+                               // (SuppressQuery is true). The reason for this is that when a question is suppressed, we want an
+                               // immediate response and not want to be blocked behind a question that is querying DNS servers.
+                               // When the question is not suppressed, we don't want two active questions sending packets on the wire.
+                               // This affects both efficiency and also the current design where there is only one active question
+                               // pointed to from a cache entry.
+                               //
+                               // We restart queries in a two step process by first calling stop and build a temporary list which we
+                               // will restart at the end. The main reason for the two step process is to handle duplicate questions.
+                               // If there are duplicate questions, calling stop inherits the values from another question on the list (which
+                               // will soon become the real question) including q->ThisQInterval which might be zero if it was
+                               // suppressed before. At the end when we have restarted all questions, none of them is active as each
+                               // inherits from one another and we need to reactivate one of the questions here which is a little hacky.
+                               //
+                               // It is much cleaner and less error prone to build a list of questions and restart at the end.
+
+                               LogInfo("CheckSuppressUnusableQuestions: Stop question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+                               mDNS_StopQuery_internal(m, q);
+                               q->next = restart;
+                               restart = q;
+                               }
+                       }
+               }
+       while (restart)
+               {
+               q = restart;
+               restart = restart->next;
+               q->next = mDNSNULL;
+               LogInfo("CheckSuppressUnusableQuestions: Start question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+               mDNS_StartQuery_internal(m, q);
+               }
+       }
+
 mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question)
        {
        if (question->Target.type && !ValidQuestionTarget(question))
@@ -7586,13 +7269,11 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
                question->Target.type = mDNSAddrType_None;
                }
 
-       if (!question->Target.type) question->TargetPort = zeroIPPort;  // If question->Target specified clear TargetPort
+       if (!question->Target.type) question->TargetPort = zeroIPPort;  // If no question->Target specified clear TargetPort
 
        question->TargetQID =
 #ifndef UNICAST_DISABLED
-               (question->Target.type || (question->InterfaceID == mDNSInterface_Unicast) ||
-               (question->InterfaceID != mDNSInterface_LocalOnly && !question->ForceMCast && !IsLocalDomain(&question->qname)))
-               ? mDNS_NewMessageID(m) :
+               (question->Target.type || Question_uDNS(question)) ? mDNS_NewMessageID(m) :
 #endif // UNICAST_DISABLED
                zeroID;
 
@@ -7613,7 +7294,7 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
 
                // Note: It important that new questions are appended at the *end* of the list, not prepended at the start
                q = &m->Questions;
-               if (question->InterfaceID == mDNSInterface_LocalOnly) q = &m->LocalOnlyQuestions;
+               if (question->InterfaceID == mDNSInterface_LocalOnly || question->InterfaceID == mDNSInterface_P2P) q = &m->LocalOnlyQuestions;
                while (*q && *q != question) q=&(*q)->next;
 
                if (*q)
@@ -7626,7 +7307,7 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
                *q = question;
 
                // If this question is referencing a specific interface, verify it exists
-               if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly && question->InterfaceID != mDNSInterface_Unicast)
+               if (question->InterfaceID && question->InterfaceID != mDNSInterface_LocalOnly && question->InterfaceID != mDNSInterface_Unicast && question->InterfaceID != mDNSInterface_P2P)
                        {
                        NetworkInterfaceInfo *intf = FirstInterfaceForID(m, question->InterfaceID);
                        if (!intf)
@@ -7652,7 +7333,12 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
                question->UniqueAnswers     = 0;
                question->FlappingInterface1 = mDNSNULL;
                question->FlappingInterface2 = mDNSNULL;
-               question->AuthInfo          = GetAuthInfoForQuestion(m, question);              // Must do this before calling FindDuplicateQuestion()
+               // Must do AuthInfo and SuppressQuery before calling FindDuplicateQuestion()
+               question->AuthInfo          = GetAuthInfoForQuestion(m, question);
+               if (question->SuppressUnusable)
+                       question->SuppressQuery = ShouldSuppressQuery(m, &question->qname, question->qtype, question->InterfaceID);
+               else
+                       question->SuppressQuery = 0;
                question->DuplicateOf       = FindDuplicateQuestion(m, question);
                question->NextInDQList      = mDNSNULL;
                question->SendQNow          = mDNSNULL;
@@ -7666,6 +7352,7 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
                // We also don't need one for LLQs because (when we're using NAT) we want them all to share a single
                // NAT mapping for receiving inbound add/remove events.
                question->LocalSocket       = mDNSNULL;
+               question->deliverAddEvents  = mDNSfalse;
                question->qDNSServer        = mDNSNULL;
                question->unansweredQueries = 0;
                question->nta               = mDNSNULL;
@@ -7679,6 +7366,9 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
                question->expire            = 0;
                question->ntries            = 0;
                question->id                = zeroOpaque64;
+               question->validDNSServers   = zeroOpaque64;
+               question->triedAllServersOnce = 0;
+               question->noServerResponse = 0;
 
                if (question->DuplicateOf) question->AuthInfo = question->DuplicateOf->AuthInfo;
 
@@ -7687,11 +7377,15 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
 
                debugf("mDNS_StartQuery: Question %##s (%s) Interface %p Now %d Send in %d Answer in %d (%p) %s (%p)",
                        question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, m->timenow,
-                       question->LastQTime + question->ThisQInterval - m->timenow,
+                       NextQSendTime(question) - m->timenow,
                        question->DelayAnswering ? question->DelayAnswering - m->timenow : 0,
                        question, question->DuplicateOf ? "duplicate of" : "not duplicate", question->DuplicateOf);
 
-               if (question->InterfaceID == mDNSInterface_LocalOnly)
+               if (question->DelayAnswering)
+                       LogInfo("mDNS_StartQuery_internal: Delaying answering for %d ticks while cache stabilizes for %##s (%s)",
+                               question->DelayAnswering - m->timenow, question->qname.c, DNSTypeName(question->qtype));
+
+               if (question->InterfaceID == mDNSInterface_LocalOnly || question->InterfaceID == mDNSInterface_P2P)
                        {
                        if (!m->NewLocalOnlyQuestions) m->NewLocalOnlyQuestions = question;
                        }
@@ -7707,7 +7401,27 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
                        // this routine with the question list data structures in an inconsistent state.
                        if (!mDNSOpaque16IsZero(question->TargetQID))
                                {
-                               question->qDNSServer = GetServerForName(m, &question->qname, mDNSNULL);
+                               // Duplicate questions should have the same DNSServers so that when we find
+                               // a matching resource record, all of them get the answers. Calling GetServerForQuestion
+                               // for the duplicate question may get a different DNS server from the original question
+                               if (question->DuplicateOf)
+                                       {
+                                       question->validDNSServers = question->DuplicateOf->validDNSServers;
+                                       question->qDNSServer = question->DuplicateOf->qDNSServer;
+                                       LogInfo("mDNS_StartQuery_internal: Duplicate question %p (%p) %##s (%s), DNS Server %#a:%d",
+                                               question, question->DuplicateOf, question->qname.c, DNSTypeName(question->qtype),
+                                               question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
+                                           mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
+                                       }
+                               else
+                                       {
+                                       SetValidDNSServers(m, question);
+                                       question->qDNSServer = GetServerForQuestion(m, question);
+                                       LogInfo("mDNS_StartQuery_internal: question %p %##s (%s), DNS Server %#a:%d",
+                                               question, question->qname.c, DNSTypeName(question->qtype),
+                                               question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
+                                           mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
+                                       }
                                ActivateUnicastQuery(m, question, mDNSfalse);
 
                                // If long-lived query, and we don't have our NAT mapping active, start it now
@@ -7738,7 +7452,15 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
 mDNSexport void CancelGetZoneData(mDNS *const m, ZoneData *nta)
        {
        debugf("CancelGetZoneData %##s (%s)", nta->question.qname.c, DNSTypeName(nta->question.qtype));
-       mDNS_StopQuery_internal(m, &nta->question);
+       // This function may be called anytime to free the zone information.The question may or may not have stopped.
+       // If it was already stopped, mDNS_StopQuery_internal would have set q->ThisQInterval to -1 and should not
+       // call it again
+       if (nta->question.ThisQInterval != -1)
+               {
+               mDNS_StopQuery_internal(m, &nta->question);
+               if (nta->question.ThisQInterval != -1)
+                       LogMsg("CancelGetZoneData: Question %##s (%s) ThisQInterval %d not -1", nta->question.qname.c, DNSTypeName(nta->question.qtype), nta->question.ThisQInterval);
+               }
        mDNSPlatformMemFree(nta);
        }
 
@@ -7751,7 +7473,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
        
        //LogInfo("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
 
-       if (question->InterfaceID == mDNSInterface_LocalOnly) qp = &m->LocalOnlyQuestions;
+       if (question->InterfaceID == mDNSInterface_LocalOnly || question->InterfaceID == mDNSInterface_P2P) qp = &m->LocalOnlyQuestions;
        while (*qp && *qp != question) qp=&(*qp)->next;
        if (*qp) *qp = (*qp)->next;
        else
@@ -7779,10 +7501,14 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
                if (rr->CRActiveQuestion == question)
                        {
                        DNSQuestion *q;
+                       // Checking for ActiveQuestion filters questions that are suppressed also
+                       // as suppressed questions are not active
                        for (q = m->Questions; q; q=q->next)            // Scan our list of questions
                                if (ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
                                        break;
-                       debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s", q, CRDisplayString(m,rr));
+                       if (q)
+                               debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s, Original question CurrentAnswers %d, new question "
+                                       "CurrentAnswers %d, SuppressQuery %d", q, CRDisplayString(m,rr), question->CurrentAnswers, q->CurrentAnswers, q->SuppressQuery);
                        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
                        }
@@ -7816,7 +7542,6 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
        // so if we delete it earlier in this routine, we could find that our "question->next" pointer above is already
        // invalid before we even use it. By making sure that we update m->CurrentQuestion and m->NewQuestions if necessary
        // *first*, then they're all ready to be updated a second time if necessary when we cancel our GetZoneData query.
-       if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
        if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; }
        if (question->LocalSocket) { mDNSPlatformUDPClose(question->LocalSocket); question->LocalSocket = mDNSNULL; }
        if (!mDNSOpaque16IsZero(question->TargetQID) && question->LongLived)
@@ -7856,6 +7581,8 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
                UpdateAutoTunnelDomainStatuses(m);
 #endif
                }
+       // wait until we send the refresh above which needs the nta
+       if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
 
        return(mStatus_NoError);
        }
@@ -7941,22 +7668,15 @@ mDNSlocal mStatus mDNS_StartBrowse_internal(mDNS *const m, DNSQuestion *const qu
        question->Target           = zeroAddr;
        question->qtype            = kDNSType_PTR;
        question->qclass           = kDNSClass_IN;
-       question->LongLived        = mDNSfalse;
+       question->LongLived        = mDNStrue;
        question->ExpectUnique     = mDNSfalse;
        question->ForceMCast       = ForceMCast;
        question->ReturnIntermed   = mDNSfalse;
+       question->SuppressUnusable = mDNSfalse;
        question->QuestionCallback = Callback;
        question->QuestionContext  = Context;
        if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain)) return(mStatus_BadParamErr);
 
-#ifndef UNICAST_DISABLED
-    if (Question_uDNS(question))
-               {
-               question->LongLived     = mDNStrue;
-               question->ThisQInterval = InitialQuestionInterval;
-               question->LastQTime     = m->timenow - question->ThisQInterval;
-               }
-#endif // UNICAST_DISABLED
        return(mDNS_StartQuery_internal(m, question));
        }
 
@@ -8125,6 +7845,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
        query->qSRV.ExpectUnique        = mDNStrue;
        query->qSRV.ForceMCast          = mDNSfalse;
        query->qSRV.ReturnIntermed      = mDNSfalse;
+       query->qSRV.SuppressUnusable    = mDNSfalse;
        query->qSRV.QuestionCallback    = FoundServiceInfoSRV;
        query->qSRV.QuestionContext     = query;
 
@@ -8138,6 +7859,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
        query->qTXT.ExpectUnique        = mDNStrue;
        query->qTXT.ForceMCast          = mDNSfalse;
        query->qTXT.ReturnIntermed      = mDNSfalse;
+       query->qTXT.SuppressUnusable    = mDNSfalse;
        query->qTXT.QuestionCallback    = FoundServiceInfoTXT;
        query->qTXT.QuestionContext     = query;
 
@@ -8151,6 +7873,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
        query->qAv4.ExpectUnique        = mDNStrue;
        query->qAv4.ForceMCast          = mDNSfalse;
        query->qAv4.ReturnIntermed      = mDNSfalse;
+       query->qAv4.SuppressUnusable    = mDNSfalse;
        query->qAv4.QuestionCallback    = FoundServiceInfo;
        query->qAv4.QuestionContext     = query;
 
@@ -8164,6 +7887,7 @@ mDNSexport mStatus mDNS_StartResolveService(mDNS *const m,
        query->qAv6.ExpectUnique        = mDNStrue;
        query->qAv6.ForceMCast          = mDNSfalse;
        query->qAv6.ReturnIntermed      = mDNSfalse;
+       query->qAv6.SuppressUnusable    = mDNSfalse;
        query->qAv6.QuestionCallback    = FoundServiceInfo;
        query->qAv6.QuestionContext     = query;
 
@@ -8213,6 +7937,7 @@ mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, m
        question->ExpectUnique     = mDNSfalse;
        question->ForceMCast       = mDNSfalse;
        question->ReturnIntermed   = mDNSfalse;
+       question->SuppressUnusable = mDNSfalse;
        question->QuestionCallback = Callback;
        question->QuestionContext  = Context;
        if (DomainType > mDNS_DomainTypeMax) return(mStatus_BadParamErr);
@@ -8240,12 +7965,6 @@ mDNSexport mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr)
 mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newttl,
        const mDNSu16 newrdlength, RData *const newrdata, mDNSRecordUpdateCallback *Callback)
        {
-#ifndef UNICAST_DISABLED
-       mDNSBool unicast = !(rr->resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(rr->resrec.name));
-#else
-       mDNSBool unicast = mDNSfalse;
-#endif
-
        if (!ValidateRData(rr->resrec.rrtype, newrdlength, newrdata))
                {
                LogMsg("Attempt to update record with invalid rdata: %s", GetRRDisplayString_rdb(&rr->resrec, &newrdata->u, m->MsgBuffer));
@@ -8257,37 +7976,36 @@ mDNSexport mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newt
        // If TTL is unspecified, leave TTL unchanged
        if (newttl == 0) newttl = rr->resrec.rroriginalttl;
 
-       // If we already have an update queued up which has not gone through yet,
-       // give the client a chance to free that memory
-       if (!unicast && rr->NewRData)
+       // If we already have an update queued up which has not gone through yet, give the client a chance to free that memory
+       if (rr->NewRData)
                {
                RData *n = rr->NewRData;
-               rr->NewRData = mDNSNULL;                        // Clear the NewRData pointer ...
+               rr->NewRData = mDNSNULL;                                                        // Clear the NewRData pointer ...
                if (rr->UpdateCallback)
-                       rr->UpdateCallback(m, rr, n);   // ...and let the client free this memory, if necessary
+                       rr->UpdateCallback(m, rr, n, rr->newrdlength);  // ...and let the client free this memory, if necessary
                }
 
        rr->NewRData             = newrdata;
        rr->newrdlength          = newrdlength;
        rr->UpdateCallback       = Callback;
 
-       if (unicast) { mStatus status = uDNS_UpdateRecord(m, rr); mDNS_Unlock(m); return(status); }
+#ifndef UNICAST_DISABLED
+       if (rr->resrec.InterfaceID != mDNSInterface_LocalOnly && rr->resrec.InterfaceID != mDNSInterface_P2P && !IsLocalDomain(rr->resrec.name))
+               {
+               mStatus status = uDNS_UpdateRecord(m, rr);
+               // The caller frees the memory on error, don't retain stale pointers
+               if (status != mStatus_NoError) { rr->NewRData = mDNSNULL; rr->newrdlength = 0; }
+               mDNS_Unlock(m);
+               return(status);
+               }
+#endif
 
        if (rr->resrec.rroriginalttl == newttl &&
                rr->resrec.rdlength == newrdlength && mDNSPlatformMemSame(rr->resrec.rdata->u.data, newrdata->u.data, newrdlength))
                CompleteRDataUpdate(m, rr);
        else
                {
-               domainlabel name;
-               domainname 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
-               // update. For the _ichat service type, the XML encoding introduces spurious noise differences into the data
-               // even though there's no actual semantic change, so the mDNSPlatformMemSame() check doesn't help us.
-               // To work around this, we simply unilaterally limit all legacy _ichat-type updates to a single announcement.
-               if (SameDomainLabel(type.c, (mDNSu8*)"\x6_ichat")) rr->AnnounceCount = 1;
                InitializeLastAPTime(m, rr);
                while (rr->NextUpdateCredit && m->timenow - rr->NextUpdateCredit >= 0) GrantUpdateCredit(rr);
                if (!rr->UpdateBlocked && rr->UpdateCredits) rr->UpdateCredits--;
@@ -8519,22 +8237,16 @@ mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *act
 mDNSlocal void RestartRecordGetZoneData(mDNS * const m)
        {
        AuthRecord *rr;
-       ServiceRecordSet *s;
-
+       LogInfo("RestartRecordGetZoneData: ResourceRecords");
        for (rr = m->ResourceRecords; rr; rr=rr->next)
-               if (AuthRecord_uDNS(rr))
+               if (AuthRecord_uDNS(rr) && rr->state != regState_NoTarget)
                        {
                        debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", rr->resrec.name->c);
-                       if (rr->nta) CancelGetZoneData(m, rr->nta);
+                       // Zero out the updateid so that if we have a pending response from the server, it won't
+                       // be accepted as a valid response. If we accept the response, we might free the new "nta"
+                       if (rr->nta) { rr->updateid = zeroID; CancelGetZoneData(m, rr->nta); }
                        rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationGotZoneData, rr);
                        }
-
-       for (s = m->ServiceRegistrations; s; s = s->uDNS_next)
-               {
-               debugf("RestartRecordGetZoneData: StartGetZoneData for %##s", s->RR_SRV.resrec.name->c);
-               if (s->srs_nta) CancelGetZoneData(m, s->srs_nta);
-               s->srs_nta = StartGetZoneData(m, s->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, s);
-               }
        }
 
 mDNSlocal void InitializeNetWakeState(mDNS *const m, NetworkInterfaceInfo *set)
@@ -8579,7 +8291,12 @@ mDNSexport void mDNS_DeactivateNetWake_internal(mDNS *const m, NetworkInterfaceI
                for (i=0; i<3; i++) if (set->NetWakeResolve[i].ThisQInterval >= 0) mDNS_StopQuery_internal(m, &set->NetWakeResolve[i]);
 
                // Make special call to the browse callback to let it know it can to remove all records for this interface
-               if (m->SPSBrowseCallback) m->SPSBrowseCallback(m, &set->NetWakeBrowse, mDNSNULL, mDNSfalse);
+               if (m->SPSBrowseCallback)
+                       {
+                       mDNS_DropLockBeforeCallback();          // Allow client to legally make mDNS API calls from the callback
+                       m->SPSBrowseCallback(m, &set->NetWakeBrowse, mDNSNULL, mDNSfalse);
+                       mDNS_ReclaimLockAfterCallback();        // Decrement mDNS_reentrancy to block mDNS API calls again
+                       }
 
                // Reset our variables back to initial state, so we're ready for when NetWake is turned back on
                // (includes resetting NetWakeBrowse.ThisQInterval back to -1)
@@ -8603,8 +8320,8 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
        
        // Assume this interface will be active now, unless we find a duplicate already in the list
        set->InterfaceActive = mDNStrue;
-       set->IPv4Available   = (set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx);
-       set->IPv6Available   = (set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx);
+       set->IPv4Available   = (mDNSu8)(set->ip.type == mDNSAddrType_IPv4 && set->McastTxRx);
+       set->IPv6Available   = (mDNSu8)(set->ip.type == mDNSAddrType_IPv6 && set->McastTxRx);
        
        InitializeNetWakeState(m, set);
 
@@ -8650,37 +8367,40 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
        if (set->McastTxRx && ((m->KnownBugs & mDNS_KnownBug_PhantomInterfaces) || FirstOfType || set->InterfaceActive))
                {
                DNSQuestion *q;
-               // If flapping, delay between first and second queries is eight seconds instead of one
-               mDNSs32 delay    = flapping ? mDNSPlatformOneSecond   * 5 : 0;
-               mDNSu8  announce = flapping ? (mDNSu8)1                   : InitialAnnounceCount;
-               mDNSs32 newSS    = 0;
+               // Normally, after an interface comes up, we pause half a second before beginning probing.
+               // This is to guard against cases where there's rapid interface changes, where we could be confused by
+               // seeing packets we ourselves sent just moments ago (perhaps when this interface had a different address)
+               // which are then echoed back after a short delay by some Ethernet switches and some 802.11 base stations.
+               // We don't want to do a probe, and then see a stale echo of an announcement we ourselves sent,
+               // and think it's a conflicting answer to our probe.
+               // In the case of a flapping interface, we pause for five seconds, and reduce the announcement count to one packet.
+               const mDNSs32 probedelay  = flapping ? mDNSPlatformOneSecond * 5 : mDNSPlatformOneSecond / 2;
+               const mDNSu8  numannounce = flapping ? (mDNSu8)1                 : InitialAnnounceCount;
 
                // 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 all
                // to go and hit the network with identical queries at exactly the same moment.
-               newSS = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
-#if APPLE_OSX_mDNSResponder
-               // We set this to at least 2 seconds, because the MacOSX platform layer typically gets lots
-               // of network change notifications in a row, and we don't know when we're done getting notified.
-               // Note that this will not be set if the interface doesn't do multicast (set->McastTxRx).
-               newSS += mDNSPlatformOneSecond * 2;
-#endif
-               if (!m->SuppressSending || newSS - m->SuppressSending < 0) m->SuppressSending = newSS;
-               
-               if (flapping)
-                       {
-                       LogMsg("RegisterInterface: Frequent transitions for interface %s (%#a)",
-                               set->ifname, &set->ip);
-                       if (!m->SuppressProbes ||
-                               m->SuppressProbes - (m->timenow + delay) < 0)
-                               m->SuppressProbes = (m->timenow + delay);
-                       }
+               // We set a random delay of up to InitialQuestionInterval (1/3 second).
+               // We must *never* set m->SuppressSending to more than that (or set it repeatedly in a way
+               // that causes mDNSResponder to remain in a prolonged state of SuppressSending, because
+               // suppressing packet sending for more than about 1/3 second can cause protocol correctness
+               // to start to break down (e.g. we don't answer probes fast enough, and get name conflicts).
+               // See <rdar://problem/4073853> mDNS: m->SuppressSending set too enthusiastically
+               if (!m->SuppressSending) m->SuppressSending = m->timenow + (mDNSs32)mDNSRandom((mDNSu32)InitialQuestionInterval);
+
+               if (flapping) LogMsg("RegisterInterface: Frequent transitions for interface %s (%#a)", set->ifname, &set->ip);
+
+               LogInfo("RegisterInterface: %s (%#a) probedelay %d", set->ifname, &set->ip, probedelay);
+               if (m->SuppressProbes == 0 ||
+                       m->SuppressProbes - NonZeroTime(m->timenow + probedelay) < 0)
+                       m->SuppressProbes = NonZeroTime(m->timenow + probedelay);
 
                for (q = m->Questions; q; q=q->next)                                                            // Scan our list of questions
                        if (mDNSOpaque16IsZero(q->TargetQID))
                                if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)              // If non-specific Q, or Q on this specific interface,
                                        {                                                                                                                       // then reactivate this question
+                                       // If flapping, delay between first and second queries is nine seconds instead of one second
                                        mDNSBool dodelay = flapping && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID);
                                        mDNSs32 initial  = dodelay ? InitialQuestionInterval * QuestionIntervalStep2 : InitialQuestionInterval;
                                        mDNSs32 qdelay   = dodelay ? mDNSPlatformOneSecond * 5 : 0;
@@ -8704,13 +8424,18 @@ 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);
-                                       if (rr->AnnounceCount < announce) rr->AnnounceCount  = announce;
+                                       if (rr->AnnounceCount < numannounce) rr->AnnounceCount  = numannounce;
+                                       rr->SendNSECNow    = mDNSNULL;
                                        InitializeLastAPTime(m, rr);
                                        }
                }
 
        RestartRecordGetZoneData(m);
 
+       CheckSuppressUnusableQuestions(m);
+
+       mDNS_UpdateAllowSleep(m);
+
        mDNS_Unlock(m);
        return(mStatus_NoError);
        }
@@ -8780,9 +8505,8 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
                        LogInfo("mDNS_DeregisterInterface: Last representative of InterfaceID %p %s (%#a) deregistered;"
                                " marking questions etc. dormant", set->InterfaceID, set->ifname, &set->ip);
 
-                       if (flapping)
-                               LogMsg("DeregisterInterface: Frequent transitions for interface %s (%#a)",
-                                       set->ifname, &set->ip);
+                       if (set->McastTxRx && flapping)
+                               LogMsg("DeregisterInterface: Frequent transitions for interface %s (%#a)", set->ifname, &set->ip);
 
                        // 1. Deactivate any questions specific to this interface, and tag appropriate questions
                        // so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
@@ -8803,15 +8527,16 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
                                        {
                                        // If this interface is deemed flapping,
                                        // postpone deleting the cache records in case the interface comes back again
-                                       if (!flapping) mDNS_PurgeCacheResourceRecord(m, rr);
-                                       else
+                                       if (set->McastTxRx && flapping)
                                                {
-                                               // We want these record to go away in 30 seconds
+                                               // For a flapping interface we want these record to go away after 30 seconds
+                                               mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
                                                // We set UnansweredQueries = MaxUnansweredQueries so we don't waste time doing any queries for them --
                                                // if the interface does come back, any relevant questions will be reactivated anyway
-                                               mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
                                                rr->UnansweredQueries = MaxUnansweredQueries;
                                                }
+                                       else
+                                               mDNS_PurgeCacheResourceRecord(m, rr);
                                        }
 
                        // 3. Any DNS servers specific to this interface are now unusable
@@ -8836,12 +8561,15 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
                mDNSu32 slot;
                CacheGroup *cg;
                CacheRecord *rr;
-               m->NextCacheCheck = m->timenow;
                FORALL_CACHERECORDS(slot, cg, rr)
                        if (rr->resrec.InterfaceID == set->InterfaceID)
                                mDNS_Reconfirm_internal(m, rr, kDefaultReconfirmTimeForFlappingInterface);
                }
 
+       CheckSuppressUnusableQuestions(m);
+
+       mDNS_UpdateAllowSleep(m);
+
        mDNS_Unlock(m);
        }
 
@@ -8877,24 +8605,27 @@ mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus resu
                // are still in the process of deregistering, don't pass on the NameConflict/MemFree message until
                // every record is finished cleaning up.
                mDNSu32 i;
+               ExtraResourceRecord *e = sr->Extras;
+
                if (sr->RR_SRV.resrec.RecordType != kDNSRecordTypeUnregistered) return;
                if (sr->RR_TXT.resrec.RecordType != kDNSRecordTypeUnregistered) return;
                if (sr->RR_PTR.resrec.RecordType != kDNSRecordTypeUnregistered) return;
                if (sr->RR_ADV.resrec.RecordType != kDNSRecordTypeUnregistered) return;
                for (i=0; i<sr->NumSubTypes; i++) if (sr->SubTypes[i].resrec.RecordType != kDNSRecordTypeUnregistered) return;
 
+               while (e)
+                       {
+                       if (e->r.resrec.RecordType != kDNSRecordTypeUnregistered) return;
+                       e = e->next;
+                       }
+
                // If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse,
                // then we can now report the NameConflict to the client
                if (sr->Conflict) result = mStatus_NameConflict;
 
-               if (sr->srs_nta)
-                       {
-                       LogMsg("ServiceCallback ERROR Got mStatus_MemFree with srs_nta still set for %s", ARDisplayString(m, &sr->RR_SRV));
-                       CancelGetZoneData(m, sr->srs_nta);
-                       sr->srs_nta = mDNSNULL;
-                       }
                }
 
+       LogInfo("ServiceCallback: All records %s for %##s", (result == mStatus_MemFree ? "Unregistered": "Registered"), sr->RR_PTR.resrec.name->c);
        // CAUTION: MUST NOT do anything more with sr after calling sr->Callback(), because the client's callback
        // function is allowed to do anything, including deregistering this service and freeing its memory.
        if (sr->ServiceCallback)
@@ -8908,47 +8639,6 @@ mDNSlocal void NSSCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
                sr->ServiceCallback(m, sr, result);
        }
 
-#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
-mDNSlocal mStatus uDNS_RegisterService(mDNS *const m, ServiceRecordSet *srs)
-       {
-       mDNSu32 i;
-       ServiceRecordSet **p = &m->ServiceRegistrations;
-       while (*p && *p != srs) p=&(*p)->uDNS_next;
-       if (*p) { LogMsg("uDNS_RegisterService: %p %##s already in list", srs, srs->RR_SRV.resrec.name->c); return(mStatus_AlreadyRegistered); }
-
-       srs->uDNS_next = mDNSNULL;
-       *p = srs;
-
-       srs->RR_SRV.resrec.rroriginalttl = kHostNameTTL;
-       srs->RR_TXT.resrec.rroriginalttl = kStandardTTL;
-       srs->RR_PTR.resrec.rroriginalttl = kStandardTTL;
-       for (i = 0; i < srs->NumSubTypes;i++) srs->SubTypes[i].resrec.rroriginalttl = kStandardTTL;
-
-       srs->srs_uselease = mDNStrue;
-
-       if (srs->RR_SRV.AutoTarget)
-               {
-               // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other
-               // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate,
-               // with the port number in our advertised SRV record automatically tracking the external mapped port.
-               DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name);
-               if (!AuthInfo || !AuthInfo->AutoTunnel) srs->RR_SRV.AutoTarget = Target_AutoHostAndNATMAP;
-               }
-
-       if (!GetServiceTarget(m, &srs->RR_SRV))
-               {
-               // defer registration until we've got a target
-               LogInfo("uDNS_RegisterService - no target for %##s", srs->RR_SRV.resrec.name->c);
-               srs->state   = regState_NoTarget;
-               return mStatus_NoError;
-               }
-
-       ActivateUnicastRegistration(m, &srs->RR_SRV);
-       srs->state = regState_FetchingZoneData;
-       return mStatus_NoError;
-       }
-#endif
-
 // Note:
 // Name is first label of domain name (any dots in the name are actual dots, not label separators)
 // Type is service type (e.g. "_ipp._tcp.")
@@ -8967,22 +8657,6 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
        mStatus err;
        mDNSu32 i;
 
-       sr->state                  = regState_Zero;
-       sr->srs_uselease           = 0;
-       sr->TestForSelfConflict    = 0;
-       sr->Private                = 0;
-       sr->id                     = zeroID;
-       sr->zone.c[0]              = 0;
-       sr->SRSUpdateServer        = zeroAddr;
-       sr->SRSUpdatePort          = zeroIPPort;
-       mDNSPlatformMemZero(&sr->NATinfo, sizeof(sr->NATinfo));
-       sr->NATinfo.IntPort        = port;              // Record originally-requested port
-       sr->ClientCallbackDeferred = 0;
-       sr->DeferredStatus         = 0;
-       sr->SRVUpdateDeferred      = 0;
-       sr->SRVChanged             = 0;
-       sr->tcp                    = mDNSNULL;
-
        sr->ServiceCallback = Callback;
        sr->ServiceContext  = Context;
        sr->Conflict        = mDNSfalse;
@@ -9021,6 +8695,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
 
        // 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
+       // Note: uDNS registration code assumes that Additional1 points to the SRV record
        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;
@@ -9052,6 +8727,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
 
        // 4. Set up the TXT record rdata,
        // and set DependentOn because we're depending on the SRV record to find and resolve conflicts for us
+       // Note: uDNS registration code assumes that DependentOn points to the SRV record
        if (txtinfo == mDNSNULL) sr->RR_TXT.resrec.rdlength = 0;
        else if (txtinfo != sr->RR_TXT.resrec.rdata->u.txt.c)
                {
@@ -9061,28 +8737,10 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
                }
        sr->RR_TXT.DependentOn = &sr->RR_SRV;
 
-       sr->srs_nta = mDNSNULL;
-
-#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
-       // 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.namestorage)))
-               {
-               mStatus status;
-               mDNS_Lock(m);
-               // BIND named (name daemon) doesn't allow TXT records with zero-length rdata. This is strictly speaking correct,
-               // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
-               // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
-               // (We have to duplicate this check here because uDNS_RegisterService() bypasses the usual mDNS_Register_internal() bottleneck)
-               if (!sr->RR_TXT.resrec.rdlength) { sr->RR_TXT.resrec.rdlength = 1; sr->RR_TXT.resrec.rdata->u.txt.c[0] = 0; }
-               
-               status = uDNS_RegisterService(m, sr);
-               mDNS_Unlock(m);
-               return(status);
-               }
-#endif
-
        mDNS_Lock(m);
+       // It is important that we register SRV first. uDNS assumes that SRV is registered first so
+       // that if the SRV cannot find a target, rest of the records that belong to this service
+       // will not be activated.
        err = mDNS_Register_internal(m, &sr->RR_SRV);
        if (!err) err = mDNS_Register_internal(m, &sr->RR_TXT);
        // We register the RR_PTR last, because we want to be sure that in the event of a forced call to
@@ -9100,14 +8758,6 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
        return(err);
        }
 
-mDNSlocal void DummyCallback(mDNS *const m, AuthRecord *rr, mStatus result)
-       {
-       (void)m;                // Unused
-       (void)rr;               // Unused
-       (void)result;   // Unused
-       LogInfo("DummyCallback %d %s", result, ARDisplayString(m, rr));
-       }
-
 mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
        ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl)
        {
@@ -9131,18 +8781,7 @@ mDNSexport mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr,
                extra->r.resrec.name->c, DNSTypeName(extra->r.resrec.rrtype), extra->r.resrec.rdlength);
 
        status = mDNS_Register_internal(m, &extra->r);
-       if (status == mStatus_NoError)
-               {
-               *e = extra;
-#ifndef UNICAST_DISABLED
-               if (AuthRecord_uDNS(&sr->RR_SRV))
-                       {
-                       extra->r.resrec.RecordType = kDNSRecordTypeShared;      // don't want it to conflict with the service name (???)
-                       extra->r.RecordCallback = DummyCallback;        // don't generate callbacks for extra RRs for unicast services (WHY NOT????)
-                       if (sr->state != regState_Registered && sr->state != regState_Refresh) extra->r.state = regState_ExtraQueued;
-                       }
-#endif
-               }
+       if (status == mStatus_NoError) *e = extra;
 
        mDNS_Unlock(m);
        return(status);
@@ -9216,22 +8855,12 @@ mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordS
 
 // Note: mDNS_DeregisterService calls mDNS_Deregister_internal 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.
-mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
-       {
-       // If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService()
-       if (mDNSIPPortIsZero(sr->RR_SRV.resrec.rdata->u.srv.port)) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV));
-
-#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
-       if (!(sr->RR_SRV.resrec.InterfaceID == mDNSInterface_LocalOnly || IsLocalDomain(sr->RR_SRV.resrec.name)))
-               {
-               mStatus status;
-               mDNS_Lock(m);
-               status = uDNS_DeregisterService(m, sr);
-               mDNS_Unlock(m);
-               return(status);
-               }
-#endif
+// Any code walking either list must use the CurrentQuestion and/or CurrentRecord mechanism to protect against this.
+mDNSexport mStatus mDNS_DeregisterService_drt(mDNS *const m, ServiceRecordSet *sr, mDNS_Dereg_type drt)
+       {
+       // If port number is zero, that means this was actually registered using mDNS_RegisterNoSuchService()
+       if (mDNSIPPortIsZero(sr->RR_SRV.resrec.rdata->u.srv.port)) return(mDNS_DeregisterNoSuchService(m, &sr->RR_SRV));
+
        if (sr->RR_PTR.resrec.RecordType == kDNSRecordTypeUnregistered)
                {
                debugf("Service set for %##s already deregistered", sr->RR_SRV.resrec.name->c);
@@ -9239,7 +8868,7 @@ mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
                }
        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);
+               LogInfo("Service set for %##s already in the process of deregistering", sr->RR_SRV.resrec.name->c);
                // Avoid race condition:
                // If a service gets a conflict, then we set the Conflict flag to tell us to generate
                // an mStatus_NameConflict message when we get the mStatus_MemFree for our PTR record.
@@ -9267,7 +8896,7 @@ mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
                mDNS_Deregister_internal(m, &sr->RR_SRV, mDNS_Dereg_repeat);
                mDNS_Deregister_internal(m, &sr->RR_TXT, mDNS_Dereg_repeat);
                
-               mDNS_Deregister_internal(m, &sr->RR_ADV, mDNS_Dereg_normal);
+               mDNS_Deregister_internal(m, &sr->RR_ADV, drt);
        
                // We deregister all of the extra records, but we leave the sr->Extras list intact
                // in case the client wants to do a RenameAndReregister and reinstate the registration
@@ -9278,14 +8907,9 @@ mDNSexport mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
                        }
 
                for (i=0; i<sr->NumSubTypes; i++)
-                       mDNS_Deregister_internal(m, &sr->SubTypes[i], mDNS_Dereg_normal);
-
-               // Be sure to deregister the PTR last!
-               // Deregistering this record is what triggers the mStatus_MemFree callback to ServiceCallback,
-               // which in turn passes on the mStatus_MemFree (or mStatus_NameConflict) back to the client callback,
-               // which is then at liberty to free the ServiceRecordSet memory at will. We need to make sure
-               // we've deregistered all our records and done any other necessary cleanup before that happens.
-               status = mDNS_Deregister_internal(m, &sr->RR_PTR, mDNS_Dereg_normal);
+                       mDNS_Deregister_internal(m, &sr->SubTypes[i], drt);
+
+               status = mDNS_Deregister_internal(m, &sr->RR_PTR, drt);
                mDNS_Unlock(m);
                return(status);
                }
@@ -9321,20 +8945,33 @@ mDNSexport mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr,
        return(mDNS_Register(m, rr));
        }
        
+mDNSlocal mDNSBool mDNS_IdUsedInResourceRecordsList(mDNS * const m, mDNSOpaque16 id)
+       {
+       AuthRecord *r;
+       for (r = m->ResourceRecords; r; r=r->next) if (mDNSSameOpaque16(id, r->updateid)) return mDNStrue;
+       return mDNSfalse;
+       }
+       
+mDNSlocal mDNSBool mDNS_IdUsedInQuestionsList(mDNS * const m, mDNSOpaque16 id)
+       {
+       DNSQuestion *q;
+       for (q = m->Questions; q; q=q->next) if (mDNSSameOpaque16(id, q->TargetQID)) return mDNStrue;
+       return mDNSfalse;
+       }
+       
 mDNSexport mDNSOpaque16 mDNS_NewMessageID(mDNS * const m)
        {
        mDNSOpaque16 id;
        int i;
+
        for (i=0; i<10; i++)
                {
-               AuthRecord *r;
-               DNSQuestion *q;
-               id = mDNSOpaque16fromIntVal(1 + mDNSRandom(0xFFFE));
-               for (r = m->ResourceRecords; r; r=r->next) if (mDNSSameOpaque16(id, r->updateid )) continue;
-               for (q = m->Questions;       q; q=q->next) if (mDNSSameOpaque16(id, q->TargetQID)) continue;
-               break;
+               id = mDNSOpaque16fromIntVal(1 + (mDNSu16)mDNSRandom(0xFFFE));
+               if (!mDNS_IdUsedInResourceRecordsList(m, id) && !mDNS_IdUsedInQuestionsList(m, id)) break;
                }
+               
        debugf("mDNS_NewMessageID: %5d", mDNSVal16(id));
+
        return id;
        }
 
@@ -9376,222 +9013,331 @@ mDNSlocal void RestartARPProbing(mDNS *const m, AuthRecord *const rr)
                }
        }
 
-mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID)
+mDNSlocal void mDNSCoreReceiveRawARP(mDNS *const m, const ARP_EthIP *const arp, const mDNSInterfaceID InterfaceID)
        {
-       static const mDNSOpaque16 Ethertype_IP = { { 0x08, 0x00 } };
-       static const mDNSOpaque32 ARP_EthIP_h0 = { { 0x08, 0x06, 0x00, 0x01 } };        // Ethertype (ARP = 0x0806), Hardware address space (Ethernet = 1)
-       static const mDNSOpaque32 ARP_EthIP_h1 = { { 0x08, 0x00, 0x06, 0x04 } };        // Protocol address space (IP = 0x0800), hlen, plen
        static const mDNSOpaque16 ARP_op_request = { { 0, 1 } };
-       const EthernetHeader *const eth = (const EthernetHeader *)p;
-       const ARP_EthIP      *const arp = (const ARP_EthIP      *)(eth+1);
-       const IPv4Header     *const v4  = (const IPv4Header     *)(eth+1);
-       const IPv6Header     *const v6  = (const IPv6Header     *)(eth+1);
-       if (end >= p+42 && *(mDNSu32*)(p+12) == ARP_EthIP_h0.NotAnInteger && *(mDNSu32*)(p+16) == ARP_EthIP_h1.NotAnInteger)
-               {
-               AuthRecord *rr;
-               NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
-               if (!intf) return;
+       AuthRecord *rr;
+       NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
+       if (!intf) return;
 
-               debugf("Got ARP from %.4a/%.6a for %.4a", &arp->spa, &arp->sha, &arp->tpa);
+       mDNS_Lock(m);
 
-               mDNS_Lock(m);
+       // Pass 1:
+       // Process ARP Requests and Probes (but not Announcements), and generate an ARP Reply if necessary.
+       // We also process ARPs from our own kernel (and 'answer' them by injecting a local ARP table entry)
+       // We ignore ARP Announcements here -- Announcements are not questions, they're assertions, so we don't need to answer them.
+       // The times we might need to react to an ARP Announcement are:
+       // (i) as an indication that the host in question has not gone to sleep yet (so we should delay beginning to proxy for it) or
+       // (ii) if it's a conflicting Announcement from another host
+       // -- and we check for these in Pass 2 below.
+       if (mDNSSameOpaque16(arp->op, ARP_op_request) && !mDNSSameIPv4Address(arp->spa, arp->tpa))
+               {
+               for (rr = m->ResourceRecords; rr; rr=rr->next)
+                       if (rr->resrec.InterfaceID == InterfaceID && rr->resrec.RecordType != kDNSRecordTypeDeregistering &&
+                               rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->tpa))
+                               {
+                               static const char msg1[] = "ARP Req from owner -- re-probing";
+                               static const char msg2[] = "Ignoring  ARP Request from      ";
+                               static const char msg3[] = "Creating Local ARP Cache entry  ";
+                               static const char msg4[] = "Answering ARP Request from      ";
+                               const char *const msg = mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC) ? msg1 :
+                                                                               (rr->AnnounceCount == InitialAnnounceCount)     ? msg2 :
+                                                                               mDNSSameEthAddress(&arp->sha, &intf->MAC)       ? msg3 : msg4;
+                               LogSPS("%-7s %s %.6a %.4a for %.4a -- H-MAC %.6a I-MAC %.6a %s",
+                                       intf->ifname, msg, &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
+                               if      (msg == msg1) RestartARPProbing(m, rr);
+                               else if (msg == msg3) mDNSPlatformSetLocalAddressCacheEntry(m, &rr->AddressProxy, &rr->WakeUp.IMAC, InterfaceID);
+                               else if (msg == msg4) SendARP(m, 2, rr, &arp->tpa, &arp->sha, &arp->spa, &arp->sha);
+                               }
+               }
 
-               // Pass 1:
-               // Process ARP Requests and Probes (but not Announcements), and generate an ARP Reply if necessary.
-               // We also process ARPs from our own kernel (and 'answer' them by injecting a local ARP table entry)
-               // We ignore ARP Announcements here -- Announcements are not questions, they're assertions, so we don't need to answer them.
-               // The times we might need to react to an ARP Announcement are:
-               // (i) as an indication that the host in question has not gone to sleep yet (so we should delay beginning to proxy for it) or
-               // (ii) if it's a conflicting Announcement from another host
-               // -- and we check for these in Pass 2 below.
-               if (mDNSSameOpaque16(arp->op, ARP_op_request) && !mDNSSameIPv4Address(arp->spa, arp->tpa))
+       // Pass 2:
+       // For all types of ARP packet we check the Sender IP address to make sure it doesn't conflict with any AddressProxy record we're holding.
+       // (Strictly speaking we're only checking Announcement/Request/Reply packets, since ARP Probes have zero Sender IP address,
+       // so by definition (and by design) they can never conflict with any real (i.e. non-zero) IP address).
+       // We ignore ARPs we sent ourselves (Sender MAC address is our MAC address) because our own proxy ARPs do not constitute a conflict that we need to handle.
+       // If we see an apparently conflicting ARP, we check the sender hardware address:
+       //   If the sender hardware address is the original owner this is benign, so we just suppress our own proxy answering for a while longer.
+       //   If the sender hardware address is *not* the original owner, then this is a conflict, and we need to wake the sleeping machine to handle it.
+       if (mDNSSameEthAddress(&arp->sha, &intf->MAC))
+               debugf("ARP from self for %.4a", &arp->tpa);
+       else
+               {
+               if (!mDNSSameIPv4Address(arp->spa, zerov4Addr))
                        for (rr = m->ResourceRecords; rr; rr=rr->next)
-                               if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->tpa))
+                               if (rr->resrec.InterfaceID == InterfaceID && rr->resrec.RecordType != kDNSRecordTypeDeregistering &&
+                                       rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->spa))
                                        {
-                                       char *ifname = InterfaceNameForID(m, InterfaceID);
-                                       if (!ifname) ifname = "<NULL InterfaceID>";
-                                       static const char msg1[] = "ARP Req from owner -- re-probing";
-                                       static const char msg2[] = "Ignoring  ARP Request from      ";
-                                       static const char msg3[] = "Creating Local ARP Cache entry  ";
-                                       static const char msg4[] = "Answering ARP Request from      ";
-                                       const char *const msg = mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC) ? msg1 :
-                                                                                       (rr->AnnounceCount == InitialAnnounceCount)     ? msg2 :
-                                                                                       mDNSSameEthAddress(&arp->sha, &intf->MAC)       ? msg3 : msg4;
-                                       LogSPS("%-7s %s %.6a %.4a for %.4a -- H-MAC %.6a I-MAC %.6a %s",
-                                               ifname, msg, &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
-                                       if      (msg == msg1) RestartARPProbing(m, rr);
-                                       else if (msg == msg3) mDNSPlatformSetLocalARP(&arp->tpa, &rr->WakeUp.IMAC, InterfaceID);
-                                       else if (msg == msg4) SendARP(m, 2, rr, arp->tpa.b, arp->sha.b, arp->spa.b, arp->sha.b);
+                                       RestartARPProbing(m, rr);
+                                       if (mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC))
+                                               LogSPS("%-7s ARP %s from owner %.6a %.4a for %-15.4a -- re-starting probing for %s", intf->ifname,
+                                                       mDNSSameIPv4Address(arp->spa, arp->tpa) ? "Announcement " : mDNSSameOpaque16(arp->op, ARP_op_request) ? "Request      " : "Response     ",
+                                                       &arp->sha, &arp->spa, &arp->tpa, ARDisplayString(m, rr));
+                                       else
+                                               {
+                                               LogMsg("%-7s Conflicting ARP from %.6a %.4a for %.4a -- waking H-MAC %.6a I-MAC %.6a %s", intf->ifname,
+                                                       &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
+                                               ScheduleWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.HMAC);
+                                               }
                                        }
+               }
 
-               // Pass 2:
-               // For all types of ARP packet we check the Sender IP address to make sure it doesn't conflict with any AddressProxy record we're holding.
-               // (Strictly speaking we're only checking Announcement/Request/Reply packets, since ARP Probes have zero Sender IP address,
-               // so by definition (and by design) they can never conflict with any real (i.e. non-zero) IP address).
-               // We ignore ARPs we sent ourselves (Sender MAC address is our MAC address) because our own proxy ARPs do not constitute a conflict that we need to handle.
-               // If we see an apparently conflicting ARP, we check the sender hardware address:
-               //   If the sender hardware address is the original owner this is benign, so we just suppress our own proxy answering for a while longer.
-               //   If the sender hardware address is *not* the original owner, then this is a conflict, and we need to wake the sleeping machine to handle it.
-               if (mDNSSameEthAddress(&arp->sha, &intf->MAC))
-                       debugf("ARP from self for %.4a", &arp->tpa);
-               else
-                       {
-                       if (!mDNSSameIPv4Address(arp->spa, zerov4Addr))
-                               for (rr = m->ResourceRecords; rr; rr=rr->next)
-                                       if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, arp->spa))
+       mDNS_Unlock(m);
+       }
+
+/*
+// Option 1 is Source Link Layer Address Option
+// Option 2 is Target Link Layer Address Option
+mDNSlocal const mDNSEthAddr *GetLinkLayerAddressOption(const IPv6NDP *const ndp, const mDNSu8 *const end, mDNSu8 op)
+       {
+       const mDNSu8 *options = (mDNSu8 *)(ndp+1);
+       while (options < end)
+               {
+               debugf("NDP Option %02X len %2d %d", options[0], options[1], end - options);
+               if (options[0] == op && options[1] == 1) return (const mDNSEthAddr*)(options+2);
+               options += options[1] * 8;
+               }
+       return mDNSNULL;
+       }
+*/
+
+mDNSlocal void mDNSCoreReceiveRawND(mDNS *const m, const mDNSEthAddr *const sha, const mDNSv6Addr *spa,
+       const IPv6NDP *const ndp, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID)
+       {
+       AuthRecord *rr;
+       NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
+       if (!intf) return;
+
+       mDNS_Lock(m);
+
+       // Pass 1: Process Neighbor Solicitations, and generate a Neighbor Advertisement if necessary.
+       if (ndp->type == NDP_Sol)
+               {
+               //const mDNSEthAddr *const sha = GetLinkLayerAddressOption(ndp, end, NDP_SrcLL);
+               (void)end;
+               for (rr = m->ResourceRecords; rr; rr=rr->next)
+                       if (rr->resrec.InterfaceID == InterfaceID && rr->resrec.RecordType != kDNSRecordTypeDeregistering &&
+                               rr->AddressProxy.type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->AddressProxy.ip.v6, ndp->target))
+                               {
+                               static const char msg1[] = "NDP Req from owner -- re-probing";
+                               static const char msg2[] = "Ignoring  NDP Request from      ";
+                               static const char msg3[] = "Creating Local NDP Cache entry  ";
+                               static const char msg4[] = "Answering NDP Request from      ";
+                               static const char msg5[] = "Answering NDP Probe   from      ";
+                               const char *const msg = sha && mDNSSameEthAddress(sha, &rr->WakeUp.IMAC) ? msg1 :
+                                                                               (rr->AnnounceCount == InitialAnnounceCount)      ? msg2 :
+                                                                               sha && mDNSSameEthAddress(sha, &intf->MAC)       ? msg3 :
+                                                                               spa && mDNSIPv6AddressIsZero(*spa)               ? msg4 : msg5;
+                               LogSPS("%-7s %s %.6a %.16a for %.16a -- H-MAC %.6a I-MAC %.6a %s",
+                                       intf->ifname, msg, sha, spa, &ndp->target, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
+                               if      (msg == msg1) RestartARPProbing(m, rr);
+                               else if (msg == msg3)
+                                       {
+                                       if (!(m->KnownBugs & mDNS_KnownBug_LimitedIPv6))
+                                               mDNSPlatformSetLocalAddressCacheEntry(m, &rr->AddressProxy, &rr->WakeUp.IMAC, InterfaceID);
+                                       }
+                               else if (msg == msg4) SendNDP(m, NDP_Adv, NDP_Solicited, rr, &ndp->target, mDNSNULL, spa,          sha             );
+                               else if (msg == msg5) SendNDP(m, NDP_Adv, 0,             rr, &ndp->target, mDNSNULL, &AllHosts_v6, &AllHosts_v6_Eth);
+                               }
+               }
+
+       // Pass 2: For all types of NDP packet we check the Sender IP address to make sure it doesn't conflict with any AddressProxy record we're holding.
+       if (mDNSSameEthAddress(sha, &intf->MAC))
+               debugf("NDP from self for %.16a", &ndp->target);
+       else
+               {
+               // For Neighbor Advertisements we check the Target address field, not the actual IPv6 source address.
+               // When a machine has both link-local and routable IPv6 addresses, it may send NDP packets making assertions
+               // about its routable IPv6 address, using its link-local address as the source address for all NDP packets.
+               // Hence it is the NDP target address we care about, not the actual packet source address.
+               if (ndp->type == NDP_Adv) spa = &ndp->target;
+               if (!mDNSSameIPv6Address(*spa, zerov6Addr))
+                       for (rr = m->ResourceRecords; rr; rr=rr->next)
+                               if (rr->resrec.InterfaceID == InterfaceID && rr->resrec.RecordType != kDNSRecordTypeDeregistering &&
+                                       rr->AddressProxy.type == mDNSAddrType_IPv6 && mDNSSameIPv6Address(rr->AddressProxy.ip.v6, *spa))
+                                       {
+                                       RestartARPProbing(m, rr);
+                                       if (mDNSSameEthAddress(sha, &rr->WakeUp.IMAC))
+                                               LogSPS("%-7s NDP %s from owner %.6a %.16a for %.16a -- re-starting probing for %s", intf->ifname,
+                                                       ndp->type == NDP_Sol ? "Solicitation " : "Advertisement", sha, spa, &ndp->target, ARDisplayString(m, rr));
+                                       else
                                                {
-                                               char *ifname = InterfaceNameForID(m, InterfaceID);
-                                               if (!ifname) ifname = "<NULL InterfaceID>";
-
-                                               RestartARPProbing(m, rr);
-                                               if (mDNSSameEthAddress(&arp->sha, &rr->WakeUp.IMAC))
-                                                       LogSPS("%-7s ARP %s from owner %.6a %.4a for %-15.4a -- re-starting probing for %s",
-                                                               ifname,
-                                                               mDNSSameIPv4Address(arp->spa, arp->tpa) ? "Announcement" : mDNSSameOpaque16(arp->op, ARP_op_request) ? "Request     " : "Response    ",
-                                                               &arp->sha, &arp->spa, &arp->tpa, ARDisplayString(m, rr));
-                                               else
-                                                       {
-                                                       LogMsg("%-7s Conflicting ARP from %.6a %.4a for %.4a -- waking H-MAC %.6a I-MAC %.6a %s",
-                                                               ifname, &arp->sha, &arp->spa, &arp->tpa, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
-                                                       SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password);
-                                                       }
+                                               LogMsg("%-7s Conflicting NDP from %.6a %.16a for %.16a -- waking H-MAC %.6a I-MAC %.6a %s", intf->ifname,
+                                                       sha, spa, &ndp->target, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
+                                               ScheduleWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.HMAC);
                                                }
-                       }
-
-               mDNS_Unlock(m);
+                                       }
                }
-       else if (end >= p+34 && mDNSSameOpaque16(eth->ethertype, Ethertype_IP) && (v4->flagsfrags.b[0] & 0x1F) == 0 && v4->flagsfrags.b[1] == 0)
+
+       mDNS_Unlock(m);
+       }
+
+mDNSlocal void mDNSCoreReceiveRawTransportPacket(mDNS *const m, const mDNSEthAddr *const sha, const mDNSAddr *const src, const mDNSAddr *const dst, const mDNSu8 protocol,
+       const mDNSu8 *const p, const TransportLayerPacket *const t, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID, const mDNSu16 len)
+       {
+       const mDNSIPPort port = (protocol == 0x06) ? t->tcp.dst : (protocol == 0x11) ? t->udp.dst : zeroIPPort;
+       mDNSBool wake = mDNSfalse;
+
+       switch (protocol)
                {
-               const mDNSu8 *const trans = p + 14 + (v4->vlen & 0xF) * 4;
-               const mDNSu8 *const required = trans + (v4->protocol == 1 ? 4 : v4->protocol == 6 ? 20 : v4->protocol == 17 ? 8 : 0);
-               debugf("Got IPv4 from %.4a to %.4a", &v4->src, &v4->dst);
-               if (end >= required)
-                       {
-                       #define SSH_AsNumber 22
-                       #define ARD_AsNumber 3283
-                       static const mDNSIPPort SSH   = { { SSH_AsNumber   >> 8, SSH_AsNumber   & 0xFF } };
-                       static const mDNSIPPort ARD   = { { ARD_AsNumber   >> 8, ARD_AsNumber   & 0xFF } };
+               #define XX wake ? "Received" : "Ignoring", end-p
+               case 0x01:      LogSPS("Ignoring %d-byte ICMP from %#a to %#a", end-p, src, dst);
+                                       break;
 
-                       mDNSBool wake = mDNSfalse;
-                       mDNSIPPort port = zeroIPPort;
-       
-                       switch (v4->protocol)
-                               {
-                               #define XX wake ? "Received" : "Ignoring", end-p
-                               case  1:        LogSPS("%s %d-byte ICMP from %.4a to %.4a", XX, &v4->src, &v4->dst);
-                                                       break;
-
-                               case  6:        {
-                                                       const TCPHeader *const tcp = (const TCPHeader *)trans;
-                                                       port = tcp->dst;
-
-                                                       // Plan to wake if
-                                                       // (a) RST is not set, AND
-                                                       // (b) packet is SYN, SYN+FIN, or plain data packet (no SYN or FIN). We won't wake for FIN alone.
-                                                       wake = (!(tcp->flags & 4) && (tcp->flags & 3) != 1);
-
-                                                       // For now, to reduce spurious wakeups, we wake only for TCP SYN,
-                                                       // except for ssh connections, where we'll wake for plain data packets too
-                                                       if (!mDNSSameIPPort(port, SSH) && !(tcp->flags & 2)) wake = mDNSfalse;
-
-                                                       LogSPS("%s %d-byte TCP from %.4a:%d to %.4a:%d%s%s%s", XX,
-                                                               &v4->src, mDNSVal16(tcp->src), &v4->dst, mDNSVal16(port),
-                                                               (tcp->flags & 2) ? " SYN" : "",
-                                                               (tcp->flags & 1) ? " FIN" : "",
-                                                               (tcp->flags & 4) ? " RST" : "");
-                                                       }
-                                                       break;
+               case 0x06:      {
+                                       #define SSH_AsNumber 22
+                                       static const mDNSIPPort SSH = { { SSH_AsNumber >> 8, SSH_AsNumber & 0xFF } };
 
-                               case 17:        {
-                                                       const UDPHeader *const udp = (const UDPHeader *)trans;
-                                                       const mDNSu16 udplen = (mDNSu16)((mDNSu16)trans[4] << 8 | trans[5]);            // Length *including* 8-byte UDP header
-                                                       if (udplen >= sizeof(UDPHeader))
-                                                               {
-                                                               const mDNSu16 datalen = udplen - sizeof(UDPHeader);
-                                                               port = udp->dst;
-                                                               wake = mDNStrue;
+                                       // Plan to wake if
+                                       // (a) RST is not set, AND
+                                       // (b) packet is SYN, SYN+FIN, or plain data packet (no SYN or FIN). We won't wake for FIN alone.
+                                       wake = (!(t->tcp.flags & 4) && (t->tcp.flags & 3) != 1);
 
-                                                               // For Back to My Mac UDP port 4500 (IPSEC) packets, we do some special handling
-                                                               if (mDNSSameIPPort(port, IPSECPort))
-                                                                       {
-                                                                       // Specifically ignore NAT keepalive packets
-                                                                       if (datalen == 1 && end >= trans + 9 && trans[8] == 0xFF) wake = mDNSfalse;
-                                                                       else
-                                                                               {
-                                                                               // Skip over the Non-ESP Marker if present
-                                                                               const mDNSBool NonESP = (end >= trans + 12 && trans[8] == 0 && trans[9] == 0 && trans[10] == 0 && trans[11] == 0);
-                                                                               const IKEHeader *const ike    = (IKEHeader *)(trans + (NonESP ? 12 : 8));
-                                                                               const mDNSu16          ikelen = datalen - (NonESP ? 4 : 0);
-                                                                               if (ikelen >= sizeof(IKEHeader) && end >= ((mDNSu8 *)ike) + sizeof(IKEHeader))
-                                                                                       if ((ike->Version & 0x10) == 0x10)
-                                                                                               {
-                                                                                               // ExchangeType ==  5 means 'Informational' <http://www.ietf.org/rfc/rfc2408.txt>
-                                                                                               // ExchangeType == 34 means 'IKE_SA_INIT'   <http://www.iana.org/assignments/ikev2-parameters>
-                                                                                               if (ike->ExchangeType == 5 || ike->ExchangeType == 34) wake = mDNSfalse;
-                                                                                               LogSPS("%s %d-byte IKE ExchangeType %d", XX, ike->ExchangeType);
-                                                                                               }
-                                                                               }
-                                                                       }
+                                       // For now, to reduce spurious wakeups, we wake only for TCP SYN,
+                                       // except for ssh connections, where we'll wake for plain data packets too
+                                       if (!mDNSSameIPPort(port, SSH) && !(t->tcp.flags & 2)) wake = mDNSfalse;
 
-                                                               // For now, because we haven't yet worked out a clean elegant way to do this, we just special-case the
-                                                               // Apple Remote Desktop port number -- we ignore all packets to UDP 3283 (the "Net Assistant" port),
-                                                               // except for Apple Remote Desktop's explicit manual wakeup packet, which looks like this:
-                                                               // UDP header (8 bytes)
-                                                               // Payload: 13 88 00 6a 41 4e 41 20 (8 bytes) ffffffffffff (6 bytes) 16xMAC (96 bytes) = 110 bytes total
-                                                               if (mDNSSameIPPort(port, ARD)) wake = (datalen >= 110 && end >= trans+10 && trans[8] == 0x13 && trans[9] == 0x88);
+                                       LogSPS("%s %d-byte TCP from %#a:%d to %#a:%d%s%s%s", XX,
+                                               src, mDNSVal16(t->tcp.src), dst, mDNSVal16(port),
+                                               (t->tcp.flags & 2) ? " SYN" : "",
+                                               (t->tcp.flags & 1) ? " FIN" : "",
+                                               (t->tcp.flags & 4) ? " RST" : "");
+                                       }
+                                       break;
+
+               case 0x11:      {
+                                       #define ARD_AsNumber 3283
+                                       static const mDNSIPPort ARD = { { ARD_AsNumber >> 8, ARD_AsNumber & 0xFF } };
+                                       const mDNSu16 udplen = (mDNSu16)((mDNSu16)t->bytes[4] << 8 | t->bytes[5]);              // Length *including* 8-byte UDP header
+                                       if (udplen >= sizeof(UDPHeader))
+                                               {
+                                               const mDNSu16 datalen = udplen - sizeof(UDPHeader);
+                                               wake = mDNStrue;
 
-                                                               LogSPS("%s %d-byte UDP from %.4a:%d to %.4a:%d", XX, &v4->src, mDNSVal16(udp->src), &v4->dst, mDNSVal16(port));
+                                               // For Back to My Mac UDP port 4500 (IPSEC) packets, we do some special handling
+                                               if (mDNSSameIPPort(port, IPSECPort))
+                                                       {
+                                                       // Specifically ignore NAT keepalive packets
+                                                       if (datalen == 1 && end >= &t->bytes[9] && t->bytes[8] == 0xFF) wake = mDNSfalse;
+                                                       else
+                                                               {
+                                                               // Skip over the Non-ESP Marker if present
+                                                               const mDNSBool NonESP = (end >= &t->bytes[12] && t->bytes[8] == 0 && t->bytes[9] == 0 && t->bytes[10] == 0 && t->bytes[11] == 0);
+                                                               const IKEHeader *const ike    = (IKEHeader *)(t + (NonESP ? 12 : 8));
+                                                               const mDNSu16          ikelen = datalen - (NonESP ? 4 : 0);
+                                                               if (ikelen >= sizeof(IKEHeader) && end >= ((mDNSu8 *)ike) + sizeof(IKEHeader))
+                                                                       if ((ike->Version & 0x10) == 0x10)
+                                                                               {
+                                                                               // ExchangeType ==  5 means 'Informational' <http://www.ietf.org/rfc/rfc2408.txt>
+                                                                               // ExchangeType == 34 means 'IKE_SA_INIT'   <http://www.iana.org/assignments/ikev2-parameters>
+                                                                               if (ike->ExchangeType == 5 || ike->ExchangeType == 34) wake = mDNSfalse;
+                                                                               LogSPS("%s %d-byte IKE ExchangeType %d", XX, ike->ExchangeType);
+                                                                               }
                                                                }
                                                        }
-                                                       break;
 
-                               default:        LogSPS("%s %d-byte IP packet unknown protocol %d from %.4a to %.4a", XX, v4->protocol, &v4->src, &v4->dst);
-                                                       break;
-                               }
+                                               // For now, because we haven't yet worked out a clean elegant way to do this, we just special-case the
+                                               // Apple Remote Desktop port number -- we ignore all packets to UDP 3283 (the "Net Assistant" port),
+                                               // except for Apple Remote Desktop's explicit manual wakeup packet, which looks like this:
+                                               // UDP header (8 bytes)
+                                               // Payload: 13 88 00 6a 41 4e 41 20 (8 bytes) ffffffffffff (6 bytes) 16xMAC (96 bytes) = 110 bytes total
+                                               if (mDNSSameIPPort(port, ARD)) wake = (datalen >= 110 && end >= &t->bytes[10] && t->bytes[8] == 0x13 && t->bytes[9] == 0x88);
 
-                       if (wake)
-                               {
-                               AuthRecord *rr, *r2;
+                                               LogSPS("%s %d-byte UDP from %#a:%d to %#a:%d", XX, src, mDNSVal16(t->udp.src), dst, mDNSVal16(port));
+                                               }
+                                       }
+                                       break;
 
-                               mDNS_Lock(m);
-                               for (rr = m->ResourceRecords; rr; rr=rr->next)
-                                       if (rr->resrec.InterfaceID == InterfaceID &&
-                                               rr->AddressProxy.type == mDNSAddrType_IPv4 && mDNSSameIPv4Address(rr->AddressProxy.ip.v4, v4->dst))
+               case 0x3A:      if (&t->bytes[len] <= end)
                                                {
-                                               const mDNSu8 *const tp = (v4->protocol == 6) ? (const mDNSu8 *)"\x4_tcp" : (const mDNSu8 *)"\x4_udp";
-                                               for (r2 = m->ResourceRecords; r2; r2=r2->next)
-                                                       if (r2->resrec.InterfaceID == InterfaceID && mDNSSameEthAddress(&r2->WakeUp.HMAC, &rr->WakeUp.HMAC) &&
-                                                               r2->resrec.rrtype == kDNSType_SRV && mDNSSameIPPort(r2->resrec.rdata->u.srv.port, port) &&
-                                                               SameDomainLabel(ThirdLabel(r2->resrec.name)->c, tp))
-                                                               break;
-                                               if (!r2 && mDNSSameIPPort(port, IPSECPort)) r2 = rr;    // So that we wake for BTMM IPSEC packets, even without a matching SRV record
-                                               char *ifname = InterfaceNameForID(m, rr->resrec.InterfaceID);
-                                               if (!ifname) ifname = "<NULL InterfaceID>";
-                                               if (r2)
-                                                       {
-                                                       rr->AnnounceCount = 0;
-                                                       LogMsg("Waking host at %s %.4a H-MAC %.6a I-MAC %.6a for %s",
-                                                               ifname, &v4->dst, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, r2));
-                                                       SendWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.IMAC, &rr->WakeUp.password);
-                                                       }
-                                               else
-                                                       LogSPS("Sleeping host at %s %.4a %.6a has no service on %#s %d",
-                                                               ifname, &v4->dst, &rr->WakeUp.HMAC, tp, mDNSVal16(port));
+                                               mDNSu16 checksum = IPv6CheckSum(&src->ip.v6, &dst->ip.v6, protocol, t->bytes, len);
+                                               if (!checksum) mDNSCoreReceiveRawND(m, sha, &src->ip.v6, &t->ndp, &t->bytes[len], InterfaceID);
+                                               else LogInfo("IPv6CheckSum bad %04X %02X%02X from %#a to %#a", checksum, t->bytes[2], t->bytes[3], src, dst);
                                                }
-                               mDNS_Unlock(m);
-                               }
-                       }
+                                       break;
+
+               default:        LogSPS("Ignoring %d-byte IP packet unknown protocol %d from %#a to %#a", end-p, protocol, src, dst);
+                                       break;
                }
-       else if (end >= p+34 && mDNSSameOpaque16(eth->ethertype, Ethertype_IP) && (v4->flagsfrags.b[0] & 0x1F) == 0 && v4->flagsfrags.b[1] == 0)
+
+       if (wake)
                {
-               debugf("Got IPv6 from %.16a to %.16a", &v4->src, &v6->dst);
-               (void)v6;
+               AuthRecord *rr, *r2;
+
+               mDNS_Lock(m);
+               for (rr = m->ResourceRecords; rr; rr=rr->next)
+                       if (rr->resrec.InterfaceID == InterfaceID &&
+                               rr->resrec.RecordType != kDNSRecordTypeDeregistering &&
+                               rr->AddressProxy.type && mDNSSameAddress(&rr->AddressProxy, dst))
+                               {
+                               const mDNSu8 *const tp = (protocol == 6) ? (const mDNSu8 *)"\x4_tcp" : (const mDNSu8 *)"\x4_udp";
+                               for (r2 = m->ResourceRecords; r2; r2=r2->next)
+                                       if (r2->resrec.InterfaceID == InterfaceID && mDNSSameEthAddress(&r2->WakeUp.HMAC, &rr->WakeUp.HMAC) &&
+                                               r2->resrec.RecordType != kDNSRecordTypeDeregistering &&
+                                               r2->resrec.rrtype == kDNSType_SRV && mDNSSameIPPort(r2->resrec.rdata->u.srv.port, port) &&
+                                               SameDomainLabel(ThirdLabel(r2->resrec.name)->c, tp))
+                                               break;
+                               if (!r2 && mDNSSameIPPort(port, IPSECPort)) r2 = rr;    // So that we wake for BTMM IPSEC packets, even without a matching SRV record
+                               if (r2)
+                                       {
+                                       LogMsg("Waking host at %s %#a H-MAC %.6a I-MAC %.6a for %s",
+                                               InterfaceNameForID(m, rr->resrec.InterfaceID), dst, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, r2));
+                                       ScheduleWakeup(m, rr->resrec.InterfaceID, &rr->WakeUp.HMAC);
+                                       }
+                               else
+                                       LogSPS("Sleeping host at %s %#a %.6a has no service on %#s %d",
+                                               InterfaceNameForID(m, rr->resrec.InterfaceID), dst, &rr->WakeUp.HMAC, tp, mDNSVal16(port));
+                               }
+               mDNS_Unlock(m);
+               }
+       }
+
+mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID)
+       {
+       static const mDNSOpaque16 Ethertype_ARP  = { { 0x08, 0x06 } };  // Ethertype 0x0806 = ARP
+       static const mDNSOpaque16 Ethertype_IPv4 = { { 0x08, 0x00 } };  // Ethertype 0x0800 = IPv4
+       static const mDNSOpaque16 Ethertype_IPv6 = { { 0x86, 0xDD } };  // Ethertype 0x86DD = IPv6
+       static const mDNSOpaque16 ARP_hrd_eth    = { { 0x00, 0x01 } };  // Hardware address space (Ethernet = 1)
+       static const mDNSOpaque16 ARP_pro_ip     = { { 0x08, 0x00 } };  // Protocol address space (IP = 0x0800)
+
+       // Note: BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
+       // In other words, we can safely assume that pkt below (ARP, IPv4 or IPv6) is properly word aligned,
+       // but if pkt is 4-byte aligned, that necessarily means that eth CANNOT also be 4-byte aligned
+       // since it points to a an address 14 bytes before pkt.
+       const EthernetHeader     *const eth = (const EthernetHeader *)p;
+       const NetworkLayerPacket *const pkt = (const NetworkLayerPacket *)(eth+1);
+       mDNSAddr src, dst;
+       #define RequiredCapLen(P) ((P)==0x01 ? 4 : (P)==0x06 ? 20 : (P)==0x11 ? 8 : (P)==0x3A ? 24 : 0)
+
+       // Is ARP? Length must be at least 14 + 28 = 42 bytes
+       if (end >= p+42 && mDNSSameOpaque16(eth->ethertype, Ethertype_ARP) && mDNSSameOpaque16(pkt->arp.hrd, ARP_hrd_eth) && mDNSSameOpaque16(pkt->arp.pro, ARP_pro_ip))
+               mDNSCoreReceiveRawARP(m, &pkt->arp, InterfaceID);
+       // Is IPv4 with zero fragmentation offset? Length must be at least 14 + 20 = 34 bytes
+       else if (end >= p+34 && mDNSSameOpaque16(eth->ethertype, Ethertype_IPv4) && (pkt->v4.flagsfrags.b[0] & 0x1F) == 0 && pkt->v4.flagsfrags.b[1] == 0)
+               {
+               const mDNSu8 *const trans = p + 14 + (pkt->v4.vlen & 0xF) * 4;
+               debugf("Got IPv4 %02X from %.4a to %.4a", pkt->v4.protocol, &pkt->v4.src, &pkt->v4.dst);
+               src.type = mDNSAddrType_IPv4; src.ip.v4 = pkt->v4.src;
+               dst.type = mDNSAddrType_IPv4; dst.ip.v4 = pkt->v4.dst;
+               if (end >= trans + RequiredCapLen(pkt->v4.protocol))
+                       mDNSCoreReceiveRawTransportPacket(m, &eth->src, &src, &dst, pkt->v4.protocol, p, (TransportLayerPacket*)trans, end, InterfaceID, 0);
+               }
+       // Is IPv6? Length must be at least 14 + 28 = 42 bytes
+       else if (end >= p+54 && mDNSSameOpaque16(eth->ethertype, Ethertype_IPv6))
+               {
+               const mDNSu8 *const trans = p + 54;
+               debugf("Got IPv6  %02X from %.16a to %.16a", pkt->v6.pro, &pkt->v6.src, &pkt->v6.dst);
+               src.type = mDNSAddrType_IPv6; src.ip.v6 = pkt->v6.src;
+               dst.type = mDNSAddrType_IPv6; dst.ip.v6 = pkt->v6.dst;
+               if (end >= trans + RequiredCapLen(pkt->v6.pro))
+                       mDNSCoreReceiveRawTransportPacket(m, &eth->src, &src, &dst, pkt->v6.pro, p, (TransportLayerPacket*)trans, end, InterfaceID,
+                               (mDNSu16)pkt->bytes[4] << 8 | pkt->bytes[5]);
                }
        }
 
 mDNSlocal void ConstructSleepProxyServerName(mDNS *const m, domainlabel *name)
        {
-       name->c[0] = mDNS_snprintf((char*)name->c+1, 62, "%d-%d-%d-%d %#s",
+       name->c[0] = (mDNSu8)mDNS_snprintf((char*)name->c+1, 62, "%d-%d-%d-%d %#s",
                m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower, &m->nicelabel);
        }
 
@@ -9605,7 +9351,7 @@ mDNSlocal void SleepProxyServerCallback(mDNS *const m, ServiceRecordSet *const s
                        m->SPSState = 3;
                else
                        {
-                       m->SPSState = (m->SPSSocket != mDNSNULL);
+                       m->SPSState = (mDNSu8)(m->SPSSocket != mDNSNULL);
                        if (m->SPSState)
                                {
                                domainlabel name;
@@ -9623,15 +9369,19 @@ mDNSlocal void SleepProxyServerCallback(mDNS *const m, ServiceRecordSet *const s
                }
        }
 
-mDNSexport void mDNSCoreBeSleepProxyServer(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower)
+// Called with lock held
+mDNSexport void mDNSCoreBeSleepProxyServer_internal(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower)
        {
+       // This routine uses mDNS_DeregisterService and calls SleepProxyServerCallback, so we execute in user callback context
+       mDNS_DropLockBeforeCallback();
+
        // If turning off SPS, close our socket
        // (Do this first, BEFORE calling mDNS_DeregisterService below)
        if (!sps && m->SPSSocket) { mDNSPlatformUDPClose(m->SPSSocket); m->SPSSocket = mDNSNULL; }
 
        // If turning off, or changing type, deregister old name
        if (m->SPSState == 1 && sps != m->SPSType)
-               { m->SPSState = 2; mDNS_DeregisterService(m, &m->SPSRecords); }
+               { m->SPSState = 2; mDNS_DeregisterService_drt(m, &m->SPSRecords, sps ? mDNS_Dereg_rapid : mDNS_Dereg_normal); }
 
        // Record our new SPS parameters
        m->SPSType          = sps;
@@ -9645,10 +9395,17 @@ mDNSexport void mDNSCoreBeSleepProxyServer(mDNS *const m, mDNSu8 sps, mDNSu8 por
                if (!m->SPSSocket)
                        {
                        m->SPSSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
-                       if (!m->SPSSocket) { LogMsg("mDNSCoreBeSleepProxyServer: Failed to allocate SPSSocket"); return; }
+                       if (!m->SPSSocket) { LogMsg("mDNSCoreBeSleepProxyServer: Failed to allocate SPSSocket"); goto fail; }
                        }
                if (m->SPSState == 0) SleepProxyServerCallback(m, &m->SPSRecords, mStatus_MemFree);
                }
+       else if (m->SPSState)
+               {
+               LogSPS("mDNSCoreBeSleepProxyServer turning off from state %d; will wake clients", m->SPSState);
+               m->NextScheduledSPS = m->timenow;
+               }
+fail:
+       mDNS_ReclaimLockAfterCallback();
        }
 
 // ***************************************************************************
@@ -9727,11 +9484,12 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
        m->RandomQueryDelay        = 0;
        m->RandomReconfirmDelay    = 0;
        m->PktNum                  = 0;
+       m->LocalRemoveEvents       = mDNSfalse;
        m->SleepState              = SleepState_Awake;
        m->SleepSeqNum             = 0;
        m->SystemWakeOnLANEnabled  = mDNSfalse;
        m->SentSleepProxyRegistration = mDNSfalse;
-       m->AnnounceOwner           = 0;
+       m->AnnounceOwner           = NonZeroTime(timenow + 60 * mDNSPlatformOneSecond);
        m->DelaySleep              = 0;
        m->SleepLimit              = 0;
 
@@ -9747,7 +9505,11 @@ 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;
+       for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
+               {
+               m->rrcache_hash[slot]      = mDNSNULL;
+               m->rrcache_nextcheck[slot] = timenow + 0x78000000;;
+               }
 
        mDNS_GrowCache_internal(m, rrcachestorage, rrcachesize);
 
@@ -9769,9 +9531,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
 #ifndef UNICAST_DISABLED
        m->NextuDNSEvent            = timenow + 0x78000000;
        m->NextSRVUpdate            = timenow + 0x78000000;
-       m->SuppressStdPort53Queries = 0;
 
-       m->ServiceRegistrations     = mDNSNULL;
        m->DNSServers               = mDNSNULL;
 
        m->Router                   = zeroAddr;
@@ -9789,6 +9549,7 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
        m->AutoTunnelLabel.c[0]     = 0;
 
        m->RegisterSearchDomains    = mDNSfalse;
+       m->RegisterAutoTunnel6      = mDNStrue;
 
        // NAT traversal fields
        m->NATTraversals            = mDNSNULL;
@@ -9826,6 +9587,15 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
 
 #if APPLE_OSX_mDNSResponder
        m->TunnelClients            = mDNSNULL;
+
+#if ! NO_WCF
+       CHECK_WCF_FUNCTION(WCFConnectionNew)
+               {
+               m->WCF = WCFConnectionNew();
+               if (!m->WCF) { LogMsg("WCFConnectionNew failed"); return -1; }
+               }
+#endif
+
 #endif
 
        result = mDNSPlatformInit(m);
@@ -9853,7 +9623,7 @@ mDNSexport void mDNS_ConfigChanged(mDNS *const m)
                        // When SleepProxyServerCallback gets the mStatus_MemFree message,
                        // it will reregister the service under the new name
                        m->SPSState = 2;
-                       mDNS_DeregisterService(m, &m->SPSRecords);
+                       mDNS_DeregisterService_drt(m, &m->SPSRecords, mDNS_Dereg_rapid);
                        }
                }
        
@@ -9877,10 +9647,186 @@ mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const
 
        (void) lameduck;
        (void) ptr;
-       debugf("uDNS_SetupDNSConfig: %s cache record due to %s server %p %#a:%d (%##s): %s", purge ? "purging" : "reconfirming", lameduck ? "lame duck" : "new", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c, CRDisplayString(m, cr));
+       debugf("PurgeOrReconfirmCacheRecord: %s cache record due to %s server %p %#a:%d (%##s): %s",
+               purge    ? "purging"   : "reconfirming",
+               lameduck ? "lame duck" : "new",
+               ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c, CRDisplayString(m, cr));
+
+       if (purge)
+               {
+               LogInfo("PurgeorReconfirmCacheRecord: Purging Resourcerecord %s, RecordType %x", CRDisplayString(m, cr), cr->resrec.RecordType);
+               mDNS_PurgeCacheResourceRecord(m, cr);
+               }
+       else
+               {
+               LogInfo("PurgeorReconfirmCacheRecord: Reconfirming Resourcerecord %s, RecordType %x", CRDisplayString(m, cr), cr->resrec.RecordType);
+               mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
+               }
+       }
+
+mDNSlocal void CacheRecordResetDNSServer(mDNS *const m, DNSQuestion *q, DNSServer *new)
+       {
+       const mDNSu32 slot = HashSlot(&q->qname);
+       CacheGroup *const cg = CacheGroupForName(m, slot, q->qnamehash, &q->qname);
+       CacheRecord *rp;
+       mDNSBool found = mDNSfalse;
+       mDNSBool foundNew = mDNSfalse;
+       DNSServer *old = q->qDNSServer;
+       mDNSBool newQuestion = IsQuestionNew(m, q);
+       DNSQuestion *qptr;
+
+       // This function is called when the DNSServer is updated to the new question. There may already be
+       // some cache entries matching the old DNSServer and/or new DNSServer. There are four cases. In the
+       // following table, "Yes" denotes that a cache entry was found for old/new DNSServer.
+       //
+       //                                      old DNSServer           new DNSServer
+       //
+       //      Case 1                          Yes                                     Yes
+       //  Case 2                              No                                      Yes
+       //  Case 3                              Yes                                     No
+       //  Case 4                              No                                      No
+       //
+       // Case 1: There are cache entries for both old and new DNSServer. We handle this case by simply
+       //                 expiring the old Cache entries, deliver a RMV event (if an ADD event was delivered before)
+       //                 followed by the ADD event of the cache entries corresponding to the new server. This
+       //                 case happens when we pick a DNSServer, issue a query and get a valid response and create
+       //                 cache entries after which it stops responding. Another query (non-duplicate) picks a different
+       //             DNSServer and creates identical cache entries (perhaps through records in Additional records).
+       //                 Now if the first one expires and tries to pick the new DNSServer (the original DNSServer
+       //                 is not responding) we will find cache entries corresponding to both DNSServers.
+       //
+       // Case 2: There are no cache entries for the old DNSServer but there are some for the new DNSServer.
+       //                 This means we should deliver an ADD event. Normally ADD events are delivered by
+       //                 AnswerNewQuestion if it is a new question. So, we check to see if it is a new question
+       //                 and if so, leave it to AnswerNewQuestion to deliver it. Otherwise, we use
+       //                 AnswerQuestionsForDNSServerChanges to deliver the ADD event. This case happens when a
+       //                 question picks a DNS server for which AnswerNewQuestion could not deliver an answer even
+       //         though there were potential cache entries but DNSServer did not match. Now when we
+       //         pick a new DNSServer, those cache entries may answer this question.
+       //
+       // Case 3: There are the cache entries for the old DNSServer but none for the new. We just move
+       //                 the old cache entries to point to the new DNSServer and the caller is expected to
+       //                 do a purge or reconfirm to delete or validate the RDATA. We don't need to do anything
+       //                 special for delivering ADD events, as it should have been done/will be done by
+       //                 AnswerNewQuestion. This case happens when we picked a DNSServer, sent the query and
+       //                 got a response and the cache is expired now and we are reissuing the question but the
+       //                 original DNSServer does not respond.
+       //
+       // Case 4: There are no cache entries either for the old or for the new DNSServer. There is nothing
+       //                 much we can do here.
+       //
+       // Case 2 and 3 are the most common while case 4 is possible when no DNSServers are working. Case 1
+       // is relatively less likely to happen in practice
+
+       // Temporarily set the DNSServer to look for the matching records for the new DNSServer.
+       q->qDNSServer = new;
+       for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next)
+               {
+               if (SameNameRecordAnswersQuestion(&rp->resrec, q))
+                       {
+                       LogInfo("CacheRecordResetDNSServer: Found cache record %##s for new DNSServer address: %#a", rp->resrec.name->c,
+                               (rp->resrec.rDNSServer != mDNSNULL ?  &rp->resrec.rDNSServer->addr : mDNSNULL));
+                       foundNew = mDNStrue;
+                       break;
+                       }
+               }
+       q->qDNSServer = old;
+
+       for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next)
+               {
+               if (SameNameRecordAnswersQuestion(&rp->resrec, q))
+                       {
+                       // Case1
+                       found = mDNStrue;
+                       if (foundNew)
+                               {
+                               LogInfo("CacheRecordResetDNSServer: Flushing Resourcerecord %##s, before:%#a, after:%#a", rp->resrec.name->c,
+                                       (rp->resrec.rDNSServer != mDNSNULL ?  &rp->resrec.rDNSServer->addr : mDNSNULL),
+                                       (new != mDNSNULL ?  &new->addr : mDNSNULL));
+                               mDNS_PurgeCacheResourceRecord(m, rp);
+                               if (newQuestion)
+                                       {
+                                       // "q" is not a duplicate question. If it is a newQuestion, then the CRActiveQuestion can't be
+                                       // possibly set as it is set only when we deliver the ADD event to the question.
+                                       if (rp->CRActiveQuestion != mDNSNULL)
+                                               {
+                                               LogMsg("CacheRecordResetDNSServer: ERROR!!: CRActiveQuestion %p set, current question %p, name %##s", rp->CRActiveQuestion, q, q->qname.c);
+                                               rp->CRActiveQuestion = mDNSNULL;
+                                               }
+                                       // if this is a new question, then we never delivered an ADD yet, so don't deliver the RMV.
+                                       continue;
+                                       }
+                               }
+                       LogInfo("CacheRecordResetDNSServer: resetting cache record %##s DNSServer address before:%#a,"
+                               " after:%#a, CRActiveQuestion %p", rp->resrec.name->c, (rp->resrec.rDNSServer != mDNSNULL ?
+                               &rp->resrec.rDNSServer->addr : mDNSNULL), (new != mDNSNULL ?  &new->addr : mDNSNULL),
+                               rp->CRActiveQuestion);
+                       // Though we set it to the new DNS server, the caller is *assumed* to do either a purge
+                       // or reconfirm or send out questions to the "new" server to verify whether the cached
+                       // RDATA is valid
+                       rp->resrec.rDNSServer = new;
+                       }
+               }
+
+       // Case 1 and Case 2
+       if ((found && foundNew) || (!found && foundNew))
+               {
+               if (newQuestion)
+                       LogInfo("CacheRecordResetDNSServer: deliverAddEvents not set for question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+               else if (QuerySuppressed(q))
+                       LogInfo("CacheRecordResetDNSServer: deliverAddEvents not set for suppressed question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+               else
+                       {
+                       LogInfo("CacheRecordResetDNSServer: deliverAddEvents set for %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+                       q->deliverAddEvents = mDNStrue;
+                       for (qptr = q->next; qptr; qptr = qptr->next)
+                               if (qptr->DuplicateOf == q) qptr->deliverAddEvents = mDNStrue;
+                       }
+               return;
+               }
+
+       // Case 3 and Case 4
+       return;
+       }
+
+mDNSexport void DNSServerChangeForQuestion(mDNS *const m, DNSQuestion *q, DNSServer *new)
+       {
+       DNSQuestion *qptr;
+
+       // 1. Whenever we change the DNS server, we change the message identifier also so that response
+       // from the old server is not accepted as a response from the new server but only messages
+       // from the new server are accepted as valid responses. We do it irrespective of whether "new"
+       // is NULL or not. It is possible that we send two queries, no responses, pick a new DNS server
+       // which is NULL and now the response comes back and will try to penalize the DNS server which
+       // is NULL. By setting the messageID here, we will not accept that as a valid response.
+
+       q->TargetQID = mDNS_NewMessageID(m);
+               
+       // 2. Move the old cache records to point them at the new DNSServer so that we can deliver the ADD/RMV events
+       // appropriately. At any point in time, we want all the cache records point only to one DNSServer for a given
+       // question. "DNSServer" here is the DNSServer object and not the DNS server itself. It is possible to
+       // have the same DNS server address in two objects, one scoped and another not scoped. But, the cache is per
+       // DNSServer object. By maintaining the question and the cache entries point to the same DNSServer
+       // always, the cache maintenance and delivery of ADD/RMV events becomes simpler.
+       //
+       // CacheRecordResetDNSServer should be called only once for the non-duplicate question as once the cache
+       // entries are moved to point to the new DNSServer, we don't need to call it for the duplicate question
+       // and it is wrong to call for the duplicate question as it's decision to mark deliverAddevents will be
+       // incorrect.
+
+       if (q->DuplicateOf)
+               LogMsg("DNSServerChangeForQuestion: ERROR: Called for duplicate question %##s", q->qname.c);
+       else
+               CacheRecordResetDNSServer(m, q, new);
 
-       if (purge) mDNS_PurgeCacheResourceRecord(m, cr);
-       else mDNS_Reconfirm_internal(m, cr, kDefaultReconfirmTimeForNoAnswer);
+       // 3. Make sure all the duplicate questions point to the same DNSServer so that delivery
+       // of events for all of them are consistent. Duplicates for a question are always inserted
+       // after in the list.
+       q->qDNSServer = new;
+       for (qptr = q->next ; qptr; qptr = qptr->next)
+               {
+               if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = new; }
+               }
        }
        
 mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
@@ -9912,12 +9858,45 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
 
        mDNSPlatformSetDNSConfig(m, mDNStrue, mDNSfalse, &fqdn, mDNSNULL, mDNSNULL);
 
+       // Mark the records to be flushed that match a new resolver. We need to do this before
+       // we walk the questions below where we change the DNSServer pointer of the cache
+       // record
+       FORALL_CACHERECORDS(slot, cg, cr)
+               {
+               if (cr->resrec.InterfaceID) continue;
+
+               // We just mark them for purge or reconfirm. We can't affect the DNSServer pointer
+               // here as the code below that calls CacheRecordResetDNSServer relies on this
+               //
+               // The new DNSServer may be a scoped or non-scoped one. We use the active question's
+               // InterfaceID for looking up the right DNS server
+               ptr = GetServerForName(m, cr->resrec.name, cr->CRActiveQuestion ? cr->CRActiveQuestion->InterfaceID : mDNSNULL);
+
+               // Purge or Reconfirm if this cache entry would use the new DNS server
+               if (ptr && (ptr != cr->resrec.rDNSServer))
+                       {
+                       // As the DNSServers for this cache record is not the same anymore, we don't
+                       // want any new questions to pick this old value
+                       if (cr->CRActiveQuestion == mDNSNULL)
+                               {
+                               LogInfo("uDNS_SetupDNSConfig: Purging Resourcerecord %s", CRDisplayString(m, cr));
+                               mDNS_PurgeCacheResourceRecord(m, cr);
+                               }
+                       else
+                               PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNSfalse);
+                       }
+               }
        // Update our qDNSServer pointers before we go and free the DNSServer object memory
        for (q = m->Questions; q; q=q->next)
                if (!mDNSOpaque16IsZero(q->TargetQID))
                        {
-                       DNSServer *s = GetServerForName(m, &q->qname, mDNSNULL);
-                       DNSServer *t = q->qDNSServer;
+                       DNSServer *s, *t;
+                       DNSQuestion *qptr;
+                       if (q->DuplicateOf) continue;
+                       SetValidDNSServers(m, q);
+                       q->triedAllServersOnce = 0;
+                       s = GetServerForQuestion(m, q);
+                       t = q->qDNSServer;
                        if (t != s)
                                {
                                // If DNS Server for this question has changed, reactivate it
@@ -9925,25 +9904,47 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
                                        t, t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), t ? t->domain.c : (mDNSu8*)"",
                                        s, s ? &s->addr : mDNSNULL, mDNSVal16(s ? s->port : zeroIPPort), s ? s->domain.c : (mDNSu8*)"",
                                        q->qname.c, DNSTypeName(q->qtype));
-                               q->qDNSServer = s;
-                               q->unansweredQueries = 0;
-                               
-                               // Change the query ID so that we won't cache responses to any in-flight queries
-                               q->TargetQID = mDNS_NewMessageID(m);
 
-                               ActivateUnicastQuery(m, q, mDNStrue);
+                               // After we reset the DNSServer pointer on the cache records here, three things could happen:
+                               //
+                               // 1) The query gets sent out and when the actual response comes back later it is possible
+                               // that the response has the same RDATA, in which case we update our cache entry.
+                               // If the response is different, then the entry will expire and a new entry gets added.
+                               // For the latter case to generate a RMV followed by ADD events, we need to reset the DNS
+                               // server here to match the question and the cache record.
+                               //
+                               // 2) We might have marked the cache entries for purge above and for us to be able to generate the RMV
+                               // events for the questions, the DNSServer on the question should match the Cache Record
+                               //
+                               // 3) We might have marked the cache entries for reconfirm above, for which we send the query out which is
+                               // the same as the first case above.
+
+                               DNSServerChangeForQuestion(m, q, s);
+                               q->unansweredQueries = 0;
+                               // We still need to pick a new DNSServer for the questions that have been
+                               // suppressed, but it is wrong to activate the query as DNS server change
+                               // could not possibly change the status of SuppressUnusable questions
+                               if (!QuerySuppressed(q))
+                                       {
+                                       debugf("uDNS_SetupDNSConfig: Activating query %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+                                       ActivateUnicastQuery(m, q, mDNStrue);
+                                       // ActivateUnicastQuery is called for duplicate questions also as it does something
+                                       // special for AutoTunnel questions
+                                       for (qptr = q->next ; qptr; qptr = qptr->next)
+                                               {
+                                               if (qptr->DuplicateOf == q) ActivateUnicastQuery(m, qptr, mDNStrue);
+                                               }
+                                       }
+                               }
+                       else
+                               {
+                               debugf("uDNS_SetupDNSConfig: Not Updating DNS server question %p %##s (%s) DNS server %#a:%d %p %d",
+                                       q, q->qname.c, DNSTypeName(q->qtype), t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), q->DuplicateOf, q->SuppressUnusable);
+                               for (qptr = q->next ; qptr; qptr = qptr->next)
+                                       if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; }
                                }
                        }
 
-       // Flush all records that match a new resolver
-       FORALL_CACHERECORDS(slot, cg, cr)
-               {
-               if (cr->resrec.InterfaceID) continue;
-               ptr = GetServerForName(m, cr->resrec.name, mDNSNULL);
-               if (ptr && (ptr->flags & DNSServer_FlagNew))
-                       PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNSfalse);
-               }
-       
        while (*p)
                {
                if (((*p)->flags & DNSServer_FlagDelete) != 0)
@@ -9952,13 +9953,58 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
                        // We reconfirm any records that match, because in this world of split DNS, firewalls, etc.
                        // different DNS servers can give different answers to the same question.
                        ptr = *p;
-                       ptr->flags &= ~DNSServer_FlagDelete;    // Clear del so GetServerForName will (temporarily) find this server again before it's finally deleted
                        FORALL_CACHERECORDS(slot, cg, cr)
-                               if (!cr->resrec.InterfaceID && GetServerForName(m, cr->resrec.name, mDNSNULL) == ptr)
+                               {
+                               if (cr->resrec.InterfaceID) continue;
+                               if (cr->resrec.rDNSServer == ptr)
+                                       {
+                                       // If we don't have an active question for this cache record, neither Purge can
+                                       // generate RMV events nor Reconfirm can send queries out. Just set the DNSServer
+                                       // pointer on the record NULL so that we don't point to freed memory (We might dereference
+                                       // DNSServer pointers from resource record for logging purposes).
+                                       //
+                                       // If there is an active question, point to its DNSServer as long as it does not point to the
+                                       // freed one. We already went through the questions above and made them point at either the
+                                       // new server or NULL if there is no server and also affected the cache entries that match
+                                       // this question. Hence, whenever we hit a resource record with a DNSServer that is just
+                                       // about to be deleted, we should never have an active question. The code below just tries to
+                                       // be careful logging messages if we ever hit this case.
+
+                                       if (cr->CRActiveQuestion)
+                                               {
+                                               DNSQuestion *qptr = cr->CRActiveQuestion;
+                                               if (qptr->qDNSServer == mDNSNULL)
+                                                       LogMsg("uDNS_SetupDNSConfig: Cache Record %s match: Active question %##s (%s) with DNSServer Address NULL, Server to be deleted %#a",
+                                                               CRDisplayString(m, cr), qptr->qname.c, DNSTypeName(qptr->qtype), &ptr->addr);
+                                               else
+                                                       LogMsg("uDNS_SetupDNSConfig: Cache Record %s match: Active question %##s (%s) DNSServer Address %#a, Server to be deleted %#a",
+                                                               CRDisplayString(m, cr),  qptr->qname.c, DNSTypeName(qptr->qtype), &qptr->qDNSServer->addr, &ptr->addr);
+
+                                               if (qptr->qDNSServer == ptr)
+                                                       {
+                                                       qptr->validDNSServers = zeroOpaque64;
+                                                       qptr->qDNSServer = mDNSNULL;
+                                                       cr->resrec.rDNSServer = mDNSNULL;
+                                                       }
+                                               else
+                                                       {
+                                                       cr->resrec.rDNSServer = qptr->qDNSServer;
+                                                       }
+                                               }
+                                       else
+                                               {
+                                               LogInfo("uDNS_SetupDNSConfig: Cache Record %##s has no Active question, Record's DNSServer Address %#a, Server to be deleted %#a",
+                                                       cr->resrec.name, &cr->resrec.rDNSServer->addr, &ptr->addr);
+                                               cr->resrec.rDNSServer = mDNSNULL;
+                                               }
+                                               
                                        PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNStrue);
+                                       }
+                               }
                        *p = (*p)->next;
                        debugf("uDNS_SetupDNSConfig: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c);
                        mDNSPlatformMemFree(ptr);
+                       NumUnicastDNSServers--;
                        }
                else
                        {
@@ -10015,6 +10061,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
                if (m->FQDN.c[0]) mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); // Set status to 1 to indicate temporary failure
                }
 
+       debugf("uDNS_SetupDNSConfig: number of unicast DNS servers %d", NumUnicastDNSServers);
        return mStatus_NoError;
        }
 
@@ -10031,21 +10078,24 @@ mDNSexport void mDNSCoreInitComplete(mDNS *const m, mStatus result)
                }
        }
 
-extern ServiceRecordSet *CurrentServiceRecordSet;
-
 mDNSlocal void DeregLoop(mDNS *const m, AuthRecord *const start)
        {
        m->CurrentRecord = start;
        while (m->CurrentRecord)
                {
                AuthRecord *rr = m->CurrentRecord;
+               LogInfo("DeregLoop: %s deregistration for %p %02X %s",
+                       (rr->resrec.RecordType != kDNSRecordTypeDeregistering) ? "Initiating  " : "Accelerating",
+                       rr, rr->resrec.RecordType, ARDisplayString(m, rr));
                if (rr->resrec.RecordType != kDNSRecordTypeDeregistering)
+                       mDNS_Deregister_internal(m, rr, mDNS_Dereg_rapid);
+               else if (rr->AnnounceCount > 1)
                        {
-                       LogInfo("DeregLoop: Deregistering %p %02X %s", rr, rr->resrec.RecordType, ARDisplayString(m, rr));
-                       mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
+                       rr->AnnounceCount = 1;
+                       rr->LastAPTime = m->timenow - rr->ThisAPInterval;
                        }
-               // Note: We mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because
-               // the list may have been changed in that call.
+               // Mustn't advance m->CurrentRecord until *after* mDNS_Deregister_internal, because
+               // new records could have been added to the end of the list as a result of that call.
                if (m->CurrentRecord == rr) // If m->CurrentRecord was not advanced for us, do it now
                        m->CurrentRecord = rr->next;
                }
@@ -10058,17 +10108,25 @@ mDNSexport void mDNS_StartExit(mDNS *const m)
 
        mDNS_Lock(m);
 
+       LogInfo("mDNS_StartExit");
        m->ShutdownTime = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 5);
 
-       mDNS_DropLockBeforeCallback();          // mDNSCoreBeSleepProxyServer expects to be called without the lock held, so we emulate that here
-       mDNSCoreBeSleepProxyServer(m, 0, 0, 0, 0);
-       mDNS_ReclaimLockAfterCallback();
+       mDNSCoreBeSleepProxyServer_internal(m, 0, 0, 0, 0);
+
+#if APPLE_OSX_mDNSResponder
+#if ! NO_WCF
+       CHECK_WCF_FUNCTION(WCFConnectionDealloc)
+               {
+               if (m->WCF) WCFConnectionDealloc((WCFConnection *)m->WCF);
+               }
+#endif
+#endif
 
 #ifndef UNICAST_DISABLED
        {
        SearchListElem *s;
        SuspendLLQs(m);
-       // Don't need to do SleepRecordRegistrations() or SleepServiceRegistrations() here,
+       // Don't need to do SleepRecordRegistrations() here
        // because we deregister all records and services later in this routine
        while (m->Hostnames) mDNS_RemoveDynDNSHostName(m, &m->Hostnames->fqdn);
 
@@ -10099,9 +10157,11 @@ mDNSexport void mDNS_StartExit(mDNS *const m)
                // This has particularly important implications for our AutoTunnel records --
                // when we deregister our AutoTunnel records below, we don't want their mStatus_MemFree
                // handlers to just turn around and attempt to re-register those same records.
-               // Clearing t->ExternalPort will cause the mStatus_MemFree callback handlers to not do this.
+               // Clearing t->ExternalPort/t->RequestedPort will cause the mStatus_MemFree callback handlers
+               // to not do this.
                t->ExternalAddress = zerov4Addr;
                t->ExternalPort    = zeroIPPort;
+               t->RequestedPort   = zeroIPPort;
                t->Lifetime        = 0;
                t->Result          = mStatus_NoError;
                }
@@ -10127,24 +10187,9 @@ mDNSexport void mDNS_StartExit(mDNS *const m)
                m->SuppressSending = 0;
                }
 
-#if !defined(UNICAST_DISABLED) && USE_SEPARATE_UDNS_SERVICE_LIST
-       CurrentServiceRecordSet = m->ServiceRegistrations;
-       while (CurrentServiceRecordSet)
-               {
-               ServiceRecordSet *srs = CurrentServiceRecordSet;
-               LogInfo("mDNS_StartExit: Deregistering uDNS service %##s", srs->RR_SRV.resrec.name->c);
-               uDNS_DeregisterService(m, srs);
-               if (CurrentServiceRecordSet == srs)
-                       CurrentServiceRecordSet = srs->uDNS_next;
-               }
-#endif
-
        if (m->ResourceRecords) LogInfo("mDNS_StartExit: Sending final record deregistrations");
        else                    LogInfo("mDNS_StartExit: No deregistering records remain");
 
-       if (m->ServiceRegistrations) LogInfo("mDNS_StartExit: Sending final uDNS service deregistrations");
-       else                         LogInfo("mDNS_StartExit: No deregistering uDNS services remain");
-
        for (rr = m->DuplicateRecords; rr; rr = rr->next)
                LogMsg("mDNS_StartExit: Should not still have Duplicate Records remaining: %02X %s", rr->resrec.RecordType, ARDisplayString(m, rr));
 
@@ -10162,7 +10207,6 @@ mDNSexport void mDNS_FinalExit(mDNS *const m)
        mDNSu32 rrcache_totalused = 0;
        mDNSu32 slot;
        AuthRecord *rr;
-       ServiceRecordSet *srs;
 
        LogInfo("mDNS_FinalExit: mDNSPlatformClose");
        mDNSPlatformClose(m);
@@ -10191,8 +10235,5 @@ mDNSexport void mDNS_FinalExit(mDNS *const m)
        for (rr = m->ResourceRecords; rr; rr = rr->next)
                LogMsg("mDNS_FinalExit failed to send goodbye for: %p %02X %s", rr, rr->resrec.RecordType, ARDisplayString(m, rr));
 
-       for (srs = m->ServiceRegistrations; srs; srs = srs->uDNS_next)
-               LogMsg("mDNS_FinalExit failed to deregister service: %p %##s", srs, srs->RR_SRV.resrec.name->c);
-
        LogInfo("mDNS_FinalExit: done");
        }
index 36cbc439b208ce2f855b22ecbae47f6db23d5849..07647b52d452d3030ed303bd3c757f5298e82fa7 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: mDNSDebug.h,v $
-Revision 1.51  2009/06/25 23:36:59  cheshire
-To facilitate testing, added command-line switch "-OfferSleepProxyService"
-to re-enable the previously-supported mode of operation where we offer
-sleep proxy service on desktop Macs that are set to never sleep.
-
-Revision 1.50  2009/05/19 23:34:06  cheshire
-Updated comment to show correct metric of 80 for a low-priority sleep proxy
-
-Revision 1.49  2009/04/24 23:32:28  cheshire
-To facilitate testing, put back code to be a sleep proxy when set to never sleep, compiled out by compile-time switch
-
-Revision 1.48  2009/04/11 01:43:27  jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.47  2009/04/11 00:19:41  jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.46  2009/02/13 06:36:50  cheshire
-Update LogSPS definition
-
-Revision 1.45  2009/02/13 06:03:12  cheshire
-Added LogInfo for informational message logging
-
-Revision 1.44  2009/02/12 20:57:25  cheshire
-Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
-
-Revision 1.43  2008/12/10 02:27:14  cheshire
-Commented out definitions of LogClientOperations, LogTimeStamps, ForceAlerts and MACOSX_MDNS_MALLOC_DEBUGGING
-to allow overriding values to be easily defined in a Makefile or similar build environment
-
-Revision 1.42  2008/11/02 21:22:05  cheshire
-Changed mallocL size parameter back to "unsigned int"
-
-Revision 1.41  2008/11/02 21:14:58  cheshire
-Fixes to make mallocL/freeL debugging checks work on 64-bit
-
-Revision 1.40  2008/10/24 20:53:37  cheshire
-For now, define USE_SEPARATE_UDNS_SERVICE_LIST, so that we use the old service list code for this submission
-
-Revision 1.39  2008/02/26 21:17:11  cheshire
-Grouped all user settings together near the start of the file; added LogTimeStamps option
-
-Revision 1.38  2007/12/13 20:27:07  cheshire
-Remove unused VerifySameNameAssumptions symbol
-
-Revision 1.37  2007/12/01 00:33:17  cheshire
-Fixes from Bob Bradley for building on EFI
-
-Revision 1.36  2007/10/01 19:06:19  cheshire
-Defined symbolic constant MDNS_LOG_INITIAL_LEVEL to set the logging level we start out at
-
-Revision 1.35  2007/07/27 20:19:56  cheshire
-For now, comment out unused log levels MDNS_LOG_ERROR, MDNS_LOG_WARN, MDNS_LOG_INFO, MDNS_LOG_DEBUG
-
-Revision 1.34  2007/07/24 17:23:33  cheshire
-<rdar://problem/5357133> Add list validation checks for debugging
-
-Revision 1.33  2007/06/15 21:54:50  cheshire
-<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
-
-Revision 1.32  2007/05/25 16:03:03  cheshire
-Remove unused LogMalloc
-
-Revision 1.31  2007/04/06 19:50:05  cheshire
-Add ProgramName declaration
-
-Revision 1.30  2007/03/24 01:22:44  cheshire
-Add validator for uDNS data structures
-
-Revision 1.29  2006/08/14 23:24:23  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.28  2006/07/07 01:09:09  cheshire
-<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
-
-Revision 1.27  2006/06/29 07:42:14  cheshire
-<rdar://problem/3922989> Performance: Remove unnecessary SameDomainName() checks
-
-Revision 1.26  2005/07/04 22:40:26  cheshire
-Additional debugging code to help catch memory corruption
-
-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
-
-Revision 1.23  2004/05/18 23:51:25  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
-
-Revision 1.22  2004/04/22 04:27:42  cheshire
-Spacing tidyup
-
-Revision 1.21  2004/04/14 23:21:41  ksekar
-Removed accidental checkin of MALLOC_DEBUGING flag in 1.20
-
-Revision 1.20  2004/04/14 23:09:28  ksekar
-Support for TSIG signed dynamic updates.
-
-Revision 1.19  2004/03/15 18:57:59  cheshire
-Undo last checkin that accidentally made verbose debugging the default for all targets
-
-Revision 1.18  2004/03/13 01:57:33  ksekar
-<rdar://problem/3192546>: DynDNS: Dynamic update of service records
-
-Revision 1.17  2004/01/28 21:14:23  cheshire
-Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
-
-Revision 1.16  2003/12/09 01:30:06  rpantos
-Fix usage of ARGS... macros to build properly on Windows.
-
-Revision 1.15  2003/12/08 20:55:26  rpantos
-Move some definitions here from mDNSMacOSX.h.
-
-Revision 1.14  2003/08/12 19:56:24  cheshire
-Update to APSL 2.0
-
-Revision 1.13  2003/07/02 21:19:46  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.12  2003/05/26 03:01:27  cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
-
-Revision 1.11  2003/05/21 17:48:10  cheshire
-Add macro to enable GCC's printf format string checking
-
-Revision 1.10  2003/04/26 02:32:57  cheshire
-Add extern void LogMsg(const char *format, ...);
-
-Revision 1.9  2002/09/21 20:44:49  zarzycki
-Added APSL info
-
-Revision 1.8  2002/09/19 04:20:43  cheshire
-Remove high-ascii characters that confuse some systems
-
-Revision 1.7  2002/09/16 18:41:42  cheshire
-Merge in license terms from Quinn's copy, in preparation for Darwin release
-
-*/
+ */
 
 #ifndef __mDNSDebug_h
 #define __mDNSDebug_h
@@ -198,8 +55,6 @@ typedef enum
 //#define ForceAlerts 1
 //#define LogTimeStamps 1
 
-#define USE_SEPARATE_UDNS_SERVICE_LIST 1
-
 // Developer-settings section ends here
 
 #if MDNS_CHECK_PRINTF_STYLE_FUNCTIONS
@@ -240,31 +95,31 @@ typedef enum
 #if (MDNS_HAS_VA_ARG_MACROS)
        #if (MDNS_C99_VA_ARGS)
                #define debug_noop( ... ) ((void)0)
-               #define LogMsg( ... ) LogMsgWithLevel(MDNS_LOG_MSG, __VA_ARGS__)
-               #define LogOperation( ... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, __VA_ARGS__); } while (0)
-               #define LogSPS( ... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS, __VA_ARGS__); } while (0)
-               #define LogInfo( ... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO, __VA_ARGS__); } while (0)
+               #define LogMsg( ... )           LogMsgWithLevel(MDNS_LOG_MSG, __VA_ARGS__)
+               #define LogOperation( ... )     do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, __VA_ARGS__); } while (0)
+               #define LogSPS( ... )           do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS,       __VA_ARGS__); } while (0)
+               #define LogInfo( ... )          do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO,      __VA_ARGS__); } while (0)
        #elif (MDNS_GNU_VA_ARGS)
                #define debug_noop( ARGS... ) ((void)0)
-               #define LogMsg( ARGS... ) LogMsgWithLevel(MDNS_LOG_MSG, ARGS)
+               #define LogMsg( ARGS... )       LogMsgWithLevel(MDNS_LOG_MSG, ARGS)
                #define LogOperation( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, ARGS); } while (0)
-               #define LogSPS( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS, ARGS); } while (0)
-               #define LogInfo( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO, ARGS); } while (0)
+               #define LogSPS( ARGS... )       do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS,       ARGS); } while (0)
+               #define LogInfo( ARGS... )      do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO,      ARGS); } while (0)
        #else
                #error Unknown variadic macros
        #endif
 #else
        // If your platform does not support variadic macros, you need to define the following variadic functions.
        // See mDNSShared/mDNSDebug.c for sample implementation
-       extern void debug_noop(const char *format, ...);
+       #define debug_noop 1 ? (void)0 : (void)
        #define LogMsg LogMsg_
-       #define LogOperation mDNS_LoggingEnabled == 0 ? ((void)0) : LogOperation_
-       #define LogSPS mDNS_LoggingEnabled == 0 ? ((void)0) : LogSPS_
-       #define LogInfo mDNS_LoggingEnabled == 0 ? ((void)0) : LogInfo_
-       extern void LogMsg_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
+       #define LogOperation (mDNS_LoggingEnabled == 0) ? ((void)0) : LogOperation_
+       #define LogSPS       (mDNS_LoggingEnabled == 0) ? ((void)0) : LogSPS_
+       #define LogInfo      (mDNS_LoggingEnabled == 0) ? ((void)0) : LogInfo_
+       extern void LogMsg_(const char *format, ...)       IS_A_PRINTF_STYLE_FUNCTION(1,2);
        extern void LogOperation_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
-       extern void LogSPS_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
-       extern void LogInfo_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
+       extern void LogSPS_(const char *format, ...)       IS_A_PRINTF_STYLE_FUNCTION(1,2);
+       extern void LogInfo_(const char *format, ...)      IS_A_PRINTF_STYLE_FUNCTION(1,2);
 #endif
 
 #if MDNS_DEBUGMSGS
@@ -287,6 +142,8 @@ extern int        mDNS_DebugMode;   // If non-zero, LogMsg() writes to stderr inst
 extern const char ProgramName[];
 
 extern void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(2,3);
+// LogMsgNoIdent needs to be fixed so that it logs without the ident prefix like it used to
+// (or completely overhauled to use the new "log to a separate file" facility)
 #define LogMsgNoIdent LogMsg
 
 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
index 621d534f7e2558a08a80e4530c24b5f01fa36c3a..509d50b9f49946d76a14506a473132ee67295389 100755 (executable)
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
 
-
    NOTE:
    If you're building an application that uses DNS Service Discovery
    this is probably NOT the header file you're looking for.
    you can still use the exact same client C code as you'd use on a
    general-purpose desktop system.
 
-
-    Change History (most recent first):
-
-$Log: mDNSEmbeddedAPI.h,v $
-Revision 1.577  2009/07/16 00:34:18  cheshire
-<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
-Additional refinement: If we didn't register with a Sleep Proxy when going to sleep,
-we don't need to include our OWNER option in our packets when we re-awaken
-
-Revision 1.576  2009/07/15 23:35:37  cheshire
-<rdar://problem/6434656> Sleep Proxy: Put owner OPT records in multicast announcements to avoid conflicts
-
-Revision 1.575  2009/07/11 01:57:00  cheshire
-<rdar://problem/6613674> Sleep Proxy: Add support for using sleep proxy in local network interface hardware
-Added declaration of ActivateLocalProxy
-
-Revision 1.574  2009/07/10 23:03:17  cheshire
-Made SecondLabel(X) more defensive, to guard against the case where the name doesn't have a second label
-
-Revision 1.573  2009/06/30 18:17:45  herscher
-Add to 64 bit macro check for 64 bit Windows OSes
-
-Revision 1.572  2009/06/27 00:52:27  cheshire
-<rdar://problem/6959273> mDNSResponder taking up 13% CPU with 400 KBps incoming bonjour requests
-Removed overly-complicate and ineffective multi-packet known-answer snooping code
-(Bracketed it with "#if ENABLE_MULTI_PACKET_QUERY_SNOOPING" for now; will delete actual code later)
-
-Revision 1.571  2009/06/26 01:55:54  cheshire
-<rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
-Additional refinements -- except for the case of explicit queries for record types we don't have (for names we own),
-add additional NSEC records only when there's space to do that without having to generate an additional packet
-
-Revision 1.570  2009/06/24 22:14:21  cheshire
-<rdar://problem/6911445> Plugging and unplugging the power cable shouldn't cause a network change event
-
-Revision 1.569  2009/06/03 23:07:12  cheshire
-<rdar://problem/6890712> mDNS: iChat's Buddy photo always appears as the "shadow person" over Bonjour
-Large records were not being added in cases where an NSEC record was also required
-
-Revision 1.568  2009/05/19 22:37:04  cheshire
-<rdar://problem/6903507> Sleep Proxy: Retransmission logic not working reliably on quiet networks
-Added NextScheduledSPRetry field
-
-Revision 1.567  2009/05/13 17:25:33  mkrochma
-<rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
-Sleep proxy client should only look for services being advertised via Multicast
-
-Revision 1.566  2009/05/12 23:09:24  cheshire
-<rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
-Declare mDNSCoreHaveAdvertisedServices routine so it can be called from daemon.c
-
-Revision 1.565  2009/05/09 00:10:58  jessic2
-Change expected size of NetworkInterfaceInfo to fix build failure
-
-Revision 1.564  2009/05/07 23:31:26  cheshire
-<rdar://problem/6601427> Sleep Proxy: Retransmit and retry Sleep Proxy Server requests
-Added NextSPSAttempt and NextSPSAttemptTime fields to NetworkInterfaceInfo_struct
-
-Revision 1.563  2009/04/24 21:06:38  cheshire
-Added comment about UDP length field (includes UDP header, so minimum value is 8 bytes)
-
-Revision 1.562  2009/04/24 00:22:23  cheshire
-<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
-Added definition of rdataNSEC
-
-Revision 1.561  2009/04/23 22:06:29  cheshire
-Added CacheRecord and InterfaceID parameters to MakeNegativeCacheRecord, in preparation for:
-<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
-
-Revision 1.560  2009/04/23 21:54:50  cheshire
-Updated comments
-
-Revision 1.559  2009/04/22 00:37:38  cheshire
-<rdar://problem/6814427> Remove unused kDNSType_MAC
-
-Revision 1.558  2009/04/21 23:36:25  cheshire
-<rdar://problem/6814427> Remove unused kDNSType_MAC
-
-Revision 1.557  2009/04/15 20:42:51  mcguire
-<rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
-
-Revision 1.556  2009/04/11 00:19:43  jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.555  2009/04/01 21:12:27  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows.
-
-Revision 1.554  2009/04/01 17:50:11  mcguire
-cleanup mDNSRandom
-
-Revision 1.553  2009/03/26 03:59:00  jessic2
-Changes for <rdar://problem/6492552&6492593&6492609&6492613&6492628&6492640&6492699>
-
-Revision 1.552  2009/03/20 23:53:03  jessic2
-<rdar://problem/6646228> SIGHUP should restart all in-progress queries
-
-Revision 1.551  2009/03/18 20:41:04  cheshire
-Added definition of the all-ones mDNSOpaque16 ID
-
-Revision 1.550  2009/03/17 19:10:29  mcguire
-Fix sizechecks for x86_64
-
-Revision 1.549  2009/03/17 01:22:56  cheshire
-<rdar://problem/6601427> Sleep Proxy: Retransmit and retry Sleep Proxy Server requests
-Initial support for resolving up to three Sleep Proxies in parallel
-
-Revision 1.548  2009/03/14 01:42:56  mcguire
-<rdar://problem/5457116> BTMM: Fix issues with multiple .Mac accounts on the same machine
-
-Revision 1.547  2009/03/10 01:14:30  cheshire
-Sleep Proxies with invalid names need to be ignored (score 10000),
-not treated as "Sleep Proxy of last resort" (score 9999)
-
-Revision 1.546  2009/03/06 23:51:51  mcguire
-Fix broken build by defining DiscardPort
-
-Revision 1.545  2009/03/06 22:39:23  cheshire
-<rdar://problem/6655850> Ignore prototype base stations when picking Sleep Proxy to register with
-
-Revision 1.544  2009/03/04 01:33:30  cheshire
-Add m->ProxyRecords counter
-
-Revision 1.543  2009/03/03 23:04:43  cheshire
-For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC)
-
-Revision 1.542  2009/03/03 22:51:53  cheshire
-<rdar://problem/6504236> Sleep Proxy: Waking on same network but different interface will cause conflicts
-
-Revision 1.541  2009/03/03 00:45:19  cheshire
-Added m->PrimaryMAC field
-
-Revision 1.540  2009/02/27 02:56:57  cheshire
-Moved struct SearchListElem definition from uDNS.c into mDNSEmbeddedAPI.h
-
-Revision 1.539  2009/02/17 23:29:01  cheshire
-Throttle logging to a slower rate when running on SnowLeopard
-
-Revision 1.538  2009/02/11 02:31:57  cheshire
-Moved SystemWakeOnLANEnabled from mDNSMacOSX.h, so it's accessible to mDNSCore routines
-
-Revision 1.537  2009/02/07 02:51:48  cheshire
-<rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
-Added new functions and timing variables
-
-Revision 1.536  2009/01/30 23:50:31  cheshire
-Added LastLabel() routine to get the last label of a domainname
-
-Revision 1.535  2009/01/23 00:38:36  mcguire
-<rdar://problem/5570906> BTMM: Doesn't work with Linksys WRT54GS firmware 4.71.1
-
-Revision 1.534  2009/01/22 02:14:25  cheshire
-<rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
-
-Revision 1.533  2009/01/21 03:43:57  mcguire
-<rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore
-
-Revision 1.532  2009/01/16 19:50:36  cheshire
-Oops. Fixed definition of SleepProxyServiceType.
-
-Revision 1.531  2009/01/16 19:48:09  cheshire
-Added definition of SleepProxyServiceType
-
-Revision 1.530  2009/01/15 00:22:49  mcguire
-<rdar://problem/6437092> NAT-PMP: mDNSResponder needs to listen on 224.0.0.1:5350/UDP with REUSEPORT
-
-Revision 1.529  2009/01/13 00:31:44  cheshire
-Fixed off-by-one error in computing the implicit limit pointer in the "DomainNameLength(name)" macro
-
-Revision 1.528  2009/01/10 01:43:52  cheshire
-Changed misleading function name 'AnsweredLOQ' to more informative 'AnsweredLocalQ'
-
-Revision 1.527  2008/12/12 01:23:19  cheshire
-Added m->SPSProxyListChanged state variable to flag when we need to update our BPF filter program
-
-Revision 1.526  2008/12/12 00:51:14  cheshire
-Added structure definitions for IPv6Header, etc.
-
-Revision 1.525  2008/12/10 02:18:31  cheshire
-Increased MaxMsg to 160 for showing longer TXT records in SIGINFO output
-
-Revision 1.524  2008/12/10 01:49:39  cheshire
-Fixes for alignment issues on ARMv5
-
-Revision 1.523  2008/12/05 02:35:24  mcguire
-<rdar://problem/6107390> Write to the DynamicStore when a Sleep Proxy server is available on the network
-
-Revision 1.522  2008/12/04 21:08:51  mcguire
-<rdar://problem/6116863> mDNS: Provide mechanism to disable Multicast advertisements
-
-Revision 1.521  2008/12/04 02:19:24  cheshire
-Updated comment
-
-Revision 1.520  2008/11/26 20:28:05  cheshire
-Added new SSHPort constant
-
-Revision 1.519  2008/11/25 22:46:30  cheshire
-For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta"
-
-Revision 1.518  2008/11/25 05:07:15  cheshire
-<rdar://problem/6374328> Advertise Sleep Proxy metrics in service name
-
-Revision 1.517  2008/11/20 01:51:19  cheshire
-Exported RecreateNATMappings so it's callable from other files
-
-Revision 1.516  2008/11/16 16:49:25  cheshire
-<rdar://problem/6375808> LLQs broken in mDNSResponder-184
-DNSOpt_LLQData_Space was incorrectly defined to be 18 instead of 22
-
-Revision 1.515  2008/11/14 20:59:41  cheshire
-Added mDNSEthAddressIsZero(A) macro
-
-Revision 1.514  2008/11/14 02:17:41  cheshire
-Added NextScheduledSPS task scheduling variable
-
-Revision 1.513  2008/11/14 00:47:19  cheshire
-Added TimeRcvd and TimeExpire fields to AuthRecord_struct
-
-Revision 1.512  2008/11/14 00:00:53  cheshire
-After client machine wakes up, Sleep Proxy machine need to remove any records
-it was temporarily holding as proxy for that client
-
-Revision 1.511  2008/11/13 19:04:44  cheshire
-Added definition of OwnerOptData
-
-Revision 1.510  2008/11/06 23:48:32  cheshire
-Changed SleepProxyServerType to mDNSu8
-
-Revision 1.509  2008/11/04 23:06:50  cheshire
-Split RDataBody union definition into RDataBody and RDataBody2, and removed
-SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord
-
-Revision 1.508  2008/11/04 22:21:43  cheshire
-Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord
-
-Revision 1.507  2008/11/04 22:13:43  cheshire
-Made RDataBody parameter to GetRRDisplayString_rdb "const"
-
-Revision 1.506  2008/11/04 20:06:19  cheshire
-<rdar://problem/6186231> Change MAX_DOMAIN_NAME to 256
-
-Revision 1.505  2008/11/03 23:49:47  mkrochma
-Increase NATMAP_DEFAULT_LEASE to 2 hours so we do maintenance wake less often
-
-Revision 1.504  2008/10/31 22:55:04  cheshire
-Initial support for structured SPS names
-
-Revision 1.503  2008/10/24 23:58:47  cheshire
-Ports should be mDNSIPPort, not mDNSOpaque16
-
-Revision 1.502  2008/10/23 22:25:56  cheshire
-Renamed field "id" to more descriptive "updateid"
-
-Revision 1.501  2008/10/22 22:22:27  cheshire
-Added packet structure definitions
-
-Revision 1.500  2008/10/22 19:55:35  cheshire
-Miscellaneous fixes; renamed FindFirstAnswerInCache to FindSPSInCache
-
-Revision 1.499  2008/10/22 17:15:47  cheshire
-Updated definitions of mDNSIPv4AddressIsZero/mDNSIPv4AddressIsOnes, etc.
-
-Revision 1.498  2008/10/22 01:01:52  cheshire
-Added onesEthAddr constant, used for sending ARP broadcasts
-
-Revision 1.497  2008/10/21 00:51:11  cheshire
-Added declaration of mDNSPlatformSetBPF(), used by uds_daemon.c to pass BPF fd to mDNSMacOSX.c
-
-Revision 1.496  2008/10/16 22:38:52  cheshire
-Added declaration of mDNSCoreReceiveRawPacket()
-
-Revision 1.495  2008/10/15 22:53:51  cheshire
-Removed unused "#define LocalReverseMapDomain"
-
-Revision 1.494  2008/10/15 20:37:17  cheshire
-Added "#define DNSOpt_Lease_Space 19"
-
-Revision 1.493  2008/10/14 21:37:56  cheshire
-Removed unnecessary m->BeSleepProxyServer variable
-
-Revision 1.492  2008/10/14 20:26:36  cheshire
-Added definition of a new kDNSType_MAC rdata type
-
-Revision 1.491  2008/10/09 22:29:04  cheshire
-Added "mDNSEthAddr MAC" to NetworkInterfaceInfo_struct
-
-Revision 1.490  2008/10/09 21:39:20  cheshire
-Update list of DNS types
-
-Revision 1.489  2008/10/09 18:59:19  cheshire
-Added NetWakeResolve code, removed unused m->SendDeregistrations and m->SendImmediateAnswers
-
-Revision 1.488  2008/10/08 01:02:03  cheshire
-Added mDNS_SetupQuestion() convenience function
-
-Revision 1.487  2008/10/07 21:41:57  mcguire
-Increase sizecheck limits to account for DNSQuestion added to NetworkInterfaceInfo_struct in 64bit builds
-
-Revision 1.486  2008/10/07 15:56:24  cheshire
-Increase sizecheck limits to account for DNSQuestion added to NetworkInterfaceInfo_struct
-
-Revision 1.485  2008/10/04 00:48:37  cheshire
-Added DNSQuestion to NetworkInterfaceInfo_struct, used for browsing for Sleep Proxy Servers
-
-Revision 1.484  2008/10/04 00:01:45  cheshire
-Move NetworkInterfaceInfo_struct further down in file (we'll need to add a DNSQuestion to it later)
-
-Revision 1.483  2008/10/03 23:28:41  cheshire
-Added declaration of mDNSPlatformSendRawPacket
-
-Revision 1.482  2008/10/03 17:30:05  cheshire
-Added declaration of mDNS_ConfigChanged(mDNS *const m);
-
-Revision 1.481  2008/10/02 22:38:58  cheshire
-Added SleepProxyServer fields, and mDNSCoreBeSleepProxyServer() call for turning SleepProxyServer on and off
-
-Revision 1.480  2008/10/01 21:22:17  cheshire
-Added NetWake field to NetworkInterfaceInfo structure, to signal when Wake-On-Magic-Packet is enabled for that interface
-
-Revision 1.479  2008/09/29 20:12:37  cheshire
-Rename 'AnswerLocalQuestions' to more descriptive 'AnswerLocalOnlyQuestions' and 'AnsweredLocalQ' to 'AnsweredLOQ'
-
-Revision 1.478  2008/09/23 02:37:10  cheshire
-Added FirstLabel/SecondLabel macros
-
-Revision 1.477  2008/09/20 00:34:22  mcguire
-<rdar://problem/6129039> BTMM: Add support for WANPPPConnection
-
-Revision 1.476  2008/09/05 22:22:01  cheshire
-Move "UDPSocket *LocalSocket" field to more logical place in DNSQuestion_struct
-
-Revision 1.475  2008/07/25 22:34:11  mcguire
-fix sizecheck issues for 64bit
-
-Revision 1.474  2008/07/24 20:23:03  cheshire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-
-Revision 1.473  2008/07/18 21:37:42  mcguire
-<rdar://problem/5736845> BTMM: alternate SSDP queries between multicast & unicast
-
-Revision 1.472  2008/07/01 01:39:59  mcguire
-<rdar://problem/5823010> 64-bit fixes
-
-Revision 1.471  2008/06/26 17:24:11  mkrochma
-<rdar://problem/5450912> BTMM: Stop listening on UDP 5351 for NAT Status Announcements
-
-Revision 1.470  2008/06/19 01:20:49  mcguire
-<rdar://problem/4206534> Use all configured DNS servers
-
-Revision 1.469  2008/03/07 18:56:02  cheshire
-<rdar://problem/5777647> dnsbugtest query every three seconds when source IP address of response doesn't match
-
-Revision 1.468  2008/03/06 02:48:34  mcguire
-<rdar://problem/5321824> write status to the DS
-
-Revision 1.467  2008/02/26 20:48:46  cheshire
-Need parentheses around use of macro argument in mDNS_TimeNow_NoLock(m)
-
-Revision 1.466  2008/02/21 21:36:32  cheshire
-Updated comment about record type values (kDNSRecordTypePacketAns/Auth/Add)
-
-Revision 1.465  2008/02/20 00:39:05  mcguire
-<rdar://problem/5427102> Some device info XML blobs too large
-
-Revision 1.464  2008/01/31 23:33:29  mcguire
-<rdar://problem/5614450> changes to build using gcc 4.2 with -Werror
-
-Revision 1.463  2007/12/17 23:53:25  cheshire
-Added DNSDigest_SignMessageHostByteOrder, for signing messages not yet converted to network byte order
-
-Revision 1.462  2007/12/17 23:48:29  cheshire
-DNSDigest_SignMessage doesn't need to return a result -- it already updates the 'end' parameter
-
-Revision 1.461  2007/12/15 00:18:51  cheshire
-Renamed question->origLease to question->ReqLease
-
-Revision 1.460  2007/12/14 23:55:28  cheshire
-Moved "struct tcpInfo_t" definition from uDNS.c to mDNSEmbeddedAPI.h
-
-Revision 1.459  2007/12/07 22:40:34  cheshire
-Rename 'LocalAnswer' to more descriptive 'AnsweredLocalQ'
-
-Revision 1.458  2007/12/07 00:45:58  cheshire
-<rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
-
-Revision 1.457  2007/12/06 00:22:27  mcguire
-<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
-
-Revision 1.456  2007/12/05 01:45:35  cheshire
-Renamed markedForDeletion -> MarkedForDeletion
-
-Revision 1.455  2007/12/01 01:21:27  jgraessley
-<rdar://problem/5623140> mDNSResponder unicast DNS improvements
-
-Revision 1.454  2007/12/01 00:34:03  cheshire
-Fixes from Bob Bradley for building on EFI
-
-Revision 1.453  2007/10/29 23:51:22  cheshire
-Added comment about NATTraversalInfo ExternalAddress field
-
-Revision 1.452  2007/10/29 18:13:40  cheshire
-Added Question_uDNS macro, analogous to AuthRecord_uDNS macro
-
-Revision 1.451  2007/10/26 23:42:57  cheshire
-Removed unused "mDNSs32 expire" field from ServiceRecordSet_struct
-
-Revision 1.450  2007/10/26 22:24:08  cheshire
-Added AuthRecord_uDNS() macro to determine when a given AuthRecord needs to be registered via unicast DNS
-
-Revision 1.449  2007/10/25 20:48:47  cheshire
-For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
-
-Revision 1.448  2007/10/22 22:19:44  cheshire
-Tidied up code alignment
-
-Revision 1.447  2007/10/22 19:40:30  cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-Made subroutine mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst)
-
-Revision 1.446  2007/10/17 22:49:54  cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-
-Revision 1.445  2007/10/17 22:37:23  cheshire
-<rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
-
-Revision 1.444  2007/09/29 03:14:52  cheshire
-<rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
-Added AutoTunnelUnregistered macro to check state of DomainAuthInfo AuthRecords
-
-Revision 1.443  2007/09/27 21:21:39  cheshire
-Export CompleteDeregistration so it's callable from other files
-
-Revision 1.442  2007/09/27 00:25:39  cheshire
-Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
-<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
-
-Revision 1.441  2007/09/26 23:17:49  cheshire
-Get rid of unused kWideAreaTTL constant
-
-Revision 1.440  2007/09/26 22:06:02  cheshire
-<rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
-
-Revision 1.439  2007/09/21 21:12:36  cheshire
-DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter
-
-Revision 1.438  2007/09/19 20:32:09  cheshire
-Export GetAuthInfoForName so it's callable from other files
-
-Revision 1.437  2007/09/18 21:42:29  cheshire
-To reduce programming mistakes, renamed ExtPort to RequestedPort
-
-Revision 1.436  2007/09/14 21:26:08  cheshire
-<rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
-
-Revision 1.435  2007/09/13 00:16:41  cheshire
-<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
-
-Revision 1.434  2007/09/12 23:03:07  cheshire
-<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
-
-Revision 1.433  2007/09/12 22:19:28  cheshire
-<rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
-
-Revision 1.432  2007/09/12 19:22:19  cheshire
-Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
-Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
-
-Revision 1.431  2007/09/11 19:19:16  cheshire
-Correct capitalization of "uPNP" to "UPnP"
-
-Revision 1.430  2007/09/10 22:06:50  cheshire
-Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
-
-Revision 1.429  2007/09/07 21:16:58  cheshire
-Add new symbol "NATPMPAnnouncementPort" (5350)
-
-Revision 1.428  2007/09/05 21:48:01  cheshire
-<rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
-Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code needs
-to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
-otherwise those records will expire and vanish from the cache.
-
-Revision 1.427  2007/09/05 20:47:12  cheshire
-Tidied up alignment of code layout
-
-Revision 1.426  2007/09/04 20:37:06  cheshire
-<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
-Reorder fields into more logical order, with AuthInfo before DuplicateOf
-
-Revision 1.425  2007/08/31 19:53:14  cheshire
-<rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
-If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
-
-Revision 1.424  2007/08/31 18:49:49  vazquez
-<rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
-
-Revision 1.423  2007/08/31 00:04:28  cheshire
-Added comment explaining deltime in DomainAuthInfo structure
-
-Revision 1.422  2007/08/28 23:58:42  cheshire
-Rename HostTarget -> AutoTarget
-
-Revision 1.421  2007/08/27 20:30:43  cheshire
-Only include TunnelClients list when building for OS X
-
-Revision 1.420  2007/08/23 21:47:09  vazquez
-<rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
-make sure we clean up port mappings on base stations by sending a lease value of 0,
-and only send NAT-PMP packets on private networks; also save some memory by
-not using packet structs in NATTraversals.
-
-Revision 1.419  2007/08/08 21:07:47  vazquez
-<rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
-
-Revision 1.418  2007/08/01 16:09:13  cheshire
-Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
-
-Revision 1.417  2007/08/01 03:04:59  cheshire
-Add NATTraversalInfo structures to HostnameInfo and DomainAuthInfo
-
-Revision 1.416  2007/08/01 00:04:13  cheshire
-<rdar://problem/5261696> Crash in tcpKQSocketCallback
-Half-open TCP connections were not being cancelled properly
-
-Revision 1.415  2007/07/31 02:28:35  vazquez
-<rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
-
-Revision 1.414  2007/07/30 23:34:19  cheshire
-Remove unused "udpSock" from DNSQuestion
-
-Revision 1.413  2007/07/28 01:25:56  cheshire
-<rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
-
-Revision 1.412  2007/07/27 23:57:23  cheshire
-Added compile-time structure size checks
-
-Revision 1.411  2007/07/27 22:50:08  vazquez
-Allocate memory for UPnP request and reply buffers instead of using arrays
-
-Revision 1.410  2007/07/27 19:37:19  cheshire
-Moved AutomaticBrowseDomainQ into main mDNS object
-
-Revision 1.409  2007/07/27 19:30:39  cheshire
-Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
-to properly reflect tri-state nature of the possible responses
-
-Revision 1.408  2007/07/27 18:44:01  cheshire
-Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
-
-Revision 1.407  2007/07/26 21:19:26  vazquez
-Retry port mapping with incremented port number (up to max) in order to handle
-port mapping conflicts on UPnP gateways
-
-Revision 1.406  2007/07/25 22:19:59  cheshire
-ClientTunnel structure also needs a rmt_outer_port field
-
-Revision 1.405  2007/07/25 03:05:02  vazquez
-Fixes for:
-<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
-<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
-and a myriad of other security problems
-
-Revision 1.404  2007/07/24 20:22:07  cheshire
-Add AutoTunnelHostAddrActive flag
-
-Revision 1.403  2007/07/24 04:14:29  cheshire
-<rdar://problem/5356281> LLQs not working in with NAT Traversal
-
-Revision 1.402  2007/07/21 00:54:44  cheshire
-<rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
-
-Revision 1.401  2007/07/20 20:01:38  cheshire
-Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
-
-Revision 1.400  2007/07/20 00:54:18  cheshire
-<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-
-Revision 1.399  2007/07/18 03:22:35  cheshire
-SetupLocalAutoTunnelInterface_internal needs to be callable from uDNS.c
-
-Revision 1.398  2007/07/18 02:26:56  cheshire
-Don't need to declare UpdateTunnels here
-
-Revision 1.397  2007/07/18 01:03:50  cheshire
-<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
-Add list of client tunnels so we can automatically reconfigure when local address changes
-
-Revision 1.396  2007/07/16 23:54:48  cheshire
-<rdar://problem/5338850> Crash when removing or changing DNS keys
-
-Revision 1.395  2007/07/16 20:12:33  vazquez
-<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
-
-Revision 1.394  2007/07/12 02:51:27  cheshire
-<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
-
-Revision 1.393  2007/07/11 23:43:42  cheshire
-Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
-
-Revision 1.392  2007/07/11 22:44:40  cheshire
-<rdar://problem/5328801> SIGHUP should purge the cache
-
-Revision 1.391  2007/07/11 20:30:45  cheshire
-<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
-Added AutoTunnelTarget and AutoTunnelService to DomainAuthInfo structure
-
-Revision 1.390  2007/07/11 18:56:55  cheshire
-Added comments about AutoTunnelHostAddr and AutoTunnelLabel
-
-Revision 1.389  2007/07/11 02:44:03  cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-Added AutoTunnel fields to structures
-
-Revision 1.388  2007/07/10 01:53:18  cheshire
-<rdar://problem/5196524> uDNS: mDNSresponder is leaking TCP connections to DNS server
-AuthRecord, ServiceRecordSet, and DNSQuestion structures need tcpInfo_t pointers
-so they can keep track of what TCP connections they open
-
-Revision 1.387  2007/07/06 18:55:15  cheshire
-Add explicit NextScheduledNATOp scheduling variable
-
-Revision 1.386  2007/07/03 20:54:11  cheshire
-Tidied up code layout of NATTraversalInfo_struct fields and comments
-
-Revision 1.385  2007/07/03 00:40:23  vazquez
-More changes for <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-Safely deal with packet replies and client callbacks
-
-Revision 1.384  2007/06/29 00:08:07  vazquez
-<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-
-Revision 1.383  2007/06/20 01:10:12  cheshire
-<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-
-Revision 1.382  2007/06/19 20:31:59  cheshire
-Add DNSServer_Disabled state
-Add mDNSInterfaceID for DNS servers reachable over specific interfaces
-
-Revision 1.381  2007/06/15 18:11:16  cheshire
-<rdar://problem/5174466> mDNSResponder crashed in memove() near end of MobileSafari stress test
-Made AssignDomainName more defensive when source name is garbage
-
-Revision 1.380  2007/05/25 00:04:51  cheshire
-Added comment explaining rdlength
-
-Revision 1.379  2007/05/21 18:04:40  cheshire
-Updated comments -- port_mapping_create_reply renamed to port_mapping_reply
-
-Revision 1.378  2007/05/17 19:11:46  cheshire
-Tidy up code layout
-
-Revision 1.377  2007/05/15 00:43:33  cheshire
-Remove unused regState_Cancelled
-
-Revision 1.376  2007/05/14 23:51:49  cheshire
-Added constants MAX_REVERSE_MAPPING_NAME_V4 and MAX_REVERSE_MAPPING_NAME_V6
-
-Revision 1.375  2007/05/10 21:19:18  cheshire
-Rate-limit DNS test queries to at most one per three seconds
-(useful when we have a dozen active WAB queries, and then we join a new network)
-
-Revision 1.374  2007/05/07 22:07:47  cheshire
-<rdar://problem/4738025> Enhance GetLargeResourceRecord to decompress more record types
-
-Revision 1.373  2007/05/07 20:43:45  cheshire
-<rdar://problem/4241419> Reduce the number of queries and announcements
-
-Revision 1.372  2007/05/04 22:15:29  cheshire
-Get rid of unused q->RestartTime
-
-Revision 1.371  2007/05/03 22:40:37  cheshire
-<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
-
-Revision 1.370  2007/05/02 22:18:09  cheshire
-Renamed NATTraversalInfo_struct context to NATTraversalContext
-
-Revision 1.369  2007/05/01 21:21:42  cheshire
-Add missing parentheses in LEASE_OPT_RDLEN definition
-
-Revision 1.368  2007/04/30 21:33:38  cheshire
-Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
-is iterating through the m->ServiceRegistrations list
-
-Revision 1.367  2007/04/28 01:31:59  cheshire
-Improve debugging support for catching memory corruption problems
-
-Revision 1.366  2007/04/27 19:28:02  cheshire
-Any code that calls StartGetZoneData needs to keep a handle to the structure, so
-it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
--- it would start a query and then quickly cancel it, and then when
-StartGetZoneData completed, it had a dangling pointer and crashed.)
-
-Revision 1.365  2007/04/26 00:35:15  cheshire
-<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
-Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
-inside the firewall may give answers where a public one gives none, and vice versa.)
-
-Revision 1.364  2007/04/24 02:07:42  cheshire
-<rdar://problem/4246187> Identical client queries should reference a single shared core query
-Deleted some more redundant code
-
-Revision 1.363  2007/04/24 00:09:47  cheshire
-Remove MappedV4 field from mDNS_struct (not actually used anywhere)
-
-Revision 1.362  2007/04/22 06:02:02  cheshire
-<rdar://problem/4615977> Query should immediately return failure when no server
-
-Revision 1.361  2007/04/21 19:43:33  cheshire
-Code tidying: represent NAT opcodes as bitwise combinations rather than numerical additions
-
-Revision 1.360  2007/04/20 21:17:24  cheshire
-For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
-
-Revision 1.359  2007/04/19 22:50:53  cheshire
-<rdar://problem/4246187> Identical client queries should reference a single shared core query
-
-Revision 1.358  2007/04/19 20:06:41  cheshire
-Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
-
-Revision 1.357  2007/04/19 18:14:51  cheshire
-In mDNS_AddSearchDomain_CString check for NULL pointer before calling MakeDomainNameFromDNSNameString()
-
-Revision 1.356  2007/04/18 20:56:46  cheshire
-Added mDNS_AddSearchDomain_CString macro
-
-Revision 1.355  2007/04/17 19:21:29  cheshire
-<rdar://problem/5140339> Domain discovery not working over VPN
-
-Revision 1.354  2007/04/05 22:55:34  cheshire
-<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
-
-Revision 1.353  2007/04/05 20:40:37  cheshire
-Remove unused mDNSPlatformTCPGetFlags()
-
-Revision 1.352  2007/04/04 21:48:52  cheshire
-<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
-
-Revision 1.351  2007/04/04 01:27:45  cheshire
-Update comment
-
-Revision 1.350  2007/04/04 00:03:26  cheshire
-<rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
-
-Revision 1.349  2007/04/03 19:37:58  cheshire
-Rename mDNSAddrIsv4Private() to more precise mDNSAddrIsRFC1918()
-
-Revision 1.348  2007/04/03 19:13:39  cheshire
-Added macros mDNSSameIPPort, mDNSSameOpaque16, mDNSIPPortIsZero, mDNSOpaque16IsZero
-
-Revision 1.347  2007/03/28 20:59:26  cheshire
-<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
-
-Revision 1.346  2007/03/28 15:56:37  cheshire
-<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
-
-Revision 1.345  2007/03/22 19:29:23  cheshire
-Add comment and check to ensure StandardAuthRDSize is at least 256 bytes
-
-Revision 1.344  2007/03/22 18:31:48  cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.343  2007/03/22 00:49:20  cheshire
-<rdar://problem/4848295> Advertise model information via Bonjour
-
-Revision 1.342  2007/03/21 23:06:00  cheshire
-Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
-
-Revision 1.341  2007/03/21 20:44:11  cheshire
-Added mDNSAddressIsv4LinkLocal macro
-
-Revision 1.340  2007/03/21 00:30:02  cheshire
-<rdar://problem/4789455> Multiple errors in DNameList-related code
-
-Revision 1.339  2007/03/20 17:07:15  cheshire
-Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-
-Revision 1.338  2007/03/10 02:28:28  cheshire
-Added comment explaining NATResponseHndlr
-
-Revision 1.337  2007/03/10 02:02:58  cheshire
-<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
-Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
-
-Revision 1.336  2007/02/28 22:12:24  cheshire
-Get rid of unused mDNSVal32 and mDNSOpaque32fromIntVal
-
-Revision 1.335  2007/02/28 21:49:07  cheshire
-Off-by-one error: SameDomainLabelCS (case-sensitive) was stopping one character short of
-the end of the label, e.g. it would fail to detect that "chesh1" and "chesh2" are different.
-
-Revision 1.334  2007/02/28 01:44:26  cheshire
-<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
-
-Revision 1.333  2007/02/27 22:55:22  cheshire
-Get rid of unused AllDNSLinkGroupv4 and AllDNSLinkGroupv6
-
-Revision 1.332  2007/02/27 02:48:24  cheshire
-Parameter to LNT_GetPublicIP function is IPv4 address, not anonymous "mDNSOpaque32" object
-
-Revision 1.331  2007/02/14 03:16:39  cheshire
-<rdar://problem/4789477> Eliminate unnecessary malloc/free in mDNSCore code
-
-Revision 1.330  2007/02/08 21:12:28  cheshire
-<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
-
-Revision 1.329  2007/02/07 01:19:36  cheshire
-<rdar://problem/4849427> API: Reconcile conflicting error code values
-
-Revision 1.328  2007/01/25 00:19:40  cheshire
-Add CNAMEReferrals field to DNSQuestion_struct
-
-Revision 1.327  2007/01/23 02:56:10  cheshire
-Store negative results in the cache, instead of generating them out of pktResponseHndlr()
-
-Revision 1.326  2007/01/20 01:30:49  cheshire
-Update comments
-
-Revision 1.325  2007/01/19 18:39:11  cheshire
-Fix a bunch of parameters that should have been declared "const"
-
-Revision 1.324  2007/01/19 18:04:04  cheshire
-For naming consistency, use capital letters for RR types: rdataOpt should be rdataOPT
-
-Revision 1.323  2007/01/17 21:46:02  cheshire
-Remove redundant duplicated "isPrivate" field from LLQ_Info
-
-Revision 1.322  2007/01/10 22:51:56  cheshire
-<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
-
-Revision 1.321  2007/01/09 22:37:18  cheshire
-Provide ten-second grace period for deleted keys, to give mDNSResponder
-time to delete host name before it gives up access to the required key.
-
-Revision 1.320  2007/01/05 08:30:41  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.319  2007/01/04 23:11:11  cheshire
-<rdar://problem/4720673> uDNS: Need to start caching unicast records
-When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
-
-Revision 1.318  2007/01/04 20:57:48  cheshire
-Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
-
-Revision 1.317  2007/01/04 02:39:53  cheshire
-<rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
-
-Revision 1.316  2006/12/22 20:59:49  cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.315  2006/12/20 04:07:35  cheshire
-Remove uDNS_info substructure from AuthRecord_struct
-
-Revision 1.314  2006/12/19 22:49:23  cheshire
-Remove uDNS_info substructure from ServiceRecordSet_struct
-
-Revision 1.313  2006/12/19 02:38:20  cheshire
-Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
-
-Revision 1.312  2006/12/19 02:18:48  cheshire
-Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
-
-Revision 1.311  2006/12/16 01:58:31  cheshire
-<rdar://problem/4720673> uDNS: Need to start caching unicast records
-
-Revision 1.310  2006/12/15 19:09:56  cheshire
-<rdar://problem/4769083> ValidateRData() should be stricter about malformed MX and SRV records
-Made DomainNameLength() more defensive by adding a limit parameter, so it can be
-safely used to inspect potentially malformed data received from external sources.
-Without this, a domain name that starts off apparently valid, but extends beyond the end of
-the received packet data, could have appeared valid if the random bytes are already in memory
-beyond the end of the packet just happened to have reasonable values (e.g. all zeroes).
-
-Revision 1.309  2006/12/14 03:02:37  cheshire
-<rdar://problem/4838433> Tools: dns-sd -G 0 only returns IPv6 when you have a routable IPv6 address
-
-Revision 1.308  2006/11/30 23:07:56  herscher
-<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
-
-Revision 1.307  2006/11/18 05:01:30  cheshire
-Preliminary support for unifying the uDNS and mDNS code,
-including caching of uDNS answers
-
-Revision 1.306  2006/11/10 07:44:04  herscher
-<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
-
-Revision 1.305  2006/11/10 00:54:15  cheshire
-<rdar://problem/4816598> Changing case of Computer Name doesn't work
-
-Revision 1.304  2006/10/20 05:35:05  herscher
-<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
-
-Revision 1.303  2006/10/04 21:37:33  herscher
-Remove uDNS_info substructure from DNSQuestion_struct
-
-Revision 1.302  2006/09/26 01:53:25  herscher
-<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
-
-Revision 1.301  2006/09/15 21:20:15  cheshire
-Remove uDNS_info substructure from mDNS_struct
-
-Revision 1.300  2006/08/14 23:24:23  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.299  2006/07/15 02:01:28  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Fix broken "empty string" browsing
-
-Revision 1.298  2006/07/05 22:55:03  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Need Private field in uDNS_RegInfo
-
-Revision 1.297  2006/07/05 22:20:03  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-
-Revision 1.296  2006/06/29 05:28:01  cheshire
-Added comment about mDNSlocal and mDNSexport
-
-Revision 1.295  2006/06/29 03:02:43  cheshire
-<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
-
-Revision 1.294  2006/06/28 06:50:08  cheshire
-In future we may want to change definition of mDNSs32 from "signed long" to "signed int"
-I doubt anyone is building mDNSResponder on systems where int is 16-bits,
-but lets add a compile-time assertion to make sure.
-
-Revision 1.293  2006/06/12 18:00:43  cheshire
-To make code a little more defensive, check _ILP64 before _LP64,
-in case both are set by mistake on some platforms
-
-Revision 1.292  2006/03/19 17:00:57  cheshire
-Define symbol MaxMsg instead of using hard-coded constant value '80'
-
-Revision 1.291  2006/03/19 02:00:07  cheshire
-<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-
-Revision 1.290  2006/03/08 22:42:23  cheshire
-Fix spelling mistake: LocalReverseMapomain -> LocalReverseMapDomain
-
-Revision 1.289  2006/02/26 00:54:41  cheshire
-Fixes to avoid code generation warning/error on FreeBSD 7
-
-*/
+ */
 
 #ifndef __mDNSClientAPI_h
 #define __mDNSClientAPI_h
@@ -1219,6 +276,12 @@ typedef mDNSOpaque32  mDNSv4Addr;         // An IP address is a four-byte opaque identi
 typedef mDNSOpaque128 mDNSv6Addr;              // An IPv6 address is a 16-byte opaque identifier (not an integer)
 typedef mDNSOpaque48  mDNSEthAddr;             // An Ethernet address is a six-byte opaque identifier (not an integer)
 
+// Bit operations for opaque 64 bit quantity. Uses the 32 bit quantity(l[2]) to set and clear bits
+#define mDNSNBBY 8
+#define bit_set_opaque64(op64, index) (op64.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] |= (1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY))))
+#define bit_clr_opaque64(op64, index) (op64.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] &= ~(1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY))))
+#define bit_get_opaque64(op64, index) (op64.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] & (1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY))))
+
 enum
        {
        mDNSAddrType_None    = 0,
@@ -1305,7 +368,8 @@ typedef mDNSs32 mStatus;
 #define MAX_DOMAIN_LABEL 63
 typedef struct { mDNSu8 c[ 64]; } domainlabel;         // One label: length byte and up to 63 characters
 
-// RFC 1034/1035/2181 specify that a domain name, including length bytes, data bytes, and terminating zero, may be up to 256 bytes long
+// RFC 1034/1035/2181 specify that a domain name (length bytes and data bytes) may be up to 255 bytes long,
+// plus the terminating zero at the end makes 256 bytes total in the on-the-wire format.
 #define MAX_DOMAIN_NAME 256
 typedef struct { mDNSu8 c[256]; } domainname;          // Up to 256 bytes of length-prefixed domainlabels
 
@@ -1342,6 +406,18 @@ typedef struct { mDNSu8 c[256]; } UTF8str255;             // Null-terminated C string
 #define kStandardTTL (3600UL * 100 / 80)
 #define kHostNameTTL 120UL
 
+// Multicast DNS uses announcements (gratuitous responses) to update peer caches.
+// This means it is feasible to use relatively larger TTL values than we might otherwise
+// use, because we have a cache coherency protocol to keep the peer caches up to date.
+// With Unicast DNS, once an authoritative server gives a record with a certain TTL value to a client
+// or caching server, that client or caching server is entitled to hold onto the record until its TTL
+// expires, and has no obligation to contact the authoritative server again until that time arrives.
+// This means that whereas Multicast DNS can use announcements to pre-emptively update stale data
+// before it would otherwise have expired, standard Unicast DNS (not using LLQs) has no equivalent
+// mechanism, and TTL expiry is the *only* mechanism by which stale data gets deleted. Because of this,
+// we currently limit the TTL to ten seconds in such cases where no dynamic cache updating is possible.
+#define kStaticCacheTTL 10
+
 #define DefaultTTLforRRType(X) (((X) == kDNSType_A || (X) == kDNSType_AAAA || (X) == kDNSType_SRV) ? kHostNameTTL : kStandardTTL)
 
 typedef struct AuthRecord_struct AuthRecord;
@@ -1397,10 +473,10 @@ typedef struct tcpInfo_t
        DNSMessage        request;
        int               requestLen;
        DNSQuestion      *question;   // For queries
-       ServiceRecordSet *srs;        // For service record updates
        AuthRecord       *rr;         // For record updates
        mDNSAddr          Addr;
        mDNSIPPort        Port;
+       mDNSIPPort        SrcPort;
        DNSMessage       *reply;
        mDNSu16           replylen;
        unsigned long     nread;
@@ -1441,7 +517,7 @@ typedef packedstruct
        mDNSOpaque16 id;
        mDNSOpaque16 flagsfrags;
        mDNSu8       ttl;
-       mDNSu8       protocol;
+       mDNSu8       protocol;  // Payload type: 0x06 = TCP, 0x11 = UDP
        mDNSu16      checksum;
        mDNSv4Addr   src;
        mDNSv4Addr   dst;
@@ -1451,7 +527,7 @@ typedef packedstruct
        {
        mDNSu32      vcf;               // Version, Traffic Class, Flow Label
        mDNSu16      len;               // Payload Length
-       mDNSu8       protocol;  // Type of next header: 0x06 = TCP, 0x11 = UDP, 0x3A = ICMPv6
+       mDNSu8       pro;               // Type of next header: 0x06 = TCP, 0x11 = UDP, 0x3A = ICMPv6
        mDNSu8       ttl;               // Hop Limit
        mDNSv6Addr   src;
        mDNSv6Addr   dst;
@@ -1459,20 +535,68 @@ typedef packedstruct
 
 typedef packedstruct
        {
-       mDNSu8       type;              // 0x87 == Neighbor Solicitation, 0x88 == Neighbor Advertisement
-       mDNSu8       code;
+       mDNSv6Addr   src;
+       mDNSv6Addr   dst;
+       mDNSOpaque32 len;
+       mDNSOpaque32 pro;
+       } IPv6PseudoHeader;             // 40 bytes
+
+typedef union
+       {
+       mDNSu8       bytes[20];
+       ARP_EthIP    arp;
+       IPv4Header   v4;
+       IPv6Header   v6;
+       } NetworkLayerPacket;
+
+typedef packedstruct
+       {
+       mDNSIPPort   src;
+       mDNSIPPort   dst;
+       mDNSu32      seq;
+       mDNSu32      ack;
+       mDNSu8       offset;
+       mDNSu8       flags;
+       mDNSu16      window;
        mDNSu16      checksum;
-       mDNSu32      reserved;
-       mDNSv6Addr   target;
-       } IPv6ND;                               // 24 bytes
+       mDNSu16      urgent;
+       } TCPHeader;                    // 20 bytes; IP protocol type 0x06
 
 typedef packedstruct
        {
        mDNSIPPort   src;
        mDNSIPPort   dst;
-       mDNSu16      len;               // Length including UDP header (ie. minimum value is 8 bytes)
+       mDNSu16      len;               // Length including UDP header (i.e. minimum value is 8 bytes)
        mDNSu16      checksum;
-       } UDPHeader;                    // 8 bytes
+       } UDPHeader;                    // 8 bytes; IP protocol type 0x11
+
+typedef packedstruct
+       {
+       mDNSu8       type;              // 0x87 == Neighbor Solicitation, 0x88 == Neighbor Advertisement
+       mDNSu8       code;
+       mDNSu16      checksum;
+       mDNSu32      flags_res; // R/S/O flags and reserved bits
+       mDNSv6Addr   target;
+       // Typically 8 bytes of options are also present
+       } IPv6NDP;                              // 24 bytes or more; IP protocol type 0x3A
+
+#define NDP_Sol 0x87
+#define NDP_Adv 0x88
+
+#define NDP_Router    0x80
+#define NDP_Solicited 0x40
+#define NDP_Override  0x20
+
+#define NDP_SrcLL 1
+#define NDP_TgtLL 2
+
+typedef union
+       {
+       mDNSu8       bytes[20];
+       TCPHeader    tcp;
+       UDPHeader    udp;
+       IPv6NDP      ndp;
+       } TransportLayerPacket;
 
 typedef packedstruct
        {
@@ -1486,19 +610,6 @@ typedef packedstruct
        mDNSu32      Length;
        } IKEHeader;                    // 28 bytes
 
-typedef packedstruct
-       {
-       mDNSIPPort   src;
-       mDNSIPPort   dst;
-       mDNSu32      seq;
-       mDNSu32      ack;
-       mDNSu8       offset;
-       mDNSu8       flags;
-       mDNSu16      window;
-       mDNSu16      checksum;
-       mDNSu16      urgent;
-       } TCPHeader;                    // 20 bytes
-
 // ***************************************************************************
 #if 0
 #pragma mark -
@@ -1572,7 +683,9 @@ enum
        kDNSRecordTypeKnownUnique      = 0x20,  // Known Unique means mDNS can assume name is unique without checking
                                                // For Dynamic Update records, Known Unique means the record must already exist on the server.
        kDNSRecordTypeUniqueMask       = (kDNSRecordTypeUnique | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique),
-       kDNSRecordTypeActiveMask       = (kDNSRecordTypeAdvisory | kDNSRecordTypeShared | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique),
+       kDNSRecordTypeActiveSharedMask = (kDNSRecordTypeAdvisory         | kDNSRecordTypeShared),
+       kDNSRecordTypeActiveUniqueMask = (kDNSRecordTypeVerified         | kDNSRecordTypeKnownUnique),
+       kDNSRecordTypeActiveMask       = (kDNSRecordTypeActiveSharedMask | kDNSRecordTypeActiveUniqueMask),
 
        kDNSRecordTypePacketAdd        = 0x80,  // Received in the Additional  Section of a DNS Response
        kDNSRecordTypePacketAddUnique  = 0x90,  // Received in the Additional  Section of a DNS Response with kDNSClass_UniqueRRSet set
@@ -1583,7 +696,7 @@ enum
 
        kDNSRecordTypePacketNegative   = 0xF0,  // Pseudo-RR generated to cache non-existence results like NXDomain
 
-       kDNSRecordTypePacketUniqueMask = 0x10   // True for PacketAddUnique, PacketAnsUnique, PacketAuthUnique
+       kDNSRecordTypePacketUniqueMask = 0x10   // True for PacketAddUnique, PacketAnsUnique, PacketAuthUnique, kDNSRecordTypePacketNegative
        };
 
 typedef packedstruct { mDNSu16 priority; mDNSu16 weight; mDNSIPPort port; domainname target;   } rdataSRV;
@@ -1656,10 +769,6 @@ typedef packedstruct
                                                                (X) == DNSOpt_OwnerData_ID_Wake_PW4_Space - 4 || \
                                                                (X) == DNSOpt_OwnerData_ID_Wake_PW6_Space - 4    )
 
-#define ValidDNSOpt(O) (((O)->opt == kDNSOpt_LLQ   && (O)->optlen == DNSOpt_LLQData_Space   - 4) || \
-                                               ((O)->opt == kDNSOpt_Lease && (O)->optlen == DNSOpt_LeaseData_Space - 4) || \
-                                               ((O)->opt == kDNSOpt_Owner && ValidOwnerLength((O)->optlen)            )    )
-
 #define DNSOpt_Owner_Space(A,B) (mDNSSameEthAddress((A),(B)) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space)
 
 #define DNSOpt_Data_Space(O) (                                  \
@@ -1700,15 +809,15 @@ typedef struct
 // On 64-bit, the pointers in a CacheRecord are bigger, and that creates 8 bytes more space for the name in a CacheGroup
 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
        #if defined(_ILP64) || defined(__ILP64__) || defined(_LP64) || defined(__LP64__) || defined(_WIN64)
-       #define InlineCacheGroupNameSize 152
+       #define InlineCacheGroupNameSize 160
        #else
-       #define InlineCacheGroupNameSize 144
+       #define InlineCacheGroupNameSize 148
        #endif
 #else
        #if defined(_ILP64) || defined(__ILP64__) || defined(_LP64) || defined(__LP64__) || defined(_WIN64)
-       #define InlineCacheGroupNameSize 136
+       #define InlineCacheGroupNameSize 144
        #else
-       #define InlineCacheGroupNameSize 128
+       #define InlineCacheGroupNameSize 132
        #endif
 #endif
 
@@ -1768,7 +877,7 @@ typedef void mDNSRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus res
 // Restrictions: An mDNSRecordUpdateCallback may not make any mDNS API calls.
 // The intent of this callback is to allow the client to free memory, if necessary.
 // 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);
+typedef void mDNSRecordUpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData, mDNSu16 OldRDLen);
 
 // ***************************************************************************
 #if 0
@@ -1860,9 +969,9 @@ struct tcpLNTInfo_struct
        LNTOp_t           op;                           // operation performed using this connection
        mDNSAddr          Address;                      // router address
        mDNSIPPort        Port;                         // router port
-       mDNSs8           *Request;                      // xml request to router
+       mDNSu8           *Request;                      // xml request to router
        int               requestLen;
-       mDNSs8           *Reply;                        // xml reply from router
+       mDNSu8           *Reply;                        // xml reply from router
        int               replyLen;
        unsigned long     nread;                        // number of bytes read so far
        int               retries;                      // number of times we've tried to do this port mapping
@@ -1913,6 +1022,36 @@ struct NATTraversalInfo_struct
        void                       *clientContext;
        };
 
+enum
+       {
+       DNSServer_Untested = 0,
+       DNSServer_Passed   = 1,
+       DNSServer_Failed   = 2,
+       DNSServer_Disabled = 3
+       };
+
+enum
+       {
+       DNSServer_FlagDelete = 1,
+       DNSServer_FlagNew    = 2
+       };
+
+typedef struct DNSServer
+       {
+       struct DNSServer *next;
+       mDNSInterfaceID interface;      // For specialized uses; we can have DNS servers reachable over specific interfaces
+       mDNSAddr        addr;
+       mDNSIPPort      port;
+       mDNSOpaque16    testid;
+       mDNSu32         flags;          // Set when we're planning to delete this from the list
+       mDNSu32         teststate;      // Have we sent bug-detection query to this server?
+       mDNSs32         lasttest;       // Time we sent last bug-detection query to this server
+       domainname      domain;         // name->server matching for "split dns"
+       mDNSs32                 penaltyTime; // amount of time this server is penalized
+       mDNSBool                scoped;         // interface should be matched against question only
+                                                               // if scoped is set
+       } DNSServer;
+
 typedef struct                                                 // Size is 36 bytes when compiling for 32-bit; 48 when compiling for 64-bit
        {
        mDNSu8           RecordType;            // See enum above
@@ -1938,24 +1077,22 @@ typedef struct                                                  // Size is 36 bytes when compiling for 32-bit; 48 when comp
                                                                                // that are interface-specific (e.g. address records, especially linklocal addresses)
        const domainname *name;
        RData           *rdata;                         // Pointer to storage for this rdata
+       DNSServer       *rDNSServer;            // Unicast DNS server authoritative for this entry;null for multicast
        } ResourceRecord;
 
 // Unless otherwise noted, states may apply to either independent record registrations or service registrations
 typedef enum
        {
        regState_Zero              = 0,
-       regState_FetchingZoneData  = 1,     // getting info - update not sent
-       regState_Pending           = 2,     // update sent, reply not received
-       regState_Registered        = 3,     // update sent, reply received
-       regState_DeregPending      = 4,     // dereg sent, reply not received
-       regState_DeregDeferred     = 5,     // dereg requested while in Pending state - send dereg AFTER registration is confirmed
-       regState_Unregistered      = 8,     // not in any list
-       regState_Refresh           = 9,     // outstanding refresh (or target change) message
-       regState_NATMap            = 10,    // establishing NAT port mapping (service registrations only)
-       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_NATError          = 14     // unable to complete NAT traversal
+       regState_Pending           = 1,     // update sent, reply not received
+       regState_Registered        = 2,     // update sent, reply received
+       regState_DeregPending      = 3,     // dereg sent, reply not received
+       regState_Unregistered      = 4,     // not in any list
+       regState_Refresh           = 5,     // outstanding refresh (or target change) message
+       regState_NATMap            = 6,     // establishing NAT port mapping 
+       regState_UpdatePending     = 7,     // update in flight as result of mDNS_Update call
+       regState_NoTarget          = 8,     // SRV Record registration pending registration of hostname 
+       regState_NATError          = 9     // unable to complete NAT traversal
        } regState_t;
 
 enum
@@ -1965,6 +1102,12 @@ enum
        Target_AutoHostAndNATMAP = 2
        };
 
+typedef enum
+       {
+       mergeState_Zero = 0,
+       mergeState_DontMerge = 1  // Set on fatal error conditions to disable merging
+       } mergeState_t;
+
 struct AuthRecord_struct
        {
        // For examples of how to set up this structure for use in mDNS_Register(),
@@ -1987,11 +1130,10 @@ 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
 
-       OwnerOptData    WakeUp;                         // Fpr Sleep Proxy records, MAC address of original owner (so we can wake it)
+       OwnerOptData    WakeUp;                         // WakeUp.HMAC.l[0] nonzero indicates that this is a Sleep Proxy record
        mDNSAddr        AddressProxy;           // For reverse-mapping Sleep Proxy PTR records, address in question
        mDNSs32         TimeRcvd;                       // In platform time units
        mDNSs32         TimeExpire;                     // In platform time units
-       
 
        // Field Group 3: Transient state for Authoritative Records
        mDNSu8          Acknowledged;           // Set if we've given the success callback to the client
@@ -2034,15 +1176,17 @@ struct AuthRecord_struct
        mDNSBool     Private;           // If zone is private, DNS updates may have to be encrypted to prevent eavesdropping
        mDNSOpaque16 updateid;          // Identifier to match update request and response -- also used when transferring records to Sleep Proxy
        const domainname *zone;         // the zone that is updated
-       mDNSAddr     UpdateServer;      // DNS server that handles updates for this zone
-       mDNSIPPort   UpdatePort;        // port on which server accepts dynamic updates
-                                                               // !!!KRS not technically correct to cache longer than TTL
-                                                               // SDC Perhaps should keep a reference to the relevant SRV record in the cache?
        ZoneData  *nta;
        struct tcpInfo_t *tcp;
+       NATTraversalInfo  NATinfo;
+       mDNSBool SRVChanged;       // temporarily deregistered service because its SRV target or port changed
+       mergeState_t  mState;      // Unicast Record Registrations merge state
+       mDNSu8            refreshCount; // Number of refreshes to the server
+       mStatus           updateError;  // Record update resulted in Error ?
 
        // uDNS_UpdateRecord support fields
        // Do we really need all these in *addition* to NewRData and newrdlength above?
+       void *UpdateContext;    // Context parameter for the update callback function
        mDNSu16 OrigRDLen;              // previously registered, being deleted
        mDNSu16 InFlightRDLen;  // currently being registered
        mDNSu16 QueuedRDLen;    // pending operation (re-transmitting if necessary) THEN register the queued update
@@ -2058,8 +1202,27 @@ struct AuthRecord_struct
        // DO NOT ADD ANY MORE FIELDS HERE
        };
 
+// IsLocalDomain alone is not sufficient to determine that a record is mDNS or uDNS. By default domain names within
+// the "local" pseudo-TLD (and within the IPv4 and IPv6 link-local reverse mapping domains) are automatically treated
+// as mDNS records, but it is also possible to force any record (even those not within one of the inherently local
+// domains) to be handled as an mDNS record by setting the ForceMCast flag, or by setting a non-zero InterfaceID.
+// For example, the reverse-mapping PTR record created in AdvertiseInterface sets the ForceMCast flag, since it points to
+// a dot-local hostname, and therefore it would make no sense to register this record with a wide-area Unicast DNS server.
+// The same applies to Sleep Proxy records, which we will answer for when queried via mDNS, but we never want to try
+// to register them with a wide-area Unicast DNS server -- and we probably don't have the required credentials anyway.
+// Currently we have no concept of a wide-area uDNS record scoped to a particular interface, so if the InterfaceID is
+// nonzero we treat this the same as ForceMCast.
+// Note: Question_uDNS(Q) is used in *only* one place -- on entry to mDNS_StartQuery_internal, to decide whether to set TargetQID.
+// Everywhere else in the code, the determination of whether a question is unicast is made by checking to see if TargetQID is nonzero.
 #define AuthRecord_uDNS(R) ((R)->resrec.InterfaceID == mDNSInterface_Any && !(R)->ForceMCast && !IsLocalDomain((R)->resrec.name))
-#define Question_uDNS(Q)   ((Q)->InterfaceID == mDNSInterface_Any        && !(Q)->ForceMCast && !IsLocalDomain(&(Q)->qname))
+#define Question_uDNS(Q)   ((Q)->InterfaceID == mDNSInterface_Unicast || \
+       ((Q)->InterfaceID != mDNSInterface_LocalOnly && (Q)->InterfaceID != mDNSInterface_P2P && !(Q)->ForceMCast && !IsLocalDomain(&(Q)->qname)))
+
+// Question (A or AAAA) that is suppressed currently because IPv4 or IPv6 address
+// is not available locally for A or AAAA question respectively
+#define QuerySuppressed(Q) ((Q)->SuppressUnusable && (Q)->SuppressQuery)
+
+#define PrivateQuery(Q) ((Q)->AuthInfo && (Q)->AuthInfo->AutoTunnel)
 
 // Wrapper struct for Auth Records for higher-level code that cannot use the AuthRecord's ->next pointer field
 typedef struct ARListElem
@@ -2090,7 +1253,7 @@ struct CacheRecord_struct
        mDNSs32         DelayDelivery;          // Set if we want to defer delivery of this answer to local clients
        mDNSs32         NextRequiredQuery;      // In platform time units
        mDNSs32         LastUsed;                       // In platform time units
-       DNSQuestion    *CRActiveQuestion;       // Points to an active question referencing this answer
+       DNSQuestion    *CRActiveQuestion;       // Points to an active question referencing this answer. Can never point to a NewQuestion.
        mDNSu32         UnansweredQueries;      // Number of times we've issued a query for this record without getting an answer
        mDNSs32         LastUnansweredTime;     // In platform time units; last time we incremented UnansweredQueries
 #if ENABLE_MULTI_PACKET_QUERY_SNOOPING
@@ -2127,34 +1290,6 @@ typedef struct HostnameInfo
        const void *StatusContext;                // Client Context
        } HostnameInfo;
 
-enum
-       {
-       DNSServer_Untested = 0,
-       DNSServer_Passed   = 1,
-       DNSServer_Failed   = 2,
-       DNSServer_Disabled = 3
-       };
-
-enum
-       {
-       DNSServer_FlagDelete = 1,
-       DNSServer_FlagNew    = 2
-       };
-
-typedef struct DNSServer
-       {
-       struct DNSServer *next;
-       mDNSInterfaceID interface;      // For specialized uses; we can have DNS servers reachable over specific interfaces
-       mDNSAddr        addr;
-       mDNSIPPort      port;
-       mDNSOpaque16    testid;
-       mDNSu32         flags;          // Set when we're planning to delete this from the list
-       mDNSu32         teststate;      // Have we sent bug-detection query to this server?
-       mDNSs32         lasttest;       // Time we sent last bug-detection query to this server
-       domainname      domain;         // name->server matching for "split dns"
-       mDNSs32                 penaltyTime; // amount of time this server is penalized                 
-       } DNSServer;
-
 typedef struct ExtraResourceRecord_struct ExtraResourceRecord;
 struct ExtraResourceRecord_struct
        {
@@ -2169,49 +1304,21 @@ struct ExtraResourceRecord_struct
 // Note: Within an mDNSServiceCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute()
 typedef void mDNSServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result);
 
-// A ServiceRecordSet is basically a convenience structure to group together
-// the PTR/SRV/TXT records that make up a standard service registration
-// It contains its own ServiceCallback+ServiceContext to report aggregate results up to the next layer of software above
+// A ServiceRecordSet has no special meaning to the core code of the Multicast DNS protocol engine;
+// it is just a convenience structure to group together the records that make up a standard service
+// registration so that they can be allocted and deallocted together as a single memory object.
+// It contains its own ServiceCallback+ServiceContext to report aggregate results up to the next layer of software above.
 // It also contains:
+//  * the basic PTR/SRV/TXT triplet used to represent any DNS-SD service
 //  * the "_services" PTR record for service enumeration
-//  * the optional target host name (for proxy registrations)
 //  * the optional list of SubType PTR records
 //  * the optional list of additional records attached to the service set (e.g. iChat pictures)
-//
-// ... and a bunch of stuff related to uDNS, some of which could be simplified or eliminated
 
 struct ServiceRecordSet_struct
        {
        // These internal state fields are used internally by mDNSCore; the client layer needn't be concerned with them.
        // No fields need to be set up by the client prior to calling mDNS_RegisterService();
        // all required data is passed as parameters to that function.
-
-       // Begin uDNS info ****************
-       // All of these fields should be eliminated
-
-       // Note: The current uDNS code keeps an explicit list of registered services, and handles them
-       // differently to how individual records are treated (this is probably a mistake). What this means is
-       // that ServiceRecordSets for uDNS are kept in a linked list, whereas ServiceRecordSets for mDNS exist
-       // just as a convenient placeholder to group the component records together and are not kept on any list.
-       ServiceRecordSet *uDNS_next;
-       regState_t        state;
-       mDNSBool          srs_uselease;                         // dynamic update contains (should contain) lease option
-       mDNSBool          TestForSelfConflict;          // on name conflict, check if we're just seeing our own orphaned records
-       mDNSBool          Private;                                      // If zone is private, DNS updates may have to be encrypted to prevent eavesdropping
-       ZoneData         *srs_nta;
-       mDNSOpaque16      id;
-       domainname        zone;                                         // the zone that is updated
-       mDNSAddr          SRSUpdateServer;                      // primary name server for the record's zone  !!!KRS not technically correct to cache longer than TTL
-       mDNSIPPort        SRSUpdatePort;                        // port on which server accepts dynamic updates
-       NATTraversalInfo  NATinfo;
-       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          SRVChanged;                           // temporarily deregistered service because its SRV target or port changed
-       struct tcpInfo_t *tcp;
-
-       // End uDNS info ****************
-
        mDNSServiceCallback *ServiceCallback;
        void                *ServiceContext;
        mDNSBool             Conflict;  // Set if this record set was forcibly deregistered because of a conflict
@@ -2234,7 +1341,7 @@ struct ServiceRecordSet_struct
 #endif
 
 // We record the last eight instances of each duplicate query
-// This gives us v4/v6 on each of Ethernet/AirPort and Firewire, and two free slots "for future expansion"
+// This gives us v4/v6 on each of EthernetAirPort and Firewire, and two free slots "for future expansion"
 // If the host has more active interfaces that this it is not fatal -- duplicate question suppression will degrade gracefully.
 // Since we will still remember the last eight, the busiest interfaces will still get the effective duplicate question suppression.
 #define DupSuppressInfoSize 8
@@ -2286,7 +1393,8 @@ enum { NoAnswer_Normal = 0, NoAnswer_Suspended = 1, NoAnswer_Fail = 2 };
 #define AutoTunnelUnregistered(X) (                                              \
        (X)->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered && \
        (X)->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered && \
-       (X)->AutoTunnelService.   resrec.RecordType == kDNSRecordTypeUnregistered    )
+       (X)->AutoTunnelService.   resrec.RecordType == kDNSRecordTypeUnregistered && \
+       (X)->AutoTunnel6Record.   resrec.RecordType == kDNSRecordTypeUnregistered    )
 
 // Internal data structure to maintain authentication information
 typedef struct DomainAuthInfo
@@ -2298,6 +1406,7 @@ typedef struct DomainAuthInfo
        AuthRecord       AutoTunnelTarget;              // Opaque hostname of tunnel endpoint; used as SRV target for AutoTunnelService record
        AuthRecord       AutoTunnelDeviceInfo;  // Device info of tunnel endpoint
        AuthRecord       AutoTunnelService;             // Service record (possibly NAT-Mapped) of IKE daemon implementing tunnel endpoint
+       AuthRecord       AutoTunnel6Record;     // AutoTunnel AAAA Record obtained from Connectivityd
        NATTraversalInfo AutoTunnelNAT;
        domainname       domain;
        domainname       keyname;
@@ -2309,6 +1418,11 @@ typedef struct DomainAuthInfo
 // Note: Within an mDNSQuestionCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute()
 typedef enum { QC_rmv = 0, QC_add = 1, QC_addnocache = 2 } QC_result;
 typedef void mDNSQuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
+
+#define NextQSendTime(Q)  ((Q)->LastQTime + (Q)->ThisQInterval)
+#define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
+#define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - NextQSendTime(Q) >= 0)
+
 struct DNSQuestion_struct
        {
        // Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
@@ -2337,16 +1451,23 @@ struct DNSQuestion_struct
        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
        mDNSu32               CNAMEReferrals;   // Count of how many CNAME redirections we've done
+       mDNSBool              SuppressQuery;    // This query should be suppressed and not sent on the wire 
 
        // Wide Area fields. These are used internally by the uDNS core
        UDPSocket            *LocalSocket;
+       mDNSBool             deliverAddEvents;  // Change in DNSSserver requiring to deliver ADD events
        DNSServer            *qDNSServer;               // Caching server for this query (in the absence of an SRV saying otherwise)
+       mDNSOpaque64          validDNSServers;  // Valid DNSServers for this question
+       mDNSu16              noServerResponse;  // At least one server did not respond.
+       mDNSu16              triedAllServersOnce; // Tried all DNS servers once
        mDNSu8                unansweredQueries;// The number of unanswered queries to this server
 
        ZoneData             *nta;                              // Used for getting zone data for private or LLQ query
        mDNSAddr              servAddr;                 // Address and port learned from _dns-llq, _dns-llq-tls or _dns-query-tls SRV query
        mDNSIPPort            servPort;
        struct tcpInfo_t *tcp;
+       mDNSIPPort            tcpSrcPort;               // Local Port TCP packet received on;need this as tcp struct is disposed
+                                                                                       // by tcpCallback before calling into mDNSCoreReceive
        mDNSu8                NoAnswer;                 // Set if we want to suppress answers until tunnel setup has completed
 
        // LLQ-specific fields. These fields are only meaningful when LongLived flag is set
@@ -2371,6 +1492,7 @@ struct DNSQuestion_struct
        mDNSBool              ExpectUnique;             // Set by client if it's expecting unique RR(s) for this question, not shared RRs
        mDNSBool              ForceMCast;               // Set by client to force mDNS query, even for apparently uDNS names
        mDNSBool              ReturnIntermed;   // Set by client to request callbacks for intermediate CNAME/NXDOMAIN results
+       mDNSBool              SuppressUnusable; // Set by client to suppress unusable queries to be sent on the wire
        mDNSQuestionCallback *QuestionCallback;
        void                 *QuestionContext;
        };
@@ -2442,6 +1564,12 @@ typedef struct DNameListElem
        } DNameListElem;
 
 #if APPLE_OSX_mDNSResponder
+// Different states that we go through locating the peer
+#define TC_STATE_AAAA_PEER                     0x000000001             /* Peer's BTMM IPv6 address */
+#define TC_STATE_AAAA_PEER_RELAY       0x000000002             /* Peer's IPv6 Relay address */
+#define TC_STATE_SRV_PEER                      0x000000003             /* Peer's SRV Record corresponding to IPv4 address */
+#define TC_STATE_ADDR_PEER                     0x000000004             /* Peer's IPv4 address */
+
 typedef struct ClientTunnel
        {
        struct ClientTunnel *next;
@@ -2449,9 +1577,12 @@ typedef struct ClientTunnel
        mDNSBool   MarkedForDeletion;
        mDNSv6Addr loc_inner;
        mDNSv4Addr loc_outer;
+       mDNSv6Addr loc_outer6;
        mDNSv6Addr rmt_inner;
        mDNSv4Addr rmt_outer;
+       mDNSv6Addr rmt_outer6;
        mDNSIPPort rmt_outer_port;
+       mDNSu16 tc_state;
        DNSQuestion q;
        } ClientTunnel;
 #endif
@@ -2515,6 +1646,8 @@ typedef struct SearchListElem
        DNSQuestion AutomaticBrowseQ;
        DNSQuestion RegisterQ;
        DNSQuestion DefRegisterQ;
+       DNSQuestion DirQ;
+       int     numDirAnswers;
        ARListElem *AuthRecs;
        } SearchListElem;
 
@@ -2535,10 +1668,11 @@ typedef void mDNSCallback(mDNS *const m, mStatus result);
 
 #define CACHE_HASH_SLOTS 499
 
-enum
+enum           // Bit flags -- i.e. values should be 1, 2, 4, 8, etc.
        {
        mDNS_KnownBug_PhantomInterfaces = 1,
-       mDNS_KnownBug_LossySyslog       = 2             // <rdar://problem/6561888>
+       mDNS_KnownBug_LimitedIPv6       = 2,
+       mDNS_KnownBug_LossySyslog       = 4             // <rdar://problem/6561888>
        };
 
 enum
@@ -2584,7 +1718,7 @@ struct mDNS_struct
        mDNSs32  timenow_last;                          // The time the last time we ran
        mDNSs32  NextScheduledEvent;            // Derived from values below
        mDNSs32  ShutdownTime;                          // Set when we're shutting down; allows us to skip some unnecessary steps
-       mDNSs32  SuppressSending;                       // Don't send *any* packets during this time
+       mDNSs32  SuppressSending;                       // Don't send local-link mDNS packets during this time
        mDNSs32  NextCacheCheck;                        // Next time to refresh cache record before it expires
        mDNSs32  NextScheduledQuery;            // Next time to send query in its exponential backoff sequence
        mDNSs32  NextScheduledProbe;            // Next time to probe for new authoritative record
@@ -2594,10 +1728,12 @@ struct mDNS_struct
        mDNSs32  RandomQueryDelay;                      // For de-synchronization of query packets on the wire
        mDNSu32  RandomReconfirmDelay;          // For de-synchronization of reconfirmation queries on the wire
        mDNSs32  PktNum;                                        // Unique sequence number assigned to each received packet
+       mDNSu8   LocalRemoveEvents;                     // Set if we may need to deliver remove events for local-only questions and/or local-only records
        mDNSu8   SleepState;                            // Set if we're sleeping
        mDNSu8   SleepSeqNum;                           // "Epoch number" of our current period of wakefulness
        mDNSu8   SystemWakeOnLANEnabled;        // Set if we want to register with a Sleep Proxy before going to sleep
        mDNSu8   SentSleepProxyRegistration;// Set if we registered (or tried to register) with a Sleep Proxy
+       mDNSu8   SystemSleepOnlyIfWakeOnLAN;// Set if we may only sleep if we managed to register with a Sleep Proxy
        mDNSs32  AnnounceOwner;                         // After waking from sleep, include OWNER option in packets until this time
        mDNSs32  DelaySleep;                            // To inhibit re-sleeping too quickly right after wake
        mDNSs32  SleepLimit;                            // Time window to allow deregistrations, etc.,
@@ -2609,14 +1745,15 @@ struct mDNS_struct
        DNSQuestion *Questions;                         // List of all registered questions, active and inactive
        DNSQuestion *NewQuestions;                      // Fresh questions not yet answered from cache
        DNSQuestion *CurrentQuestion;           // Next question about to be examined in AnswerLocalQuestions()
-       DNSQuestion *LocalOnlyQuestions;        // Questions with InterfaceID set to mDNSInterface_LocalOnly
-       DNSQuestion *NewLocalOnlyQuestions;     // Fresh local-only questions not yet answered
+       DNSQuestion *LocalOnlyQuestions;        // Questions with InterfaceID set to mDNSInterface_LocalOnly or mDNSInterface_P2P
+       DNSQuestion *NewLocalOnlyQuestions;     // Fresh local-only or P2P questions not yet answered
        mDNSu32 rrcache_size;                           // Total number of available cache entries
        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;
        CacheEntity *rrcache_free;
        CacheGroup *rrcache_hash[CACHE_HASH_SLOTS];
+       mDNSs32  rrcache_nextcheck[CACHE_HASH_SLOTS];
 
        // Fields below only required for mDNS Responder...
        domainlabel nicelabel;                          // Rich text label encoded using canonically precomposed UTF-8
@@ -2627,7 +1764,7 @@ struct mDNS_struct
        AuthRecord  DeviceInfo;
        AuthRecord *ResourceRecords;
        AuthRecord *DuplicateRecords;           // Records currently 'on hold' because they are duplicates of existing records
-       AuthRecord *NewLocalRecords;            // Fresh local-only records not yet delivered to local-only questions
+       AuthRecord *NewLocalRecords;            // Fresh AuthRecords (both local-only and public) not yet delivered to our local-only questions
        AuthRecord *CurrentRecord;                      // Next AuthRecord about to be examined
        NetworkInterfaceInfo *HostInterfaces;
        mDNSs32 ProbeFailTime;
@@ -2637,9 +1774,7 @@ struct mDNS_struct
        // Unicast-specific data
        mDNSs32           NextuDNSEvent;                // uDNS next event
        mDNSs32           NextSRVUpdate;        // Time to perform delayed update
-       mDNSs32 SuppressStdPort53Queries;       // Wait before allowing the next standard unicast query to the user's configured DNS server
 
-       ServiceRecordSet *ServiceRegistrations;
        DNSServer        *DNSServers;           // list of DNS servers
 
        mDNSAddr          Router;
@@ -2655,9 +1790,11 @@ struct mDNS_struct
        HostnameInfo     *Hostnames;            // List of registered hostnames + hostname metadata
        mDNSv6Addr        AutoTunnelHostAddr;   // IPv6 address advertised for AutoTunnel services on this machine
        mDNSBool          AutoTunnelHostAddrActive;
+       mDNSv6Addr        AutoTunnelRelayAddr;  // IPv6 address advertised for AutoTunnel Relay services on this machine
        domainlabel       AutoTunnelLabel;              // Used to construct hostname for *IPv4* address of tunnel endpoints
 
        mDNSBool          RegisterSearchDomains;
+       mDNSBool          RegisterAutoTunnel6;
 
        // NAT-Traversal fields
        NATTraversalInfo  LLQNAT;                                       // Single shared NAT Traversal to receive inbound LLQ notifications
@@ -2702,6 +1839,7 @@ struct mDNS_struct
 #if APPLE_OSX_mDNSResponder
        ClientTunnel     *TunnelClients;
        uuid_t           asl_uuid;                                      // uuid for ASL logging
+       void                *WCF;
 #endif
 
        // Fixed storage, to avoid creating large objects on the stack
@@ -2722,21 +1860,11 @@ struct mDNS_struct
 #pragma mark - Useful Static Constants
 #endif
 
-extern const mDNSIPPort      zeroIPPort;
-extern const mDNSv4Addr      zerov4Addr;
-extern const mDNSv6Addr      zerov6Addr;
-extern const mDNSEthAddr     zeroEthAddr;
-extern const mDNSv4Addr      onesIPv4Addr;
-extern const mDNSv6Addr      onesIPv6Addr;
-extern const mDNSEthAddr     onesEthAddr;
-extern const mDNSAddr        zeroAddr;
-
-extern const OwnerOptData    zeroOwner;
-
 extern const mDNSInterfaceID mDNSInterface_Any;                                // Zero
 extern const mDNSInterfaceID mDNSInterface_LocalOnly;          // Special value
 extern const mDNSInterfaceID mDNSInterface_Unicast;                    // Special value
 extern const mDNSInterfaceID mDNSInterfaceMark;                                // Special value
+extern const mDNSInterfaceID mDNSInterface_P2P;                                // Special value
 
 extern const mDNSIPPort   DiscardPort;
 extern const mDNSIPPort   SSHPort;
@@ -2751,8 +1879,22 @@ extern const mDNSIPPort   MulticastDNSPort;
 extern const mDNSIPPort   LoopbackIPCPort;
 extern const mDNSIPPort   PrivateDNSPort;
 
+extern const OwnerOptData    zeroOwner;
+
+extern const mDNSIPPort      zeroIPPort;
+extern const mDNSv4Addr      zerov4Addr;
+extern const mDNSv6Addr      zerov6Addr;
+extern const mDNSEthAddr     zeroEthAddr;
+extern const mDNSv4Addr      onesIPv4Addr;
+extern const mDNSv6Addr      onesIPv6Addr;
+extern const mDNSEthAddr     onesEthAddr;
+extern const mDNSAddr        zeroAddr;
+
 extern const mDNSv4Addr   AllDNSAdminGroup;
-extern const mDNSv4Addr   AllSystemsMcast;
+extern const mDNSv4Addr   AllHosts_v4;
+extern const mDNSv6Addr   AllHosts_v6;
+extern const mDNSv6Addr   NDP_prefix;
+extern const mDNSEthAddr  AllHosts_v6_Eth;
 extern const mDNSAddr     AllDNSLinkGroup_v4;
 extern const mDNSAddr     AllDNSLinkGroup_v6;
 
@@ -2767,6 +1909,7 @@ extern const mDNSOpaque16 UpdateRespFlags;
 extern const mDNSOpaque64 zeroOpaque64;
 
 extern mDNSBool StrictUnicastOrdering;
+extern mDNSu8 NumUnicastDNSServers;
 
 #define localdomain           (*(const domainname *)"\x5" "local")
 #define DeviceInfoName        (*(const domainname *)"\xC" "_device-info" "\x4" "_tcp")
@@ -2887,7 +2030,7 @@ extern void    mDNS_GrowCache (mDNS *const m, CacheEntity *storage, mDNSu32 numr
 extern void    mDNS_StartExit (mDNS *const m);
 extern void    mDNS_FinalExit (mDNS *const m);
 #define mDNS_Close(m) do { mDNS_StartExit(m); mDNS_FinalExit(m); } while(0)
-#define mDNS_ExitNow(m, now) ((now) - (m)->ShutdownTime >= 0 || (!(m)->ResourceRecords && !(m)->ServiceRegistrations))
+#define mDNS_ExitNow(m, now) ((now) - (m)->ShutdownTime >= 0 || (!(m)->ResourceRecords))
 
 extern mDNSs32 mDNS_Execute   (mDNS *const m);
 
@@ -2910,6 +2053,8 @@ extern mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *travers
 
 extern DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const name);
 
+extern void    mDNS_UpdateAllowSleep(mDNS *const m);
+
 // ***************************************************************************
 #if 0
 #pragma mark -
@@ -2924,6 +2069,12 @@ extern mDNSs32  mDNSPlatformOneSecond;
 #pragma mark - General utility and helper functions
 #endif
 
+// mDNS_Dereg_normal is used for most calls to mDNS_Deregister_internal
+// mDNS_Dereg_rapid is used to send one goodbye instead of three, when we want the memory available for reuse sooner
+// mDNS_Dereg_conflict is used to indicate that this record is being forcibly deregistered because of a conflict
+// mDNS_Dereg_repeat is used when cleaning up, for records that may have already been forcibly deregistered
+typedef enum { mDNS_Dereg_normal, mDNS_Dereg_rapid, mDNS_Dereg_conflict, mDNS_Dereg_repeat } mDNS_Dereg_type;
+
 // mDNS_RegisterService is a single call to register the set of resource records associated with a given named service.
 //
 // mDNS_StartResolveService is single call which is equivalent to multiple calls to mDNS_StartQuery,
@@ -2957,7 +2108,8 @@ extern mStatus mDNS_RegisterService  (mDNS *const m, ServiceRecordSet *sr,
 extern mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl);
 extern mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, mDNSRecordCallback MemFreeCallback, void *Context);
 extern mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname);
-extern mStatus mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr);
+extern mStatus mDNS_DeregisterService_drt(mDNS *const m, ServiceRecordSet *sr, mDNS_Dereg_type drt);
+#define mDNS_DeregisterService(M,S) mDNS_DeregisterService_drt((M), (S), mDNS_Dereg_normal)
 
 extern mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr,
                const domainlabel *const name, const domainname *const type, const domainname *const domain,
@@ -2996,8 +2148,11 @@ extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainT
 #define        mDNS_StopAdvertiseDomains mDNS_Deregister
 
 extern mDNSOpaque16 mDNS_NewMessageID(mDNS *const m);
-               
-extern DNSServer *GetServerForName(mDNS *m, const domainname *name, DNSServer *current);
+extern mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr);
+
+extern DNSServer *GetServerForName(mDNS *m, const domainname *name, mDNSInterfaceID InterfaceID);
+extern DNSServer *GetServerForQuestion(mDNS *m, DNSQuestion *question);
+extern void SetValidDNSServers(mDNS *m, DNSQuestion *question);
 
 // ***************************************************************************
 #if 0
@@ -3022,6 +2177,7 @@ extern DNSServer *GetServerForName(mDNS *m, const domainname *name, DNSServer *c
 extern mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
 extern mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2);
 extern mDNSBool SameDomainNameCS(const domainname *const d1, const domainname *const d2);
+typedef mDNSBool DomainNameComparisonFn(const domainname *const d1, const domainname *const d2);
 extern mDNSBool IsLocalDomain(const domainname *d);     // returns true for domains that by default should be looked up using link-local multicast
 
 #define StripFirstLabel(X) ((const domainname *)&(X)->c[(X)->c[0] ? 1 + (X)->c[0] : 0])
@@ -3155,6 +2311,12 @@ extern mDNSBool mDNSv4AddrIsRFC1918(mDNSv4Addr *addr);  // returns true for RFC1
        ((X)->type == mDNSAddrType_IPv4) ? mDNSv4AddressIsLinkLocal(&(X)->ip.v4) :          \
        ((X)->type == mDNSAddrType_IPv6) ? mDNSv6AddressIsLinkLocal(&(X)->ip.v6) : mDNSfalse)
 
+#define mDNSv4AddressIsLoopback(X) ((X)->b[0] == 127 && (X)->b[1] == 0 && (X)->b[2] == 0 && (X)->b[3] == 1)
+#define mDNSv6AddressIsLoopback(X) ((((X)->l[0] | (X)->l[1] | (X)->l[2]) == 0) && ((X)->b[12] == 0 && (X)->b[13] == 0 && (X)->b[14] == 0 && (X)->b[15] == 1))
+
+#define mDNSAddressIsLoopback(X)  (                                                    \
+       ((X)->type == mDNSAddrType_IPv4) ? mDNSv4AddressIsLoopback(&(X)->ip.v4) :          \
+       ((X)->type == mDNSAddrType_IPv6) ? mDNSv6AddressIsLoopback(&(X)->ip.v6) : mDNSfalse)
 // ***************************************************************************
 #if 0
 #pragma mark -
@@ -3195,8 +2357,8 @@ extern void RecreateNATMappings(mDNS *const m);
 extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext);
 extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn);
 extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr,  const mDNSAddr *v6addr, const mDNSAddr *router);
-extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port);
-extern void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSBool QueryFail);
+extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped);
+extern void PenalizeDNSServer(mDNS *const m, DNSQuestion *q);
 extern void mDNS_AddSearchDomain(const domainname *const domain);
 
 // We use ((void *)0) here instead of mDNSNULL to avoid compile warnings on gcc 4.2
@@ -3345,8 +2507,8 @@ typedef void (*TCPConnectionCallback)(TCPSocket *sock, void *context, mDNSBool C
 extern TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port);        // creates a TCP socket
 extern TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd);
 extern int        mDNSPlatformTCPGetFD(TCPSocket *sock);
-extern mStatus    mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
-                                         TCPConnectionCallback callback, void *context);
+extern mStatus    mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname,
+                                                                               mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context);
 extern void       mDNSPlatformTCPCloseConnection(TCPSocket *sock);
 extern long       mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed);
 extern long       mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len);
@@ -3355,7 +2517,7 @@ extern void       mDNSPlatformUDPClose(UDPSocket *sock);
 extern void       mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd);
 extern void       mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID);
 extern void       mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID);
-extern void       mDNSPlatformSetLocalARP(const mDNSv4Addr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID);
+extern void       mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID);
 extern void       mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst);
 
 // mDNSPlatformTLSSetupCerts/mDNSPlatformTLSTearDownCerts used by dnsextd
@@ -3369,10 +2531,12 @@ extern void       mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, m
 extern mStatus    mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *router);
 extern void       mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status);
 
+extern void       mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep);
+
 #ifdef _LEGACY_NAT_TRAVERSAL_
 // Support for legacy NAT traversal protocols, implemented by the platform layer and callable by the core.
 extern void     LNT_SendDiscoveryMsg(mDNS *m);
-extern void     LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *data, mDNSu16 len);
+extern void     LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, const mDNSu8 *const data, const mDNSu16 len);
 extern mStatus  LNT_GetExternalAddress(mDNS *m);
 extern mStatus  LNT_MapPort(mDNS *m, NATTraversalInfo *n);
 extern mStatus  LNT_UnmapPort(mDNS *m, NATTraversalInfo *n);
@@ -3422,43 +2586,173 @@ extern void     mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
 extern void     mDNSCoreInitComplete(mDNS *const m, mStatus result);
 extern void     mDNSCoreReceive(mDNS *const m, void *const msg, const mDNSu8 *const end,
                                                                const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
-                                                               const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID);
+                                                               const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID);
 extern void    mDNSCoreRestartQueries(mDNS *const m);
 extern mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m);
 extern void     mDNSCoreMachineSleep(mDNS *const m, mDNSBool wake);
 extern mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now);
 extern mDNSs32  mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now);
 
-extern void     mDNSCoreBeSleepProxyServer(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower);
 extern void     mDNSCoreReceiveRawPacket  (mDNS *const m, const mDNSu8 *const p, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID);
 
 extern mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip);
 
-extern CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg);
+extern CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg, mDNSs32 delay);
+extern void ScheduleNextCacheCheckTime(mDNS *const m, const mDNSu32 slot, const mDNSs32 event);
 extern void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease);
 extern void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr,
-       const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds, mDNSInterfaceID InterfaceID);
+       const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds,
+       mDNSInterfaceID InterfaceID, DNSServer *dnsserver);
 extern void CompleteDeregistration(mDNS *const m, AuthRecord *rr);
-extern void FindSPSInCache(mDNS *const m, const DNSQuestion *const q, const CacheRecord *sps[3]);
-#define PrototypeSPSName(X) ((X)[0] >= 11 && (X)[3] == '-' && (X)[ 4] == '9' && (X)[ 5] == '9' && \
-                                             (X)[6] == '-' && (X)[ 7] == '9' && (X)[ 8] == '9' && \
-                                             (X)[9] == '-' && (X)[10] == '9' && (X)[11] == '9'    )
-#define ValidSPSName(X) ((X)[0] >= 5 && mDNSIsDigit((X)[1]) && mDNSIsDigit((X)[2]) && mDNSIsDigit((X)[4]) && mDNSIsDigit((X)[5]))
-#define SPSMetric(X) (!ValidSPSName(X) || PrototypeSPSName(X) ? 1000000 : \
-       ((X)[1]-'0') * 100000 + ((X)[2]-'0') * 10000 + ((X)[4]-'0') * 1000 + ((X)[5]-'0') * 100 + ((X)[7]-'0') * 10 + ((X)[8]-'0'))
 extern void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord);
 extern char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID);
+extern void DNSServerChangeForQuestion(mDNS *const m, DNSQuestion *q, DNSServer *new);
+extern void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr);
+extern void CheckSuppressUnusableQuestions(mDNS *const m);
 
 // For now this AutoTunnel stuff is specific to Mac OS X.
 // In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
 #if APPLE_OSX_mDNSResponder
 extern void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
 extern void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q);
-extern void SetupLocalAutoTunnelInterface_internal(mDNS *const m);
+extern void SetupLocalAutoTunnelInterface_internal(mDNS *const m, mDNSBool servicesStarting);
 extern void UpdateAutoTunnelDomainStatuses(const mDNS *const m);
 extern mStatus ActivateLocalProxy(mDNS *const m, char *ifname);
+extern void RemoveAutoTunnel6Record(mDNS *const m);
+extern void SetupConndConfigChanges(mDNS *const m);
+extern mDNSBool RecordReadyForSleep(mDNS *const m, AuthRecord *rr);
+#endif
+
+// ***************************************************************************
+#if 0
+#pragma mark -
+#pragma mark - Sleep Proxy
 #endif
 
+// Sleep Proxy Server Property Encoding
+//
+// Sleep Proxy Servers are advertised using a structured service name, consisting of four
+// metrics followed by a human-readable name. The metrics assist clients in deciding which
+// Sleep Proxy Server(s) to use when multiple are available on the network. Each metric
+// is a two-digit decimal number in the range 10-99. Lower metrics are generally better.
+//
+//   AA-BB-CC-DD Name
+//
+// Metrics:
+//
+// AA = Intent
+// BB = Portability
+// CC = Marginal Power
+// DD = Total Power
+//
+//
+// ** Intent Metric **
+//
+// 20 = Dedicated Sleep Proxy Server -- a device, permanently powered on,
+//      installed for the express purpose of providing Sleep Proxy Service.
+//
+// 30 = Primary Network Infrastructure Hardware -- a router, DHCP server, NAT gateway,
+//      or similar permanently installed device which is permanently powered on.
+//      This is hardware designed for the express purpose of being network
+//      infrastructure, and for most home users is typically a single point
+//      of failure for the local network -- e.g. most home users only have
+//      a single NAT gateway / DHCP server. Even though in principle the
+//      hardware might technically be capable of running different software,
+//      a typical user is unlikely to do that. e.g. AirPort base station.
+//
+// 40 = Primary Network Infrastructure Software -- a general-purpose computer
+//      (e.g. Mac, Windows, Linux, etc.) which is currently running DHCP server
+//      or NAT gateway software, but the user could choose to turn that off
+//      fairly easily. e.g. iMac running Internet Sharing
+//
+// 50 = Secondary Network Infrastructure Hardware -- like primary infrastructure
+//      hardware, except not a single point of failure for the entire local network.
+//      For example, an AirPort base station in bridge mode. This may have clients
+//      associated with it, and if it goes away those clients will be inconvenienced,
+//      but unlike the NAT gateway / DHCP server, the entire local network is not
+//      dependent on it.
+//
+// 60 = Secondary Network Infrastructure Software -- like 50, but in a general-
+//      purpose CPU.
+//
+// 70 = Incidentally Available Hardware -- a device which has no power switch
+//      and is generally left powered on all the time. Even though it is not a
+//      part of what we conventionally consider network infrastructure (router,
+//      DHCP, NAT, DNS, etc.), and the rest of the network can operate fine
+//      without it, since it's available and unlikely to be turned off, it is a
+//      reasonable candidate for providing Sleep Proxy Service e.g. Apple TV,
+//      or an AirPort base station in client mode, associated with an existing
+//      wireless network (e.g. AirPort Express connected to a music system, or
+//      being used to share a USB printer).
+//
+// 80 = Incidentally Available Software -- a general-purpose computer which
+//      happens at this time to be set to "never sleep", and as such could be
+//      useful as a Sleep Proxy Server, but has not been intentionally provided
+//      for this purpose. Of all the Intent Metric categories this is the
+//      one most likely to be shut down or put to sleep without warning.
+//      However, if nothing else is availalable, it may be better than nothing.
+//      e.g. Office computer in the workplace which has been set to "never sleep"
+//
+//
+// ** Portability Metric **
+//
+// Inversely related to mass of device, on the basis that, all other things
+// being equal, heavier devices are less likely to be moved than lighter devices.
+// E.g. A MacBook running Internet Sharing is probably more likely to be
+// put to sleep and taken away than a Mac Pro running Internet Sharing.
+// The Portability Metric is a logarithmic decibel scale, computed by taking the
+// (approximate) mass of the device in milligrammes, taking the base 10 logarithm
+// of that, multiplying by 10, and subtracting the result from 100:
+//
+//   Portability Metric = 100 - (log10(mg) * 10)
+//
+// The Portability Metric is not necessarily computed literally from the actual
+// mass of the device; the intent is just that lower numbers indicate more
+// permanent devices, and higher numbers indicate devices more likely to be
+// removed from the network, e.g., in order of increasing portability:
+//
+// Mac Pro < iMac < Laptop < iPhone
+//
+// Example values:
+//
+// 10 = 1 metric tonne
+// 40 = 1kg
+// 70 = 1g
+// 90 = 10mg
+//
+//
+// ** Marginal Power and Total Power Metrics **
+//
+// The Marginal Power Metric is the power difference between sleeping and staying awake
+// to be a Sleep Proxy Server.
+//
+// The Total Power Metric is the total power consumption when being Sleep Proxy Server.
+//
+// The Power Metrics use a logarithmic decibel scale, computed as ten times the
+// base 10 logarithm of the (approximate) power in microwatts:
+//
+//   Power Metric = log10(uW) * 10
+//
+// Higher values indicate higher power consumption. Example values:
+//
+// 10 =  10 uW
+// 20 = 100 uW
+// 30 =   1 mW
+// 60 =   1 W
+// 90 =   1 kW
+
+extern void mDNSCoreBeSleepProxyServer_internal(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower);
+#define mDNSCoreBeSleepProxyServer(M,S,P,MP,TP) \
+       do { mDNS_Lock(m); mDNSCoreBeSleepProxyServer_internal((M),(S),(P),(MP),(TP)); mDNS_Unlock(m); } while(0)
+
+extern void FindSPSInCache(mDNS *const m, const DNSQuestion *const q, const CacheRecord *sps[3]);
+#define PrototypeSPSName(X) ((X)[0] >= 11 && (X)[3] == '-' && (X)[ 4] == '9' && (X)[ 5] == '9' && \
+                                             (X)[6] == '-' && (X)[ 7] == '9' && (X)[ 8] == '9' && \
+                                             (X)[9] == '-' && (X)[10] == '9' && (X)[11] == '9'    )
+#define ValidSPSName(X) ((X)[0] >= 5 && mDNSIsDigit((X)[1]) && mDNSIsDigit((X)[2]) && mDNSIsDigit((X)[4]) && mDNSIsDigit((X)[5]))
+#define SPSMetric(X) (!ValidSPSName(X) || PrototypeSPSName(X) ? 1000000 : \
+       ((X)[1]-'0') * 100000 + ((X)[2]-'0') * 10000 + ((X)[4]-'0') * 1000 + ((X)[5]-'0') * 100 + ((X)[7]-'0') * 10 + ((X)[8]-'0'))
+
 // ***************************************************************************
 #if 0
 #pragma mark -
@@ -3494,7 +2788,7 @@ struct CompileTimeAssertionChecks_mDNS
        char assertG[(sizeof(ARP_EthIP     )   ==   28                         ) ? 1 : -1];
        char assertH[(sizeof(IPv4Header    )   ==   20                         ) ? 1 : -1];
        char assertI[(sizeof(IPv6Header    )   ==   40                         ) ? 1 : -1];
-       char assertJ[(sizeof(IPv6ND        )   ==   24                         ) ? 1 : -1];
+       char assertJ[(sizeof(IPv6NDP       )   ==   24                         ) ? 1 : -1];
        char assertK[(sizeof(UDPHeader     )   ==    8                         ) ? 1 : -1];
        char assertL[(sizeof(IKEHeader     )   ==   28                         ) ? 1 : -1];
        char assertM[(sizeof(TCPHeader     )   ==   20                         ) ? 1 : -1];
@@ -3503,21 +2797,21 @@ struct CompileTimeAssertionChecks_mDNS
        // other overly-large structures instead of having a pointer to them, can inadvertently
        // cause structure sizes (and therefore memory usage) to balloon unreasonably.
        char sizecheck_RDataBody           [(sizeof(RDataBody)            ==   264) ? 1 : -1];
-       char sizecheck_ResourceRecord      [(sizeof(ResourceRecord)       <=    56) ? 1 : -1];
-       char sizecheck_AuthRecord          [(sizeof(AuthRecord)           <=  1000) ? 1 : -1];
-       char sizecheck_CacheRecord         [(sizeof(CacheRecord)          <=   176) ? 1 : -1];
-       char sizecheck_CacheGroup          [(sizeof(CacheGroup)           <=   176) ? 1 : -1];
-       char sizecheck_DNSQuestion         [(sizeof(DNSQuestion)          <=   728) ? 1 : -1];
-       char sizecheck_ZoneData            [(sizeof(ZoneData)             <=  1560) ? 1 : -1];
+       char sizecheck_ResourceRecord      [(sizeof(ResourceRecord)       <=    64) ? 1 : -1];
+       char sizecheck_AuthRecord          [(sizeof(AuthRecord)           <=  1208) ? 1 : -1];
+       char sizecheck_CacheRecord         [(sizeof(CacheRecord)          <=   184) ? 1 : -1];
+       char sizecheck_CacheGroup          [(sizeof(CacheGroup)           <=   184) ? 1 : -1];
+       char sizecheck_DNSQuestion         [(sizeof(DNSQuestion)          <=   752) ? 1 : -1];
+       char sizecheck_ZoneData            [(sizeof(ZoneData)             <=  1588) ? 1 : -1];
        char sizecheck_NATTraversalInfo    [(sizeof(NATTraversalInfo)     <=   192) ? 1 : -1];
-       char sizecheck_HostnameInfo        [(sizeof(HostnameInfo)         <=  2800) ? 1 : -1];
-       char sizecheck_DNSServer           [(sizeof(DNSServer)            <=   312) ? 1 : -1];
-       char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <=  5968) ? 1 : -1];
+       char sizecheck_HostnameInfo        [(sizeof(HostnameInfo)         <=  3050) ? 1 : -1];
+       char sizecheck_DNSServer           [(sizeof(DNSServer)            <=   320) ? 1 : -1];
+       char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <=  6750) ? 1 : -1];
        char sizecheck_ServiceRecordSet    [(sizeof(ServiceRecordSet)     <=  5500) ? 1 : -1];
-       char sizecheck_DomainAuthInfo      [(sizeof(DomainAuthInfo)       <=  5500) ? 1 : -1];
-       char sizecheck_ServiceInfoQuery    [(sizeof(ServiceInfoQuery)     <=  2944) ? 1 : -1];
+       char sizecheck_DomainAuthInfo      [(sizeof(DomainAuthInfo)       <=  7550) ? 1 : -1];
+       char sizecheck_ServiceInfoQuery    [(sizeof(ServiceInfoQuery)     <=  3050) ? 1 : -1];
 #if APPLE_OSX_mDNSResponder
-       char sizecheck_ClientTunnel        [(sizeof(ClientTunnel)         <=  1072) ? 1 : -1];
+       char sizecheck_ClientTunnel        [(sizeof(ClientTunnel)         <=  1104) ? 1 : -1];
 #endif
        };
 
index 992e2141bd3dac23609b61ed1224a60326318e37..dcfcf6583fdd760a35ae1446ceda27007d979b56 100755 (executable)
  * Elimate all mDNSPlatformMemAllocate/mDNSPlatformMemFree from this code -- the core code
  * is supposed to be malloc-free so that it runs in constant memory determined at compile-time.
  * Any dynamic run-time requirements should be handled by the platform layer below or client layer above
-
-       Change History (most recent first):
-
-$Log: uDNS.c,v $
-Revision 1.617  2009/06/30 20:51:02  cheshire
-Improved "Error! Tried to add a NAT traversal that's already in the active list" debugging message
-
-Revision 1.616  2009/05/27 20:29:36  cheshire
-<rdar://problem/6926465> Sleep is delayed by 10 seconds if BTMM is on
-After receiving confirmation of LLQ deletion, need to schedule another evaluation of whether we're ready to sleep yet
-
-Revision 1.615  2009/05/05 01:32:50  jessic2
-<rdar://problem/6830541> regservice_callback: instance->request is NULL 0 -- Clean up spurious logs resulting from fixing this bug.
-
-Revision 1.614  2009/04/24 02:17:57  mcguire
-<rdar://problem/5264124> uDNS: Not always respecting preference order of DNS servers
-
-Revision 1.613  2009/04/23 22:06:29  cheshire
-Added CacheRecord and InterfaceID parameters to MakeNegativeCacheRecord, in preparation for:
-<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
-
-Revision 1.612  2009/04/22 01:19:57  jessic2
-<rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32
-
-Revision 1.611  2009/04/15 20:42:51  mcguire
-<rdar://problem/6768947> uDNS: Treat RCODE 5 (Refused) responses as failures
-
-Revision 1.610  2009/04/15 01:10:39  jessic2
-<rdar://problem/6466541> BTMM: Add support for setting kDNSServiceErr_NoSuchRecord in DynamicStore
-
-Revision 1.609  2009/04/11 00:19:45  jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.608  2009/04/06 23:44:59  cheshire
-<rdar://problem/6757838> mDNSResponder thrashing kernel lock in the UDP close path, hurting SPECweb performance
-
-Revision 1.607  2009/04/02 22:36:34  jessic2
-Fix crash when calling debugf with null opt
-
-Revision 1.606  2009/03/26 03:59:00  jessic2
-Changes for <rdar://problem/6492552&6492593&6492609&6492613&6492628&6492640&6492699>
-
-Revision 1.605  2009/03/04 00:40:14  cheshire
-Updated DNS server error codes to be more consistent with definitions at
-<http://www.iana.org/assignments/dns-parameters>
-
-Revision 1.604  2009/02/27 03:08:47  cheshire
-<rdar://problem/6547720> Crash while shutting down when "local" is in the user's DNS searchlist
-
-Revision 1.603  2009/02/27 02:56:57  cheshire
-Moved struct SearchListElem definition from uDNS.c into mDNSEmbeddedAPI.h
-
-Revision 1.602  2009/02/13 06:29:54  cheshire
-Converted LogOperation messages to LogInfo
-
-Revision 1.601  2009/02/12 20:57:25  cheshire
-Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
-
-Revision 1.600  2009/01/31 21:05:12  cheshire
-Improved "Failed to obtain NAT port mapping" debugging log message
-
-Revision 1.599  2009/01/23 00:38:36  mcguire
-<rdar://problem/5570906> BTMM: Doesn't work with Linksys WRT54GS firmware 4.71.1
-
-Revision 1.598  2009/01/21 03:43:57  mcguire
-<rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore
-
-Revision 1.597  2009/01/10 01:55:49  cheshire
-Added LogOperation message showing when domains are added and removed in FoundDomain
-
-Revision 1.596  2008/12/19 20:23:33  mcguire
-<rdar://problem/6459269> Lots of duplicate log messages about failure to bind to NAT-PMP Announcement port
-
-Revision 1.595  2008/12/18 23:32:19  mcguire
-<rdar://problem/6019470> BTMM: Include the question in the LLQ notification acknowledgment
-
-Revision 1.594  2008/12/10 02:25:31  cheshire
-Minor fixes to use of LogClientOperations symbol
-
-Revision 1.593  2008/12/10 02:11:42  cheshire
-ARMv5 compiler doesn't like uncommented stuff after #endif
-
-Revision 1.592  2008/12/06 01:42:55  mcguire
-<rdar://problem/6418958> Need to exponentially back-off after failure to get public address
-
-Revision 1.591  2008/12/06 00:17:11  cheshire
-<rdar://problem/6380477> mDNS_StopNATOperation doesn't handle duplicate NAT mapping requests properly
-Refinement: For duplicate ssh mappings we want to suppress the syslog warning message, but not the "unmap = mDNSfalse"
-
-Revision 1.590  2008/12/04 20:57:36  mcguire
-fix build
-
-Revision 1.589  2008/12/04 02:24:09  cheshire
-Improved NAT-PMP debugging messages
-
-Revision 1.588  2008/11/26 20:38:08  cheshire
-Changed some "LogOperation" debugging messages to "debugf"
-
-Revision 1.587  2008/11/26 19:53:26  cheshire
-Don't overwrite srs->NATinfo.IntPort in StartSRVNatMap()
-
-Revision 1.586  2008/11/25 23:43:07  cheshire
-<rdar://problem/5745355> Crashes at ServiceRegistrationGotZoneData + 397
-Made code more defensive to guard against ServiceRegistrationGotZoneData being called with invalid ServiceRecordSet object
-
-Revision 1.585  2008/11/25 22:46:30  cheshire
-For ease of code searching, renamed ZoneData field of ServiceRecordSet_struct from "nta" to "srs_nta"
-
-Revision 1.584  2008/11/24 19:46:40  cheshire
-When sending query over TCP, don't include LLQ option when we're talking to a conventional DNS server or cache
-
-Revision 1.583  2008/11/21 00:34:58  cheshire
-<rdar://problem/6380477> mDNS_StopNATOperation doesn't handle duplicate NAT mapping requests properly
-
-Revision 1.582  2008/11/20 02:23:37  mcguire
-<rdar://problem/6041208> need to handle URLBase
-
-Revision 1.581  2008/11/20 01:51:19  cheshire
-Exported RecreateNATMappings so it's callable from other files
-
-Revision 1.580  2008/11/13 19:08:45  cheshire
-Fixed code to handle rdataOPT properly
-
-Revision 1.579  2008/11/07 00:18:01  mcguire
-<rdar://problem/6351068> uDNS: Supress reverse DNS query until required
-
-Revision 1.578  2008/11/04 22:21:46  cheshire
-Changed zone field of AuthRecord_struct from domainname to pointer, saving 252 bytes per AuthRecord
-
-Revision 1.577  2008/10/29 21:37:01  cheshire
-Removed some old debugging messages
-
-Revision 1.576  2008/10/23 22:25:57  cheshire
-Renamed field "id" to more descriptive "updateid"
-
-Revision 1.575  2008/10/20 02:07:49  mkrochma
-<rdar://problem/6296804> Remove Note: DNS Server <ip> for domain <d> registered more than once
-
-Revision 1.574  2008/10/14 19:06:45  cheshire
-In uDNS_ReceiveMsg(), only do checkUpdateResult() for uDNS records
-
-Revision 1.573  2008/09/25 20:43:44  cheshire
-<rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
-In UpdateSRVRecords, call mDNS_SetFQDN(m) to update AutoTarget SRV records on the main m->ResourceRecords list
-
-Revision 1.572  2008/09/24 23:48:05  cheshire
-Don't need to pass whole ServiceRecordSet reference to GetServiceTarget;
-it only needs to access the embedded SRV member of the set
-
-Revision 1.571  2008/09/23 22:56:53  cheshire
-<rdar://problem/5298845> Remove dnsbugtest query
-
-Revision 1.570  2008/09/23 01:30:18  cheshire
-The putLLQ() routine was not setting the OPT record's rrclass to NormalMaxDNSMessageData
-
-Revision 1.569  2008/07/25 22:34:11  mcguire
-fix sizecheck issues for 64bit
-
-Revision 1.568  2008/07/24 20:23:03  cheshire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-
-Revision 1.567  2008/07/01 01:40:00  mcguire
-<rdar://problem/5823010> 64-bit fixes
-
-Revision 1.566  2008/06/26 17:24:11  mkrochma
-<rdar://problem/5450912> BTMM: Stop listening on UDP 5351 for NAT Status Announcements
-
-Revision 1.565  2008/06/21 19:06:58  mcguire
-<rdar://problem/4206534> Use all configured DNS servers
-
-Revision 1.564  2008/06/19 23:42:03  mcguire
-<rdar://problem/4206534> Use all configured DNS servers
-
-Revision 1.563  2008/06/19 17:46:14  mcguire
-<rdar://problem/4206534> Use all configured DNS servers
-Don't do extra work for log messages if we're not going to log
-
-Revision 1.562  2008/06/19 17:35:19  mcguire
-<rdar://problem/4206534> Use all configured DNS servers
-cleanup log messages
-check for null pointers
-
-Revision 1.561  2008/06/19 01:20:49  mcguire
-<rdar://problem/4206534> Use all configured DNS servers
-
-Revision 1.560  2008/05/31 01:51:09  mcguire
-fixed typo in log message
-
-Revision 1.559  2008/04/15 22:37:58  mkrochma
-Change LogMsg to LogOperation
-
-Revision 1.558  2008/03/17 18:02:35  mkrochma
-Add space to log message for consistency
-
-Revision 1.557  2008/03/14 19:58:38  mcguire
-<rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
-Make sure we add the record when sending LLQ refreshes
-
-Revision 1.556  2008/03/07 23:55:05  cheshire
-<rdar://problem/5787898> LLQ refresh randomization not working properly
-
-Revision 1.555  2008/03/07 23:25:56  cheshire
-Improved debugging messages
-
-Revision 1.554  2008/03/07 18:56:03  cheshire
-<rdar://problem/5777647> dnsbugtest query every three seconds when source IP address of response doesn't match
-
-Revision 1.553  2008/03/06 02:48:34  mcguire
-<rdar://problem/5321824> write status to the DS
-
-Revision 1.552  2008/03/05 01:56:42  cheshire
-<rdar://problem/5687667> BTMM: Don't fallback to unencrypted operations when SRV lookup fails
-
-Revision 1.551  2008/03/01 01:43:04  cheshire
-<rdar://problem/5631565> BTMM: Lots of "Error getting external address 3" when double-NATed prevents sleep
-Added code to suppress logging of multiple identical error results
-
-Revision 1.550  2008/03/01 01:34:47  cheshire
-<rdar://problem/5736313> BTMM: Double-NAT'd machines register all but AutoTunnel v4 address records
-Further refinements
-
-Revision 1.549  2008/02/29 01:35:37  mcguire
-<rdar://problem/5736313> BTMM: Double-NAT'd machines register all but AutoTunnel v4 address records
-
-Revision 1.548  2008/02/20 23:54:18  cheshire
-<rdar://problem/5661518> "Failed to obtain NAT port mapping" syslog messages
-Improved log message so it tells us more about what's going on
-
-Revision 1.547  2008/02/20 00:41:09  cheshire
-Change "PrivateQueryGotZoneData ... invoked with error code" from LogMsg to LogOperation
-
-Revision 1.546  2008/02/19 23:26:50  cheshire
-<rdar://problem/5661661> BTMM: Too many members.mac.com SOA queries
-
-Revision 1.545  2007/12/22 02:25:29  cheshire
-<rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
-
-Revision 1.544  2007/12/18 00:40:11  cheshire
-<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
-Reordered code to avoid double-TSIGs in some cases
-
-Revision 1.543  2007/12/17 23:57:43  cheshire
-<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
-Need to include TSIG signature when sending LLQ cancellations over TLS
-
-Revision 1.542  2007/12/15 01:12:27  cheshire
-<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
-
-Revision 1.541  2007/12/15 00:18:51  cheshire
-Renamed question->origLease to question->ReqLease
-
-Revision 1.540  2007/12/14 23:55:28  cheshire
-Moved "struct tcpInfo_t" definition from uDNS.c to mDNSEmbeddedAPI.h
-
-Revision 1.539  2007/12/14 20:44:24  cheshire
-<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
-SleepRecordRegistrations/WakeRecordRegistrations should only operate on uDNS records
-
-Revision 1.538  2007/12/14 01:13:40  cheshire
-<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
-Additional fixes (existing code to deregister private records and services didn't work at all)
-
-Revision 1.537  2007/12/11 00:18:25  cheshire
-<rdar://problem/5569316> BTMM: My iMac has a "ghost" ID associated with it
-There were cases where the code was incorrectly clearing the "uselease" flag, and never resetting it.
-
-Revision 1.536  2007/12/10 23:07:00  cheshire
-Removed some unnecessary log messages
-
-Revision 1.535  2007/12/06 00:22:27  mcguire
-<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
-
-Revision 1.534  2007/12/04 00:49:37  cheshire
-<rdar://problem/5607082> BTMM: mDNSResponder taking 100 percent CPU after upgrading to 10.5.1
-
-Revision 1.533  2007/12/01 01:21:27  jgraessley
-<rdar://problem/5623140> mDNSResponder unicast DNS improvements
-
-Revision 1.532  2007/11/30 20:16:44  cheshire
-Fixed compile warning: declaration of 'end' shadows a previous local
-
-Revision 1.531  2007/11/28 22:00:09  cheshire
-In StartSRVNatMap, change "mDNSu8 *p" to "const mDNSu8 *p"
-
-Revision 1.530  2007/11/16 22:19:40  cheshire
-<rdar://problem/5547474> mDNSResponder leaks on network changes
-The "connection failed" code path in MakeTCPConn was not disposing of the TCPSocket it had created
-
-Revision 1.529  2007/11/15 22:52:29  cheshire
-<rdar://problem/5589039> ERROR: mDNSPlatformWriteTCP - send Broken pipe
-
-Revision 1.528  2007/11/02 21:32:30  cheshire
-<rdar://problem/5575593> BTMM: Deferring deregistration of record log messages on sleep/wake
-
-Revision 1.527  2007/11/01 16:08:51  cheshire
-Tidy up alignment of "SetRecordRetry refresh" log messages
-
-Revision 1.526  2007/10/31 19:26:55  cheshire
-Don't need to log "Permanently abandoning service registration" message when we're intentionally deleting a service
-
-Revision 1.525  2007/10/30 23:58:59  cheshire
-<rdar://problem/5496734> BTMM: Need to retry registrations after failures
-After failure, double retry interval up to maximum of 30 minutes
-
-Revision 1.524  2007/10/30 20:10:47  cheshire
-<rdar://problem/5496734> BTMM: Need to retry registrations after failures
-
-Revision 1.523  2007/10/30 00:54:31  cheshire
-<rdar://problem/5496734> BTMM: Need to retry registrations after failures
-Fixed timing logic to double retry interval properly
-
-Revision 1.522  2007/10/30 00:04:43  cheshire
-<rdar://problem/5496734> BTMM: Need to retry registrations after failures
-Made the code not give up and abandon the record when it gets an error in regState_UpdatePending state
-
-Revision 1.521  2007/10/29 23:58:52  cheshire
-<rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
-Use standard "if (mDNSIPv4AddressIsOnes(....ExternalAddress))" mechanism to determine whether callback has been invoked yet
-
-Revision 1.520  2007/10/29 21:48:36  cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-Added 10% random variation on LLQ renewal time, to reduce unintended timing correlation between multiple machines
-
-Revision 1.519  2007/10/29 21:37:00  cheshire
-<rdar://problem/5496734> BTMM: Need to retry registrations after failures
-Added 10% random variation on record refresh time, to reduce accidental timing correlation between multiple machines
-
-Revision 1.518  2007/10/26 23:41:29  cheshire
-<rdar://problem/5496734> BTMM: Need to retry registrations after failures
-
-Revision 1.517  2007/10/25 23:30:12  cheshire
-Private DNS registered records now deregistered on sleep and re-registered on wake
-
-Revision 1.516  2007/10/25 22:53:52  cheshire
-<rdar://problem/5496734> BTMM: Need to retry registrations after failures
-Don't unlinkSRS and permanently give up at the first sign of trouble
-
-Revision 1.515  2007/10/25 21:08:07  cheshire
-Don't try to send record registrations/deletions before we have our server address
-
-Revision 1.514  2007/10/25 20:48:47  cheshire
-For naming consistency (with AuthRecord's UpdateServer) renamed 'ns' to 'SRSUpdateServer'
-
-Revision 1.513  2007/10/25 20:06:13  cheshire
-Don't try to do SOA queries using private DNS (TLS over TCP) queries
-
-Revision 1.512  2007/10/25 18:25:15  cheshire
-<rdar://problem/5496734> BTMM: Need to retry registrations after failures
-Don't need a NAT mapping for autotunnel services
-
-Revision 1.511  2007/10/25 00:16:23  cheshire
-<rdar://problem/5496734> BTMM: Need to retry registrations after failures
-Fixed retry timing logic; when DNS server returns an error code, we should retry later,
-instead of just deleting our record ("UnlinkAuthRecord") and completely giving up
-
-Revision 1.510  2007/10/24 22:40:06  cheshire
-Renamed: RecordRegistrationCallback          -> RecordRegistrationGotZoneData
-Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
-
-Revision 1.509  2007/10/24 00:54:07  cheshire
-<rdar://problem/5496734> BTMM: Need to retry registrations after failures
-
-Revision 1.508  2007/10/24 00:05:03  cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-When sending TLS/TCP LLQ setup request over VPN, need to set EventPort to 5353, not zero
-
-Revision 1.507  2007/10/23 00:33:36  cheshire
-Improved debugging messages
-
-Revision 1.506  2007/10/22 19:54:13  cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-Only put EventPort in LLQ request when sending from an RFC 1918 source address, not when sending over VPN
-
-Revision 1.505  2007/10/19 22:08:49  cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-Additional fixes and refinements
-
-Revision 1.504  2007/10/18 23:06:43  cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-Additional fixes and refinements
-
-Revision 1.503  2007/10/18 20:23:17  cheshire
-Moved SuspendLLQs into mDNS.c, since it's only called from one place
-
-Revision 1.502  2007/10/17 22:49:54  cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-
-Revision 1.501  2007/10/17 22:37:23  cheshire
-<rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
-
-Revision 1.500  2007/10/17 21:53:51  cheshire
-Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
-
-Revision 1.499  2007/10/16 21:16:50  cheshire
-Get rid of unused uDNS_Sleep() routine
-
-Revision 1.498  2007/10/16 20:59:41  cheshire
-Export SuspendLLQs/SleepServiceRegistrations/SleepRecordRegistrations so they're callable from other files
-
-Revision 1.497  2007/10/05 18:09:44  cheshire
-<rdar://problem/5524841> Services advertised with wrong target host
-
-Revision 1.496  2007/10/04 22:38:59  cheshire
-Added LogOperation message showing new q->ThisQInterval after sending uDNS query packet
-
-Revision 1.495  2007/10/03 00:16:19  cheshire
-In PrivateQueryGotZoneData, need to grab lock before calling SetNextQueryTime
-
-Revision 1.494  2007/10/02 21:11:08  cheshire
-<rdar://problem/5518270> LLQ refreshes don't work, which breaks BTMM browsing
-
-Revision 1.493  2007/10/02 19:50:23  cheshire
-Improved debugging message
-
-Revision 1.492  2007/09/29 03:15:43  cheshire
-<rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
-Use AutoTunnelUnregistered macro instead of checking record state directly
-
-Revision 1.491  2007/09/29 01:33:45  cheshire
-<rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
-
-Revision 1.490  2007/09/29 01:06:17  mcguire
-<rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
-
-Revision 1.489  2007/09/27 22:02:33  cheshire
-<rdar://problem/5464941> BTMM: Registered records in BTMM don't get removed from server after calling RemoveRecord
-
-Revision 1.488  2007/09/27 21:20:17  cheshire
-Improved debugging syslog messages
-
-Revision 1.487  2007/09/27 18:55:11  cheshire
-<rdar://problem/5477165> BTMM: Multiple SRV records get registered after changing Computer Name
-
-Revision 1.486  2007/09/27 17:42:49  cheshire
-Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
-
-Revision 1.485  2007/09/27 02:16:30  cheshire
-<rdar://problem/5500111> BTMM: LLQ refreshes being sent in the clear to the wrong port
-
-Revision 1.484  2007/09/27 00:25:39  cheshire
-Added ttl_seconds parameter to MakeNegativeCacheRecord in preparation for:
-<rdar://problem/4947392> uDNS: Use SOA to determine TTL for negative answers
-
-Revision 1.483  2007/09/26 23:16:58  cheshire
-<rdar://problem/5496399> BTMM: Leopard sending excessive LLQ registration requests to .Mac
-
-Revision 1.482  2007/09/26 22:06:02  cheshire
-<rdar://problem/5507399> BTMM: No immediate failure notifications for BTMM names
-
-Revision 1.481  2007/09/26 00:49:46  cheshire
-Improve packet logging to show sent and received packets,
-transport protocol (UDP/TCP/TLS) and source/destination address:port
-
-Revision 1.480  2007/09/21 21:08:52  cheshire
-Get rid of unnecessary DumpPacket() calls -- it makes more sense
-to do this in mDNSSendDNSMessage and mDNSCoreReceive instead
-
-Revision 1.479  2007/09/21 20:01:17  cheshire
-<rdar://problem/5496750> BTMM: Skip directly to member name in SOA queries to avoid sending names in the clear
-
-Revision 1.478  2007/09/21 19:29:14  cheshire
-Added dump of uDNS questions when in MDNS_LOG_VERBOSE_DEBUG mode
-
-Revision 1.477  2007/09/20 02:29:37  cheshire
-<rdar://problem/4038277> BTMM: Not getting LLQ remove events when logging out of VPN or disconnecting from network
-
-Revision 1.476  2007/09/20 01:19:49  cheshire
-Improve debugging messages: report startLLQHandshake errors; show state in uDNS_StopLongLivedQuery message
-
-Revision 1.475  2007/09/19 23:51:26  cheshire
-<rdar://problem/5480517> BTMM: Need to log a message when NAT port mapping fails
-
-Revision 1.474  2007/09/19 20:32:09  cheshire
-Export GetAuthInfoForName so it's callable from other files
-
-Revision 1.473  2007/09/18 21:42:29  cheshire
-To reduce programming mistakes, renamed ExtPort to RequestedPort
-
-Revision 1.472  2007/09/14 21:26:08  cheshire
-<rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
-
-Revision 1.471  2007/09/14 01:07:10  cheshire
-If UPnP NAT gateway returns 0.0.0.0 as external address (e.g. because it hasn't
-got a DHCP address yet) then retry periodically until it gives us a real address.
-
-Revision 1.470  2007/09/13 00:36:26  cheshire
-<rdar://problem/5477360> NAT Reboot detection logic incorrect
-
-Revision 1.469  2007/09/13 00:28:50  cheshire
-<rdar://problem/5477354> Host records not updated on NAT address change
-
-Revision 1.468  2007/09/13 00:16:41  cheshire
-<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
-
-Revision 1.467  2007/09/12 23:03:08  cheshire
-<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
-
-Revision 1.466  2007/09/12 22:19:29  cheshire
-<rdar://problem/5476977> Need to listen for port 5350 NAT-PMP announcements
-
-Revision 1.465  2007/09/12 19:22:19  cheshire
-Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
-Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
-
-Revision 1.464  2007/09/12 01:22:13  cheshire
-Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
-
-Revision 1.463  2007/09/11 20:23:28  vazquez
-<rdar://problem/5466719> CrashTracer: 3 crashes in mDNSResponder at mDNSResponder: natTraversalHandlePortMapReply + 107
-Make sure we clean up NATTraversals before free'ing HostnameInfo
-
-Revision 1.462  2007/09/11 19:19:16  cheshire
-Correct capitalization of "uPNP" to "UPnP"
-
-Revision 1.461  2007/09/10 22:08:17  cheshire
-Rename uptime => upseconds and LastNATUptime => LastNATupseconds to make it clear these time values are in seconds
-
-Revision 1.460  2007/09/07 21:47:43  vazquez
-<rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
-Try to allocate using port 5350 if we get a failure, and only log message if that fails too.
-
-Revision 1.459  2007/09/07 01:01:05  cheshire
-<rdar://problem/5464844> BTMM: Services being registered and deregistered in a loop
-In hndlServiceUpdateReply, need to clear SRVUpdateDeferred
-
-Revision 1.458  2007/09/06 19:14:33  cheshire
-Fixed minor error introduced in 1.379 (an "if" statement was deleted but the "else" following it was left there)
-
-Revision 1.457  2007/09/05 21:48:01  cheshire
-<rdar://problem/5385864> BTMM: mDNSResponder flushes wide-area Bonjour records after an hour for a zone.
-Now that we're respecting the TTL of uDNS records in the cache, the LLQ maintenance code needs
-to update the cache lifetimes of all relevant records every time it successfully renews an LLQ,
-otherwise those records will expire and vanish from the cache.
-
-Revision 1.456  2007/09/05 21:00:17  cheshire
-<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
-Additional refinement: ThisQInterval needs to be restored in tcpCallback, not in PrivateQueryGotZoneData
-
-Revision 1.455  2007/09/05 20:53:06  cheshire
-Tidied up alignment of code layout; code was clearing m->tcpAddrInfo.sock instead of m->tcpDeviceInfo.sock
-
-Revision 1.454  2007/09/05 02:32:55  cheshire
-Fixed posix build error (mixed declarations and code)
-
-Revision 1.453  2007/09/05 02:26:57  cheshire
-<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
-In PrivateQueryGotZoneData, restore q->ThisQInterval to non-zero value after GetZoneData completes
-
-Revision 1.452  2007/08/31 22:58:22  cheshire
-If we have an existing TCP connection we should re-use it instead of just bailing out
-After receiving dnsbugtest response, need to set m->NextScheduledQuery to cause queries to be re-issued
-
-Revision 1.451  2007/08/31 18:49:49  vazquez
-<rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
-
-Revision 1.450  2007/08/30 22:50:04  mcguire
-<rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
-
-Revision 1.449  2007/08/30 00:43:17  cheshire
-Need to clear m->rec.r.resrec.RecordType before returning from uDNS_recvLLQResponse
-
-Revision 1.448  2007/08/30 00:18:46  cheshire
-<rdar://problem/5448804> Error messages: "SendServiceRegistration: Already have TCP connection..."
-
-Revision 1.447  2007/08/29 01:18:33  cheshire
-<rdar://problem/5400181> BTMM: Tunneled services do not need NAT port mappings
-Only create NAT mappings for SRV records with AutoTarget set to Target_AutoHostAndNATMAP
-
-Revision 1.446  2007/08/28 23:58:42  cheshire
-Rename HostTarget -> AutoTarget
-
-Revision 1.445  2007/08/28 23:53:21  cheshire
-Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
-
-Revision 1.444  2007/08/27 20:29:20  cheshire
-Additional debugging messages
-
-Revision 1.443  2007/08/24 23:18:28  cheshire
-mDNS_SetSecretForDomain is called with lock held; needs to use
-GetAuthInfoForName_internal() instead of external version GetAuthInfoForName()
-
-Revision 1.442  2007/08/24 22:43:06  cheshire
-Tidied up coded layout
-
-Revision 1.441  2007/08/24 01:20:55  cheshire
-<rdar://problem/5434381> BTMM: Memory corruption in KeychainChanged event handling
-
-Revision 1.440  2007/08/24 00:15:20  cheshire
-Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
-
-Revision 1.439  2007/08/23 21:47:09  vazquez
-<rdar://problem/5427316> BTMM: mDNSResponder sends NAT-PMP packets on public network
-make sure we clean up port mappings on base stations by sending a lease value of 0,
-and only send NAT-PMP packets on private networks; also save some memory by
-not using packet structs in NATTraversals.
-
-Revision 1.438  2007/08/22 17:50:08  vazquez
-<rdar://problem/5399276> Need to handle errors returned by NAT-PMP routers properly
-Propagate router errors to clients, and stop logging spurious "message too short" logs.
-
-Revision 1.437  2007/08/18 00:54:15  mcguire
-<rdar://problem/5413147> BTMM: Should not register private addresses or zeros
-
-Revision 1.436  2007/08/08 21:07:48  vazquez
-<rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
-
-Revision 1.435  2007/08/03 02:04:09  vazquez
-<rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
-Fix case where NAT-PMP returns an external address but does not support
-port mappings. Undo previous change and now, if the router returns an
-error in the reply packet we respect it.
-
-Revision 1.434  2007/08/02 21:03:05  vazquez
-Change NAT logic to fix case where base station with port mapping turned off
-returns an external address but does not make port mappings.
-
-Revision 1.433  2007/08/02 03:30:11  vazquez
-<rdar://problem/5371843> BTMM: Private LLQs never fall back to polling
-
-Revision 1.432  2007/08/01 18:15:19  cheshire
-Fixed crash in tcpCallback; fixed some problems with LLQ setup behind NAT
-
-Revision 1.431  2007/08/01 16:11:06  cheshire
-Fixed "mixed declarations and code" compiler error in Posix build
-
-Revision 1.430  2007/08/01 16:09:13  cheshire
-Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
-
-Revision 1.429  2007/08/01 03:09:22  cheshire
-<rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
-
-Revision 1.428  2007/08/01 01:43:36  cheshire
-Need to do mDNS_DropLockBeforeCallback/ReclaimLock around invokation of NAT client callback
-
-Revision 1.427  2007/08/01 01:31:13  cheshire
-Need to initialize traversal->tcpInfo fields or code may crash
-
-Revision 1.426  2007/08/01 01:15:57  cheshire
-<rdar://problem/5375791> Need to invoke NAT client callback when not on RFC1918 private network
-
-Revision 1.425  2007/08/01 00:04:14  cheshire
-<rdar://problem/5261696> Crash in tcpKQSocketCallback
-Half-open TCP connections were not being cancelled properly
-
-Revision 1.424  2007/07/31 02:28:35  vazquez
-<rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
-
-Revision 1.423  2007/07/30 23:31:26  cheshire
-Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
-
-Revision 1.422  2007/07/28 01:25:57  cheshire
-<rdar://problem/4780038> BTMM: Add explicit UDP event port to LLQ setup request, to fix LLQs not working behind NAT
-
-Revision 1.421  2007/07/28 00:04:14  cheshire
-Various fixes for comments and debugging messages
-
-Revision 1.420  2007/07/27 23:59:18  cheshire
-Added compile-time structure size checks
-
-Revision 1.419  2007/07/27 20:52:29  cheshire
-Made uDNS_recvLLQResponse() return tri-state result: LLQ_Not, LLQ_First, or LLQ_Events
-
-Revision 1.418  2007/07/27 20:32:05  vazquez
-Flag a UPnP NAT traversal before starting a UPnP port mapping, and make sure all
-calls to mDNS_StopNATOperation() go through the UPnP code
-
-Revision 1.417  2007/07/27 20:19:42  cheshire
-Use MDNS_LOG_VERBOSE_DEBUG for dumping out packets instead of MDNS_LOG_DEBUG
-
-Revision 1.416  2007/07/27 19:59:28  cheshire
-MUST NOT touch m->CurrentQuestion (or q) after calling AnswerCurrentQuestionWithResourceRecord()
-
-Revision 1.415  2007/07/27 19:51:01  cheshire
-Use symbol QC_addnocache instead of literal constant "2"
-
-Revision 1.414  2007/07/27 19:30:39  cheshire
-Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
-to properly reflect tri-state nature of the possible responses
-
-Revision 1.413  2007/07/27 18:44:01  cheshire
-Rename "AnswerQuestionWithResourceRecord" to more informative "AnswerCurrentQuestionWithResourceRecord"
-
-Revision 1.412  2007/07/27 18:38:56  cheshire
-Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
-
-Revision 1.411  2007/07/27 00:57:13  cheshire
-Create hostname address records using standard kHostNameTTL (2 minutes) instead of 1 second
-
-Revision 1.410  2007/07/25 21:41:00  vazquez
-Make sure we clean up opened sockets when there are network transitions and when changing
-port mappings
-
-Revision 1.409  2007/07/25 03:05:02  vazquez
-Fixes for:
-<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
-<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
-and a myriad of other security problems
-
-Revision 1.408  2007/07/24 21:47:51  cheshire
-Don't do mDNS_StopNATOperation() for operations we never started
-
-Revision 1.407  2007/07/24 17:23:33  cheshire
-<rdar://problem/5357133> Add list validation checks for debugging
-
-Revision 1.406  2007/07/24 04:14:30  cheshire
-<rdar://problem/5356281> LLQs not working in with NAT Traversal
-
-Revision 1.405  2007/07/24 01:29:03  cheshire
-<rdar://problem/5356026> DNSServiceNATPortMappingCreate() returns stale external address information
-
-Revision 1.404  2007/07/20 23:10:51  cheshire
-Fix code layout
-
-Revision 1.403  2007/07/20 20:12:37  cheshire
-Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
-
-Revision 1.402  2007/07/20 00:54:20  cheshire
-<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-
-Revision 1.401  2007/07/18 03:23:33  cheshire
-In GetServiceTarget, need to call SetupLocalAutoTunnelInterface_internal to bring up tunnel on demand, if necessary
-
-Revision 1.400  2007/07/18 02:30:25  cheshire
-Defer AutoTunnel server record advertising until we have at least one service to advertise
-Do AutoTunnel target host selection in GetServiceTarget (instead of uDNS_RegisterService)
-
-Revision 1.399  2007/07/18 01:02:28  cheshire
-<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
-Declare records as kDNSRecordTypeKnownUnique so we don't get name conflicts with ourselves
-
-Revision 1.398  2007/07/16 23:54:48  cheshire
-<rdar://problem/5338850> Crash when removing or changing DNS keys
-
-Revision 1.397  2007/07/16 20:13:31  vazquez
-<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
-
-Revision 1.396  2007/07/14 00:33:04  cheshire
-Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
-
-Revision 1.395  2007/07/12 23:56:23  cheshire
-Change "GetZoneData GOT SRV" message to debugf to reduce verbosity in syslog
-
-Revision 1.394  2007/07/12 23:36:08  cheshire
-Changed some 'LogOperation' calls to 'debugf' to reduce verbosity in syslog
-
-Revision 1.393  2007/07/12 22:15:10  cheshire
-Modified mDNS_SetSecretForDomain() so it can be called to update an existing entry
-
-Revision 1.392  2007/07/12 02:51:27  cheshire
-<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
-
-Revision 1.391  2007/07/11 23:16:31  cheshire
-<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
-Need to prepend _autotunnel._udp to start of AutoTunnel SRV record name
-
-Revision 1.390  2007/07/11 22:47:55  cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
-In mDNS_SetSecretForDomain(), don't register records until after we've validated the parameters
-
-Revision 1.389  2007/07/11 21:33:10  cheshire
-<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
-Set up and register AutoTunnelTarget and AutoTunnelService DNS records
-
-Revision 1.388  2007/07/11 19:27:10  cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
-For temporary testing fake up an IPv4LL address instead of IPv6 ULA
-
-Revision 1.387  2007/07/11 03:04:08  cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-Add AutoTunnel parameter to mDNS_SetSecretForDomain; Set up AutoTunnel information for domains that require it
-
-Revision 1.386  2007/07/10 01:57:28  cheshire
-<rdar://problem/5196524> uDNS: mDNSresponder is leaking TCP connections to DNS server
-Turned vast chunks of replicated code into a subroutine MakeTCPConn(...);
-Made routines hold on to the reference it returns instead of leaking it
-
-Revision 1.385  2007/07/09 23:50:18  cheshire
-unlinkSRS needs to call mDNS_StopNATOperation_internal(), not mDNS_StopNATOperation()
-
-Revision 1.384  2007/07/06 21:20:21  cheshire
-Fix scheduling error (was causing "Task Scheduling Error: Continuously busy for more than a second")
-
-Revision 1.383  2007/07/06 18:59:59  cheshire
-Avoid spinning in an infinite loop when uDNS_SendNATMsg() returns an error
-
-Revision 1.382  2007/07/04 00:49:43  vazquez
-Clean up extraneous comments
-
-Revision 1.381  2007/07/03 00:41:14  vazquez
- More changes for <rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
- Safely deal with packet replies and client callbacks
-
-Revision 1.380  2007/07/02 22:08:47  cheshire
-Fixed crash in "Received public IP address" message
-
-Revision 1.379  2007/06/29 00:08:49  vazquez
-<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-
-Revision 1.378  2007/06/27 20:25:10  cheshire
-Expanded dnsbugtest comment, explaining requirement that we also need these
-test queries to black-hole before they get to the root name servers.
-
-Revision 1.377  2007/06/22 21:27:21  cheshire
-Modified "could not convert shared secret from base64" log message
-
-Revision 1.376  2007/06/20 01:10:12  cheshire
-<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-
-Revision 1.375  2007/06/15 21:54:51  cheshire
-<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
-
-Revision 1.374  2007/06/12 02:15:26  cheshire
-Fix incorrect "DNS Server passed" LogOperation message
-
-Revision 1.373  2007/05/31 00:25:43  cheshire
-<rdar://problem/5238688> Only send dnsbugtest query for questions where it's warranted
-
-Revision 1.372  2007/05/25 17:03:45  cheshire
-lenptr needs to be declared unsigned, otherwise sign extension can mess up the shifting and ORing operations
-
-Revision 1.371  2007/05/24 00:11:44  cheshire
-Remove unnecessary lenbuf field from tcpInfo_t
-
-Revision 1.370  2007/05/23 00:30:59  cheshire
-Don't change question->TargetQID when repeating query over TCP
-
-Revision 1.369  2007/05/21 18:04:40  cheshire
-Updated comments -- port_mapping_create_reply renamed to port_mapping_reply
-
-Revision 1.368  2007/05/17 19:12:16  cheshire
-Updated comment about finding matching pair of sockets
-
-Revision 1.367  2007/05/15 23:38:00  cheshire
-Need to grab lock before calling SendRecordRegistration();
-
-Revision 1.366  2007/05/15 00:43:05  cheshire
-<rdar://problem/4983538> uDNS serviceRegistrationCallback locking failures
-
-Revision 1.365  2007/05/10 21:19:18  cheshire
-Rate-limit DNS test queries to at most one per three seconds
-(useful when we have a dozen active WAB queries, and then we join a new network)
-
-Revision 1.364  2007/05/07 20:43:45  cheshire
-<rdar://problem/4241419> Reduce the number of queries and announcements
-
-Revision 1.363  2007/05/04 22:12:48  cheshire
-Work towards solving <rdar://problem/5176892> "uDNS_CheckQuery: LastQTime" log messages
-When code gets in this invalid state, double ThisQInterval each time, to avoid excessive logging
-
-Revision 1.362  2007/05/04 21:23:05  cheshire
-<rdar://problem/5167263> Private DNS always returns no answers in the initial LLQ setup response
-Preparatory work to enable us to do a four-way LLQ handshake over TCP, if we decide that's what we want
-
-Revision 1.361  2007/05/03 23:50:48  cheshire
-<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
-In the case of negative answers for the address record, set the server address to zerov4Addr
-
-Revision 1.360  2007/05/03 22:40:38  cheshire
-<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
-
-Revision 1.359  2007/05/02 22:21:33  cheshire
-<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
-
-Revision 1.358  2007/05/01 21:46:31  cheshire
-Move GetLLQOptData/GetPktLease from uDNS.c into DNSCommon.c so that dnsextd can use them
-
-Revision 1.357  2007/05/01 01:33:49  cheshire
-Removed "#define LLQ_Info DNSQuestion" and manually reconciled code that was still referring to "LLQ_Info"
-
-Revision 1.356  2007/04/30 21:51:06  cheshire
-Updated comments
-
-Revision 1.355  2007/04/30 21:33:38  cheshire
-Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
-is iterating through the m->ServiceRegistrations list
-
-Revision 1.354  2007/04/30 01:30:04  cheshire
-GetZoneData_QuestionCallback needs to call client callback function on error, so client knows operation is finished
-RecordRegistrationCallback and serviceRegistrationCallback need to clear nta reference when they're invoked
-
-Revision 1.353  2007/04/28 01:28:25  cheshire
-Fixed memory leak on error path in FoundDomain
-
-Revision 1.352  2007/04/27 19:49:53  cheshire
-In uDNS_ReceiveTestQuestionResponse, also check that srcport matches
-
-Revision 1.351  2007/04/27 19:28:02  cheshire
-Any code that calls StartGetZoneData needs to keep a handle to the structure, so
-it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
--- it would start a query and then quickly cancel it, and then when
-StartGetZoneData completed, it had a dangling pointer and crashed.)
-
-Revision 1.350  2007/04/26 22:47:14  cheshire
-Defensive coding: tcpCallback only needs to check "if (closed)", not "if (!n && closed)"
-
-Revision 1.349  2007/04/26 16:04:06  cheshire
-In mDNS_AddDNSServer, check whether port matches
-In uDNS_CheckQuery, handle case where startLLQHandshake changes q->llq->state to LLQ_Poll
-
-Revision 1.348  2007/04/26 04:01:59  cheshire
-Copy-and-paste error: Test should be "if (result == DNSServer_Passed)" not "if (result == DNSServer_Failed)"
-
-Revision 1.347  2007/04/26 00:35:15  cheshire
-<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
-Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
-inside the firewall may give answers where a public one gives none, and vice versa.)
-
-Revision 1.346  2007/04/25 19:16:59  cheshire
-Don't set SuppressStdPort53Queries unless we do actually send a DNS packet
-
-Revision 1.345  2007/04/25 18:05:11  cheshire
-Don't try to restart inactive (duplicate) queries
-
-Revision 1.344  2007/04/25 17:54:07  cheshire
-Don't cancel Private LLQs using a clear-text UDP packet
-
-Revision 1.343  2007/04/25 16:40:08  cheshire
-Add comment explaining uDNS_recvLLQResponse logic
-
-Revision 1.342  2007/04/25 02:14:38  cheshire
-<rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
-Additional fixes to make LLQs work properly
-
-Revision 1.341  2007/04/24 02:07:42  cheshire
-<rdar://problem/4246187> Identical client queries should reference a single shared core query
-Deleted some more redundant code
-
-Revision 1.340  2007/04/23 22:01:23  cheshire
-<rdar://problem/5094009> IPv6 filtering in AirPort base station breaks Wide-Area Bonjour
-As of March 2007, AirPort base stations now block incoming IPv6 connections by default, so there's no point
-advertising IPv6 addresses in DNS any more -- we have to assume that most of the time a host's IPv6 address
-probably won't work for incoming connections (but its IPv4 address probably will, using NAT-PMP).
-
-Revision 1.339  2007/04/22 06:02:03  cheshire
-<rdar://problem/4615977> Query should immediately return failure when no server
-
-Revision 1.338  2007/04/21 19:44:11  cheshire
-Improve uDNS_HandleNATPortMapReply log message
-
-Revision 1.337  2007/04/21 02:03:00  cheshire
-Also need to set AddressRec->resrec.RecordType in the NAT case too
-
-Revision 1.336  2007/04/20 21:16:12  cheshire
-Fixed bogus double-registration of host name -- was causing these warning messages in syslog:
-Error! Tried to register AuthRecord 0181FB0C host.example.com. (Addr) that's already in the list
-
-Revision 1.335  2007/04/19 23:57:20  cheshire
-Temporary workaround for some AirPort base stations that don't seem to like us requesting public port zero
-
-Revision 1.334  2007/04/19 23:21:51  cheshire
-Fixed a couple of places where the StartGetZoneData check was backwards
-
-Revision 1.333  2007/04/19 22:50:53  cheshire
-<rdar://problem/4246187> Identical client queries should reference a single shared core query
-
-Revision 1.332  2007/04/19 20:34:32  cheshire
-Add debugging log message in uDNS_CheckQuery()
-
-Revision 1.331  2007/04/19 20:06:41  cheshire
-Rename field 'Private' (sounds like a boolean) to more informative 'AuthInfo' (it's a DomainAuthInfo pointer)
-
-Revision 1.330  2007/04/19 19:51:54  cheshire
-Get rid of unnecessary initializeQuery() routine
-
-Revision 1.329  2007/04/19 18:03:52  cheshire
-Improved "mDNS_AddSearchDomain" log message
-
-Revision 1.328  2007/04/18 20:57:20  cheshire
-Commented out "GetAuthInfoForName none found" debugging message
-
-Revision 1.327  2007/04/17 19:21:29  cheshire
-<rdar://problem/5140339> Domain discovery not working over VPN
-
-Revision 1.326  2007/04/16 20:49:39  cheshire
-Fix compile errors for mDNSPosix build
-
-Revision 1.325  2007/04/05 22:55:35  cheshire
-<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
-
-Revision 1.324  2007/04/05 20:43:30  cheshire
-Collapse sprawling code onto one line -- this is part of a bigger block of identical
-code that has been copied-and-pasted into six different places in the same file.
-This really needs to be turned into a subroutine.
-
-Revision 1.323  2007/04/04 21:48:52  cheshire
-<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
-
-Revision 1.322  2007/04/03 19:53:06  cheshire
-Use mDNSSameIPPort (and similar) instead of accessing internal fields directly
-
-Revision 1.321  2007/04/02 23:44:09  cheshire
-Minor code tidying
-
-Revision 1.320  2007/03/31 01:26:13  cheshire
-Take out GetAuthInfoForName syslog message
-
-Revision 1.319  2007/03/31 01:10:53  cheshire
-Add debugging
-
-Revision 1.318  2007/03/31 00:17:11  cheshire
-Remove some LogMsgs
-
-Revision 1.317  2007/03/29 00:09:31  cheshire
-Improve "uDNS_InitLongLivedQuery" log message
-
-Revision 1.316  2007/03/28 21:16:27  cheshire
-Remove DumpPacket() call now that OPT pseudo-RR rrclass bug is fixed
-
-Revision 1.315  2007/03/28 21:02:18  cheshire
-<rdar://problem/3810563> Wide-Area Bonjour should work on multi-subnet private network
-
-Revision 1.314  2007/03/28 15:56:37  cheshire
-<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
-
-Revision 1.313  2007/03/28 01:27:32  cheshire
-<rdar://problem/4996439> Unicast DNS polling server every three seconds
-StartLLQPolling was using INIT_UCAST_POLL_INTERVAL instead of LLQ_POLL_INTERVAL for the retry interval
-
-Revision 1.312  2007/03/27 23:48:21  cheshire
-Use mDNS_StopGetDomains(), not mDNS_StopQuery()
-
-Revision 1.311  2007/03/27 22:47:51  cheshire
-Remove unnecessary "*(long*)0 = 0;" to generate crash and stack trace
-
-Revision 1.310  2007/03/24 01:24:13  cheshire
-Add validator for uDNS data structures; fixed crash in RegisterSearchDomains()
-
-Revision 1.309  2007/03/24 00:47:53  cheshire
-<rdar://problem/4983538> serviceRegistrationCallback: Locking Failure! mDNS_busy (1) != mDNS_reentrancy (2)
-Locking in this file is all messed up. For now we'll just work around the issue.
-
-Revision 1.308  2007/03/24 00:41:33  cheshire
-Minor code cleanup (move variable declarations to minimum enclosing scope)
-
-Revision 1.307  2007/03/21 23:06:00  cheshire
-Rename uDNS_HostnameInfo to HostnameInfo; deleted some unused fields
-
-Revision 1.306  2007/03/21 00:30:03  cheshire
-<rdar://problem/4789455> Multiple errors in DNameList-related code
-
-Revision 1.305  2007/03/20 17:07:15  cheshire
-Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-
-Revision 1.304  2007/03/17 00:02:11  cheshire
-<rdar://problem/5067013> NAT-PMP: Lease TTL is being ignored
-
-Revision 1.303  2007/03/10 03:26:44  cheshire
-<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
-
-Revision 1.302  2007/03/10 02:29:58  cheshire
-Added comments about NAT-PMP response functions
-
-Revision 1.301  2007/03/10 02:02:58  cheshire
-<rdar://problem/4961667> uDNS: LLQ refresh response packet causes cached records to be removed from cache
-Eliminate unnecessary "InternalResponseHndlr responseCallback" function pointer
-
-Revision 1.300  2007/03/08 18:56:00  cheshire
-Fixed typo: "&v4.ip.v4.b[0]" is always non-zero (ampersand should not be there)
-
-Revision 1.299  2007/02/28 01:45:47  cheshire
-<rdar://problem/4683261> NAT-PMP: Port mapping refreshes should contain actual public port
-<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
-
-Revision 1.298  2007/02/14 03:16:39  cheshire
-<rdar://problem/4789477> Eliminate unnecessary malloc/free in mDNSCore code
-
-Revision 1.297  2007/02/08 21:12:28  cheshire
-<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
-
-Revision 1.296  2007/01/29 16:03:22  cheshire
-Fix unused parameter warning
-
-Revision 1.295  2007/01/27 03:34:27  cheshire
-Made GetZoneData use standard queries (and cached results);
-eliminated GetZoneData_Callback() packet response handler
-
-Revision 1.294  2007/01/25 00:40:16  cheshire
-Unified CNAME-following functionality into cache management code (which means CNAME-following
-should now also work for mDNS queries too); deleted defunct pktResponseHndlr() routine.
-
-Revision 1.293  2007/01/23 02:56:11  cheshire
-Store negative results in the cache, instead of generating them out of pktResponseHndlr()
-
-Revision 1.292  2007/01/20 01:32:40  cheshire
-Update comments and debugging messages
-
-Revision 1.291  2007/01/20 00:07:02  cheshire
-When we have credentials in the keychain for a domain, we attempt private queries, but
-if the authoritative server is not set up for private queries (i.e. no _dns-query-tls
-or _dns-llq-tls record) then we need to fall back to conventional non-private queries.
-
-Revision 1.290  2007/01/19 23:41:45  cheshire
-Need to clear m->rec.r.resrec.RecordType after calling GetLLQOptData()
-
-Revision 1.289  2007/01/19 23:32:07  cheshire
-Eliminate pointless timenow variable
-
-Revision 1.288  2007/01/19 23:26:08  cheshire
-Right now tcpCallback does not run holding the lock, so no need to drop the lock before invoking callbacks
-
-Revision 1.287  2007/01/19 22:55:41  cheshire
-Eliminate redundant identical parameters to GetZoneData_StartQuery()
-
-Revision 1.286  2007/01/19 21:17:33  cheshire
-StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
-
-Revision 1.285  2007/01/19 18:39:11  cheshire
-Fix a bunch of parameters that should have been declared "const"
-
-Revision 1.284  2007/01/19 18:28:28  cheshire
-Improved debugging messages
-
-Revision 1.283  2007/01/19 18:09:33  cheshire
-Fixed getLLQAtIndex (now called GetLLQOptData):
-1. It incorrectly assumed all EDNS0 OPT records are the same size (it ignored optlen)
-2. It used inefficient memory copying instead of just returning a pointer
-
-Revision 1.282  2007/01/17 22:06:01  cheshire
-Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
-
-Revision 1.281  2007/01/17 21:58:13  cheshire
-For clarity, rename ntaContext field "isPrivate" to "ntaPrivate"
-
-Revision 1.280  2007/01/17 21:46:02  cheshire
-Remove redundant duplicated "isPrivate" field from LLQ_Info
-
-Revision 1.279  2007/01/17 21:35:31  cheshire
-For clarity, rename zoneData_t field "isPrivate" to "zonePrivate"
-
-Revision 1.278  2007/01/16 03:04:16  cheshire
-<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
-Don't cache result of ntaContextSRV(context) in a local variable --
-the macro evaluates to a different result after we clear "context->isPrivate"
-
-Revision 1.277  2007/01/10 22:51:58  cheshire
-<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
-
-Revision 1.276  2007/01/10 02:09:30  cheshire
-Better LogOperation record of keys read from System Keychain
-
-Revision 1.275  2007/01/09 22:37:18  cheshire
-Provide ten-second grace period for deleted keys, to give mDNSResponder
-time to delete host name before it gives up access to the required key.
-
-Revision 1.274  2007/01/09 01:16:32  cheshire
-Improve "ERROR m->CurrentQuestion already set" debugging messages
-
-Revision 1.273  2007/01/08 23:58:00  cheshire
-Don't request regDomain and browseDomains in uDNS_SetupDNSConfig() -- it just ignores those results
-
-Revision 1.272  2007/01/05 08:30:42  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.271  2007/01/05 06:34:03  cheshire
-Improve "ERROR m->CurrentQuestion already set" debugging messages
-
-Revision 1.270  2007/01/05 05:44:33  cheshire
-Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
-so that mDNSPosix embedded clients will compile again
-
-Revision 1.269  2007/01/04 23:11:13  cheshire
-<rdar://problem/4720673> uDNS: Need to start caching unicast records
-When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
-
-Revision 1.268  2007/01/04 22:06:38  cheshire
-Fixed crash in LLQNatMapComplete()
-
-Revision 1.267  2007/01/04 21:45:20  cheshire
-Added mDNS_DropLockBeforeCallback/mDNS_ReclaimLockAfterCallback macros,
-to do additional lock sanity checking around callback invocations
-
-Revision 1.266  2007/01/04 21:01:20  cheshire
-<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
-Only return NXDOMAIN results to clients that request them using kDNSServiceFlagsReturnIntermediates
-
-Revision 1.265  2007/01/04 20:47:17  cheshire
-Fixed crash in CheckForUnreferencedLLQMapping()
-
-Revision 1.264  2007/01/04 20:39:27  cheshire
-Fix locking mismatch
-
-Revision 1.263  2007/01/04 02:39:53  cheshire
-<rdar://problem/4030599> Hostname passed into DNSServiceRegister ignored for Wide-Area service registrations
-
-Revision 1.262  2007/01/04 00:29:25  cheshire
-Covert LogMsg() in GetAuthInfoForName to LogOperation()
-
-Revision 1.261  2006/12/22 20:59:49  cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.260  2006/12/21 00:06:07  cheshire
-Don't need to do mDNSPlatformMemZero() -- mDNS_SetupResourceRecord() does it for us
-
-Revision 1.259  2006/12/20 04:07:36  cheshire
-Remove uDNS_info substructure from AuthRecord_struct
-
-Revision 1.258  2006/12/19 22:49:24  cheshire
-Remove uDNS_info substructure from ServiceRecordSet_struct
-
-Revision 1.257  2006/12/19 02:38:20  cheshire
-Get rid of unnecessary duplicate query ID field from DNSQuestion_struct
-
-Revision 1.256  2006/12/19 02:18:48  cheshire
-Get rid of unnecessary duplicate "void *context" field from DNSQuestion_struct
-
-Revision 1.255  2006/12/16 01:58:31  cheshire
-<rdar://problem/4720673> uDNS: Need to start caching unicast records
-
-Revision 1.254  2006/12/15 19:23:39  cheshire
-Use new DomainNameLengthLimit() function, to be more defensive against malformed
-data received from the network.
-
-Revision 1.253  2006/12/01 07:43:34  herscher
-Fix byte ordering problem for one-shot TCP queries.
-Iterate more intelligently over duplicates in uDNS_ReceiveMsg to avoid spin loops.
-
-Revision 1.252  2006/11/30 23:07:57  herscher
-<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
-
-Revision 1.251  2006/11/28 21:42:11  mkrochma
-Work around a crashing bug that was introduced by uDNS and mDNS code unification
-
-Revision 1.250  2006/11/18 05:01:30  cheshire
-Preliminary support for unifying the uDNS and mDNS code,
-including caching of uDNS answers
-
-Revision 1.249  2006/11/10 07:44:04  herscher
-<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
-
-Revision 1.248  2006/11/08 04:26:53  cheshire
-Fix typo in debugging message
-
-Revision 1.247  2006/10/20 05:35:04  herscher
-<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
-
-Revision 1.246  2006/10/11 19:29:41  herscher
-<rdar://problem/4744553> uDNS: mDNSResponder-111 using 100% CPU
-
-Revision 1.245  2006/10/04 22:21:15  herscher
-Tidy up references to mDNS_struct introduced when the embedded uDNS_info struct was removed.
-
-Revision 1.244  2006/10/04 21:51:27  herscher
-Replace calls to mDNSPlatformTimeNow(m) with m->timenow
-
-Revision 1.243  2006/10/04 21:38:59  herscher
-Remove uDNS_info substructure from DNSQuestion_struct
-
-Revision 1.242  2006/09/27 00:51:46  herscher
-Fix compile error when _LEGACY_NAT_TRAVERSAL_ is not defined
-
-Revision 1.241  2006/09/26 01:54:47  herscher
-<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
-
-Revision 1.240  2006/09/15 21:20:15  cheshire
-Remove uDNS_info substructure from mDNS_struct
-
-Revision 1.239  2006/08/16 02:52:56  mkrochma
-<rdar://problem/4104154> Actually fix it this time
-
-Revision 1.238  2006/08/16 00:31:50  mkrochma
-<rdar://problem/4386944> Get rid of NotAnInteger references
-
-Revision 1.237  2006/08/15 23:38:17  mkrochma
-<rdar://problem/4104154> Requested Public Port field should be set to zero on mapping deletion
-
-Revision 1.236  2006/08/14 23:24:23  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.235  2006/07/30 05:45:36  cheshire
-<rdar://problem/4304215> Eliminate MIN_UCAST_PERIODIC_EXEC
-
-Revision 1.234  2006/07/22 02:58:36  cheshire
-Code was clearing namehash twice instead of namehash and rdatahash
-
-Revision 1.233  2006/07/20 19:46:51  mkrochma
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Fix Private DNS
-
-Revision 1.232  2006/07/15 02:01:29  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Fix broken "empty string" browsing
-
-Revision 1.231  2006/07/05 23:28:22  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-
-Revision 1.230  2006/06/29 03:02:44  cheshire
-<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
-
-Revision 1.229  2006/03/02 22:03:41  cheshire
-<rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
-Refinement: m->rec.r.resrec.RecordType needs to be cleared *every* time around for loop, not just once at the end
-
-Revision 1.228  2006/02/26 00:54:42  cheshire
-Fixes to avoid code generation warning/error on FreeBSD 7
-
-Revision 1.227  2006/01/09 20:47:05  cheshire
-<rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
-
-*/
+ */
 
 #include "uDNS.h"
 
@@ -1338,106 +38,59 @@ Revision 1.227  2006/01/09 20:47:05  cheshire
 // default registration) and possibly one or more recommended automatic browsing domains.
 mDNSexport SearchListElem *SearchList = mDNSNULL;
 
-// Temporary workaround to make ServiceRecordSet list management safe.
-// Ideally a ServiceRecordSet shouldn't be a special entity that's given special treatment by the uDNS code
-// -- it should just be a grouping of records that are treated the same as any other registered records.
-// In that case it may no longer be necessary to keep an explicit list of ServiceRecordSets, which in turn
-// would avoid the perils of modifying that list cleanly while some other piece of code is iterating through it.
-ServiceRecordSet *CurrentServiceRecordSet = mDNSNULL;
-
 // The value can be set to true by the Platform code e.g., MacOSX uses the plist mechanism
 mDNSBool StrictUnicastOrdering = mDNSfalse;
 
+// We keep track of the number of unicast DNS servers and log a message when we exceed 64.
+// Currently the unicast queries maintain a 64 bit map to track the valid DNS servers for that
+// question. Bit position is the index into the DNS server list. This is done so to try all
+// the servers exactly once before giving up. If we could allocate memory in the core, then
+// arbitrary limitation of 64 DNSServers can be removed.
+mDNSu8 NumUnicastDNSServers = 0;
+#define MAX_UNICAST_DNS_SERVERS        64
+
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark - General Utility Functions
 #endif
 
-// Unlink an AuthRecord from the m->ResourceRecords list.
-// This seems risky. Probably some (or maybe all) of the places calling UnlinkAuthRecord to directly
-// remove a record from the list should actually be using mDNS_Deregister/mDNS_Deregister_internal.
-mDNSlocal mStatus UnlinkAuthRecord(mDNS *const m, AuthRecord *const rr)
-       {
-       AuthRecord **list = &m->ResourceRecords;
-       if (m->NewLocalRecords == rr) m->NewLocalRecords = rr->next;
-       if (m->CurrentRecord == rr) m->CurrentRecord = rr->next;
-       while (*list && *list != rr) list = &(*list)->next;
-       if (!*list)
-               {
-               list = &m->DuplicateRecords;
-               while (*list && *list != rr) list = &(*list)->next;
-               }
-       if (*list) { *list = rr->next; rr->next = mDNSNULL; return(mStatus_NoError); }
-       LogMsg("ERROR: UnlinkAuthRecord - no such active record %##s", rr->resrec.name->c);
-       return(mStatus_NoSuchRecord);
-       }
-
-// unlinkSRS is an internal routine (i.e. must be called with the lock already held)
-mDNSlocal void unlinkSRS(mDNS *const m, ServiceRecordSet *srs)
-       {
-       ServiceRecordSet **p;
-
-       if (srs->NATinfo.clientContext)
-               {
-               mDNS_StopNATOperation_internal(m, &srs->NATinfo);
-               srs->NATinfo.clientContext = mDNSNULL;
-               }
-
-       for (p = &m->ServiceRegistrations; *p; p = &(*p)->uDNS_next)
-               if (*p == srs)
-                       {
-                       ExtraResourceRecord *e;
-                       *p = srs->uDNS_next;
-                       if (CurrentServiceRecordSet == srs)
-                               CurrentServiceRecordSet = srs->uDNS_next;
-                       srs->uDNS_next = mDNSNULL;
-                       for (e=srs->Extras; e; e=e->next)
-                               if (UnlinkAuthRecord(m, &e->r))
-                                       LogMsg("unlinkSRS: extra record %##s not found", e->r.resrec.name->c);
-                       return;
-                       }
-       LogMsg("ERROR: unlinkSRS - SRS not found in ServiceRegistrations list %##s", srs->RR_SRV.resrec.name->c);
-       }
-
 // set retry timestamp for record with exponential backoff
-// (for service record sets, use RR_SRV as representative for time checks
-mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr)
+mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mDNSu32 random)
        {
-       mDNSs32 elapsed = m->timenow - rr->LastAPTime;
        rr->LastAPTime = m->timenow;
 
-#if 0
-       // Code for stress-testing registration renewal code
-       if (rr->expire && rr->expire - m->timenow > mDNSPlatformOneSecond * 120)
-               {
-               LogInfo("Adjusting expiry from %d to 120 seconds for %s",
-                       (rr->expire - m->timenow) / mDNSPlatformOneSecond, ARDisplayString(m, rr));
-               rr->expire = m->timenow + mDNSPlatformOneSecond * 120;
-               }
-#endif
-
-       if (rr->expire && rr->expire - m->timenow > mDNSPlatformOneSecond)
+       if (rr->expire && rr->refreshCount < MAX_UPDATE_REFRESH_COUNT)
                {
                mDNSs32 remaining = rr->expire - m->timenow;
-               rr->ThisAPInterval = remaining/2 + mDNSRandom(remaining/10);
-               debugf("SetRecordRetry refresh in %4d of %4d for %s",
-                       rr->ThisAPInterval / mDNSPlatformOneSecond, (rr->expire - m->timenow) / mDNSPlatformOneSecond, ARDisplayString(m, rr));
+               rr->refreshCount++;
+               if (remaining > MIN_UPDATE_REFRESH_TIME)
+                       {
+                       // Refresh at 70% + random (currently it is 0 to 10%)
+                       rr->ThisAPInterval =  7 * (remaining/10) + (random ? random : mDNSRandom(remaining/10));
+                       // Don't update more often than 5 minutes
+                       if (rr->ThisAPInterval < MIN_UPDATE_REFRESH_TIME)
+                               rr->ThisAPInterval = MIN_UPDATE_REFRESH_TIME;
+                       LogInfo("SetRecordRetry refresh in %d of %d for %s",
+                               rr->ThisAPInterval/mDNSPlatformOneSecond, (rr->expire - m->timenow)/mDNSPlatformOneSecond, ARDisplayString(m, rr));
+                       }
+               else
+                       {
+                       rr->ThisAPInterval = MIN_UPDATE_REFRESH_TIME;
+                       LogInfo("SetRecordRetry clamping to min refresh in %d of %d for %s",
+                               rr->ThisAPInterval/mDNSPlatformOneSecond, (rr->expire - m->timenow)/mDNSPlatformOneSecond, ARDisplayString(m, rr));
+                       }
                return;
                }
 
        rr->expire = 0;
 
-       // If at least half our our time interval has elapsed, it's time to double rr->ThisAPInterval
-       // If resulting interval is too small, set to at least INIT_UCAST_POLL_INTERVAL (3 seconds)
-       // If resulting interval is too large, set to at most 30 minutes
-       if (rr->ThisAPInterval / 2 <= elapsed) rr->ThisAPInterval *= 2;
-       if (rr->ThisAPInterval < INIT_UCAST_POLL_INTERVAL || SendErr == mStatus_TransientErr)
-               rr->ThisAPInterval = INIT_UCAST_POLL_INTERVAL;
-       rr->ThisAPInterval += mDNSRandom(rr->ThisAPInterval/20);
-       if (rr->ThisAPInterval > 30 * 60 * mDNSPlatformOneSecond)
-               rr->ThisAPInterval = 30 * 60 * mDNSPlatformOneSecond;
-
-       LogInfo("SetRecordRetry retry   in %4d for %s", rr->ThisAPInterval / mDNSPlatformOneSecond, ARDisplayString(m, rr));
+       rr->ThisAPInterval = rr->ThisAPInterval * QuestionIntervalStep; // Same Retry logic as Unicast Queries
+       if (rr->ThisAPInterval < INIT_RECORD_REG_INTERVAL)
+               rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
+       if (rr->ThisAPInterval > MAX_RECORD_REG_INTERVAL)
+               rr->ThisAPInterval = MAX_RECORD_REG_INTERVAL;
+
+       LogInfo("SetRecordRetry retry in %d ms for %s", rr->ThisAPInterval, ARDisplayString(m, rr));
        }
 
 // ***************************************************************************
@@ -1445,20 +98,26 @@ mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mStatus SendErr)
 #pragma mark - Name Server List Management
 #endif
 
-mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port)
+mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped)
        {
        DNSServer **p = &m->DNSServers;
        DNSServer *tmp = mDNSNULL;
        
+       if ((NumUnicastDNSServers + 1) > MAX_UNICAST_DNS_SERVERS)
+               {
+               LogMsg("mDNS_AddDNSServer: DNS server limit of %d reached, not adding this server", MAX_UNICAST_DNS_SERVERS);
+               return mDNSNULL;
+               }
+
        if (!d) d = (const domainname *)"";
 
-       LogInfo("mDNS_AddDNSServer: Adding %#a for %##s", addr, d->c);
+       LogInfo("mDNS_AddDNSServer: Adding %#a for %##s, InterfaceID %p, scoped %d", addr, d->c, interface, scoped);
        if (m->mDNS_busy != m->mDNS_reentrancy+1)
                LogMsg("mDNS_AddDNSServer: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 
        while (*p)      // Check if we already have this {interface,address,port,domain} tuple registered
                {
-               if ((*p)->interface == interface && (*p)->teststate != DNSServer_Disabled &&
+               if ((*p)->scoped == scoped && (*p)->interface == interface && (*p)->teststate != DNSServer_Disabled &&
                        mDNSSameAddress(&(*p)->addr, addr) && mDNSSameIPPort((*p)->port, port) && SameDomainName(&(*p)->domain, d))
                        {
                        if (!((*p)->flags & DNSServer_FlagDelete)) debugf("Note: DNS Server %#a:%d for domain %##s (%p) registered more than once", addr, mDNSVal16(port), d->c, interface);
@@ -1479,6 +138,8 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
                if (!*p) LogMsg("Error: mDNS_AddDNSServer - malloc");
                else
                        {
+                       NumUnicastDNSServers++;
+                       (*p)->scoped    = scoped;
                        (*p)->interface = interface;
                        (*p)->addr      = *addr;
                        (*p)->port      = port;
@@ -1495,33 +156,29 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
 
 // PenalizeDNSServer is called when the number of queries to the unicast
 // DNS server exceeds MAX_UCAST_UNANSWERED_QUERIES or when we receive an
-// error e.g., SERV_FAIL from DNS server. QueryFail is TRUE if this function
-// is called when we exceed MAX_UCAST_UNANSWERED_QUERIES
-
-mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSBool QueryFail)
+// error e.g., SERV_FAIL from DNS server.
+mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q)
        {
+       DNSServer *new;
        DNSServer *orig = q->qDNSServer;
        
        if (m->mDNS_busy != m->mDNS_reentrancy+1)
                LogMsg("PenalizeDNSServer: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 
+       // This should never happen. Whenever we change DNS server, we change the ID on the question and hence
+       // we should never accept a response after we penalize a DNS server e.g., send two queries, no response,
+       // penalize DNS server and no new servers to pick for the question and hence qDNSServer is NULL. If we
+       // receive a response now, the DNS server can be NULL. But we won't because the ID already has been
+       // changed.
        if (!q->qDNSServer)
                {
-               LogMsg("PenalizeDNSServer: Null DNS server for %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), q->unansweredQueries);
+               LogMsg("PenalizeDNSServer: ERROR!! Null DNS server for %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), q->unansweredQueries);
                goto end;
                }
 
-       if (QueryFail)
-               {
-                       LogInfo("PenalizeDNSServer: DNS server %#a:%d (%##s) %d unanswered queries for %##s (%s)",
-               &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype));
-               }
-       else
-               {
-                       LogInfo("PenalizeDNSServer: DNS server %#a:%d (%##s) Server Error for %##s (%s)",
-               &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q->qname.c, DNSTypeName(q->qtype));
-               }
-
+       LogInfo("PenalizeDNSServer: Penalizing DNS server %#a:%d question (%##s) for question %p %##s (%s) SuppressUnusable %d",
+               &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q, q->qname.c, DNSTypeName(q->qtype),
+               q->SuppressUnusable);
 
        // If strict ordering of unicast servers needs to be preserved, we just lookup
        // the next best match server below
@@ -1552,47 +209,68 @@ mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSBool QueryF
                }
 
 end:
-       q->qDNSServer = GetServerForName(m, &q->qname, q->qDNSServer);
+       new = GetServerForQuestion(m, q);
 
-       if ((q->qDNSServer != orig) && (QueryFail))
+       
+       if (new == orig)
                {
-               // We picked a new server. In the case where QueryFail is true, the code has already incremented the interval
-               // and to compensate that we decrease it here.  When two queries are sent, the QuestionIntervalStep is at 9. We just
-               // move it back to 3 here when we pick a new server. We can't start at 1 because if we have two servers failing, we will never
-               // backoff 
-               //
-               q->ThisQInterval = q->ThisQInterval / QuestionIntervalStep;
-               if (q->qDNSServer) LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to %#a:%d (%##s), Question Interval %u", q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c, q->ThisQInterval);
-               else               LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to <null>, Question Interval %u",        q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
-
+               if (new)
+                       LogMsg("PenalizeDNSServer: ERROR!! GetServerForQuestion returned the same server %#a:%d", &new->addr, 
+                       mDNSVal16(new->port));
+               else
+                       LogMsg("PenalizeDNSServer: ERROR!! GetServerForQuestion returned the same server NULL");
+               q->ThisQInterval = 0;   // Inactivate this question so that we dont bombard the network
                }
-       else 
+       else
                {
-               // if we are here it means,
-               //
-               // 1) We picked the same server, QueryFail = false
-               // 2) We picked the same server, QueryFail = true 
-               // 3) We picked a different server, QueryFail = false
-               //
-               // For all these three cases, ThisQInterval is already set properly
+               // The new DNSServer is set in DNSServerChangeForQuestion
+               DNSServerChangeForQuestion(m, q, new);
 
-               if (q->qDNSServer) 
+               if (new)
                        {
-                       if (q->qDNSServer != orig)
-                               {
-                               LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to %#a:%d (%##s)", q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c);
-                               }
-                               else
+                       LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to %#a:%d (%##s)",
+                               q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c);
+                       // We want to try the next server immediately. As the question may already have backed off, reset
+                       // the interval. We do this only the first time when we try all the DNS servers. Once we reached the end of
+                       // list and retrying all the servers again e.g., at least one server failed to respond in the previous try, we
+                       // use the normal backoff which is done in uDNS_CheckCurrentQuestion when we send the packet out.
+                       if (!q->triedAllServersOnce)
                                {
-                               LogInfo("PenalizeDNSServer: Server for %##s (%s) remains the same at %#a:%d (%##s)", q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c);
+                               q->ThisQInterval = InitialQuestionInterval;
+                               q->LastQTime  = m->timenow - q->ThisQInterval;
+                               SetNextQueryTime(m, q);
                                }
                        }
                else
-                       { 
-                       LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to <null>",        q->qname.c, DNSTypeName(q->qtype));
+                       {
+                       // We don't have any more DNS servers for this question. If some server in the list did not return
+                       // any response, we need to keep retrying till we get a response. uDNS_CheckCurrentQuestion handles
+                       // this case.
+                       //
+                       // If all servers responded with a negative response, We need to do two things. First, generate a
+                       // negative response so that applications get a reply. We also need to reinitialize the DNS servers
+                       // so that when the cache expires, we can restart the query. 
+                       //
+                       // Negative response may be generated in two ways.
+                       //
+                       // 1. AnswerQuestionForDNSServerChanges (called from DNSServerChangedForQuestion) might find some
+                       //    cache entries and answer this question.
+                       // 2. uDNS_CheckCurrentQuestion will create a new cache entry and answer this question
+                       //
+                       // For (1), it might be okay to reinitialize the DNS servers here. But for (2), we can't do it here
+                       // because uDNS_CheckCurrentQuestion will try resending the queries. Hence, to be consistent, we
+                       // defer reintializing the DNS servers up until generating a negative cache response.
+                       //
+                       // Be careful not to touch the ThisQInterval here. For a normal question, when we answer the question
+                       // in AnswerCurrentQuestionWithResourceRecord will set ThisQInterval to MaxQuestionInterval and hence
+                       // the next query will not happen until cache expiry. If it is a long lived question,
+                       // AnswerCurrentQuestionWithResourceRecord will not set it to MaxQuestionInterval. In that case,
+                       // we want the normal backoff to work.
+                       LogInfo("PenalizeDNSServer: Server for %p, %##s (%s) changed to NULL, Interval %d", q, q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
                        }
+               q->unansweredQueries = 0;
+
                }
-       q->unansweredQueries = 0;
        }
 
 // ***************************************************************************
@@ -1690,7 +368,7 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
        info->deltime = 0;
 
        while (*p && (*p) != info) p=&(*p)->next;
-       if (*p) return(mStatus_AlreadyRegistered);
+       if (*p) {LogInfo("mDNS_SetSecretForDomain: Domain %##s Already in list", (*p)->domain.c); return(mStatus_AlreadyRegistered);}
 
        // Caution: Only zero AutoTunnelHostRecord.namestorage and AutoTunnelNAT.clientContext AFTER we've determined that this is a NEW DomainAuthInfo
        // being added to the list. Otherwise we risk smashing our AutoTunnel host records and NATOperation that are already active and in use.
@@ -1699,6 +377,7 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
        info->AutoTunnelTarget    .resrec.RecordType = kDNSRecordTypeUnregistered;
        info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
        info->AutoTunnelService   .resrec.RecordType = kDNSRecordTypeUnregistered;
+       info->AutoTunnel6Record   .resrec.RecordType = kDNSRecordTypeUnregistered;
        info->AutoTunnelNAT.clientContext = mDNSNULL;
        info->next = mDNSNULL;
        *p = info;
@@ -1864,7 +543,7 @@ mDNSexport mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalIn
        {
        NATTraversalInfo **n;
        
-       LogInfo("mDNS_StartNATOperation_internal Protocol %d IntPort %d RequestedPort %d NATLease %d",
+       LogInfo("mDNS_StartNATOperation_internal %p Protocol %d IntPort %d RequestedPort %d NATLease %d", traversal,
                traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease);
 
        // Note: It important that new traversal requests are appended at the *end* of the list, not prepended at the start
@@ -1926,11 +605,11 @@ mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *tra
        if (*ptr) *ptr = (*ptr)->next;          // If we found it, cut this NATTraversalInfo struct from our list
        else
                {
-               LogMsg("mDNS_StopNATOperation: NATTraversalInfo %p not found in list", traversal);
+               LogMsg("mDNS_StopNATOperation_internal: NATTraversalInfo %p not found in list", traversal);
                return(mStatus_BadReferenceErr);
                }
 
-       LogInfo("mDNS_StopNATOperation_internal %d %d %d %d",
+       LogInfo("mDNS_StopNATOperation_internal %p %d %d %d %d", traversal,
                traversal->Protocol, mDNSVal16(traversal->IntPort), mDNSVal16(traversal->RequestedPort), traversal->NATLease);
 
        if (m->CurrentNATTraversal == traversal)
@@ -1966,7 +645,7 @@ mDNSexport mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *tra
        return(mStatus_NoError);
        }
 
-mDNSexport mStatus mDNS_StartNATOperation(mDNS *m, NATTraversalInfo *traversal)
+mDNSexport mStatus mDNS_StartNATOperation(mDNS *const m, NATTraversalInfo *traversal)
        {
        mStatus status;
        mDNS_Lock(m);
@@ -1975,7 +654,7 @@ mDNSexport mStatus mDNS_StartNATOperation(mDNS *m, NATTraversalInfo *traversal)
        return(status);
        }
 
-mDNSexport mStatus mDNS_StopNATOperation(mDNS *m, NATTraversalInfo *traversal)
+mDNSexport mStatus mDNS_StopNATOperation(mDNS *const m, NATTraversalInfo *traversal)
        {
        mStatus status;
        mDNS_Lock(m);
@@ -2056,6 +735,10 @@ mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const
        mDNSu8 *responsePtr = m->omsg.data;
        LLQOptData llqBuf;
 
+       if (q->tcp) { LogMsg("sendChallengeResponse: ERROR!!: question %##s (%s) tcp non-NULL", q->qname.c, DNSTypeName(q->qtype)); return; }
+
+       if (PrivateQuery(q)) { LogMsg("sendChallengeResponse: ERROR!!: Private Query %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
+
        if (q->ntries++ == kLLQ_MAX_TRIES)
                {
                LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s", kLLQ_MAX_TRIES, q->qname.c);
@@ -2084,12 +767,8 @@ mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const
        responsePtr = putLLQ(&m->omsg, responsePtr, q, llq);
        if (responsePtr)
                {
-               mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, q->AuthInfo);
-               if (err)
-                       {
-                       LogMsg("sendChallengeResponse: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err);
-                       if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
-                       }
+               mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL);
+               if (err) { LogMsg("sendChallengeResponse: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err); }
                }
        else StartLLQPolling(m,q);
        }
@@ -2143,7 +822,7 @@ mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const
                // an issue for private LLQs, because we skip parts 2 and 3 of the handshake.  This is related to a bigger
                // problem of the current implementation of TCP LLQ setup: we're not handling state transitions correctly
                // if the server sends back SERVFULL or STATIC.
-               if (q->AuthInfo)
+               if (PrivateQuery(q))
                        {
                        LogInfo("Private LLQ_SecondaryRequest; copying id %08X%08X", llq->id.l[0], llq->id.l[1]);
                        q->id = llq->id;
@@ -2161,7 +840,8 @@ mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const
                }
        }
 
-mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport)
+mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
+       const mDNSAddr *const srcaddr, const mDNSIPPort srcport, DNSQuestion **matchQuestion)
        {
        DNSQuestion pktQ, *q;
        if (msg->h.numQuestions && getQuestion(msg, msg->data, end, 0, &pktQ))
@@ -2179,12 +859,30 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co
                                if (q->state == LLQ_Poll && mDNSSameOpaque16(msg->h.id, q->TargetQID))
                                        {
                                        m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
-                                       debugf("uDNS_recvLLQResponse got poll response; moving to LLQ_InitialRequest for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-                                       q->state         = LLQ_InitialRequest;
+                                       
+                                       // Don't reset the state to IntialRequest as we may write that to the dynamic store
+                                       // and PrefPane might wrongly think that we are "Starting" instead of "Polling". If
+                                       // we are in polling state because of NAT-PMP disabled or DoubleNAT, next LLQNATCallback
+                                       // would kick us back to LLQInitialRequest. So, resetting the state here may not be useful.
+                                       //
+                                       // If we have a good NAT (neither NAT-PMP disabled nor Double-NAT), then we should not be
+                                       // possibly in polling state. To be safe, we want to retry from the start in that case
+                                       // as there may not be another LLQNATCallback
+                                       //
+                                       // NOTE: We can be in polling state if we cannot resolve the SOA record i.e, servAddr is set to
+                                       // all ones. In that case, we would set it in LLQ_InitialRequest as it overrides the NAT-PMP or
+                                       // Double-NAT state.
+                                       if (!mDNSAddressIsOnes(&q->servAddr) && !mDNSIPPortIsZero(m->LLQNAT.ExternalPort) &&
+                                               !m->LLQNAT.Result)
+                                               {
+                                               debugf("uDNS_recvLLQResponse got poll response; moving to LLQ_InitialRequest for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+                                               q->state         = LLQ_InitialRequest;
+                                               }
                                        q->servPort      = zeroIPPort;          // Clear servPort so that startLLQHandshake will retry the GetZoneData processing
                                        q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10);        // Retry LLQ setup in approx 15 minutes
                                        q->LastQTime     = m->timenow;
                                        SetNextQueryTime(m, q);
+                                       *matchQuestion = q;
                                        return uDNS_LLQ_Entire;         // uDNS_LLQ_Entire means flush stale records; assume a large effective TTL
                                        }
                                // Note: In LLQ Event packets, the msg->h.id does not match our q->TargetQID, because in that case the msg->h.id nonce is selected by the server
@@ -2197,6 +895,7 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co
                                        if (ackEnd) mDNSSendDNSMessage(m, &m->omsg, ackEnd, mDNSInterface_Any, q->LocalSocket, srcaddr, srcport, mDNSNULL, mDNSNULL);
                                        m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
                                        debugf("uDNS_LLQ_Events: q->state == LLQ_Established msg->h.id %d q->TargetQID %d", mDNSVal16(msg->h.id), mDNSVal16(q->TargetQID));
+                                       *matchQuestion = q;
                                        return uDNS_LLQ_Events;
                                        }
                                if (opt && mDNSSameOpaque16(msg->h.id, q->TargetQID))
@@ -2215,6 +914,7 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co
                                                        q->ntries = 0;
                                                        }
                                                m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
+                                               *matchQuestion = q;
                                                return uDNS_LLQ_Ignore;
                                                }
                                        if (q->state < LLQ_Established && mDNSSameAddress(srcaddr, &q->servAddr))
@@ -2229,6 +929,7 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co
                                                // are still valid, so this packet should not cause us to do anything that messes with our cache.
                                                // The ack+answers packet gives us the whole truth, so we should handle it by updating our cache
                                                // to match the answers in the packet, and only the answers in the packet.
+                                               *matchQuestion = q;
                                                return (oldstate == LLQ_SecondaryRequest ? uDNS_LLQ_Entire : uDNS_LLQ_Ignore);
                                                }
                                        }
@@ -2236,6 +937,7 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co
                        }
                m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
                }
+       *matchQuestion = mDNSNULL;
        return uDNS_LLQ_Not;
        }
 
@@ -2252,11 +954,10 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
        DNSQuestion *const q = tcpInfo->question;
        tcpInfo_t **backpointer =
                q                 ? &q           ->tcp :
-               tcpInfo->srs      ? &tcpInfo->srs->tcp :
                tcpInfo->rr       ? &tcpInfo->rr ->tcp : mDNSNULL;
        if (backpointer && *backpointer != tcpInfo)
-               LogMsg("tcpCallback: %d backpointer %p incorrect tcpInfo %p question %p srs %p rr %p",
-                       mDNSPlatformTCPGetFD(tcpInfo->sock), *backpointer, tcpInfo, q, tcpInfo->srs, tcpInfo->rr);
+               LogMsg("tcpCallback: %d backpointer %p incorrect tcpInfo %p question %p rr %p",
+                       mDNSPlatformTCPGetFD(tcpInfo->sock), *backpointer, tcpInfo, q, tcpInfo->rr);
 
        if (err) goto exit;
 
@@ -2267,17 +968,12 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
 
                // Defensive coding for <rdar://problem/5546824> Crash in mDNSResponder at GetAuthInfoForName_internal + 366
                // Don't know yet what's causing this, but at least we can be cautious and try to avoid crashing if we find our pointers in an unexpected state
-               if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage)
-                       LogMsg("tcpCallback: ERROR: tcpInfo->srs->RR_SRV.resrec.name %p != &tcpInfo->srs->RR_SRV.namestorage %p",
-                               tcpInfo->srs->RR_SRV.resrec.name, &tcpInfo->srs->RR_SRV.namestorage);
                if (tcpInfo->rr && tcpInfo->rr->resrec.name != &tcpInfo->rr->namestorage)
                        LogMsg("tcpCallback: ERROR: tcpInfo->rr->resrec.name %p != &tcpInfo->rr->namestorage %p",
                                tcpInfo->rr->resrec.name, &tcpInfo->rr->namestorage);
-               if (tcpInfo->srs && tcpInfo->srs->RR_SRV.resrec.name != &tcpInfo->srs->RR_SRV.namestorage) return;
                if (tcpInfo->rr  && tcpInfo->rr->        resrec.name != &tcpInfo->rr->        namestorage) return;
 
-               AuthInfo =  tcpInfo->srs ? GetAuthInfoForName(m, tcpInfo->srs->RR_SRV.resrec.name) :
-                                       tcpInfo->rr  ? GetAuthInfoForName(m, tcpInfo->rr->resrec.name)         : mDNSNULL;
+               AuthInfo =  tcpInfo->rr  ? GetAuthInfoForName(m, tcpInfo->rr->resrec.name)         : mDNSNULL;
 
                // connection is established - send the message
                if (q && q->LongLived && q->state == LLQ_Established)
@@ -2404,32 +1100,34 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
 
                if ((tcpInfo->nread - 2) == tcpInfo->replylen)
                        {
-                       AuthRecord *rr    = tcpInfo->rr;
+                       mDNSBool tls;
                        DNSMessage *reply = tcpInfo->reply;
                        mDNSu8     *end   = (mDNSu8 *)tcpInfo->reply + tcpInfo->replylen;
                        mDNSAddr    Addr  = tcpInfo->Addr;
                        mDNSIPPort  Port  = tcpInfo->Port;
+                       mDNSIPPort srcPort = zeroIPPort;
                        tcpInfo->numReplies++;
                        tcpInfo->reply    = mDNSNULL;   // Detach reply buffer from tcpInfo_t, to make sure client callback can't cause it to be disposed
                        tcpInfo->nread    = 0;
                        tcpInfo->replylen = 0;
                        
                        // If we're going to dispose this connection, do it FIRST, before calling client callback
-                       // Note: Sleep code depends on us clearing *backpointer here -- it uses the clearing of rr->tcp and srs->tcp
+                       // Note: Sleep code depends on us clearing *backpointer here -- it uses the clearing of rr->tcp
                        // as the signal that the DNS deregistration operation with the server has completed, and the machine may now sleep
+                       // If we clear the tcp pointer in the question, mDNSCoreReceiveResponse cannot find a matching question. Hence
+                       // we store the minimal information i.e., the source port of the connection in the question itself.
+                       // Dereference sock before it is disposed in DisposeTCPConn below.
+                       
+                       if (sock->flags & kTCPSocketFlags_UseTLS) tls = mDNStrue;
+                       else tls = mDNSfalse;
+
+                       if (q && q->tcp) {srcPort = q->tcp->SrcPort; q->tcpSrcPort = srcPort;}
+                       
                        if (backpointer)
                                if (!q || !q->LongLived || m->SleepState)
                                        { *backpointer = mDNSNULL; DisposeTCPConn(tcpInfo); }
                        
-                       if (rr && rr->resrec.RecordType == kDNSRecordTypeDeregistering)
-                               {
-                               mDNS_Lock(m);
-                               LogInfo("tcpCallback: CompleteDeregistration %s", ARDisplayString(m, rr));
-                               CompleteDeregistration(m, rr);          // Don't touch rr after this
-                               mDNS_Unlock(m);
-                               }
-                       else
-                               mDNSCoreReceive(m, reply, end, &Addr, Port, (sock->flags & kTCPSocketFlags_UseTLS) ? (mDNSAddr *)1 : mDNSNULL, zeroIPPort, 0);
+                       mDNSCoreReceive(m, reply, end, &Addr, Port, tls ? (mDNSAddr *)1 : mDNSNULL, srcPort, 0);
                        // USE CAUTION HERE: Invoking mDNSCoreReceive may have caused the environment to change, including canceling this operation itself
                        
                        mDNSPlatformMemFree(reply);
@@ -2481,7 +1179,7 @@ exit:
                                        }
                                SetNextQueryTime(m, q);
                                }
-                       else if (q->LastQTime + q->ThisQInterval - m->timenow > (q->LongLived ? LLQ_POLL_INTERVAL : MAX_UCAST_POLL_INTERVAL))
+                       else if (NextQSendTime(q) - m->timenow > (q->LongLived ? LLQ_POLL_INTERVAL : MAX_UCAST_POLL_INTERVAL))
                                {
                                // If we get an error and our next scheduled query for this question is more than the max interval from now,
                                // reset the next query to ensure we wait no longer the maximum interval from now before trying again.
@@ -2507,10 +1205,6 @@ exit:
                                }
                        }
 
-               if (tcpInfo->rr) SetRecordRetry(m, tcpInfo->rr, mStatus_NoError);
-
-               if (tcpInfo->srs) SetRecordRetry(m, &tcpInfo->srs->RR_SRV, mStatus_NoError);
-
                mDNS_Unlock(m);
 
                DisposeTCPConn(tcpInfo);
@@ -2518,12 +1212,17 @@ exit:
        }
 
 mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
-       TCPSocketFlags flags, const mDNSAddr *const Addr, const mDNSIPPort Port,
-       DNSQuestion *const question, ServiceRecordSet *const srs, AuthRecord *const rr)
+       TCPSocketFlags flags, const mDNSAddr *const Addr, const mDNSIPPort Port, domainname *hostname,
+       DNSQuestion *const question, AuthRecord *const rr)
        {
        mStatus err;
        mDNSIPPort srcport = zeroIPPort;
-       tcpInfo_t *info = (tcpInfo_t *)mDNSPlatformMemAllocate(sizeof(tcpInfo_t));
+       tcpInfo_t *info;
+
+       if ((flags & kTCPSocketFlags_UseTLS) && (!hostname || !hostname->c[0]))
+               { LogMsg("MakeTCPConn: TLS connection being setup with NULL hostname"); return mDNSNULL; }
+
+       info = (tcpInfo_t *)mDNSPlatformMemAllocate(sizeof(tcpInfo_t));
        if (!info) { LogMsg("ERROR: MakeTCP - memallocate failed"); return(mDNSNULL); }
        mDNSPlatformMemZero(info, sizeof(tcpInfo_t));
 
@@ -2531,7 +1230,6 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con
        info->sock       = mDNSPlatformTCPSocket(m, flags, &srcport);
        info->requestLen = 0;
        info->question   = question;
-       info->srs        = srs;
        info->rr         = rr;
        info->Addr       = *Addr;
        info->Port       = Port;
@@ -2539,6 +1237,7 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con
        info->replylen   = 0;
        info->nread      = 0;
        info->numReplies = 0;
+       info->SrcPort = srcport;
 
        if (msg)
                {
@@ -2546,8 +1245,8 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con
                mDNSPlatformMemCopy(&info->request, msg, info->requestLen);
                }
 
-       if (!info->sock) { LogMsg("SendServiceRegistration: unable to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); }
-       err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpCallback, info);
+       if (!info->sock) { LogMsg("MakeTCPConn: unable to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); }
+       err = mDNSPlatformTCPConnect(info->sock, Addr, Port, hostname, (question ? question->InterfaceID : mDNSNULL), tcpCallback, info);
 
        // Probably suboptimal here.
        // Instead of returning mDNSNULL here on failure, we should probably invoke the callback with an error code.
@@ -2557,7 +1256,7 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con
 
        // Don't need to log "connection failed" in customer builds -- it happens quite often during sleep, wake, configuration changes, etc.
        if      (err == mStatus_ConnEstablished) { tcpCallback(info->sock, info, mDNStrue, mStatus_NoError); }
-       else if (err != mStatus_ConnPending    ) { LogInfo("MakeTCPConnection: connection failed"); DisposeTCPConn(info); return(mDNSNULL); }
+       else if (err != mStatus_ConnPending    ) { LogInfo("MakeTCPConn: connection failed"); DisposeTCPConn(info); return(mDNSNULL); }
        return(info);
        }
 
@@ -2580,9 +1279,12 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
                return;
                }
 
-       if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort))
+       // Either we don't have NAT-PMP support (ExternalPort is zero) or behind a Double NAT that may or
+       // may not have NAT-PMP support (NATResult is non-zero)
+       if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort) || m->LLQNAT.Result)
                {
-               LogInfo("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+               LogInfo("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s) External Port %d, NAT Result %d",
+                       q->qname.c, DNSTypeName(q->qtype), mDNSVal16(m->LLQNAT.ExternalPort), m->LLQNAT.Result);
                StartLLQPolling(m, q);
                return;
                }
@@ -2600,11 +1302,29 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
                return;
                }
 
-       if (q->AuthInfo)
+       if (PrivateQuery(q))
                {
                if (q->tcp) LogInfo("startLLQHandshake: Disposing existing TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-               if (q->tcp) DisposeTCPConn(q->tcp);
-               q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL);
+               if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
+               if (!q->nta)
+                       {
+                       // Normally we lookup the zone data and then call this function. And we never free the zone data
+                       // for "PrivateQuery". But sometimes this can happen due to some race conditions. When we
+                       // switch networks, we might end up "Polling" the network e.g., we are behind a Double NAT.
+                       // When we poll, we free the zone information as we send the query to the server (See
+                       // PrivateQueryGotZoneData). The NAT callback (LLQNATCallback) may happen soon after that. If we
+                       // are still behind Double NAT, we would have returned early in this function. But we could
+                       // have switched to a network with no NATs and we should get the zone data again.
+                       LogInfo("startLLQHandshake: nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+                       q->nta = StartGetZoneData(m, &q->qname, ZoneServiceLLQ, LLQGotZoneData, q);
+                       return;
+                       }
+               else if (!q->nta->Host.c[0])
+                       {
+                       // This should not happen. If it happens, we print a log and MakeTCPConn will fail if it can't find a hostname
+                       LogMsg("startLLQHandshake: ERROR!!: nta non NULL for %##s (%s) but HostName %d NULL, LongLived %d", q->qname.c, DNSTypeName(q->qtype), q->nta->Host.c[0], q->LongLived);
+                       }
+               q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, &q->nta->Host, q, mDNSNULL);
                if (!q->tcp)
                        q->ThisQInterval = mDNSPlatformOneSecond * 5;   // If TCP failed (transient networking glitch) try again in five seconds
                else
@@ -2674,8 +1394,12 @@ mDNSexport const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr)
                        // If this AutoTunnel is not yet active, start it now (which entails activating its NAT Traversal request,
                        // which will subsequently advertise the appropriate records when the NAT Traversal returns a result)
                        if (!AuthInfo->AutoTunnelNAT.clientContext && m->AutoTunnelHostAddr.b[0])
-                               SetupLocalAutoTunnelInterface_internal(m);
+                               {
+                               LogInfo("GetServiceTarget: Calling SetupLocalAutoTunnelInterface_internal");
+                               SetupLocalAutoTunnelInterface_internal(m, mDNStrue);
+                               }
                        if (AuthInfo->AutoTunnelHostRecord.namestorage.c[0] == 0) return(mDNSNULL);
+                       debugf("GetServiceTarget: Returning %##s", AuthInfo->AutoTunnelHostRecord.namestorage.c);
                        return(&AuthInfo->AutoTunnelHostRecord.namestorage);
                        }
                else
@@ -2698,144 +1422,11 @@ mDNSexport const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr)
                        }
                if (m->StaticHostname.c[0]) return(&m->StaticHostname);
                else GetStaticHostname(m); // asynchronously do reverse lookup for primary IPv4 address
+               LogInfo("GetServiceTarget: Returning NULL for %s", ARDisplayString(m, rr));
                return(mDNSNULL);
                }
        }
 
-// Called with lock held
-mDNSlocal void SendServiceRegistration(mDNS *m, ServiceRecordSet *srs)
-       {
-       mDNSu8 *ptr = m->omsg.data;
-       mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
-       mDNSOpaque16 id;
-       mStatus err = mStatus_NoError;
-       const domainname *target;
-       mDNSu32 i;
-
-       if (m->mDNS_busy != m->mDNS_reentrancy+1)
-               LogMsg("SendServiceRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
-
-       if (mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4))  // Don't know our UpdateServer yet
-               {
-               srs->RR_SRV.LastAPTime = m->timenow;
-               if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 5)
-                       srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5;
-               return;
-               }
-
-       if (srs->state == regState_Registered) srs->state = regState_Refresh;
-
-       id = mDNS_NewMessageID(m);
-       InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags);
-
-       // setup resource records
-       SetNewRData(&srs->RR_PTR.resrec, mDNSNULL, 0);          // Update rdlength, rdestimate, rdatahash
-       SetNewRData(&srs->RR_TXT.resrec, mDNSNULL, 0);          // Update rdlength, rdestimate, rdatahash
-
-       // replace port w/ NAT mapping if necessary
-       if (srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP && !mDNSIPPortIsZero(srs->NATinfo.ExternalPort))
-               srs->RR_SRV.resrec.rdata->u.srv.port = srs->NATinfo.ExternalPort;
-
-       // construct update packet
-       // set zone
-       ptr = putZone(&m->omsg, ptr, end, &srs->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
-       if (!ptr) { err = mStatus_UnknownErr; goto exit; }
-
-       if (srs->TestForSelfConflict)
-               {
-               // update w/ prereq that SRV already exist to make sure previous registration was ours, and delete any stale TXT records
-               if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numPrereqs, &srs->RR_SRV.resrec, 0))) { err = mStatus_UnknownErr; goto exit; }
-               if (!(ptr = putDeleteRRSet(&m->omsg, ptr, srs->RR_TXT.resrec.name, srs->RR_TXT.resrec.rrtype)))            { err = mStatus_UnknownErr; goto exit; }
-               }
-
-       else if (srs->state != regState_Refresh && srs->state != regState_UpdatePending)
-               {
-               // use SRV name for prereq
-               //ptr = putPrereqNameNotInUse(srs->RR_SRV.resrec.name, &m->omsg, ptr, end);
-
-               // For now, until we implement RFC 4701 (DHCID RR) to detect whether an existing record is someone else using the name, or just a
-               // stale echo of our own previous registration before we changed our host name, we just overwrite whatever may have already been there
-               ptr = putDeleteRRSet(&m->omsg, ptr, srs->RR_SRV.resrec.name, kDNSQType_ANY);
-               if (!ptr) { err = mStatus_UnknownErr; goto exit; }
-               }
-
-       //!!!KRS Need to do bounds checking and use TCP if it won't fit!!!
-       if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_PTR.resrec, srs->RR_PTR.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
-
-       for (i = 0; i < srs->NumSubTypes; i++)
-               if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->SubTypes[i].resrec, srs->SubTypes[i].resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
-
-       if (srs->state == regState_UpdatePending) // we're updating the txt record
-               {
-               AuthRecord *txt = &srs->RR_TXT;
-               // delete old RData
-               SetNewRData(&txt->resrec, txt->OrigRData, txt->OrigRDLen);
-               if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->RR_TXT.resrec))) { err = mStatus_UnknownErr; goto exit; }    // delete old rdata
-
-               // add new RData
-               SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen);
-               if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
-               }
-       else
-               if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_TXT.resrec, srs->RR_TXT.resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
-
-       target = GetServiceTarget(m, &srs->RR_SRV);
-       if (!target || target->c[0] == 0)
-               {
-               debugf("SendServiceRegistration - no target for %##s", srs->RR_SRV.resrec.name->c);
-               srs->state = regState_NoTarget;
-               return;
-               }
-
-       if (!SameDomainName(target, &srs->RR_SRV.resrec.rdata->u.srv.target))
-               {
-               AssignDomainName(&srs->RR_SRV.resrec.rdata->u.srv.target, target);
-               SetNewRData(&srs->RR_SRV.resrec, mDNSNULL, 0);          // Update rdlength, rdestimate, rdatahash
-               }
-
-       ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &srs->RR_SRV.resrec, srs->RR_SRV.resrec.rroriginalttl);
-       if (!ptr) { err = mStatus_UnknownErr; goto exit; }
-
-       if (srs->srs_uselease)
-               { ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; } }
-
-       if (srs->state != regState_Refresh && srs->state != regState_DeregDeferred && srs->state != regState_UpdatePending)
-               srs->state = regState_Pending;
-
-       srs->id = id;
-
-       if (srs->Private)
-               {
-               if (srs->tcp) LogInfo("SendServiceRegistration: Disposing existing TCP connection for %s", ARDisplayString(m, &srs->RR_SRV));
-               if (srs->tcp) DisposeTCPConn(srs->tcp);
-               srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL);
-               if (!srs->tcp) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2)
-               else if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 30) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 30;
-               }
-       else
-               {
-               err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name));
-               if (err) debugf("ERROR: SendServiceRegistration - mDNSSendDNSMessage - %d", err);
-               }
-
-       SetRecordRetry(m, &srs->RR_SRV, err);
-       return;
-
-exit:
-       if (err)
-               {
-               LogMsg("SendServiceRegistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err, srs->RR_SRV.resrec.name->c);
-               unlinkSRS(m, srs);
-               srs->state = regState_Unregistered;
-
-               mDNS_DropLockBeforeCallback();
-               srs->ServiceCallback(m, srs, err);
-               mDNS_ReclaimLockAfterCallback();
-               // 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.
-               }
-       }
-
 mDNSlocal const domainname *PUBLIC_UPDATE_SERVICE_TYPE  = (const domainname*)"\x0B_dns-update"     "\x04_udp";
 mDNSlocal const domainname *PUBLIC_LLQ_SERVICE_TYPE     = (const domainname*)"\x08_dns-llq"        "\x04_udp";
 
@@ -2867,6 +1458,8 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question
                {
                debugf("GetZoneData GOT SOA %s", RRDisplayString(m, answer));
                mDNS_StopQuery(m, question);
+               if (question->ThisQInterval != -1)
+                       LogMsg("GetZoneData_QuestionCallback: Question %##s (%s) ThisQInterval %d not -1", question->qname.c, DNSTypeName(question->qtype), question->ThisQInterval);
                if (answer->rdlength)
                        {
                        AssignDomainName(&zd->ZoneName, answer->name);
@@ -2876,21 +1469,33 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question
                        }
                else if (zd->CurrentSOA->c[0])
                        {
-                       zd->CurrentSOA = (domainname *)(zd->CurrentSOA->c + zd->CurrentSOA->c[0]+1);
-                       AssignDomainName(&zd->question.qname, zd->CurrentSOA);
-                       GetZoneData_StartQuery(m, zd, kDNSType_SOA);
+                       DomainAuthInfo *AuthInfo = GetAuthInfoForName(m, zd->CurrentSOA);
+                       if (AuthInfo && AuthInfo->AutoTunnel)
+                               {
+                               // To keep the load on the server down, we don't chop down on
+                               // SOA lookups for AutoTunnels
+                               LogInfo("GetZoneData_QuestionCallback: not chopping labels for %##s", zd->CurrentSOA->c);
+                               zd->ZoneDataCallback(m, mStatus_NoSuchNameErr, zd);
+                               }
+                       else 
+                               {
+                               zd->CurrentSOA = (domainname *)(zd->CurrentSOA->c + zd->CurrentSOA->c[0]+1);
+                               AssignDomainName(&zd->question.qname, zd->CurrentSOA);
+                               GetZoneData_StartQuery(m, zd, kDNSType_SOA);
+                               }
                        }
                else
                        {
                        LogInfo("GetZoneData recursed to root label of %##s without finding SOA", zd->ChildName.c);
                        zd->ZoneDataCallback(m, mStatus_NoSuchNameErr, zd);
-                       mDNSPlatformMemFree(zd);
                        }
                }
        else if (answer->rrtype == kDNSType_SRV)
                {
                debugf("GetZoneData GOT SRV %s", RRDisplayString(m, answer));
                mDNS_StopQuery(m, question);
+               if (question->ThisQInterval != -1)
+                       LogMsg("GetZoneData_QuestionCallback: Question %##s (%s) ThisQInterval %d not -1", question->qname.c, DNSTypeName(question->qtype), question->ThisQInterval);
 // Right now we don't want to fail back to non-encrypted operations
 // If the AuthInfo has the AutoTunnel field set, then we want private or nothing
 // <rdar://problem/5687667> BTMM: Don't fallback to unencrypted operations when SRV lookup fails
@@ -2917,7 +1522,6 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question
                                zd->Port = zeroIPPort;
                                zd->Addr = zeroAddr;
                                zd->ZoneDataCallback(m, mStatus_NoError, zd);
-                               mDNSPlatformMemFree(zd);
                                }
                        }
                }
@@ -2925,6 +1529,8 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question
                {
                debugf("GetZoneData GOT A %s", RRDisplayString(m, answer));
                mDNS_StopQuery(m, question);
+               if (question->ThisQInterval != -1)
+                       LogMsg("GetZoneData_QuestionCallback: Question %##s (%s) ThisQInterval %d not -1", question->qname.c, DNSTypeName(question->qtype), question->ThisQInterval);
                zd->Addr.type  = mDNSAddrType_IPv4;
                zd->Addr.ip.v4 = (answer->rdlength == 4) ? answer->rdata->u.ipv4 : zerov4Addr;
                // In order to simulate firewalls blocking our outgoing TCP connections, returning immediate ICMP errors or TCP resets,
@@ -2937,8 +1543,8 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question
                zd->Addr.ip.v4.b[2] = 0;
                zd->Addr.ip.v4.b[3] = 1;
 #endif
+               // The caller needs to free the memory when done with zone data
                zd->ZoneDataCallback(m, mStatus_NoError, zd);
-               mDNSPlatformMemFree(zd);
                }
        }
 
@@ -2952,7 +1558,10 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt
                debugf("lookupDNSPort %##s", zd->question.qname.c);
                }
 
-       zd->question.ThisQInterval       = -1;          // So that GetZoneData_QuestionCallback() knows whether to cancel this question (Is this necessary?)
+       // CancelGetZoneData can get called at any time. We should stop the question if it has not been
+       // stopped already. A value of -1 for ThisQInterval indicates that the question is not active
+       // yet.
+       zd->question.ThisQInterval       = -1;
        zd->question.InterfaceID         = mDNSInterface_Any;
        zd->question.Target              = zeroAddr;
        //zd->question.qname.c[0]        = 0;                   // Already set
@@ -2962,6 +1571,7 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt
        zd->question.ExpectUnique        = mDNStrue;
        zd->question.ForceMCast          = mDNSfalse;
        zd->question.ReturnIntermed      = mDNStrue;
+       zd->question.SuppressUnusable    = mDNSfalse;
        zd->question.QuestionCallback    = GetZoneData_QuestionCallback;
        zd->question.QuestionContext     = zd;
 
@@ -3016,216 +1626,288 @@ mDNSexport DomainAuthInfo *GetAuthInfoForQuestion(mDNS *m, const DNSQuestion *co
 #pragma mark - host name and interface management
 #endif
 
-// Called in normal client context (lock not held)
-mDNSlocal void CompleteSRVNatMap(mDNS *m, NATTraversalInfo *n)
+mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr);
+mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr);
+mDNSlocal mDNSBool IsRecordMergeable(mDNS *const m, AuthRecord *rr, mDNSs32 time);
+
+// When this function is called, service record is already deregistered. We just
+// have to deregister the PTR and TXT records.
+mDNSlocal void UpdateAllServiceRecords(mDNS *const m, AuthRecord *rr, mDNSBool reg)
        {
-       ServiceRecordSet *srs = (ServiceRecordSet *)n->clientContext;
-       debugf("SRVNatMap complete %.4a IntPort %u ExternalPort %u NATLease %u", &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), n->NATLease);
+       AuthRecord *r, *srvRR;
 
-       if (!srs) { LogMsg("CompleteSRVNatMap called with unknown ServiceRecordSet object"); return; }
-       if (!n->NATLease) return;
+       if (rr->resrec.rrtype != kDNSType_SRV) { LogMsg("UpdateAllServiceRecords:ERROR!! ResourceRecord not a service record %s", ARDisplayString(m, rr)); return; }
 
-       mDNS_Lock(m);
-       if (!mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4))
-               SendServiceRegistration(m, srs);        // non-zero server address means we already have necessary zone data to send update
-       else
+       if (reg && rr->state == regState_NoTarget) { LogMsg("UpdateAllServiceRecords:ERROR!! SRV record %s in noTarget state during registration", ARDisplayString(m, rr)); return; }
+
+       LogInfo("UpdateAllServiceRecords: ResourceRecord %s", ARDisplayString(m, rr));
+
+       for (r = m->ResourceRecords; r; r=r->next)
                {
-               // SHOULD NEVER HAPPEN!
-               LogInfo("ERROR: CompleteSRVNatMap called but srs->SRSUpdateServer.ip.v4 is zero!");
-               srs->state = regState_FetchingZoneData;
-               if (srs->srs_nta) CancelGetZoneData(m, srs->srs_nta); // Make sure we cancel old one before we start a new one
-               srs->srs_nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs);
+               if (!AuthRecord_uDNS(r)) continue;
+               srvRR = mDNSNULL;
+               if (r->resrec.rrtype == kDNSType_PTR)
+                       srvRR = r->Additional1;
+               else if (r->resrec.rrtype == kDNSType_TXT)
+                       srvRR = r->DependentOn;
+               if (srvRR && srvRR->resrec.rrtype != kDNSType_SRV)
+                       LogMsg("UpdateAllServiceRecords: ERROR!! Resource record %s wrong, expecting SRV type", ARDisplayString(m, srvRR));
+               if (srvRR == rr)
+                       {
+                       if (!reg)
+                               {
+                               LogInfo("UpdateAllServiceRecords: deregistering %s", ARDisplayString(m, r));
+                               r->SRVChanged = mDNStrue;
+                               r->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
+                               r->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL;
+                               r->state = regState_DeregPending;
+                               }
+                       else 
+                               {
+                               // Clearing SRVchanged is a safety measure. If our pewvious dereg never
+                               // came back and we had a target change, we are starting fresh
+                               r->SRVChanged = mDNSfalse;
+                               // if it is already registered or in the process of registering, then don't
+                               // bother re-registering. This happens today for non-BTMM domains where the
+                               // TXT and PTR get registered before SRV records because of the delay in
+                               // getting the port mapping. There is no point in re-registering the TXT
+                               // and PTR records. 
+                               if ((r->state == regState_Registered) ||
+                                   (r->state == regState_Pending && r->nta && !mDNSIPv4AddressIsZero(r->nta->Addr.ip.v4)))
+                                       LogInfo("UpdateAllServiceRecords: not registering %s, state %d", ARDisplayString(m, r), r->state);
+                               else
+                                       {
+                                       LogInfo("UpdateAllServiceRecords: registering %s, state %d", ARDisplayString(m, r), r->state);
+                                       ActivateUnicastRegistration(m, r);
+                                       }
+                               }
+                       }
                }
-       mDNS_Unlock(m);
-       }
-
-mDNSlocal void StartSRVNatMap(mDNS *m, ServiceRecordSet *srs)
-       {
-       const mDNSu8 *p = srs->RR_PTR.resrec.name->c;
-       if (p[0]) p += 1 + p[0];
-       if      (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) srs->NATinfo.Protocol = NATOp_MapTCP;
-       else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) srs->NATinfo.Protocol = NATOp_MapUDP;
-       else { LogMsg("StartSRVNatMap: could not determine transport protocol of service %##s", srs->RR_SRV.resrec.name->c); return; }
-       
-       if (srs->NATinfo.clientContext) mDNS_StopNATOperation_internal(m, &srs->NATinfo);
-       // Don't try to set IntPort here --
-       // SendServiceRegistration overwrites srs->RR_SRV.resrec.rdata->u.srv.port with external (mapped) port number
-       //srs->NATinfo.IntPort      = srs->RR_SRV.resrec.rdata->u.srv.port;
-       srs->NATinfo.RequestedPort  = srs->RR_SRV.resrec.rdata->u.srv.port;
-       srs->NATinfo.NATLease       = 0;                // Request default lease
-       srs->NATinfo.clientCallback = CompleteSRVNatMap;
-       srs->NATinfo.clientContext  = srs;
-       mDNS_StartNATOperation_internal(m, &srs->NATinfo);
        }
 
-// Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
-mDNSexport void ServiceRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneData)
+// Called in normal client context (lock not held)
+// Currently only supports SRV records for nat mapping
+mDNSlocal void CompleteRecordNatMap(mDNS *m, NATTraversalInfo *n)
        {
-       ServiceRecordSet *srs = (ServiceRecordSet *)zoneData->ZoneDataContext;
-
-       if (m->mDNS_busy != m->mDNS_reentrancy)
-               LogMsg("ServiceRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
-
-       if (!srs->RR_SRV.resrec.rdata)
-               { LogMsg("ServiceRegistrationGotZoneData: ERROR: srs->RR_SRV.resrec.rdata is NULL"); return; }
-
-       srs->srs_nta = mDNSNULL;
-
-       // Start off assuming we're going to use a lease
-       // If we get an error from the server, and the update port as given in the SRV record is 53, then we'll retry without the lease option
-       srs->srs_uselease = mDNStrue;
-
-       if (err || !zoneData) return;
+       const domainname *target;
+       domainname *srvt;
+       AuthRecord *rr = (AuthRecord *)n->clientContext;
+       debugf("SRVNatMap complete %.4a IntPort %u ExternalPort %u NATLease %u", &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), n->NATLease);
 
-       if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr)) return;
+       if (!rr) { LogMsg("CompleteRecordNatMap called with unknown AuthRecord object"); return; }
+       if (!n->NATLease) { LogMsg("CompleteRecordNatMap No NATLease for %s", ARDisplayString(m, rr)); return; }
 
-       // cache zone data
-       AssignDomainName(&srs->zone, &zoneData->ZoneName);
-       srs->SRSUpdateServer.type = mDNSAddrType_IPv4;
-       srs->SRSUpdateServer      = zoneData->Addr;
-       srs->SRSUpdatePort        = zoneData->Port;
-       srs->Private              = zoneData->ZonePrivate;
+       if (rr->resrec.rrtype != kDNSType_SRV) {LogMsg("CompleteRecordNatMap: Not a service record %s", ARDisplayString(m, rr)); return; }
 
-       srs->RR_SRV.LastAPTime     = m->timenow;
-       srs->RR_SRV.ThisAPInterval = 0;
+       if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) { LogInfo("CompleteRecordNatMap called for %s, Service deregistering", ARDisplayString(m, rr)); return; }
 
-       debugf("ServiceRegistrationGotZoneData My IPv4 %#a%s Server %#a:%d%s for %##s",
-               &m->AdvertisedV4, mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC1918)" : "",
-               &srs->SRSUpdateServer, mDNSVal16(srs->SRSUpdatePort), mDNSAddrIsRFC1918(&srs->SRSUpdateServer) ? " (RFC1918)" : "",
-               srs->RR_SRV.resrec.name->c);
+       if (rr->state == regState_DeregPending) { LogInfo("CompleteRecordNatMap called for %s, record in DeregPending", ARDisplayString(m, rr)); return; }
 
-       // If we have non-zero service port (always?)
-       // and a private address, and update server is non-private
-       // and this service is AutoTarget
-       // then initiate a NAT mapping request. On completion it will do SendServiceRegistration() for us
-       if (!mDNSIPPortIsZero(srs->RR_SRV.resrec.rdata->u.srv.port) &&
-               mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&srs->SRSUpdateServer) &&
-               srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP)
+       // As we free the zone info after registering/deregistering with the server (See hndlRecordUpdateReply),
+       // we need to restart the get zone data and nat mapping request to get the latest mapping result as we can't handle it
+       // at this moment. Restart from the beginning.
+       if (!rr->nta || mDNSIPv4AddressIsZero(rr->nta->Addr.ip.v4))
                {
-               srs->state = regState_NATMap;
-               debugf("ServiceRegistrationGotZoneData StartSRVNatMap");
-               StartSRVNatMap(m, srs);
+               LogInfo("CompleteRecordNatMap called for %s but no zone information!", ARDisplayString(m, rr));
+               // We need to clear out the NATinfo state so that it will result in re-acuqiring the mapping
+               // and hence this callback called again.
+               if (rr->NATinfo.clientContext)
+                       {
+                       mDNS_StopNATOperation_internal(m, &rr->NATinfo);
+                       rr->NATinfo.clientContext = mDNSNULL;
+                       }
+               rr->state = regState_Pending;
+               rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
+               rr->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL;
+               return;
                }
-       else
-               {
-               mDNS_Lock(m);
-               SendServiceRegistration(m, srs);
+
+       mDNS_Lock(m);
+       // Reevaluate the target always as Target could have changed while
+       // we were getting the port mapping (See UpdateOneSRVRecord)
+       target = GetServiceTarget(m, rr);
+       srvt = GetRRDomainNameTarget(&rr->resrec);
+       if (!target || target->c[0] == 0 || mDNSIPPortIsZero(n->ExternalPort))
+               {
+               if (target && target->c[0])
+                       LogInfo("CompleteRecordNatMap - Target %##s for ResourceRecord %##s, ExternalPort %d", target->c, rr->resrec.name->c, mDNSVal16(n->ExternalPort));
+               else
+                       LogInfo("CompleteRecordNatMap - no target for %##s, ExternalPort %d", rr->resrec.name->c, mDNSVal16(n->ExternalPort));
+               if (srvt) srvt->c[0] = 0;
+               rr->state = regState_NoTarget;
+               rr->resrec.rdlength = rr->resrec.rdestimate = 0;
                mDNS_Unlock(m);
+               UpdateAllServiceRecords(m, rr, mDNSfalse);
+               return;
+               }
+       LogInfo("CompleteRecordNatMap - Target %##s for ResourceRecord %##s, ExternalPort %d", target->c, rr->resrec.name->c, mDNSVal16(n->ExternalPort));
+       // This function might get called multiple times during a network transition event. Previosuly, we could
+       // have put the SRV record in NoTarget state above and deregistered all the other records. When this
+       // function gets called again with a non-zero ExternalPort, we need to set the target and register the
+       // other records again.
+       if (srvt && !SameDomainName(srvt, target))
+               {
+               AssignDomainName(srvt, target);
+               SetNewRData(&rr->resrec, mDNSNULL, 0);          // Update rdlength, rdestimate, rdatahash
                }
+
+       // SRVChanged is set when when the target of the SRV record changes (See UpdateOneSRVRecord).
+       // As a result of the target change, we might register just that SRV Record if it was
+       // previously registered and we have a new target OR deregister SRV (and the associated
+       // PTR/TXT records) if we don't have a target anymore. When we get a response from the server,
+       // SRVChanged state tells that we registered/deregistered because of a target change
+       // and hence handle accordingly e.g., if we deregistered, put the records in NoTarget state OR
+       // if we registered then put it in Registered state.
+       //
+       // Here, we are registering all the records again from the beginning. Treat this as first time
+       // registration rather than a temporary target change.
+       rr->SRVChanged = mDNSfalse;
+
+       // We want IsRecordMergeable to check whether it is a record whose update can be
+       // sent with others. We set the time before we call IsRecordMergeable, so that
+       // it does not fail this record based on time. We are interested in other checks
+       // at this time
+       rr->state = regState_Pending;
+       rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
+       rr->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL;
+       if (IsRecordMergeable(m, rr, m->timenow + MERGE_DELAY_TIME))
+               // Delay the record registration by MERGE_DELAY_TIME so that we can merge them
+               // into one update
+               rr->LastAPTime += MERGE_DELAY_TIME;
+       mDNS_Unlock(m);
+       // We call this always even though it may not be necessary always e.g., normal registration
+       // process where TXT and PTR gets registered followed by the SRV record after it gets
+       // the port mapping. In that case, UpdateAllServiceRecords handles the optimization. The
+       // update of TXT and PTR record is required if we entered noTargetState before as explained
+       // above.
+       UpdateAllServiceRecords(m, rr, mDNStrue);
        }
 
-mDNSlocal void SendServiceDeregistration(mDNS *m, ServiceRecordSet *srs)
+mDNSlocal void StartRecordNatMap(mDNS *m, AuthRecord *rr)
        {
-       mDNSOpaque16 id;
-       mDNSu8 *ptr = m->omsg.data;
-       mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
-       mStatus err = mStatus_UnknownErr;
-       mDNSu32 i;
+       const mDNSu8 *p;
+       mDNSu8 protocol;
 
-       if (mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4))  // Don't know our UpdateServer yet
+       if (rr->resrec.rrtype != kDNSType_SRV)
                {
-               srs->RR_SRV.LastAPTime = m->timenow;
-               if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 5)
-                       srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5;
+               LogInfo("StartRecordNatMap: Resource Record %##s type %d, not supported", rr->resrec.name->c, rr->resrec.rrtype);
                return;
                }
+       p = rr->resrec.name->c;
+       //Assume <Service Instance>.<App Protocol>.<Transport protocol>.<Name>
+       // Skip the first two labels to get to the transport protocol
+       if (p[0]) p += 1 + p[0];
+       if (p[0]) p += 1 + p[0];
+       if      (SameDomainLabel(p, (mDNSu8 *)"\x4" "_tcp")) protocol = NATOp_MapTCP;
+       else if (SameDomainLabel(p, (mDNSu8 *)"\x4" "_udp")) protocol = NATOp_MapUDP;
+       else { LogMsg("StartRecordNatMap: could not determine transport protocol of service %##s", rr->resrec.name->c); return; }
+       
+       if (rr->NATinfo.clientContext) mDNS_StopNATOperation_internal(m, &rr->NATinfo);
+       rr->NATinfo.Protocol       = protocol;
+       rr->NATinfo.IntPort        = rr->resrec.rdata->u.srv.port;
+       rr->NATinfo.RequestedPort  = rr->resrec.rdata->u.srv.port;
+       rr->NATinfo.NATLease       = 0;         // Request default lease
+       rr->NATinfo.clientCallback = CompleteRecordNatMap;
+       rr->NATinfo.clientContext  = rr;
+       mDNS_StartNATOperation_internal(m, &rr->NATinfo);
+       }
 
-       id = mDNS_NewMessageID(m);
-       InitializeDNSMessage(&m->omsg.h, id, UpdateReqFlags);
-
-       // put zone
-       ptr = putZone(&m->omsg, ptr, end, &srs->zone, mDNSOpaque16fromIntVal(srs->RR_SRV.resrec.rrclass));
-       if (!ptr) { LogMsg("ERROR: SendServiceDeregistration - putZone"); err = mStatus_UnknownErr; goto exit; }
-
-       if (!(ptr = putDeleteAllRRSets(&m->omsg, ptr, srs->RR_SRV.resrec.name))) { err = mStatus_UnknownErr; goto exit; } // this deletes SRV, TXT, and Extras
-       if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->RR_PTR.resrec))) { err = mStatus_UnknownErr; goto exit; }
-       for (i = 0; i < srs->NumSubTypes; i++)
-               if (!(ptr = putDeletionRecord(&m->omsg, ptr, &srs->SubTypes[i].resrec))) { err = mStatus_UnknownErr; goto exit; }
-
-       srs->id    = id;
-       srs->state = regState_DeregPending;
-       srs->RR_SRV.expire = 0;         // Indicate that we have no active registration any more
-
-       if (srs->Private)
-               {
-               LogInfo("SendServiceDeregistration TCP %p %s", srs->tcp, ARDisplayString(m, &srs->RR_SRV));
-               if (srs->tcp) LogInfo("SendServiceDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m, &srs->RR_SRV));
-               if (srs->tcp) DisposeTCPConn(srs->tcp);
-               srs->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, srs, mDNSNULL);
-               if (!srs->tcp) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2)
-               else if (srs->RR_SRV.ThisAPInterval < mDNSPlatformOneSecond * 30) srs->RR_SRV.ThisAPInterval = mDNSPlatformOneSecond * 30;
-               }
-       else
+// Unlink an Auth Record from the m->ResourceRecords list.
+// When a resource record enters regState_NoTarget initially, mDNS_Register_internal
+// does not initialize completely e.g., it cannot check for duplicates etc. The resource
+// record is temporarily left in the ResourceRecords list so that we can initialize later
+// when the target is resolvable. Similarly, when host name changes, we enter regState_NoTarget
+// and we do the same.
+mDNSlocal mStatus UnlinkResourceRecord(mDNS *const m, AuthRecord *const rr)
+       {
+       AuthRecord **list = &m->ResourceRecords;
+       while (*list && *list != rr) list = &(*list)->next;
+       if (*list)
                {
-               err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &srs->SRSUpdateServer, srs->SRSUpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, srs->RR_SRV.resrec.name));
-               if (err && err != mStatus_TransientErr) { debugf("ERROR: SendServiceDeregistration - mDNSSendDNSMessage - %d", err); goto exit; }
+               *list = rr->next;
+               rr->next = mDNSNULL;
+               return(mStatus_NoError);
                }
+       LogMsg("UnlinkResourceRecord:ERROR!! - no such active record %##s", rr->resrec.name->c);
+       return(mStatus_NoSuchRecord);
+       }
 
-       SetRecordRetry(m, &srs->RR_SRV, err);
-       return;
-
-exit:
-       if (err)
-               {
-               LogMsg("SendServiceDeregistration ERROR formatting message %d!! Permanently abandoning service registration %##s", err, srs->RR_SRV.resrec.name->c);
-               unlinkSRS(m, srs);
-               srs->state = regState_Unregistered;
-               }
+// We need to go through mDNS_Register again as we did not complete the 
+// full initialization last time e.g., duplicate checks.
+// After we register, we will be in regState_GetZoneData.
+mDNSlocal void RegisterAllServiceRecords(mDNS *const m, AuthRecord *rr)
+       {
+       LogInfo("RegisterAllServiceRecords: Service Record %##s", rr->resrec.name->c);
+       // First Register the service record, we do this differently from other records because
+       // when it entered NoTarget state, it did not go through complete initialization
+       rr->SRVChanged = mDNSfalse;
+       UnlinkResourceRecord(m, rr);
+       mDNS_Register_internal(m, rr);
+       // Register the other records
+       UpdateAllServiceRecords(m, rr, mDNStrue);
        }
 
 // Called with lock held
-mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
+mDNSlocal void UpdateOneSRVRecord(mDNS *m, AuthRecord *rr)
        {
-       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 *curtarget = &srs->RR_SRV.resrec.rdata->u.srv.target;
-       const domainname *const nt = GetServiceTarget(m, &srs->RR_SRV);
+       domainname *curtarget = &rr->resrec.rdata->u.srv.target;
+       const domainname *const nt = GetServiceTarget(m, rr);
        const domainname *const newtarget = nt ? nt : (domainname*)"";
-       mDNSBool TargetChanged = (newtarget->c[0] && srs->state == regState_NoTarget) || !SameDomainName(curtarget, newtarget);
-       mDNSBool HaveZoneData  = !mDNSIPv4AddressIsZero(srs->SRSUpdateServer.ip.v4);
+       mDNSBool TargetChanged = (newtarget->c[0] && rr->state == regState_NoTarget) || !SameDomainName(curtarget, newtarget);
+       mDNSBool HaveZoneData  = rr->nta && !mDNSIPv4AddressIsZero(rr->nta->Addr.ip.v4);
 
        // 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 external port
        // We were not behind a NAT and now we are
 
-       mDNSIPPort port        = srs->RR_SRV.resrec.rdata->u.srv.port;
-       mDNSBool NowNeedNATMAP = (srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP && !mDNSIPPortIsZero(port) && mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && !mDNSAddrIsRFC1918(&srs->SRSUpdateServer));
-       mDNSBool WereBehindNAT = (srs->NATinfo.clientContext != mDNSNULL);
-       mDNSBool PortWasMapped = (srs->NATinfo.clientContext && !mDNSSameIPPort(srs->NATinfo.RequestedPort, port));             // I think this is always false -- SC Sept 07
+       mDNSIPPort port        = rr->resrec.rdata->u.srv.port;
+       mDNSBool NowNeedNATMAP = (rr->AutoTarget == Target_AutoHostAndNATMAP && !mDNSIPPortIsZero(port) && mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && rr->nta && !mDNSAddrIsRFC1918(&rr->nta->Addr));
+       mDNSBool WereBehindNAT = (rr->NATinfo.clientContext != mDNSNULL);
+       mDNSBool PortWasMapped = (rr->NATinfo.clientContext && !mDNSSameIPPort(rr->NATinfo.RequestedPort, port));               // I think this is always false -- SC Sept 07
        mDNSBool NATChanged    = (!WereBehindNAT && NowNeedNATMAP) || (!NowNeedNATMAP && PortWasMapped);
 
-       debugf("UpdateSRV %##s newtarget %##s TargetChanged %d HaveZoneData %d port %d NowNeedNATMAP %d WereBehindNAT %d PortWasMapped %d NATChanged %d",
-               srs->RR_SRV.resrec.name->c, newtarget,
+       (void)HaveZoneData; //unused
+
+       LogInfo("UpdateOneSRVRecord: Resource Record %s TargetChanged %d, NewTarget %##s", ARDisplayString(m, rr), TargetChanged, nt->c);
+
+       debugf("UpdateOneSRVRecord: %##s newtarget %##s TargetChanged %d HaveZoneData %d port %d NowNeedNATMAP %d WereBehindNAT %d PortWasMapped %d NATChanged %d",
+               rr->resrec.name->c, newtarget,
                TargetChanged, HaveZoneData, mDNSVal16(port), NowNeedNATMAP, WereBehindNAT, PortWasMapped, NATChanged);
 
        if (m->mDNS_busy != m->mDNS_reentrancy+1)
-               LogMsg("UpdateSRV: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+               LogMsg("UpdateOneSRVRecord: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 
        if (!TargetChanged && !NATChanged) return;
 
-       switch(srs->state)
+       // If we are deregistering the record, then ignore any NAT/Target change.
+       if (rr->resrec.RecordType == kDNSRecordTypeDeregistering)
+               {
+               LogInfo("UpdateOneSRVRecord: Deregistering record, Ignoring TargetChanged %d, NATChanged %d for %##s, state %d", TargetChanged, NATChanged,
+                       rr->resrec.name->c, rr->state);
+               return;
+               }
+
+       if (newtarget)
+               LogInfo("UpdateOneSRVRecord: TargetChanged %d, NATChanged %d for %##s, state %d, newtarget %##s", TargetChanged, NATChanged, rr->resrec.name->c, rr->state, newtarget->c);
+       else
+               LogInfo("UpdateOneSRVRecord: TargetChanged %d, NATChanged %d for %##s, state %d, null newtarget", TargetChanged, NATChanged, rr->resrec.name->c, rr->state);
+       switch(rr->state)
                {
-               case regState_FetchingZoneData:
-               case regState_DeregPending:
-               case regState_DeregDeferred:
-               case regState_Unregistered:
                case regState_NATMap:
-               case regState_ExtraQueued:
                        // In these states, the SRV has either not yet been registered (it will get up-to-date information when it is)
-                       // or is in the process of, or has already been, deregistered
+                       // or is in the process of, or has already been, deregistered. This assumes that whenever we transition out
+                       // of this state, we need to look at the target again.
                        return;
 
-               case regState_Pending:
-               case regState_Refresh:
                case regState_UpdatePending:
-                       // let the in-flight operation complete before updating
-                       srs->SRVUpdateDeferred = mDNStrue;
+                       // We are getting a Target change/NAT change while the SRV record is being updated ?
+                       // let us not do anything for now.
                        return;
 
                case regState_NATError:
@@ -3233,61 +1915,75 @@ mDNSlocal void UpdateSRV(mDNS *m, ServiceRecordSet *srs)
                        // if nat changed, register if we have a target (below)
 
                case regState_NoTarget:
-                       if (newtarget->c[0])
+                       if (!newtarget->c[0])
                                {
-                               debugf("UpdateSRV: %s service %##s", HaveZoneData ? (NATChanged && NowNeedNATMAP ? "Starting Port Map for" : "Registering") : "Getting Zone Data for", srs->RR_SRV.resrec.name->c);
-                               if (!HaveZoneData)
-                                       {
-                                       srs->state = regState_FetchingZoneData;
-                                       if (srs->srs_nta) CancelGetZoneData(m, srs->srs_nta); // Make sure we cancel old one before we start a new one
-                                       srs->srs_nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs);
-                                       }
-                               else
-                                       {
-                                       if (srs->NATinfo.clientContext && (NATChanged || !NowNeedNATMAP))
-                                               {
-                                               mDNS_StopNATOperation_internal(m, &srs->NATinfo);
-                                               srs->NATinfo.clientContext = mDNSNULL;
-                                               }
-                                       if (NATChanged && NowNeedNATMAP && srs->RR_SRV.AutoTarget == Target_AutoHostAndNATMAP)
-                                               { srs->state = regState_NATMap; StartSRVNatMap(m, srs); }
-                                       else SendServiceRegistration(m, srs);
-                                       }
+                               LogInfo("UpdateOneSRVRecord: No target yet for Resource Record %s", ARDisplayString(m, rr));
+                               return;
                                }
+                       RegisterAllServiceRecords(m , rr);
                        return;
-
+               case regState_DeregPending:
+                       // We are in DeregPending either because the service was deregistered from above or we handled
+                       // a NAT/Target change before and sent the deregistration below. There are a few race conditions
+                       // possible
+                       //
+                       // 1. We are handling a second NAT/Target change while the first dereg is in progress. It is possible
+                       //    that first dereg never made it through because there was no network connectivity e.g., disconnecting
+                       //    from network triggers this function due to a target change and later connecting to the network
+                       //    retriggers this function but the deregistration never made it through yet. Just fall through.
+                       //    If there is a target register otherwise deregister.
+                       //
+                       // 2. While we sent the dereg during a previous NAT/Target change, uDNS_DeregisterRecord gets
+                       //    called as part of service deregistration. When the response comes back, we call
+                       //    CompleteDeregistration rather than handle NAT/Target change because the record is in
+                       //    kDNSRecordTypeDeregistering state.
+                       //
+                       // 3. If the upper layer deregisters the service, we check for kDNSRecordTypeDeregistering both
+                       //    here in this function to avoid handling NAT/Target change and in hndlRecordUpdateReply to call
+                       //    CompleteDeregistration instead of handling NAT/Target change. Hence, we are not concerned
+                       //    about that case here.
+                       //
+                       // We just handle case (1) by falling through
+               case regState_Pending:
+               case regState_Refresh:
                case regState_Registered:
                        // 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.state = regState_ExtraQueued;        // extra will be re-registed if the service is re-registered
-                       srs->SRVChanged = mDNStrue;
-                       SendServiceDeregistration(m, srs);
+                       rr->SRVChanged = mDNStrue;
+                       rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
+                       rr->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL;
+                       if (newtarget->c[0])
+                               {
+                               LogInfo("UpdateOneSRVRecord: SRV record changed for service %##s, registering with new target %##s",
+                                       rr->resrec.name->c, newtarget->c);
+                               rr->state = regState_Pending;
+                               }
+                       else
+                               {
+                               LogInfo("UpdateOneSRVRecord: SRV record changed for service %##s de-registering", rr->resrec.name->c);
+                               rr->state = regState_DeregPending;
+                               UpdateAllServiceRecords(m, rr, mDNSfalse);
+                               }
                        return;
-
-               default: LogMsg("UpdateSRV: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
+               case regState_Unregistered:
+               default: LogMsg("UpdateOneSRVRecord: Unknown state %d for %##s", rr->state, rr->resrec.name->c);
                }
        }
 
-// Called with lock held
-mDNSlocal void UpdateSRVRecords(mDNS *m)
+mDNSexport void UpdateAllSRVRecords(mDNS *m)
        {
-       debugf("UpdateSRVRecords%s", m->SleepState ? " (ignored due to SleepState)" : "");
-       if (m->SleepState) return;
+       m->NextSRVUpdate = 0;
+       LogInfo("UpdateAllSRVRecords %d", m->SleepState);
 
-       if (CurrentServiceRecordSet)
-               LogMsg("UpdateSRVRecords ERROR CurrentServiceRecordSet already set");
-       CurrentServiceRecordSet = m->ServiceRegistrations;
-       
-       while (CurrentServiceRecordSet)
+       if (m->CurrentRecord)
+               LogMsg("UpdateAllSRVRecords ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
+       m->CurrentRecord = m->ResourceRecords;
+       while (m->CurrentRecord)
                {
-               ServiceRecordSet *s = CurrentServiceRecordSet;
-               CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
-               UpdateSRV(m, s);
+               AuthRecord *rptr = m->CurrentRecord;
+               m->CurrentRecord = m->CurrentRecord->next;
+               if (AuthRecord_uDNS(rptr) && rptr->resrec.rrtype == kDNSType_SRV)
+                       UpdateOneSRVRecord(m, rptr);
                }
-
-       mDNS_DropLockBeforeCallback();          // mDNS_SetFQDN expects to be called without the lock held, so we emulate that here
-       mDNS_SetFQDN(m);
-       mDNS_ReclaimLockAfterCallback();
        }
 
 // Forward reference: AdvertiseHostname references HostnameCallback, and HostnameCallback calls AdvertiseHostname
@@ -3307,7 +2003,7 @@ mDNSlocal void hostnameGetPublicAddressCallback(mDNS *m, NATTraversalInfo *n)
                if (h->arv4.resrec.RecordType)
                        {
                        if (mDNSSameIPv4Address(h->arv4.resrec.rdata->u.ipv4, n->ExternalAddress)) return;      // If address unchanged, do nothing
-                       LogInfo("Updating hostname %##s IPv4 from %.4a to %.4a (NAT gateway's external address)",
+                       LogInfo("Updating hostname %p %##s IPv4 from %.4a to %.4a (NAT gateway's external address)",n,
                                h->arv4.resrec.name->c, &h->arv4.resrec.rdata->u.ipv4, &n->ExternalAddress);
                        mDNS_Deregister(m, &h->arv4);   // mStatus_MemFree callback will re-register with new address
                        }
@@ -3412,7 +2108,7 @@ mDNSlocal void HostnameCallback(mDNS *const m, AuthRecord *const rr, mStatus res
 
        // register any pending services that require a target
        mDNS_Lock(m);
-       UpdateSRVRecords(m);
+       m->NextSRVUpdate = NonZeroTime(m->timenow);
        mDNS_Unlock(m);
 
        // Deliver success to client
@@ -3436,30 +2132,34 @@ mDNSlocal void FoundStaticHostname(mDNS *const m, DNSQuestion *question, const R
 
        (void)question;
 
-       debugf("FoundStaticHostname: %##s -> %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "added" : "removed");
-       if (AddRecord && !SameDomainName(pktname, storedname))
+       if (answer->rdlength != 0)
+               LogInfo("FoundStaticHostname: question %##s -> answer %##s (%s)", question->qname.c, answer->rdata->u.name.c, AddRecord ? "ADD" : "RMV");
+       else
+               LogInfo("FoundStaticHostname: question %##s -> answer NULL (%s)", question->qname.c, AddRecord ? "ADD" : "RMV");
+
+       if (AddRecord && answer->rdlength != 0 && !SameDomainName(pktname, storedname))
                {
                AssignDomainName(storedname, pktname);
                while (h)
                        {
-                       if (h->arv4.state == regState_FetchingZoneData || h->arv4.state == regState_Pending || h->arv4.state == regState_NATMap ||
-                               h->arv6.state == regState_FetchingZoneData || h->arv6.state == regState_Pending)
+                       if (h->arv4.state == regState_Pending || h->arv4.state == regState_NATMap || h->arv6.state == regState_Pending)
                                {
                                // 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->NextSRVUpdate = NonZeroTime(m->timenow + 5 * mDNSPlatformOneSecond);
+                               debugf("FoundStaticHostname: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
                                return;
                                }
                        h = h->next;
                        }
                mDNS_Lock(m);
-               UpdateSRVRecords(m);
+               m->NextSRVUpdate = NonZeroTime(m->timenow);
                mDNS_Unlock(m);
                }
        else if (!AddRecord && SameDomainName(pktname, storedname))
                {
                mDNS_Lock(m);
                storedname->c[0] = 0;
-               UpdateSRVRecords(m);
+               m->NextSRVUpdate = NonZeroTime(m->timenow);
                mDNS_Unlock(m);
                }
        }
@@ -3488,6 +2188,7 @@ mDNSlocal void GetStaticHostname(mDNS *m)
        q->ExpectUnique     = mDNSfalse;
        q->ForceMCast       = mDNSfalse;
        q->ReturnIntermed   = mDNStrue;
+       q->SuppressUnusable = mDNSfalse;
        q->QuestionCallback = FoundStaticHostname;
        q->QuestionContext  = mDNSNULL;
 
@@ -3541,7 +2242,8 @@ mDNSexport void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn)
                if (f6) mDNS_Deregister_internal(m, &hi->arv6, mDNS_Dereg_normal);
                // When both deregistrations complete we'll free the memory in the mStatus_MemFree callback
                }
-       UpdateSRVRecords(m);
+       if (!m->mDNS_busy) LogMsg("mDNS_RemoveDynDNSHostName: ERROR: Lock not held");
+       m->NextSRVUpdate = NonZeroTime(m->timenow);
        }
 
 // Currently called without holding the lock
@@ -3559,8 +2261,6 @@ mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, co
 
        mDNS_Lock(m);
 
-       if (v4addr && !mDNSv4AddressIsLinkLocal(&v4addr->ip.v4)) v6addr = mDNSNULL;
-
        v4Changed     = !mDNSSameIPv4Address(m->AdvertisedV4.ip.v4, v4addr ? v4addr->ip.v4 : zerov4Addr);
        v6Changed     = !mDNSSameIPv6Address(m->AdvertisedV6.ip.v6, v6addr ? v6addr->ip.v6 : zerov6Addr);
        RouterChanged = !mDNSSameIPv4Address(m->Router.ip.v4,       router ? router->ip.v4 : zerov4Addr);
@@ -3626,7 +2326,7 @@ mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, co
                if (m->ReverseMap.ThisQInterval != -1) mDNS_StopQuery_internal(m, &m->ReverseMap);
                m->StaticHostname.c[0] = 0;
                
-               UpdateSRVRecords(m); // Will call GetStaticHostname if needed
+               m->NextSRVUpdate = NonZeroTime(m->timenow);
                
 #if APPLE_OSX_mDNSResponder
                if (RouterChanged)      uuid_generate(m->asl_uuid);
@@ -3655,7 +2355,7 @@ mDNSlocal mStatus ParseTSIGError(mDNS *const m, const DNSMessage *const msg, con
                {
                ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
                if (!ptr) goto finish;
-               if (m->rec.r.resrec.rrtype == kDNSType_TSIG)
+               if (m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && m->rec.r.resrec.rrtype == kDNSType_TSIG)
                        {
                        mDNSu32 macsize;
                        mDNSu8 *rd = m->rec.r.resrec.rdata->u.data;
@@ -3733,342 +2433,723 @@ mDNSlocal mStatus checkUpdateResult(mDNS *const m, const domainname *const displ
                }
        else
                {
-               LogMsg("Update %##s failed with rcode %d", displayname->c, rcode);
-               return mStatus_UnknownErr;
+               LogMsg("Update %##s failed with rcode %d", displayname->c, rcode);
+               return mStatus_UnknownErr;
+               }
+       }
+
+// We add three Additional Records for unicast resource record registrations
+// which is a function of AuthInfo and AutoTunnel properties
+mDNSlocal mDNSu32 RRAdditionalSize(mDNS *const m, DomainAuthInfo *AuthInfo)
+       {
+       mDNSu32 leaseSize, hinfoSize, tsigSize;
+       mDNSu32 rr_base_size = 10; // type (2) class (2) TTL (4) rdlength (2)
+
+       // OPT RR : Emptyname(.) + base size + rdataOPT
+       leaseSize = 1 + rr_base_size + sizeof(rdataOPT);
+
+       // HINFO: Resource Record Name + base size + RDATA
+       // HINFO is added only for autotunnels
+       hinfoSize = 0;
+       if (AuthInfo && AuthInfo->AutoTunnel)
+               hinfoSize = (m->hostlabel.c[0] + 1) + DomainNameLength(&AuthInfo->domain) +
+                       rr_base_size + (2 + m->HIHardware.c[0] + m->HISoftware.c[0]);
+
+       //TSIG: Resource Record Name + base size + RDATA
+       // RDATA:
+    //         Algorithm name: hmac-md5.sig-alg.reg.int (8+7+3+3 + 5 bytes for length = 26 bytes)
+    //         Time: 6 bytes
+       //      Fudge: 2 bytes
+    //         Mac Size: 2 bytes
+       //      Mac: 16 bytes
+       //      ID: 2 bytes
+    //         Error: 2 bytes
+    //         Len: 2 bytes
+       //      Total: 58 bytes 
+       tsigSize = 0;
+       if (AuthInfo) tsigSize = DomainNameLength(&AuthInfo->keyname) + rr_base_size + 58;
+
+       return (leaseSize + hinfoSize + tsigSize);
+       }
+
+//Note: Make sure that RREstimatedSize is updated accordingly if anything that is done here
+//would modify rdlength/rdestimate
+mDNSlocal mDNSu8* BuildUpdateMessage(mDNS *const m, mDNSu8 *ptr, AuthRecord *rr, mDNSu8 *limit)
+       {
+       //If this record is deregistering, then just send the deletion record
+       if (rr->state == regState_DeregPending)
+               {
+               rr->expire = 0;         // Indicate that we have no active registration any more
+               ptr = putDeletionRecordWithLimit(&m->omsg, ptr, &rr->resrec, limit);
+               if (!ptr) goto exit;
+               return ptr;
+               }
+
+       // This is a common function to both sending an update in a group or individual
+       // records separately. Hence, we change the state here.
+       if (rr->state == regState_Registered) rr->state = regState_Refresh;
+       if (rr->state != regState_Refresh && rr->state != regState_UpdatePending)
+               rr->state = regState_Pending;
+
+       // For Advisory records like e.g., _services._dns-sd, which is shared, don't send goodbyes as multiple
+       // host might be registering records and deregistering from one does not make sense
+       if (rr->resrec.RecordType != kDNSRecordTypeAdvisory) rr->RequireGoodbye = mDNStrue;
+
+       if ((rr->resrec.rrtype == kDNSType_SRV) && (rr->AutoTarget == Target_AutoHostAndNATMAP) &&
+               !mDNSIPPortIsZero(rr->NATinfo.ExternalPort))
+               {
+               rr->resrec.rdata->u.srv.port = rr->NATinfo.ExternalPort;
+               }
+
+       if (rr->state == regState_UpdatePending)
+               {
+               // delete old RData
+               SetNewRData(&rr->resrec, rr->OrigRData, rr->OrigRDLen);
+               if (!(ptr = putDeletionRecordWithLimit(&m->omsg, ptr, &rr->resrec, limit))) goto exit; // delete old rdata
+
+               // add new RData
+               SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen);
+               if (!(ptr = PutResourceRecordTTLWithLimit(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit)))  goto exit;
+               }
+       else
+               {
+               if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique || rr->resrec.RecordType == kDNSRecordTypeVerified)
+                       {
+                       // KnownUnique : Delete any previous value 
+                       // For Unicast registrations, we don't verify that it is unique, but set to verified and hence we want to
+                       // delete any previous value
+                       ptr = putDeleteRRSetWithLimit(&m->omsg, ptr, rr->resrec.name, rr->resrec.rrtype, limit);
+                       if (!ptr) goto exit;
+                       }
+               else if (rr->resrec.RecordType != kDNSRecordTypeShared)
+                       {
+                       // For now don't do this, until we have the logic for intelligent grouping of individual records into logical service record sets
+                       //ptr = putPrereqNameNotInUse(rr->resrec.name, &m->omsg, ptr, end);
+                       if (!ptr) goto exit;
+                       }
+
+               ptr = PutResourceRecordTTLWithLimit(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl, limit);
+               if (!ptr) goto exit;
                }
+
+       return ptr;
+exit:
+       LogMsg("BuildUpdateMessage: Error formatting message for %s", ARDisplayString(m, rr));
+       return mDNSNULL;
        }
 
 // Called with lock held
 mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr)
        {
        mDNSu8 *ptr = m->omsg.data;
-       mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
        mStatus err = mStatus_UnknownErr;
+       mDNSu8 *limit;
+       DomainAuthInfo *AuthInfo;
+
+       // For the ability to register large TXT records, we limit the single record registrations
+       // to AbsoluteMaxDNSMessageData
+       limit = ptr + AbsoluteMaxDNSMessageData;
+
+       AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
+       limit -= RRAdditionalSize(m, AuthInfo);
 
        if (m->mDNS_busy != m->mDNS_reentrancy+1)
                LogMsg("SendRecordRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 
-       if (mDNSIPv4AddressIsZero(rr->UpdateServer.ip.v4))      // Don't know our UpdateServer yet
+       if (!rr->nta || mDNSIPv4AddressIsZero(rr->nta->Addr.ip.v4))
                {
-               rr->LastAPTime = m->timenow;
-               if (rr->ThisAPInterval < mDNSPlatformOneSecond * 5)
-                       rr->ThisAPInterval = mDNSPlatformOneSecond * 5;
+               // We never call this function when there is no zone information . Log a message if it ever happens.
+               LogMsg("SendRecordRegistration: No Zone information, should not happen %s", ARDisplayString(m, rr));
                return;
                }
 
-       rr->RequireGoodbye = mDNStrue;
        rr->updateid = mDNS_NewMessageID(m);
        InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags);
 
        // set zone
-       ptr = putZone(&m->omsg, ptr, end, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
-       if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+       ptr = putZone(&m->omsg, ptr, limit, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+       if (!ptr) goto exit;
 
-       if (rr->state == regState_UpdatePending)
-               {
-               // delete old RData
-               SetNewRData(&rr->resrec, rr->OrigRData, rr->OrigRDLen);
-               if (!(ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec))) { err = mStatus_UnknownErr; goto exit; } // delete old rdata
+       if (!(ptr = BuildUpdateMessage(m, ptr, rr, limit))) goto exit;
 
-               // add new RData
-               SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen);
-               if (!(ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl))) { err = mStatus_UnknownErr; goto exit; }
+       if (rr->uselease)
+               {
+               ptr = putUpdateLeaseWithLimit(&m->omsg, ptr, DEFAULT_UPDATE_LEASE, limit);
+               if (!ptr) goto exit;
+               }
+       if (rr->Private)
+               {
+               LogInfo("SendRecordRegistration TCP %p %s", rr->tcp, ARDisplayString(m, rr));
+               if (rr->tcp) LogInfo("SendRecordRegistration: Disposing existing TCP connection for %s", ARDisplayString(m, rr));
+               if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
+               if (!rr->nta) { LogMsg("SendRecordRegistration:Private:ERROR!! nta is NULL for %s", ARDisplayString(m, rr)); return; }
+               rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->nta->Addr, rr->nta->Port, &rr->nta->Host, mDNSNULL, rr);
                }
-
        else
                {
-               if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique)
-                       {
-                       // KnownUnique: Delete any previous value
-                       ptr = putDeleteRRSet(&m->omsg, ptr, rr->resrec.name, rr->resrec.rrtype);
-                       if (!ptr) { err = mStatus_UnknownErr; goto exit; }
-                       }
+               LogInfo("SendRecordRegistration UDP %s", ARDisplayString(m, rr));
+               if (!rr->nta) { LogMsg("SendRecordRegistration:ERROR!! nta is NULL for %s", ARDisplayString(m, rr)); return; }
+               err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->nta->Addr, rr->nta->Port, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
+               if (err) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %d", err);
+               }
 
-               else if (rr->resrec.RecordType != kDNSRecordTypeShared)
-                       {
-                       // For now don't do this, until we have the logic for intelligent grouping of individual recors into logical service record sets
-                       //ptr = putPrereqNameNotInUse(rr->resrec.name, &m->omsg, ptr, end);
-                       if (!ptr) { err = mStatus_UnknownErr; goto exit; }
-                       }
+       SetRecordRetry(m, rr, 0);
+       return;
+exit:
+       LogMsg("SendRecordRegistration: Error formatting message for %s, disabling further updates", ARDisplayString(m, rr));
+       // Disable this record from future updates
+       rr->state = regState_NoTarget;
+       }
+
+// Is the given record "rr" eligible for merging ?
+mDNSlocal mDNSBool IsRecordMergeable(mDNS *const m, AuthRecord *rr, mDNSs32 time)
+       {
+       DomainAuthInfo *info;
+       (void) m; //unused
+       // A record is eligible for merge, if the following properties are met.
+       //
+       // 1. uDNS Resource Record
+       // 2. It is time to send them now
+       // 3. It is in proper state
+       // 4. Update zone has been resolved
+       // 5. if DomainAuthInfo exists for the zone, it should not be soon deleted
+       // 6. Zone information is present
+       // 7. Update server is not zero
+       // 8. It has a non-null zone
+       // 9. It uses a lease option 
+       // 10. DontMerge is not set
+       //
+       // Following code is implemented as separate "if" statements instead of one "if" statement
+       // is for better debugging purposes e.g., we know exactly what failed if debugging turned on.
+
+       if (!AuthRecord_uDNS(rr)) return mDNSfalse;
+
+       if (rr->LastAPTime + rr->ThisAPInterval - time > 0)
+               { debugf("IsRecordMergeable: Time %d not reached for %s", rr->LastAPTime + rr->ThisAPInterval - m->timenow, ARDisplayString(m, rr)); return mDNSfalse; }
+
+       if (!rr->zone) return mDNSfalse;
+
+       info = GetAuthInfoForName_internal(m, rr->zone);
+
+       if (info && info->deltime && m->timenow - info->deltime >= 0) {debugf("IsRecordMergeable: Domain %##s will be deleted soon", info->domain.c); return mDNSfalse;}
+
+       if (rr->state != regState_DeregPending && rr->state != regState_Pending && rr->state != regState_Registered && rr->state != regState_Refresh && rr->state != regState_UpdatePending)
+               { debugf("IsRecordMergeable: state %d not right  %s", rr->state, ARDisplayString(m, rr)); return mDNSfalse; }
+
+       if (!rr->nta || mDNSIPv4AddressIsZero(rr->nta->Addr.ip.v4)) return mDNSfalse;
+
+       if (!rr->uselease) return mDNSfalse;
+       
+       if (rr->mState == mergeState_DontMerge) {debugf("IsRecordMergeable Dontmerge true %s", ARDisplayString(m, rr));return mDNSfalse;}
+       debugf("IsRecordMergeable: Returning true for %s", ARDisplayString(m, rr));
+       return mDNStrue;
+       }
+
+// Is the resource record "rr" eligible to merge to with "currentRR" ?
+mDNSlocal mDNSBool AreRecordsMergeable(mDNS *const m, AuthRecord *currentRR, AuthRecord *rr, mDNSs32 time)
+       {
+       // A record is eligible to merge with another record as long it is eligible for merge in itself
+       // and it has the same zone information as the other record
+       if (!IsRecordMergeable(m, rr, time)) return mDNSfalse;
 
-               ptr = PutResourceRecordTTLJumbo(&m->omsg, ptr, &m->omsg.h.mDNS_numUpdates, &rr->resrec, rr->resrec.rroriginalttl);
-               if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+       if (!SameDomainName(currentRR->zone, rr->zone))
+               { debugf("AreRecordMergeable zone mismatch current rr Zone %##s, rr zone  %##s", currentRR->zone->c, rr->zone->c); return mDNSfalse; }
+
+       if (!mDNSSameIPv4Address(currentRR->nta->Addr.ip.v4, rr->nta->Addr.ip.v4)) return mDNSfalse;
+
+       if (!mDNSSameIPPort(currentRR->nta->Port, rr->nta->Port)) return mDNSfalse;
+
+       debugf("AreRecordsMergeable: Returning true for %s", ARDisplayString(m, rr));
+       return mDNStrue;
+       }
+
+// If we can't build the message successfully because of problems in pre-computing
+// the space, we disable merging for all the current records
+mDNSlocal void RRMergeFailure(mDNS *const m)
+       {
+       AuthRecord *rr;
+       for (rr = m->ResourceRecords; rr; rr = rr->next)
+               {
+               rr->mState = mergeState_DontMerge;
+               rr->SendRNow = mDNSNULL;
+               // Restarting the registration is much simpler than saving and restoring
+               // the exact time
+               ActivateUnicastRegistration(m, rr);
                }
+       }
 
-       if (rr->uselease)
+mDNSlocal void SendGroupRRMessage(mDNS *const m, AuthRecord *anchorRR, mDNSu8 *ptr, DomainAuthInfo *info)
+       {
+       mDNSu8 *limit;
+       if (!anchorRR) {debugf("SendGroupRRMessage: Could not merge records"); return;}
+
+       if (info && info->AutoTunnel) limit = m->omsg.data + AbsoluteMaxDNSMessageData;
+       else limit = m->omsg.data + NormalMaxDNSMessageData;
+
+       // This has to go in the additional section and hence need to be done last
+       ptr = putUpdateLeaseWithLimit(&m->omsg, ptr, DEFAULT_UPDATE_LEASE, limit);
+       if (!ptr)
+               {
+               LogMsg("SendGroupRRMessage: ERROR: Could not put lease option, failing the group registration");
+               // if we can't put the lease, we need to undo the merge
+               RRMergeFailure(m);
+               return;
+               }
+       if (anchorRR->Private)
+               {
+               if (anchorRR->tcp) debugf("SendGroupRRMessage: Disposing existing TCP connection for %s", ARDisplayString(m, anchorRR));
+               if (anchorRR->tcp) { DisposeTCPConn(anchorRR->tcp); anchorRR->tcp = mDNSNULL; }
+               if (!anchorRR->nta) { LogMsg("SendGroupRRMessage:ERROR!! nta is NULL for %s", ARDisplayString(m, anchorRR)); return; }
+               anchorRR->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &anchorRR->nta->Addr, anchorRR->nta->Port, &anchorRR->nta->Host, mDNSNULL, anchorRR);
+               if (!anchorRR->tcp) LogInfo("SendGroupRRMessage: Cannot establish TCP connection for %s", ARDisplayString(m, anchorRR));
+               else LogInfo("SendGroupRRMessage: Sent a group update ID: %d start %p, end %p, limit %p", mDNSVal16(m->omsg.h.id), m->omsg.data, ptr, limit);
+               }
+       else 
                {
-               ptr = putUpdateLease(&m->omsg, ptr, DEFAULT_UPDATE_LEASE); if (!ptr) { err = mStatus_UnknownErr; goto exit; }
+               mStatus err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &anchorRR->nta->Addr, anchorRR->nta->Port, mDNSNULL, info);
+               if (err) LogInfo("SendGroupRRMessage: Cannot send UDP message for %s", ARDisplayString(m, anchorRR));
+               else LogInfo("SendGroupRRMessage: Sent a group UDP update ID: %d start %p, end %p, limit %p", mDNSVal16(m->omsg.h.id), m->omsg.data, ptr, limit);
                }
+       return;
+       }
 
-       if (rr->Private)
+// As we always include the zone information and the resource records contain zone name
+// at the end, it will get compressed. Hence, we subtract zoneSize and add two bytes for
+// the compression pointer
+mDNSlocal mDNSu32 RREstimatedSize(AuthRecord *rr, int zoneSize)
+       {
+       int rdlength;
+
+       // Note: Estimation of the record size has to mirror the logic in BuildUpdateMessage, otherwise estimation
+       // would be wrong. Currently BuildUpdateMessage calls SetNewRData in UpdatePending case. Hence, we need
+       // to account for that here. Otherwise, we might under estimate the size.
+       if (rr->state == regState_UpdatePending)
+               // old RData that will be deleted
+               // new RData that will be added
+               rdlength = rr->OrigRDLen + rr->InFlightRDLen;
+       else
+               rdlength = rr->resrec.rdestimate;
+
+       if (rr->state == regState_DeregPending)
                {
-               LogInfo("SendRecordRegistration TCP %p %s", rr->tcp, ARDisplayString(m, rr));
-               if (rr->tcp) LogInfo("SendRecordRegistration: Disposing existing TCP connection for %s", ARDisplayString(m, rr));
-               if (rr->tcp) DisposeTCPConn(rr->tcp);
-               rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, mDNSNULL, rr);
-               if (!rr->tcp) rr->ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2)
-               else if (rr->ThisAPInterval < mDNSPlatformOneSecond * 30) rr->ThisAPInterval = mDNSPlatformOneSecond * 30;
+               debugf("RREstimatedSize: ResourceRecord %##s (%s), DomainNameLength %d, zoneSize %d, rdestimate %d",
+                               rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), DomainNameLength(rr->resrec.name), zoneSize, rdlength);
+               return DomainNameLength(rr->resrec.name) - zoneSize + 2 + 10 + rdlength;
+               }
+
+       // For SRV, TXT, AAAA etc. that are Unique/Verified, we also send a Deletion Record
+       if (rr->resrec.RecordType == kDNSRecordTypeKnownUnique || rr->resrec.RecordType == kDNSRecordTypeVerified)
+               {
+               // Deletion Record: Resource Record Name + Base size (10) + 0
+               // Record: Resource Record Name (Compressed = 2) + Base size (10) + rdestimate
+
+               debugf("RREstimatedSize: ResourceRecord %##s (%s), DomainNameLength %d, zoneSize %d, rdestimate %d",
+                               rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), DomainNameLength(rr->resrec.name), zoneSize, rdlength);
+               return DomainNameLength(rr->resrec.name) - zoneSize + 2 + 10 + 2 + 10 + rdlength;
                }
        else
                {
-               err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
-               if (err) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %d", err);
+               return DomainNameLength(rr->resrec.name) - zoneSize + 2 + 10 + rdlength;
                }
+       }
 
-       SetRecordRetry(m, rr, err);
+mDNSlocal AuthRecord *MarkRRForSending(mDNS *const m)
+       {
+       AuthRecord *rr;
+       AuthRecord *firstRR = mDNSNULL;
 
-       if (rr->state != regState_Refresh && rr->state != regState_DeregDeferred && rr->state != regState_UpdatePending)
-               rr->state = regState_Pending;
+       // Look for records that needs to be sent in the next two seconds (MERGE_DELAY_TIME is set to 1 second).
+       // The logic is as follows.
+       //
+       // 1. Record 1 finishes getting zone data and its registration gets delayed by 1 second
+       // 2. Record 2 comes 0.1 second later, finishes getting its zone data and its registration is also delayed by
+       //    1 second which is now scheduled at 1.1 second
+       //
+       // By looking for 1 second into the future (m->timenow + MERGE_DELAY_TIME below does that) we have merged both
+       // of the above records. Note that we can't look for records too much into the future as this will affect the
+       // retry logic. The first retry is scheduled at 3 seconds. Hence, we should always look smaller than that.
+       // Anything more than one second will affect the first retry to happen sooner. 
+       //
+       // Note: As a side effect of looking one second into the future to facilitate merging, the retries happen
+       // one second sooner.
+       for (rr = m->ResourceRecords; rr; rr = rr->next)
+               {
+               if (!firstRR)
+                       {
+                       if (!IsRecordMergeable(m, rr, m->timenow + MERGE_DELAY_TIME)) continue;
+                       firstRR = rr;
+                       }
+               else if (!AreRecordsMergeable(m, firstRR, rr, m->timenow + MERGE_DELAY_TIME)) continue;
 
-       return;
+               if (rr->SendRNow) LogMsg("MarkRRForSending: Resourcerecord %s already marked for sending", ARDisplayString(m, rr));
+               rr->SendRNow = mDNSInterfaceMark;
+               }
 
-exit:
-       LogMsg("SendRecordRegistration: Error formatting message for %s", ARDisplayString(m, rr));
+       // We parsed through all records and found something to send. The services/records might
+       // get registered at different times but we want the refreshes to be all merged and sent
+       // as one update. Hence, we accelerate some of the records so that they will sync up in
+       // the future. Look at the records excluding the ones that we have already sent in the
+       // previous pass. If it half way through its scheduled refresh/retransmit, merge them
+       // into this packet.
+       //
+       // Note that we only look at Registered/Refresh state to keep it simple. As we don't know
+       // whether the current update will fit into one or more packets, merging a resource record
+       // (which is in a different state) that has been scheduled for retransmit would trigger
+       // sending more packets.
+       if (firstRR)
+               {
+               int acc = 0;
+               for (rr = m->ResourceRecords; rr; rr = rr->next)
+                       {
+                       if ((rr->state != regState_Registered && rr->state != regState_Refresh) ||
+                               (rr->SendRNow == mDNSInterfaceMark) || 
+                               (!AreRecordsMergeable(m, firstRR, rr, m->timenow + rr->ThisAPInterval/2)))
+                               continue;
+                       rr->SendRNow = mDNSInterfaceMark;
+                       acc++;
+                       }
+               if (acc) LogInfo("MarkRRForSending: Accelereated %d records", acc);
+               }
+       return firstRR;
        }
 
-// Called with lock held
-mDNSlocal void hndlServiceUpdateReply(mDNS *const m, ServiceRecordSet *srs,  mStatus err)
+mDNSlocal mDNSBool SendGroupUpdates(mDNS *const m)
        {
-       mDNSBool InvokeCallback = mDNSfalse;
-       ExtraResourceRecord **e = &srs->Extras;
-       AuthRecord *txt = &srs->RR_TXT;
-
-       if (m->mDNS_busy != m->mDNS_reentrancy+1)
-               LogMsg("hndlServiceUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
+       mDNSOpaque16 msgid;
+       mDNSs32 spaceleft = 0;
+       mDNSs32 zoneSize, rrSize;
+       mDNSu8 *oldnext; // for debugging
+       mDNSu8 *next = m->omsg.data;
+       AuthRecord *rr;
+       AuthRecord *anchorRR = mDNSNULL;
+       int nrecords = 0;
+       AuthRecord *startRR = m->ResourceRecords;
+       mDNSu8 *limit = mDNSNULL;
+       DomainAuthInfo *AuthInfo = mDNSNULL;
+       mDNSBool sentallRecords = mDNStrue;
 
-       debugf("hndlServiceUpdateReply: err %d state %d %##s", err, srs->state, srs->RR_SRV.resrec.name->c);
 
-       SetRecordRetry(m, &srs->RR_SRV, mStatus_NoError);
+       // We try to fit as many ResourceRecords as possible in AbsoluteNormal/MaxDNSMessageData. Before we start
+       // putting in resource records, we need to reserve space for a few things. Every group/packet should
+       // have the following.
+       //
+       // 1) Needs space for the Zone information (which needs to be at the beginning)
+       // 2) Additional section MUST have space for lease option, HINFO and TSIG option (which needs to
+       //    to be at the end)
+       // 
+       // In future we need to reserve space for the pre-requisites which also goes at the beginning.
+       // To accomodate pre-requisites in the future, first we walk the whole list marking records
+       // that can be sent in this packet and computing the space needed for these records. 
+       // For TXT and SRV records, we delete the previous record if any by sending the same
+       // resource record with ANY RDATA and zero rdlen. Hence, we need to have space for both of them.
+
+       while (startRR)
+               {
+               AuthInfo = mDNSNULL;
+               anchorRR = mDNSNULL;
+               nrecords = 0;
+               zoneSize = 0;
+               for (rr = startRR; rr; rr = rr->next)
+                       {
+                       if (rr->SendRNow != mDNSInterfaceMark) continue;
+       
+                       rr->SendRNow = mDNSNULL;
 
-       switch (srs->state)
-               {
-               case regState_Pending:
-                       if (err == mStatus_NameConflict && !srs->TestForSelfConflict)
+                       if (!anchorRR)
                                {
-                               srs->TestForSelfConflict = mDNStrue;
-                               debugf("checking for self-conflict of service %##s", srs->RR_SRV.resrec.name->c);
-                               SendServiceRegistration(m, srs);
-                               return;
-                               }
-                       else if (srs->TestForSelfConflict)
-                               {
-                               srs->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) srs->state = regState_Registered;
-                               InvokeCallback = mDNStrue;
-                               break;
-                               }
-                       else if (srs->srs_uselease && err == mStatus_UnknownErr && mDNSSameIPPort(srs->SRSUpdatePort, UnicastDNSPort))
-                               {
-                               LogMsg("Re-trying update of service %##s without lease option", srs->RR_SRV.resrec.name->c);
-                               srs->srs_uselease = mDNSfalse;
-                               SendServiceRegistration(m, srs);
-                               return;
-                               }
-                       else
-                               {
-                               //!!!KRS make sure all structs will still get cleaned up when client calls DeregisterService with this state
-                               if (err) LogMsg("Error %d for registration of service %##s", err, srs->RR_SRV.resrec.name->c);
-                               else srs->state = regState_Registered;
-                               InvokeCallback = mDNStrue;
-                               break;
-                               }
-               case regState_Refresh:
-                       if (err)
-                               {
-                               LogMsg("Error %d for refresh of service %##s", err, srs->RR_SRV.resrec.name->c);
-                               InvokeCallback = mDNStrue;
-                               }
-                       else srs->state = regState_Registered;
-                       break;
-               case regState_DeregPending:
-                       if (err) LogMsg("Error %d for deregistration of service %##s", err, srs->RR_SRV.resrec.name->c);
-                       if (srs->SRVChanged)
-                               {
-                               srs->state = regState_NoTarget; // NoTarget will allow us to pick up new target OR nat traversal state
-                               break;
-                               }
-                       err = mStatus_MemFree;
-                       InvokeCallback = mDNStrue;
-                       if (srs->NATinfo.clientContext)
-                               {
-                               // deletion completed
-                               mDNS_StopNATOperation_internal(m, &srs->NATinfo);
-                               srs->NATinfo.clientContext = mDNSNULL;
-                               }
-                       srs->state = regState_Unregistered;
-                       break;
-               case regState_DeregDeferred:
-                       if (err)
-                               {
-                               debugf("Error %d received prior to deferred deregistration of %##s", err, srs->RR_SRV.resrec.name->c);
-                               err = mStatus_MemFree;
-                               InvokeCallback = mDNStrue;
-                               srs->state = regState_Unregistered;
-                               break;
-                               }
-                       else
-                               {
-                               debugf("Performing deferred deregistration of %##s", srs->RR_SRV.resrec.name->c);
-                               srs->state = regState_Registered;
-                               SendServiceDeregistration(m, srs);
-                               return;
+                               AuthInfo = GetAuthInfoForName_internal(m, rr->zone);
+
+                               // Though we allow single record registrations for UDP to be AbsoluteMaxDNSMessageData (See
+                               // SendRecordRegistration) to handle large TXT records, to avoid fragmentation we limit UDP
+                               // message to NormalMaxDNSMessageData
+                               if (AuthInfo && AuthInfo->AutoTunnel) spaceleft = AbsoluteMaxDNSMessageData;
+                               else spaceleft = NormalMaxDNSMessageData;
+               
+                               next = m->omsg.data;
+                               spaceleft -= RRAdditionalSize(m, AuthInfo);
+                               if (spaceleft <= 0)
+                                       {
+                                       LogMsg("SendGroupUpdates: ERROR!!: spaceleft is zero at the beginning");
+                                       RRMergeFailure(m);
+                                       return mDNSfalse;
+                                       }
+                               limit = next + spaceleft;
+
+                               // Build the initial part of message before putting in the other records
+                               msgid = mDNS_NewMessageID(m);
+                               InitializeDNSMessage(&m->omsg.h, msgid, UpdateReqFlags);
+       
+                               // We need zone information at the beginning of the packet. Length: ZNAME, ZTYPE(2), ZCLASS(2)
+                               // zone has to be non-NULL for a record to be mergeable, hence it is safe to set/ examine zone
+                               //without checking for NULL.
+                               zoneSize = DomainNameLength(rr->zone) + 4;
+                               spaceleft -= zoneSize;
+                               if (spaceleft <= 0)
+                                       {
+                                       LogMsg("SendGroupUpdates: ERROR no space for zone information, disabling merge");
+                                       RRMergeFailure(m);
+                                       return mDNSfalse;
+                                       }
+                               next = putZone(&m->omsg, next, limit, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+                               if (!next)
+                                       {
+                                       LogMsg("SendGroupUpdates: ERROR! Cannot put zone, disabling merge");
+                                       RRMergeFailure(m);
+                                       return mDNSfalse;
+                                       }
+                               anchorRR = rr;
                                }
-               case regState_UpdatePending:
-                       if (err)
+
+                       rrSize = RREstimatedSize(rr, zoneSize - 4);
+
+                       if ((spaceleft - rrSize) < 0) 
                                {
-                               LogMsg("hndlServiceUpdateReply: error updating TXT record for service %##s", srs->RR_SRV.resrec.name->c);
-                               InvokeCallback = mDNStrue;
+                               // If we can't fit even a single message, skip it, it will be sent separately
+                               // in CheckRecordUpdates
+                               if (!nrecords)
+                                       {
+                                       LogInfo("SendGroupUpdates: Skipping message %s, spaceleft %d, rrSize %d", ARDisplayString(m, rr), spaceleft, rrSize);
+                                       // Mark this as not sent so that the caller knows about it
+                                       rr->SendRNow = mDNSInterfaceMark;
+                                       // We need to remove the merge delay so that we can send it immediately
+                                       rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
+                                       rr->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL;
+                                       rr = rr->next;
+                                       anchorRR = mDNSNULL;
+                                       sentallRecords = mDNSfalse;
+                                       }
+                               else
+                                       {
+                                       LogInfo("SendGroupUpdates:1: Parsed %d records and sending using %s, spaceleft %d, rrSize %d", nrecords, ARDisplayString(m, anchorRR), spaceleft, rrSize);
+                                       SendGroupRRMessage(m, anchorRR, next, AuthInfo);
+                                       }
+                               break;          // breaks out of for loop
                                }
-                       else
+                       spaceleft -= rrSize;
+                       oldnext = next;
+                       LogInfo("SendGroupUpdates: Building a message with resource record %s, next %p, state %d", ARDisplayString(m, rr), next, rr->state);
+                       if (!(next = BuildUpdateMessage(m, next, rr, limit)))
                                {
-                               srs->state = regState_Registered;
-                               // deallocate old RData
-                               if (txt->UpdateCallback) txt->UpdateCallback(m, txt, txt->OrigRData);
-                               SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen);
-                               txt->OrigRData = mDNSNULL;
-                               txt->InFlightRData = mDNSNULL;
+                               // We calculated the space and if we can't fit in, we had some bug in the calculation,
+                               // disable merge completely.
+                               LogMsg("SendGroupUpdates: ptr NULL while building message with %s", ARDisplayString(m, rr));
+                               RRMergeFailure(m);
+                               return mDNSfalse;
                                }
-                       break;
-               case regState_NoTarget:
-                       // This state is used when using SendServiceDeregistration() when going to sleep -- no further action required
-                       return;
-               case regState_FetchingZoneData:
-               case regState_Registered:
-               case regState_Unregistered:
-               case regState_NATMap:
-               case regState_ExtraQueued:
-               case regState_NATError:
-                       LogMsg("hndlServiceUpdateReply called for service %##s in unexpected state %d with error %d.  Unlinking.",
-                                  srs->RR_SRV.resrec.name->c, srs->state, err);
-                       err = mStatus_UnknownErr;
-               default: LogMsg("hndlServiceUpdateReply: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
+                       // If our estimate was higher, adjust to the actual size
+                       if ((next - oldnext) > rrSize)
+                               LogMsg("SendGroupUpdates: ERROR!! Record size estimation is wrong for %s, Estimate %d, Actual %d, state %d", ARDisplayString(m, rr), rrSize, next - oldnext, rr->state); 
+                       else { spaceleft += rrSize; spaceleft -= (next - oldnext); }
+
+                       nrecords++;
+                       // We could have sent an update earlier with this "rr" as anchorRR for which we never got a response.
+                       // To preserve ordering, we blow away the previous connection before sending this.
+                       if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL;}
+                       rr->updateid = msgid;
+       
+                       // By setting the retry time interval here, we will not be looking at these records
+                       // again when we return to CheckGroupRecordUpdates.
+                       SetRecordRetry(m, rr, 0);
+                       }
+                       // Either we have parsed all the records or stopped at "rr" above due to lack of space
+                       startRR = rr;
                }
 
-       if ((srs->SRVChanged || srs->SRVUpdateDeferred) && (srs->state == regState_NoTarget || srs->state == regState_Registered))
+       if (anchorRR)
                {
-               debugf("hndlServiceUpdateReply: SRVChanged %d SRVUpdateDeferred %d state %d", srs->SRVChanged, srs->SRVUpdateDeferred, srs->state);
-               if (InvokeCallback)
-                       {
-                       srs->ClientCallbackDeferred = mDNStrue;
-                       srs->DeferredStatus = err;
-                       }
-               srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse;
-               UpdateSRV(m, srs);
-               return;
+               LogInfo("SendGroupUpdates: Parsed %d records and sending using %s", nrecords, ARDisplayString(m, anchorRR));
+               SendGroupRRMessage(m, anchorRR, next, AuthInfo);
                }
+       return sentallRecords;
+       }
 
-       while (*e)
+// Merge the record registrations and send them as a group only if they
+// have same DomainAuthInfo and hence the same key to put the TSIG
+mDNSlocal void CheckGroupRecordUpdates(mDNS *const m)
+       {
+       AuthRecord *rr, *nextRR;
+       // Keep sending as long as there is at least one record to be sent
+       while (MarkRRForSending(m))
                {
-               if ((*e)->r.state == regState_ExtraQueued)
+               if (!SendGroupUpdates(m))
                        {
-                       if (srs->state == regState_Registered && !err)
+                       // if everything that was marked was not sent, send them out individually
+                       for (rr = m->ResourceRecords; rr; rr = nextRR)
                                {
-                               // extra resource record queued for this service - copy zone srs and register
-                               (*e)->r.zone = &srs->zone;
-                               (*e)->r.UpdateServer    = srs->SRSUpdateServer;
-                               (*e)->r.UpdatePort  = srs->SRSUpdatePort;
-                               (*e)->r.uselease = srs->srs_uselease;
-                               SendRecordRegistration(m, &(*e)->r);
-                               e = &(*e)->next;
-                               }
-                       else if (err && (*e)->r.state != regState_Unregistered)
-                               {
-                               // unlink extra from list
-                               (*e)->r.state = regState_Unregistered;
-                               *e = (*e)->next;
+                               // SendRecordRegistrtion might delete the rr from list, hence
+                               // dereference nextRR before calling the function
+                               nextRR = rr->next;
+                               if (rr->SendRNow == mDNSInterfaceMark)
+                                       {
+                                       // Any records marked for sending should be eligible to be sent out
+                                       // immediately. Just being cautious
+                                       if (rr->LastAPTime + rr->ThisAPInterval - m->timenow > 0)
+                                               { LogMsg("CheckGroupRecordUpdates: ERROR!! Resourcerecord %s not ready", ARDisplayString(m, rr)); continue; }
+                                       rr->SendRNow = mDNSNULL;
+                                       SendRecordRegistration(m, rr);
+                                       }
                                }
-                       else e = &(*e)->next;
                        }
-               else e = &(*e)->next;
                }
+               
+       debugf("CheckGroupRecordUpdates: No work, returning");
+       return;
+       }
 
-       if (srs->state == regState_Unregistered)
-               {
-               if (err != mStatus_MemFree)
-                       LogMsg("hndlServiceUpdateReply ERROR! state == regState_Unregistered but err != mStatus_MemFree. Permanently abandoning service registration %##s",
-                               srs->RR_SRV.resrec.name->c);
-               unlinkSRS(m, srs);
-               }
-       else if (txt->QueuedRData && srs->state == regState_Registered)
+mDNSlocal void hndlSRVChanged(mDNS *const m, AuthRecord *rr)
+       {
+       // Reevaluate the target always as NAT/Target could have changed while
+       // we were registering/deeregistering
+       domainname *dt;
+       const domainname *target = GetServiceTarget(m, rr);
+       if (!target || target->c[0] == 0)
                {
-               if (InvokeCallback)
+               // we don't have a target, if we just derregistered, then we don't have to do anything
+               if (rr->state == regState_DeregPending)
                        {
-                       // if we were supposed to give a client callback, we'll do it after we update the primary txt record
-                       srs->ClientCallbackDeferred = mDNStrue;
-                       srs->DeferredStatus = err;
+                       LogInfo("hndlSRVChanged: SRVChanged, No Target, SRV Deregistered for %##s, state %d", rr->resrec.name->c,
+                               rr->state);
+                       rr->SRVChanged = mDNSfalse;
+                       dt = GetRRDomainNameTarget(&rr->resrec);
+                       if (dt) dt->c[0] = 0;
+                       rr->state = regState_NoTarget;  // Wait for the next target change
+                       rr->resrec.rdlength = rr->resrec.rdestimate = 0;
+                       return;
                        }
-               srs->state = regState_UpdatePending;
-               txt->InFlightRData = txt->QueuedRData;
-               txt->InFlightRDLen = txt->QueuedRDLen;
-               txt->OrigRData = txt->resrec.rdata;
-               txt->OrigRDLen = txt->resrec.rdlength;
-               txt->QueuedRData = mDNSNULL;
-               SendServiceRegistration(m, srs);
-               return;
+       
+               // we don't have a target, if we just registered, we need to deregister
+               if (rr->state == regState_Pending)
+                       {
+                       LogInfo("hndlSRVChanged: SRVChanged, No Target, Deregistering again %##s, state %d", rr->resrec.name->c, rr->state);
+                       rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
+                       rr->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL;
+                       rr->state = regState_DeregPending;
+                       return;
+                       }
+               LogInfo("hndlSRVChanged: Not in DeregPending or RegPending state %##s, state %d", rr->resrec.name->c, rr->state);
                }
-
-       mDNS_DropLockBeforeCallback();
-       if (InvokeCallback)
-               srs->ServiceCallback(m, srs, err);
-       else if (srs->ClientCallbackDeferred)
+       else
                {
-               srs->ClientCallbackDeferred = mDNSfalse;
-               srs->ServiceCallback(m, srs, srs->DeferredStatus);
+               // If we were in registered state and SRV changed to NULL, we deregister and come back here
+               // if we have a target, we need to register again.
+               //
+               // if we just registered check to see if it is same. If it is different just re-register the
+               // SRV and its assoicated records
+               //
+               // UpdateOneSRVRecord takes care of re-registering all service records
+               if ((rr->state == regState_DeregPending) ||
+                  (rr->state == regState_Pending && !SameDomainName(target, &rr->resrec.rdata->u.srv.target)))
+                       {
+                       dt = GetRRDomainNameTarget(&rr->resrec);
+                       if (dt) dt->c[0] = 0;
+                       rr->state = regState_NoTarget;  // NoTarget will allow us to pick up new target OR nat traversal state
+                       rr->resrec.rdlength = rr->resrec.rdestimate = 0;
+                       LogInfo("hndlSRVChanged: SRVChanged, Valid Target %##s, Registering all records for %##s, state %d",
+                               target->c, rr->resrec.name->c, rr->state);
+                       rr->SRVChanged = mDNSfalse;
+                       UpdateOneSRVRecord(m, rr);
+                       return;
+                       }
+               // Target did not change while this record was registering. Hence, we go to
+               // Registered state - the state we started from.
+               if (rr->state == regState_Pending) rr->state = regState_Registered;
                }
-       mDNS_ReclaimLockAfterCallback();
-       // 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.
+       
+       rr->SRVChanged = mDNSfalse;
        }
 
 // Called with lock held
-mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
+mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err, mDNSu32 random)
        {
        mDNSBool InvokeCallback = mDNStrue;
+       mDNSIPPort UpdatePort = zeroIPPort;
 
        if (m->mDNS_busy != m->mDNS_reentrancy+1)
                LogMsg("hndlRecordUpdateReply: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 
-       LogInfo("hndlRecordUpdateReply: err %d state %d %s", err, rr->state, ARDisplayString(m, rr));
+       LogInfo("hndlRecordUpdateReply: err %d ID %d state %d %s(%p)", err, mDNSVal16(rr->updateid), rr->state, ARDisplayString(m, rr), rr);
+
+       rr->updateError = err;
+#if APPLE_OSX_mDNSResponder
+       if (err == mStatus_BadSig) UpdateAutoTunnelDomainStatuses(m);
+#endif
+
+       SetRecordRetry(m, rr, random);
 
-       if (m->SleepState) return;              // If we just sent a deregister on going to sleep, no further action required
+       rr->updateid = zeroID;  // Make sure that this is not considered as part of a group anymore
+       // Later when need to send an update, we will get the zone data again. Thus we avoid
+       // using stale information.
+       //
+       // Note: By clearing out the zone info here, it also helps better merging of records
+       // in some cases. For example, when we get out regState_NoTarget state e.g., move out
+       // of Double NAT, we want all the records to be in one update. Some BTMM records like
+       // _autotunnel6 and host records are registered/deregistered when NAT state changes.
+       // As they are re-registered the zone information is cleared out. To merge with other
+       // records that might be possibly going out, clearing out the information here helps
+       // as all of them try to get the zone data.
+       if (rr->nta)
+               {
+               // We always expect the question to be stopped when we get a valid response from the server.
+               // If the zone info tries to change during this time, updateid would be different and hence
+               // this response should not have been accepted.
+               if (rr->nta->question.ThisQInterval != -1)
+                       LogMsg("hndlRecordUpdateReply: ResourceRecord %s, zone info question %##s (%s) interval %d not -1",
+                               ARDisplayString(m, rr), rr->nta->question.qname.c, DNSTypeName(rr->nta->question.qtype), rr->nta->question.ThisQInterval);
+               UpdatePort = rr->nta->Port;
+               CancelGetZoneData(m, rr->nta);
+               rr->nta = mDNSNULL;
+               }
+
+       // If we are deregistering the record, then complete the deregistration. Ignore any NAT/SRV change
+       // that could have happened during that time.
+       if (rr->resrec.RecordType == kDNSRecordTypeDeregistering && rr->state == regState_DeregPending)
+               {
+               debugf("hndlRecordUpdateReply: 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 %d",
+                                               rr->resrec.name->c, rr->resrec.rrtype, err);
+               rr->state = regState_Unregistered;
+               CompleteDeregistration(m, rr);
+               return;
+               }
 
-       SetRecordRetry(m, rr, mStatus_NoError);
+       // We are returning early without updating the state. When we come back from sleep we will re-register after
+       // re-initializing all the state as though it is a first registration. If the record can't be registered e.g.,
+       // no target, it will be deregistered. Hence, the updating to the right state should not matter when going
+       // to sleep.
+       if (m->SleepState)
+               {
+               // Need to set it to NoTarget state so that RecordReadyForSleep knows that
+               // we are done
+               if (rr->resrec.rrtype == kDNSType_SRV && rr->state == regState_DeregPending)
+                       rr->state = regState_NoTarget;
+               return;
+               }
 
        if (rr->state == regState_UpdatePending)
                {
                if (err) LogMsg("Update record failed for %##s (err %d)", rr->resrec.name->c, err);
                rr->state = regState_Registered;
                // deallocate old RData
-               if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->OrigRData);
+               if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->OrigRData, rr->OrigRDLen);
                SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen);
                rr->OrigRData = mDNSNULL;
                rr->InFlightRData = mDNSNULL;
                }
 
-       if (rr->state == regState_DeregPending)
-               {
-               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 %d",
-                                               rr->resrec.name->c, rr->resrec.rrtype, err);
-               err = mStatus_MemFree;
-               rr->state = regState_Unregistered;
-               }
-
-       if (rr->state == regState_DeregDeferred)
+       if (rr->SRVChanged)
                {
-               if (err)
+               if (rr->resrec.rrtype == kDNSType_SRV)
+                       hndlSRVChanged(m, rr);
+               else
                        {
-                       LogMsg("Cancelling deferred deregistration record %##s type %d due to registration error %d",
-                                  rr->resrec.name->c, rr->resrec.rrtype, err);
-                       rr->state = regState_Unregistered;
+                       LogInfo("hndlRecordUpdateReply: Deregistered %##s (%s), state %d", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype), rr->state);
+                       rr->SRVChanged = mDNSfalse; 
+                       if (rr->state != regState_DeregPending) LogMsg("hndlRecordUpdateReply: ResourceRecord %s not in DeregPending state %d", ARDisplayString(m, rr), rr->state);
+                       rr->state = regState_NoTarget;  // Wait for the next target change
                        }
-               debugf("Calling deferred deregistration of record %##s type %d",  rr->resrec.name->c, rr->resrec.rrtype);
-               rr->state = regState_Registered;
-               mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);
                return;
                }
-
+               
        if (rr->state == regState_Pending || rr->state == regState_Refresh)
                {
                if (!err)
@@ -4078,24 +3159,20 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
                        }
                else
                        {
-                       if (rr->uselease && err == mStatus_UnknownErr && mDNSSameIPPort(rr->UpdatePort, UnicastDNSPort))
+                       // Retry without lease only for non-Private domains
+                       LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %d", rr->resrec.name->c, rr->resrec.rrtype, err);
+                       if (!rr->Private && rr->uselease && err == mStatus_UnknownErr && mDNSSameIPPort(UpdatePort, UnicastDNSPort))
                                {
-                               LogMsg("Re-trying update of record %##s without lease option", rr->resrec.name->c);
+                               LogMsg("hndlRecordUpdateReply: Will retry update of record %##s without lease option", rr->resrec.name->c);
                                rr->uselease = mDNSfalse;
-                               SendRecordRegistration(m, rr);
+                               rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
+                               rr->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL;
                                return;
                                }
-                       LogMsg("hndlRecordUpdateReply: Registration of record %##s type %d failed with error %d", rr->resrec.name->c, rr->resrec.rrtype, err);
-                       return;
+                       // Communicate the error to the application in the callback below
                        }
                }
 
-       if (rr->state == regState_Unregistered)         // Should never happen
-               {
-               LogMsg("hndlRecordUpdateReply rr->state == regState_Unregistered %s", ARDisplayString(m, rr));
-               return;
-               }
-
        if (rr->QueuedRData && rr->state == regState_Registered)
                {
                rr->state = regState_UpdatePending;
@@ -4104,12 +3181,17 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err)
                rr->OrigRData = rr->resrec.rdata;
                rr->OrigRDLen = rr->resrec.rdlength;
                rr->QueuedRData = mDNSNULL;
-               SendRecordRegistration(m, rr);
+               rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
+               rr->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL;
                return;
                }
 
-       if (InvokeCallback && rr->RecordCallback)
+       // Don't invoke the callback on error as this may not be useful to the client.
+       // The client may potentially delete the resource record on error which we normally
+       // delete during deregistration
+       if (!err && InvokeCallback && rr->RecordCallback)
                {
+               LogInfo("hndlRecordUpdateReply: Calling record callback on %##s", rr->resrec.name->c);
                mDNS_DropLockBeforeCallback();
                rr->RecordCallback(m, rr, err);
                mDNS_ReclaimLockAfterCallback();
@@ -4139,11 +3221,14 @@ mDNSexport void uDNS_ReceiveNATPMPPacket(mDNS *m, const mDNSInterfaceID Interfac
 
        // We compute a conservative estimate of how much the NAT gateways's clock should have advanced
        // 1. We subtract 12.5% from our own measured elapsed time, to allow for NAT gateways that have an inacurate clock that runs slowly
-       // 2. We add a two-second safety margin to allow for rounding errors:
-       //    -- e.g. if NAT gateway sends a packet at t=2.00 seconds, then one at t=7.99, that's virtually 6 seconds,
-       //       but based on the values in the packet (2,7) the apparent difference is only 5 seconds
-       //    -- similarly, if we're slow handling packets and/or we have coarse clock granularity, we could over-estimate the true interval
-       //       (e.g. t=1.99 seconds rounded to 1, and t=8.01 rounded to 8, gives an apparent difference of 7 seconds)
+       // 2. We add a two-second safety margin to allow for rounding errors: e.g.
+       //    -- if NAT gateway sends a packet at t=2.000 seconds, then one at t=7.999, that's approximately 6 real seconds,
+       //       but based on the values in the packet (2,7) the apparent difference according to the packet is only 5 seconds
+       //    -- if we're slow handling packets and/or we have coarse clock granularity,
+       //       we could receive the t=2 packet at our t=1.999 seconds, which we round down to 1
+       //       and the t=7.999 packet at our t=8.000 seconds, which we record as 8,
+       //       giving an apparent local time difference of 7 seconds
+       //    The two-second safety margin coves this possible calculation discrepancy
        if (AddrReply->upseconds < m->LastNATupseconds || nat_elapsed + 2 < our_elapsed - our_elapsed/8)
                { LogMsg("NAT gateway %#a rebooted", &m->Router); RecreateNATMappings(m); }
 
@@ -4335,12 +3420,12 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
        (void)srcport; // Unused
 
        debugf("uDNS_ReceiveMsg from %#-15a with "
-               "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s",
+               "%2d Question%s %2d Answer%s %2d Authorit%s %2d Additional%s %d bytes",
                srcaddr,
-               msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", " : "s,",
-               msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", " : "s,",
+               msg->h.numQuestions,   msg->h.numQuestions   == 1 ? ", "   : "s,",
+               msg->h.numAnswers,     msg->h.numAnswers     == 1 ? ", "   : "s,",
                msg->h.numAuthorities, msg->h.numAuthorities == 1 ? "y,  " : "ies,",
-               msg->h.numAdditionals, msg->h.numAdditionals == 1 ? "" : "s");
+               msg->h.numAdditionals, msg->h.numAdditionals == 1 ? ""     : "s", end - msg->data);
 
        if (QR_OP == StdR)
                {
@@ -4350,48 +3435,27 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
                        if (msg->h.flags.b[0] & kDNSFlag0_TC && mDNSSameOpaque16(qptr->TargetQID, msg->h.id) && m->timenow - qptr->LastQTime < RESPONSE_WINDOW)
                                {
                                if (!srcaddr) LogMsg("uDNS_ReceiveMsg: TCP DNS response had TC bit set: ignoring");
-                               else if (qptr->tcp)
+                               else
                                        {
-                                       // There may be a race condition here, if the server decides to drop the connection just as we decide to reuse it
-                                       // For now it should not be serious because our normal retry logic (as used to handle UDP packet loss)
-                                       // should take care of it but later we may want to look at handling this case explicitly
-                                       LogInfo("uDNS_ReceiveMsg: Using existing TCP connection for %##s (%s)", qptr->qname.c, DNSTypeName(qptr->qtype));
-                                       mDNS_DropLockBeforeCallback();
-                                       tcpCallback(qptr->tcp->sock, qptr->tcp, mDNStrue, mStatus_NoError);
-                                       mDNS_ReclaimLockAfterCallback();
+                                       // Don't reuse TCP connections. We might have failed over to a different DNS server
+                                       // while the first TCP connection is in progress. We need a new TCP connection to the
+                                       // new DNS server. So, always try to establish a new connection.
+                                       if (qptr->tcp) { DisposeTCPConn(qptr->tcp); qptr->tcp = mDNSNULL; }
+                                       qptr->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_Zero, srcaddr, srcport, mDNSNULL, qptr, mDNSNULL);
                                        }
-                               else qptr->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_Zero, srcaddr, srcport, qptr, mDNSNULL, mDNSNULL);
                                }
                }
 
        if (QR_OP == UpdateR)
                {
                mDNSu32 lease = GetPktLease(m, msg, end);
-               mDNSs32 expire = m->timenow + (mDNSs32)lease * mDNSPlatformOneSecond;
-
-               //rcode = kDNSFlag1_RC_ServFail;        // Simulate server failure (rcode 2)
-
-               if (CurrentServiceRecordSet)
-                       LogMsg("uDNS_ReceiveMsg ERROR CurrentServiceRecordSet already set");
-               CurrentServiceRecordSet = m->ServiceRegistrations;
-
-               while (CurrentServiceRecordSet)
-                       {
-                       ServiceRecordSet *sptr = CurrentServiceRecordSet;
-                       CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
-
-                       if (mDNSSameOpaque16(sptr->id, msg->h.id))
-                               {
-                               err = checkUpdateResult(m, sptr->RR_SRV.resrec.name, rcode, msg, end);
-                               if (!err && sptr->srs_uselease && lease)
-                                       if (sptr->RR_SRV.expire - expire >= 0 || sptr->state != regState_UpdatePending)
-                                               sptr->RR_SRV.expire = expire;
-                               hndlServiceUpdateReply(m, sptr, err);
-                               CurrentServiceRecordSet = mDNSNULL;
-                               return;
-                               }
-                       }
+               mDNSs32 expire = m->timenow + (mDNSs32)lease * mDNSPlatformOneSecond;
+               mDNSu32 random = mDNSRandom((mDNSs32)lease * mDNSPlatformOneSecond/10);
+
+               //rcode = kDNSFlag1_RC_ServFail;        // Simulate server failure (rcode 2)
 
+               // Walk through all the records that matches the messageID. There could be multiple
+               // records if we had sent them in a group
                if (m->CurrentRecord)
                        LogMsg("uDNS_ReceiveMsg ERROR m->CurrentRecord already set %s", ARDisplayString(m, m->CurrentRecord));
                m->CurrentRecord = m->ResourceRecords;
@@ -4404,10 +3468,13 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
                                err = checkUpdateResult(m, rptr->resrec.name, rcode, msg, end);
                                if (!err && rptr->uselease && lease)
                                        if (rptr->expire - expire >= 0 || rptr->state != regState_UpdatePending)
+                                               {
                                                rptr->expire = expire;
-                               hndlRecordUpdateReply(m, rptr, err);
-                               m->CurrentRecord = mDNSNULL;
-                               return;
+                                               rptr->refreshCount = 0;
+                                               }
+                               // We pass the random value to make sure that if we update multiple
+                               // records, they all get the same random value
+                               hndlRecordUpdateReply(m, rptr, err, random);
                                }
                        }
                }
@@ -4423,6 +3490,7 @@ mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q)
        {
        mDNSu8 *end;
        LLQOptData llq;
+       mDNSu8 *limit = m->omsg.data + AbsoluteMaxDNSMessageData;
 
        if (q->ReqLease)
                if ((q->state == LLQ_Established && q->ntries >= kLLQ_MAX_TRIES) || q->expire - m->timenow < 0)
@@ -4444,23 +3512,31 @@ mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q)
 
        // Note that we (conditionally) add HINFO and TSIG here, since the question might be going away,
        // so we may not be able to reference it (most importantly it's AuthInfo) when we actually send the message
-       end = putHINFO(m, &m->omsg, end, q->AuthInfo);
+       end = putHINFO(m, &m->omsg, end, q->AuthInfo, limit);
        if (!end) { LogMsg("sendLLQRefresh: putHINFO failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
 
-       if (q->AuthInfo)
+       if (PrivateQuery(q))
                {
                DNSDigest_SignMessageHostByteOrder(&m->omsg, &end, q->AuthInfo);
                if (!end) { LogMsg("sendLLQRefresh: DNSDigest_SignMessage failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
                }
 
-       if (q->AuthInfo && !q->tcp)
+       if (PrivateQuery(q) && !q->tcp)
                {
                LogInfo("sendLLQRefresh setting up new TLS session %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-               q->tcp = MakeTCPConn(m, &m->omsg, end, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, q, mDNSNULL, mDNSNULL);
+               if (!q->nta) { LogMsg("sendLLQRefresh:ERROR!! q->nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
+               q->tcp = MakeTCPConn(m, &m->omsg, end, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, &q->nta->Host, q, mDNSNULL);
                }
        else
                {
-               mStatus err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, mDNSNULL);
+               mStatus err;
+
+               // if AuthInfo and AuthInfo->AutoTunnel is set, we use the TCP socket but don't need to pass the AuthInfo as
+               // we already protected the message above.
+               LogInfo("sendLLQRefresh: using existing %s session %##s (%s)", PrivateQuery(q) ? "TLS" : "UDP",
+                       q->qname.c, DNSTypeName(q->qtype));
+
+               err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, mDNSNULL);
                if (err)
                        {
                        LogMsg("sendLLQRefresh: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err);
@@ -4482,24 +3558,39 @@ mDNSexport void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneI
 
        mDNS_Lock(m);
 
-       // If we get here it means that the GetZoneData operation has completed, and is is about to cancel
-       // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which
-       // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes).
-       q->nta      = mDNSNULL;
+       // If we get here it means that the GetZoneData operation has completed.
+       // We hold on to the zone data if it is AutoTunnel as we use the hostname
+       // in zoneInfo during the TLS connection setup.
        q->servAddr = zeroAddr;
        q->servPort = zeroIPPort;
 
-       if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port) && !mDNSAddressIsZero(&zoneInfo->Addr))
+       if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port) && !mDNSAddressIsZero(&zoneInfo->Addr) && zoneInfo->Host.c[0])
                {
                q->servAddr = zoneInfo->Addr;
                q->servPort = zoneInfo->Port;
-               q->AuthInfo = zoneInfo->ZonePrivate ? GetAuthInfoForName_internal(m, &q->qname) : mDNSNULL;
+               if (!PrivateQuery(q))
+                       {
+                       // We don't need the zone data as we use it only for the Host information which we
+                       // don't need if we are not going to use TLS connections.
+                       if (q->nta)
+                               {
+                               if (q->nta != zoneInfo) LogMsg("LLQGotZoneData: nta (%p) != zoneInfo (%p)  %##s (%s)", q->nta, zoneInfo, q->qname.c, DNSTypeName(q->qtype));
+                               CancelGetZoneData(m, q->nta);
+                               q->nta = mDNSNULL;
+                               }
+                       }
                q->ntries = 0;
                debugf("LLQGotZoneData %#a:%d", &q->servAddr, mDNSVal16(q->servPort));
                startLLQHandshake(m, q);
                }
        else
                {
+               if (q->nta)
+                       {
+                       if (q->nta != zoneInfo) LogMsg("LLQGotZoneData: nta (%p) != zoneInfo (%p)  %##s (%s)", q->nta, zoneInfo, q->qname.c, DNSTypeName(q->qtype));
+                       CancelGetZoneData(m, q->nta);
+                       q->nta = mDNSNULL;
+                       }
                StartLLQPolling(m,q);
                if (err == mStatus_NoSuchNameErr) 
                        {
@@ -4519,17 +3610,16 @@ mDNSlocal void PrivateQueryGotZoneData(mDNS *const m, mStatus err, const ZoneDat
 
        LogInfo("PrivateQueryGotZoneData %##s (%s) err %d Zone %##s Private %d", q->qname.c, DNSTypeName(q->qtype), err, zoneInfo->ZoneName.c, zoneInfo->ZonePrivate);
 
-       // If we get here it means that the GetZoneData operation has completed, and is is about to cancel
-       // its question and free the ZoneData memory. We no longer need to hold onto our pointer (which
-       // we use for cleaning up if our LLQ is cancelled *before* the GetZoneData operation has completes).
-       q->nta = mDNSNULL;
+       if (q->nta != zoneInfo) LogMsg("PrivateQueryGotZoneData:ERROR!!: nta (%p) != zoneInfo (%p)  %##s (%s)", q->nta, zoneInfo, q->qname.c, DNSTypeName(q->qtype));
 
-       if (err || !zoneInfo || mDNSAddressIsZero(&zoneInfo->Addr) || mDNSIPPortIsZero(zoneInfo->Port))
+       if (err || !zoneInfo || mDNSAddressIsZero(&zoneInfo->Addr) || mDNSIPPortIsZero(zoneInfo->Port) || !zoneInfo->Host.c[0])
                {
-               LogInfo("ERROR: PrivateQueryGotZoneData %##s (%s) invoked with error code %d %p %#a:%d",
+               LogInfo("PrivateQueryGotZoneData: ERROR!! %##s (%s) invoked with error code %d %p %#a:%d",
                        q->qname.c, DNSTypeName(q->qtype), err, zoneInfo,
                        zoneInfo ? &zoneInfo->Addr : mDNSNULL,
                        zoneInfo ? mDNSVal16(zoneInfo->Port) : 0);
+               CancelGetZoneData(m, q->nta);
+               q->nta = mDNSNULL;
                return;
                }
 
@@ -4539,6 +3629,8 @@ mDNSlocal void PrivateQueryGotZoneData(mDNS *const m, mStatus err, const ZoneDat
                q->AuthInfo      = mDNSNULL;            // Clear AuthInfo so we try again non-private
                q->ThisQInterval = InitialQuestionInterval;
                q->LastQTime     = m->timenow - q->ThisQInterval;
+               CancelGetZoneData(m, q->nta);
+               q->nta = mDNSNULL;
                mDNS_Lock(m);
                SetNextQueryTime(m, q);
                mDNS_Unlock(m);
@@ -4546,15 +3638,19 @@ mDNSlocal void PrivateQueryGotZoneData(mDNS *const m, mStatus err, const ZoneDat
                // Next call to uDNS_CheckCurrentQuestion() will do this as a non-private query
                }
 
-       if (!q->AuthInfo)
+       if (!PrivateQuery(q))
                {
-               LogMsg("ERROR: PrivateQueryGotZoneData: cannot find credentials for q %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+               LogMsg("PrivateQueryGotZoneData: ERROR!! Not a private query %##s (%s) AuthInfo %p", q->qname.c, DNSTypeName(q->qtype), q->AuthInfo);
+               CancelGetZoneData(m, q->nta);
+               q->nta = mDNSNULL;
                return;
                }
 
        q->TargetQID = mDNS_NewMessageID(m);
-       if (q->tcp) DisposeTCPConn(q->tcp);
-       q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &zoneInfo->Addr, zoneInfo->Port, q, mDNSNULL, mDNSNULL);
+       if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
+       if (!q->nta) { LogMsg("PrivateQueryGotZoneData:ERROR!! nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
+       q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &zoneInfo->Addr, zoneInfo->Port, &q->nta->Host, q, mDNSNULL);
+       if (q->nta) { CancelGetZoneData(m, q->nta); q->nta = mDNSNULL; }
        }
 
 // ***************************************************************************
@@ -4569,23 +3665,28 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const
        AuthRecord *ptr;
        int c1, c2;
 
+       if (newRR->nta != zoneData)
+               LogMsg("RecordRegistrationGotZoneData: nta (%p) != zoneData (%p)  %##s (%s)", newRR->nta, zoneData, newRR->resrec.name->c, DNSTypeName(newRR->resrec.rrtype));
+
        if (m->mDNS_busy != m->mDNS_reentrancy)
                LogMsg("RecordRegistrationGotZoneData: mDNS_busy (%ld) != mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 
-       newRR->nta = mDNSNULL;
-
-       // Start off assuming we're going to use a lease
-       // If we get an error from the server, and the update port as given in the SRV record is 53, then we'll retry without the lease option
-       newRR->uselease = mDNStrue;
-
        // make sure record is still in list (!!!)
        for (ptr = m->ResourceRecords; ptr; ptr = ptr->next) if (ptr == newRR) break;
-       if (!ptr) { LogMsg("RecordRegistrationGotZoneData - RR no longer in list.  Discarding."); return; }
+       if (!ptr)
+               {
+               LogMsg("RecordRegistrationGotZoneData - RR no longer in list.  Discarding.");
+               CancelGetZoneData(m, newRR->nta);
+               newRR->nta = mDNSNULL;
+               return;
+               }
 
        // check error/result
        if (err)
                {
                if (err != mStatus_NoSuchNameErr) LogMsg("RecordRegistrationGotZoneData: error %d", err);
+               CancelGetZoneData(m, newRR->nta);
+               newRR->nta = mDNSNULL;
                return;
                }
 
@@ -4594,6 +3695,8 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const
        if (newRR->resrec.rrclass != zoneData->ZoneClass)
                {
                LogMsg("ERROR: New resource record's class (%d) does not match zone class (%d)", newRR->resrec.rrclass, zoneData->ZoneClass);
+               CancelGetZoneData(m, newRR->nta);
+               newRR->nta = mDNSNULL;
                return;
                }
 
@@ -4603,6 +3706,8 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const
        if (zoneData->ZoneName.c[0] == 0)
                {
                LogInfo("RecordRegistrationGotZoneData: No name server found claiming responsibility for \"%##s\"!", newRR->resrec.name->c);
+               CancelGetZoneData(m, newRR->nta);
+               newRR->nta = mDNSNULL;
                return;
                }
 
@@ -4612,188 +3717,267 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const
        if (c2 > c1)
                {
                LogMsg("RecordRegistrationGotZoneData: Zone \"%##s\" is longer than \"%##s\"", zoneData->ZoneName.c, newRR->resrec.name->c);
+               CancelGetZoneData(m, newRR->nta);
+               newRR->nta = mDNSNULL;
                return;
                }
        newRR->zone = SkipLeadingLabels(newRR->resrec.name, c1-c2);
        if (!SameDomainName(newRR->zone, &zoneData->ZoneName))
                {
                LogMsg("RecordRegistrationGotZoneData: Zone \"%##s\" does not match \"%##s\" for \"%##s\"", newRR->zone->c, zoneData->ZoneName.c, newRR->resrec.name->c);
+               CancelGetZoneData(m, newRR->nta);
+               newRR->nta = mDNSNULL;
                return;
                }
-       newRR->UpdateServer = zoneData->Addr;
-       newRR->UpdatePort   = zoneData->Port;
-       newRR->Private      = zoneData->ZonePrivate;
-       debugf("RecordRegistrationGotZoneData: Set newRR->UpdateServer %##s %##s to %#a:%d",
-               newRR->resrec.name->c, zoneData->ZoneName.c, &newRR->UpdateServer, mDNSVal16(newRR->UpdatePort));
 
-       if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr))
+       if (mDNSIPPortIsZero(zoneData->Port) || mDNSAddressIsZero(&zoneData->Addr) || !zoneData->Host.c[0])
                {
                LogInfo("RecordRegistrationGotZoneData: No _dns-update._udp service found for \"%##s\"!", newRR->resrec.name->c);
+               CancelGetZoneData(m, newRR->nta);
+               newRR->nta = mDNSNULL;
                return;
                }
 
-       newRR->ThisAPInterval = 5 * mDNSPlatformOneSecond;              // After doubling, first retry will happen after ten seconds
+       newRR->Private      = zoneData->ZonePrivate;
+       debugf("RecordRegistrationGotZoneData: Set zone information for %##s %##s to %#a:%d",
+               newRR->resrec.name->c, zoneData->ZoneName.c, &zoneData->Addr, mDNSVal16(zoneData->Port));
+
+       // If we are deregistering, uDNS_DeregisterRecord will do that as it has the zone data now.
+       if (newRR->state == regState_DeregPending)
+               {
+               mDNS_Lock(m);
+               uDNS_DeregisterRecord(m, newRR);
+               mDNS_Unlock(m);
+               return;
+               }
 
-       mDNS_Lock(m);   // SendRecordRegistration expects to be called with the lock held
-       SendRecordRegistration(m, newRR);
+       if (newRR->resrec.rrtype == kDNSType_SRV)
+               {
+               const domainname *target;
+               // Reevaluate the target always as NAT/Target could have changed while
+               // we were fetching zone data.
+               mDNS_Lock(m);
+               target = GetServiceTarget(m, newRR);
+               mDNS_Unlock(m);
+               if (!target || target->c[0] == 0)
+                       {
+                       domainname *t = GetRRDomainNameTarget(&newRR->resrec);
+                       LogInfo("RecordRegistrationGotZoneData - no target for %##s", newRR->resrec.name->c);
+                       if (t) t->c[0] = 0;
+                       newRR->resrec.rdlength = newRR->resrec.rdestimate = 0;
+                       newRR->state = regState_NoTarget;
+                       CancelGetZoneData(m, newRR->nta);
+                       newRR->nta = mDNSNULL;
+                       return;
+                       }
+               }
+       // If we have non-zero service port (always?)
+       // and a private address, and update server is non-private
+       // and this service is AutoTarget
+       // then initiate a NAT mapping request. On completion it will do SendRecordRegistration() for us
+       if (newRR->resrec.rrtype == kDNSType_SRV && !mDNSIPPortIsZero(newRR->resrec.rdata->u.srv.port) &&
+               mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && newRR->nta && !mDNSAddrIsRFC1918(&newRR->nta->Addr) &&
+               newRR->AutoTarget == Target_AutoHostAndNATMAP)
+               {
+               DomainAuthInfo *AuthInfo;
+               AuthInfo = GetAuthInfoForName(m, newRR->resrec.name);
+               if (AuthInfo && AuthInfo->AutoTunnel)
+                       {
+                       domainname *t = GetRRDomainNameTarget(&newRR->resrec);
+                       LogMsg("RecordRegistrationGotZoneData: ERROR!! AutoTunnel has Target_AutoHostAndNATMAP for %s", ARDisplayString(m, newRR));
+                       if (t) t->c[0] = 0;
+                       newRR->resrec.rdlength = newRR->resrec.rdestimate = 0;
+                       newRR->state = regState_NoTarget;
+                       CancelGetZoneData(m, newRR->nta);
+                       newRR->nta = mDNSNULL;
+                       return;
+                       }
+               // During network transitions, we are called multiple times in different states. Setup NAT
+               // state just once for this record.
+               if (!newRR->NATinfo.clientContext)
+                       {
+                       LogInfo("RecordRegistrationGotZoneData StartRecordNatMap %s", ARDisplayString(m, newRR));
+                       newRR->state = regState_NATMap;
+                       StartRecordNatMap(m, newRR);
+                       return;
+                       }
+               else LogInfo("RecordRegistrationGotZoneData: StartRecordNatMap for %s, state %d, context %p", ARDisplayString(m, newRR), newRR->state, newRR->NATinfo.clientContext);
+               }
+       mDNS_Lock(m);
+       // We want IsRecordMergeable to check whether it is a record whose update can be
+       // sent with others. We set the time before we call IsRecordMergeable, so that
+       // it does not fail this record based on time. We are interested in other checks
+       // at this time. If a previous update resulted in error, then don't reset the
+       // interval. Preserve the back-off so that we don't keep retrying aggressively.
+       if (newRR->updateError == mStatus_NoError)
+               {
+               newRR->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
+               newRR->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL;
+               }
+       if (IsRecordMergeable(m, newRR, m->timenow + MERGE_DELAY_TIME))
+               {
+               // Delay the record registration by MERGE_DELAY_TIME so that we can merge them
+               // into one update
+               LogInfo("RecordRegistrationGotZoneData: Delayed registration for %s", ARDisplayString(m, newRR));
+               newRR->LastAPTime += MERGE_DELAY_TIME;
+               }
        mDNS_Unlock(m);
        }
 
 mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
        {
        mDNSu8 *ptr = m->omsg.data;
-       mDNSu8 *end = (mDNSu8 *)&m->omsg + sizeof(DNSMessage);
+       mDNSu8 *limit;
+       DomainAuthInfo *AuthInfo;
+
+       if (m->mDNS_busy != m->mDNS_reentrancy+1)
+               LogMsg("SendRecordDeRegistration: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
 
-       if (mDNSIPv4AddressIsZero(rr->UpdateServer.ip.v4))      // Don't know our UpdateServer yet
+       if (!rr->nta || mDNSIPv4AddressIsZero(rr->nta->Addr.ip.v4))
                {
-               rr->LastAPTime = m->timenow;
-               if (rr->ThisAPInterval < mDNSPlatformOneSecond * 5)
-                       rr->ThisAPInterval = mDNSPlatformOneSecond * 5;
+               LogMsg("SendRecordDeRegistration: No zone info for Resource record %s RecordType %d", ARDisplayString(m, rr), rr->resrec.RecordType);
                return;
                }
 
+       limit = ptr + AbsoluteMaxDNSMessageData;
+       AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
+       limit -= RRAdditionalSize(m, AuthInfo);
+
+       rr->updateid = mDNS_NewMessageID(m);
        InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags);
 
-       ptr = putZone(&m->omsg, ptr, end, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
-       if (ptr) ptr = putDeletionRecord(&m->omsg, ptr, &rr->resrec);
-       if (!ptr)
+       // set zone
+       ptr = putZone(&m->omsg, ptr, limit, rr->zone, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
+       if (!ptr) goto exit;
+
+       ptr = BuildUpdateMessage(m, ptr, rr, limit);
+
+       if (!ptr) goto exit;
+
+       if (rr->Private)
                {
-               LogMsg("SendRecordDeregistration Error: could not contruct deregistration packet for %s", ARDisplayString(m, rr));
-               if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr);
+               LogInfo("SendRecordDeregistration TCP %p %s", rr->tcp, ARDisplayString(m, rr));
+               if (rr->tcp) LogInfo("SendRecordDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m, rr));
+               if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
+               if (!rr->nta) { LogMsg("SendRecordDeregistration:Private:ERROR!! nta is NULL for %s", ARDisplayString(m, rr)); return; }
+               rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->nta->Addr, rr->nta->Port, &rr->nta->Host, mDNSNULL, rr);
                }
        else
                {
-               rr->expire = 0;         // Indicate that we have no active registration any more
-               if (rr->Private)
-                       {
-                       LogInfo("SendRecordDeregistration TCP %p %s", rr->tcp, ARDisplayString(m, rr));
-                       if (rr->tcp) LogInfo("SendRecordDeregistration: Disposing existing TCP connection for %s", ARDisplayString(m, rr));
-                       if (rr->tcp) DisposeTCPConn(rr->tcp);
-                       rr->tcp = MakeTCPConn(m, &m->omsg, ptr, kTCPSocketFlags_UseTLS, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, mDNSNULL, rr);
-                       if (!rr->tcp) rr->ThisAPInterval = mDNSPlatformOneSecond * 5; // If failed to make TCP connection, try again in ten seconds (5*2)
-                       else if (rr->ThisAPInterval < mDNSPlatformOneSecond * 30) rr->ThisAPInterval = mDNSPlatformOneSecond * 30;
-                       SetRecordRetry(m, rr, mStatus_NoError);
-                       }
-               else
-                       {
-                       mStatus err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->UpdateServer, rr->UpdatePort, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
-                       if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %d", err);
-                       if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr);          // Don't touch rr after this
-                       }
+               mStatus err;
+               LogInfo("SendRecordDeregistration UDP %s", ARDisplayString(m, rr));
+               if (!rr->nta) { LogMsg("SendRecordDeregistration:ERROR!! nta is NULL for %s", ARDisplayString(m, rr)); return; }
+               err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->nta->Addr, rr->nta->Port, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name));
+               if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %d", err);
+               //if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr);                // Don't touch rr after this
                }
+       SetRecordRetry(m, rr, 0);
+       return;
+exit:
+       LogMsg("SendRecordDeregistration: Error formatting message for %s", ARDisplayString(m, rr));
        }
 
 mDNSexport mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr)
        {
+       DomainAuthInfo *info;
+
+       LogInfo("uDNS_DeregisterRecord: Resource Record %s, state %d", ARDisplayString(m, rr), rr->state);
+
        switch (rr->state)
                {
-               case regState_NATMap:        LogMsg("regState_NATMap        %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
-               case regState_ExtraQueued: rr->state = regState_Unregistered; break;
                case regState_Refresh:
                case regState_Pending:
                case regState_UpdatePending:
-               case regState_FetchingZoneData:
                case regState_Registered: break;
                case regState_DeregPending: break;
-               case regState_DeregDeferred: LogMsg("regState_DeregDeferred %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
-               case regState_Unregistered:  LogMsg("regState_Unregistered  %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
-               case regState_NATError:      LogMsg("regState_NATError      %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
-               case regState_NoTarget:      LogMsg("regState_NoTarget      %##s type %s", rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
-               default: LogMsg("uDNS_DeregisterRecord: State %d for %##s type %s", rr->state, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype)); return mStatus_NoError;
-               }
-
-       if (rr->state != regState_Unregistered) { rr->state = regState_DeregPending; SendRecordDeregistration(m, rr); }
-       return mStatus_NoError;
-       }
 
-// Called with lock held
-mDNSexport mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs)
-       {
-       char *errmsg = "Unknown State";
-
-       if (m->mDNS_busy != m->mDNS_reentrancy+1)
-               LogMsg("uDNS_DeregisterService: Lock not held! mDNS_busy (%ld) mDNS_reentrancy (%ld)", m->mDNS_busy, m->mDNS_reentrancy);
-
-       // don't re-register with a new target following deregistration
-       srs->SRVChanged = srs->SRVUpdateDeferred = mDNSfalse;
+               case regState_NATError: 
+               case regState_NATMap:
+               // A record could be in NoTarget to start with if the corresponding SRV record could not find a target.
+               // It is also possible to reenter the NoTarget state when we move to a network with a NAT that has
+               // no NAT-PMP/UPnP support. In that case before we entered NoTarget, we already deregistered with
+               // the server.
+               case regState_NoTarget: 
+               case regState_Unregistered:
+               case regState_Zero:
+               default:
+                       LogInfo("uDNS_DeregisterRecord: State %d for %##s type %s", rr->state, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+                       // This function may be called during sleep when there are no sleep proxy servers
+                       if (rr->resrec.RecordType == kDNSRecordTypeDeregistering) CompleteDeregistration(m, rr);
+                       return mStatus_NoError;
+               }
 
-       if (srs->srs_nta) { CancelGetZoneData(m, srs->srs_nta); srs->srs_nta = mDNSNULL; }
+       // If a current group registration is pending, we can't send this deregisration till that registration
+       // has reached the server i.e., the ordering is important. Previously, if we did not send this
+       // registration in a group, then the previous connection will be torn down as part of sending the
+       // deregistration. If we send this in a group, we need to locate the resource record that was used
+       // to send this registration and terminate that connection. This means all the updates on that might
+       // be lost (assuming the response is not waiting for us at the socket) and the retry will send the
+       // update again sometime in the near future.
+       //
+       // NOTE: SSL handshake failures normally free the TCP connection immediately. Hence, you may not
+       // find the TCP below there. This case can happen only when tcp is trying to actively retransmit
+       // the request or SSL negotiation taking time i.e resource record is actively trying to get the
+       // message to the server. During that time a deregister has to happen.
 
-       if (srs->NATinfo.clientContext)
+       if (!mDNSOpaque16IsZero(rr->updateid))
                {
-               mDNS_StopNATOperation_internal(m, &srs->NATinfo);
-               srs->NATinfo.clientContext = mDNSNULL;
+               AuthRecord *anchorRR;
+               mDNSBool found = mDNSfalse;
+               for (anchorRR = m->ResourceRecords; anchorRR; anchorRR = anchorRR->next)
+                       {
+                       if (AuthRecord_uDNS(rr) && mDNSSameOpaque16(anchorRR->updateid, rr->updateid) && anchorRR->tcp)
+                               {
+                               LogInfo("uDNS_DeregisterRecord: Found Anchor RR %s terminated", ARDisplayString(m, anchorRR));
+                               if (found)
+                                       LogMsg("uDNS_DeregisterRecord: ERROR: Another anchorRR %s found", ARDisplayString(m, anchorRR));
+                               DisposeTCPConn(anchorRR->tcp);
+                               anchorRR->tcp = mDNSNULL;
+                               found = mDNStrue;
+                               }
+                       }
+               if (!found) LogInfo("uDNSDeregisterRecord: Cannot find the anchor Resource Record for %s, not an error", ARDisplayString(m, rr));
                }
 
-       switch (srs->state)
+       // Retry logic for deregistration should be no different from sending registration the first time.
+       // Currently ThisAPInterval most likely is set to the refresh interval
+       rr->state          = regState_DeregPending;
+       rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
+       rr->LastAPTime     = m->timenow - INIT_RECORD_REG_INTERVAL;
+       info = GetAuthInfoForName_internal(m, rr->resrec.name);
+       if (IsRecordMergeable(m, rr, m->timenow + MERGE_DELAY_TIME))
                {
-               case regState_Unregistered:
-                       debugf("uDNS_DeregisterService - service %##s not registered", srs->RR_SRV.resrec.name->c);
-                       return mStatus_BadReferenceErr;
-               case regState_DeregPending:
-               case regState_DeregDeferred:
-                       debugf("Double deregistration of service %##s", srs->RR_SRV.resrec.name->c);
-                       return mStatus_NoError;
-               case regState_NATError: // not registered
-               case regState_NATMap:   // not registered
-               case regState_NoTarget: // not registered
-                       unlinkSRS(m, srs);
-                       srs->state = regState_Unregistered;
-                       mDNS_DropLockBeforeCallback();
-                       srs->ServiceCallback(m, srs, mStatus_MemFree);
-                       mDNS_ReclaimLockAfterCallback();
-                       return mStatus_NoError;
-               case regState_Pending:
-               case regState_Refresh:
-               case regState_UpdatePending:
-               case regState_FetchingZoneData:
-               case regState_Registered:
-                       srs->state = regState_DeregPending;
-                       SendServiceDeregistration(m, srs);
-                       return mStatus_NoError;
-               case regState_ExtraQueued: // only for record registrations
-                       errmsg = "bad state (regState_ExtraQueued)";
-                       goto error;
-               default: LogMsg("uDNS_DeregisterService: Unknown state %d for %##s", srs->state, srs->RR_SRV.resrec.name->c);
+               // Delay the record deregistration by MERGE_DELAY_TIME so that we can merge them
+               // into one update. If the domain is being deleted, delay by 2 * MERGE_DELAY_TIME
+               // so that we can merge all the AutoTunnel records and the service records in
+               // one update (they get deregistered a little apart)
+               if (info && info->deltime) rr->LastAPTime += (2 * MERGE_DELAY_TIME);
+               else rr->LastAPTime += MERGE_DELAY_TIME;
                }
+       // IsRecordMergeable could have returned false for several reasons e.g., DontMerge is set or
+       // no zone information. Most likely it is the latter, CheckRecordUpdates will fetch the zone
+       // data when it encounters this record.
+
+       if (m->NextuDNSEvent - (rr->LastAPTime + rr->ThisAPInterval) >= 0)
+               m->NextuDNSEvent = (rr->LastAPTime + rr->ThisAPInterval);
 
-       error:
-       LogMsg("Error, uDNS_DeregisterService: %s", errmsg);
-       return mStatus_BadReferenceErr;
+       return mStatus_NoError;
        }
 
 mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
        {
-       ServiceRecordSet *parent = mDNSNULL;
-       AuthRecord *rptr;
-       regState_t *stateptr = mDNSNULL;
-
-       // find the record in registered service list
-       for (parent = m->ServiceRegistrations; parent; parent = parent->uDNS_next)
-               if (&parent->RR_TXT == rr) { stateptr = &parent->state; break; }
-
-       if (!parent)
-               {
-               // record not part of a service - check individual record registrations
-               for (rptr = m->ResourceRecords; rptr; rptr = rptr->next)
-                       if (rptr == rr) { stateptr = &rr->state; break; }
-               if (!rptr) goto unreg_error;
-               }
-
-       switch(*stateptr)
+       LogInfo("uDNS_UpdateRecord: Resource Record %##s, state %d", rr->resrec.name->c, rr->state);
+       switch(rr->state)
                {
                case regState_DeregPending:
-               case regState_DeregDeferred:
                case regState_Unregistered:
                        // not actively registered
                        goto unreg_error;
 
-               case regState_FetchingZoneData:
                case regState_NATMap:
-               case regState_ExtraQueued:
                case regState_NoTarget:
                        // change rdata directly since it hasn't been sent yet
-                       if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->resrec.rdata);
+                       if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->resrec.rdata, rr->resrec.rdlength);
                        SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
                        rr->NewRData = mDNSNULL;
                        return mStatus_NoError;
@@ -4804,7 +3988,7 @@ mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
                        // registration in-flight. queue rdata and return
                        if (rr->QueuedRData && rr->UpdateCallback)
                                // if unsent rdata is already queued, free it before we replace it
-                               rr->UpdateCallback(m, rr, rr->QueuedRData);
+                               rr->UpdateCallback(m, rr, rr->QueuedRData, rr->QueuedRDLen);
                        rr->QueuedRData = rr->NewRData;
                        rr->QueuedRDLen = rr->newrdlength;
                        rr->NewRData = mDNSNULL;
@@ -4816,21 +4000,21 @@ mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
                        rr->InFlightRData = rr->NewRData;
                        rr->InFlightRDLen = rr->newrdlength;
                        rr->NewRData = mDNSNULL;
-                       *stateptr = regState_UpdatePending;
-                       if (parent) SendServiceRegistration(m, parent);
-                       else SendRecordRegistration(m, rr);
+                       rr->state = regState_UpdatePending;
+                       rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
+                       rr->LastAPTime = m->timenow - INIT_RECORD_REG_INTERVAL;
                        return mStatus_NoError;
 
                case regState_NATError:
                        LogMsg("ERROR: uDNS_UpdateRecord called for record %##s with bad state regState_NATError", rr->resrec.name->c);
                        return mStatus_UnknownErr;      // states for service records only
 
-               default: LogMsg("uDNS_UpdateRecord: Unknown state %d for %##s", *stateptr, rr->resrec.name->c);
+               default: LogMsg("uDNS_UpdateRecord: Unknown state %d for %##s", rr->state, rr->resrec.name->c);
                }
 
        unreg_error:
-       LogMsg("Requested update of record %##s type %d, part of service not currently registered",
-                  rr->resrec.name->c, rr->resrec.rrtype);
+       LogMsg("uDNS_UpdateRecord: Requested update of record %##s type %d, in erroneous state %d",
+                  rr->resrec.name->c, rr->resrec.rrtype, rr->state);
        return mStatus_Invalid;
        }
 
@@ -4839,23 +4023,76 @@ mDNSexport mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr)
 #pragma mark - Periodic Execution Routines
 #endif
 
+mDNSlocal const mDNSu8 *mDNS_WABLabels[] =
+       {
+       (const mDNSu8 *)"\001b",
+       (const mDNSu8 *)"\002db",
+       (const mDNSu8 *)"\002lb",
+       (const mDNSu8 *)"\001r",
+       (const mDNSu8 *)"\002dr",
+       (const mDNSu8 *)"\002cf",
+       (const mDNSu8 *)mDNSNULL,
+       };
+
+// Returns true if it is a WAB question
+mDNSlocal mDNSBool WABQuestion(const domainname *qname)
+       {
+       const mDNSu8 *sd = (const mDNSu8 *)"\007_dns-sd";
+       const mDNSu8 *prot = (const mDNSu8 *)"\004_udp";
+       const domainname *d = qname;
+       const mDNSu8 *label;
+       int i = 0;
+
+       // We need at least 3 labels (WAB prefix) + one more label to make
+       // a meaningful WAB query
+       if (CountLabels(qname) < 4) { debugf("WABQuestion: question %##s, not enough labels", qname->c); return mDNSfalse; }
+
+       label = (const mDNSu8 *)d;
+       while (mDNS_WABLabels[i] != (const mDNSu8 *)mDNSNULL)
+               {
+               if (SameDomainLabel(mDNS_WABLabels[i], label)) {debugf("WABquestion: WAB question %##s, label1 match", qname->c); break;}
+               i++;
+               }
+       if (mDNS_WABLabels[i] == (const mDNSu8 *)mDNSNULL)
+               {
+               debugf("WABquestion: Not a WAB question %##s, label1 mismatch", qname->c);
+               return mDNSfalse;
+               }
+       // CountLabels already verified the number of labels 
+       d = (const domainname *)(d->c + 1 + d->c[0]);   // Second Label
+       label = (const mDNSu8 *)d;
+       if (!SameDomainLabel(label, sd)){ debugf("WABquestion: Not a WAB question %##s, label2 mismatch", qname->c);return(mDNSfalse); }
+       debugf("WABquestion: WAB question %##s, label2 match", qname->c);
+
+       d = (const domainname *)(d->c + 1 + d->c[0]);   // Third Label
+       label = (const mDNSu8 *)d;
+       if (!SameDomainLabel(label, prot)){ debugf("WABquestion: Not a WAB question %##s, label3 mismatch", qname->c);return(mDNSfalse); }
+       debugf("WABquestion: WAB question %##s, label3 match", qname->c);
+
+       LogInfo("WABquestion: Question %##s is a WAB question", qname->c);
+
+       return mDNStrue;
+       }
+
 // The question to be checked is not passed in as an explicit parameter;
 // instead it is implicit that the question to be checked is m->CurrentQuestion.
 mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
        {
        DNSQuestion *q = m->CurrentQuestion;
-       mDNSs32 sendtime = q->LastQTime + q->ThisQInterval;
-       // Don't allow sendtime to be earlier than SuppressStdPort53Queries
-       if (!q->LongLived && m->SuppressStdPort53Queries && sendtime - m->SuppressStdPort53Queries < 0)
-               sendtime = m->SuppressStdPort53Queries;
-       if (m->timenow - sendtime < 0) return;
+       if (m->timenow - NextQSendTime(q) < 0) return;
 
        if (q->LongLived)
                {
                switch (q->state)
                        {
                        case LLQ_InitialRequest:   startLLQHandshake(m, q); break;
-                       case LLQ_SecondaryRequest: sendChallengeResponse(m, q, mDNSNULL); break;
+                       case LLQ_SecondaryRequest:
+                                                                          // For PrivateQueries, we need to start the handshake again as we don't do the Challenge/Response step
+                                                                          if (PrivateQuery(q))
+                                                                                  startLLQHandshake(m, q);
+                                                                          else
+                                                                                  sendChallengeResponse(m, q, mDNSNULL);
+                                                                          break;
                        case LLQ_Established:      sendLLQRefresh(m, q); break;
                        case LLQ_Poll:             break;       // Do nothing (handled below)
                        }
@@ -4867,11 +4104,44 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                if (q->unansweredQueries >= MAX_UCAST_UNANSWERED_QUERIES)
                        {
                        DNSServer *orig = q->qDNSServer;
-                       if (orig) LogInfo("Sent %d unanswered queries for %##s (%s) to %#a:%d (%##s)", q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype), &orig->addr, mDNSVal16(orig->port), orig->domain.c);
+                       if (orig)
+                               LogInfo("uDNS_CheckCurrentQuestion: Sent %d unanswered queries for %##s (%s) to %#a:%d (%##s)",
+                                       q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype), &orig->addr, mDNSVal16(orig->port), orig->domain.c);
 
-                       PenalizeDNSServer(m, q, mDNStrue);
+                       PenalizeDNSServer(m, q);
+                       q->noServerResponse = 1;
+                       }
+               // There are two cases here.
+               //
+               // 1. We have only one DNS server for this question. It is not responding even after we sent MAX_UCAST_UNANSWERED_QUERIES.
+               //    In that case, we need to keep retrying till we get a response. But we need to backoff as we retry. We set
+               //    noServerResponse in the block above and below we do not touch the question interval. When we come here, we
+               //    already waited for the response. We need to send another query right at this moment. We do that below by
+               //    reinitializing dns servers and reissuing the query.
+               //
+               // 2. We have more than one DNS server. If at least one server did not respond, we would have set noServerResponse
+               //    either now (the last server in the list) or before (non-last server in the list). In either case, if we have
+               //    reached the end of DNS server list, we need to try again from the beginning. Ideally we should try just the
+               //    servers that did not respond, but for simplicity we try all the servers. Once we reached the end of list, we
+               //    set triedAllServersOnce so that we don't try all the servers aggressively. See PenalizeDNSServer.
+               if (!q->qDNSServer && q->noServerResponse)
+                       {
+                       DNSServer *new;
+                       DNSQuestion *qptr;
+                       q->triedAllServersOnce = 1;
+                       // Re-initialize all DNS servers for this question. If we have a DNSServer, DNSServerChangeForQuestion will
+                       // handle all the work including setting the new DNS server.
+                       SetValidDNSServers(m, q);
+                       new = GetServerForQuestion(m, q);
+                       if (new)
+                               {
+                               LogInfo("uDNS_checkCurrentQuestion: Retrying question %p %##s (%s) DNS Server %#a:%d ThisQInterval %d",
+                                       q, q->qname.c, DNSTypeName(q->qtype), new ? &new->addr : mDNSNULL, mDNSVal16(new ? new->port : zeroIPPort), q->ThisQInterval);
+                               DNSServerChangeForQuestion(m, q, new);
+                               }
+                       for (qptr = q->next ; qptr; qptr = qptr->next)
+                               if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; }
                        }
-
                if (q->qDNSServer && q->qDNSServer->teststate != DNSServer_Disabled)
                        {
                        mDNSu8 *end = m->omsg.data;
@@ -4883,7 +4153,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                        if (q->qDNSServer->teststate != DNSServer_Untested || NoTestQuery(q))
                                {
                                end = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
-                               private = (q->AuthInfo && q->AuthInfo->AutoTunnel);
+                               private = PrivateQuery(q);
                                }
                        else if (m->timenow - q->qDNSServer->lasttest >= INIT_UCAST_POLL_INTERVAL)      // Make sure at least three seconds has elapsed since last test query
                                {
@@ -4896,7 +4166,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
 
                        if (end > m->omsg.data && (q->qDNSServer->teststate != DNSServer_Failed || NoTestQuery(q)))
                                {
-                               //LogMsg("uDNS_CheckCurrentQuestion %p %d %p %##s (%s)", q, sendtime - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
+                               //LogMsg("uDNS_CheckCurrentQuestion %p %d %p %##s (%s)", q, NextQSendTime(q) - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
                                if (private)
                                        {
                                        if (q->nta) CancelGetZoneData(m, q->nta);
@@ -4905,10 +4175,12 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                                        }
                                else
                                        {
+                                   debugf("uDNS_CheckCurrentQuestion sending %p %##s (%s) %#a:%d UnansweredQueries %d",
+                                       q, q->qname.c, DNSTypeName(q->qtype),
+                                       q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->unansweredQueries);
                                        if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(m, zeroIPPort);
                                        if (!q->LocalSocket) err = mStatus_NoMemoryErr; // If failed to make socket (should be very rare), we'll try again next time
                                        else err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, q->LocalSocket, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, mDNSNULL);
-                                       m->SuppressStdPort53Queries = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+99)/100);
                                        }
                                }
 
@@ -4952,21 +4224,63 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                                for (rr = cg->members; rr; rr=rr->next)
                                        if (SameNameRecordAnswersQuestion(&rr->resrec, q)) mDNS_PurgeCacheResourceRecord(m, rr);
 
-                       if (!q->qDNSServer) LogInfo("uDNS_CheckCurrentQuestion no DNS server for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-                       else LogMsg("uDNS_CheckCurrentQuestion DNS server %#a:%d for %##s is disabled", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qname.c);
+                       if (!q->qDNSServer)
+                               {
+                               if (!mDNSOpaque64IsZero(&q->validDNSServers))
+                                       LogMsg("uDNS_CheckCurrentQuestion: ERROR!!: valid DNSServer bits not zero 0x%x, 0x%x for question %##s (%s)",
+                                               q->validDNSServers.l[1], q->validDNSServers.l[0], q->qname.c, DNSTypeName(q->qtype));
+                               // If we reached the end of list while picking DNS servers, then we don't want to deactivate the
+                               // question. Try after 60 seconds. We find this by looking for valid DNSServers for this question,
+                               // if we find any, then we must have tried them before we came here. This avoids maintaining
+                               // another state variable to see if we had valid DNS servers for this question.
+                               SetValidDNSServers(m, q);       
+                               if (mDNSOpaque64IsZero(&q->validDNSServers))
+                                       {
+                                       LogInfo("uDNS_CheckCurrentQuestion: no DNS server for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+                                       q->ThisQInterval = 0;
+                                       }
+                               else
+                                       {
+                                       DNSQuestion *qptr;
+                                       // Pretend that we sent this question. As this is an ActiveQuestion, the NextScheduledQuery should
+                                       // be set properly. Also, we need to properly backoff in cases where we don't set the question to
+                                       // MaxQuestionInterval when we answer the question e.g., LongLived, we need to keep backing off
+                                       q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep;
+                                       q->LastQTime = m->timenow;
+                                       SetNextQueryTime(m, q);
+                                       // Pick a new DNS server now. Otherwise, when the cache is 80% of its expiry, we will try
+                                       // to send a query and come back to the same place here and log the above message.
+                                       q->qDNSServer = GetServerForQuestion(m, q);
+                                       for (qptr = q->next ; qptr; qptr = qptr->next)
+                                               if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; }
+                                       LogInfo("uDNS_checkCurrentQuestion: Tried all DNS servers, retry question %p SuppressUnusable %d %##s (%s) with DNS Server %#a:%d after 60 seconds, ThisQInterval %d",
+                                               q, q->SuppressUnusable, q->qname.c, DNSTypeName(q->qtype),
+                                               q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->ThisQInterval);
+                                       }
+                               }
+                       else
+                               {
+                               q->ThisQInterval = 0;
+                               LogMsg("uDNS_CheckCurrentQuestion DNS server %#a:%d for %##s is disabled", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qname.c);
+                               }
 
-                       MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any);
-                       // Inactivate this question until the next change of DNS servers (do this before AnswerCurrentQuestionWithResourceRecord)
-                       q->ThisQInterval = 0;
+                       // For some of the WAB queries that we generate form within the mDNSResponder, most of the home routers
+                       // don't understand and return ServFail/NXDomain. In those cases, we don't want to try too often. We try
+                       // every fifteen minutes in that case
+                       MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, (WABQuestion(&q->qname) ? 60 * 15 : 60), mDNSInterface_Any, q->qDNSServer);
                        q->unansweredQueries = 0;
-                       CreateNewCacheEntry(m, slot, cg);
+                       // We're already using the m->CurrentQuestion pointer, so CacheRecordAdd can't use it to walk the question list.
+                       // To solve this problem we set rr->DelayDelivery to a nonzero value (which happens to be 'now') so that we
+                       // momentarily defer generating answer callbacks until mDNS_Execute time.
+                       CreateNewCacheEntry(m, slot, cg, NonZeroTime(m->timenow));
+                       ScheduleNextCacheCheckTime(m, slot, NonZeroTime(m->timenow));
                        m->rec.r.resrec.RecordType = 0;         // Clear RecordType to show we're not still using it
                        // MUST NOT touch m->CurrentQuestion (or q) after this -- client callback could have deleted it
                        }
                }
        }
 
-mDNSlocal void CheckNATMappings(mDNS *m)
+mDNSexport void CheckNATMappings(mDNS *m)
        {
        mStatus err = mStatus_NoError;
        mDNSBool rfc1918 = mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4);
@@ -5000,7 +4314,9 @@ mDNSlocal void CheckNATMappings(mDNS *m)
                if (m->SSDPSocket)      { debugf("CheckNATMappings destroying SSDPSocket %p", &m->SSDPSocket); mDNSPlatformUDPClose(m->SSDPSocket); m->SSDPSocket = mDNSNULL; }
                }
 
-       if (m->NATTraversals)
+       if (!m->NATTraversals)
+               m->retryGetAddr = m->timenow + 0x78000000;
+       else
                {
                if (m->timenow - m->retryGetAddr >= 0)
                        {
@@ -5067,6 +4383,10 @@ mDNSlocal void CheckNATMappings(mDNS *m)
                // (1) we have an ExternalAddress, or we've tried and failed a couple of times to discover it
                // and (2) the client doesn't want a mapping, or the client won't need a mapping, or the client has a successful mapping, or we've tried and failed a couple of times
                // and (3) we have new data to give the client that's changed since the last callback
+               // Time line is: Send, Wait 500ms, Send, Wait 1sec, Send, Wait 2sec, Send
+               // At this point we've sent three requests without an answer, we've just sent our fourth request,
+               // retryIntervalGetAddr is now 4 seconds, which is greater than NATMAP_INIT_RETRY * 8 (2 seconds),
+               // so we return an error result to the caller.
                if (!mDNSIPv4AddressIsZero(m->ExternalAddress) || m->retryIntervalGetAddr > NATMAP_INIT_RETRY * 8)
                        {
                        const mStatus EffectiveResult = cur->NewResult ? cur->NewResult : mDNSv4AddrIsRFC1918(&m->ExternalAddress) ? mStatus_DoubleNAT : mStatus_NoError;
@@ -5081,10 +4401,10 @@ mDNSlocal void CheckNATMappings(mDNS *m)
                                        if (cur->Protocol && mDNSIPPortIsZero(ExternalPort) && !mDNSIPv4AddressIsZero(m->Router.ip.v4))
                                                {
                                                if (!EffectiveResult)
-                                                       LogInfo("Failed to obtain NAT port mapping %p from router %#a external address %.4a internal port %5d interval %d error %d",
+                                                       LogInfo("CheckNATMapping: Failed to obtain NAT port mapping %p from router %#a external address %.4a internal port %5d interval %d error %d",
                                                                cur, &m->Router, &m->ExternalAddress, mDNSVal16(cur->IntPort), cur->retryInterval, EffectiveResult);
                                                else
-                                                       LogMsg("Failed to obtain NAT port mapping %p from router %#a external address %.4a internal port %5d interval %d error %d",
+                                                       LogMsg("CheckNATMapping: Failed to obtain NAT port mapping %p from router %#a external address %.4a internal port %5d interval %d error %d",
                                                                cur, &m->Router, &m->ExternalAddress, mDNSVal16(cur->IntPort), cur->retryInterval, EffectiveResult);
                                                }
 
@@ -5103,128 +4423,106 @@ mDNSlocal void CheckNATMappings(mDNS *m)
                }
        }
 
-mDNSlocal mDNSs32 CheckRecordRegistrations(mDNS *m)
+mDNSlocal mDNSs32 CheckRecordUpdates(mDNS *m)
        {
        AuthRecord *rr;
        mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
 
+       CheckGroupRecordUpdates(m);
+
        for (rr = m->ResourceRecords; rr; rr = rr->next)
                {
-               if (rr->state == regState_FetchingZoneData ||
-                       rr->state == regState_Pending || rr->state == regState_DeregPending || rr->state == regState_UpdatePending ||
-                       rr->state == regState_DeregDeferred || rr->state == regState_Refresh || rr->state == regState_Registered)
+               if (!AuthRecord_uDNS(rr)) continue;
+               if (rr->state == regState_NoTarget) {debugf("CheckRecordUpdates: Record %##s in NoTarget", rr->resrec.name->c); continue;}
+               // While we are waiting for the port mapping, we have nothing to do. The port mapping callback
+               // will take care of this
+               if (rr->state == regState_NATMap) {debugf("CheckRecordUpdates: Record %##s in NATMap", rr->resrec.name->c); continue;}
+               if (rr->state == regState_Pending || rr->state == regState_DeregPending || rr->state == regState_UpdatePending ||
+                       rr->state == regState_Refresh || rr->state == regState_Registered)
                        {
-                       if (rr->LastAPTime + rr->ThisAPInterval - m->timenow < 0)
+                       if (rr->LastAPTime + rr->ThisAPInterval - m->timenow <= 0)
                                {
                                if (rr->tcp) { DisposeTCPConn(rr->tcp); rr->tcp = mDNSNULL; }
-                               if (rr->state == regState_FetchingZoneData)
+                               if (!rr->nta || mDNSIPv4AddressIsZero(rr->nta->Addr.ip.v4))
                                        {
-                                       if (rr->nta) CancelGetZoneData(m, rr->nta);
+                                       // Zero out the updateid so that if we have a pending response from the server, it won't
+                                       // be accepted as a valid response. If we accept the response, we might free the new "nta"
+                                       if (rr->nta) { rr->updateid = zeroID; CancelGetZoneData(m, rr->nta); }
                                        rr->nta = StartGetZoneData(m, rr->resrec.name, ZoneServiceUpdate, RecordRegistrationGotZoneData, rr);
-                                       SetRecordRetry(m, rr, mStatus_NoError);
+
+                                       // We have just started the GetZoneData. We need to wait for it to finish. SetRecordRetry here
+                                       // schedules the update timer to fire in the future.
+                                       //
+                                       // There are three cases.
+                                       //
+                                       // 1) When the updates are sent the first time, the first retry is intended to be at three seconds
+                                       //    in the future. But by calling SetRecordRetry here we set it to nine seconds. But it does not
+                                       //    matter because when the answer comes back, RecordRegistrationGotZoneData resets the interval
+                                       //    back to INIT_RECORD_REG_INTERVAL. This also gives enough time for the query.
+                                       //
+                                       // 2) In the case of update errors (updateError), this causes further backoff as
+                                       //    RecordRegistrationGotZoneData does not reset the timer. This is intentional as in the case of
+                                       //    errors, we don't want to update aggressively.
+                                       //
+                                       // 3) We might be refreshing the update. This is very similar to case (1). RecordRegistrationGotZoneData
+                                       //    resets it back to INIT_RECORD_REG_INTERVAL.
+                                       // 
+                                       SetRecordRetry(m, rr, 0);
                                        }
                                else if (rr->state == regState_DeregPending) SendRecordDeregistration(m, rr);
                                else SendRecordRegistration(m, rr);
                                }
-                       if (nextevent - (rr->LastAPTime + rr->ThisAPInterval) > 0)
-                               nextevent = (rr->LastAPTime + rr->ThisAPInterval);
                        }
+               if (nextevent - (rr->LastAPTime + rr->ThisAPInterval) > 0)
+                       nextevent = (rr->LastAPTime + rr->ThisAPInterval);
                }
        return nextevent;
        }
 
-mDNSlocal mDNSs32 CheckServiceRegistrations(mDNS *m)
+mDNSexport void uDNS_Tasks(mDNS *const m)
        {
-       mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
+       mDNSs32 nexte;
+       DNSServer *d;
 
-       if (CurrentServiceRecordSet)
-               LogMsg("CheckServiceRegistrations ERROR CurrentServiceRecordSet already set");
-       CurrentServiceRecordSet = m->ServiceRegistrations;
+       m->NextuDNSEvent = m->timenow + 0x3FFFFFFF;
 
-       // Note: ServiceRegistrations list is in the order they were created; important for in-order event delivery
-       while (CurrentServiceRecordSet)
-               {
-               ServiceRecordSet *srs = CurrentServiceRecordSet;
-               CurrentServiceRecordSet = CurrentServiceRecordSet->uDNS_next;
-               if (srs->state == regState_FetchingZoneData ||
-                       srs->state == regState_Pending || srs->state == regState_DeregPending  || srs->state == regState_DeregDeferred ||
-                       srs->state == regState_Refresh || srs->state == regState_UpdatePending || srs->state == regState_Registered)
-                       {
-                       if (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval - m->timenow <= 0)
-                               {
-                               if (srs->tcp) { DisposeTCPConn(srs->tcp); srs->tcp = mDNSNULL; }
-                               if (srs->state == regState_FetchingZoneData)
-                                       {
-                                       if (srs->srs_nta) CancelGetZoneData(m, srs->srs_nta);
-                                       srs->srs_nta = StartGetZoneData(m, srs->RR_SRV.resrec.name, ZoneServiceUpdate, ServiceRegistrationGotZoneData, srs);
-                                       SetRecordRetry(m, &srs->RR_SRV, mStatus_NoError);
-                                       }
-                               else if (srs->state == regState_DeregPending) SendServiceDeregistration(m, srs);
-                               else SendServiceRegistration(m, srs);
-                               }
-                       if (nextevent - (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval) > 0)
-                               nextevent = (srs->RR_SRV.LastAPTime + srs->RR_SRV.ThisAPInterval);
-                       }
-               }
-       return nextevent;
-       }
+       nexte = CheckRecordUpdates(m);
+       if (m->NextuDNSEvent - nexte > 0)
+               m->NextuDNSEvent = nexte;
 
-// This function is called early on in mDNS_Execute before any uDNS questions are
-// dispatched so that if there are some good servers, the uDNS questions can now
-// use it
-mDNSexport void ResetDNSServerPenalties(mDNS *m)
-       {
-       DNSServer *d;
        for (d = m->DNSServers; d; d=d->next)
-               {
-               if (d->penaltyTime != 0)
+               if (d->penaltyTime)
                        {
-                       if (d->penaltyTime - m->timenow <= 0)
+                       if (m->timenow - d->penaltyTime >= 0)
                                {
-                               LogInfo("ResetDNSServerPenalties: DNS server %#a:%d out of penalty box", &d->addr, mDNSVal16(d->port));
+                               LogInfo("DNS server %#a:%d out of penalty box", &d->addr, mDNSVal16(d->port));
                                d->penaltyTime = 0;
                                }
+                       else
+                               if (m->NextuDNSEvent - d->penaltyTime > 0)
+                                       m->NextuDNSEvent = d->penaltyTime;
                        }
-               }
-       }
 
-mDNSlocal mDNSs32 CheckDNSServerPenalties(mDNS *m)
-       {
-       mDNSs32 nextevent = m->timenow + 0x3FFFFFFF;
-       DNSServer *d;
-       for (d = m->DNSServers; d; d=d->next)
+       if (m->CurrentQuestion)
+               LogMsg("uDNS_Tasks ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+       m->CurrentQuestion = m->Questions;
+       while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
                {
-               if (d->penaltyTime != 0)
+               DNSQuestion *const q = m->CurrentQuestion;
+               if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID))
                        {
-                       if ((nextevent - d->penaltyTime) > 0)
-                               nextevent = d->penaltyTime;
+                       uDNS_CheckCurrentQuestion(m);
+                       if (q == m->CurrentQuestion)
+                               if (m->NextuDNSEvent - NextQSendTime(q) > 0)
+                                       m->NextuDNSEvent = NextQSendTime(q);
                        }
+               // If m->CurrentQuestion wasn't modified out from under us, advance it now
+               // We can't do this at the start of the loop because uDNS_CheckCurrentQuestion()
+               // depends on having m->CurrentQuestion point to the right question
+               if (m->CurrentQuestion == q)
+                       m->CurrentQuestion = q->next;
                }
-       return nextevent;
-       }
-
-mDNSexport void uDNS_Execute(mDNS *const m)
-       {
-       mDNSs32 nexte;
-
-       m->NextuDNSEvent = m->timenow + 0x3FFFFFFF;
-
-       if (m->NextSRVUpdate && m->NextSRVUpdate - m->timenow < 0)
-               { m->NextSRVUpdate = 0; UpdateSRVRecords(m); }
-
-       CheckNATMappings(m);
-
-       if (m->SuppressStdPort53Queries && m->timenow - m->SuppressStdPort53Queries >= 0)
-               m->SuppressStdPort53Queries = 0; // If suppression time has passed, clear it
-
-       nexte = CheckRecordRegistrations(m);
-       if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
-
-       nexte = CheckServiceRegistrations(m);
-       if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
-
-       nexte = CheckDNSServerPenalties(m);
-       if (nexte - m->NextuDNSEvent < 0) m->NextuDNSEvent = nexte;
+       m->CurrentQuestion = mDNSNULL;
        }
 
 // ***************************************************************************
@@ -5232,61 +4530,42 @@ mDNSexport void uDNS_Execute(mDNS *const m)
 #pragma mark - Startup, Shutdown, and Sleep
 #endif
 
-// simplest sleep logic - rather than having sleep states that must be dealt with explicitly in all parts of
-// the code, we simply send a deregistration, and put the service in Refresh state, with a timeout far enough
-// in the future that we'll sleep (or the sleep will be cancelled) before it is retransmitted. Then to wake,
-// we just move up the timers.
-
 mDNSexport void SleepRecordRegistrations(mDNS *m)
        {
        AuthRecord *rr;
        for (rr = m->ResourceRecords; rr; rr=rr->next)
+               {
                if (AuthRecord_uDNS(rr))
-                       if (rr->state == regState_Registered ||
-                               rr->state == regState_Refresh)
+                       {
+                       // Zero out the updateid so that if we have a pending response from the server, it won't
+                       // be accepted as a valid response.
+                       if (rr->nta) { rr->updateid = zeroID; CancelGetZoneData(m, rr->nta); rr->nta = mDNSNULL; }
+
+                       if (rr->NATinfo.clientContext)
                                {
-                               SendRecordDeregistration(m, rr);
-                               rr->state = regState_Refresh;
-                               rr->LastAPTime = m->timenow;
-                               rr->ThisAPInterval = 300 * mDNSPlatformOneSecond;
+                               mDNS_StopNATOperation_internal(m, &rr->NATinfo);
+                               rr->NATinfo.clientContext = mDNSNULL;
+                               }
+                       // We are waiting to update the resource record. The original data of the record is
+                       // in OrigRData and the updated value is in InFlightRData. Free the old and the new
+                       // one will be registered when we come back.
+                       if (rr->state == regState_UpdatePending)
+                               {
+                               // act as if the update succeeded, since we're about to delete the name anyway
+                               rr->state = regState_Registered;
+                               // deallocate old RData
+                               if (rr->UpdateCallback) rr->UpdateCallback(m, rr, rr->OrigRData, rr->OrigRDLen);
+                               SetNewRData(&rr->resrec, rr->InFlightRData, rr->InFlightRDLen);
+                               rr->OrigRData = mDNSNULL;
+                               rr->InFlightRData = mDNSNULL;
                                }
-       }
-
-mDNSexport void SleepServiceRegistrations(mDNS *m)
-       {
-       ServiceRecordSet *srs = m->ServiceRegistrations;
-       while (srs)
-               {
-               LogInfo("SleepServiceRegistrations: state %d %s", srs->state, ARDisplayString(m, &srs->RR_SRV));
-               if (srs->srs_nta) { CancelGetZoneData(m, srs->srs_nta); srs->srs_nta = mDNSNULL; }
-
-               if (srs->NATinfo.clientContext)
-                       {
-                       mDNS_StopNATOperation_internal(m, &srs->NATinfo);
-                       srs->NATinfo.clientContext = mDNSNULL;
-                       }
 
-               if (srs->state == regState_UpdatePending)
-                       {
-                       // act as if the update succeeded, since we're about to delete the name anyway
-                       AuthRecord *txt = &srs->RR_TXT;
-                       srs->state = regState_Registered;
-                       // deallocate old RData
-                       if (txt->UpdateCallback) txt->UpdateCallback(m, txt, txt->OrigRData);
-                       SetNewRData(&txt->resrec, txt->InFlightRData, txt->InFlightRDLen);
-                       txt->OrigRData = mDNSNULL;
-                       txt->InFlightRData = mDNSNULL;
+                       // If we have not begun the registration process i.e., never sent a registration packet,
+                       // then uDNS_DeregisterRecord will not send a deregistration
+                       uDNS_DeregisterRecord(m, rr);
+                       
+                       // When we wake, we call ActivateUnicastRegistration which starts at StartGetZoneData
                        }
-
-               if (srs->state == regState_Registered || srs->state == regState_Refresh)
-                       SendServiceDeregistration(m, srs);
-
-               srs->state = regState_NoTarget; // when we wake, we'll re-register (and optionally nat-map) once our address record completes
-               srs->RR_SRV.resrec.rdata->u.srv.target.c[0] = 0;
-               srs->SRSUpdateServer = zeroAddr;                // This will cause UpdateSRV to do a new StartGetZoneData
-               srs->RR_SRV.ThisAPInterval = 5 * mDNSPlatformOneSecond;         // After doubling, first retry will happen after ten seconds
-
-               srs = srs->uDNS_next;
                }
        }
 
@@ -5320,6 +4599,95 @@ mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus r
        if (result == mStatus_MemFree) mDNSPlatformMemFree(rr->RecordContext);
        }
 
+#if APPLE_OSX_mDNSResponder
+mDNSlocal void CheckAutoTunnel6Registration(mDNS *const m, mDNSBool RegisterAutoTunnel6)
+       {
+       LogInfo("CheckAutoTunnel6Registration: Current value RegisterAutoTunnel6 %d, New value %d", m->RegisterAutoTunnel6, RegisterAutoTunnel6);
+       if (!RegisterAutoTunnel6)
+               {
+               // We are not supposed to register autotunnel6. If we had previously registered
+               // autotunnel6, deregister it now.
+               if (m->RegisterAutoTunnel6)
+                       {
+                       m->RegisterAutoTunnel6 = mDNSfalse;
+                       LogInfo("CheckAutoTunnel6Registration: Removing AutoTunnel6");
+                       RemoveAutoTunnel6Record(m);
+                       }
+               else LogInfo("CheckAutoTunnel6Registration: Already Removed AutoTunnel6");
+               }
+       else 
+               {
+               // We are supposed to register autotunnel6. If we had previously  de-registered
+               // autotunnel6, re-register it now.
+               if (!m->RegisterAutoTunnel6)
+                       {
+                       m->RegisterAutoTunnel6 = mDNStrue;
+                       LogInfo("CheckAutoTunnel6Registration: Adding AutoTunnel6");
+                       SetupConndConfigChanges(m);
+                       }
+               else LogInfo("CheckAutoTunnel6Registration: already Added AutoTunnel6");
+               }
+       }
+#endif
+
+mDNSlocal void FoundDirDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
+       {
+       SearchListElem *slElem = question->QuestionContext;
+       mDNSBool RegisterAutoTunnel6 = mDNStrue;
+       char *res = "DisableInboundRelay";
+       
+       LogInfo("FoundDirDomain: InterfaceID %p %s Question %##s Answer %s", answer->InterfaceID, AddRecord ? "Add" : "Rmv", question->qname.c, RRDisplayString(m, answer));
+       if (answer->rrtype != kDNSType_TXT)
+               {
+               LogMsg("FoundDirDomain: answer type is not TXT %s for question %##s", DNSTypeName(answer->rrtype), question->qname.c);
+               return;
+               }
+       if (answer->RecordType == kDNSRecordTypePacketNegative)
+               {
+               LogInfo("FoundDirDomain: Negative answer for %##s", question->qname.c);
+               return;
+               }
+       if (answer->InterfaceID == mDNSInterface_LocalOnly)
+               {
+               LogInfo("FoundDirDomain: LocalOnly interfaceID for %##s", question->qname.c);
+               return;
+               }
+
+       // TXT record is encoded as <len><data>
+       if (answer->rdlength != mDNSPlatformStrLen(res) + 1)
+               {
+               LogInfo("FoundDirDomain: Invalid TXT record to disable %##s, length %d", question->qname.c, answer->rdlength);
+               return;
+               }
+
+       // Compare the data (excluding the len byte)
+       if (!mDNSPlatformMemSame(&answer->rdata->u.txt.c[1], res, answer->rdlength - 1))
+               {
+               LogInfo("FoundDirDomain: Invalid TXT record to disable %##s", question->qname.c);
+               return;
+               }
+
+       // It is sufficient for one answer to disable registration of autotunnel6. But we should
+       // have zero answers across all domains to register autotunnel6.
+       if (AddRecord)
+               {
+               slElem->numDirAnswers++;
+               RegisterAutoTunnel6 = mDNSfalse;
+               }
+       else
+               {
+               const SearchListElem *s;
+               slElem->numDirAnswers--;
+               if (slElem->numDirAnswers < 0) LogMsg("FoundDirDomain: numDirAnswers less than zero %d", slElem->numDirAnswers);
+               // See if any domain (including the slElem) has any answers
+               for (s=SearchList; s; s=s->next)
+                       if (s->numDirAnswers) { RegisterAutoTunnel6 = mDNSfalse; break; }
+               }
+#if APPLE_OSX_mDNSResponder
+       CheckAutoTunnel6Registration(m, RegisterAutoTunnel6);
+#endif
+       }
+
 mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
        SearchListElem *slElem = question->QuestionContext;
@@ -5378,11 +4746,6 @@ mDNSexport void udns_validatelists(void *const v)
        {
        mDNS *const m = v;
 
-       ServiceRecordSet *s;
-       for (s = m->ServiceRegistrations; s; s=s->uDNS_next)
-               if (s->uDNS_next == (ServiceRecordSet*)~0)
-                       LogMemCorruption("m->ServiceRegistrations: %p is garbage (%lX)", s, s->uDNS_next);
-
        NATTraversalInfo *n;
        for (n = m->NATTraversals; n; n=n->next)
                if (n->next == (NATTraversalInfo *)~0 || n->clientCallback == (NATTraversalClientCallback)~0)
@@ -5410,12 +4773,33 @@ mDNSexport void udns_validatelists(void *const v)
        }
 #endif
 
+mDNSlocal void mDNS_StartDirQuestion(mDNS *const m, DNSQuestion *question, domainname *domain, void *context)
+       {
+       AssignDomainName (&question->qname, (const domainname*)"\002cf" "\007_dns-sd" "\x04_udp");
+       AppendDomainName (&question->qname, domain);
+       question->InterfaceID      = mDNSInterface_Any;
+       question->Target           = zeroAddr;
+       question->qtype            = kDNSType_TXT;
+       question->qclass           = kDNSClass_IN;
+       question->LongLived        = mDNSfalse;
+       question->ExpectUnique     = mDNStrue;
+       question->ForceMCast       = mDNSfalse;
+       question->ReturnIntermed   = mDNSfalse;
+       question->SuppressUnusable = mDNSfalse;
+       question->QuestionCallback = FoundDirDomain;
+       question->QuestionContext  = context;
+       LogInfo("mDNS_StartDirQuestion: Start DIR domain question %##s", question->qname.c);
+       if (mDNS_StartQuery(m, question))
+               LogMsg("mDNS_StartDirQuestion: ERROR!! cannot start _dir._dns-sd query");
+       }
+
 // This should probably move to the UDS daemon -- the concept of legacy clients and automatic registration / automatic browsing
 // is really a UDS API issue, not something intrinsic to uDNS
-
 mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m)
        {
        SearchListElem **p = &SearchList, *ptr;
+       const SearchListElem *s;
+       mDNSBool RegisterAutoTunnel6 = mDNStrue;
        mStatus err;
 
        // step 1: mark each element for removal (-1)
@@ -5439,6 +4823,9 @@ mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m)
                        *p = ptr->next;
 
                        // If the user has "local" in their DNS searchlist, we ignore that for the purposes of domain enumeration queries
+                       // Note: Stopping a question will not generate the RMV events for the question (handled in FoundDirDomain)
+                       // and hence we need to recheck all the domains to see if we need to register/deregister _autotunnel6.
+                       // This is done at the end.
                        if (!SameDomainName(&ptr->domain, &localdomain))
                                {
                                mDNS_StopGetDomains(m, &ptr->BrowseQ);
@@ -5446,6 +4833,7 @@ mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m)
                                mDNS_StopGetDomains(m, &ptr->DefBrowseQ);
                                mDNS_StopGetDomains(m, &ptr->DefRegisterQ);
                                mDNS_StopGetDomains(m, &ptr->AutomaticBrowseQ);
+                               mDNS_StopGetDomains(m, &ptr->DirQ);
                                }
                        mDNSPlatformMemFree(ptr);
 
@@ -5456,7 +4844,7 @@ mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m)
                                arList = arList->next;
                                debugf("Deregistering PTR %##s -> %##s", dereg->ar.resrec.name->c, dereg->ar.resrec.rdata->u.name.c);
                                err = mDNS_Deregister(m, &dereg->ar);
-                               if (err) LogMsg("ERROR: RegisterSearchDomains mDNS_Deregister returned %d", err);
+                               if (err) LogMsg("uDNS_RegisterSearchDomains ERROR!! mDNS_Deregister returned %d", err);
                                // Memory will be freed in the FreeARElemCallback
                                }
                        continue;
@@ -5474,22 +4862,28 @@ mDNSexport mStatus uDNS_RegisterSearchDomains(mDNS *const m)
                                err4 = mDNS_GetDomains(m, &ptr->DefRegisterQ,     mDNS_DomainTypeRegistrationDefault, &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
                                err5 = mDNS_GetDomains(m, &ptr->AutomaticBrowseQ, mDNS_DomainTypeBrowseAutomatic,     &ptr->domain, mDNSInterface_Any, FoundDomain, ptr);
                                if (err1 || err2 || err3 || err4 || err5)
-                                       LogMsg("GetDomains for domain %##s returned error(s):\n"
+                                       LogMsg("uDNS_RegisterSearchDomains: 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_DomainTypeBrowseAutomatic)\n",
                                                   ptr->domain.c, err1, err2, err3, err4, err5);
+                               mDNS_StartDirQuestion(m, &ptr->DirQ, &ptr->domain, ptr);
                                }
                        ptr->flag = 0;
                        }
 
-               if (ptr->flag) { LogMsg("RegisterSearchDomains - unknown flag %d. Skipping.", ptr->flag); }
+               if (ptr->flag) { LogMsg("uDNS_RegisterSearchDomains - unknown flag %d. Skipping.", ptr->flag); }
 
                p = &ptr->next;
                }
-
+       // if there is any domain has answers, need to deregister autotunnel6
+       for (s=SearchList; s; s=s->next)
+               if (s->numDirAnswers) { RegisterAutoTunnel6 = mDNSfalse; break; }
+#if APPLE_OSX_mDNSResponder
+       CheckAutoTunnel6Registration(m, RegisterAutoTunnel6);
+#endif
        return mStatus_NoError;
        }
 
@@ -5509,5 +4903,5 @@ struct CompileTimeAssertionChecks_uDNS
        // other overly-large structures instead of having a pointer to them, can inadvertently
        // cause structure sizes (and therefore memory usage) to balloon unreasonably.
        char sizecheck_tcpInfo_t     [(sizeof(tcpInfo_t)      <=  9056) ? 1 : -1];
-       char sizecheck_SearchListElem[(sizeof(SearchListElem) <=  3920) ? 1 : -1];
+       char sizecheck_SearchListElem[(sizeof(SearchListElem) <=  4800) ? 1 : -1];
        };
index 88beb9f569f223d1c188f194e26097b7dbf90bd1..0562dae17b70a6b29acc4b41a290d0eeba6d197e 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: uDNS.h,v $
-Revision 1.93  2008/09/24 23:48:05  cheshire
-Don't need to pass whole ServiceRecordSet reference to GetServiceTarget;
-it only needs to access the embedded SRV member of the set
-
-Revision 1.92  2008/06/19 23:42:03  mcguire
-<rdar://problem/4206534> Use all configured DNS servers
-
-Revision 1.91  2008/06/19 01:20:50  mcguire
-<rdar://problem/4206534> Use all configured DNS servers
-
-Revision 1.90  2007/12/22 02:25:30  cheshire
-<rdar://problem/5661128> Records and Services sometimes not re-registering on wake from sleep
-
-Revision 1.89  2007/12/15 01:12:27  cheshire
-<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
-
-Revision 1.88  2007/10/25 20:06:13  cheshire
-Don't try to do SOA queries using private DNS (TLS over TCP) queries
-
-Revision 1.87  2007/10/24 22:40:06  cheshire
-Renamed: RecordRegistrationCallback          -> RecordRegistrationGotZoneData
-Renamed: ServiceRegistrationZoneDataComplete -> ServiceRegistrationGotZoneData
-
-Revision 1.86  2007/10/18 23:06:42  cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-Additional fixes and refinements
-
-Revision 1.85  2007/10/18 20:23:17  cheshire
-Moved SuspendLLQs into mDNS.c, since it's only called from one place
-
-Revision 1.84  2007/10/17 22:49:54  cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-
-Revision 1.83  2007/10/17 22:37:23  cheshire
-<rdar://problem/5536979> BTMM: Need to create NAT port mapping for receiving LLQ events
-
-Revision 1.82  2007/10/17 21:53:51  cheshire
-Improved debugging messages; renamed startLLQHandshakeCallback to LLQGotZoneData
-
-Revision 1.81  2007/10/16 21:16:50  cheshire
-Get rid of unused uDNS_Sleep() routine
-
-Revision 1.80  2007/10/16 20:59:41  cheshire
-Export SuspendLLQs/SleepServiceRegistrations/SleepRecordRegistrations so they're callable from other files
-
-Revision 1.79  2007/09/20 01:13:19  cheshire
-Export CacheGroupForName so it's callable from other files
-
-Revision 1.78  2007/09/14 21:26:09  cheshire
-<rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
-
-Revision 1.77  2007/09/12 23:03:08  cheshire
-<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
-
-Revision 1.76  2007/09/12 19:22:19  cheshire
-Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
-Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
-
-Revision 1.75  2007/08/28 23:53:21  cheshire
-Rename serviceRegistrationCallback -> ServiceRegistrationZoneDataComplete
-
-Revision 1.74  2007/08/24 00:15:20  cheshire
-Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
-
-Revision 1.73  2007/08/01 03:09:22  cheshire
-<rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
-
-Revision 1.72  2007/08/01 00:04:13  cheshire
-<rdar://problem/5261696> Crash in tcpKQSocketCallback
-Half-open TCP connections were not being cancelled properly
-
-Revision 1.71  2007/07/30 23:31:26  cheshire
-Code for respecting TTL received in uDNS responses should exclude LLQ-type responses
-
-Revision 1.70  2007/07/27 20:52:29  cheshire
-Made uDNS_recvLLQResponse() return tri-state result: LLQ_Not, LLQ_First, or LLQ_Events
-
-Revision 1.69  2007/07/27 19:30:40  cheshire
-Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
-to properly reflect tri-state nature of the possible responses
-
-Revision 1.68  2007/07/27 18:38:56  cheshire
-Rename "uDNS_CheckQuery" to more informative "uDNS_CheckCurrentQuestion"
-
-Revision 1.67  2007/07/20 23:11:12  cheshire
-Fix code layout
-
-Revision 1.66  2007/07/16 23:54:48  cheshire
-<rdar://problem/5338850> Crash when removing or changing DNS keys
-
-Revision 1.65  2007/07/16 20:14:22  vazquez
-<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
-
-Revision 1.64  2007/07/11 02:53:36  cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-Add ServiceRecordSet parameter in GetServiceTarget
-
-Revision 1.63  2007/06/29 00:09:24  vazquez
-<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-
-Revision 1.62  2007/05/14 23:53:00  cheshire
-Export mDNS_StartQuery_internal and mDNS_StopQuery_internal so they can be called from uDNS.c
-
-Revision 1.61  2007/05/07 20:43:45  cheshire
-<rdar://problem/4241419> Reduce the number of queries and announcements
-
-Revision 1.60  2007/05/04 21:46:10  cheshire
-Get rid of uDNS_Close (synonym for uDNS_Sleep)
-
-Revision 1.59  2007/05/03 22:40:38  cheshire
-<rdar://problem/4669229> mDNSResponder ignores bogus null target in SRV record
-
-Revision 1.58  2007/05/02 22:21:33  cheshire
-<rdar://problem/5167331> RegisterRecord and RegisterService need to cancel StartGetZoneData
-
-Revision 1.57  2007/04/27 19:28:02  cheshire
-Any code that calls StartGetZoneData needs to keep a handle to the structure, so
-it can cancel it if necessary. (First noticed as a crash in Apple Remote Desktop
--- it would start a query and then quickly cancel it, and then when
-StartGetZoneData completed, it had a dangling pointer and crashed.)
-
-Revision 1.56  2007/04/25 02:14:38  cheshire
-<rdar://problem/4246187> uDNS: Identical client queries should reference a single shared core query
-Additional fixes to make LLQs work properly
-
-Revision 1.55  2007/04/22 06:02:03  cheshire
-<rdar://problem/4615977> Query should immediately return failure when no server
-
-Revision 1.54  2007/04/04 21:48:53  cheshire
-<rdar://problem/4720694> Combine unicast authoritative answer list with multicast list
-
-Revision 1.53  2007/03/28 15:56:37  cheshire
-<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
-
-Revision 1.52  2007/02/28 01:44:26  cheshire
-<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
-
-Revision 1.51  2007/01/27 03:34:27  cheshire
-Made GetZoneData use standard queries (and cached results);
-eliminated GetZoneData_Callback() packet response handler
-
-Revision 1.50  2007/01/19 21:17:32  cheshire
-StartLLQPolling needs to call SetNextQueryTime() to cause query to be done in a timely fashion
-
-Revision 1.49  2007/01/17 21:35:31  cheshire
-For clarity, rename zoneData_t field "isPrivate" to "zonePrivate"
-
-Revision 1.48  2007/01/10 22:51:57  cheshire
-<rdar://problem/4917539> Add support for one-shot private queries as well as long-lived private queries
-
-Revision 1.47  2007/01/05 08:30:43  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.46  2007/01/04 01:41:47  cheshire
-Use _dns-update-tls/_dns-query-tls/_dns-llq-tls instead of creating a new "_tls" subdomain
-
-Revision 1.45  2006/12/22 20:59:49  cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.44  2006/12/20 04:07:35  cheshire
-Remove uDNS_info substructure from AuthRecord_struct
-
-Revision 1.43  2006/12/16 01:58:32  cheshire
-<rdar://problem/4720673> uDNS: Need to start caching unicast records
-
-Revision 1.42  2006/11/30 23:07:56  herscher
-<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
-
-Revision 1.41  2006/11/18 05:01:30  cheshire
-Preliminary support for unifying the uDNS and mDNS code,
-including caching of uDNS answers
-
-Revision 1.40  2006/11/10 07:44:04  herscher
-<rdar://problem/4825493> Fix Daemon locking failures while toggling BTMM
-
-Revision 1.39  2006/10/20 05:35:05  herscher
-<rdar://problem/4720713> uDNS: Merge unicast active question list with multicast list.
-
-Revision 1.38  2006/09/26 01:54:02  herscher
-<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
-
-Revision 1.37  2006/09/15 21:20:15  cheshire
-Remove uDNS_info substructure from mDNS_struct
-
-Revision 1.36  2006/08/14 23:24:23  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.35  2006/07/30 05:45:36  cheshire
-<rdar://problem/4304215> Eliminate MIN_UCAST_PERIODIC_EXEC
-
-Revision 1.34  2006/07/15 02:01:29  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Fix broken "empty string" browsing
-
-Revision 1.33  2006/07/05 22:53:28  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-*/
+ */
 
 #ifndef __UDNS_H_
 #define __UDNS_H_
@@ -245,13 +42,23 @@ Revision 1.33  2006/07/05 22:53:28  cheshire
 #define QuestionIntervalStep3 (QuestionIntervalStep*QuestionIntervalStep*QuestionIntervalStep)
 #define InitialQuestionInterval ((mDNSPlatformOneSecond + QuestionIntervalStep-1) / QuestionIntervalStep)
 
+// For Unicast record registrations, we initialize the interval to 1 second. When we send any query for
+// the record registration e.g., GetZoneData, we always back off by QuestionIntervalStep
+// so that the first retry does not happen until 3 seconds which should be enough for TCP/TLS to be done.
+#define INIT_RECORD_REG_INTERVAL (1 * mDNSPlatformOneSecond)
+#define MAX_RECORD_REG_INTERVAL        (15 * 60 * mDNSPlatformOneSecond)
+#define MERGE_DELAY_TIME       (1 * mDNSPlatformOneSecond)
+
+// If we are refreshing, we do it at least 5 times with a min update frequency of 
+// 5 minutes
+#define MAX_UPDATE_REFRESH_COUNT       5
+#define MIN_UPDATE_REFRESH_TIME                (5 * 60 * mDNSPlatformOneSecond)
 // Entry points into unicast-specific routines
 
 extern void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo);
 extern void startLLQHandshake(mDNS *m, DNSQuestion *q);
 extern void sendLLQRefresh(mDNS *m, DNSQuestion *q);
 
-extern void SleepServiceRegistrations(mDNS *m);
 extern void SleepRecordRegistrations(mDNS *m);
 
 // uDNS_UpdateRecord
@@ -260,16 +67,11 @@ extern void SleepRecordRegistrations(mDNS *m);
 // rr->newrdlength
 // rr->UpdateCallback
 
-extern mStatus uDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra);
 extern mStatus uDNS_UpdateRecord(mDNS *m, AuthRecord *rr);
 
 extern void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q);
 extern CacheGroup *CacheGroupForName(const mDNS *const m, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name);
 extern mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr);
-// mDNS_Dereg_normal is used for most calls to mDNS_Deregister_internal
-// mDNS_Dereg_conflict is used to indicate that this record is being forcibly deregistered because of a conflict
-// mDNS_Dereg_repeat is used when cleaning up, for records that may have already been forcibly deregistered
-typedef enum { mDNS_Dereg_normal, mDNS_Dereg_conflict, mDNS_Dereg_repeat } mDNS_Dereg_type;
 extern mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr, mDNS_Dereg_type drt);
 extern mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const question);
 extern mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question);
@@ -277,20 +79,16 @@ extern mStatus mDNS_StartNATOperation_internal(mDNS *const m, NATTraversalInfo *
 
 extern void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneData);
 extern mStatus uDNS_DeregisterRecord(mDNS *const m, AuthRecord *const rr);
-
-extern void ServiceRegistrationGotZoneData(mDNS *const m, mStatus err, const ZoneData *result);
 extern const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr);
-extern mStatus uDNS_DeregisterService(mDNS *const m, ServiceRecordSet *srs);
-
 extern void uDNS_CheckCurrentQuestion(mDNS *const m);
 
 // integer fields of msg header must be in HOST byte order before calling this routine
 extern void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
        const mDNSAddr *const srcaddr, const mDNSIPPort srcport);
 
-// returns time of next scheduled event
-extern void uDNS_Execute(mDNS *const m);
-extern void ResetDNSServerPenalties(mDNS *m);
+extern void uDNS_Tasks(mDNS *const m);
+extern void UpdateAllSRVRecords(mDNS *m);
+extern void CheckNATMappings(mDNS *m);
 
 extern mStatus         uDNS_SetupDNSConfig(mDNS *const m);
 extern mStatus         uDNS_RegisterSearchDomains(mDNS *const m);
@@ -303,7 +101,7 @@ typedef enum
        uDNS_LLQ_Events         // LLQ event packet: don't flush cache; assume TTL is 2 x LLQ refresh interval
        } uDNS_LLQType;
 
-extern uDNS_LLQType    uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport);
+extern uDNS_LLQType    uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport, DNSQuestion **matchQuestion);
 extern DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname *const name);
 extern DomainAuthInfo *GetAuthInfoForQuestion(mDNS *m, const DNSQuestion *const q);
 extern void DisposeTCPConn(struct tcpInfo_t *tcp);
index c7a49a02f5561dc8326448a3f59bd052cbc6dee6..3bd7fa64509a9f29965a506a7da61e70bf3a9d10 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: CarbonResource.r,v $
-Revision 1.6  2006/08/14 23:24:29  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.5  2003/08/12 19:56:24  cheshire
-Update to APSL 2.0
-
  */
 
 data 'carb' (0) { };
index 1cf014c471e5d1f33e0495ff907aad21844eee87..eff6a5f4e7af9d84a0a0832921feaa10d0de39a0 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: Mac\040OS\040Test\040Responder.c,v $
-Revision 1.26  2008/11/04 19:43:35  cheshire
-Updated comment about MAX_ESCAPED_DOMAIN_NAME size (should be 1009, not 1005)
-
-Revision 1.25  2006/08/14 23:24:29  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.24  2004/12/16 20:49:34  cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.23  2004/09/17 01:08:50  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.22  2004/08/13 23:25:01  cheshire
-Now that we do both uDNS and mDNS, global replace "m->hostname" with
-"m->MulticastHostname" for clarity
-
-Revision 1.21  2004/03/12 21:30:25  cheshire
-Build a System-Context Shared Library from mDNSCore, for the benefit of developers
-like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
-
-Revision 1.20  2004/02/09 23:23:32  cheshire
-Advertise "IL 2\4th Floor.apple.com." as another test "browse domain"
-
-Revision 1.19  2004/01/24 23:55:15  cheshire
-Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking
-
-Revision 1.18  2003/11/14 21:27:08  cheshire
-<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
-Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1009) instead of 256-byte buffers.
-
-Revision 1.17  2003/08/14 02:19:54  cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
-
-Revision 1.16  2003/08/12 19:56:24  cheshire
-Update to APSL 2.0
-
  */
 
 #include <stdio.h>                                             // For printf()
index ca370516c7a48305c283c39562778d2c0175a29b..1de6463199f0e67ee7186da06678a7b805c16ce4 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: Mac\040OS\040Test\040Searcher.c,v $
-Revision 1.24  2008/11/04 19:43:35  cheshire
-Updated comment about MAX_ESCAPED_DOMAIN_NAME size (should be 1009, not 1005)
-
-Revision 1.23  2007/07/27 19:30:40  cheshire
-Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
-to properly reflect tri-state nature of the possible responses
-
-Revision 1.22  2006/08/14 23:24:29  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.21  2004/12/16 20:49:34  cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.20  2004/10/19 21:33:18  cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
-doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
-
-Revision 1.19  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
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.18  2004/09/16 21:59:16  cheshire
-For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
-
-Revision 1.17  2004/06/10 04:37:27  cheshire
-Add new parameter in mDNS_GetDomains()
-
-Revision 1.16  2004/03/12 21:30:25  cheshire
-Build a System-Context Shared Library from mDNSCore, for the benefit of developers
-like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
-
-Revision 1.15  2004/01/24 23:55:15  cheshire
-Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking
-
-Revision 1.14  2003/11/14 21:27:09  cheshire
-<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
-Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1009) instead of 256-byte buffers.
-
-Revision 1.13  2003/08/14 02:19:54  cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
-
-Revision 1.12  2003/08/12 19:56:24  cheshire
-Update to APSL 2.0
-
  */
 
 #include <stdio.h>                                             // For printf()
index 7a1993f6a57d0731ce1ebd1788c3246c59264501..b412bac3eb82247a6f8978411900eadd6dfb913e 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: Responder.c,v $
-Revision 1.3  2006/08/14 23:24:29  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/05/20 18:38:31  cheshire
-Fix build broken by removal of 'kDNSServiceFlagsAutoRename' from dns_sd.h
-
-Revision 1.1  2004/03/12 21:30:25  cheshire
-Build a System-Context Shared Library from mDNSCore, for the benefit of developers
-like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
-
  */
 
 #include <stdio.h>                                             // For printf()
index 9c49c8adcfa32f1e9a9c6687e461c552b8d751b4..37875ce7e59b49ea92f936b0876fa34b9449a262 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: Searcher.c,v $
-Revision 1.4  2006/12/19 22:43:54  cheshire
-Fix compiler warnings
-
-Revision 1.3  2006/08/14 23:24:29  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/05/27 06:30:21  cheshire
-Add code to test DNSServiceQueryRecord()
-
-Revision 1.1  2004/03/12 21:30:25  cheshire
-Build a System-Context Shared Library from mDNSCore, for the benefit of developers
-like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
-
  */
 
 #include <stdio.h>                                             // For printf()
index d0eb61389264c959f8fc207da3b44af2f4f940ee..18b3899b36a256544b58ca08ab7ab6fa393689a1 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: SubTypeTester.c,v $
-Revision 1.7  2006/08/14 23:24:29  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.6  2004/12/16 20:49:35  cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.5  2004/09/17 01:08:50  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.4  2004/09/16 00:24:49  cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
-
-Revision 1.3  2004/08/13 23:25:01  cheshire
-Now that we do both uDNS and mDNS, global replace "m->hostname" with
-"m->MulticastHostname" for clarity
-
-Revision 1.2  2004/08/04 22:11:30  cheshire
-<rdar://problem/3588761> Current method of doing subtypes causes name collisions
-Change to use "._sub." instead of ".s." to mark subtypes.
-
-Revision 1.1  2004/06/11 00:03:28  cheshire
-Add code for testing avail/busy subtypes
-
-
  */
 
 #include <stdio.h>                                             // For printf()
index e54ab00fc961d7d06535461058c73d39f93759c5..31d9423ec1ca700bb81497c0631599aa871efd80 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: mDNSLibrary.c,v $
-Revision 1.4  2006/08/14 23:24:29  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2004/12/16 20:49:35  cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.2  2004/09/17 01:08:50  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.1  2004/03/12 21:30:26  cheshire
-Build a System-Context Shared Library from mDNSCore, for the benefit of developers
-like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
-
  */
 
 // Define the required CFM Shared Library entry and exit points
index f829f14f7fab5a496045ebf8c1610d9c789b9705..d4b365041fca09e7f2d344cb7c5404d1ca882457 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: mDNSLibraryLoader.c,v $
-Revision 1.2  2006/08/14 23:24:29  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.1  2004/03/12 21:30:26  cheshire
-Build a System-Context Shared Library from mDNSCore, for the benefit of developers
-like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
-
  */
 
 #include <Resources.h>
index d7d0ea991d5c98acd9bfcd9bbb16fc3770c4eda7..e3a200a0770469bb7a240604b6cc44a095a6a331 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: mDNSLibraryResources.r,v $
-Revision 1.54  2007/06/27 21:59:08  cheshire
-mDNSResponder-130
-
-Revision 1.53  2007/05/29 23:47:57  cheshire
-mDNSResponder-129
-
-Revision 1.52  2007/05/25 23:45:39  jvidrine
-Update version numbers to reflect the submission number. (Thanks, Marc!)
-
-Revision 1.51  2007/05/25 22:10:19  cheshire
-mDNSResponder-127
-
-Revision 1.50  2007/05/23 00:57:23  cheshire
-mDNSResponder-126
-
-Revision 1.49  2007/05/15 00:47:50  cheshire
-mDNSResponder-125
-
-Revision 1.48  2007/05/14 20:49:54  cheshire
-mDNSResponder-124
-
-Revision 1.47  2007/05/10 21:43:12  cheshire
-mDNSResponder-123
-
-Revision 1.46  2007/04/27 19:33:07  cheshire
-mDNSResponder-122
-
-Revision 1.45  2007/04/08 03:04:00  cheshire
-mDNSResponder-121
-
-Revision 1.44  2007/03/30 23:30:04  cheshire
-mDNSResponder-120
-
-Revision 1.43  2007/02/28 22:09:24  cheshire
-mDNSResponder-119
-
-Revision 1.42  2007/01/09 01:58:20  cheshire
-mDNSResponder-116
-
-Revision 1.41  2006/11/08 04:29:02  cheshire
-mDNSResponder-115
-
-Revision 1.40  2006/10/27 01:46:40  cheshire
-mDNSResponder-114
-
-Revision 1.39  2006/09/30 01:38:53  cheshire
-mDNSResponder-113
-
-Revision 1.38  2006/09/21 23:38:13  cheshire
-mDNSResponder-112
-
-Revision 1.37  2006/08/14 23:24:29  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.36  2006/07/14 00:52:00  cheshire
-mDNSResponder-111
-
-Revision 1.35  2006/06/20 23:05:10  cheshire
-mDNSResponder-110
-
-Revision 1.34  2006/02/09 22:24:53  cheshire
-mDNSResponder-109
-
-Revision 1.33  2005/12/12 17:48:36  cheshire
-mDNSResponder-108
-
-Revision 1.32  2005/05/05 00:06:58  ksekar
-Update version string to 1.0a107.1
-
-Revision 1.31  2005/03/15 02:14:14  cheshire
-mDNSResponder-107
-
-Revision 1.30  2005/03/10 01:32:37  cheshire
-mDNSResponder-105
-
-Revision 1.29  2005/02/26 05:20:13  cheshire
-mDNSResponder-102
-
-Revision 1.28  2005/02/19 00:42:58  cheshire
-mDNSResponder-101
-
-Revision 1.27  2005/02/10 21:56:38  cheshire
-mDNSResponder-100
-
-Revision 1.26  2005/02/04 03:25:10  cheshire
-mDNSResponder-99
-
-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
-
-Revision 1.16  2004/12/06 19:09:47  cheshire
-mDNSResponder-86
-
-Revision 1.15  2004/11/29 23:36:15  cheshire
-mDNSResponder-85
-
-Revision 1.14  2004/11/23 03:46:31  cheshire
-mDNSResponder-84
-
-Revision 1.13  2004/10/26 20:30:30  cheshire
-mDNSResponder-82
-
-Revision 1.12  2004/10/14 23:38:04  cheshire
-mDNSResponder-80
-
-Revision 1.11  2004/10/07 21:49:15  cheshire
-mDNSResponder-79
-
-Revision 1.10  2004/09/25 02:52:09  cheshire
-mDNSResponder-78
-
-Revision 1.9  2004/09/22 22:52:07  cheshire
-mDNSResponder-77
-
-Revision 1.8  2004/09/21 00:20:52  cheshire
-mDNSResponder-76
-
-Revision 1.7  2004/09/15 19:45:06  cheshire
-mDNSResponder-75
-
-Revision 1.6  2004/09/09 23:32:35  cheshire
-mDNSResponder-74
-
-Revision 1.5  2004/08/10 21:51:45  cheshire
-mDNSResponder-69
-
-Revision 1.4  2004/06/10 20:28:16  cheshire
-Update version string to 1.0a66
-
-Revision 1.3  2004/06/05 00:37:12  cheshire
-Update version string to 1.0a65
-
-Revision 1.2  2004/05/27 06:24:21  cheshire
-Update version string to 1.0a64
-
-Revision 1.1  2004/03/12 21:30:26  cheshire
-Build a System-Context Shared Library from mDNSCore, for the benefit of developers
-like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
-
  */
 
 #ifndef __TYPES.R__
index 18c4da9901332142c8ddb6c572d92c5e11462c47..8ad053369ea93ab10edb2128dbec37a0a0d1143a 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: mDNSMacOS9.c,v $
-Revision 1.51  2007/09/12 19:23:17  cheshire
-Get rid of unnecessary mDNSPlatformTCPIsConnected() routine
-
-Revision 1.50  2007/04/05 20:40:37  cheshire
-Remove unused mDNSPlatformTCPGetFlags()
-
-Revision 1.49  2007/03/22 18:31:48  cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.48  2007/03/20 17:07:15  cheshire
-Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-
-Revision 1.47  2006/12/19 22:43:54  cheshire
-Fix compiler warnings
-
-Revision 1.46  2006/08/14 23:24:29  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.45  2006/03/19 02:00:14  cheshire
-<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-
-Revision 1.44  2005/09/16 21:06:50  cheshire
-Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place
-
-Revision 1.43  2004/12/17 23:37:49  cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-(and other repetitive configuration changes)
-
-Revision 1.42  2004/12/16 20:43:39  cheshire
-interfaceinfo.fMask should be interfaceinfo.fNetmask
-
-Revision 1.41  2004/10/16 00:17:00  cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
-
-Revision 1.40  2004/09/27 23:56:27  cheshire
-Fix infinite loop where mDNSPlatformUnlock() called mDNS_TimeNow(),
-and then mDNS_TimeNow() called mDNSPlatformUnlock()
-
-Revision 1.39  2004/09/21 21:02:54  cheshire
-Set up ifname before calling mDNS_RegisterInterface()
-
-Revision 1.38  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
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.37  2004/09/17 00:19:10  cheshire
-For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
-
-Revision 1.36  2004/09/16 21:59:16  cheshire
-For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
-
-Revision 1.35  2004/09/16 00:24:49  cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
-
-Revision 1.34  2004/09/14 23:42:36  cheshire
-<rdar://problem/3801296> Need to seed random number generator from platform-layer data
-
-Revision 1.33  2004/09/14 23:16:31  cheshire
-Fix compile error: mDNS_SetFQDNs has been renamed to mDNS_SetFQDN
-
-Revision 1.32  2004/09/14 21:03:16  cheshire
-Fix spacing
-
-Revision 1.31  2004/08/14 03:22:42  cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
-
-Revision 1.30  2004/07/29 19:26:03  ksekar
-Plaform-level changes for NAT-PMP support
-
-Revision 1.29  2004/05/26 20:53:16  cheshire
-Remove unncecessary "return( -1 );" at the end of mDNSPlatformUTC()
-
-Revision 1.28  2004/05/20 18:39:06  cheshire
-Fix build broken by addition of mDNSPlatformUTC requirement
-
-Revision 1.27  2004/04/21 02:49:11  cheshire
-To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
-
-Revision 1.26  2004/04/09 17:43:03  cheshire
-Make sure to set the McastTxRx field so that duplicate suppression works correctly
-
-Revision 1.25  2004/03/15 18:55:38  cheshire
-Comment out debugging message
-
-Revision 1.24  2004/03/12 21:30:26  cheshire
-Build a System-Context Shared Library from mDNSCore, for the benefit of developers
-like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
-
-Revision 1.23  2004/02/09 23:24:43  cheshire
-Need to set TTL 255 to interoperate with peers that check TTL (oops!)
-
-Revision 1.22  2004/01/27 20:15:23  cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
-
-Revision 1.21  2004/01/24 04:59:16  cheshire
-Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
-
-Revision 1.20  2003/11/14 20:59:09  cheshire
-Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
-Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
-
-Revision 1.19  2003/08/18 23:09:20  cheshire
-<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
-
-Revision 1.18  2003/08/12 19:56:24  cheshire
-Update to APSL 2.0
-
  */
 
 #include <stdio.h>
index 149ec0340804e71aedb2f118bcbb504e19f1fe41..eabd7e7100773bfb05dbcc9466b1c7ae028433fa 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: mDNSMacOS9.h,v $
-Revision 1.11  2006/08/14 23:24:29  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.10  2004/03/12 21:30:26  cheshire
-Build a System-Context Shared Library from mDNSCore, for the benefit of developers
-like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
-
-Revision 1.9  2004/02/09 23:25:35  cheshire
-Need to set TTL 255 to interoperate with peers that check TTL (oops!)
-
-Revision 1.8  2003/08/12 19:56:24  cheshire
-Update to APSL 2.0
-
  */
 
 // ***************************************************************************
index 5cf83fb936546342dffef227d9f69fc2ff7b75fd..fb8ac8843f95893095fbafc6b96f2c4140c945ce 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: mDNSPrefix.h,v $
-Revision 1.4  2006/08/14 23:24:29  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2004/06/11 00:03:28  cheshire
-Add code for testing avail/busy subtypes
-
-Revision 1.2  2004/05/21 01:57:08  cheshire
-Add macros for malloc() and free() so that dnssd_clientlib.c can use them
-
-Revision 1.1  2004/03/12 21:30:26  cheshire
-Build a System-Context Shared Library from mDNSCore, for the benefit of developers
-like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
-
  */
 
 // Global definitions that apply to all source files
index 7dc7d6219279de2f42610716179ec700226550a4..62b0296b9d3e0c4efdff3462d26df0646ebc20c4 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: DNSServiceDiscoveryDefines.h,v $
-Revision 1.8  2006/10/27 00:35:36  cheshire
-DNS_SERVICE_DISCOVERY_SERVER is now com.apple.mDNSResponder, not DNSServiceDiscoveryServer
-
-Revision 1.7  2006/08/14 23:24:39  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.6  2004/09/20 21:45:27  ksekar
-Mach IPC cleanup
-
-Revision 1.5  2003/08/12 19:56:25  cheshire
-Update to APSL 2.0
-
  */
 
 #ifndef __DNS_SERVICE_DISCOVERY_DEFINES_H
index 1a05eb16cd8ad322268d1df69b2bcb9b8e4fdbec..115719e0334b22e6dbe75edadc2420a6a89ddb9f 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: LegacyNATTraversal.c,v $
-Revision 1.65  2009/07/03 03:16:07  jessic2
-<rdar://problem/7026146> BTMM: UPnP works in Leopard but doesn't work in SnowLeopard (URLBase is empty) Made changes to support the case where the URLBase tag exists but there isn't a valid URL
-
-Revision 1.64  2009/06/25 21:07:44  herscher
-<rdar://problem/4147784> B4W should support UPnP
-
-Revision 1.63  2009/03/26 03:59:00  jessic2
-Changes for <rdar://problem/6492552&6492593&6492609&6492613&6492628&6492640&6492699>
-
-Revision 1.62  2009/02/13 06:31:09  cheshire
-Converted LogOperation messages to LogInfo
-
-Revision 1.61  2009/01/23 19:25:43  mcguire
-<rdar://problem/6514439> UPnP: Should not use NATErr_Refused when too many conflict retries
-
-Revision 1.60  2009/01/23 00:38:36  mcguire
-<rdar://problem/5570906> BTMM: Doesn't work with Linksys WRT54GS firmware 4.71.1
-
-Revision 1.59  2009/01/22 20:32:17  mcguire
-<rdar://problem/6446934> BTMM: pref pane reports enabled but negotiation failed
-Make sure we push the pointer out past the LF if we read it.
-
-Revision 1.58  2009/01/22 01:15:58  mcguire
-<rdar://problem/6446934> BTMM: pref pane reports enabled but negotiation failed
-
-Revision 1.57  2008/12/19 21:09:22  mcguire
-<rdar://problem/6431147> UPnP: error messages when canceling seemingly unrelated browse
-
-Revision 1.56  2008/12/06 01:42:57  mcguire
-<rdar://problem/6418958> Need to exponentially back-off after failure to get public address
-
-Revision 1.55  2008/12/01 19:43:48  mcguire
-<rdar://problem/6404766> UPnP: Handle errorCode 718 as a conflict when requesting a port mapping
-
-Revision 1.54  2008/11/26 20:57:37  cheshire
-For consistency with other similar macros, renamed mdnsIsDigit/mdnsIsLetter/mdnsValidHostChar
-to mDNSIsDigit/mDNSIsLetter/mDNSValidHostChar
-
-Revision 1.53  2008/11/26 20:34:04  cheshire
-Changed "destroying SSDPSocket" LogOperation debugging messages to debugf
-
-Revision 1.52  2008/11/26 19:54:03  cheshire
-Changed some "LogOperation" debugging messages to "debugf"
-
-Revision 1.51  2008/11/20 02:23:38  mcguire
-<rdar://problem/6041208> need to handle URLBase
-
-Revision 1.50  2008/09/20 00:34:22  mcguire
-<rdar://problem/6129039> BTMM: Add support for WANPPPConnection
-
-Revision 1.49  2008/08/07 21:51:13  mcguire
-<rdar://problem/5904423> UPnP: Possible memory corruption bug
-<rdar://problem/5930173> UPnP: Combine URL parsing code
-
-Revision 1.48  2008/07/24 20:23:04  cheshire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-
-Revision 1.47  2008/07/18 21:37:46  mcguire
-<rdar://problem/5736845> BTMM: alternate SSDP queries between multicast & unicast
-
-Revision 1.46  2008/05/13 01:51:12  mcguire
-<rdar://problem/5839161> UPnP compatibility workaround for Netgear WGT624
-
-Revision 1.45  2007/12/06 00:22:27  mcguire
-<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
-
-Revision 1.44  2007/11/02 20:45:40  cheshire
-Don't log "connection failed" in customer builds
-
-Revision 1.43  2007/10/18 20:09:47  cheshire
-<rdar://problem/5545930> BTMM: Back to My Mac not working with D-Link DGL-4100 NAT gateway
-
-Revision 1.42  2007/10/16 17:37:18  cheshire
-<rdar://problem/3557903> Performance: Core code will not work on platforms with small stacks
-Cut SendSOAPMsgControlAction stack from 2144 to 96 bytes
-
-Revision 1.41  2007/10/15 23:02:00  cheshire
-Off-by-one error: Incorrect trailing zero byte on the end of the SSDP Discovery message
-
-Revision 1.40  2007/09/20 21:41:49  cheshire
-<rdar://problem/5495568> Legacy NAT Traversal - unmap request failed with error -65549
-
-Revision 1.39  2007/09/20 20:41:40  cheshire
-Reordered functions in file, in preparation for following fix
-
-Revision 1.38  2007/09/18 21:42:30  cheshire
-To reduce programming mistakes, renamed ExtPort to RequestedPort
-
-Revision 1.37  2007/09/14 21:26:09  cheshire
-<rdar://problem/5482627> BTMM: Need to manually avoid port conflicts when using UPnP gateways
-
-Revision 1.36  2007/09/14 01:15:50  cheshire
-Minor fixes for problems discovered in pre-submission testing
-
-Revision 1.35  2007/09/13 00:16:42  cheshire
-<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
-
-Revision 1.34  2007/09/12 23:03:08  cheshire
-<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
-
-Revision 1.33  2007/09/12 19:22:20  cheshire
-Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
-Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
-
-Revision 1.32  2007/09/11 19:19:16  cheshire
-Correct capitalization of "uPNP" to "UPnP"
-
-Revision 1.31  2007/09/10 22:14:16  cheshire
-When constructing fake NATAddrReply or NATPortMapReply packet, need to calculate
-plausible upseconds value or core logic will think NAT engine has been rebooted
-
-Revision 1.30  2007/09/05 20:46:17  cheshire
-Tidied up alignment of code layout
-
-Revision 1.29  2007/08/03 20:18:01  vazquez
-<rdar://problem/5382177> LegacyNATTraversal: reading out of bounds can lead to DoS
-
-Revision 1.28  2007/07/31 02:28:36  vazquez
-<rdar://problem/3734269> NAT-PMP: Detect public IP address changes and base station reboot
-
-Revision 1.27  2007/07/30 23:17:03  vazquez
-Since lease times are meaningless in UPnP, return NATMAP_DEFAULT_LEASE in UPnP port mapping reply
-
-Revision 1.26  2007/07/27 22:50:08  vazquez
-Allocate memory for UPnP request and reply buffers instead of using arrays
-
-Revision 1.25  2007/07/27 20:33:44  vazquez
-Make sure we clean up previous port mapping requests before starting an unmap
-
-Revision 1.24  2007/07/27 00:57:48  vazquez
-If a tcp connection is already established for doing a port mapping, don't start it again
-
-Revision 1.23  2007/07/26 21:19:26  vazquez
-Retry port mapping with incremented port number (up to max) in order to handle
-port mapping conflicts on UPnP gateways
-
-Revision 1.22  2007/07/25 21:41:00  vazquez
-Make sure we clean up opened sockets when there are network transitions and when changing
-port mappings
-
-Revision 1.21  2007/07/25 03:05:03  vazquez
-Fixes for:
-<rdar://problem/5338913> LegacyNATTraversal: UPnP heap overflow
-<rdar://problem/5338933> LegacyNATTraversal: UPnP stack buffer overflow
-and a myriad of other security problems
-
-Revision 1.20  2007/07/16 20:15:10  vazquez
-<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
-
-Revision 1.19  2007/06/21 16:37:43  jgraessley
-Bug #: 5280520
-Reviewed by: Stuart Cheshire
-Additional changes to get this compiling on the embedded platform.
-
-Revision 1.18  2007/05/09 01:43:32  cheshire
-<rdar://problem/5187028> Change sprintf and strcpy to their safer snprintf and strlcpy equivalents
-
-Revision 1.17  2007/02/27 02:48:25  cheshire
-Parameter to LNT_GetPublicIP function is IPv4 address, not anonymous "mDNSOpaque32" object
-
-Revision 1.16  2006/08/14 23:24:39  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.15  2006/07/05 23:30:57  cheshire
-Rename LegacyNATInit() -> LNT_Init()
-
-Revision 1.14  2005/12/08 03:00:33  cheshire
-<rdar://problem/4349971> Byte order bugs in Legacy NAT traversal code
-
-Revision 1.13  2005/09/07 18:23:05  ksekar
-<rdar://problem/4151514> Off-by-one overflow in LegacyNATTraversal
-
-Revision 1.12  2005/07/22 21:36:16  ksekar
-Fix GCC 4.0/Intel compiler warnings
-
-Revision 1.11  2004/12/03 03:34:20  ksekar
-<rdar://problem/3882674> LegacyNATTraversal.c leaks threads
-
-Revision 1.10  2004/12/01 02:43:49  cheshire
-Update copyright message
-
-Revision 1.9  2004/10/27 02:25:05  cheshire
-<rdar://problem/3816029> Random memory smashing bug
-
-Revision 1.8  2004/10/27 02:17:21  cheshire
-Turn off "safe_close: ERROR" error messages -- there are too many of them
-
-Revision 1.7  2004/10/26 21:15:40  cheshire
-<rdar://problem/3854314> Legacy NAT traversal code closes file descriptor 0
-Additional fixes: Code should set fds to -1 after closing sockets.
-
-Revision 1.6  2004/10/26 20:59:20  cheshire
-<rdar://problem/3854314> Legacy NAT traversal code closes file descriptor 0
-
-Revision 1.5  2004/10/26 01:01:35  cheshire
-Use "#if 0" instead of commenting out code
-
-Revision 1.4  2004/10/10 06:51:36  cheshire
-Declared some strings "const" as appropriate
-
-Revision 1.3  2004/09/21 23:40:12  ksekar
-<rdar://problem/3810349> mDNSResponder to return errors on NAT traversal failure
-
-Revision 1.2  2004/09/17 01:08:52  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.1  2004/08/18 17:35:41  ksekar
-<rdar://problem/3651443>: Feature #9586: Need support for Legacy NAT gateways
-*/
+ */
 
 #ifdef _LEGACY_NAT_TRAVERSAL_
 
@@ -249,9 +34,9 @@ inet_pton( int family, const char * addr, void * dst )
        int sslen = sizeof( ss );
 
        ZeroMemory( &ss, sizeof( ss ) );
-       ss.ss_family = family;
+       ss.ss_family = (ADDRESS_FAMILY)family;
 
-       if ( WSAStringToAddressA( addr, family, NULL, ( struct sockaddr* ) &ss, &sslen ) == 0 )
+       if ( WSAStringToAddressA( (LPSTR)addr, family, NULL, ( struct sockaddr* ) &ss, &sslen ) == 0 )
                {
                if ( family == AF_INET ) { memcpy( dst, &( ( struct sockaddr_in* ) &ss)->sin_addr, sizeof( IN_ADDR ) ); return 1; }
                else if ( family == AF_INET6 ) { memcpy( dst, &( ( struct sockaddr_in6* ) &ss)->sin6_addr, sizeof( IN6_ADDR ) ); return 1; }
@@ -290,26 +75,27 @@ typedef struct Property_struct
 // In the event of a port conflict, handleLNTPortMappingResponse then increments tcpInfo->retries and calls back to SendPortMapRequest to try again
 mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n);
 
-#define RequestedPortNum(n) (mDNSVal16(mDNSIPPortIsZero((n)->RequestedPort) ? (n)->IntPort : (n)->RequestedPort) + (n)->tcpInfo.retries)
+#define RequestedPortNum(n) (mDNSVal16(mDNSIPPortIsZero((n)->RequestedPort) ? (n)->IntPort : (n)->RequestedPort) + (mDNSu16)(n)->tcpInfo.retries)
 
 // Note that this function assumes src is already NULL terminated
-mDNSlocal void AllocAndCopy(mDNSu8** dst, mDNSu8* src)
+mDNSlocal void AllocAndCopy(mDNSu8 **const dst, const mDNSu8 *const src)
        {
        if (src == mDNSNULL) return;
-       if ((*dst = (mDNSu8 *) mDNSPlatformMemAllocate(strlen((char*)src) + 1)) == mDNSNULL) { LogMsg("AllocAndCopy: can't allocate string"); return; }
-       strcpy((char *)*dst, (char*)src);
+       if ((*dst = mDNSPlatformMemAllocate((mDNSu32)strlen((char*)src) + 1)) == mDNSNULL)
+               { LogMsg("AllocAndCopy: can't allocate string"); return; }
+       strcpy((char*)*dst, (char*)src);
        }
 
 // This function does a simple parse of an HTTP URL that may include a hostname, port, and path
 // If found in the URL, addressAndPort and path out params will point to newly allocated space (and will leak if they were previously pointing at allocated space)
-mDNSlocal mStatus ParseHttpUrl(char* ptr, char* end, mDNSu8** addressAndPort, mDNSIPPort* port, mDNSu8** path)
+mDNSlocal mStatus ParseHttpUrl(const mDNSu8 *ptr, const mDNSu8 *const end, mDNSu8 **const addressAndPort, mDNSIPPort *const port, mDNSu8 **const path)
        {
        // if the data begins with "http://", we assume there is a hostname and possibly a port number
-       if (end - ptr >= 7 && strncasecmp(ptr, "http://", 7) == 0)
+       if (end - ptr >= 7 && strncasecmp((char*)ptr, "http://", 7) == 0)
                {
-               int  i;
-               char* stop = end;
-               char* addrPtr = mDNSNULL;
+               int i;
+               const mDNSu8 *stop = end;
+               const mDNSu8 *addrPtr = mDNSNULL;
                
                ptr += 7; //skip over "http://"
                if (ptr >= end) { LogInfo("ParseHttpUrl: past end of buffer parsing host:port"); return mStatus_BadParamErr; }
@@ -319,22 +105,21 @@ mDNSlocal mStatus ParseHttpUrl(char* ptr, char* end, mDNSu8** addressAndPort, mD
                for (i = 0; addrPtr && addrPtr != end; i++, addrPtr++) if (*addrPtr == '/') break;
 
                // allocate the buffer (len i+1 so we have space to terminate the string)
-               if ((*addressAndPort = (mDNSu8 *) mDNSPlatformMemAllocate(i+1)) == mDNSNULL) { LogMsg("ParseHttpUrl: can't allocate address string"); return mStatus_NoMemoryErr; }
-               strncpy((char *)*addressAndPort, ptr, i);
+               if ((*addressAndPort = mDNSPlatformMemAllocate(i+1)) == mDNSNULL)
+                       { LogMsg("ParseHttpUrl: can't allocate address string"); return mStatus_NoMemoryErr; }
+               strncpy((char*)*addressAndPort, (char*)ptr, i);
                (*addressAndPort)[i] = '\0';
 
                // find the port number in the string, by looking backwards for the ':'
                stop = ptr;    // can't go back farther than the original start
                ptr = addrPtr; // move ptr to the path part
                
-               for (addrPtr--;addrPtr>stop;addrPtr--)
+               for (addrPtr--; addrPtr>stop; addrPtr--)
                        {
                        if (*addrPtr == ':')
                                {
-                               int tmpport;
                                addrPtr++; // skip over ':'
-                               tmpport = (int)strtol(addrPtr, mDNSNULL, 10);
-                               *port = mDNSOpaque16fromIntVal(tmpport); // store it properly converted
+                               *port = mDNSOpaque16fromIntVal((mDNSu16)strtol((char*)addrPtr, mDNSNULL, 10)); // store it properly converted
                                break;
                                }
                        }
@@ -344,8 +129,9 @@ mDNSlocal mStatus ParseHttpUrl(char* ptr, char* end, mDNSu8** addressAndPort, mD
        // everything that remains is the path
        if (path && ptr < end)
                {
-               if ((*path = (mDNSu8 *)mDNSPlatformMemAllocate(end - ptr + 1)) == mDNSNULL) { LogMsg("ParseHttpUrl: can't mDNSPlatformMemAllocate path"); return mStatus_NoMemoryErr; }
-               strncpy((char *)*path, ptr, end - ptr);
+               if ((*path = mDNSPlatformMemAllocate((mDNSu32)(end - ptr) + 1)) == mDNSNULL)
+                       { LogMsg("ParseHttpUrl: can't mDNSPlatformMemAllocate path"); return mStatus_NoMemoryErr; }
+               strncpy((char*)*path, (char*)ptr, end - ptr);
                (*path)[end - ptr] = '\0';
                }
                
@@ -362,10 +148,10 @@ enum
        HTTPCode_500          = 500,
        };
        
-mDNSlocal mDNSs16 ParseHTTPResponseCode(mDNSu8** data, mDNSu8* end)
+mDNSlocal mDNSs16 ParseHTTPResponseCode(const mDNSu8 **const data, const mDNSu8 *const end)
        {
-       mDNSu8* ptr = *data;
-       char * code;
+       const mDNSu8 *ptr = *data;
+       const mDNSu8 *code;
        
        if (end - ptr < 5) return HTTPCode_NeedMoreData;
        if (strncasecmp((char*)ptr, "HTTP/", 5) != 0) return HTTPCode_Bad;
@@ -384,7 +170,7 @@ mDNSlocal mDNSs16 ParseHTTPResponseCode(mDNSu8** data, mDNSu8* end)
        
        if (end - ptr < 3) return HTTPCode_NeedMoreData;
 
-       code = (char*)ptr;
+       code = ptr;
        ptr += 3;
        while (ptr && ptr != end)
                {
@@ -394,27 +180,28 @@ mDNSlocal mDNSs16 ParseHTTPResponseCode(mDNSu8** data, mDNSu8* end)
        if (ptr == end) return HTTPCode_NeedMoreData;
        *data = ++ptr;
        
-       if (memcmp(code, "200", 3) == 0) return HTTPCode_200;
-       if (memcmp(code, "404", 3) == 0) return HTTPCode_404;
-       if (memcmp(code, "500", 3) == 0) return HTTPCode_500;
+       if (memcmp((char*)code, "200", 3) == 0) return HTTPCode_200;
+       if (memcmp((char*)code, "404", 3) == 0) return HTTPCode_404;
+       if (memcmp((char*)code, "500", 3) == 0) return HTTPCode_500;
        
        LogInfo("ParseHTTPResponseCode found unexpected result code: %c%c%c", code[0], code[1], code[2]);
        return HTTPCode_Other;
        }
 
-// This function parses the xml body of the device description response from the router. Basically, we look to make sure this is a response
-// referencing a service we care about (WANIPConnection or WANPPPConnection), look for the "controlURL" header immediately following, and copy the addressing and URL info we need
+// This function parses the xml body of the device description response from the router. Basically, we look to
+// make sure this is a response referencing a service we care about (WANIPConnection or WANPPPConnection),
+// look for the "controlURL" header immediately following, and copy the addressing and URL info we need
 mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo)
        {
        mDNS    *m    = tcpInfo->m;
-       char    *ptr  = (char *)tcpInfo->Reply;
-       char    *end  = (char *)tcpInfo->Reply + tcpInfo->nread;
-       char    *stop = mDNSNULL;
+       const mDNSu8 *ptr  = tcpInfo->Reply;
+       const mDNSu8 *end  = tcpInfo->Reply + tcpInfo->nread;
+       const mDNSu8 *stop;
        mDNSs16 http_result;
        
        if (!mDNSIPPortIsZero(m->UPnPSOAPPort)) return; // already have the info we need
 
-       http_result = ParseHTTPResponseCode((mDNSu8**)&ptr, (mDNSu8*)end); // Note: modifies ptr
+       http_result = ParseHTTPResponseCode(&ptr, end); // Note: modifies ptr
        if (http_result == HTTPCode_404) LNT_ClearState(m);
        if (http_result != HTTPCode_200) 
                {
@@ -428,15 +215,15 @@ mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo)
        // find either service we care about
        while (ptr && ptr < end)
                {
-               if (*ptr == 'W' && (strncasecmp(ptr, "WANIPConnection:1", 17) == 0)) break;
+               if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANIPConnection:1", 17) == 0)) break;
                ptr++;
                }
        if (ptr == end)
                {
-               ptr = (char *)tcpInfo->Reply;
+               ptr = tcpInfo->Reply;
                while (ptr && ptr < end)
                        {
-                       if (*ptr == 'W' && (strncasecmp(ptr, "WANPPPConnection:1", 18) == 0))
+                       if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANPPPConnection:1", 18) == 0))
                                {
                                m->UPnPWANPPPConnection = mDNStrue;
                                break;
@@ -449,7 +236,7 @@ mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo)
        // find "controlURL", starting from where we left off
        while (ptr && ptr < end)
                {
-               if (*ptr == 'c' && (strncasecmp(ptr, "controlURL", 10) == 0)) break;                    // find the first 'c'; is this controlURL? if not, keep looking
+               if ((*ptr & 0xDF) == 'C' && (strncasecmp((char*)ptr, "controlURL", 10) == 0)) break;                    // find the first 'c'; is this controlURL? if not, keep looking
                ptr++;
                }
        if (ptr == mDNSNULL || ptr == end) { LogInfo("handleLNTDeviceDescriptionResponse: didn't find controlURL string"); return; }
@@ -479,10 +266,10 @@ mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo)
 
        if (m->UPnPSOAPAddressString == mDNSNULL)
                {
-               ptr = (char *)tcpInfo->Reply;
+               ptr = tcpInfo->Reply;
                while (ptr && ptr < end)
                        {
-                       if (*ptr == 'U' && (strncasecmp(ptr, "URLBase", 7) == 0))               break;
+                       if ((*ptr & 0xDF) == 'U' && (strncasecmp((char*)ptr, "URLBase", 7) == 0))               break;
                        ptr++;
                        }
 
@@ -499,7 +286,7 @@ mDNSlocal void handleLNTDeviceDescriptionResponse(tcpLNTInfo *tcpInfo)
                        }
                
                // if all else fails, use the router address string
-               if (m->UPnPSOAPAddressString == mDNSNULL)  AllocAndCopy(&m->UPnPSOAPAddressString, m->UPnPRouterAddressString);
+               if (m->UPnPSOAPAddressString == mDNSNULL) AllocAndCopy(&m->UPnPSOAPAddressString, m->UPnPRouterAddressString);
                }
        if (m->UPnPSOAPAddressString == mDNSNULL) LogMsg("handleLNTDeviceDescriptionResponse: UPnPSOAPAddressString is NULL");
        else LogInfo("handleLNTDeviceDescriptionResponse: SOAP address string [%s]", m->UPnPSOAPAddressString);
@@ -514,10 +301,11 @@ mDNSlocal void handleLNTGetExternalAddressResponse(tcpLNTInfo *tcpInfo)
        mDNS       *m = tcpInfo->m;
        mDNSu16     err = NATErr_None;
        mDNSv4Addr  ExtAddr;
-       mDNSu8     *ptr = (mDNSu8*)tcpInfo->Reply;
-       mDNSu8     *end = (mDNSu8*)tcpInfo->Reply + tcpInfo->nread;
-       mDNSu8     *addrend;
-       static char tagname[20] = "NewExternalIPAddress";               // Array NOT including a terminating nul
+       const mDNSu8 *ptr = tcpInfo->Reply;
+       const mDNSu8 *end = tcpInfo->Reply + tcpInfo->nread;
+       mDNSu8       *addrend;
+       static char tagname[20] = { 'N','e','w','E','x','t','e','r','n','a','l','I','P','A','d','d','r','e','s','s' };
+       // Array NOT including a terminating nul
 
 //     LogInfo("handleLNTGetExternalAddressResponse: %s", ptr);
 
@@ -529,13 +317,14 @@ mDNSlocal void handleLNTGetExternalAddressResponse(tcpLNTInfo *tcpInfo)
                return;
                }
 
-       
        while (ptr < end && strncasecmp((char*)ptr, tagname, sizeof(tagname))) ptr++;
        ptr += sizeof(tagname);                                         // Skip over "NewExternalIPAddress"
        while (ptr < end && *ptr != '>') ptr++;
        ptr += 1;                                                                       // Skip over ">"
+
        // Find the end of the address and terminate the string so inet_pton() can convert it
-       addrend = ptr;
+       // (Might be better to copy this to a local string here -- this is overwriting tcpInfo->Reply in-place
+       addrend = (mDNSu8*)ptr;
        while (addrend < end && (mDNSIsDigit(*addrend) || *addrend == '.')) addrend++;
        if (addrend >= end) return;
        *addrend = 0;
@@ -554,10 +343,10 @@ mDNSlocal void handleLNTGetExternalAddressResponse(tcpLNTInfo *tcpInfo)
 
 mDNSlocal void handleLNTPortMappingResponse(tcpLNTInfo *tcpInfo)
        {
-       mDNS             *m       = tcpInfo->m;
-       mDNSIPPort        extport = zeroIPPort;
-       mDNSu8           *ptr     = (mDNSu8*)tcpInfo->Reply;
-       mDNSu8           *end     = (mDNSu8*)tcpInfo->Reply + tcpInfo->nread;
+       mDNS             *m         = tcpInfo->m;
+       mDNSIPPort        extport   = zeroIPPort;
+       const mDNSu8     *ptr       = tcpInfo->Reply;
+       const mDNSu8     *const end = tcpInfo->Reply + tcpInfo->nread;
        NATTraversalInfo *natInfo;
        mDNSs16 http_result;
 
@@ -580,7 +369,8 @@ mDNSlocal void handleLNTPortMappingResponse(tcpLNTInfo *tcpInfo)
                {
                while (ptr && ptr != end)
                        {
-                       if (((*ptr == 'c' || *ptr == 'C') && end - ptr >= 8 && strncasecmp((char*)ptr, "Conflict", 8) == 0) || (*ptr == '>' && end - ptr >= 15 && strncasecmp((char*)ptr, ">718</errorCode", 15) == 0))
+                       if (((*ptr & 0xDF) == 'C' && end - ptr >= 8 && strncasecmp((char*)ptr, "Conflict", 8) == 0) ||
+                               (*ptr == '>' && end - ptr >= 15 && strncasecmp((char*)ptr, ">718</errorCode", 15) == 0))
                                {
                                if (tcpInfo->retries < 100)
                                        { 
@@ -630,12 +420,12 @@ mDNSlocal void tcpConnectionCallback(TCPSocket *sock, void *context, mDNSBool Co
        if (ConnectionEstablished)              // connection is established - send the message
                {
                LogInfo("tcpConnectionCallback: connection established, sending message");
-               nsent = mDNSPlatformWriteTCP(sock, (char *)tcpInfo->Request, tcpInfo->requestLen);
+               nsent = mDNSPlatformWriteTCP(sock, (char*)tcpInfo->Request, tcpInfo->requestLen);
                if (nsent != (long)tcpInfo->requestLen) { LogMsg("tcpConnectionCallback: error writing"); status = mStatus_UnknownErr; goto exit; }
                }
        else
                {
-               n = mDNSPlatformReadTCP(sock, (char *)tcpInfo->Reply + tcpInfo->nread, tcpInfo->replyLen - tcpInfo->nread, &closed);
+               n = mDNSPlatformReadTCP(sock, (char*)tcpInfo->Reply + tcpInfo->nread, tcpInfo->replyLen - tcpInfo->nread, &closed);
                LogInfo("tcpConnectionCallback: mDNSPlatformReadTCP read %d bytes", n);
 
                if      (n < 0)  { LogInfo("tcpConnectionCallback - read returned %d", n);                           status = mStatus_ConnFailed; goto exit; }
@@ -671,7 +461,9 @@ exit:
                                                                         if (m->UPnPSOAPAddressString && m->UPnPSOAPURL)
                                                                                mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.DeviceDescription", "success", "success", "");
                                                                         break;
-                       case LNTExternalAddrOp:  mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest", mDNSIPv4AddressIsZero(m->ExternalAddress) ? "failure" : "success", mDNSIPv4AddressIsZero(m->ExternalAddress) ? "failure" : "success", "");
+                       case LNTExternalAddrOp:  mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.AddressRequest",
+                                                                               mDNSIPv4AddressIsZero(m->ExternalAddress) ? "failure" : "success",
+                                                                               mDNSIPv4AddressIsZero(m->ExternalAddress) ? "failure" : "success", "");
                                                                         break;
                        case LNTPortMapOp:       if (tcpInfo->parentNATInfo)    
                                                                                mDNSASLLog((uuid_t *)&m->asl_uuid, "natt.legacy.PortMapRequest", (tcpInfo->parentNATInfo->Result) ? "failure" : "success", 
@@ -705,14 +497,14 @@ mDNSlocal mStatus MakeTCPConnection(mDNS *const m, tcpLNTInfo *info, const mDNSA
        info->op        = op;
        info->nread     = 0;
        info->replyLen  = LNT_MAXBUFSIZE;
-       if      (info->Reply != mDNSNULL)  mDNSPlatformMemZero(info->Reply, LNT_MAXBUFSIZE);   // reuse previously allocated buffer
-       else if ((info->Reply = (mDNSs8 *) mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate reply buffer"); return (mStatus_NoMemoryErr); }
+       if      (info->Reply != mDNSNULL) mDNSPlatformMemZero(info->Reply, LNT_MAXBUFSIZE);   // reuse previously allocated buffer
+       else if ((info->Reply = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate reply buffer"); return (mStatus_NoMemoryErr); }
 
        if (info->sock) { LogInfo("MakeTCPConnection: closing previous open connection"); mDNSPlatformTCPCloseConnection(info->sock); info->sock = mDNSNULL; }
        info->sock = mDNSPlatformTCPSocket(m, kTCPSocketFlags_Zero, &srcport);
        if (!info->sock) { LogMsg("LNT MakeTCPConnection: unable to create TCP socket"); mDNSPlatformMemFree(info->Reply); info->Reply = mDNSNULL; return(mStatus_NoMemoryErr); }
        LogInfo("MakeTCPConnection: connecting to %#a:%d", &info->Address, mDNSVal16(info->Port));
-       err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpConnectionCallback, info);
+       err = mDNSPlatformTCPConnect(info->sock, Addr, Port, mDNSNULL, 0, tcpConnectionCallback, info);
 
        if      (err == mStatus_ConnPending) err = mStatus_NoError;
        else if (err == mStatus_ConnEstablished)
@@ -734,7 +526,7 @@ mDNSlocal mStatus MakeTCPConnection(mDNS *const m, tcpLNTInfo *info, const mDNSA
        return(err);
        }
 
-mDNSlocal unsigned int AddSOAPArguments(char *buf, unsigned int maxlen, int numArgs, Property *a)
+mDNSlocal unsigned int AddSOAPArguments(char *const buf, const unsigned int maxlen, const int numArgs, const Property *const a)
        {
        static const char f1[] = "<%s>%s</%s>";
        static const char f2[] = "<%s xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"%s\">%s</%s>";
@@ -748,7 +540,7 @@ mDNSlocal unsigned int AddSOAPArguments(char *buf, unsigned int maxlen, int numA
        return(len);
        }
 
-mDNSlocal mStatus SendSOAPMsgControlAction(mDNS *m, tcpLNTInfo *info, char *Action, int numArgs, Property *Arguments, LNTOp_t op)
+mDNSlocal mStatus SendSOAPMsgControlAction(mDNS *m, tcpLNTInfo *info, const char *const Action, const int numArgs, const Property *const Arguments, const LNTOp_t op)
        {
        // SOAP message header format -
        //  - control URL
@@ -781,7 +573,7 @@ mDNSlocal mStatus SendSOAPMsgControlAction(mDNS *m, tcpLNTInfo *info, char *Acti
                "</SOAP-ENV:Envelope>\r\n";
 
        mStatus err;
-       char   *body = (char *)&m->omsg;                        // Typically requires 1110-1122 bytes; m->omsg is 8952 bytes, which is plenty
+       char   *body = (char*)&m->omsg;                 // Typically requires 1110-1122 bytes; m->omsg is 8952 bytes, which is plenty
        int     bodyLen;
 
        if (mDNSIPPortIsZero(m->UPnPSOAPPort) || m->UPnPSOAPURL == mDNSNULL || m->UPnPSOAPAddressString == mDNSNULL)    // if no SOAP URL or address exists get out here
@@ -795,7 +587,7 @@ mDNSlocal mStatus SendSOAPMsgControlAction(mDNS *m, tcpLNTInfo *info, char *Acti
        // Create info->Request; the header needs to contain the bodyLen in the "Content-Length" field
        if (!info->Request) info->Request = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE);
        if (!info->Request) { LogMsg("SendSOAPMsgControlAction: Can't allocate info->Request"); return mStatus_NoMemoryErr; }
-       info->requestLen = mDNS_snprintf((char *)info->Request, LNT_MAXBUFSIZE, header, m->UPnPSOAPURL, m->UPnPWANPPPConnection ? "PPP" : "IP", Action, m->UPnPSOAPAddressString, bodyLen, body);
+       info->requestLen = mDNS_snprintf((char*)info->Request, LNT_MAXBUFSIZE, header, m->UPnPSOAPURL, m->UPnPWANPPPConnection ? "PPP" : "IP", Action, m->UPnPSOAPAddressString, bodyLen, body);
 
        err = MakeTCPConnection(m, info, &m->Router, m->UPnPSOAPPort, op);
        if (err) { mDNSPlatformMemFree(info->Request); info->Request = mDNSNULL; }
@@ -883,7 +675,7 @@ mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n)
        return SendSOAPMsgControlAction(m, &n->tcpInfo, "AddPortMapping", 8, propArgs, LNTPortMapOp);
        }
 
-mDNSexport mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *n)
+mDNSexport mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *const n)
        {
        LogInfo("LNT_MapPort");
        if (n->tcpInfo.sock) return(mStatus_NoError);   // If we already have a connection up don't make another request for the same thing
@@ -892,7 +684,7 @@ mDNSexport mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *n)
        return SendPortMapRequest(m, n);
        }
 
-mDNSexport mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *n)
+mDNSexport mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *const n)
        {
        char        externalPort[10];
        Property    propArgs[3];
@@ -957,12 +749,12 @@ mDNSlocal mStatus GetDeviceDescription(mDNS *m, tcpLNTInfo *info)
 
        if (!mDNSIPPortIsZero(m->UPnPSOAPPort)) return mStatus_NoError; // already have the info we need
        
-       if (m->UPnPRouterURL == mDNSNULL || m->UPnPRouterAddressString == mDNSNULL)     { LogInfo("GetDeviceDescription: no router URL or address string!"); return (mStatus_Invalid); }
+       if (m->UPnPRouterURL == mDNSNULL || m->UPnPRouterAddressString == mDNSNULL) { LogInfo("GetDeviceDescription: no router URL or address string!"); return (mStatus_Invalid); }
 
        // build message
-       if      (info->Request != mDNSNULL)  mDNSPlatformMemZero(info->Request, LNT_MAXBUFSIZE); // reuse previously allocated buffer
-       else if ((info->Request = (mDNSs8 *) mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate send buffer for discovery"); return (mStatus_NoMemoryErr); }
-       info->requestLen = mDNS_snprintf((char *)info->Request, LNT_MAXBUFSIZE, szSSDPMsgDescribeDeviceFMT, m->UPnPRouterURL, m->UPnPRouterAddressString);
+       if      (info->Request != mDNSNULL) mDNSPlatformMemZero(info->Request, LNT_MAXBUFSIZE); // reuse previously allocated buffer
+       else if ((info->Request = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate send buffer for discovery"); return (mStatus_NoMemoryErr); }
+       info->requestLen = mDNS_snprintf((char*)info->Request, LNT_MAXBUFSIZE, szSSDPMsgDescribeDeviceFMT, m->UPnPRouterURL, m->UPnPRouterAddressString);
        LogInfo("Describe Device: [%s]", info->Request);
        return MakeTCPConnection(m, info, &m->Router, m->UPnPRouterPort, LNTDiscoveryOp);
        }
@@ -970,11 +762,11 @@ mDNSlocal mStatus GetDeviceDescription(mDNS *m, tcpLNTInfo *info)
 // This function parses the response to our SSDP discovery message. Basically, we look to make sure this is a response
 // referencing a service we care about (WANIPConnection or WANPPPConnection), then look for the "Location:" header and copy the addressing and
 // URL info we need.
-mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, mDNSu8 *data, mDNSu16 len)
+mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, const mDNSu8 *const data, const mDNSu16 len)
        {
-       char *ptr = (char *)data;
-       char *end = (char *)data + len;
-       char *stop = ptr;
+       const mDNSu8 *ptr = data;
+       const mDNSu8 *end = data + len;
+       const mDNSu8 *stop = ptr;
        
        if (!mDNSIPPortIsZero(m->UPnPRouterPort)) return; // already have the info we need
 
@@ -984,25 +776,25 @@ mDNSexport void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID Interface
        // figure out if this is a message from a service we care about
        while (ptr && ptr != end)
                {
-               if (*ptr == 'W' && (strncasecmp(ptr, "WANIPConnection:1", 17) == 0)) break;
+               if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANIPConnection:1", 17) == 0)) break;
                ptr++;
                }
        if (ptr == end)
                {
-               ptr = (char *)data;
+               ptr = data;
                while (ptr && ptr != end)
                        {
-                       if (*ptr == 'W' && (strncasecmp(ptr, "WANPPPConnection:1", 18) == 0)) break;
+                       if ((*ptr & 0xDF) == 'W' && (strncasecmp((char*)ptr, "WANPPPConnection:1", 18) == 0)) break;
                        ptr++;
                        }
                }
        if (ptr == mDNSNULL || ptr == end) return;      // not a message we care about
 
        // find "Location:", starting from the beginning
-       ptr = (char *)data;
+       ptr = data;
        while (ptr && ptr != end)
                {
-               if ((*ptr & 0xDF) == 'L' && (strncasecmp(ptr, "Location:", 9) == 0)) break;                     // find the first 'L'; is this Location? if not, keep looking
+               if ((*ptr & 0xDF) == 'L' && (strncasecmp((char*)ptr, "Location:", 9) == 0)) break;                      // find the first 'L'; is this Location? if not, keep looking
                ptr++;
                }
        if (ptr == mDNSNULL || ptr == end) 
@@ -1076,7 +868,7 @@ mDNSexport void LNT_SendDiscoveryMsg(mDNS *m)
                "MX:3\r\n\r\n";
        static const mDNSAddr multicastDest = { mDNSAddrType_IPv4, { { { 239, 255, 255, 250 } } } };
        
-       mDNSu8buf = (mDNSu8*)&m->omsg; //m->omsg is 8952 bytes, which is plenty
+       mDNSu8 *buf = (mDNSu8*)&m->omsg; //m->omsg is 8952 bytes, which is plenty
        unsigned int bufLen;
        
        if (!mDNSIPPortIsZero(m->UPnPRouterPort))
index af22edf3e1c9e878a419b3b71cc4704b4578beb6..d5b2d1a10b5eddce920ee2e4e3325d09ba2743fa 100644 (file)
     OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
     (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
     ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-    Change History (most recent first):
-
-$Log: ConfigurationAuthority.c,v $
-Revision 1.3  2008/06/26 17:34:18  mkrochma
-<rdar://problem/6030630> Pref pane destroying shared "system.preferences" authorization right
-
-Revision 1.2  2005/08/07 22:48:05  mkrochma
-<rdar://problem/4204003> Bonjour Pref Pane returns -927 when "system.preferences" is not shared
-
-Revision 1.1  2005/02/05 02:28:22  cheshire
-Add Preference Pane to facilitate testing of DDNS & wide-area features
-
-*/
+ */
 
 #include "ConfigurationAuthority.h"
 #include "ConfigurationRights.h"
@@ -119,7 +106,7 @@ OSStatus InitConfigAuthority(void)
        require_noerr( err, NewAuthFailed);
 
        err = AuthorizationRightGet( UPDATE_SC_RIGHT, (CFDictionaryRef*) NULL);
-       iferr == errAuthorizationDenied)
+       if (err == errAuthorizationDenied)
        {
                rightInfo = CFCopyLocalizedString(CFSTR("Authentication required to set Dynamic DNS preferences."), 
                                                CFSTR("Describes operation that requires user authorization"));
@@ -135,7 +122,7 @@ OSStatus InitConfigAuthority(void)
        require_noerr( err, AuthSetFailed);
 
        err = AuthorizationRightGet( EDIT_SYS_KEYCHAIN_RIGHT, (CFDictionaryRef*) NULL);
-       iferr == errAuthorizationDenied)
+       if (err == errAuthorizationDenied)
        {
                rightInfo = CFCopyLocalizedString( CFSTR("Authentication required to edit System Keychain."), 
                                                CFSTR("Describes operation that requires user authorization"));
index 5a1a720b52097e3ddba517def7e3ed300ef4300f..3b033bbb6d120347997bacff6c661fc5aa547ac8 100644 (file)
     OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
     (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
     ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-    Change History (most recent first):
-
-$Log: ConfigurationAuthority.h,v $
-Revision 1.1  2005/02/05 02:32:30  cheshire
-Add Preference Pane to facilitate testing of DDNS & wide-area features
-
-*/
+ */
 
 #include <CoreServices/CoreServices.h>
 #include <Security/Security.h>
index 9e59fa50d5b16738bc6af80123851e46af16bc35..a16cbbbe98327c1777ca07564eefc5c240661310 100644 (file)
     OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
     (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
     ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-    Change History (most recent first):
-
-$Log: ConfigurationRights.h,v $
-Revision 1.2  2006/08/14 23:15:47  cheshire
-Tidy up Change History comment
-
-Revision 1.1  2005/02/05 01:59:19  cheshire
-Add Preference Pane to facilitate testing of DDNS & wide-area features
-
-*/
+ */
 
 #define        UPDATE_SC_RIGHT          "system.preferences"
 #define        EDIT_SYS_KEYCHAIN_RIGHT  "system.preferences"
index cf69c9c2e19a7c329725b5928e5318e72363ee90..212e711df24fc5c0af15b4402596c7938b508004 100644 (file)
     OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
     (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
     ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-    Change History (most recent first):
-
-$Log: DNSServiceDiscoveryPref.h,v $
-Revision 1.6  2006/08/14 23:15:47  cheshire
-Tidy up Change History comment
-
-Revision 1.5  2005/02/26 00:44:24  cheshire
-Restore default reg domain if user deletes text and clicks "apply"
-
-Revision 1.4  2005/02/25 02:29:28  cheshire
-Show yellow dot for "update in progress"
-
-Revision 1.3  2005/02/10 22:35:19  cheshire
-<rdar://problem/3727944> Update name
-
-Revision 1.2  2005/02/08 01:32:05  cheshire
-Add trimCharactersFromDomain routine to strip leading and trailing
-white space and punctuation from user-entered fields.
-
-Revision 1.1  2005/02/05 01:59:19  cheshire
-Add Preference Pane to facilitate testing of DDNS & wide-area features
-
-*/
+ */
 
 #import <Cocoa/Cocoa.h>
 #import <PreferencePanes/PreferencePanes.h>
index 1c481dc57ccc6fb674d53b7f26f69996caee644c..c1d16b114a9cbd4a0b8bdaff4c35bec88a2f0cdf 100644 (file)
     OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
     (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
     ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-    Change History (most recent first):
-
-$Log: DNSServiceDiscoveryPref.m,v $
-Revision 1.16  2008/09/15 23:52:30  cheshire
-<rdar://problem/6218902> mDNSResponder-177 fails to compile on Linux with .desc pseudo-op
-Made __crashreporter_info__ symbol conditional, so we only use it for OS X build
-
-Revision 1.15  2008/08/18 17:57:04  mcguire
-<rdar://problem/6156209> build error
-
-Revision 1.14  2008/07/18 17:39:14  cheshire
-If NSInteger is not defined (indicated by lack of definition for NSINTEGER_DEFINED)
-then #define "NSInteger" to be "int" like it used to be
-
-Revision 1.13  2008/07/01 01:40:01  mcguire
-<rdar://problem/5823010> 64-bit fixes
-
-Revision 1.12  2008/05/08 00:46:38  cheshire
-<rdar://problem/5919272> GetNextLabel insufficiently defensive
-User shared copy of GetNextLabel in ClientCommon.c instead of having a local copy here
-
-Revision 1.11  2007/11/30 23:42:09  cheshire
-Fixed compile warning: declaration of 'index' shadows a global declaration
-
-Revision 1.10  2007/09/18 19:09:02  cheshire
-<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
-
-Revision 1.9  2007/02/09 00:39:06  cheshire
-Fix compile warnings
-
-Revision 1.8  2006/08/14 23:15:47  cheshire
-Tidy up Change History comment
-
-Revision 1.7  2006/07/14 03:59:14  cheshire
-Fix compile warnings: 'sortUsingFunction:context:' comparison function needs to return int
-
-Revision 1.6  2005/02/26 00:44:24  cheshire
-Restore default reg domain if user deletes text and clicks "apply"
-
-Revision 1.5  2005/02/25 02:29:28  cheshire
-Show yellow dot for "update in progress"
-
-Revision 1.4  2005/02/16 00:18:33  cheshire
-Bunch o' fixes
-
-Revision 1.3  2005/02/10 22:35:20  cheshire
-<rdar://problem/3727944> Update name
-
-Revision 1.2  2005/02/08 01:32:05  cheshire
-Add trimCharactersFromDomain routine to strip leading and trailing
-white space and punctuation from user-entered fields.
-
-Revision 1.1  2005/02/05 01:59:19  cheshire
-Add Preference Pane to facilitate testing of DDNS & wide-area features
-
-*/
+ */
 
 #import "DNSServiceDiscoveryPref.h"
 #import "ConfigurationAuthority.h"
index 5be57927106477af2a26fac372aa980c4b161012..49d35b93701e8707fdcb9537c4deb4583bde99f3 100644 (file)
     OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
     (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
     ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-    Change History (most recent first):
-
-$Log: PrivilegedOperations.c,v $
-Revision 1.9  2008/06/26 17:34:18  mkrochma
-<rdar://problem/6030630> Pref pane destroying shared "system.preferences" authorization right
-
-Revision 1.8  2007/11/30 23:42:33  cheshire
-Fixed compile warning: declaration of 'status' shadows a previous local
-
-Revision 1.7  2007/02/09 00:39:06  cheshire
-Fix compile warnings
-
-Revision 1.6  2006/08/14 23:15:47  cheshire
-Tidy up Change History comment
-
-Revision 1.5  2006/06/10 02:07:11  mkrochma
-Whoa.  Make sure code compiles before checking it in.
-
-Revision 1.4  2006/05/27 02:32:38  mkrochma
-Wait for installer script to exit before returning result
-
-Revision 1.3  2005/06/04 04:50:00  cheshire
-<rdar://problem/4138070> ddnswriteconfig (Bonjour PreferencePane) vulnerability
-Use installtool instead of requiring ddnswriteconfig to self-install
-
-Revision 1.2  2005/02/10 22:35:20  cheshire
-<rdar://problem/3727944> Update name
-
-Revision 1.1  2005/02/05 01:59:19  cheshire
-Add Preference Pane to facilitate testing of DDNS & wide-area features
-
-*/
+ */
 
 #include "PrivilegedOperations.h"
 #include "ConfigurationAuthority.h"
index e76cb6895e5f1c5bd0d52701ff312fa9d8afde4e..4f9514a40d1194e794bad0c607c76a117b958c9a 100644 (file)
     OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
     (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
     ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-    Change History (most recent first):
-
-$Log: PrivilegedOperations.h,v $
-Revision 1.5  2006/08/14 23:15:47  cheshire
-Tidy up Change History comment
-
-Revision 1.4  2005/06/04 04:50:00  cheshire
-<rdar://problem/4138070> ddnswriteconfig (Bonjour PreferencePane) vulnerability
-Use installtool instead of requiring ddnswriteconfig to self-install
-
-Revision 1.3  2005/02/16 00:17:35  cheshire
-Don't create empty arrays -- CFArrayGetValueAtIndex(array,0) returns an essentially random (non-null)
-result for empty arrays, which can lead to code crashing if it's not sufficiently defensive.
-
-Revision 1.2  2005/02/10 22:35:20  cheshire
-<rdar://problem/3727944> Update name
-
-Revision 1.1  2005/02/05 01:59:19  cheshire
-Add Preference Pane to facilitate testing of DDNS & wide-area features
-
-*/
+ */
 
 #include <CoreServices/CoreServices.h>
 #include <CoreFoundation/CoreFoundation.h>
 
-#define        PRIV_OP_TOOL_VERS       3
+#define        PRIV_OP_TOOL_VERS       4
 
 #define        kToolName      "ddnswriteconfig"
 #define        kToolPath      "/Library/Application Support/Bonjour/" kToolName
index 441741893cf93ddf424097762dde168097f662a7..437879bca18f17a98ceea33f92ba03f1353d2ab4 100644 (file)
     OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
     (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
     ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-    Change History (most recent first):
-
-$Log: ddnswriteconfig.m,v $
-Revision 1.13  2008/11/04 20:08:44  cheshire
-Use constant kDNSServiceMaxDomainName instead of literal value "1005"
-
-Revision 1.12  2008/09/15 23:52:30  cheshire
-<rdar://problem/6218902> mDNSResponder-177 fails to compile on Linux with .desc pseudo-op
-Made __crashreporter_info__ symbol conditional, so we only use it for OS X build
-
-Revision 1.11  2008/06/26 17:34:18  mkrochma
-<rdar://problem/6030630> Pref pane destroying shared "system.preferences" authorization right
-
-Revision 1.10  2007/11/30 23:43:04  cheshire
-Fixed compile warning: declaration of 'access' shadows a global declaration
-
-Revision 1.9  2007/09/18 19:09:02  cheshire
-<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
-
-Revision 1.8  2007/07/20 23:41:03  mkrochma
-<rdar://problem/5348663> null deref in ddnswriteconfig
-
-Revision 1.7  2007/03/07 00:49:00  cheshire
-<rdar://problem/4618207> Security: ddnswriteconfig does not verify that authorization blob is of correct size
-
-Revision 1.6  2007/02/09 00:39:06  cheshire
-Fix compile warnings
-
-Revision 1.5  2006/08/14 23:15:47  cheshire
-Tidy up Change History comment
-
-Revision 1.4  2005/06/04 04:47:47  cheshire
-<rdar://problem/4138070> ddnswriteconfig (Bonjour PreferencePane) vulnerability
-Remove self-installing capability of ddnswriteconfig
-
-Revision 1.3  2005/02/16 00:17:35  cheshire
-Don't create empty arrays -- CFArrayGetValueAtIndex(array,0) returns an essentially random (non-null)
-result for empty arrays, which can lead to code crashing if it's not sufficiently defensive.
-
-Revision 1.2  2005/02/10 22:35:20  cheshire
-<rdar://problem/3727944> Update name
-
-Revision 1.1  2005/02/05 01:59:19  cheshire
-Add Preference Pane to facilitate testing of DDNS & wide-area features
-
-*/
+ */
 
 
 #import "PrivilegedOperations.h"
@@ -171,8 +125,8 @@ static int
 readTaggedBlock(int fd, u_int32_t *pTag, u_int32_t *pLen, char **ppBuff)
 // Read tag, block len and block data from stream and return. Dealloc *ppBuff via free().
 {
-       ssize_t         num, len;
-       u_int32_t       tag;
+       ssize_t         num;
+       u_int32_t       tag, len;               // Don't use ssize_t because that's different on 32- vs. 64-bit
        int                     result = 0;
 
        num = read(fd, &tag, sizeof tag);
@@ -184,7 +138,7 @@ readTaggedBlock(int fd, u_int32_t *pTag, u_int32_t *pLen, char **ppBuff)
        require_action(*ppBuff != NULL, AllocFailed, result = -1;);
 
        num = read(fd, *ppBuff, len);
-       if (num == len) {
+       if (num == (ssize_t)len) {
                *pTag = tag;
                *pLen = len;
        } else {
index 6240d338c11752c1152e778f783903a1812f2a2c..ce341c87e9bdd768d33201f8ddf59382f923c235 100755 (executable)
 # OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
 # (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
 # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# 
-# Change History (most recent first):
-# 
-# $Log: installtool,v $
-# Revision 1.3  2006/09/05 20:00:13  cheshire
-# Moved Emacs settings to second line of file
-#
-# Revision 1.2  2006/08/14 23:15:14  cheshire
-# Added "tab-width" emacs header line
-#
-# Revision 1.1  2005/06/04 04:51:48  cheshire
-# <rdar://problem/4138070> ddnswriteconfig (Bonjour PreferencePane) vulnerability
-# Added separate "installtool" script instead of making ddnswriteconfig self-install
 #
 # Create the Bonjour subdirectory.
 # Copy ARGV[0] to $dest and set owner and suid permissions.
index 76ec65a6ef69377cadc1c8f3b66c231cc1c82dc5..e75ce59b70b633400439c0b8c1beee4a28b7f821 100644 (file)
  * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
  * understand why variable y is not of type "char*" just proves the point that poor code
  * layout leads people to unfortunate misunderstandings about how the C language really works.)
-
-       Change History (most recent first):
-
-$Log: SamplemDNSClient.c,v $
-Revision 1.56  2008/10/22 02:59:58  mkrochma
-<rdar://problem/6309616> Fix errors compiling mDNS tool caused by BIND8 removal
-
-Revision 1.55  2008/09/15 23:52:30  cheshire
-<rdar://problem/6218902> mDNSResponder-177 fails to compile on Linux with .desc pseudo-op
-Made __crashreporter_info__ symbol conditional, so we only use it for OS X build
-
-Revision 1.54  2007/11/30 23:39:55  cheshire
-Fixed compile warning: declaration of 'client' shadows a global declaration
-
-Revision 1.53  2007/09/18 19:09:02  cheshire
-<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
-
-Revision 1.52  2007/03/06 22:45:52  cheshire
-
-<rdar://problem/4138615> argv buffer overflow issues
-
-Revision 1.51  2007/02/13 18:56:45  cheshire
-<rdar://problem/4993485> Mach mDNS tool inconsistent with UDS-based dns-sd tool
-(missing domain should mean "system default(s)", not "local")
-
-Revision 1.50  2007/01/05 08:30:47  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.49  2007/01/04 21:54:49  cheshire
-Fix compile warnings related to the deprecated Mach-based API
-
-Revision 1.48  2006/08/14 23:24:39  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.47  2006/01/10 02:29:22  cheshire
-<rdar://problem/4403861> Cosmetic IPv6 address display problem in mDNS test tool
-
-*/
+ */
 
 #include <libc.h>
 #include <arpa/nameser.h>
index 69e23d6b53bcdde49309e06f0dc77ff13d568226..62d2f78372312df194518f0cf56201064cdb81d2 100644 (file)
  * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
  * understand why variable y is not of type "char*" just proves the point that poor code
  * layout leads people to unfortunate misunderstandings about how the C language really works.)
+ */
 
-    Change History (most recent first):
-
-$Log: daemon.c,v $
-Revision 1.434  2009/06/27 00:55:27  cheshire
-Added code for displaying the size of various structures like CacheRecord and CacheGroup
-
-Revision 1.433  2009/06/25 23:36:57  cheshire
-To facilitate testing, added command-line switch "-OfferSleepProxyService"
-to re-enable the previously-supported mode of operation where we offer
-sleep proxy service on desktop Macs that are set to never sleep.
-
-Revision 1.432  2009/05/13 17:25:33  mkrochma
-<rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
-Sleep proxy client should only look for services being advertised via Multicast
-
-Revision 1.431  2009/05/12 23:21:18  cheshire
-<rdar://problem/6879926> Should not schedule maintenance wake when machine has no advertised services
-Use mDNSCoreHaveAdvertisedServices routine to determine whether we should schedule a maintenance wake
-
-Revision 1.430  2009/05/01 19:17:36  cheshire
-<rdar://problem/6501561> Sleep Proxy: Reduce the frequency of maintenance wakes: ODD, fans, power
-
-Revision 1.429  2009/04/30 20:07:50  mcguire
-<rdar://problem/6822674> Support multiple UDSs from launchd
-
-Revision 1.428  2009/04/22 19:43:37  cheshire
-To facilitate debugging, added -DebugLogging and -UnicastPacketLogging switches
-as launch-time alternatives to sending SIGUSR1 and SIGUSR2 signals later
-
-Revision 1.427  2009/04/22 01:19:57  jessic2
-<rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32
-
-Revision 1.426  2009/04/20 19:25:26  cheshire
-For readability, changed "nomulticastadvertisements" to "NoMulticastAdvertisements"
-
-Revision 1.425  2009/04/20 19:17:19  cheshire
-Added a comment explaining why we don't need our CatchABRT handler on 10.5 and later
-
-Revision 1.424  2009/04/17 19:10:27  mcguire
-<rdar://problem/6802833> May still ping-pong with kernel when a framework calls abort()
-
-Revision 1.423  2009/04/16 16:03:08  mcguire
-<rdar://problem/6792024> abort() causes high CPU usage instead of crash & restart
-
-Revision 1.422  2009/04/11 01:43:28  jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.421  2009/04/11 00:20:06  jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.420  2009/03/20 23:53:03  jessic2
-<rdar://problem/6646228> SIGHUP should restart all in-progress queries
-
-Revision 1.419  2009/03/20 21:30:04  cheshire
-<rdar://problem/6705866> Crash passing invalid parameters to DNSServiceBrowserCreate()
-Do not append a new question to the browser list until *after* we verify that mDNS_StartBrowse() succeeded
-
-Revision 1.418  2009/03/17 21:32:15  cheshire
-Improved "DHCPWakeTime: SCDynamicStoreCopyDHCPInfo failed" error message
-
-Revision 1.417  2009/03/17 01:25:39  cheshire
-<rdar://problem/6601427> Sleep Proxy: Retransmit and retry Sleep Proxy Server requests
-In SIGINFO output, show three best Sleep Proxies
-
-Revision 1.416  2009/02/21 01:47:36  cheshire
-<rdar://problem/6600825> Race condition when sleep initiated and then immediately canceled
-
-Revision 1.415  2009/02/21 01:45:33  cheshire
-Move declaration of "mDNSs32 interval"
-
-Revision 1.414  2009/02/14 00:05:32  cheshire
-Left-justify interface names
-
-Revision 1.413  2009/02/13 18:16:05  cheshire
-Fixed some compile warnings
-
-Revision 1.412  2009/02/13 06:34:41  cheshire
-Converted LogOperation messages to LogInfo or LogSPS
-
-Revision 1.411  2009/02/12 20:57:26  cheshire
-Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
-
-Revision 1.410  2009/02/11 02:32:18  cheshire
-m->p->SystemWakeForNetworkAccessEnabled renamed to m->SystemWakeOnLANEnabled
-
-Revision 1.409  2009/02/09 21:16:14  cheshire
-Improved debugging messages
-
-Revision 1.408  2009/02/07 06:08:44  cheshire
-Commented out testing code
-
-Revision 1.407  2009/02/07 02:57:31  cheshire
-<rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
-
-Revision 1.406  2009/02/06 03:06:49  mcguire
-<rdar://problem/5858533> Adopt vproc_transaction API in mDNSResponder
-
-Revision 1.405  2009/02/04 23:00:28  cheshire
-Move logic for deciding when to next wake up into a subroutine called AllowSleepNow
-
-Revision 1.404  2009/02/02 22:18:32  cheshire
-If we wake up and find no wireless network, don't just give up and go back to sleep and never try again
-
-Revision 1.403  2009/01/15 21:58:18  cheshire
-Stop using ifa_name field of NetworkInterfaceInfoOSX structure, because it will be going away
-
-Revision 1.402  2009/01/07 23:08:18  cheshire
-Updated debugging messages and comments
-
-Revision 1.401  2008/12/17 05:05:26  cheshire
-Fixed alignment of NAT mapping syslog messages
-
-Revision 1.400  2008/12/10 19:30:57  cheshire
-Use symbolic name OSXVers_10_3_Panther in version check instead of literal integer "7"
-
-Revision 1.399  2008/12/10 02:13:04  cheshire
-Fix alignment of SIGINFO output for longer interface names like "bridge0"
-
-Revision 1.398  2008/12/04 21:08:51  mcguire
-<rdar://problem/6116863> mDNS: Provide mechanism to disable Multicast advertisements
-
-Revision 1.397  2008/12/04 02:18:50  cheshire
-Improved sleep/wake debugging messages
-
-Revision 1.396  2008/11/26 23:37:44  cheshire
-Use SCDynamicStoreCopyDHCPInfo to compute desired wakeup time for our next DHCP lease renewal
-
-Revision 1.395  2008/11/14 21:56:31  cheshire
-Moved debugging routine ShowTaskSchedulingError() from daemon.c into DNSCommon.c
-
-Revision 1.394  2008/11/14 02:20:03  cheshire
-Include m->NextScheduledSPS in task scheduling calculations
-
-Revision 1.393  2008/11/14 01:22:38  cheshire
-Include SPS-registered records when computing the next required wakeup time
-
-Revision 1.392  2008/11/11 01:55:16  cheshire
-Improved comments; minium requested sleep is 60 seconds
-
-Revision 1.391  2008/11/04 02:29:55  cheshire
-Clear interface list before sleeping
-
-Revision 1.390  2008/11/02 21:22:05  cheshire
-Changed mallocL size parameter back to "unsigned int"
-
-Revision 1.389  2008/11/02 21:14:58  cheshire
-Fixes to make mallocL/freeL debugging checks work on 64-bit
-
-Revision 1.388  2008/10/31 23:05:30  cheshire
-Move logic to decide when to at as Sleep Proxy Server from daemon.c to mDNSMacOSX.c
-
-Revision 1.387  2008/10/30 01:08:18  cheshire
-After waking for network maintenance operations go back to sleep again
-
-Revision 1.386  2008/10/29 22:03:39  cheshire
-Compute correct required wakeup time for NAT traversals and uDNS-registered records
-
-Revision 1.385  2008/10/28 20:40:13  cheshire
-Now that the BPF code in mDNSMacOSX.c makes its own CFSocketCreateWithNative directly, the
-udsSupportAddFDToEventLoop/udsSupportRemoveFDFromEventLoop routines can go back to using kqueue
-
-Revision 1.384  2008/10/27 22:22:59  cheshire
-Extra sanity checking in udsSupportAddFDToEventLoop/udsSupportRemoveFDFromEventLoop
-
-Revision 1.383  2008/10/27 07:24:53  cheshire
-Need a "usleep(1000)" (workaround for <rdar://problem/3585273>) to avoid crashes
-
-Revision 1.382  2008/10/24 01:51:48  cheshire
-Before going to sleep, request a future wakeup to renew NAT-PMP mappings, SPS registrations, etc.
-
-Revision 1.381  2008/10/23 22:25:58  cheshire
-Renamed field "id" to more descriptive "updateid"
-
-Revision 1.380  2008/10/23 02:25:08  cheshire
-Added locking in InternetSharingChanged()
-
-Revision 1.379  2008/10/22 23:23:59  cheshire
-Moved definition of OSXVers from daemon.c into mDNSMacOSX.c
-
-Revision 1.378  2008/10/22 19:55:35  cheshire
-Miscellaneous fixes; renamed FindFirstAnswerInCache to FindSPSInCache
-
-Revision 1.377  2008/10/22 17:17:22  cheshire
-Need to open and close BPF fds when turning Sleep Proxy Server on and off
-
-Revision 1.376  2008/10/22 01:42:39  cheshire
-Before allowing sleep, delay until NetWakeResolve queries have completed
-
-Revision 1.375  2008/10/20 22:31:31  cheshire
-Instead of requesting a single BPF descriptor via mDNSRequestBPF(), call mDNSMacOSXNetworkChanged()
-to signal that UDS is now available to handle BPF requests, and let it work out what it needs
-
-Revision 1.374  2008/10/16 22:40:48  cheshire
-Removed "usleep(100000);" from CFSCallBack()
-
-Revision 1.373  2008/10/16 20:49:30  cheshire
-When kevent/kqueue fails, fall back to using old CFSocket RunLoopSource instead
-
-Revision 1.372  2008/10/15 00:03:21  cheshire
-When finally going to sleep, update m->SleepState from SleepState_Transferring to SleepState_Sleeping
-
-Revision 1.371  2008/10/14 19:09:53  cheshire
-When going to sleep, delay sleep until we've got our acknowledgment from the SPS
-
-Revision 1.370  2008/10/09 22:32:27  cheshire
-Include MAC address in interface listing in SIGINFO output
-
-Revision 1.369  2008/10/09 19:32:39  cheshire
-Updated SIGINFO output to indicate whether we've found a sleep proxy server on a given interface
-Hollow sun with rays "☼" indicates we're still looking; solid sun with rays "☀" indicates we found one
-
-Revision 1.368  2008/10/03 21:23:17  mkrochma
-Fix crash by not passing NULL to CFGetTypeID
-
-Revision 1.367  2008/10/03 18:25:17  cheshire
-Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);"
-
-Revision 1.366  2008/10/03 00:34:55  cheshire
-<rdar://problem/6134215> Mac with Internet Sharing should also offer Sleep Proxy service
-Start and stop Sleep Proxy service when user starts and stops Internet Sharing
-
-Revision 1.365  2008/10/02 22:23:13  cheshire
-Additional debugging message giving explanation if shutdown is delayed
-
-Revision 1.364  2008/10/01 21:23:40  cheshire
-In SIGINFO interface listing, indicate whether NetWake is set
-
-Revision 1.363  2008/09/27 01:29:15  cheshire
-Call mDNSRequestBPF() to request the helper to send us the BPF fd
-
-Revision 1.362  2008/09/26 19:47:42  cheshire
-Fixed locking error: lock is supposed to be held when calling mDNS_PurgeCacheResourceRecord
-
-Revision 1.361  2008/09/15 23:52:30  cheshire
-<rdar://problem/6218902> mDNSResponder-177 fails to compile on Linux with .desc pseudo-op
-Made __crashreporter_info__ symbol conditional, so we only use it for OS X build
-
-Revision 1.360  2008/03/13 20:55:16  mcguire
-<rdar://problem/5769316> fix deprecated warnings/errors
-Additional cleanup: use a conditional macro instead of lots of #if
-
-Revision 1.359  2008/03/12 23:02:58  mcguire
-<rdar://problem/5769316> fix deprecated warnings/errors
-
-Revision 1.358  2008/03/06 21:26:11  cheshire
-Moved duplicated STRINGIFY macro from individual C files to DNSCommon.h
-
-Revision 1.357  2008/02/13 17:40:43  cheshire
-<rdar://problem/5740501> Investigate mysterious SIGABRTs in mDNSResponder
-
-Revision 1.356  2007/12/18 00:28:56  cheshire
-<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
-Error in ReadyForSleep() logic -- missing "not" in "!mDNSOpaque16IsZero(q->TargetQID)"
-
-Revision 1.355  2007/12/17 22:29:22  cheshire
-<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
-Log message indicating when we make IOAllowPowerChange call; make sure nextTimerEvent is set appropriately
-
-Revision 1.354  2007/12/15 01:12:28  cheshire
-<rdar://problem/5526796> Need to remove active LLQs from server upon question cancellation, on sleep, and on shutdown
-
-Revision 1.353  2007/12/14 19:14:02  cheshire
-Added (commented out) code for testing sleep/wake
-
-Revision 1.352  2007/12/14 00:58:29  cheshire
-<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
-Additional fixes: When going to sleep, mDNSResponder needs to postpone sleep
-until TLS/TCP deregistrations have completed (up to five seconds maximum)
-
-Revision 1.351  2007/12/12 21:34:18  cheshire
-Now that <rdar://problem/5124399> "Not getting Keychain events" is apparently fixed,
-it makes sense to reduce our workaround retry count from 5 to 2 retries. Once we've
-confirmed that the bug is definitely fixed we'll remove the workaround altogether.
-
-Revision 1.350  2007/12/07 00:45:58  cheshire
-<rdar://problem/5526800> BTMM: Need to clean up registrations on shutdown
-
-Revision 1.349  2007/12/04 22:00:54  cheshire
-Fixed mistake in comment
-
-Revision 1.348  2007/12/01 00:27:43  cheshire
-Fixed compile warning: declaration of 'r' shadows a previous local
-
-Revision 1.347  2007/11/02 22:00:13  cheshire
-<rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
-Need to hold the lock while calling SetDomainSecrets
-
-Revision 1.346  2007/11/02 20:18:13  cheshire
-<rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
-
-Revision 1.345  2007/10/17 18:41:21  cheshire
-For debugging, make SIGUSR1 simulate a KeychainChanged event as well as a NetworkChanged
-
-Revision 1.344  2007/09/29 01:06:17  mcguire
-<rdar://problem/5507862> 9A564: mDNSResponder crash in mDNS_Execute
-
-Revision 1.343  2007/09/24 05:02:41  cheshire
-Debugging: In SIGINFO output, indicate explicitly when a given section is empty
-
-Revision 1.342  2007/09/18 19:09:02  cheshire
-<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
-
-Revision 1.341  2007/09/12 01:22:13  cheshire
-Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
-
-Revision 1.340  2007/09/07 22:44:03  mcguire
-<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
-
-Revision 1.339  2007/09/06 19:08:29  cheshire
-LogClientOperations check needs to be "#if LogClientOperations || MDNS_DEBUGMSGS"
-
-Revision 1.338  2007/09/05 23:34:27  mcguire
-Revert logging change
-
-Revision 1.337  2007/09/05 20:45:50  cheshire
-Added list of KQSocketEventSources in SIGINFO output
-
-Revision 1.336  2007/08/31 17:15:37  cheshire
-Reordered startup log messages so that "mDNSResponder ... starting" is the first message
-
-Revision 1.335  2007/08/31 02:00:16  cheshire
-Added comment explaining use of zero-width non-breaking space character to tag literal strings
-
-Revision 1.334  2007/08/24 23:40:24  cheshire
-Added comment about FreeServiceInstance
-
-Revision 1.333  2007/08/23 21:02:35  cheshire
-SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
-
-Revision 1.332  2007/08/22 23:54:54  mcguire
-<rdar://problem/5422558> BTMM: mDNSResponder should be able to run from the cmdline
-
-Revision 1.331  2007/08/18 01:02:03  mcguire
-<rdar://problem/5415593> No Bonjour services are getting registered at boot
-
-Revision 1.330  2007/08/10 22:25:57  mkrochma
-<rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
-
-Revision 1.329  2007/08/08 22:34:58  mcguire
-<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
-
-Revision 1.328  2007/07/27 22:43:37  cheshire
-Improved mallocL/freeL "suspiciously large" debugging messages
-
-Revision 1.327  2007/07/27 19:30:41  cheshire
-Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
-to properly reflect tri-state nature of the possible responses
-
-Revision 1.326  2007/07/24 17:23:33  cheshire
-<rdar://problem/5357133> Add list validation checks for debugging
-
-Revision 1.325  2007/07/11 23:43:43  cheshire
-Rename PurgeCacheResourceRecord to mDNS_PurgeCacheResourceRecord
-
-Revision 1.324  2007/07/11 22:44:40  cheshire
-<rdar://problem/5328801> SIGHUP should purge the cache
-
-Revision 1.323  2007/07/11 03:01:50  cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-
-Revision 1.322  2007/07/06 18:58:16  cheshire
-Check m->NextScheduledNATOp in ShowTaskSchedulingError()
-
-Revision 1.321  2007/07/02 21:54:20  cheshire
-Fix compile error in MACOSX_MDNS_MALLOC_DEBUGGING checks
-
-Revision 1.320  2007/06/28 21:16:27  cheshire
-Rename "m->nextevent" as more informative "m->NextuDNSEvent"
-
-Revision 1.319  2007/06/22 20:47:08  cheshire
-<rdar://problem/5285417> DOS charset changes from CP932 to CP850 after Computer Name conflict
-Made a "SafeSCPreferencesSetComputerName" routine to set the Computer Name without changing the machine's default character set
-
-Revision 1.318  2007/06/20 01:45:40  cheshire
-When showing dormant interfaces, display last-seen IP address for that dormant interface
-
-Revision 1.317  2007/06/20 01:10:12  cheshire
-<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-
-Revision 1.316  2007/06/19 19:27:11  cheshire
-<rdar://problem/5141540> Sandbox mDNSResponder
-Weak-link sandbox_init, so mDNSResponder can be run on Tiger for regression testing
-
-Revision 1.315  2007/06/15 21:54:51  cheshire
-<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
-
-Revision 1.314  2007/06/15 19:23:17  cheshire
-<rdar://problem/5254053> mDNSResponder renames my host without asking
-Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
-
-Revision 1.313  2007/05/25 16:02:05  cheshire
-When MACOSX_MDNS_MALLOC_DEBUGGING is enabled, log suspiciously large memory allocations
-
-Revision 1.312  2007/05/22 19:07:21  cheshire
-Add comment explaining RR_CACHE_SIZE calculation
-
-Revision 1.311  2007/05/15 21:47:21  cheshire
-Get rid of "#pragma unused(m)"
-
-Revision 1.310  2007/05/08 00:56:17  cheshire
-<rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
-
-Revision 1.309  2007/04/30 21:33:38  cheshire
-Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
-is iterating through the m->ServiceRegistrations list
-
-Revision 1.308  2007/04/28 01:31:59  cheshire
-Improve debugging support for catching memory corruption problems
-
-Revision 1.307  2007/04/24 18:32:00  cheshire
-Grab a copy of KQtask string pointer in case KQcallback deletes the task
-
-Revision 1.306  2007/04/22 19:11:51  cheshire
-Some quirk of RemoveFromList (GenLinkedList.c) was corrupting the list and causing a crash
-if the element being removed was not the last in the list. Fixed by removing GenLinkedList.c
-from the project and just using simple vanilla C linked-list manipulation instead.
-
-Revision 1.305  2007/04/22 06:02:03  cheshire
-<rdar://problem/4615977> Query should immediately return failure when no server
-
-Revision 1.304  2007/04/21 21:47:47  cheshire
-<rdar://problem/4376383> Daemon: Add watchdog timer
-
-Revision 1.303  2007/04/18 00:50:47  cheshire
-<rdar://problem/5141540> Sandbox mDNSResponder
-
-Revision 1.302  2007/04/07 01:01:48  cheshire
-<rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
-
-Revision 1.301  2007/04/05 19:13:48  cheshire
-Use better name in SCPreferencesCreate
-
-Revision 1.300  2007/04/04 21:22:18  cheshire
-Suppress "Local Hostname changed" syslog message when name has not actually changed
-
-Revision 1.299  2007/04/03 19:19:33  cheshire
-Use mDNSIPPortIsZero() instead of peeking into 'NotAnInteger' field
-
-Revision 1.298  2007/03/30 21:51:45  cheshire
-Minor code tidying
-
-Revision 1.297  2007/03/27 22:47:19  cheshire
-On memory corruption, if ForceAlerts is set, force a crash to get a stack trace
-
-Revision 1.296  2007/03/24 01:23:29  cheshire
-Call validator for uDNS data structures
-
-Revision 1.295  2007/03/20 23:32:49  cheshire
-Minor textual tidying
-
-Revision 1.294  2007/03/07 02:50:50  cheshire
-<rdar://problem/4574528> Name conflict dialog doesn't appear if Bonjour is persistantly unable to find an available hostname
-
-Revision 1.293  2007/03/06 22:59:01  cheshire
-<rdar://problem/4157921> Security: Null dereference possible in daemon.c
-
-Revision 1.292  2007/02/28 21:55:10  cheshire
-<rdar://problem/3862944> UI: Name conflict notifications should be localized
-Additional fix: We were not getting our NotificationCallBackDismissed messages
-because we were scheduling our CFUserNotification RunLoopSource on the wrong runloop.
-(We were incorrectly assuming CFRunLoopGetCurrent() would be the right runloop.)
-
-Revision 1.291  2007/02/28 03:51:24  cheshire
-<rdar://problem/3862944> UI: Name conflict notifications should be localized
-Moved curly quotes out of the literal text and into the localized text, so they
-can be replaced with alternate characters as appropriate for other languages.
-
-Revision 1.290  2007/02/14 01:58:19  cheshire
-<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
-
-Revision 1.289  2007/02/07 19:32:00  cheshire
-<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
-
-Revision 1.288  2007/02/07 01:01:24  cheshire
-<rdar://problem/3956518> Need to go native with launchd
-Additional refinements -- was unnecessarily calling launch_data_free()
-
-Revision 1.287  2007/02/06 19:06:48  cheshire
-<rdar://problem/3956518> Need to go native with launchd
-
-Revision 1.286  2007/01/06 01:00:33  cheshire
-Improved SIGINFO output
-
-Revision 1.285  2007/01/05 08:30:47  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.284  2007/01/05 05:44:35  cheshire
-Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
-so that mDNSPosix embedded clients will compile again
-
-Revision 1.283  2007/01/04 23:11:14  cheshire
-<rdar://problem/4720673> uDNS: Need to start caching unicast records
-When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
-
-Revision 1.282  2006/12/21 00:09:45  cheshire
-Use mDNSPlatformMemZero instead of bzero
-
-Revision 1.281  2006/11/18 05:01:32  cheshire
-Preliminary support for unifying the uDNS and mDNS code,
-including caching of uDNS answers
-
-Revision 1.280  2006/11/10 00:54:16  cheshire
-<rdar://problem/4816598> Changing case of Computer Name doesn't work
-
-Revision 1.279  2006/11/02 17:44:01  cheshire
-No longer have a separate uDNS ActiveQueries list
-
-Revision 1.278  2006/10/05 04:04:24  herscher
-Remove embedded uDNS_info struct from DNSQuestion_struct
-
-Revision 1.277  2006/09/21 21:01:24  cheshire
-Change 'autorename' to more accurate name 'renameonmemfree'
-
-Revision 1.276  2006/09/17 19:12:02  cheshire
-Further changes for removal of uDNS_info substructure from mDNS_struct
-
-Revision 1.275  2006/09/15 21:20:16  cheshire
-Remove uDNS_info substructure from mDNS_struct
-
-Revision 1.274  2006/08/14 23:24:39  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.273  2006/07/30 05:43:19  cheshire
-<rdar://problem/4049048> Convert mDNSResponder to use kqueue
-Problems using KQueueFD with select() -- for now we'll stick to pure kevent()
-
-Revision 1.272  2006/07/27 03:24:35  cheshire
-<rdar://problem/4049048> Convert mDNSResponder to use kqueue
-Further refinement: Declare KQueueEntry parameter "const"
-
-Revision 1.271  2006/07/27 02:59:26  cheshire
-<rdar://problem/4049048> Convert mDNSResponder to use kqueue
-Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
-after releasing BigMutex, in case actions it took have resulted in new work for the
-kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
-add new active interfaces to its list, and consequently schedule queries to be sent).
-
-Revision 1.270  2006/07/25 17:16:36  mkrochma
-Quick fix to solve kqueue related crashes and hangs
-
-Revision 1.269  2006/07/22 06:11:37  cheshire
-<rdar://problem/4049048> Convert mDNSResponder to use kqueue
-
-Revision 1.268  2006/07/15 02:01:32  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Fix broken "empty string" browsing
-
-Revision 1.267  2006/07/07 01:09:10  cheshire
-<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
-
-Revision 1.266  2006/07/05 23:34:53  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-
-Revision 1.265  2006/06/29 07:32:08  cheshire
-Added missing LogOperation logging for DNSServiceBrowse results
-
-Revision 1.264  2006/06/29 05:33:30  cheshire
-<rdar://problem/4607043> mDNSResponder conditional compilation options
-
-Revision 1.263  2006/06/08 23:23:48  cheshire
-Fix errant indentation of curly brace at the end of provide_DNSServiceBrowserCreate_rpc()
-
-Revision 1.262  2006/03/18 21:49:11  cheshire
-Added comment in ShowTaskSchedulingError(mDNS *const m)
-
-Revision 1.261  2006/01/06 01:22:28  cheshire
-<rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
-
-*/
+// We set VERSION_MIN_REQUIRED to 10.4 to avoid "bootstrap_register is deprecated" warnings from bootstrap.h
+#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_4
 
 #include <mach/mach.h>
 #include <mach/mach_error.h>
 #include <servers/bootstrap.h>
 #include <sys/types.h>
+#include <errno.h>
+#include <signal.h>
 #include <unistd.h>
 #include <paths.h>
 #include <fcntl.h>
@@ -649,8 +83,14 @@ static CacheEntity rrcachestorage[RR_CACHE_SIZE];
 
 static const char kmDNSBootstrapName[] = "com.apple.mDNSResponderRestart";
 static mach_port_t m_port            = MACH_PORT_NULL;
+
+#ifdef __LIB_DISPATCH__
+mDNSlocal void PrepareForIdle(void *m_param);
+#else __LIB_DISPATCH__
 static mach_port_t client_death_port = MACH_PORT_NULL;
 static mach_port_t signal_port       = MACH_PORT_NULL;
+#endif __LIB_DISPATCH__
+
 static mach_port_t server_priv_port  = MACH_PORT_NULL;
 
 static dnssd_sock_t *launchd_fds = mDNSNULL;
@@ -1107,6 +547,8 @@ mDNSlocal mDNSBool CheckForExistingClient(mach_port_t c)
        return(e || b || l || r);
        }
 
+#ifndef __LIB_DISPATCH__
+
 mDNSlocal void ClientDeathCallback(CFMachPortRef unusedport, void *voidmsg, CFIndex size, void *info)
        {
        KQueueLock(&mDNSStorage);
@@ -1125,14 +567,29 @@ mDNSlocal void ClientDeathCallback(CFMachPortRef unusedport, void *voidmsg, CFIn
        KQueueUnlock(&mDNSStorage, "Mach AbortClient");
        }
 
+#endif __LIB_DISPATCH__
+
 mDNSlocal void EnableDeathNotificationForClient(mach_port_t ClientMachPort, void *m)
        {
+#ifdef __LIB_DISPATCH__
+       dispatch_source_t mach_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, ClientMachPort, 0, dispatch_get_main_queue());
+       if (mach_source == mDNSNULL)
+               {
+               AbortClientWithLogMessage(ClientMachPort, "died/deallocated before we could enable death notification", "", m);
+               return;
+               }
+       dispatch_source_set_event_handler(mach_source, ^{
+               mach_port_destroy(mach_task_self(), ClientMachPort);
+               });
+       dispatch_resume(mach_source);
+#else __LIB_DISPATCH__
        mach_port_t prev;
        kern_return_t r = mach_port_request_notification(mach_task_self(), ClientMachPort, MACH_NOTIFY_DEAD_NAME, 0,
                                                                                                         client_death_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev);
        // If the port already died while we were thinking about it, then abort the operation right away
        if (r != KERN_SUCCESS)
                AbortClientWithLogMessage(ClientMachPort, "died/deallocated before we could enable death notification", "", m);
+#endif __LIB_DISPATCH__
        }
 
 //*************************************************************************************************************
@@ -1391,7 +848,7 @@ mDNSlocal void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query)
        kern_return_t status;
        DNSServiceResolver *x = (DNSServiceResolver *)query->ServiceInfoQueryContext;
        NetworkInterfaceInfoOSX *ifx = IfindexToInterfaceInfoOSX(m, query->info->InterfaceID);
-       if (query->info->InterfaceID == mDNSInterface_LocalOnly) ifx = mDNSNULL;
+       if (query->info->InterfaceID == mDNSInterface_LocalOnly || query->info->InterfaceID == mDNSInterface_P2P) ifx = mDNSNULL;
        struct sockaddr_storage interface;
        struct sockaddr_storage address;
        char cstring[1024];
@@ -1789,6 +1246,65 @@ fail:
        return(err);
        }
 
+mDNSlocal void mDNSPreferencesSetNames(mDNS *const m, int key, domainlabel *old, domainlabel *new)
+       {
+       domainlabel *prevold, *prevnew;
+       switch (key)
+               {
+               case kmDNSComputerName:
+               case kmDNSLocalHostName:
+                       if (key == kmDNSComputerName)
+                               {
+                               prevold = &m->p->prevoldnicelabel;
+                               prevnew = &m->p->prevnewnicelabel;
+                               }
+                       else
+                               {
+                               prevold = &m->p->prevoldhostlabel;
+                               prevnew = &m->p->prevnewhostlabel;
+                               }
+                       // There are a few cases where we need to invoke the helper.
+                       //
+                       // 1. If the "old" label and "new" label are not same, it means there is a conflict. We need
+                       //    to invoke the helper so that it pops up a dialogue to inform the user about the
+                       //    conflict
+                       //
+                       // 2. If the "old" label and "new" label are same, it means the user has set the host/nice label
+                       //    through the preferences pane. We may have to inform the helper as it may have popped up
+                       //    a dialogue previously (due to a conflict) and it needs to suppress it now. We can avoid invoking
+                       //    the helper in this case if the previous values (old and new) that we told helper last time
+                       //    are same. If the previous old and new values are same, helper does not care.
+                       //
+                       // Note: "new" can be NULL when we have repeated conflicts and we are asking helper to give up. "old"
+                       // is not called with NULL today, but this makes it future proof.
+                       if (!old || !new || !SameDomainLabelCS(old->c, new->c) || 
+                           !SameDomainLabelCS(old->c, prevold->c) ||
+                           !SameDomainLabelCS(new->c, prevnew->c))
+                               {
+                               if (old)
+                                       *prevold = *old;
+                               else
+                                       prevold->c[0] = 0;
+                               if (new)
+                                       *prevnew = *new;
+                               else
+                                       prevnew->c[0] = 0;
+                               mDNSPreferencesSetName(key, old, new);
+                               }
+                       else 
+                               {
+                               LogInfo("mDNSPreferencesSetNames not invoking helper %s %#s, %s %#s, old %#s, new %#s",
+                                               (key == kmDNSComputerName ? "prevoldnicelabel" : "prevoldhostlabel"), prevold->c,
+                                               (key == kmDNSComputerName ? "prevnewnicelabel" : "prevnewhostlabel"), prevnew->c,
+                                               old->c, new->c);
+                               }
+                       break;
+               default:
+                       LogMsg("mDNSPreferencesSetNames: unrecognized key: %d", key);
+                       return;
+               }
+       }
+
 mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
        {
        (void)m; // Unused
@@ -1806,7 +1322,7 @@ mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
                else if (m->timenow - m->p->HostNameConflict > 60 * mDNSPlatformOneSecond)
                        {
                        // Tell the helper we've given up
-                       mDNSPreferencesSetName(kmDNSLocalHostName, &m->p->userhostlabel, NULL);
+                       mDNSPreferencesSetNames(m, kmDNSLocalHostName, &m->p->userhostlabel, NULL);
                        }
                }
        else if (result == mStatus_GrowCache)
@@ -1819,8 +1335,8 @@ mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
        else if (result == mStatus_ConfigChanged)
                {
                // Tell the helper we've seen a change in the labels.  It will dismiss the name conflict alert if needed.
-               mDNSPreferencesSetName(kmDNSComputerName, &m->p->usernicelabel, &m->nicelabel);
-               mDNSPreferencesSetName(kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel);
+               mDNSPreferencesSetNames(m, kmDNSComputerName, &m->p->usernicelabel, &m->nicelabel);
+               mDNSPreferencesSetNames(m, kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel);
 
                // First we check our list of old Mach-based registered services, to see if any need to be updated to a new name
                DNSServiceRegistration *r;
@@ -1834,8 +1350,8 @@ mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
                                                {
                                                debugf("NetworkChanged renaming %##s to %#s", si->srs.RR_SRV.resrec.name->c, m->nicelabel.c);
                                                si->renameonmemfree = mDNStrue;
-                                               if (mDNS_DeregisterService(m, &si->srs))        // If service deregistered already, we can re-register immediately
-                                                       RegCallback(m, &si->srs, mStatus_MemFree);
+                                               if (mDNS_DeregisterService_drt(m, &si->srs, mDNS_Dereg_rapid))
+                                                       RegCallback(m, &si->srs, mStatus_MemFree);      // If service deregistered already, we can re-register immediately
                                                }
                                        }
                                }
@@ -1904,9 +1420,10 @@ fail:
        return mStatus_UnknownErr;
        }
 
-mDNSlocal void UpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData)
+mDNSlocal void UpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData, mDNSu16 OldRDLen)
        {
        (void)m;                // Unused
+       (void)OldRDLen; // Unused
        if (OldRData != &rr->rdatastorage)
                freeL("Old RData", OldRData);
        }
@@ -2233,6 +1750,8 @@ mDNSlocal void ExitCallback(int sig)
        mDNS_StartExit(&mDNSStorage);
        }
 
+#ifndef __LIB_DISPATCH__
+
 // Send a mach_msg to ourselves (since that is signal safe) telling us to cleanup and exit
 mDNSlocal void HandleSIG(int sig)
        {
@@ -2259,6 +1778,8 @@ mDNSlocal void CatchABRT(int sig)
        while(1) *(long*)0 = 0;
        }
 
+#endif __LIB_DISPATCH__
+
 mDNSlocal void INFOCallback(void)
        {
        mDNSs32 utc = mDNSPlatformUTC();
@@ -2269,7 +1790,7 @@ mDNSlocal void INFOCallback(void)
        NetworkInterfaceInfoOSX     *i;
        DNSServer *s;
 
-       LogMsg("---- BEGIN STATE LOG ----");
+       LogMsg("---- BEGIN STATE LOG ---- %s", mDNSResponderVersionString);
        
        udsserver_info(&mDNSStorage);
 
@@ -2287,6 +1808,7 @@ mDNSlocal void INFOCallback(void)
                        for (qptr = b->qlist; qptr; qptr = qptr->next)
                                LogMsgNoIdent("%5d: Mach ServiceBrowse       %##s", b->ClientMachPort, qptr->q.qname.c);
                        }
+
                for (l = DNSServiceResolverList; l; l=l->next)
                        LogMsgNoIdent("%5d: Mach ServiceResolve      %##s", l->ClientMachPort, l->i.name.c);
        
@@ -2304,7 +1826,10 @@ mDNSlocal void INFOCallback(void)
                {
                KQSocketEventSource *k;
                for (k = gEventSources; k; k=k->next)
+                       {
                        LogMsgNoIdent("%3d %s", k->fd, k->kqs.KQtask);
+                       usleep((mDNSStorage.KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
+                       }
                }
 
        LogMsgNoIdent("------ Network Interfaces ------");
@@ -2315,16 +1840,16 @@ mDNSlocal void INFOCallback(void)
                        {
                        // Allow six characters for interface name, for names like "vmnet8"
                        if (!i->Exists)
-                               LogMsgNoIdent("%p %s %-6s(%lu) %.6a %.6a %#-14a dormant for %d seconds",
-                                       i->ifinfo.InterfaceID,
+                               LogMsgNoIdent("%p (%p), Registered %p,  %s %-6s(%lu) %.6a %.6a %#-14a dormant for %d seconds",
+                                       i->ifinfo.InterfaceID, i, i->Registered,
                                        i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifinfo.ifname, i->scope_id, &i->ifinfo.MAC, &i->BSSID,
                                        &i->ifinfo.ip, utc - i->LastSeen);
                        else
                                {
                                const CacheRecord *sps[3];
                                FindSPSInCache(&mDNSStorage, &i->ifinfo.NetWakeBrowse, sps);
-                               LogMsgNoIdent("%p %s %-6s(%lu) %.6a %.6a %s %s %-15.4a %s %s %s %s %#a",
-                                       i->ifinfo.InterfaceID,
+                               LogMsgNoIdent("%p (%p), Registered %p,  %s %-6s(%lu) %.6a %.6a %s %s %-15.4a %s %s %s %s %#a",
+                                       i->ifinfo.InterfaceID, i, i->Registered,
                                        i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifinfo.ifname, i->scope_id, &i->ifinfo.MAC, &i->BSSID,
                                        i->ifinfo.InterfaceActive ? "Active" : "      ",
                                        i->ifinfo.IPv4Available ? "v4" : "  ",
@@ -2349,9 +1874,9 @@ mDNSlocal void INFOCallback(void)
                for (s = mDNSStorage.DNSServers; s; s = s->next)
                        {
                        NetworkInterfaceInfoOSX *ifx = IfindexToInterfaceInfoOSX(&mDNSStorage, s->interface);
-                       LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %d %s",
+                       LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %d %s %s",
                                s->domain.c, ifx ? ifx->ifinfo.ifname : "", ifx ? " " : "", &s->addr, mDNSVal16(s->port),
-                               s->penaltyTime ? s->penaltyTime - mDNS_TimeNow(&mDNSStorage) : 0,
+                               s->penaltyTime ? s->penaltyTime - mDNS_TimeNow(&mDNSStorage) : 0, s->scoped ? "Scoped" : "",
                                s->teststate == DNSServer_Untested ? "(Untested)" :
                                s->teststate == DNSServer_Passed   ? ""           :
                                s->teststate == DNSServer_Failed   ? "(Failed)"   :
@@ -2362,9 +1887,11 @@ mDNSlocal void INFOCallback(void)
        mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
        LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32)now, now);
 
-       LogMsg("----  END STATE LOG  ----");
+       LogMsg("----  END STATE LOG  ---- %s", mDNSResponderVersionString);
        }
 
+#ifndef __LIB_DISPATCH__
+
 mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
        {
        (void)port;             // Unused
@@ -2405,11 +1932,12 @@ mDNSlocal void SignalCallback(CFMachPortRef port, void *msg, CFIndex size, void
 
 // On 10.2 the MachServerName is DNSServiceDiscoveryServer
 // On 10.3 and later, the MachServerName is com.apple.mDNSResponder
-
 mDNSlocal kern_return_t mDNSDaemonInitialize(void)
        {
        mStatus            err;
        CFMachPortRef      s_port;
+       CFRunLoopSourceRef s_rls;
+       CFRunLoopSourceRef d_rls;
 
        // If launchd already created our Mach port for us, then use that, else we create a new one of our own
        if (m_port != MACH_PORT_NULL)
@@ -2426,16 +1954,12 @@ mDNSlocal kern_return_t mDNSDaemonInitialize(void)
                        if (status == 1103)
                                LogMsg("bootstrap_register() failed: A copy of the daemon is apparently already running");
                        else
-                               LogMsg("bootstrap_register() failed: %s %d", mach_error_string(status), status);
+                               LogMsg("bootstrap_register() failed: %d %X %s", status, status, mach_error_string(status));
                        return(status);
                        }
                }
 
        CFMachPortRef      d_port = CFMachPortCreate(NULL, ClientDeathCallback, NULL, NULL);
-       CFMachPortRef      i_port = CFMachPortCreate(NULL, SignalCallback, NULL, NULL);
-       CFRunLoopSourceRef d_rls  = CFMachPortCreateRunLoopSource(NULL, d_port, 0);
-       CFRunLoopSourceRef s_rls  = CFMachPortCreateRunLoopSource(NULL, s_port, 0);
-       CFRunLoopSourceRef i_rls  = CFMachPortCreateRunLoopSource(NULL, i_port, 0);
 
        err = mDNS_Init(&mDNSStorage, &PlatformStorage,
                rrcachestorage, RR_CACHE_SIZE,
@@ -2445,18 +1969,164 @@ mDNSlocal kern_return_t mDNSDaemonInitialize(void)
        if (err) { LogMsg("Daemon start: mDNS_Init failed %d", err); return(err); }
 
        client_death_port = CFMachPortGetPort(d_port);
-       signal_port       = CFMachPortGetPort(i_port);
 
-       CFRunLoopAddSource(PlatformStorage.CFRunLoop, d_rls, kCFRunLoopDefaultMode);
+       s_rls  = CFMachPortCreateRunLoopSource(NULL, s_port, 0);
        CFRunLoopAddSource(PlatformStorage.CFRunLoop, s_rls, kCFRunLoopDefaultMode);
-       CFRunLoopAddSource(PlatformStorage.CFRunLoop, i_rls, kCFRunLoopDefaultMode);
-       CFRelease(d_rls);
        CFRelease(s_rls);
+
+       d_rls  = CFMachPortCreateRunLoopSource(NULL, d_port, 0);
+       CFRunLoopAddSource(PlatformStorage.CFRunLoop, d_rls, kCFRunLoopDefaultMode);
+       CFRelease(d_rls);
+
+       CFMachPortRef      i_port = CFMachPortCreate(NULL, SignalCallback, NULL, NULL);
+       CFRunLoopSourceRef i_rls  = CFMachPortCreateRunLoopSource(NULL, i_port, 0);
+       signal_port       = CFMachPortGetPort(i_port);
+       CFRunLoopAddSource(PlatformStorage.CFRunLoop, i_rls, kCFRunLoopDefaultMode);
        CFRelease(i_rls);
+
+       if (mDNS_DebugMode) printf("Service registered with Mach Port %d\n", m_port);
+       return(err);
+       }
+
+#else __LIB_DISPATCH__
+
+// SignalDispatch is mostly just a copy/paste of entire code block from SignalCallback above.
+// The common code should be a subroutine, or we end up having to fix bugs in two places all the time.
+// The same applies to mDNSDaemonInitialize, much of which is just a copy/paste of chunks
+// of code from above. Alternatively we could remove the duplicated source code by having
+// single routines, with the few differing parts bracketed with "#ifndef __LIB_DISPATCH__"
+
+mDNSlocal void SignalDispatch(dispatch_source_t source)
+       {
+       int sig = (int)dispatch_source_get_handle(source);
+       mDNS *const m = &mDNSStorage;
+       KQueueLock(m);
+       switch(sig)
+               {
+               case SIGHUP:    {
+                                               mDNSu32 slot;
+                                               CacheGroup *cg;
+                                               CacheRecord *rr;
+                                               LogMsg("SIGHUP: Purge cache");
+                                               mDNS_Lock(m);
+                                               FORALL_CACHERECORDS(slot, cg, rr) mDNS_PurgeCacheResourceRecord(m, rr);
+                                               // Restart unicast and multicast queries
+                                               mDNSCoreRestartQueries(m);
+                                               mDNS_Unlock(m);
+                                               } break;
+               case SIGINT:
+               case SIGTERM:   ExitCallback(sig); break;
+               case SIGINFO:   INFOCallback(); break;
+               case SIGUSR1:   mDNS_LoggingEnabled = mDNS_LoggingEnabled ? 0 : 1;
+                                               LogMsg("SIGUSR1: Logging %s", mDNS_LoggingEnabled ? "Enabled" : "Disabled");
+                                               WatchDogReportingThreshold = mDNS_LoggingEnabled ? 50 : 250;
+                                               break;
+               case SIGUSR2:   mDNS_PacketLoggingEnabled = mDNS_PacketLoggingEnabled ? 0 : 1;
+                                               LogMsg("SIGUSR2: Packet Logging %s", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled");
+                                               break;
+               default: LogMsg("SignalCallback: Unknown signal %d", sig); break;
+               }
+       KQueueUnlock(m, "Unix Signal");
+       }
+
+mDNSlocal void mDNSSetupSignal(dispatch_queue_t queue, int sig)
+       {
+       signal(sig, SIG_IGN);
+       dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, sig, 0, queue);
+
+       if (source)
+               {
+               dispatch_source_set_event_handler(source, ^{SignalDispatch(source);});
+               // Start processing signals
+               dispatch_resume(source);
+               }
+       else
+               {
+               LogMsg("mDNSSetupSignal: Cannot setup signal %d", sig);
+               }
+       }
+
+// On 10.2 the MachServerName is DNSServiceDiscoveryServer
+// On 10.3 and later, the MachServerName is com.apple.mDNSResponder
+mDNSlocal kern_return_t mDNSDaemonInitialize(void)
+       {
+       mStatus            err;
+       CFMachPortRef      s_port;
+       dispatch_source_t mach_source;
+       dispatch_queue_t queue = dispatch_get_main_queue();
+
+       // If launchd already created our Mach port for us, then use that, else we create a new one of our own
+       if (m_port != MACH_PORT_NULL)
+               s_port = CFMachPortCreateWithPort(NULL, m_port, DNSserverCallback, NULL, NULL);
+       else
+               {
+               s_port = CFMachPortCreate(NULL, DNSserverCallback, NULL, NULL);
+               m_port = CFMachPortGetPort(s_port);
+               char *MachServerName = OSXVers < OSXVers_10_3_Panther ? "DNSServiceDiscoveryServer" : "com.apple.mDNSResponder";
+               kern_return_t status = bootstrap_register(bootstrap_port, MachServerName, m_port);
+       
+               if (status)
+                       {
+                       if (status == 1103)
+                               LogMsg("bootstrap_register() failed: A copy of the daemon is apparently already running");
+                       else
+                               LogMsg("bootstrap_register() failed: %d %X %s", status, status, mach_error_string(status));
+                       return(status);
+                       }
+               }
+
+       err = mDNS_Init(&mDNSStorage, &PlatformStorage,
+               rrcachestorage, RR_CACHE_SIZE,
+               advertise,
+               mDNS_StatusCallback, mDNS_Init_NoInitCallbackContext);
+
+       if (err) { LogMsg("Daemon start: mDNS_Init failed %d", err); return(err); }
+
+       mach_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, m_port, 0, queue);
+       if (mach_source == mDNSNULL){LogMsg("mDNSDaemonInitialize: Error creating source for m_port"); return -1;}
+       dispatch_source_set_event_handler(mach_source, ^{
+               dispatch_mig_server(mach_source, sizeof(union __RequestUnion__DNSServiceDiscoveryReply_subsystem),
+               DNSServiceDiscoveryRequest_server);
+               });
+       dispatch_resume(mach_source);
+
+       mDNSSetupSignal(queue, SIGHUP);
+       mDNSSetupSignal(queue, SIGINT);
+       mDNSSetupSignal(queue, SIGTERM);
+       mDNSSetupSignal(queue, SIGINFO);
+       mDNSSetupSignal(queue, SIGUSR1);
+       mDNSSetupSignal(queue, SIGUSR2);
+       mDNSSetupSignal(queue, SIGHUP);
+
+       // Create a custom handler for doing the housekeeping work. This is either triggered
+       // by the timer or an event source
+       PlatformStorage.custom = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, queue);
+       if (PlatformStorage.custom == mDNSNULL){LogMsg("mDNSDaemonInitialize: Error creating custom source"); return -1;}
+       dispatch_source_set_event_handler(PlatformStorage.custom, ^{PrepareForIdle(&mDNSStorage);});
+       dispatch_resume(PlatformStorage.custom);
+
+       // Create a timer source to trigger housekeeping work. The houskeeping work itself
+       // is done in the custom handler that we set below.
+       
+       PlatformStorage.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
+       if (PlatformStorage.timer == mDNSNULL){LogMsg("mDNSDaemonInitialize: Error creating timer source"); return -1;}
+
+       // As the API does not support one shot timers, we pass zero for the interval. In the custom handler, we
+       // always reset the time to the new time computed. In effect, we ignore the interval
+       dispatch_source_set_timer(PlatformStorage.timer, DISPATCH_TIME_NOW, 1000ull * 1000000000, 0);
+       dispatch_source_set_event_handler(PlatformStorage.timer, ^{
+               dispatch_source_merge_data(PlatformStorage.custom, 1);
+               });
+       dispatch_resume(PlatformStorage.timer);
+
+       LogMsg("DaemonIntialize done successfully");
+
        if (mDNS_DebugMode) printf("Service registered with Mach Port %d\n", m_port);
        return(err);
        }
 
+#endif __LIB_DISPATCH__
+
 mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m)
        {
        mDNSs32 now = mDNS_TimeNow(m);
@@ -2562,13 +2232,13 @@ mDNSlocal mDNSs32 mDNSDaemonIdle(mDNS *const m)
                        if (!SameDomainLabelCS(m->p->usernicelabel.c, m->nicelabel.c))
                                {
                                LogMsg("Name Conflict: Updated Computer Name from \"%#s\" to \"%#s\"", m->p->usernicelabel.c, m->nicelabel.c);
-                               mDNSPreferencesSetName(kmDNSComputerName, &m->p->usernicelabel, &m->nicelabel);
+                               mDNSPreferencesSetNames(m, kmDNSComputerName, &m->p->usernicelabel, &m->nicelabel);
                                m->p->usernicelabel = m->nicelabel;
                                }
                        if (!SameDomainLabelCS(m->p->userhostlabel.c, m->hostlabel.c))
                                {
                                LogMsg("Name Conflict: Updated Local Hostname from \"%#s.local\" to \"%#s.local\"", m->p->userhostlabel.c, m->hostlabel.c);
-                               mDNSPreferencesSetName(kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel);
+                               mDNSPreferencesSetNames(m, kmDNSLocalHostName, &m->p->userhostlabel, &m->hostlabel);
                                m->p->HostNameConflict = 0;     // Clear our indicator, now name change has been successful
                                m->p->userhostlabel = m->hostlabel;
                                }
@@ -2762,7 +2432,7 @@ mDNSlocal mDNSBool AllowSleepNow(mDNS *const m, mDNSs32 now)
                }
 
        LogSPS("AllowSleepNow: %s(%lX) %s at %ld (%d ticks remaining)",
-#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+#if !TARGET_OS_EMBEDDED && defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
                (m->p->IOPMConnection) ? "IOPMConnectionAcknowledgeEventWithOptions" :
 #endif
                (result == kIOReturnSuccess) ? "IOAllowPowerChange" : "IOCancelPowerChange",
@@ -2770,7 +2440,7 @@ mDNSlocal mDNSBool AllowSleepNow(mDNS *const m, mDNSs32 now)
 
        m->SleepLimit = 0;      // Don't clear m->SleepLimit until after we've logged it above
 
-#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+#if !TARGET_OS_EMBEDDED && defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
        if (m->p->IOPMConnection) IOPMConnectionAcknowledgeEventWithOptions(m->p->IOPMConnection, m->p->SleepCookie, opts);
        else
 #endif
@@ -2781,6 +2451,84 @@ mDNSlocal mDNSBool AllowSleepNow(mDNS *const m, mDNSs32 now)
        return(mDNStrue);
        }
 
+#ifdef __LIB_DISPATCH__
+
+mDNSexport void TriggerEventCompletion()
+       {
+       debugf("TriggerEventCompletion: Merge data");
+       dispatch_source_merge_data(PlatformStorage.custom, 1);
+       }
+
+mDNSlocal void PrepareForIdle(void *m_param)
+       {
+       mDNS            *m = m_param;
+       int64_t                 time_offset;
+       dispatch_time_t dtime;
+
+       const int multiplier = 1000000000 / mDNSPlatformOneSecond;
+       
+       // This is the main work loop:
+       // (1) First we give mDNSCore a chance to finish off any of its deferred work and calculate the next sleep time
+       // (2) Then we make sure we've delivered all waiting browse messages to our clients
+       // (3) Then we sleep for the time requested by mDNSCore, or until the next event, whichever is sooner
+
+       debugf("PrepareForIdle: called");
+       // Run mDNS_Execute to find out the time we next need to wake up
+       mDNSs32 start          = mDNSPlatformRawTime();
+       mDNSs32 nextTimerEvent = udsserver_idle(mDNSDaemonIdle(m));
+       mDNSs32 end            = mDNSPlatformRawTime();
+       if (end - start >= WatchDogReportingThreshold)
+               LogInfo("CustomSourceHandler:WARNING: Idle task took %dms to complete", end - start);
+
+       mDNSs32 now = mDNS_TimeNow(m);
+
+       if (m->ShutdownTime)
+               {
+               if (mDNSStorage.ResourceRecords)
+                       {
+                       LogInfo("Cannot exit yet; Resource Record still exists: %s", ARDisplayString(m, mDNSStorage.ResourceRecords));
+                       if (mDNS_LoggingEnabled) usleep(10000);         // Sleep 10ms so that we don't flood syslog with too many messages
+                       }
+               if (mDNS_ExitNow(m, now))
+                       {
+                       if (!mDNSStorage.ResourceRecords)
+                               safe_vproc_transaction_end();
+                       LogInfo("IdleLoop: mDNS_FinalExit");
+                       mDNS_FinalExit(&mDNSStorage);
+                       usleep(1000);           // Little 1ms pause before exiting, so we don't lose our final syslog messages
+                       exit(0);
+                       }
+               if (nextTimerEvent - m->ShutdownTime >= 0)
+                       nextTimerEvent = m->ShutdownTime;
+               }
+
+       if (m->SleepLimit)
+               if (!AllowSleepNow(m, now))
+                       if (nextTimerEvent - m->SleepLimit >= 0)
+                               nextTimerEvent = m->SleepLimit;
+
+       // Convert absolute wakeup time to a relative time from now
+       mDNSs32 ticks = nextTimerEvent - now;
+       if (ticks < 1) ticks = 1;
+       
+       static mDNSs32 RepeatedBusy = 0;        // Debugging sanity check, to guard against CPU spins
+       if (ticks > 1)
+               RepeatedBusy = 0;
+       else
+               {
+               ticks = 1;
+               if (++RepeatedBusy >= mDNSPlatformOneSecond) { ShowTaskSchedulingError(&mDNSStorage); RepeatedBusy = 0; }
+               }
+
+       time_offset = ((mDNSu32)ticks / mDNSPlatformOneSecond) * 1000000000 + (ticks % mDNSPlatformOneSecond) * multiplier;
+       dtime = dispatch_time(DISPATCH_TIME_NOW, time_offset);
+       dispatch_source_set_timer(PlatformStorage.timer, dtime, 1000ull*1000000000, 0);
+       debugf("PrepareForIdle: scheduling timer with ticks %d", ticks);
+       return;
+       }
+
+#else __LIB_DISPATCH__
+
 mDNSlocal void KQWokenFlushBytes(int fd, __unused short filter, __unused void *context)
        {
        // Read all of the bytes so we won't wake again.
@@ -2828,14 +2576,16 @@ mDNSlocal void * KQueueLoop(void *m_param)
                        {
                        if (mDNSStorage.ResourceRecords)
                                {
-                               LogInfo("Cannot exit yet; Resource Record still exists: %s", ARDisplayString(m, mDNSStorage.ResourceRecords));
-                               if (mDNS_LoggingEnabled) usleep(10000);         // Sleep 10ms so that we don't flood syslog with too many messages
+                               AuthRecord *rr;
+                               for (rr = mDNSStorage.ResourceRecords; rr; rr=rr->next)
+                                       {
+                                       LogInfo("Cannot exit yet; Resource Record still exists: %s", ARDisplayString(m, rr));
+                                       if (mDNS_LoggingEnabled) usleep(10000);         // Sleep 10ms so that we don't flood syslog with too many messages
+                                       }
                                }
-                       if (mDNSStorage.ServiceRegistrations)
-                               LogInfo("Cannot exit yet; ServiceRegistrations still exists: %s", ARDisplayString(m, &mDNSStorage.ServiceRegistrations->RR_SRV));
                        if (mDNS_ExitNow(m, now))
                                {
-                               if (!mDNSStorage.ResourceRecords && !mDNSStorage.ServiceRegistrations)
+                               if (!mDNSStorage.ResourceRecords)
                                        safe_vproc_transaction_end();
                                LogInfo("mDNS_FinalExit");
                                mDNS_FinalExit(&mDNSStorage);
@@ -2930,6 +2680,8 @@ mDNSlocal void * KQueueLoop(void *m_param)
        return NULL;
        }
 
+#endif __LIB_DISPATCH__
+
 mDNSlocal void LaunchdCheckin(void)
        {
        launch_data_t msg  = launch_data_new_string(LAUNCH_KEY_CHECKIN);
@@ -3043,7 +2795,6 @@ mDNSexport int main(int argc, char **argv)
        {
        int i;
        kern_return_t status;
-       pthread_t KQueueThread;
 
        LogMsg("%s starting", mDNSResponderVersionString);
        
@@ -3069,11 +2820,13 @@ mDNSexport int main(int argc, char **argv)
                if (!strcasecmp(argv[i], "-launchd"                  )) started_via_launchdaemon  = mDNStrue;
                if (!strcasecmp(argv[i], "-launchdaemon"             )) started_via_launchdaemon  = mDNStrue;
                if (!strcasecmp(argv[i], "-NoMulticastAdvertisements")) advertise                 = mDNS_Init_DontAdvertiseLocalAddresses;
+               if (!strcasecmp(argv[i], "-DisableSleepProxyClient"  )) DisableSleepProxyClient   = mDNStrue;
                if (!strcasecmp(argv[i], "-DebugLogging"             )) mDNS_LoggingEnabled       = mDNStrue;
                if (!strcasecmp(argv[i], "-UnicastPacketLogging"     )) mDNS_PacketLoggingEnabled = mDNStrue;
                if (!strcasecmp(argv[i], "-OfferSleepProxyService"   ))
                        OfferSleepProxyService = (i+1<argc && mDNSIsDigit(argv[i+1][0]) && mDNSIsDigit(argv[i+1][1]) && argv[i+1][2]==0) ? atoi(argv[++i]) : 80;
-               if (!strcasecmp(argv[i], "-StrictUnicastOrdering"     )) StrictUnicastOrdering = mDNStrue;
+               if (!strcasecmp(argv[i], "-StrictUnicastOrdering"    )) StrictUnicastOrdering = mDNStrue;
+               if (!strcasecmp(argv[i], "-DisableInboundRelay"      )) DisableInboundRelayConnection = mDNStrue;
                }
        
        // Note that mDNSPlatformInit will set DivertMulticastAdvertisements in the mDNS structure
@@ -3081,6 +2834,8 @@ mDNSexport int main(int argc, char **argv)
 
        OSXVers = mDNSMacOSXSystemBuildNumber(NULL);
 
+#ifndef __LIB_DISPATCH__
+
        signal(SIGHUP,  HandleSIG);             // (Debugging) Purge the cache to check for cache handling bugs
        signal(SIGINT,  HandleSIG);             // Ctrl-C: Detach from Mach BootstrapService and exit cleanly
        // On 10.5 and later, the default action for SIGABRT is to generate a crash report, so we only need our CatchABRT handler on 10.4
@@ -3095,6 +2850,8 @@ mDNSexport int main(int argc, char **argv)
        signal(SIGUSR1, HandleSIG);             // (Debugging) Enable Logging
        signal(SIGUSR2, HandleSIG);             // (Debugging) Enable Packet Logging
 
+#endif __LIB_DISPATCH__
+
        mDNSStorage.p = &PlatformStorage;       // Make sure mDNSStorage.p is set up, because validatelists uses it
        LaunchdCheckin();
 
@@ -3115,6 +2872,8 @@ mDNSexport int main(int argc, char **argv)
                        }
                }
 
+#ifndef __LIB_DISPATCH__
+
        // Create the kqueue, mutex and thread to support KQSockets
        KQueueFD = kqueue();
        if (KQueueFD == -1) { LogMsg("kqueue() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
@@ -3130,23 +2889,35 @@ mDNSexport int main(int argc, char **argv)
        // We will use the first socket to send the second socket. The second socket
        // will be added to the kqueue so it will wake when data is sent.
        static const KQueueEntry wakeKQEntry = { KQWokenFlushBytes, NULL, "kqueue wakeup after CFRunLoop event" };
+
        PlatformStorage.WakeKQueueLoopFD = fdpair[0];
        KQueueSet(fdpair[1], EV_ADD, EVFILT_READ, &wakeKQEntry);
+
+#endif __LIB_DISPATCH__
        
        // Invoke sandbox profile /usr/share/sandbox/mDNSResponder.sb
 #if MDNS_NO_SANDBOX
        LogMsg("Note: Compiled without Apple Sandbox support");
-#else
+#else MDNS_NO_SANDBOX
        if (!sandbox_init)
                LogMsg("Note: Running without Apple Sandbox support (not available on this OS)");
        else
                {
                char *sandbox_msg;
-               int sandbox_err = sandbox_init("mDNSResponder", SANDBOX_NAMED, &sandbox_msg);
+               struct stat s;
+               uint64_t sandbox_flags = SANDBOX_NAMED;
+
+               if (stat("/usr/share/sandbox/mDNSResponder.sb", &s) == 0)
+                       {
+                       sandbox_flags = SANDBOX_NAMED_EXTERNAL;
+                       LogInfo("Will load Sandbox profile from filesystem");
+                       }
+
+               int sandbox_err = sandbox_init("mDNSResponder", sandbox_flags, &sandbox_msg);
                if (sandbox_err) { LogMsg("WARNING: sandbox_init error %s", sandbox_msg); sandbox_free_error(sandbox_msg); }
                else LogInfo("Now running under Apple Sandbox restrictions");
                }
-#endif
+#endif MDNS_NO_SANDBOX
 
        status = mDNSDaemonInitialize();
        if (status) { LogMsg("Daemon start: mDNSDaemonInitialize failed"); goto exit; }
@@ -3156,16 +2927,22 @@ mDNSexport int main(int argc, char **argv)
 
        mDNSMacOSXNetworkChanged(&mDNSStorage);
 
+#ifdef __LIB_DISPATCH__
+       LogInfo("Daemon Start: Using LibDispatch");
+       // CFRunLoopRun runs both CFRunLoop sources and dispatch sources
+       CFRunLoopRun();
+#else __LIB_DISPATCH__
        // Start the kqueue thread
+       pthread_t KQueueThread;
        i = pthread_create(&KQueueThread, NULL, KQueueLoop, &mDNSStorage);
        if (i == -1) { LogMsg("pthread_create() failed errno %d (%s)", errno, strerror(errno)); status = errno; goto exit; }
-
        if (status == 0)
                {
                CFRunLoopRun();
                LogMsg("ERROR: CFRunLoopRun Exiting.");
                mDNS_Close(&mDNSStorage);
                }
+#endif __LIB_DISPATCH__
 
        LogMsg("%s exiting", mDNSResponderVersionString);
 
@@ -3177,9 +2954,10 @@ exit:
 // uds_daemon.c support routines /////////////////////////////////////////////
 
 // Arrange things so that when data appears on fd, callback is called with context
-mDNSexport mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context)
+mDNSexport mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context, void **platform_data)
        {
        KQSocketEventSource **p = &gEventSources;
+       (void) platform_data;
        while (*p && (*p)->fd != fd) p = &(*p)->next;
        if (*p) { LogMsg("udsSupportAddFDToEventLoop: ERROR fd %d already has EventLoop source entry", fd); return mStatus_AlreadyRegistered; }
 
@@ -3191,6 +2969,11 @@ mDNSexport mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback,
        newSource->kqs.KQcallback = callback;
        newSource->kqs.KQcontext  = context;
        newSource->kqs.KQtask     = "UDS client";
+#ifdef __LIB_DISPATCH__
+       newSource->kqs.readSource  = mDNSNULL;
+       newSource->kqs.writeSource = mDNSNULL;
+       newSource->kqs.fdClosed    = mDNSfalse;
+#endif __LIB_DISPATCH__
 
        if (KQueueSet(fd, EV_ADD, EVFILT_READ, &newSource->kqs) == 0)
                {
@@ -3203,9 +2986,16 @@ mDNSexport mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback,
        return mStatus_BadParamErr;
        }
 
-mDNSexport mStatus udsSupportRemoveFDFromEventLoop(int fd)             // Note: This also CLOSES the file descriptor
+int udsSupportReadFD(dnssd_sock_t fd, char *buf, int len, int flags, void *platform_data)
+       {
+       (void) platform_data;
+       return recv(fd, buf, len, flags);
+       }
+
+mDNSexport mStatus udsSupportRemoveFDFromEventLoop(int fd, void *platform_data)                // Note: This also CLOSES the file descriptor
        {
        KQSocketEventSource **p = &gEventSources;
+       (void) platform_data;
        while (*p && (*p)->fd != fd) p = &(*p)->next;
        if (*p)
                {
@@ -3213,7 +3003,7 @@ mDNSexport mStatus udsSupportRemoveFDFromEventLoop(int fd)                // Note: This also C
                *p = (*p)->next;
                // We don't have to explicitly do a kqueue EV_DELETE here because closing the fd
                // causes the kernel to automatically remove any associated kevents
-               close(s->fd);
+               mDNSPlatformCloseFD(&s->kqs, s->fd);
                freeL("KQSocketEventSource", s);
                return mStatus_NoError;
                }
diff --git a/mDNSMacOSX/helper-entitlements.plist b/mDNSMacOSX/helper-entitlements.plist
new file mode 100644 (file)
index 0000000..cf478cd
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>com.apple.SystemConfiguration.SCDynamicStore-write-access</key>
+       <true/>
+       <key>com.apple.SystemConfiguration.SCPreferences-write-access</key>
+       <array>
+               <string>com.apple.AutoWake.xml</string>
+       </array>
+</dict>
+</plist>
index 3552c8acbca76b27009ff1734da9db50fb8cfa84..93307c15c4493241dafb0a22472e7a6ff7ae6539 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: helper-error.h,v $
-Revision 1.8  2007/11/07 00:22:30  jgraessley
-Bug #: <rdar://problem/5573573> mDNSResponder doesn't build without IPSec
-Reviewed by: Stuart Cheshire
-
-Revision 1.7  2007/09/12 00:42:47  mcguire
-<rdar://problem/5468236> BTMM: Need to clean up security associations
-
-Revision 1.6  2007/09/04 22:32:58  mcguire
-<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
-
-Revision 1.5  2007/08/29 21:42:12  mcguire
-<rdar://problem/5431192> BTMM: Duplicate Private DNS names are being added to DynamicStore
-
-Revision 1.4  2007/08/23 21:15:49  cheshire
-Added $Log header
-
-Revision 1.3  2007/08/23 21:04:44  cheshire
-Tidied up alignment of error message list
-
-Revision 1.2  2007/08/18 01:02:03  mcguire
-<rdar://problem/5415593> No Bonjour services are getting registered at boot
-
-Revision 1.1  2007/08/08 22:34:58  mcguire
-<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
-
  */
 
 ERROR(kmDNSHelperCommunicationFailed,             "Mach communication failed")
index 336dd68bc86aeee960424e05a73ca0da1387b3c3..72e9fbc5747149afc08374ba49e4fb44eb1c5ea8 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: helper-main.c,v $
-Revision 1.28  2009/04/11 00:20:08  jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.27  2009/03/09 19:00:26  mcguire
-<rdar://problem/6660098> temporarily don't use getpwnam
-
-Revision 1.26  2009/03/05 23:08:12  cheshire
-<rdar://problem/6648751> mDNSResponderHelper deadlocked — Can't use syslog from within a signal handler
-
-Revision 1.25  2009/02/06 03:06:49  mcguire
-<rdar://problem/5858533> Adopt vproc_transaction API in mDNSResponder
-
-Revision 1.24  2009/01/28 17:20:46  mcguire
-changed incorrect notice level log to debug
-
-Revision 1.23  2009/01/28 03:17:19  mcguire
-<rdar://problem/5858535> helper: Adopt vproc_transaction API
-
-Revision 1.22  2008/12/19 01:56:47  mcguire
-<rdar://problem/6181947> crashes in mDNSResponderHelper
-
-Revision 1.21  2008/09/15 23:52:30  cheshire
-<rdar://problem/6218902> mDNSResponder-177 fails to compile on Linux with .desc pseudo-op
-Made __crashreporter_info__ symbol conditional, so we only use it for OS X build
-
-Revision 1.20  2008/08/13 23:11:35  mcguire
-<rdar://problem/5858535> handle SIGTERM in mDNSResponderHelper
-
-Revision 1.19  2008/08/13 23:04:06  mcguire
-<rdar://problem/5858535> handle SIGTERM in mDNSResponderHelper
-Preparation: rename message function, as it will no longer be called only on idle exit
-
-Revision 1.18  2008/08/13 22:56:32  mcguire
-<rdar://problem/5858535> handle SIGTERM in mDNSResponderHelper
-Preparation: store mach port in global variable so we can write to it from a signal handler
-
-Revision 1.17  2008/07/24 01:04:04  mcguire
-<rdar://problem/6003721> helper spawned every 10s
-
-Revision 1.16  2008/07/01 01:40:01  mcguire
-<rdar://problem/5823010> 64-bit fixes
-
-Revision 1.15  2008/03/13 20:55:16  mcguire
-<rdar://problem/5769316> fix deprecated warnings/errors
-Additional cleanup: use a conditional macro instead of lots of #if
-
-Revision 1.14  2008/03/12 23:02:59  mcguire
-<rdar://problem/5769316> fix deprecated warnings/errors
-
-Revision 1.13  2007/09/21 16:13:14  cheshire
-Additional Tiger compatibility fix: After bootstrap_check_in, we need to give
-ourselves a Mach "send" right to the port, otherwise our ten-second idle timeout
-mechanism is not able to send the "mDNSIdleExit" message to itself
-
-Revision 1.12  2007/09/20 22:26:20  cheshire
-Add necessary bootstrap_check_in() in Tiger compatibility code (not used on Leopard)
-
-Revision 1.11  2007/09/18 19:09:02  cheshire
-<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
-
-Revision 1.10  2007/09/09 02:21:17  mcguire
-<rdar://problem/5469345> Leopard Server9A547(Insatll):mDNSResponderHelper crashing
-
-Revision 1.9  2007/09/07 22:44:03  mcguire
-<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
-
-Revision 1.8  2007/09/07 22:24:36  vazquez
-<rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
-
-Revision 1.7  2007/08/31 18:09:32  cheshire
-<rdar://problem/5434050> Restore ability to run mDNSResponder on Tiger
-
-Revision 1.6  2007/08/31 17:45:13  cheshire
-Allow maxidle time of zero, meaning "run indefinitely"
-
-Revision 1.5  2007/08/31 00:09:54  cheshire
-Deleted extraneous whitespace (shortened code from 260 lines to 160)
-
-Revision 1.4  2007/08/28 00:33:04  jgraessley
-<rdar://problem/5423932> Selective compilation options
-
-Revision 1.3  2007/08/23 23:21:24  cheshire
-Tiger compatibility: Use old bootstrap_register() instead of Leopard-only bootstrap_register2()
-
-Revision 1.2  2007/08/23 21:36:17  cheshire
-Made code layout style consistent with existing project style; added $Log header
-
-Revision 1.1  2007/08/08 22:34:58  mcguire
-<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
  */
 
 #define _FORTIFY_SOURCE 2
+
+// We set VERSION_MIN_REQUIRED to 10.4 to avoid "bootstrap_register is deprecated" warnings from bootstrap.h
+#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_4
+
 #include <CoreFoundation/CoreFoundation.h>
 #include <sys/cdefs.h>
 #include <sys/time.h>
@@ -309,7 +220,7 @@ static mach_port_t checkin(char *service_name)
        if (MACH_PORT_NULL == (port = launch_data_get_machport(datum)))
                { helplog(ASL_LEVEL_ERR, "Launchd gave me a null Mach port."); goto fin; }
        if (KERN_SUCCESS != (kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)))
-               { helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %s", mach_error_string(kr)); goto fin; }
+               { helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %d %X %s", kr, kr, mach_error_string(kr)); goto fin; }
 
 fin:
        if (NULL != msg)   launch_data_free(msg);
@@ -326,18 +237,18 @@ static mach_port_t register_service(const char *service_name)
        if (KERN_SUCCESS == (kr = bootstrap_check_in(bootstrap_port, (char *)service_name, &port)))
                {
                if (KERN_SUCCESS != (kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)))
-                       helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %s", mach_error_string(kr));
+                       helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %d %X %s", kr, kr, mach_error_string(kr));
                else
                        return port;
                }
        if (KERN_SUCCESS != (kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port)))
-               { helplog(ASL_LEVEL_ERR, "mach_port_allocate: %s", mach_error_string(kr)); goto error; }
+               { helplog(ASL_LEVEL_ERR, "mach_port_allocate: %d %X %s", kr, kr, mach_error_string(kr)); goto error; }
        if (KERN_SUCCESS != (kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)))
-               { helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %s", mach_error_string(kr)); goto error; }
+               { helplog(ASL_LEVEL_ERR, "mach_port_insert_right: %d %X %s", kr, kr, mach_error_string(kr)); goto error; }
 
        // XXX bootstrap_register does not modify its second argument, but the prototype does not include const.
        if (KERN_SUCCESS != (kr = bootstrap_register(bootstrap_port, (char *)service_name, port)))
-               { helplog(ASL_LEVEL_ERR, "bootstrap_register failed: %s", mach_error_string(kr)); goto error; }
+               { helplog(ASL_LEVEL_ERR, "bootstrap_register failed: %s %d %X %s", service_name, kr, kr, mach_error_string(kr)); goto error; }
 
        return port;
 error:
@@ -407,14 +318,15 @@ int main(int ac, char *av[])
                hdr.msgh_size = sizeof(hdr);
                hdr.msgh_id = 0;
                kr = mach_msg(&hdr, MACH_RCV_LARGE | MACH_RCV_MSG, 0, hdr.msgh_size, gPort, 0, 0);
-               if (MACH_RCV_TOO_LARGE != kr) helplog(ASL_LEVEL_ERR, "kr: %d: %s", kr, mach_error_string(kr));
+               if (MACH_RCV_TOO_LARGE != kr)
+                       helplog(ASL_LEVEL_ERR, "main MACH_RCV_MSG error: %d %X %s", kr, kr, mach_error_string(kr));
                
                safe_vproc_transaction_begin();
                
                kr = mach_msg_server_once(helper_server, MAX_MSG_SIZE, gPort,
                        MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0));
                if (KERN_SUCCESS != kr)
-                       { helplog(ASL_LEVEL_ERR, "mach_msg_server: %s\n", mach_error_string(kr)); exit(EXIT_FAILURE); }
+                       { helplog(ASL_LEVEL_ERR, "mach_msg_server: %d %X %s", kr, kr, mach_error_string(kr)); exit(EXIT_FAILURE); }
                
                safe_vproc_transaction_end();
                }
index 1efaa415af9ea16c6a769ab16dbf28b92f710698..66bdb37fcf019568e82690f78a8f113a0934174e 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: helper-server.h,v $
-Revision 1.5  2009/02/06 03:06:49  mcguire
-<rdar://problem/5858533> Adopt vproc_transaction API in mDNSResponder
-
-Revision 1.4  2009/01/28 03:17:19  mcguire
-<rdar://problem/5858535> helper: Adopt vproc_transaction API
-
-Revision 1.3  2007/09/07 22:44:03  mcguire
-<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
-
-Revision 1.2  2007/08/23 21:39:01  cheshire
-Made code layout style consistent with existing project style; added $Log header
-
-Revision 1.1  2007/08/08 22:34:58  mcguire
-<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
  */
 
 #ifndef H_HELPER_SERVER_H
index 09b262c7380bde28fc6f32f2f8841cdee440d213..9e5686041e7f0bfc00786cce3e52566ca181857d 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: helper-stubs.c,v $
-Revision 1.19  2009/04/20 20:40:14  cheshire
-<rdar://problem/6786150> uDNS: Running location cycling caused configd and mDNSResponder to deadlock
-Changed mDNSPreferencesSetName (and similar) routines from MIG "routine" to MIG "simpleroutine"
-so we don't deadlock waiting for a result that we're just going to ignore anyway
-
-Revision 1.18  2009/03/20 22:12:27  mcguire
-<rdar://problem/6703952> Support CFUserNotificationDisplayNotice in mDNSResponderHelper
-Make the call to the helper a simpleroutine: don't wait for an unused return value
-
-Revision 1.17  2009/03/20 20:52:22  cheshire
-<rdar://problem/6703952> Support CFUserNotificationDisplayNotice in mDNSResponderHelper
-
-Revision 1.16  2009/03/14 01:42:56  mcguire
-<rdar://problem/5457116> BTMM: Fix issues with multiple .Mac accounts on the same machine
-
-Revision 1.15  2009/01/22 02:14:27  cheshire
-<rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
-
-Revision 1.14  2009/01/14 01:38:42  mcguire
-<rdar://problem/6492710> Write out DynamicStore per-interface SleepProxyServer info
-
-Revision 1.13  2009/01/14 01:28:17  mcguire
-removed unused variable
-
-Revision 1.12  2008/11/11 00:46:37  cheshire
-Don't just show "<unknown error>"; show the actual numeric error code too, so we can see what the unknown error was
-
-Revision 1.11  2008/11/04 23:54:09  cheshire
-Added routine mDNSSetARP(), used to replace an SPS client's entry in our ARP cache with
-a dummy one, so that IP traffic to the SPS client initiated by the SPS machine can be
-captured by our BPF filters, and used as a trigger to wake the sleeping machine.
-
-Revision 1.10  2008/10/29 21:25:35  cheshire
-Don't report kIOReturnNotReady errors
-
-Revision 1.9  2008/10/24 01:42:36  cheshire
-Added mDNSPowerRequest helper routine to request a scheduled wakeup some time in the future
-
-Revision 1.8  2008/10/20 22:01:28  cheshire
-Made new Mach simpleroutine "mDNSRequestBPF"
-
-Revision 1.7  2008/09/27 00:58:32  cheshire
-Added mDNSRequestBPF definition
-
-Revision 1.6  2007/12/10 23:23:48  cheshire
-Removed unnecessary log message ("mDNSKeychainGetSecrets failed 0 00000000" because mDNSKeychainGetSecrets was failing to return a valid array)
-
-Revision 1.5  2007/09/07 22:44:03  mcguire
-<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
-
-Revision 1.4  2007/09/04 22:32:58  mcguire
-<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
-
-Revision 1.3  2007/08/23 21:44:55  cheshire
-Made code layout style consistent with existing project style; added $Log header
-
-Revision 1.2  2007/08/18 01:02:03  mcguire
-<rdar://problem/5415593> No Bonjour services are getting registered at boot
-
-Revision 1.1  2007/08/08 22:34:58  mcguire
-<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
  */
 
 #include <mach/mach.h>
@@ -127,7 +62,7 @@ const char *mDNSHelperError(int err)
                else                                                                                                                                                            \
                        {                                                                                                                                                               \
                        (err) = kmDNSHelperCommunicationFailed;                                                                                 \
-                       LogMsg("%s: Mach communication failed: %s", __func__, mach_error_string(kr));   \
+                       LogMsg("%s: Mach communication failed: %d %X %s", __func__, kr, kr, mach_error_string(kr));     \
                        goto fin;                                                                                                                                               \
                        }                                                                                                                                                               \
                }                                                                                                                                                                       \
@@ -214,12 +149,12 @@ fin:
        return err;
        }
 
-int mDNSSetARP(int ifindex, const v4addr_t ip, const ethaddr_t eth)
+int mDNSSetLocalAddressCacheEntry(int ifindex, int family, const v6addr_t ip, const ethaddr_t eth)
        {
        kern_return_t kr = KERN_FAILURE;
        int retry = 0, err = 0;
        MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
-       kr = proxy_mDNSSetARP(getHelperPort(retry), ifindex, (uint8_t*)ip, (uint8_t*)eth, &err);
+       kr = proxy_mDNSSetLocalAddressCacheEntry(getHelperPort(retry), ifindex, family, (uint8_t*)ip, (uint8_t*)eth, &err);
        MACHRETRYLOOP_END(kr, retry, err, fin);
 fin:
        return err;
@@ -242,15 +177,15 @@ int mDNSKeychainGetSecrets(CFArrayRef *result)
        CFDataRef bytes = NULL;
        kern_return_t kr = KERN_FAILURE;
        unsigned int numsecrets = 0;
-       void *secrets = NULL;
+       vm_offset_t secrets = 0;
        mach_msg_type_number_t secretsCnt = 0;
        int retry = 0, err = 0;
 
        MACHRETRYLOOP_BEGIN(kr, retry, err, fin);
-       kr = proxy_mDNSKeychainGetSecrets(getHelperPort(retry), &numsecrets, (vm_offset_t *)&secrets, &secretsCnt, &err);
+       kr = proxy_mDNSKeychainGetSecrets(getHelperPort(retry), &numsecrets, &secrets, &secretsCnt, &err);
        MACHRETRYLOOP_END(kr, retry, err, fin);
 
-       if (NULL == (bytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, secrets, secretsCnt, kCFAllocatorNull)))
+       if (NULL == (bytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (void*)secrets, secretsCnt, kCFAllocatorNull)))
                {
                err = kmDNSHelperCreationFailed;
                LogMsg("%s: CFDataCreateWithBytesNoCopy failed", __func__);
@@ -273,8 +208,8 @@ int mDNSKeychainGetSecrets(CFArrayRef *result)
        *result = (CFArrayRef)plist;
 
 fin:
-       if (NULL != bytes) CFRelease(bytes);
-       if (NULL != secrets) vm_deallocate(mach_task_self(), (vm_offset_t)secrets, secretsCnt);
+       if (bytes) CFRelease(bytes);
+       if (secrets) vm_deallocate(mach_task_self(), secrets, secretsCnt);
        return err;
        }
 
@@ -308,8 +243,8 @@ fin:
        }
 
 int mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner,
-    v4addr_t local_outer, short local_port, v6addr_t remote_inner,
-    v4addr_t remote_outer, short remote_port, const domainname *const fqdn)
+    v6addr_t local_outer, short local_port, v6addr_t remote_inner,
+    v6addr_t remote_outer, short remote_port, const domainname *const fqdn)
        {
        kern_return_t kr = KERN_SUCCESS;
        int retry = 0, err = 0;
index 8b2a74200b40f96d36440afea5a7fd33fb228953..f4c0771a00134c25747ade400e8d33a9c791ac5c 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: helper.c,v $
-Revision 1.66  2009/04/20 20:40:14  cheshire
-<rdar://problem/6786150> uDNS: Running location cycling caused configd and mDNSResponder to deadlock
-Changed mDNSPreferencesSetName (and similar) routines from MIG "routine" to MIG "simpleroutine"
-so we don't deadlock waiting for a result that we're just going to ignore anyway
-
-Revision 1.65  2009/03/20 22:12:28  mcguire
-<rdar://problem/6703952> Support CFUserNotificationDisplayNotice in mDNSResponderHelper
-Make the call to the helper a simpleroutine: don't wait for an unused return value
-
-Revision 1.64  2009/03/20 21:52:39  cheshire
-<rdar://problem/6703952> Support CFUserNotificationDisplayNotice in mDNSResponderHelper
-Need to CFRelease strings in do_mDNSNotify
-
-Revision 1.63  2009/03/20 21:21:15  cheshire
-<rdar://problem/6703952> Support CFUserNotificationDisplayNotice in mDNSResponderHelper
-Need to set error code correctly in do_mDNSNotify
-
-Revision 1.62  2009/03/20 20:52:22  cheshire
-<rdar://problem/6703952> Support CFUserNotificationDisplayNotice in mDNSResponderHelper
-
-Revision 1.61  2009/03/14 01:42:56  mcguire
-<rdar://problem/5457116> BTMM: Fix issues with multiple .Mac accounts on the same machine
-
-Revision 1.60  2009/02/18 02:09:10  cheshire
-<rdar://problem/6514947> Sleep Proxy: PF_ROUTE command to set ARP entry returns errno 17 (EEXIST)
-Also need to set rtmsg.hdr.rtm_index
-
-Revision 1.59  2009/02/17 23:33:45  cheshire
-<rdar://problem/6514947> Sleep Proxy: PF_ROUTE command to set ARP entry returns errno 17 (EEXIST)
-
-Revision 1.58  2009/02/04 22:23:04  cheshire
-Simplified do_mDNSPowerRequest --
-code was checking for CFAbsoluteTimeGetCurrent() returning NULL, which makes no sense
-
-Revision 1.57  2009/01/22 02:14:27  cheshire
-<rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
-
-Revision 1.56  2009/01/20 21:03:22  cheshire
-Improved debugging messages
-
-Revision 1.55  2009/01/20 02:37:26  mcguire
-revert previous erroneous commit
-
-Revision 1.54  2009/01/20 02:35:15  mcguire
-mDNSMacOSX/mDNSMacOSX.c
-
-Revision 1.53  2009/01/14 01:38:42  mcguire
-<rdar://problem/6492710> Write out DynamicStore per-interface SleepProxyServer info
-
-Revision 1.52  2009/01/13 05:31:34  mkrochma
-<rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
-
-Revision 1.51  2009/01/12 22:26:12  mkrochma
-Change DynamicStore location from BonjourSleepProxy/DiscoveredServers to SleepProxyServers
-
-Revision 1.50  2008/12/15 18:40:41  mcguire
-<rdar://problem/6444440> Socket leak in helper's doTunnelPolicy
-
-Revision 1.49  2008/12/12 00:37:42  mcguire
-<rdar://problem/6417648> BTMM outbound fails if /var/run/racoon doesn't exist
-
-Revision 1.48  2008/12/05 02:35:24  mcguire
-<rdar://problem/6107390> Write to the DynamicStore when a Sleep Proxy server is available on the network
-
-Revision 1.47  2008/11/21 02:28:55  mcguire
-<rdar://problem/6354979> send racoon a SIGUSR1 instead of SIGHUP
-
-Revision 1.46  2008/11/11 02:09:42  cheshire
-Removed some unnecessary log messages
-
-Revision 1.45  2008/11/06 23:35:38  cheshire
-Refinements to the do_mDNSSetARP() routine
-
-Revision 1.44  2008/11/05 18:41:14  cheshire
-Log errors from read() call in do_mDNSSetARP()
-
-Revision 1.43  2008/11/04 23:54:09  cheshire
-Added routine mDNSSetARP(), used to replace an SPS client's entry in our ARP cache with
-a dummy one, so that IP traffic to the SPS client initiated by the SPS machine can be
-captured by our BPF filters, and used as a trigger to wake the sleeping machine.
-
-Revision 1.42  2008/10/31 23:35:31  cheshire
-When scheduling new power event make sure all old events are deleted;
-mDNSPowerRequest(-1,-1); just clears old events without scheduling a new one
-
-Revision 1.41  2008/10/31 18:41:55  cheshire
-Do update_idle_timer() before returning from do_mDNSRequestBPF()
-
-Revision 1.40  2008/10/30 01:05:27  cheshire
-mDNSPowerRequest(0, 0) means "sleep now"
-
-Revision 1.39  2008/10/29 21:26:50  cheshire
-Only log IOPMSchedulePowerEvent calls when there's an error
-
-Revision 1.38  2008/10/24 01:42:36  cheshire
-Added mDNSPowerRequest helper routine to request a scheduled wakeup some time in the future
-
-Revision 1.37  2008/10/24 00:17:22  mcguire
-Add compatibility for older racoon behavior
-
-Revision 1.36  2008/10/22 17:22:31  cheshire
-Remove SO_NOSIGPIPE bug workaround
-
-Revision 1.35  2008/10/20 22:01:28  cheshire
-Made new Mach simpleroutine "mDNSRequestBPF"
-
-Revision 1.34  2008/10/02 23:50:07  mcguire
-<rdar://problem/6136442> shutdown time issues
-improve log messages when SCDynamicStoreCreate() fails
-
-Revision 1.33  2008/09/30 01:00:45  cheshire
-Added workaround to avoid SO_NOSIGPIPE bug
-
-Revision 1.32  2008/09/27 01:11:46  cheshire
-Added handler to respond to kmDNSSendBPF message
-
-Revision 1.31  2008/09/08 17:42:40  mcguire
-<rdar://problem/5536811> change location of racoon files
-cleanup, handle stat failure cases, reduce log messages
-
-Revision 1.30  2008/09/05 21:51:26  mcguire
-<rdar://problem/6077707> BTMM: Need to launch racoon by opening VPN control socket
-
-Revision 1.29  2008/09/05 18:26:53  mcguire
-<rdar://problem/6077707> BTMM: Need to launch racoon by opening VPN control socket
-
-Revision 1.28  2008/09/04 22:49:28  mcguire
-<rdar://problem/5536811> change location of racoon files
-
-Revision 1.27  2008/08/28 23:11:12  mcguire
-<rdar://problem/5858535> handle SIGTERM in mDNSResponderHelper
-
-Revision 1.26  2008/08/19 00:35:02  mcguire
-<rdar://problem/5858535> handle SIGTERM in mDNSResponderHelper
-
-Revision 1.25  2008/08/13 23:04:06  mcguire
-<rdar://problem/5858535> handle SIGTERM in mDNSResponderHelper
-Preparation: rename message function, as it will no longer be called only on idle exit
-
-Revision 1.24  2008/01/30 19:01:51  mcguire
-<rdar://problem/5703989> Crash in mDNSResponderHelper
-
-Revision 1.23  2007/11/30 23:21:51  cheshire
-Rename variables to eliminate "declaration of 'sin_loc' shadows a previous local" warning
-
-Revision 1.22  2007/11/27 00:08:49  jgraessley
-<rdar://problem/5613538> Interface specific resolvers not setup correctly
-
-Revision 1.21  2007/11/07 00:22:30  jgraessley
-Bug #: <rdar://problem/5573573> mDNSResponder doesn't build without IPSec
-Reviewed by: Stuart Cheshire
-
-Revision 1.20  2007/09/12 18:07:44  cheshire
-Fix compile errors ("passing argument from incompatible pointer type")
-
-Revision 1.19  2007/09/12 00:42:47  mcguire
-<rdar://problem/5468236> BTMM: Need to clean up security associations
-
-Revision 1.18  2007/09/12 00:40:16  mcguire
-<rdar://problem/5469660> 9A547: Computer Name had incorrectly encoded unicode
-
-Revision 1.17  2007/09/09 02:21:17  mcguire
-<rdar://problem/5469345> Leopard Server9A547(Insatll):mDNSResponderHelper crashing
-
-Revision 1.16  2007/09/07 22:44:03  mcguire
-<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
-
-Revision 1.15  2007/09/07 22:24:36  vazquez
-<rdar://problem/5466301> Need to stop spewing mDNSResponderHelper logs
-
-Revision 1.14  2007/09/06 20:39:05  cheshire
-Added comment explaining why we allow both "ddns" and "sndd" as valid item types
-The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time)
-
-Revision 1.13  2007/09/04 22:32:58  mcguire
-<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
-
-Revision 1.12  2007/08/29 21:42:12  mcguire
-<rdar://problem/5431192> BTMM: Duplicate Private DNS names are being added to DynamicStore
-
-Revision 1.11  2007/08/28 00:33:04  jgraessley
-<rdar://problem/5423932> Selective compilation options
-
-Revision 1.10  2007/08/27 22:16:38  mcguire
-<rdar://problem/5437362> BTMM: MTU should be set to 1280
-
-Revision 1.9  2007/08/27 22:13:59  mcguire
-<rdar://problem/5437373> BTMM: IPSec security associations should have a shorter timeout
-
-Revision 1.8  2007/08/23 21:49:51  cheshire
-Made code layout style consistent with existing project style; added $Log header
-
-Revision 1.7  2007/08/23 00:29:05  mcguire
-<rdar://problem/5425800> BTMM: IPSec policy not installed in some situations - connections fail
-
-Revision 1.6  2007/08/18 01:02:03  mcguire
-<rdar://problem/5415593> No Bonjour services are getting registered at boot
-
-Revision 1.5  2007/08/18 00:59:55  mcguire
-<rdar://problem/5392568> Blocked: BTMM: Start racoon with '-e' parameter
-
-Revision 1.4  2007/08/16 01:00:06  mcguire
-<rdar://problem/5392548> BTMM: Install generate IPsec policies to block non-BTMM traffic
-
-Revision 1.3  2007/08/15 23:20:28  mcguire
-<rdar://problem/5408105> BTMM: racoon files can get corrupted if autotunnel is listening on port > 32767
-
-Revision 1.2  2007/08/10 22:30:39  mcguire
-<rdar://problem/5400259> BTMM: racoon config files are not always the correct mode
-
-Revision 1.1  2007/08/08 22:34:58  mcguire
-<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
  */
 
 #include <sys/cdefs.h>
@@ -244,12 +28,14 @@ Revision 1.1  2007/08/08 22:34:58  mcguire
 #include <netinet6/nd6.h>
 #include <netinet6/ipsec.h>
 #include <sys/ioctl.h>
+#include <sys/param.h>
 #include <sys/socket.h>
 #include <asl.h>
 #include <ctype.h>
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <signal.h>
 #include <stdarg.h>
 #include <stdbool.h>
 #include <string.h>
@@ -276,6 +62,9 @@ Revision 1.1  2007/08/08 22:34:58  mcguire
 #endif
 
 #if TARGET_OS_EMBEDDED
+#ifndef MDNS_NO_IPSEC
+#define MDNS_NO_IPSEC 1
+#endif
 #define NO_CFUSERNOTIFICATION 1
 #define NO_SECURITYFRAMEWORK 1
 #endif
@@ -401,10 +190,18 @@ fin:
        return KERN_SUCCESS;
        }
 
-kern_return_t do_mDNSSetARP(__unused mach_port_t port, int ifindex, v4addr_t v4, ethaddr_t eth, int *err, audit_token_t token)
+kern_return_t do_mDNSSetLocalAddressCacheEntry(__unused mach_port_t port, int ifindex, int family, v6addr_t ip, ethaddr_t eth, int *err, audit_token_t token)
        {
-       //helplog(ASL_LEVEL_ERR, "do_mDNSSetARP %d %d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X",
-       //      ifindex, v4[0], v4[1], v4[2], v4[3], eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
+       #define IPv6FMTSTRING "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X"
+       #define IPv6FMTARGS  ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15] 
+       #if 0
+       if (family == 4)
+               helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry %d IPv%d %d.%d.%d.%d %02X:%02X:%02X:%02X:%02X:%02X",
+                       ifindex, family, ip[0], ip[1], ip[2], ip[3], eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
+       else
+               helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry %d IPv%d " IPv6FMTSTRING " %02X:%02X:%02X:%02X:%02X:%02X",
+                       ifindex, family, IPv6FMTARGS, eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
+       #endif
 
        *err = -1;
        if (!authorized(&token)) { *err = kmDNSHelperNotAuthorized; goto fin; }
@@ -413,59 +210,109 @@ kern_return_t do_mDNSSetARP(__unused mach_port_t port, int ifindex, v4addr_t v4,
        if (s < 0)
                {
                s = socket(PF_ROUTE, SOCK_RAW, 0);
-               if (s < 0) helplog(ASL_LEVEL_ERR, "do_mDNSSetARP: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno, strerror(errno));
+               if (s < 0) helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: socket(PF_ROUTE, SOCK_RAW, 0) failed %d (%s)", errno, strerror(errno));
                }
 
        if (s >= 0)
                {
                struct timeval tv;
                gettimeofday(&tv, 0);
+               if (family == 4)
+                       {
+                       struct { struct rt_msghdr hdr; struct sockaddr_inarp dst; struct sockaddr_dl sdl; } rtmsg;
+                       memset(&rtmsg, 0, sizeof(rtmsg));
+
+                       rtmsg.hdr.rtm_msglen         = sizeof(rtmsg);
+                       rtmsg.hdr.rtm_version        = RTM_VERSION;
+                       rtmsg.hdr.rtm_type           = RTM_ADD;
+                       rtmsg.hdr.rtm_index          = ifindex;
+                       rtmsg.hdr.rtm_flags          = RTF_HOST | RTF_STATIC | RTF_IFSCOPE;
+                       rtmsg.hdr.rtm_addrs          = RTA_DST | RTA_GATEWAY;
+                       rtmsg.hdr.rtm_pid            = 0;
+                       rtmsg.hdr.rtm_seq            = seq++;
+                       rtmsg.hdr.rtm_errno          = 0;
+                       rtmsg.hdr.rtm_use            = 0;
+                       rtmsg.hdr.rtm_inits          = RTV_EXPIRE;
+                       rtmsg.hdr.rtm_rmx.rmx_expire = tv.tv_sec + 30;
+
+                       rtmsg.dst.sin_len            = sizeof(rtmsg.dst);
+                       rtmsg.dst.sin_family         = AF_INET;
+                       rtmsg.dst.sin_port           = 0;
+                       rtmsg.dst.sin_addr.s_addr    = *(in_addr_t*)ip;
+                       rtmsg.dst.sin_srcaddr.s_addr = 0;
+                       rtmsg.dst.sin_tos            = 0;
+                       rtmsg.dst.sin_other          = 0;
+
+                       rtmsg.sdl.sdl_len            = sizeof(rtmsg.sdl);
+                       rtmsg.sdl.sdl_family         = AF_LINK;
+                       rtmsg.sdl.sdl_index          = ifindex;
+                       rtmsg.sdl.sdl_type           = IFT_ETHER;
+                       rtmsg.sdl.sdl_nlen           = 0;
+                       rtmsg.sdl.sdl_alen           = ETHER_ADDR_LEN;
+                       rtmsg.sdl.sdl_slen           = 0;
+
+                       // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
+                       memcpy(rtmsg.sdl.sdl_data, eth, sizeof(ethaddr_t));
+
+                       int len = write(s, (char *)&rtmsg, sizeof(rtmsg));
+                       if (len < 0)
+                               helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)",
+                                       sizeof(rtmsg), ifindex, ip[0], ip[1], ip[2], ip[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno));
+                       len = read(s, (char *)&rtmsg, sizeof(rtmsg));
+                       if (len < 0 || rtmsg.hdr.rtm_errno)
+                               helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s) %d",
+                                       sizeof(rtmsg), ifindex, ip[0], ip[1], ip[2], ip[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno), rtmsg.hdr.rtm_errno);
+
+                       *err = 0;
+                       }
+               else
+                       {
+                       struct { struct rt_msghdr hdr; struct sockaddr_in6 dst; struct sockaddr_dl sdl; } rtmsg;
+                       memset(&rtmsg, 0, sizeof(rtmsg));
+
+                       rtmsg.hdr.rtm_msglen         = sizeof(rtmsg);
+                       rtmsg.hdr.rtm_version        = RTM_VERSION;
+                       rtmsg.hdr.rtm_type           = RTM_ADD;
+                       rtmsg.hdr.rtm_index          = ifindex;
+                       rtmsg.hdr.rtm_flags          = RTF_HOST | RTF_STATIC | RTF_IFSCOPE;
+                       rtmsg.hdr.rtm_addrs          = RTA_DST | RTA_GATEWAY;
+                       rtmsg.hdr.rtm_pid            = 0;
+                       rtmsg.hdr.rtm_seq            = seq++;
+                       rtmsg.hdr.rtm_errno          = 0;
+                       rtmsg.hdr.rtm_use            = 0;
+                       rtmsg.hdr.rtm_inits          = RTV_EXPIRE;
+                       rtmsg.hdr.rtm_rmx.rmx_expire = tv.tv_sec + 30;
+
+                       rtmsg.dst.sin6_len           = sizeof(rtmsg.dst);
+                       rtmsg.dst.sin6_family        = AF_INET6;
+                       rtmsg.dst.sin6_port          = 0;
+                       rtmsg.dst.sin6_flowinfo      = 0;
+                       rtmsg.dst.sin6_addr          = *(struct in6_addr*)ip;
+                       rtmsg.dst.sin6_scope_id      = ifindex;
+
+                       rtmsg.sdl.sdl_len            = sizeof(rtmsg.sdl);
+                       rtmsg.sdl.sdl_family         = AF_LINK;
+                       rtmsg.sdl.sdl_index          = ifindex;
+                       rtmsg.sdl.sdl_type           = IFT_ETHER;
+                       rtmsg.sdl.sdl_nlen           = 0;
+                       rtmsg.sdl.sdl_alen           = ETHER_ADDR_LEN;
+                       rtmsg.sdl.sdl_slen           = 0;
+
+                       // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
+                       memcpy(rtmsg.sdl.sdl_data, eth, sizeof(ethaddr_t));
+
+                       int len = write(s, (char *)&rtmsg, sizeof(rtmsg));
+                       if (len < 0)
+                               helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: write(%d) interface %d address " IPv6FMTSTRING " seq %d result %d errno %d (%s)",
+                                       sizeof(rtmsg), ifindex, IPv6FMTARGS, rtmsg.hdr.rtm_seq, len, errno, strerror(errno));
+                       len = read(s, (char *)&rtmsg, sizeof(rtmsg));
+                       if (len < 0 || rtmsg.hdr.rtm_errno)
+                               helplog(ASL_LEVEL_ERR, "do_mDNSSetLocalAddressCacheEntry: read (%d) interface %d address " IPv6FMTSTRING " seq %d result %d errno %d (%s) %d",
+                                       sizeof(rtmsg), ifindex, IPv6FMTARGS, rtmsg.hdr.rtm_seq, len, errno, strerror(errno), rtmsg.hdr.rtm_errno);
+
+                       *err = 0;
+                       }
 
-               struct { struct rt_msghdr hdr; struct sockaddr_inarp dst; struct sockaddr_dl sdl; } rtmsg;
-               memset(&rtmsg, 0, sizeof(rtmsg));
-
-               rtmsg.hdr.rtm_msglen         = sizeof(rtmsg);
-               rtmsg.hdr.rtm_version        = RTM_VERSION;
-               rtmsg.hdr.rtm_type           = RTM_ADD;
-               rtmsg.hdr.rtm_index          = ifindex;
-               rtmsg.hdr.rtm_flags          = RTF_HOST | RTF_STATIC | RTF_IFSCOPE;
-               rtmsg.hdr.rtm_addrs          = RTA_DST | RTA_GATEWAY;
-               rtmsg.hdr.rtm_pid            = 0;
-               rtmsg.hdr.rtm_seq            = seq++;
-               rtmsg.hdr.rtm_errno          = 0;
-               rtmsg.hdr.rtm_use            = 0;
-               rtmsg.hdr.rtm_inits          = RTV_EXPIRE;
-               rtmsg.hdr.rtm_rmx.rmx_expire = tv.tv_sec + 30;
-
-               rtmsg.dst.sin_len            = sizeof(struct sockaddr_inarp);
-               rtmsg.dst.sin_family         = AF_INET;
-               rtmsg.dst.sin_port           = 0;
-               rtmsg.dst.sin_addr.s_addr    = *(in_addr_t*)v4;
-               rtmsg.dst.sin_srcaddr.s_addr = 0;
-               rtmsg.dst.sin_tos            = 0;
-               rtmsg.dst.sin_other          = 0;
-
-               rtmsg.sdl.sdl_len            = sizeof(struct sockaddr_dl);
-               rtmsg.sdl.sdl_family         = AF_LINK;
-               rtmsg.sdl.sdl_index          = ifindex;
-               rtmsg.sdl.sdl_type           = IFT_ETHER;
-               rtmsg.sdl.sdl_nlen           = 0;
-               rtmsg.sdl.sdl_alen           = ETHER_ADDR_LEN;
-               rtmsg.sdl.sdl_slen           = 0;
-
-               // Target MAC address goes in rtmsg.sdl.sdl_data[0..5]; (See LLADDR() in /usr/include/net/if_dl.h)
-               memcpy(rtmsg.sdl.sdl_data, eth, sizeof(ethaddr_t));
-
-               int len = write(s, (char *)&rtmsg, sizeof(rtmsg));
-               if (len < 0)
-                       helplog(ASL_LEVEL_ERR, "do_mDNSSetARP: write(%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)",
-                               sizeof(rtmsg), ifindex, v4[0], v4[1], v4[2], v4[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno));
-               len = read(s, (char *)&rtmsg, sizeof(rtmsg));
-               if (len < 0)
-                       helplog(ASL_LEVEL_ERR, "do_mDNSSetARP: read (%d) interface %d address %d.%d.%d.%d seq %d result %d errno %d (%s)",
-                               sizeof(rtmsg), ifindex, v4[0], v4[1], v4[2], v4[3], rtmsg.hdr.rtm_seq, len, errno, strerror(errno));
-
-               *err = 0;
                }
 
 fin:
@@ -489,6 +336,9 @@ kern_return_t do_mDNSNotify(__unused mach_port_t port, const char *title, const
        if (err) helplog(ASL_LEVEL_ERR, "CFUserNotificationDisplayNotice returned %d", err);
        CFRelease(alertHeader);
        CFRelease(alertMessage);
+#else
+       (void)title;
+       (void)msg;
 #endif /* NO_CFUSERNOTIFICATION */
 
        update_idle_timer();
@@ -810,7 +660,8 @@ do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, c
 
        if (0 == strncmp(old, new, MAX_DOMAIN_LABEL+1))
                {
-               // if we've changed the name, but now someone else has set it to something different, we no longer need the notification
+               // old and new are same means the config changed i.e, the user has set something in the preferences pane.
+               // This means the conflict has been resolved. We need to dismiss the dialogue.
                if (last[0] && 0 != strncmp(last, new, MAX_DOMAIN_LABEL+1))
                        {
                        last[0] = 0;
@@ -821,6 +672,10 @@ do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, c
                }
        else
                {
+               // old and new are not same, this means there is a conflict. For the first conflict, we show
+               // the old value and the new value. For all subsequent conflicts, while the dialogue is still
+               // up, we do a real time update of the "new" value in the dialogue. That's why we update just
+               // "last" here and not "user".
                if (strncmp(last, new, MAX_DOMAIN_LABEL+1))
                        {
                        strncpy(last, new, MAX_DOMAIN_LABEL);
@@ -828,6 +683,9 @@ do_mDNSPreferencesSetName(__unused mach_port_t port, int key, const char* old, c
                        }
                }
 
+       // If we are not showing the dialogue, we need to remember the first "old" value so that
+       // we maintain the same through the lifetime of the dialogue. Subsequence conflicts don't
+       // update the "old" value.
        if (!user[0])
                {
                strncpy(user, old, MAX_DOMAIN_LABEL);
@@ -1183,15 +1041,25 @@ typedef enum _mDNSTunnelPolicyWhich
        kmDNSTunnelPolicyGenerate
        } mDNSTunnelPolicyWhich;
 
+// For kmDNSTunnelPolicySetup, you can setup IPv6-in-IPv6 tunnel or IPv6-in-IPv4 tunnel
+// kmDNSNoTunnel is used for other Policy types
+typedef enum _mDNSTunnelType
+       {
+       kmDNSNoTunnel,
+       kmDNSIPv6IPv4Tunnel,
+       kmDNSIPv6IPv6Tunnel
+       } mDNSTunnelType;
+
 static const uint8_t kWholeV6Mask = 128;
 static const uint8_t kZeroV6Mask  = 0;
 
 static int
-doTunnelPolicy(mDNSTunnelPolicyWhich which,
+doTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type,
               v6addr_t loc_inner, uint8_t loc_bits,
               v4addr_t loc_outer, uint16_t loc_port, 
               v6addr_t rmt_inner, uint8_t rmt_bits,
-              v4addr_t rmt_outer, uint16_t rmt_port);
+              v4addr_t rmt_outer, uint16_t rmt_port,
+                  v6addr_t loc_outer6, v6addr_t rmt_outer6);
 
 static int
 aliasTunnelAddress(v6addr_t address)
@@ -1233,9 +1101,9 @@ aliasTunnelAddress(v6addr_t address)
                }
 
        v6addr_t zero = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0        };
-       err = doTunnelPolicy(kmDNSTunnelPolicyGenerate,
+       err = doTunnelPolicy(kmDNSTunnelPolicyGenerate, kmDNSNoTunnel,
            address, kWholeV6Mask, NULL, 0,
-           zero, kZeroV6Mask, NULL, 0);
+           zero, kZeroV6Mask, NULL, 0, NULL, NULL);
 
 fin:
        if (0 <= s)
@@ -1274,9 +1142,9 @@ unaliasTunnelAddress(v6addr_t address)
                }
 
        v6addr_t zero = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-       err = doTunnelPolicy(kmDNSTunnelPolicyTeardown,
+       err = doTunnelPolicy(kmDNSTunnelPolicyTeardown, kmDNSNoTunnel,
            address, kWholeV6Mask, NULL, 0,
-           zero, kZeroV6Mask, NULL, 0);
+           zero, kZeroV6Mask, NULL, 0, NULL, NULL);
 
 fin:
        if (0 <= s)
@@ -1309,7 +1177,6 @@ do_mDNSAutoTunnelInterfaceUpDown(__unused mach_port_t port, int updown,
 fin:
 #else
        (void)port; (void)updown; (void)address; (void)token;
-       *err = kmDNSHelperIPsecDisabled;
 #endif
        update_idle_timer();
        return KERN_SUCCESS;
@@ -1349,31 +1216,24 @@ static int MacOSXSystemBuildNumber(char* letter_out, int* minor_out)
        return(major);
        }
        
-static int g_oldRacoon = -1;
-static int g_racoonSignal = SIGUSR1;
-
-static void DetermineRacoonVersion()
+static int UseOldRacoon()
        {
+       static int g_oldRacoon = -1;
+
        if (g_oldRacoon == -1)
                {
                char letter = 0;
                int minor = 0;
                g_oldRacoon = (MacOSXSystemBuildNumber(&letter, &minor) < 10);
-               if (g_oldRacoon || (letter == 'A' && minor < 218)) g_racoonSignal = SIGHUP;
-               debug("%s, signal=%d", g_oldRacoon?"old":"new", g_racoonSignal);
+               debug("%s", g_oldRacoon?"old":"new");
                }
-       }
 
-static int UseOldRacoon()
-       {
-       DetermineRacoonVersion();
        return g_oldRacoon;
        }
        
 static int RacoonSignal()
        {
-       DetermineRacoonVersion();
-       return g_racoonSignal;
+       return UseOldRacoon() ? SIGHUP : SIGUSR1;
        }
        
 static const char* GetRacoonConfigDir()
@@ -1807,7 +1667,7 @@ startRacoon(void)
        bytes = 0;
        h.cookie = 0;
        
-       while (counter < 100)
+       for (counter = 0; counter < 100; counter++)
                {
                FD_ZERO(&fds);
                FD_SET(fd, &fds);
@@ -1886,7 +1746,6 @@ do_mDNSConfigureServer(__unused mach_port_t port, int updown, const char *fqdn,
 fin:
 #else
        (void)port; (void)updown; (void)fqdn; (void)token;
-       *err = kmDNSHelperIPsecDisabled;
 #endif
        update_idle_timer();
        return KERN_SUCCESS;
@@ -2028,13 +1887,15 @@ v6addr_to_string(v6addr_t addr, char *buf, size_t buflen)
 
 /* Caller owns object returned in `policy' */
 static int
-generateTunnelPolicy(mDNSTunnelPolicyWhich which, int in,
+generateTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type, int in,
                     v4addr_t src, uint16_t src_port,
                     v4addr_t dst, uint16_t dst_port,
+                        v6addr_t src6, v6addr_t dst6,
                     ipsec_policy_t *policy, size_t *len)
        {
        char srcs[INET_ADDRSTRLEN], dsts[INET_ADDRSTRLEN];
-       char buf[128];
+       char srcs6[INET6_ADDRSTRLEN], dsts6[INET6_ADDRSTRLEN];
+       char buf[512];
        char *inOut = in ? "in" : "out";
        ssize_t n = 0;
        int err = 0;
@@ -2045,13 +1906,26 @@ generateTunnelPolicy(mDNSTunnelPolicyWhich which, int in,
        switch (which)
        {
        case kmDNSTunnelPolicySetup:
-               if (0 != (err = v4addr_to_string(src, srcs, sizeof(srcs))))
-                       goto fin;
-               if (0 != (err = v4addr_to_string(dst, dsts, sizeof(dsts))))
-                       goto fin;
-               n = snprintf(buf, sizeof(buf),
-                   "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
-                   inOut, srcs, src_port, dsts, dst_port);
+               if (type == kmDNSIPv6IPv4Tunnel)
+                       {
+                       if (0 != (err = v4addr_to_string(src, srcs, sizeof(srcs))))
+                               goto fin;
+                       if (0 != (err = v4addr_to_string(dst, dsts, sizeof(dsts))))
+                               goto fin;
+                       n = snprintf(buf, sizeof(buf),
+                       "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
+                       inOut, srcs, src_port, dsts, dst_port);
+                       }
+               else if (type == kmDNSIPv6IPv6Tunnel)
+                       {
+                       if (0 != (err = v6addr_to_string(src6, srcs6, sizeof(srcs6))))
+                               goto fin;
+                       if (0 != (err = v6addr_to_string(dst6, dsts6, sizeof(dsts6))))
+                               goto fin;
+                       n = snprintf(buf, sizeof(buf),
+                       "%s ipsec esp/tunnel/%s-%s/require",
+                       inOut, srcs6, dsts6);
+                       }
                break;
        case kmDNSTunnelPolicyTeardown:
                n = strlcpy(buf, inOut, sizeof(buf));
@@ -2145,11 +2019,12 @@ fin:
        }
 
 static int
-doTunnelPolicy(mDNSTunnelPolicyWhich which,
+doTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type,
               v6addr_t loc_inner, uint8_t loc_bits,
               v4addr_t loc_outer, uint16_t loc_port, 
               v6addr_t rmt_inner, uint8_t rmt_bits,
-              v4addr_t rmt_outer, uint16_t rmt_port)
+              v4addr_t rmt_outer, uint16_t rmt_port,
+                  v6addr_t loc_outer6, v6addr_t rmt_outer6)
        {
        struct sockaddr_in6 sin6_loc;
        struct sockaddr_in6 sin6_rmt;
@@ -2182,9 +2057,10 @@ doTunnelPolicy(mDNSTunnelPolicyWhich which,
 
        int setup = which != kmDNSTunnelPolicyTeardown;
 
-       if (0 != (err = generateTunnelPolicy(which, 1,
+       if (0 != (err = generateTunnelPolicy(which, type, 1,
            rmt_outer, rmt_port,
            loc_outer, loc_port,
+               rmt_outer6, loc_outer6,
            &policy, &len)))
                goto fin;
        if (0 != (err = sendPolicy(s, setup,
@@ -2197,9 +2073,10 @@ doTunnelPolicy(mDNSTunnelPolicyWhich which,
                free(policy);
                policy = NULL;
                }
-       if (0 != (err = generateTunnelPolicy(which, 0,
+       if (0 != (err = generateTunnelPolicy(which, type, 0,
            loc_outer, loc_port,
            rmt_outer, rmt_port,
+               loc_outer6, rmt_outer6,
            &policy, &len)))
                goto fin;
        if (0 != (err = sendPolicy(s, setup,
@@ -2208,27 +2085,50 @@ doTunnelPolicy(mDNSTunnelPolicyWhich which,
            policy, len)))
                goto fin;
 
-       if (which == kmDNSTunnelPolicyTeardown && loc_outer && rmt_outer)
+       if (which == kmDNSTunnelPolicyTeardown)
                {
-               struct sockaddr_in sin_loc;
-               struct sockaddr_in sin_rmt;
+               if (rmt_port)           // Outer tunnel is IPv4
+                       {
+                       if (loc_outer && rmt_outer)
+                               {
+                               struct sockaddr_in sin_loc;
+                               struct sockaddr_in sin_rmt;
+                               memset(&sin_loc, 0, sizeof(sin_loc));
+                               sin_loc.sin_len = sizeof(sin_loc);
+                               sin_loc.sin_family = AF_INET;
+                               memcpy(&sin_loc.sin_addr, loc_outer, sizeof(sin_loc.sin_addr));
                
-               memset(&sin_loc, 0, sizeof(sin_loc));
-               sin_loc.sin_len = sizeof(sin_loc);
-               sin_loc.sin_family = AF_INET;
-               sin_loc.sin_port = htons(0);
-               memcpy(&sin_loc.sin_addr, loc_outer, sizeof(sin_loc.sin_addr));
-
-               memset(&sin_rmt, 0, sizeof(sin_rmt));
-               sin_rmt.sin_len = sizeof(sin_rmt);
-               sin_rmt.sin_family = AF_INET;
-               sin_rmt.sin_port = htons(0);
-               memcpy(&sin_rmt.sin_addr, rmt_outer, sizeof(sin_rmt.sin_addr));
-
-               if (0 != (err = removeSA(s, (struct sockaddr *)&sin_loc, (struct sockaddr *)&sin_rmt)))
-                       goto fin;
+                               memset(&sin_rmt, 0, sizeof(sin_rmt));
+                               sin_rmt.sin_len = sizeof(sin_rmt);
+                               sin_rmt.sin_family = AF_INET;
+                               memcpy(&sin_rmt.sin_addr, rmt_outer, sizeof(sin_rmt.sin_addr));
+                               if (0 != (err = removeSA(s, (struct sockaddr *)&sin_loc, (struct sockaddr *)&sin_rmt)))
+                                       goto fin;
+                               }
+                       }
+               else
+                       {
+                       if (loc_outer6 && rmt_outer6)
+                               {
+                               struct sockaddr_in6 sin6_lo;
+                               struct sockaddr_in6 sin6_rm;
+
+                               memset(&sin6_lo, 0, sizeof(sin6_lo));
+                               sin6_lo.sin6_len = sizeof(sin6_lo);
+                               sin6_lo.sin6_family = AF_INET6;
+                               memcpy(&sin6_lo.sin6_addr, loc_outer6, sizeof(sin6_lo.sin6_addr));
+               
+                               memset(&sin6_rm, 0, sizeof(sin6_rm));
+                               sin6_rm.sin6_len = sizeof(sin6_rm);
+                               sin6_rm.sin6_family = AF_INET6;
+                               memcpy(&sin6_rm.sin6_addr, rmt_outer6, sizeof(sin6_rm.sin6_addr));
+                               if (0 != (err = removeSA(s, (struct sockaddr *)&sin6_lo, (struct sockaddr *)&sin6_rm)))
+                                       goto fin;
+                               }
+                       }
                }
 
+
        debug("succeeded");
 
 fin:
@@ -2243,8 +2143,8 @@ fin:
 
 int
 do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
-    v6addr_t loc_inner, v4addr_t loc_outer, uint16_t loc_port,
-    v6addr_t rmt_inner, v4addr_t rmt_outer, uint16_t rmt_port,
+    v6addr_t loc_inner, v6addr_t loc_outer6, uint16_t loc_port,
+    v6addr_t rmt_inner, v6addr_t rmt_outer6, uint16_t rmt_port,
     const char *fqdn, int *err, audit_token_t token)
        {
 #ifndef MDNS_NO_IPSEC
@@ -2288,11 +2188,12 @@ do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
          "  compression_algorithm deflate;\n"
          "}\n";
        char path[PATH_MAX] = "";
-       char li[INET6_ADDRSTRLEN], lo[INET_ADDRSTRLEN],
-           ri[INET6_ADDRSTRLEN], ro[INET_ADDRSTRLEN];
+       char li[INET6_ADDRSTRLEN], lo[INET_ADDRSTRLEN], lo6[INET6_ADDRSTRLEN],
+           ri[INET6_ADDRSTRLEN], ro[INET_ADDRSTRLEN], ro6[INET6_ADDRSTRLEN];
        FILE *fp = NULL;
        int fd = -1;
        char tmp_path[PATH_MAX] = "";
+       v4addr_t loc_outer, rmt_outer;
 
        debug("entry");
        *err = 0;
@@ -2310,25 +2211,60 @@ do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
                *err = kmDNSHelperInvalidTunnelSetKeysOperation;
                goto fin;
                }
+
        if (0 != (*err = v6addr_to_string(loc_inner, li, sizeof(li))))
                goto fin;
        if (0 != (*err = v6addr_to_string(rmt_inner, ri, sizeof(ri))))
                goto fin;
-       if (0 != (*err = v4addr_to_string(loc_outer, lo, sizeof(lo))))
-               goto fin;
-       if (0 != (*err = v4addr_to_string(rmt_outer, ro, sizeof(ro))))
-               goto fin;
+
        debug("loc_inner=%s rmt_inner=%s", li, ri);
-       debug("loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
-           lo, loc_port, ro, rmt_port);
+       if (!rmt_port)
+               {
+               loc_outer[0] = loc_outer[1] = loc_outer[2] = loc_outer[3] = 0;
+               rmt_outer[0] = rmt_outer[1] = rmt_outer[2] = rmt_outer[3] = 0;
 
-       if ((int)sizeof(path) <= snprintf(path, sizeof(path),
-           "%s%s.%u.conf", GetRacoonConfigDir(), ro,
-           rmt_port))
+               if (0 != (*err = v6addr_to_string(loc_outer6, lo6, sizeof(lo6))))
+                       goto fin;
+               if (0 != (*err = v6addr_to_string(rmt_outer6, ro6, sizeof(ro6))))
+                       goto fin;
+               debug("IPv6 outer tunnel: loc_outer6=%s rmt_outer6=%s", lo6, ro6);
+               if ((int)sizeof(path) <= snprintf(path, sizeof(path),
+               "%s%s.conf", GetRacoonConfigDir(), ro6))
+                       {
+                       *err = kmDNSHelperResultTooLarge;
+                       goto fin;
+                       }
+               }
+       else
                {
-               *err = kmDNSHelperResultTooLarge;
-               goto fin;
+               loc_outer[0] = loc_outer6[0];
+               loc_outer[1] = loc_outer6[1];
+               loc_outer[2] = loc_outer6[2];
+               loc_outer[3] = loc_outer6[3];
+
+               rmt_outer[0] = rmt_outer6[0];
+               rmt_outer[1] = rmt_outer6[1];
+               rmt_outer[2] = rmt_outer6[2];
+               rmt_outer[3] = rmt_outer6[3];
+
+               if (0 != (*err = v4addr_to_string(loc_outer, lo, sizeof(lo))))
+                       goto fin;
+               if (0 != (*err = v4addr_to_string(rmt_outer, ro, sizeof(ro))))
+                       goto fin;
+               debug("IPv4 outer tunnel: loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
+               lo, loc_port, ro, rmt_port);
+
+               if ((int)sizeof(path) <= snprintf(path, sizeof(path),
+               "%s%s.%u.conf", GetRacoonConfigDir(), ro,
+               rmt_port))
+                       {
+                       *err = kmDNSHelperResultTooLarge;
+                       goto fin;
+                       }
                }
+
+
+
        if (kmDNSAutoTunnelSetKeysReplace == replacedelete)
                {
                if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir()))
@@ -2357,7 +2293,7 @@ do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
                        goto fin;
                        }
                fd = -1;
-               fprintf(fp, config, configHeader, ro, rmt_port, fqdn, fqdn, ri, li, li, ri);
+               fprintf(fp, config, configHeader, (!rmt_port ? ro6 : ro), rmt_port, fqdn, fqdn, ri, li, li, ri);
                fclose(fp);
                fp = NULL;
                if (0 > rename(tmp_path, path))
@@ -2368,8 +2304,6 @@ do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
                        *err = kmDNSHelperRacoonConfigCreationFailed;
                        goto fin;
                        }
-               if (0 != (*err = kickRacoon()))
-                       goto fin;
                }
        else
                {
@@ -2378,14 +2312,14 @@ do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
                            strerror(errno));
                }
 
-       if (0 != (*err = doTunnelPolicy(kmDNSTunnelPolicyTeardown,
+       if (0 != (*err = doTunnelPolicy(kmDNSTunnelPolicyTeardown, kmDNSNoTunnel,
            loc_inner, kWholeV6Mask, loc_outer, loc_port,
-           rmt_inner, kWholeV6Mask, rmt_outer, rmt_port)))
+           rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6)))
                goto fin;
        if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
-           0 != (*err = doTunnelPolicy(kmDNSTunnelPolicySetup,
+           0 != (*err = doTunnelPolicy(kmDNSTunnelPolicySetup, (!rmt_port ? kmDNSIPv6IPv6Tunnel : kmDNSIPv6IPv4Tunnel),
                loc_inner, kWholeV6Mask, loc_outer, loc_port,
-               rmt_inner, kWholeV6Mask, rmt_outer, rmt_port)))
+               rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6)))
                goto fin;
 
        if (0 != (*err = teardownTunnelRoute(rmt_inner)))
@@ -2394,6 +2328,10 @@ do_mDNSAutoTunnelSetKeys(__unused mach_port_t port, int replacedelete,
                0 != (*err = setupTunnelRoute(loc_inner, rmt_inner)))
                goto fin;
 
+       if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
+               0 != (*err = kickRacoon()))
+               goto fin;
+
        debug("succeeded");
 
 fin:
@@ -2403,8 +2341,8 @@ fin:
                close(fd);
        unlink(tmp_path);
 #else
-       (void)replacedelete; (void)loc_inner; (void)loc_outer; (void)loc_port; (void)rmt_inner;
-       (void)rmt_outer; (void)rmt_port; (void)keydata; (void)token;
+       (void)replacedelete; (void)loc_inner; (void)loc_outer6; (void)loc_port; (void)rmt_inner;
+       (void)rmt_outer6; (void)rmt_port; (void)fqdn; (void)token;
        
        *err = kmDNSHelperIPsecDisabled;
 #endif /* MDNS_NO_IPSEC */
index ac974a5345d17cf7ad3f709abd4f232a6bc83fa9..7bf8f495dce905d86070de9e558656c915b26ec0 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: helper.h,v $
-Revision 1.18  2009/04/20 20:40:14  cheshire
-<rdar://problem/6786150> uDNS: Running location cycling caused configd and mDNSResponder to deadlock
-Changed mDNSPreferencesSetName (and similar) routines from MIG "routine" to MIG "simpleroutine"
-so we don't deadlock waiting for a result that we're just going to ignore anyway
-
-Revision 1.17  2009/03/20 22:12:28  mcguire
-<rdar://problem/6703952> Support CFUserNotificationDisplayNotice in mDNSResponderHelper
-Make the call to the helper a simpleroutine: don't wait for an unused return value
-
-Revision 1.16  2009/03/20 20:52:22  cheshire
-<rdar://problem/6703952> Support CFUserNotificationDisplayNotice in mDNSResponderHelper
-
-Revision 1.15  2009/03/14 01:42:56  mcguire
-<rdar://problem/5457116> BTMM: Fix issues with multiple .Mac accounts on the same machine
-
-Revision 1.14  2009/01/22 02:14:27  cheshire
-<rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
-
-Revision 1.13  2009/01/14 01:38:43  mcguire
-<rdar://problem/6492710> Write out DynamicStore per-interface SleepProxyServer info
-
-Revision 1.12  2009/01/12 22:26:13  mkrochma
-Change DynamicStore location from BonjourSleepProxy/DiscoveredServers to SleepProxyServers
-
-Revision 1.11  2008/12/05 02:35:24  mcguire
-<rdar://problem/6107390> Write to the DynamicStore when a Sleep Proxy server is available on the network
-
-Revision 1.10  2008/11/04 23:54:09  cheshire
-Added routine mDNSSetARP(), used to replace an SPS client's entry in our ARP cache with
-a dummy one, so that IP traffic to the SPS client initiated by the SPS machine can be
-captured by our BPF filters, and used as a trigger to wake the sleeping machine.
-
-Revision 1.9  2008/10/24 01:42:36  cheshire
-Added mDNSPowerRequest helper routine to request a scheduled wakeup some time in the future
-
-Revision 1.8  2008/10/20 22:01:28  cheshire
-Made new Mach simpleroutine "mDNSRequestBPF"
-
-Revision 1.7  2008/09/27 00:58:11  cheshire
-Added mDNSRequestBPF declaration
-
-Revision 1.6  2007/09/20 22:33:17  cheshire
-Tidied up inconsistent and error-prone naming -- used to be mDNSResponderHelper in
-some places and mDNSResponder.helper in others; now mDNSResponderHelper everywhere
-
-Revision 1.5  2007/09/07 22:44:03  mcguire
-<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
-
-Revision 1.4  2007/09/04 22:32:58  mcguire
-<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
-
-Revision 1.3  2007/08/23 21:51:44  cheshire
-Made code layout style consistent with existing project style; added $Log header
-
-Revision 1.1  2007/08/08 22:34:58  mcguire
-<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
  */
 
 #ifndef H_HELPER_H
@@ -123,7 +63,7 @@ extern const char *mDNSHelperError(int errornum);
 
 extern void mDNSRequestBPF(void);
 extern int  mDNSPowerRequest(int key, int interval);
-extern int  mDNSSetARP(int ifindex, const v4addr_t ip, const ethaddr_t eth);
+extern int  mDNSSetLocalAddressCacheEntry(int ifindex, int family, const v6addr_t ip, const ethaddr_t eth);
 extern void mDNSNotify(const char *title, const char *msg);            // Both strings are UTF-8 text
 extern void mDNSDynamicStoreSetConfig(int key, const char *subkey, CFPropertyListRef value);
 extern void mDNSPreferencesSetName(int key, domainlabel *old, domainlabel *new);
@@ -131,7 +71,7 @@ extern int  mDNSKeychainGetSecrets(CFArrayRef *secrets);
 extern void mDNSAutoTunnelInterfaceUpDown(int updown, v6addr_t addr);
 extern void mDNSConfigureServer(int updown, const domainname *const fqdn);
 extern int  mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner,
-                               v4addr_t local_outer, short local_port, v6addr_t remote_inner,
-                               v4addr_t remote_outer, short remote_port, const domainname *const fqdn);
+                               v6addr_t local_outer, short local_port, v6addr_t remote_inner,
+                               v6addr_t remote_outer, short remote_port, const domainname *const fqdn);
 
 #endif /* H_HELPER_H */
index 07539d2848c5f851afa612bc1a69dea821a1f990..8e36635242905d927b7e2cfb6807d145d5c1fd23 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: helpermsg-types.h,v $
-Revision 1.3  2009/01/22 02:14:27  cheshire
-<rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
-
-Revision 1.2  2007/08/23 21:52:19  cheshire
-Added License header
-
-Revision 1.1  2007/08/08 22:34:58  mcguire
-<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
  */
 
 #ifndef H_HELPERMSG_TYPES_H
index 0c2d1724621234f3d58a13c0976219d535662255..ad946a3d6dc2f1283ab97215ab4e9ff8af4de0e2 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: helpermsg.defs,v $
-Revision 1.17  2009/04/20 20:40:14  cheshire
-<rdar://problem/6786150> uDNS: Running location cycling caused configd and mDNSResponder to deadlock
-Changed mDNSPreferencesSetName (and similar) routines from MIG "routine" to MIG "simpleroutine"
-so we don't deadlock waiting for a result that we're just going to ignore anyway
-
-Revision 1.16  2009/03/20 22:12:28  mcguire
-<rdar://problem/6703952> Support CFUserNotificationDisplayNotice in mDNSResponderHelper
-Make the call to the helper a simpleroutine: don't wait for an unused return value
-
-Revision 1.15  2009/03/20 20:52:22  cheshire
-<rdar://problem/6703952> Support CFUserNotificationDisplayNotice in mDNSResponderHelper
-
-Revision 1.14  2009/03/14 01:42:56  mcguire
-<rdar://problem/5457116> BTMM: Fix issues with multiple .Mac accounts on the same machine
-
-Revision 1.13  2009/01/22 02:14:26  cheshire
-<rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
-
-Revision 1.12  2009/01/14 01:38:43  mcguire
-<rdar://problem/6492710> Write out DynamicStore per-interface SleepProxyServer info
-
-Revision 1.11  2008/11/04 23:54:09  cheshire
-Added routine mDNSSetARP(), used to replace an SPS client's entry in our ARP cache with
-a dummy one, so that IP traffic to the SPS client initiated by the SPS machine can be
-captured by our BPF filters, and used as a trigger to wake the sleeping machine.
-
-Revision 1.10  2008/10/24 01:42:36  cheshire
-Added mDNSPowerRequest helper routine to request a scheduled wakeup some time in the future
-
-Revision 1.9  2008/10/20 22:01:28  cheshire
-Made new Mach simpleroutine "mDNSRequestBPF"
-
-Revision 1.8  2008/09/26 21:18:13  cheshire
-Tidy up code layout
-
-Revision 1.7  2008/08/13 23:04:06  mcguire
-<rdar://problem/5858535> handle SIGTERM in mDNSResponderHelper
-Preparation: rename message function, as it will no longer be called only on idle exit
-
-Revision 1.6  2007/09/07 22:44:03  mcguire
-<rdar://problem/5448420> Move CFUserNotification code to mDNSResponderHelper
-
-Revision 1.5  2007/09/04 22:32:58  mcguire
-<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
-
-Revision 1.4  2007/08/23 21:53:13  cheshire
-Added $Log header
-
-Revision 1.3  2007/08/18 01:02:03  mcguire
-<rdar://problem/5415593> No Bonjour services are getting registered at boot
-
-Revision 1.2  2007/08/15 23:20:28  mcguire
-<rdar://problem/5408105> BTMM: racoon files can get corrupted if autotunnel is listening on port > 32767
-
-Revision 1.1  2007/08/08 22:34:58  mcguire
-<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
  */
 
 #include <mach/std_types.defs>
@@ -101,9 +41,11 @@ routine mDNSPowerRequest(           port                    : mach_port_t;
                out                                             err                             : int;
                ServerAuditToken                token                   : audit_token_t);
 
-routine mDNSSetARP(                            port                    : mach_port_t;
+routine mDNSSetLocalAddressCacheEntry(
+                                                               port                    : mach_port_t;
                                                                ifindex                 : int;
-                                                               ip                              : v4addr_t;
+                                                               family                  : int;
+                                                               ip                              : v6addr_t;
                                                                eth                             : ethaddr_t;
                out                                             err                             : int;
                ServerAuditToken                token                   : audit_token_t);
@@ -120,7 +62,8 @@ simpleroutine mDNSDynamicStoreSetConfig(
                                                                value                   : pointer_t;
                ServerAuditToken                token                   : audit_token_t);
 
-simpleroutine mDNSPreferencesSetName( port                     : mach_port_t;
+simpleroutine mDNSPreferencesSetName(
+                                                               port                    : mach_port_t;
                                                                key                             : int;
                                                                old                             : string_t;
                                                                new                             : string_t;
@@ -138,7 +81,8 @@ simpleroutine mDNSAutoTunnelInterfaceUpDown(
                                                                address                 : v6addr_t;
                ServerAuditToken                token                   : audit_token_t);
 
-simpleroutine mDNSConfigureServer(     port                    : mach_port_t;
+simpleroutine mDNSConfigureServer(
+                                                               port                    : mach_port_t;
                                                                updown                  : int;
                                                                fqdn                    : string_t;
                ServerAuditToken                token                   : audit_token_t);
@@ -146,11 +90,11 @@ simpleroutine mDNSConfigureServer( port                    : mach_port_t;
 routine mDNSAutoTunnelSetKeys( port                    : mach_port_t;
                                                                replacedelete   : int;
                                                                local_inner             : v6addr_t;
-                                                               local_outer             : v4addr_t;
-                                                               local_port              : uint16_t;
+                                                               local_outer             : v6addr_t;
+                                                               local_port              : uint16_t;             /* Port expressed as a numeric integer value */
                                                                remote_inner    : v6addr_t;
-                                                               remote_outer    : v4addr_t;
-                                                               remote_port             : uint16_t;
+                                                               remote_outer    : v6addr_t;
+                                                               remote_port             : uint16_t;             /* Port expressed as a numeric integer value */
                                                                fqdn                    : string_t;
                out                                             err                             : int;
                ServerAuditToken                token                   : audit_token_t);
index f621c696e2629fbb32aa04af3186b13f1105c670..6b59caa1b87dff880b0d4aaedb3bc5ade359e8ec 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
 
-    Change History (most recent first):
-
-$Log: mDNSMacOSX.c,v $
-Revision 1.691  2009/07/30 20:28:15  mkrochma
-<rdar://problem/7100784> Sleep Proxy: Structure changes to data passed to userclient
-
-Revision 1.690  2009/07/15 22:34:25  cheshire
-<rdar://problem/6613674> Sleep Proxy: Add support for using sleep proxy in local network interface hardware
-Fixes to make the code still compile with old headers and libraries (pre 10.5) that don't include IOConnectCallStructMethod
-
-Revision 1.689  2009/07/15 22:09:19  cheshire
-<rdar://problem/6613674> Sleep Proxy: Add support for using sleep proxy in local network interface hardware
-Removed unnecessary sleep(1) and syslog message
-
-Revision 1.688  2009/07/11 01:58:17  cheshire
-<rdar://problem/6613674> Sleep Proxy: Add support for using sleep proxy in local network interface hardware
-Added ActivateLocalProxy routine for transferring mDNS records to local proxy
-
-Revision 1.687  2009/06/30 21:16:09  cheshire
-<rdar://problem/7020041> Plugging and unplugging the power cable shouldn't cause a network change event
-Additional fix: Only start and stop NetWake browses for active interfaces that are currently registered with mDNSCore
-
-Revision 1.686  2009/06/25 23:36:56  cheshire
-To facilitate testing, added command-line switch "-OfferSleepProxyService"
-to re-enable the previously-supported mode of operation where we offer
-sleep proxy service on desktop Macs that are set to never sleep.
-
-Revision 1.685  2009/06/25 23:15:12  cheshire
-Don't try to use private header file "IOPowerSourcesPrivate.h"
-(it prevents external developers from being able to compile the code)
-
-Revision 1.684  2009/06/24 22:14:22  cheshire
-<rdar://problem/6911445> Plugging and unplugging the power cable shouldn't cause a network change event
-
-Revision 1.683  2009/06/08 22:31:03  cheshire
-Fixed typo in comment: Portability > 35 means nominal weight < 3kg
-
-Revision 1.682  2009/05/19 23:30:31  cheshire
-Suppressed some unnecessary debugging messages; added AppleTV to list of recognized hardware
-
-Revision 1.681  2009/05/12 23:23:15  cheshire
-Removed unnecessary "mDNSPlatformTCPConnect - connect failed ... Error 50 (Network is down)" debugging message
+// ***************************************************************************
+// mDNSMacOSX.c:
+// Supporting routines to run mDNS on a CFRunLoop platform
+// ***************************************************************************
 
-Revision 1.680  2009/05/05 01:32:50  jessic2
-<rdar://problem/6830541> regservice_callback: instance->request is NULL 0 -- Clean up spurious logs resulting from fixing this bug.
+// For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
+// including ones that mDNSResponder chooses not to use.
+#define LIST_ALL_INTERFACES 0
 
-Revision 1.679  2009/05/01 23:48:46  jessic2
-<rdar://problem/6830541> regservice_callback: instance->request is NULL 0
+// For enabling AAAA records over IPv4. Setting this to 0 sends only
+// A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
+// AAAA and A records over both IPv4 and IPv6.
+#define AAAA_OVER_V4 1
 
-Revision 1.678  2009/04/24 23:32:28  cheshire
-To facilitate testing, put back code to be a sleep proxy when set to never sleep, compiled out by compile-time switch
+// In Mac OS X 10.4 and earlier, to reduce traffic, we would send and receive using IPv6 only on interfaces that had no routable
+// IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
+// which means there's a good chance that most or all the other devices on that network should also have IPv4.
+// By doing this we lost the ability to talk to true IPv6-only devices on that link, but we cut the packet rate in half.
+// At that time, reducing the packet rate was more important than v6-only devices on a large configured network,
+// so were willing to make that sacrifice.
+// In Mac OS X 10.5, in 2007, two things have changed:
+// 1. IPv6-only devices are starting to become more common, so we can't ignore them.
+// 2. Other efficiency improvements in the code mean that crude hacks like this should no longer be necessary.
 
-Revision 1.677  2009/04/24 20:50:16  mcguire
-<rdar://problem/6791775> 4 second delay in DNS response
+#define USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 0
 
-Revision 1.676  2009/04/24 02:17:58  mcguire
-<rdar://problem/5264124> uDNS: Not always respecting preference order of DNS servers
+#include "mDNSEmbeddedAPI.h"           // Defines the interface provided to the client layer above
+#include "DNSCommon.h"
+#include "uDNS.h"
+#include "mDNSMacOSX.h"                                // Defines the specific types needed to run mDNS on this platform
+#include "dns_sd.h"                                    // For mDNSInterface_LocalOnly etc.
+#include "PlatformCommon.h"
+#include "uds_daemon.h"
+#include <CoreServices/CoreServices.h>
 
-Revision 1.675  2009/04/23 18:51:28  mcguire
-<rdar://problem/6729406> uDNS: PPP doesn't automatically reconnect on wake from sleep (no name resolver)
+#include <stdio.h>
+#include <stdarg.h>                 // For va_list support
+#include <stdlib.h>                 // For arc4random
+#include <net/if.h>
+#include <net/if_types.h>                      // For IFT_ETHER
+#include <net/if_dl.h>
+#include <net/bpf.h>                           // For BIOCSETIF etc.
+#include <sys/uio.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/event.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <time.h>                   // platform support for UTC time
+#include <arpa/inet.h>              // for inet_aton
+#include <pthread.h>
 
-Revision 1.674  2009/04/23 00:58:01  jessic2
-<rdar://problem/6802117> uDNS: DNS stops working after configd crashes
+#include <netinet/in.h>             // For IP_RECVTTL
+#ifndef IP_RECVTTL
+#define IP_RECVTTL 24               // bool; receive reception TTL w/dgram
+#endif
 
-Revision 1.673  2009/04/22 01:19:57  jessic2
-<rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32
+#include <netinet/in_systm.h>       // For n_long, required by <netinet/ip.h> below
+#include <netinet/ip.h>             // For IPTOS_LOWDELAY etc.
+#include <netinet6/in6_var.h>       // For IN6_IFF_NOTREADY etc.
+#include <netinet6/nd6.h>           // For ND6_INFINITE_LIFETIME etc.
 
-Revision 1.672  2009/04/21 16:34:47  mcguire
-<rdar://problem/6810663> null deref in mDNSPlatformSetDNSConfig
+#if TARGET_OS_EMBEDDED
+#define NO_SECURITYFRAMEWORK 1
+#define NO_CFUSERNOTIFICATION 1
+#endif
 
-Revision 1.671  2009/04/15 01:14:07  mcguire
-<rdar://problem/6791775> 4 second delay in DNS response
+#ifndef NO_SECURITYFRAMEWORK
+#include <Security/SecureTransport.h>
+#include <Security/Security.h>
+#endif /* NO_SECURITYFRAMEWORK */
 
-Revision 1.670  2009/04/15 01:10:39  jessic2
-<rdar://problem/6466541> BTMM: Add support for setting kDNSServiceErr_NoSuchRecord in DynamicStore
+#include <DebugServices.h>
+#include "dnsinfo.h"
 
-Revision 1.669  2009/04/11 02:02:34  mcguire
-<rdar://problem/6780046> crash in doSSLHandshake
+// Code contributed by Dave Heller:
+// Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
+// work on Mac OS X 10.1, which does not have the getifaddrs call.
+#define RUN_ON_PUMA_WITHOUT_IFADDRS 0
+#if RUN_ON_PUMA_WITHOUT_IFADDRS
+#include "mDNSMacOSXPuma.c"
+#else
+#include <ifaddrs.h>
+#endif
 
-Revision 1.668  2009/04/11 00:20:08  jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOMessage.h>
 
-Revision 1.667  2009/04/09 20:01:00  cheshire
-<rdar://problem/6767122> IOPMCopyActivePMPreferences not available on Apple TV
-At Rory's suggestion, removed unnecessary "Could not get Wake On LAN value" log message
+#ifdef __LIB_DISPATCH__
+// This is currently defined in IOKit/PrivateHeaders/IOKitLibPrivate.h. Till it becomes an Public
+// API, we will have our own declaration
+void IONotificationPortSetDispatchQueue(IONotificationPortRef notify, dispatch_queue_t queue);
+#endif
 
-Revision 1.666  2009/04/07 21:57:53  cheshire
-<rdar://problem/6767122> IOPMCopyActivePMPreferences not available on Apple TV
-Put previous code back
+#if USE_IOPMCOPYACTIVEPMPREFERENCES
+#include <IOKit/ps/IOPowerSources.h>
+#include <IOKit/ps/IOPowerSourcesPrivate.h>
+#endif
 
-Revision 1.665  2009/04/03 21:48:44  mcguire
-Back out checkin 1.664 (<rdar://problem/6755199> MessageTracer: prepend domain to make signature field unique)
+#include <mach/mach_error.h>
+#include <mach/mach_port.h>
+#include <mach/mach_time.h>
+#include "helper.h"
 
-Revision 1.663  2009/04/02 22:21:16  mcguire
-<rdar://problem/6577409> Adopt IOPM APIs
+#include <asl.h>
 
-Revision 1.662  2009/04/02 01:08:15  mcguire
-<rdar://problem/6735635> Don't be a sleep proxy when set to sleep never
+#if APPLE_OSX_mDNSResponder
+#include <DeviceToDeviceManager/DeviceToDeviceManager.h>
+#include <AWACS.h>
 
-Revision 1.661  2009/04/01 17:50:14  mcguire
-cleanup mDNSRandom
+#if ! NO_D2D
+D2DStatus D2DInitialize(CFRunLoopRef runLoop, D2DServiceCallback serviceCallback, void* userData) __attribute__((weak_import));
+D2DStatus D2DTerminate() __attribute__((weak_import));
+D2DStatus D2DStartAdvertisingPair(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize) __attribute__((weak_import));
+D2DStatus D2DStopAdvertisingPair(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize) __attribute__((weak_import));
+D2DStatus D2DStartBrowsingForKey(const Byte *key, const size_t keySize) __attribute__((weak_import));
+D2DStatus D2DStopBrowsingForKey(const Byte *key, const size_t keySize) __attribute__((weak_import));
+void D2DStartResolvingPair(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize) __attribute__((weak_import));
+void D2DStopResolvingPair(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize) __attribute__((weak_import));
+D2DStatus D2DRetain(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import));
+D2DStatus D2DRelease(D2DServiceInstance instanceHandle, D2DTransportType transportType) __attribute__((weak_import));
 
-Revision 1.660  2009/04/01 01:13:10  mcguire
-<rdar://problem/6744276> Sleep Proxy: Detect lid closed
+#define CHECK_D2D_FUNCTION(X) if (X)
 
-Revision 1.659  2009/03/30 21:11:07  jessic2
-<rdar://problem/6728725> Need to do some polish work on MessageTracer logging
+#endif // ! NO_D2D
 
-Revision 1.658  2009/03/30 20:07:28  mcguire
-<rdar://problem/6736133> BTMM: SSLHandshake threads are leaking Mach ports
+#else
+#define NO_D2D 1
+#define NO_AWACS 1
+#endif // APPLE_OSX_mDNSResponder
 
-Revision 1.657  2009/03/27 17:27:13  cheshire
-<rdar://problem/6724859> Need to support querying IPv6 DNS servers
+#define kInterfaceSpecificOption "interface="
 
-Revision 1.656  2009/03/26 05:02:48  mcguire
-fix build error in dnsextd
+// ***************************************************************************
+// Globals
 
-Revision 1.655  2009/03/26 03:59:00  jessic2
-Changes for <rdar://problem/6492552&6492593&6492609&6492613&6492628&6492640&6492699>
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark - Globals
+#endif
 
-Revision 1.654  2009/03/20 20:53:26  cheshire
-Added test code for testing with MacBook Air, using a USB dongle that doesn't actually support Wake-On-LAN
+// By default we don't offer sleep proxy service
+// If OfferSleepProxyService is set non-zero (typically via command-line switch),
+// then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
+// We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
+mDNSexport int OfferSleepProxyService = 0;
+mDNSexport int DisableSleepProxyClient = 0;
 
-Revision 1.653  2009/03/20 20:52:22  cheshire
-<rdar://problem/6703952> Support CFUserNotificationDisplayNotice in mDNSResponderHelper
+// We disable inbound relay connection if this value is set to true (typically via command-line switch).
+mDNSBool DisableInboundRelayConnection = mDNSfalse;
+mDNSexport int OSXVers;
+mDNSexport int KQueueFD;
 
-Revision 1.652  2009/03/19 23:44:47  mcguire
-<rdar://problem/6699216> Properly handle EADDRINUSE
+#ifndef NO_SECURITYFRAMEWORK
+static CFArrayRef ServerCerts;
+OSStatus SSLSetAllowAnonymousCiphers(SSLContextRef context, Boolean enable);
+#endif /* NO_SECURITYFRAMEWORK */
 
-Revision 1.651  2009/03/17 19:15:24  mcguire
-<rdar://problem/6655415> SSLHandshake deadlock issues
+static CFStringRef NetworkChangedKey_IPv4;
+static CFStringRef NetworkChangedKey_IPv6;
+static CFStringRef NetworkChangedKey_Hostnames;
+static CFStringRef NetworkChangedKey_Computername;
+static CFStringRef NetworkChangedKey_DNS;
+static CFStringRef NetworkChangedKey_DynamicDNS       = CFSTR("Setup:/Network/DynamicDNS");
+static CFStringRef NetworkChangedKey_BackToMyMac      = CFSTR("Setup:/Network/BackToMyMac");
+static CFStringRef NetworkChangedKey_BTMMConnectivity = CFSTR("State:/Network/Connectivity");
+static CFStringRef NetworkChangedKey_PowerSettings    = CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
 
-Revision 1.650  2009/03/17 01:24:22  cheshire
-Updated to new Sleep Proxy metric ranges: 100000-999999; 1000000 means "do not use"
+static char  HINFO_HWstring_buffer[32];
+static char *HINFO_HWstring = "Device";
+static int   HINFO_HWstring_prefixlen = 6;
 
-Revision 1.649  2009/03/15 01:30:29  mcguire
-fix log message
+mDNSexport int WatchDogReportingThreshold = 250;
 
-Revision 1.648  2009/03/15 01:16:08  mcguire
-<rdar://problem/6655415> SSLHandshake deadlock issues
+#ifdef __LIB_DISPATCH__
+dispatch_queue_t SSLqueue;
+#endif
 
-Revision 1.647  2009/03/14 01:42:56  mcguire
-<rdar://problem/5457116> BTMM: Fix issues with multiple .Mac accounts on the same machine
+#if APPLE_OSX_mDNSResponder
+static mDNSu8 SPMetricPortability   = 99;
+static mDNSu8 SPMetricMarginalPower = 99;
+static mDNSu8 SPMetricTotalPower    = 99;
+mDNSexport domainname ActiveDirectoryPrimaryDomain;
+mDNSexport int        ActiveDirectoryPrimaryDomainLabelCount;
+mDNSexport mDNSAddr   ActiveDirectoryPrimaryDomainServer;
+#endif // APPLE_OSX_mDNSResponder
 
-Revision 1.646  2009/03/13 01:36:24  mcguire
-<rdar://problem/6657640> Reachability fixes on DNS config change
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - D2D Support
+#endif
 
-Revision 1.645  2009/03/10 23:48:33  cheshire
-<rdar://problem/6665739> Task scheduling failure when Sleep Proxy Server is active
+#if ! NO_D2D
 
-Revision 1.644  2009/03/10 04:17:09  cheshire
-Check for NULL answer in UpdateSPSStatus()
+// Name compression items for fake packet version number 1
+static const mDNSu8 compression_packet_v1 = 0x01;
 
-Revision 1.643  2009/03/10 01:15:55  cheshire
-Sleep Proxies with invalid names (score 10000) need to be ignored
+static DNSMessage compression_base_msg = { { {{0}}, {{0}}, 2, 0, 0, 0 }, "\x04_tcp\x05local\x00\x00\x0C\x00\x01\x04_udp\xC0\x11\x00\x0C\x00\x01" };
+static mDNSu8 *const compression_limit = (mDNSu8 *) &compression_base_msg + sizeof(DNSMessage);
+static mDNSu8 *const compression_lhs = (mDNSu8 *const) compression_base_msg.data + 27;
 
-Revision 1.642  2009/03/08 04:46:51  mkrochma
-Change Keychain LogMsg to LogInfo
+mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
+mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len);
 
-Revision 1.641  2009/03/05 23:53:34  cheshire
-Removed spurious "SnowLeopardPowerChanged: wake ERROR" syslog message
+static ARListElem *D2DRecords = NULL; // List of locally-generated PTR records to records found via D2D
 
-Revision 1.640  2009/03/05 21:57:13  cheshire
-Don't close BPF fd until we have no more records we're proxying for on that interface
+typedef struct D2DBrowseListElem
+       {
+       struct D2DBrowseListElem *next;
+       domainname name;
+       mDNSu16 type;
+       unsigned int refCount;
+       } D2DBrowseListElem;
 
-Revision 1.639  2009/03/04 01:45:01  cheshire
-HW_MODEL information should be LogSPS, not LogMsg
+D2DBrowseListElem* D2DBrowseList = NULL;
 
-Revision 1.638  2009/03/03 22:51:54  cheshire
-<rdar://problem/6504236> Sleep Proxy: Waking on same network but different interface will cause conflicts
+mDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
+       {
+       ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF);
+       ptr[1] = (mDNSu8)((val      ) & 0xFF);
+       return ptr + sizeof(mDNSu16);
+       }
 
-Revision 1.637  2009/02/26 22:58:47  cheshire
-<rdar://problem/6616335> Crash in mDNSResponder at mDNSResponder • CloseBPF + 75
-Fixed race condition between the kqueue thread and the CFRunLoop thread.
+mDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val)
+       {
+       ptr[0] = (mDNSu8)((val >> 24) & 0xFF);
+       ptr[1] = (mDNSu8)((val >> 16) & 0xFF);
+       ptr[2] = (mDNSu8)((val >>  8) & 0xFF);
+       ptr[3] = (mDNSu8)((val      ) & 0xFF);
+       return ptr + sizeof(mDNSu32);
+       }
 
-Revision 1.636  2009/02/21 01:38:39  cheshire
-Added comment: mDNSCoreMachineSleep(m, false); // Will set m->SleepState = SleepState_Awake;
+mDNSlocal void DomainnameToLower(const domainname * const in, domainname * const out)
+       {
+       const mDNSu8 * const start = (const mDNSu8 * const)in;
+       mDNSu8 *ptr = (mDNSu8*)start;
+       while(*ptr)
+               {
+               mDNSu8 c = *ptr;
+               out->c[ptr-start] = *ptr;
+               ptr++;
+               for (;c;c--,ptr++) out->c[ptr-start] = mDNSIsUpperCase(*ptr) ? (*ptr - 'A' + 'a') : *ptr;
+               }
+       out->c[ptr-start] = *ptr;
+       }
 
-Revision 1.635  2009/02/17 23:29:03  cheshire
-Throttle logging to a slower rate when running on SnowLeopard
+mDNSlocal mStatus DNSNameCompressionParseBytes(mDNS *const m, const mDNSu8 *const lhs, const mDNSu16 lhs_len, const mDNSu8 *const rhs, const mDNSu16 rhs_len, AuthRecord *rr)
+       {
+       if (mDNS_LoggingEnabled)
+               {
+               LogInfo("%s", __func__);
+               LogInfo("  Static Bytes: ");
+               PrintHex((mDNSu8*)&compression_base_msg, compression_lhs - (mDNSu8*)&compression_base_msg);
+               }
+       
+       mDNSu8 *ptr = compression_lhs; // pointer to the end of our fake packet
 
-Revision 1.634  2009/02/14 00:29:17  mcguire
-fixed typo
+       // Check to make sure we're not going to go past the end of the DNSMessage data
+       // 7 = 2 for CLASS (-1 for our version) + 4 for TTL + 2 for RDLENGTH
+       if (ptr + lhs_len - 7 + rhs_len >= compression_limit) return mStatus_NoMemoryErr;
+       
+       // Copy the LHS onto our fake wire packet
+       mDNSPlatformMemCopy(ptr, lhs, lhs_len);
+       ptr += lhs_len - 1;
+       
+       // Check the 'fake packet' version number, to ensure that we know how to decompress this data
+       if (*ptr != compression_packet_v1) return mStatus_Incompatible;
+       
+       // two bytes of CLASS
+       ptr = putVal16(ptr, kDNSClass_IN | kDNSClass_UniqueRRSet);
+       
+       // four bytes of TTL
+       ptr = putVal32(ptr, 120);
+       
+       // Copy the RHS length into the RDLENGTH of our fake wire packet
+       ptr = putVal16(ptr, rhs_len);
+       
+       // Copy the RHS onto our fake wire packet
+       mDNSPlatformMemCopy(ptr, rhs, rhs_len);
+       ptr += rhs_len;
+       
+       if (mDNS_LoggingEnabled)
+               {
+               LogInfo("  Our Bytes %d: ", __LINE__);
+               PrintHex(compression_lhs, ptr - compression_lhs);
+               }
 
-Revision 1.633  2009/02/14 00:07:11  cheshire
-Need to set up m->SystemWakeOnLANEnabled before calling UpdateInterfaceList(m, utc);
+       ptr = (mDNSu8 *) GetLargeResourceRecord(m, &compression_base_msg, compression_lhs, ptr, mDNSInterface_Any, kDNSRecordTypePacketAns, &m->rec);
+       if (!ptr || m->rec.r.resrec.RecordType == kDNSRecordTypePacketNegative)
+               { LogMsg("DNSNameCompressionParseBytes: failed to get large RR"); m->rec.r.resrec.RecordType = 0; return mStatus_UnknownErr; }
+       else LogInfo("DNSNameCompressionParseBytes: got rr: %s", CRDisplayString(m, &m->rec.r));        
 
-Revision 1.632  2009/02/13 19:40:07  cheshire
-Improved alignment of LogSPS messages
+       mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_P2P, m->rec.r.resrec.rrtype, 7200, kDNSRecordTypeShared, FreeD2DARElemCallback, NULL);
+       AssignDomainName(&rr->namestorage, &m->rec.namestorage);
+       rr->resrec.rdlength = m->rec.r.resrec.rdlength;
+       rr->resrec.rdata->MaxRDLength = m->rec.r.resrec.rdlength;
+       mDNSPlatformMemCopy(rr->resrec.rdata->u.data, m->rec.r.resrec.rdata->u.data, m->rec.r.resrec.rdlength);
+       rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
+       SetNewRData(&rr->resrec, mDNSNULL, 0);  // Sets rr->rdatahash for us
+       
+       m->rec.r.resrec.RecordType = 0; // Mark m->rec as no longer in use
 
-Revision 1.631  2009/02/13 18:16:05  cheshire
-Fixed some compile warnings
+       return mStatus_NoError;
+       }
 
-Revision 1.630  2009/02/13 06:32:43  cheshire
-Converted LogOperation messages to LogInfo or LogSPS
+mDNSlocal mDNSu8 * DNSNameCompressionBuildLHS(const domainname const *typeDomain, DNS_TypeValues qtype)
+       {
+       mDNSu8 *ptr = putDomainNameAsLabels(&compression_base_msg, compression_lhs, compression_limit, typeDomain);
+       if (!ptr) return ptr;
+       *ptr = (qtype >> 8) & 0xff;
+       ptr += 1;
+       *ptr = qtype & 0xff;
+       ptr += 1;
+       *ptr = compression_packet_v1;
+       return ptr + 1;
+       }
 
-Revision 1.629  2009/02/12 20:57:26  cheshire
-Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
+mDNSlocal mDNSu8 * DNSNameCompressionBuildRHS(mDNSu8 *start, const ResourceRecord *const resourceRecord)
+       {
+       return putRData(&compression_base_msg, start, compression_limit, resourceRecord);
+       }
 
-Revision 1.628  2009/02/11 02:34:45  cheshire
-m->p->SystemWakeForNetworkAccessEnabled renamed to m->SystemWakeOnLANEnabled
+mDNSlocal void PrintHex(mDNSu8 *data, mDNSu16 len)
+       {
+       mDNSu8 *end = data + len;
+       char buffer[49] = {0};
+       char *bufend = buffer + sizeof(buffer);
+       while(data<end)
+               {
+               char *ptr = buffer;
+               for(; data < end && ptr < bufend-1; ptr+=3,data++)
+                       mDNS_snprintf(ptr, bufend - ptr, "%02X ", *data);
+               LogInfo("    %s", buffer);
+               }
+       }
 
-Revision 1.627  2009/02/10 00:19:17  cheshire
-<rdar://problem/6107426> Sleep Proxy: Adopt SIOCGIFWAKEFLAGS ioctl to determine interface WOMP-ability
+mDNSlocal void PrintHelper(const char *const tag, mDNSu8 *lhs, mDNSu16 lhs_len, mDNSu8 *rhs, mDNSu16 rhs_len)
+       {
+       if (!mDNS_LoggingEnabled) return;
+       
+       LogInfo("%s:", tag);
+       LogInfo("  LHS: ");
+       PrintHex(lhs, lhs_len);
+       
+       if (!rhs) return;
+       
+       LogInfo("  RHS: ");
+       PrintHex(rhs, rhs_len);
+       }
 
-Revision 1.626  2009/02/10 00:15:38  cheshire
-<rdar://problem/6551529> Sleep Proxy: "Unknown DNS packet type 8849" logs
+mDNSlocal void FreeD2DARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
+       {
+       (void)m;  // unused
+       if (result == mStatus_MemFree)
+               {
+               ARListElem **ptr = &D2DRecords;
+               ARListElem *tmp;
+               while (*ptr && &(*ptr)->ar != rr) ptr = &(*ptr)->next;
+               if (!*ptr) { LogMsg("FreeD2DARElemCallback: Could not find in D2DRecords: %s", ARDisplayString(m, rr)); return; }
+               LogInfo("FreeD2DARElemCallback: Found in D2DRecords: %s", ARDisplayString(m, rr));
+               tmp = *ptr;
+               *ptr = (*ptr)->next;
+               // Just because we stoppped browsing, doesn't mean we should tear down the PAN connection.
+               mDNSPlatformMemFree(tmp);
+               }
+       }
 
-Revision 1.625  2009/02/09 21:24:25  cheshire
-Set correct bit in ifr.ifr_wake_flags (was coincidentally working because IF_WAKE_ON_MAGIC_PACKET happens to have the value 1)
+mDNSlocal void xD2DClearCache(mDNS *const m, const domainname *regType)
+       {
+       ARListElem *ptr = D2DRecords;
+       for ( ; ptr ; ptr = ptr->next)
+               {
+               if (SameDomainName(&ptr->ar.namestorage, regType)) 
+                       {
+                       char buffer[MAX_ESCAPED_DOMAIN_NAME];
+                       mDNS_Deregister(m, &ptr->ar);
+                       ConvertDomainNameToCString(regType, buffer);
+                       LogInfo("xD2DClearCache: Clearing cache record and deregistering %s", buffer);  
+                       }
+               }
+       }
 
-Revision 1.624  2009/02/09 21:11:43  cheshire
-Need to acknowledge kIOPMSystemPowerStateCapabilityCPU message
+mDNSlocal D2DBrowseListElem ** D2DFindInBrowseList(const domainname *const name, mDNSu16 type)
+       {
+       D2DBrowseListElem **ptr = &D2DBrowseList;
 
-Revision 1.623  2009/02/09 06:20:42  cheshire
-Upon receiving system power change notification, make sure our m->p->SystemWakeForNetworkAccessEnabled value
-correctly reflects the current system setting
+       for ( ; *ptr; ptr = &(*ptr)->next)
+               if ((*ptr)->type == type && SameDomainName(&(*ptr)->name, name))
+                       break;
+       
+       return ptr;
+       }
 
-Revision 1.622  2009/02/07 02:57:32  cheshire
-<rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
+mDNSlocal unsigned int D2DBrowseListRefCount(const domainname *const name, mDNSu16 type)
+       {
+       D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
+       return *ptr ? (*ptr)->refCount : 0;
+       }
 
-Revision 1.621  2009/02/06 03:18:12  mcguire
-<rdar://problem/6534643> BTMM: State not cleaned up on SIGTERM w/o reboot
+mDNSlocal void D2DBrowseListRetain(const domainname *const name, mDNSu16 type)
+       {
+       D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
+       
+       if (!*ptr)
+       {
+               *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
+               mDNSPlatformMemZero(*ptr, sizeof(**ptr));
+               (*ptr)->type = type;
+               AssignDomainName(&(*ptr)->name, name);
+       }
+       (*ptr)->refCount += 1;
+       
+       LogInfo("D2DBrowseListRetain: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);   
+       }
 
-Revision 1.620  2009/02/02 22:14:11  cheshire
-Instead of repeatedly checking the Dynamic Store, use m->p->SystemWakeForNetworkAccessEnabled variable
+mDNSlocal void D2DBrowseListRelease(const domainname *const name, mDNSu16 type)
+       {       
+       D2DBrowseListElem **ptr = D2DFindInBrowseList(name, type);
+       
+       if (!*ptr) { LogMsg("D2DBrowseListRelease: Didn't find %##s %s in list", name->c, DNSTypeName(type)); return; }
+       
+       (*ptr)->refCount -= 1;
+       
+       LogInfo("D2DBrowseListRelease: %##s %s refcount now %u", (*ptr)->name.c, DNSTypeName((*ptr)->type), (*ptr)->refCount);
+       
+       if (!(*ptr)->refCount)
+       {
+               D2DBrowseListElem *tmp = *ptr;
+               *ptr = (*ptr)->next;
+               mDNSPlatformMemFree(tmp);
+       }
+       }
 
-Revision 1.619  2009/01/24 02:11:58  cheshire
-Handle case where config->resolver[0]->nameserver[0] is NULL
+mDNSlocal mStatus xD2DParse(mDNS *const m, const mDNSu8 * const lhs, const mDNSu16 lhs_len, const mDNSu8 * const rhs, const mDNSu16 rhs_len, AuthRecord *rr)
+       {
+       if (*(lhs + (lhs_len - 1)) == compression_packet_v1)
+               return DNSNameCompressionParseBytes(m, lhs, lhs_len, rhs, rhs_len, rr);
+       else
+               return mStatus_Incompatible;
+       }
 
-Revision 1.618  2009/01/24 01:55:51  cheshire
-Handle case where config->resolver[0]->domain is NULL
+mDNSlocal void xD2DAddToCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
+       {
+       (void)transportType; // We don't care about this, yet.
+       (void)instanceHandle; // We don't care about this, yet.
+       
+       if (result == kD2DSuccess)
+               {
+               if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DAddToCache: NULL Byte * passed in or length == 0"); return; }
+               
+               mStatus err;
+               ARListElem *ptr = mDNSPlatformMemAllocate(sizeof(ARListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
 
-Revision 1.617  2009/01/24 01:48:42  cheshire
-<rdar://problem/4786302> Implement logic to determine when to send dot-local lookups via Unicast
+               if (ptr == NULL) { LogMsg("xD2DAddToCache: memory allocation failure"); return; }
 
-Revision 1.616  2009/01/24 00:28:43  cheshire
-Updated comments
+               err = xD2DParse(m, (const mDNSu8 * const)key, (const mDNSu16)keySize, (const mDNSu8 * const)value, (const mDNSu16)valueSize, &ptr->ar);
+               if (err)
+                       {
+                       LogMsg("xD2DAddToCache: xD2DParse returned error: %d", err);
+                       PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
+                       mDNSPlatformMemFree(ptr);
+                       return;
+                       }
+                       
+               err = mDNS_Register(m, &ptr->ar);
+               if (err)
+                       {
+                       LogMsg("xD2DAddToCache: mDNS_Register returned error %d for %s", err, ARDisplayString(m, &ptr->ar));
+                       mDNSPlatformMemFree(ptr);
+                       return;
+                       }
 
-Revision 1.615  2009/01/22 02:14:26  cheshire
-<rdar://problem/6515626> Sleep Proxy: Set correct target MAC address, instead of all zeroes
+               LogInfo("xD2DAddToCache: mDNS_Register succeeded for %s", ARDisplayString(m, &ptr->ar));
+               ptr->next = D2DRecords;
+               D2DRecords = ptr;
+               }
+       else
+               LogMsg("xD2DAddToCache: Unexpected result %d", result);
+       }
 
-Revision 1.614  2009/01/21 03:43:57  mcguire
-<rdar://problem/6511765> BTMM: Add support for setting kDNSServiceErr_NATPortMappingDisabled in DynamicStore
+mDNSlocal ARListElem * xD2DFindInList(mDNS *const m, const Byte *const key, const size_t keySize, const Byte *const value, const size_t valueSize)
+       {
+       ARListElem *ptr = D2DRecords;
+       ARListElem *arptr;
+       
+       if ( key == NULL || value == NULL || keySize == 0 || valueSize == 0) { LogMsg("xD2DFindInList: NULL Byte * passed in or length == 0"); return NULL; }
 
-Revision 1.613  2009/01/20 02:38:41  mcguire
-fix previous checkin comment
+       arptr = mDNSPlatformMemAllocate(sizeof(ARListElem) + (valueSize < sizeof(RData) ? 0 : valueSize - sizeof(RData)));
+       if (arptr == NULL) { LogMsg("xD2DFindInList: memory allocation failure"); return NULL; }
 
-Revision 1.612  2009/01/20 02:35:15  mcguire
-<rdar://problem/6508974> don't update BTMM & SleepProxyServers status at shutdown time
+       if (xD2DParse(m, (const mDNSu8 *const)key, (const mDNSu16)keySize, (const mDNSu8 *const)value, (const mDNSu16)valueSize, &arptr->ar) != mStatus_NoError)
+               {
+               LogMsg("xD2DFindInList: xD2DParse failed for key: %p (%u) value: %p (%u)", key, keySize, value, valueSize);
+               mDNSPlatformMemFree(arptr);
+               return NULL;
+               }
+               
+       while (ptr)
+               {
+               if (IdenticalResourceRecord(&arptr->ar.resrec, &ptr->ar.resrec)) break;
+               ptr = ptr->next;
+               }
+               
+       if (!ptr) LogMsg("xD2DFindInList: Could not find in D2DRecords: %s", ARDisplayString(m, &arptr->ar));
+       mDNSPlatformMemFree(arptr);
+       return ptr;
+       }
 
-Revision 1.611  2009/01/17 04:15:40  cheshire
-Updated "did sleep(5)" debugging message
+mDNSlocal void xD2DRemoveFromCache(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
+       {
+       (void)transportType; // We don't care about this, yet.
+       (void)instanceHandle; // We don't care about this, yet.
+       
+       if (result == kD2DSuccess)
+               {
+               ARListElem *ptr = xD2DFindInList(m, key, keySize, value, valueSize);
+               if (ptr) 
+                       {
+                       LogInfo("xD2DRemoveFromCache: Remove from cache: %s", ARDisplayString(m, &ptr->ar));
+                       mDNS_Deregister(m, &ptr->ar);
+                       }
+               }
+       else
+               LogMsg("xD2DRemoveFromCache: Unexpected result %d", result);
+       }
 
-Revision 1.610  2009/01/16 20:37:30  cheshire
-Fixed incorrect value of EOPNOTSUPP
+mDNSlocal void xD2DServiceResolved(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
+       {
+       (void)m;
+       (void)key;
+       (void)keySize;
+       (void)value;
+       (void)valueSize;
+       
+       if (result == kD2DSuccess) 
+               {
+               LogInfo("xD2DServiceResolved: Starting up PAN connection for %p", instanceHandle);
+               CHECK_D2D_FUNCTION(D2DRetain) D2DRetain(instanceHandle, transportType);
+               }
+       else LogMsg("xD2DServiceResolved: Unexpected result %d", result);
+       }
 
-Revision 1.609  2009/01/16 03:08:13  cheshire
-Use kernel event notifications to track KEV_DL_WAKEFLAGS_CHANGED
-(indicates when SIOCGIFWAKEFLAGS changes for an interface, e.g. when AirPort
-switches from a base-station that's WakeOnLAN-capable to one that isn't)
+mDNSlocal void xD2DRetainHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
+       {
+       (void)m;
+       (void)instanceHandle;
+       (void)transportType;
+       (void)key;
+       (void)keySize;
+       (void)value;
+       (void)valueSize;
+       
+       if (result == kD2DSuccess) LogInfo("xD2DRetainHappened: Opening up PAN connection for %p", instanceHandle);
+       else LogMsg("xD2DRetainHappened: Unexpected result %d", result);
+       }
 
-Revision 1.608  2009/01/16 01:27:03  cheshire
-Initial work to adopt SIOCGIFWAKEFLAGS ioctl to determine whether an interface is WakeOnLAN-capable
+mDNSlocal void xD2DReleaseHappened(mDNS *const m, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize)
+       {
+       (void)m;
+       (void)instanceHandle;
+       (void)transportType;
+       (void)key;
+       (void)keySize;
+       (void)value;
+       (void)valueSize;
+       
+       if (result == kD2DSuccess) LogInfo("xD2DReleaseHappened: Closing PAN connection for %p", instanceHandle);
+       else LogMsg("xD2DReleaseHappened: Unexpected result %d", result);
+       }
 
-Revision 1.607  2009/01/15 22:24:01  cheshire
-Get rid of unnecessary ifa_name field in NetworkInterfaceInfoOSX (it just duplicates the content of ifinfo.ifname)
-This also eliminates an unnecessary malloc, memory copy, and free
-
-Revision 1.606  2009/01/15 00:22:49  mcguire
-<rdar://problem/6437092> NAT-PMP: mDNSResponder needs to listen on 224.0.0.1:5350/UDP with REUSEPORT
-
-Revision 1.605  2009/01/14 01:38:43  mcguire
-<rdar://problem/6492710> Write out DynamicStore per-interface SleepProxyServer info
-
-Revision 1.604  2009/01/13 05:31:34  mkrochma
-<rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
-
-Revision 1.603  2009/01/12 22:26:13  mkrochma
-Change DynamicStore location from BonjourSleepProxy/DiscoveredServers to SleepProxyServers
-
-Revision 1.602  2008/12/19 20:23:34  mcguire
-<rdar://problem/6459269> Lots of duplicate log messages about failure to bind to NAT-PMP Announcement port
-
-Revision 1.601  2008/12/15 19:51:56  mcguire
-<rdar://problem/6443067> Retry UDP socket creation only when randomizing ports
-
-Revision 1.600  2008/12/12 21:30:14  cheshire
-Additional defensive coding -- make sure InterfaceID is found in our list before using it
-
-Revision 1.599  2008/12/12 04:36:26  cheshire
-Make sure we don't overflow our BPF filter buffer
-Only add addresses for records where the InterfaceID matches
+mDNSlocal void xD2DServiceCallback(D2DServiceEvent event, D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize, void *userData)
+       {
+       mDNS *m = (mDNS *) userData;
+       const char *eventString = "unknown";
+       
+       KQueueLock(m);
+       
+       if (keySize   > 0xFFFF) LogMsg("xD2DServiceCallback: keySize too large: %u", keySize);
+       if (valueSize > 0xFFFF) LogMsg("xD2DServiceCallback: valueSize too large: %u", valueSize);
+               
+       switch (event)
+               {
+               case D2DServiceFound:
+                       eventString = "D2DServiceFound";
+                       break;
+               case D2DServiceLost:
+                       eventString = "D2DServiceLost";
+                       break;
+               case D2DServiceResolved:
+                       eventString = "D2DServiceResolved";
+                       break;
+               case D2DServiceRetained:
+                       eventString = "D2DServiceRetained";
+                       break;
+               case D2DServiceReleased:
+                       eventString = "D2DServiceReleased";
+                       break;
+               default:
+                       break;
+               }
+       
+       LogInfo("xD2DServiceCallback: event=%s result=%d instanceHandle=%p transportType=%d LHS=%p (%u) RHS=%p (%u) userData=%p", eventString, result, instanceHandle, transportType, key, keySize, value, valueSize, userData);
+       PrintHelper(__func__, (mDNSu8 *)key, (mDNSu16)keySize, (mDNSu8 *)value, (mDNSu16)valueSize);
+       
+       switch (event)
+               {
+               case D2DServiceFound:
+                       xD2DAddToCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
+                       break;
+               case D2DServiceLost:
+                       xD2DRemoveFromCache(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
+                       break;
+               case D2DServiceResolved:
+                       xD2DServiceResolved(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
+                       break;
+               case D2DServiceRetained:
+                       xD2DRetainHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
+                       break;
+               case D2DServiceReleased:
+                       xD2DReleaseHappened(m, result, instanceHandle, transportType, key, keySize, value, valueSize);
+                       break;
+               default:
+                       break;
+               }
+       
+       // Need to tickle the main kqueue loop to potentially handle records we removed or added.
+       KQueueUnlock(m, "xD2DServiceCallback");
+       }
 
-Revision 1.598  2008/12/12 00:57:51  cheshire
-Updated BPF filter generation to explicitly match addresses we're proxying for,
-rather than just matching any unknown IP address
+mDNSexport void external_start_browsing_for_service(mDNS *const m, const domainname *const typeDomain, DNS_TypeValues qtype)
+       {
+       (void)m;
+       domainname lower;
+       
+       if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA)
+               {
+               LogInfo("external_start_browsing_for_service: ignoring address record");
+               return;
+               }
+       
+       DomainnameToLower(typeDomain, &lower);
+       
+       if (!D2DBrowseListRefCount(&lower, qtype))
+               {
+               LogInfo("external_start_browsing_for_service: Starting browse for: %##s %s", lower.c, DNSTypeName(qtype));
+               mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
+               PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
+               CHECK_D2D_FUNCTION(D2DStartBrowsingForKey) D2DStartBrowsingForKey(compression_lhs, end - compression_lhs);
+               }
+       D2DBrowseListRetain(&lower, qtype);
+       }
 
-Revision 1.597  2008/12/10 20:37:05  cheshire
-Don't mark interfaces like PPP as being WakeonLAN-capable
+mDNSexport void external_stop_browsing_for_service(mDNS *const m, const domainname *const typeDomain, DNS_TypeValues qtype)
+       {
+       domainname lower;
+       
+       if (qtype == kDNSServiceType_A || qtype == kDNSServiceType_AAAA)
+               {
+               LogInfo("external_stop_browsing_for_service: ignoring address record");
+               return;
+               }
+       
+       DomainnameToLower(typeDomain, &lower);
+       
+       D2DBrowseListRelease(&lower, qtype);
+       if (!D2DBrowseListRefCount(&lower, qtype))
+               {
+               LogInfo("external_stop_browsing_for_service: Stopping browse for: %##s %s", lower.c, DNSTypeName(qtype));
+               mDNSu8 *end = DNSNameCompressionBuildLHS(&lower, qtype);
+               PrintHelper(__func__, compression_lhs, end - compression_lhs, mDNSNULL, 0);
+               CHECK_D2D_FUNCTION(D2DStopBrowsingForKey) D2DStopBrowsingForKey(compression_lhs, end - compression_lhs);
+               xD2DClearCache(m, &lower);
+               }
+       }
 
-Revision 1.596  2008/12/10 19:34:30  cheshire
-Use symbolic OS version names instead of literal integers
+mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord)
+       {
+       domainname lower;
+       mDNSu8 *rhs = NULL;
+       mDNSu8 *end = NULL;
+       DomainnameToLower(resourceRecord->name, &lower);
+       
+       LogInfo("external_start_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord));
+       if (resourceRecord->rrtype == kDNSServiceType_A || resourceRecord->rrtype == kDNSServiceType_AAAA)
+               {
+               LogInfo("external_start_advertising_service: ignoring address record");
+               return;
+               }
+       rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
+       end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
+       PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
+       CHECK_D2D_FUNCTION(D2DStartAdvertisingPair) D2DStartAdvertisingPair(compression_lhs, rhs - compression_lhs, rhs, end - rhs);
+       }
 
-Revision 1.595  2008/12/10 02:25:31  cheshire
-Minor fixes to use of LogClientOperations symbol
+mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord)
+       {
+       domainname lower;
+       mDNSu8 *rhs = NULL;
+       mDNSu8 *end = NULL;
+       DomainnameToLower(resourceRecord->name, &lower);
+       
+       LogInfo("external_stop_advertising_service: %s", RRDisplayString(&mDNSStorage, resourceRecord));
+       if (resourceRecord->rrtype == kDNSServiceType_A || resourceRecord->rrtype == kDNSServiceType_AAAA)
+               {
+               LogInfo("external_stop_advertising_service: ignoring address record");
+               return;
+               }
+       rhs = DNSNameCompressionBuildLHS(&lower, resourceRecord->rrtype);
+       end = DNSNameCompressionBuildRHS(rhs, resourceRecord);
+       PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
+       CHECK_D2D_FUNCTION(D2DStopAdvertisingPair) D2DStopAdvertisingPair(compression_lhs, rhs - compression_lhs, rhs, end - rhs);
+       }
 
-Revision 1.594  2008/12/10 02:11:45  cheshire
-ARMv5 compiler doesn't like uncommented stuff after #endif
+mDNSexport void external_start_resolving_service(const domainname *const fqdn)
+       {
+       domainname lower;
+       mDNSu8 *rhs = NULL;
+       mDNSu8 *end = NULL;
+       DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
+       
+       LogInfo("external_start_resolving_service: %##s", fqdn->c);
+       rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
+       end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
+       PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
+       CHECK_D2D_FUNCTION(D2DStartResolvingPair) D2DStartResolvingPair(compression_lhs, rhs - compression_lhs, rhs, end - rhs);
+       }
 
-Revision 1.593  2008/12/09 23:08:55  mcguire
-<rdar://problem/6430877> should use IP_BOUND_IF
-additional cleanup
+mDNSexport void external_stop_resolving_service(const domainname *const fqdn) 
+       { 
+       domainname lower;
+       mDNSu8 *rhs = NULL;
+       mDNSu8 *end = NULL;
+       DomainnameToLower(SkipLeadingLabels(fqdn, 1), &lower);
+       
+       LogInfo("external_stop_resolving_service: %##s", fqdn->c);
+       rhs = DNSNameCompressionBuildLHS(&lower, kDNSType_PTR);
+       end = putDomainNameAsLabels(&compression_base_msg, rhs, compression_limit, fqdn);
+       PrintHelper(__func__, compression_lhs, rhs - compression_lhs, rhs, end - rhs);
+       CHECK_D2D_FUNCTION(D2DStopResolvingPair) D2DStopResolvingPair(compression_lhs, rhs - compression_lhs, rhs, end - rhs);
+       }
 
-Revision 1.592  2008/12/09 19:58:44  mcguire
-<rdar://problem/6430877> should use IP_BOUND_IF
+#elif APPLE_OSX_mDNSResponder
 
-Revision 1.591  2008/12/09 15:39:05  cheshire
-Workaround for bug on Leopard and earlier where Ethernet drivers report wrong link state immediately after wake from sleep
+mDNSexport void external_start_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype) { (void)m; (void)type; (void)qtype; }
+mDNSexport void external_stop_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype) { (void)m; (void)type; (void)qtype; }
+mDNSexport void external_start_advertising_service(const ResourceRecord *const resourceRecord) { (void)resourceRecord; }
+mDNSexport void external_stop_advertising_service(const ResourceRecord *const resourceRecord) { (void)resourceRecord; }
+mDNSexport void external_start_resolving_service(const domainname *const fqdn)  { (void)fqdn; }
+mDNSexport void external_stop_resolving_service(const domainname *const fqdn)  { (void)fqdn; }
 
-Revision 1.590  2008/12/09 05:21:54  cheshire
-Should key sleep/wake handling off kIOMessageSystemWillPowerOn message -- the kIOMessageSystemHasPoweredOn
-message is delayed by some seemingly-random amount in the range 0-15 seconds.
+#endif // ! NO_D2D
 
-Revision 1.589  2008/12/05 02:35:25  mcguire
-<rdar://problem/6107390> Write to the DynamicStore when a Sleep Proxy server is available on the network
+// ***************************************************************************
+// Functions
 
-Revision 1.588  2008/12/04 21:08:52  mcguire
-<rdar://problem/6116863> mDNS: Provide mechanism to disable Multicast advertisements
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Utility Functions
+#endif
 
-Revision 1.587  2008/12/04 02:17:47  cheshire
-Additional sleep/wake debugging messages
+// We only attempt to send and receive multicast packets on interfaces that are
+// (a) flagged as multicast-capable
+// (b) *not* flagged as point-to-point (e.g. modem)
+// Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
+// to run up the user's bill sending multicast traffic over a link where there's only a single device at the
+// other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
+#define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
 
-Revision 1.586  2008/11/26 20:34:55  cheshire
-Changed some "LogOperation" debugging messages to "debugf"
+mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
+       {
+       static int notifyCount = 0;
+       if (notifyCount) return;
 
-Revision 1.585  2008/11/25 20:53:35  cheshire
-Updated portability metrics; added Xserve and PowerBook to list
+       // If we display our alert early in the boot process, then it vanishes once the desktop appears.
+       // To avoid this, we don't try to display alerts in the first three minutes after boot.
+       if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return;
 
-Revision 1.584  2008/11/25 05:07:16  cheshire
-<rdar://problem/6374328> Advertise Sleep Proxy metrics in service name
+       // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
+       #if !ForceAlerts
+               {
+               // Determine if we're at Apple (17.*.*.*)
+               extern mDNS mDNSStorage;
+               NetworkInterfaceInfoOSX *i;
+               for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
+                       if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
+                               break;
+               if (!i) return; // If not at Apple, don't show the alert
+               }
+       #endif
 
-Revision 1.583  2008/11/20 01:42:31  cheshire
-For consistency with other parts of the code, changed code to only check
-that the first 4 bytes of MAC address are zero, not the whole 6 bytes.
+       LogMsg("%s", title);
+       LogMsg("%s", msg);
+       // Display a notification to the user
+       notifyCount++;
 
-Revision 1.582  2008/11/14 22:59:09  cheshire
-When on a network with more than one subnet overlayed on a single physical link, don't make local ARP
-entries for hosts that are on our physical link but not on our logical subnet -- it confuses the kernel
+#ifndef NO_CFUSERNOTIFICATION
+       mDNSNotify(title, msg);
+#endif /* NO_CFUSERNOTIFICATION */
+       }
 
-Revision 1.581  2008/11/14 21:01:26  cheshire
-Log a warning if we fail to get a MAC address for an interface
+mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
+       {
+       static struct ifaddrs *ifa = NULL;
 
-Revision 1.580  2008/11/14 02:16:15  cheshire
-Clean up NetworkChanged handling
+       if (refresh && ifa)
+               {
+               freeifaddrs(ifa);
+               ifa = NULL;
+               }
 
-Revision 1.579  2008/11/12 23:15:37  cheshire
-Updated log messages
+       if (ifa == NULL) getifaddrs(&ifa);
 
-Revision 1.578  2008/11/06 23:41:57  cheshire
-Refinement: Only need to create local ARP entry when sending ARP packet to broadcast address or to ourselves
+       return ifa;
+       }
 
-Revision 1.577  2008/11/06 01:15:47  mcguire
-Fix compile error that occurs when LogOperation is disabled
+// To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
+mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type)
+       {
+       NetworkInterfaceInfoOSX *i;
+       for (i = m->p->InterfaceList; i; i = i->next)
+               if (i->Exists && !strcmp(i->ifinfo.ifname, ifname) &&
+                       ((type == AF_UNSPEC                                         ) ||
+                        (type == AF_INET  && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
+                        (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
+       return(NULL);
+       }
 
-Revision 1.576  2008/11/05 21:55:21  cheshire
-Fixed mistake in BPF filter generation
+mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
+       {
+       struct ifaddrs *ifa;
+       for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
+               if (ifa->ifa_addr->sa_family == AF_LINK)
+                       if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex)
+                               { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
+       return -1;
+       }
 
-Revision 1.575  2008/11/04 23:54:09  cheshire
-Added routine mDNSSetARP(), used to replace an SPS client's entry in our ARP cache with
-a dummy one, so that IP traffic to the SPS client initiated by the SPS machine can be
-captured by our BPF filters, and used as a trigger to wake the sleeping machine.
+mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(const mDNS *const m, mDNSInterfaceID ifindex)
+{
+       mDNSu32 scope_id = (mDNSu32)(uintptr_t)ifindex;
+       NetworkInterfaceInfoOSX *i;
 
-Revision 1.574  2008/11/04 00:27:58  cheshire
-Corrected some timing anomalies in sleep/wake causing spurious name self-conflicts
+       // Don't get tricked by inactive interfaces
+       for (i = m->p->InterfaceList; i; i = i->next)
+               if (i->Registered && i->scope_id == scope_id) return(i);
 
-Revision 1.573  2008/11/03 01:12:42  mkrochma
-Fix compile error that occurs when LogOperation is disabled
+       return mDNSNULL;
+}
 
-Revision 1.572  2008/10/31 23:36:13  cheshire
-One wakeup clear any previous power requests
+mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
+       {
+       if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
+       if (ifindex == kDNSServiceInterfaceIndexP2P      ) return(mDNSInterface_P2P);
+       if (ifindex == kDNSServiceInterfaceIndexAny      ) return(mDNSNULL);
 
-Revision 1.571  2008/10/31 23:05:30  cheshire
-Move logic to decide when to at as Sleep Proxy Server from daemon.c to mDNSMacOSX.c
+       NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
+       if (!ifi)
+               {
+               // Not found. Make sure our interface list is up to date, then try again.
+               LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex);
+               mDNSMacOSXNetworkChanged(m);
+               ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
+               }
 
-Revision 1.570  2008/10/30 01:08:19  cheshire
-After waking for network maintenance operations go back to sleep again
+       if (!ifi) return(mDNSNULL);     
+       
+       return(ifi->ifinfo.InterfaceID);
+       }
 
-Revision 1.569  2008/10/29 21:39:43  cheshire
-Updated syslog messages; close BPF socket on read error
 
-Revision 1.568  2008/10/28 20:37:28  cheshire
-Changed code to create its own CFSocketCreateWithNative directly, instead of
-relying on udsSupportAddFDToEventLoop/udsSupportRemoveFDFromEventLoop
+mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id)
+       {
+       NetworkInterfaceInfoOSX *i;
+       if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
+       if (id == mDNSInterface_P2P      ) return(kDNSServiceInterfaceIndexP2P);
+       if (id == mDNSInterface_Any      ) return(0);
 
-Revision 1.567  2008/10/27 22:31:37  cheshire
-Can't just close BPF_fd using "close(i->BPF_fd);" -- need to call
-"udsSupportRemoveFDFromEventLoop(i->BPF_fd);" to remove it from our event source list
+       mDNSu32 scope_id = (mDNSu32)(uintptr_t)id;
 
-Revision 1.566  2008/10/23 22:33:23  cheshire
-Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
+       // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
+       for (i = m->p->InterfaceList; i; i = i->next)
+               if (i->scope_id == scope_id) return(i->scope_id);
 
-Revision 1.565  2008/10/22 23:23:55  cheshire
-Moved definition of OSXVers from daemon.c into mDNSMacOSX.c
+       // Not found. Make sure our interface list is up to date, then try again.
+       LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id);
+       mDNSMacOSXNetworkChanged(m);
+       for (i = m->p->InterfaceList; i; i = i->next)
+               if (i->scope_id == scope_id) return(i->scope_id);
 
-Revision 1.564  2008/10/22 22:08:46  cheshire
-Take IP header length into account when determining how many bytes to return from BPF filter
+       return(0);
+       }
 
-Revision 1.563  2008/10/22 20:59:28  cheshire
-BPF filter needs to capture a few more bytes so that we can examine TCP header fields
+#if APPLE_OSX_mDNSResponder
+mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...)
+       {
+       if (OSXVers < OSXVers_10_6_SnowLeopard)         return;
 
-Revision 1.562  2008/10/22 19:48:29  cheshire
-Improved syslog messages
+       static char             buffer[512];
+       aslmsg                  asl_msg = asl_new(ASL_TYPE_MSG);
 
-Revision 1.561  2008/10/22 17:18:57  cheshire
-Need to open and close BPF fds when turning Sleep Proxy Server on and off
+       if (!asl_msg)   { LogMsg("mDNSASLLog: asl_new failed"); return; }
+       if (uuid)
+               {
+               char            uuidStr[37];
+               uuid_unparse(*uuid, uuidStr);
+               asl_set         (asl_msg, "com.apple.message.uuid", uuidStr);
+               }
 
-Revision 1.560  2008/10/22 01:09:36  cheshire
-Fixed build warning when not using LogClientOperations
+       static char     domainBase[] = "com.apple.mDNSResponder.%s";
+       mDNS_snprintf   (buffer, sizeof(buffer), domainBase, subdomain);
+       asl_set                 (asl_msg, "com.apple.message.domain", buffer);
 
-Revision 1.559  2008/10/21 01:05:30  cheshire
-Added code to receive raw packets using Berkeley Packet Filter (BPF)
+       if (result)             asl_set(asl_msg, "com.apple.message.result", result);
+       if (signature)  asl_set(asl_msg, "com.apple.message.signature", signature);
 
-Revision 1.558  2008/10/16 22:42:06  cheshire
-Removed debugging messages
+       va_list ptr;
+       va_start(ptr,fmt);
+       mDNS_vsnprintf(buffer, sizeof(buffer), fmt, ptr);
+       va_end(ptr);
 
-Revision 1.557  2008/10/09 22:33:14  cheshire
-Fill in ifinfo.MAC field when fetching interface list
+       int     old_filter = asl_set_filter(NULL,ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
+       asl_log(NULL, asl_msg, ASL_LEVEL_DEBUG, "%s", buffer);
+       asl_set_filter(NULL, old_filter);
+       asl_free(asl_msg);
+       }
+#endif // APPLE_OSX_mDNSResponder
 
-Revision 1.556  2008/10/09 21:15:23  cheshire
-In mDNSPlatformUDPSocket(), need to create an IPv6 socket as well as IPv4
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - UDP & TCP send & receive
+#endif
 
-Revision 1.555  2008/10/09 19:05:57  cheshire
-No longer want to inhibit all networking when going to sleep
+mDNSlocal mDNSBool AddrRequiresPPPConnection(const struct sockaddr *addr)
+       {
+       mDNSBool result = mDNSfalse;
+       SCNetworkConnectionFlags flags;
+       SCNetworkReachabilityRef ReachRef = NULL;
 
-Revision 1.554  2008/10/08 18:36:51  mkrochma
-<rdar://problem/4371323> Supress Couldn't read user-specified Computer Name logs
+       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;
 
-Revision 1.553  2008/10/04 00:47:12  cheshire
-If NetWake setting changes for an interface, treat it as a whole new interface (like BSSID changing)
+       end:
+       if (ReachRef) CFRelease(ReachRef);
+       return result;
+       }
 
-Revision 1.552  2008/10/03 23:32:15  cheshire
-Added definition of mDNSPlatformSendRawPacket
+// 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
+// UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
+mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
+       mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstPort)
+       {
+       NetworkInterfaceInfoOSX *info = mDNSNULL;
+       struct sockaddr_storage to;
+       int s = -1, err;
+       mStatus result = mStatus_NoError;
 
-Revision 1.551  2008/10/03 18:25:16  cheshire
-Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);"
+       if (InterfaceID)
+               {
+               info = IfindexToInterfaceInfoOSX(m, InterfaceID);
+               if (info == NULL)
+                       {
+                       LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
+                       return mStatus_BadParamErr;
+                       }
+               }
 
-Revision 1.550  2008/10/03 00:51:58  cheshire
-Removed spurious "else" case that got left in by mistake
+       char *ifa_name = InterfaceID ? info->ifinfo.ifname : "unicast";
 
-Revision 1.549  2008/10/03 00:50:13  cheshire
-Minor code rearrangement; don't set up interface list until *after* we've started watching for network changes
+       if (dst->type == mDNSAddrType_IPv4)
+               {
+               struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
+               sin_to->sin_len            = sizeof(*sin_to);
+               sin_to->sin_family         = AF_INET;
+               sin_to->sin_port           = dstPort.NotAnInteger;
+               sin_to->sin_addr.s_addr    = dst->ip.v4.NotAnInteger;
+               s = (src ? src->ss : m->p->permanentsockets).sktv4;
 
-Revision 1.548  2008/10/03 00:26:25  cheshire
-Export DictionaryIsEnabled() so it's callable from other files
-
-Revision 1.547  2008/10/02 23:50:07  mcguire
-<rdar://problem/6136442> shutdown time issues
-improve log messages when SCDynamicStoreCreate() fails
-
-Revision 1.546  2008/10/02 22:26:21  cheshire
-Moved declaration of BPF_fd from uds_daemon.c to mDNSMacOSX.c, where it really belongs
-
-Revision 1.545  2008/10/01 22:01:40  cheshire
-On Allan Nathanson's advice, add "State:/IOKit/PowerManagement/CurrentSettings"
-to keys array instead of patterns array, for efficiency
-
-Revision 1.544  2008/10/01 21:35:35  cheshire
-Monitor "State:/IOKit/PowerManagement/CurrentSettings" to track state of "Wake for network access" setting
-
-Revision 1.543  2008/09/26 23:05:56  mkrochma
-Improve log messages by using good old UTF-8
-
-Revision 1.542  2008/09/26 19:49:51  cheshire
-Improved "failed to send packet" debugging message
-
-Revision 1.541  2008/09/25 21:02:05  cheshire
-<rdar://problem/6245044> Stop using separate m->ServiceRegistrations list
-In TunnelServers(), need to check main m->ResourceRecords list to see
-if we have a non-zero number of advertised AutoTunnel services
-
-Revision 1.540  2008/07/30 00:55:56  mcguire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-Additional fixes so that we know when a socket has been closed while in a loop reading from it
-
-Revision 1.539  2008/07/24 20:23:04  cheshire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
+               if (info)       // Specify outgoing interface
+                       {
+                       if (!mDNSAddrIsDNSMulticast(dst))
+                               {
+                               #ifdef IP_BOUND_IF
+                                       if (info->scope_id == 0)
+                                               LogInfo("IP_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name);
+                                       else
+                                               setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
+                               #else
+                                       {
+                                       static int displayed = 0;
+                                       if (displayed < 1000)
+                                               {
+                                               displayed++;
+                                               LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
+                                               }
+                                       }
+                               #endif
+                               }
+                       else
+                               #ifdef IP_MULTICAST_IFINDEX
+                               {
+                               err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IFINDEX, &info->scope_id, sizeof(info->scope_id));
+                               // We get an error when we compile on a machine that supports this option and run the binary on
+                               // a different machine that does not support it
+                               if (err < 0)
+                                       {
+                                       if (errno != ENOPROTOOPT) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno);
+                                       err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
+                                       if (err < 0 && !m->p->NetworkChanged)
+                                               LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
+                                       }
+                               }
+                               #else
+                               {
+                               err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
+                               if (err < 0 && !m->p->NetworkChanged)
+                                       LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
 
-Revision 1.538  2008/06/02 05:39:39  mkrochma
-<rdar://problem/5932760> Don't set TOS bits anymore
+                               }
+                               #endif
+                       }
+               }
+#ifndef NO_IPV6
+       else if (dst->type == mDNSAddrType_IPv6)
+               {
+               struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
+               sin6_to->sin6_len            = sizeof(*sin6_to);
+               sin6_to->sin6_family         = AF_INET6;
+               sin6_to->sin6_port           = dstPort.NotAnInteger;
+               sin6_to->sin6_flowinfo       = 0;
+               sin6_to->sin6_addr           = *(struct in6_addr*)&dst->ip.v6;
+               sin6_to->sin6_scope_id       = info ? info->scope_id : 0;
+               s = (src ? src->ss : m->p->permanentsockets).sktv6;
+               if (info && mDNSAddrIsDNSMulticast(dst))        // Specify outgoing interface
+                       {
+                       err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
+                       if (err < 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, errno, strerror(errno));
+                       }
+               }
+#endif
+       else
+               {
+               LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
+#if ForceAlerts
+               *(long*)0 = 0;
+#endif
+               return mStatus_BadParamErr;
+               }
 
-Revision 1.537  2008/05/01 18:30:54  mkrochma
-<rdar://problem/5895642> Make mDNSResponder and mDNSResponderHelper shutdown at regular time
+       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);
+       else
+               verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
+                       InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
 
-Revision 1.536  2008/03/25 01:27:30  mcguire
-<rdar://problem/5810718> Status sometimes wrong when link goes down
+       // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
+       // If we don't have the corresponding type of socket available, then return mStatus_Invalid
+       if (s < 0) return(mStatus_Invalid);
 
-Revision 1.535  2008/03/14 22:52:51  mcguire
-<rdar://problem/5321824> write status to the DS
-Ignore duplicate queries, which don't get established (since they're duplicates)
+       err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
+       if (err < 0)
+               {
+               static int MessageCount = 0;
+               // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
+               if (!mDNSAddressIsAllDNSLinkGroup(dst))
+                       if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
+               // Don't report EHOSTUNREACH in the first three minutes after boot
+               // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
+               // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
+               if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
+               // 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(mStatus_TransientErr);
+               if (MessageCount < 1000)
+                       {
+                       MessageCount++;
+                       if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
+                               LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
+                                       s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
+                       else
+                               LogMsg("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
+                                       s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
+                       }
+               result = mStatus_UnknownErr;
+               }
 
-Revision 1.534  2008/03/12 22:58:15  mcguire
-<rdar://problem/5321824> write status to the DS
-Fixes for NO_SECURITYFRAMEWORK
+#ifdef IP_BOUND_IF
+       if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst))
+               {
+               static const mDNSu32 ifindex = 0;
+               setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex));
+               }
+#endif
 
-Revision 1.533  2008/03/07 00:48:54  mcguire
-<rdar://problem/5321824> write status to the DS
-cleanup strings
+       return(result);
+       }
 
-Revision 1.532  2008/03/06 23:44:39  mcguire
-<rdar://problem/5321824> write status to the DS
-cleanup function names & log messages
-add external port numbers to dictionary
-add defensive code in case CF*Create fails
-don't output NAT statuses if zero
+mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
+       struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
+       {
+       static unsigned int numLogMessages = 0;
+       struct iovec databuffers = { (char *)buffer, max };
+       struct msghdr   msg;
+       ssize_t         n;
+       struct cmsghdr *cmPtr;
+       char            ancillary[1024];
 
-Revision 1.531  2008/03/06 21:27:47  cheshire
-<rdar://problem/5500969> BTMM: Need ability to identify version of mDNSResponder client
-To save network bandwidth, removed unnecessary redundant information from HINFO record
+       *ttl = 255;  // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
 
-Revision 1.530  2008/03/06 03:15:48  mcguire
-<rdar://problem/5321824> write status to the DS
-use mStatus_* instead of kDNSServiceErr_*
+       // Set up the message
+       msg.msg_name       = (caddr_t)from;
+       msg.msg_namelen    = *fromlen;
+       msg.msg_iov        = &databuffers;
+       msg.msg_iovlen     = 1;
+       msg.msg_control    = (caddr_t)&ancillary;
+       msg.msg_controllen = sizeof(ancillary);
+       msg.msg_flags      = 0;
 
-Revision 1.529  2008/03/06 02:48:35  mcguire
-<rdar://problem/5321824> write status to the DS
+       // Receive the data
+       n = recvmsg(s, &msg, 0);
+       if (n<0)
+               {
+               if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
+               return(-1);
+               }
+       if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
+               {
+               if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
+                       s, n, msg.msg_controllen, sizeof(struct cmsghdr));
+               return(-1);
+               }
+       if (msg.msg_flags & MSG_CTRUNC)
+               {
+               if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
+               return(-1);
+               }
 
-Revision 1.528  2008/02/29 01:33:57  mcguire
-<rdar://problem/5611801> BTMM: Services stay registered after previously successful NAT Port mapping fails
+       *fromlen = msg.msg_namelen;
 
-Revision 1.527  2008/02/28 03:25:26  mcguire
-<rdar://problem/5535772> config cleanup on shutdown/reboot
+       // Parse each option out of the ancillary data.
+       for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
+               {
+               // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
+               if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
+                       {
+                       dstaddr->type = mDNSAddrType_IPv4;
+                       dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
+                       //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
+                       }
+               if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
+                       {
+                       struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
+                       if (sdl->sdl_nlen < IF_NAMESIZE)
+                               {
+                               mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
+                               ifname[sdl->sdl_nlen] = 0;
+                               // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
+                               }
+                       }
+               if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
+                       *ttl = *(u_char*)CMSG_DATA(cmPtr);
+               if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
+                       {
+                       struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
+                       dstaddr->type = mDNSAddrType_IPv6;
+                       dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
+                       myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
+                       }
+               if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
+                       *ttl = *(int*)CMSG_DATA(cmPtr);
+               }
 
-Revision 1.526  2008/02/26 21:43:54  cheshire
-Renamed 'clockdivisor' to 'mDNSPlatformClockDivisor' (LogTimeStamps code needs to be able to access it)
+       return(n);
+       }
 
-Revision 1.525  2008/02/20 00:53:20  cheshire
-<rdar://problem/5492035> getifaddrs is returning invalid netmask family for fw0 and vmnet
-Removed overly alarming syslog message
+mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context)
+       {
+       KQSocketSet *const ss = (KQSocketSet *)context;
+       mDNS *const m = ss->m;
+       int err = 0, count = 0, closed = 0;
 
-Revision 1.524  2008/01/31 22:25:10  jgraessley
-<rdar://problem/5715434> using default Macintosh-0016CBF62EFD.local
-Use sysctlbyname to get hardware type for the default name.
+       if (filter != EVFILT_READ)
+               LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
 
-Revision 1.523  2008/01/15 01:32:56  jgraessley
-Bug #: 5595309
-Reviewed by: Stuart Cheshire
-Additional change to print warning message up to 1000 times to make it more visible
+       if (s1 != ss->sktv4
+#ifndef NO_IPV6
+               && s1 != ss->sktv6
+#endif
+               )
+               {
+               LogMsg("myKQSocketCallBack: native socket %d", s1);
+               LogMsg("myKQSocketCallBack: sktv4 %d", ss->sktv4);
+#ifndef NO_IPV6
+               LogMsg("myKQSocketCallBack: sktv6 %d", ss->sktv6);
+#endif
+               }
 
-Revision 1.522  2008/01/15 01:14:02  mcguire
-<rdar://problem/5674390> mDNSPlatformSendUDP should allow unicast queries on specific interfaces
-removed check and log message, as they are no longer relevant
+       while (!closed)
+               {
+               mDNSAddr senderAddr, destAddr;
+               mDNSIPPort senderPort;
+               struct sockaddr_storage from;
+               size_t fromlen = sizeof(from);
+               char packetifname[IF_NAMESIZE] = "";
+               mDNSu8 ttl;
+               err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
+               if (err < 0) break;
 
-Revision 1.521  2007/12/14 00:58:28  cheshire
-<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
-Additional fixes: When going to sleep, mDNSResponder needs to postpone sleep
-until TLS/TCP deregistrations have completed (up to five seconds maximum)
+               count++;
+               if (from.ss_family == AF_INET)
+                       {
+                       struct sockaddr_in *s = (struct sockaddr_in*)&from;
+                       senderAddr.type = mDNSAddrType_IPv4;
+                       senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
+                       senderPort.NotAnInteger = s->sin_port;
+                       //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
+                       }
+               else if (from.ss_family == AF_INET6)
+                       {
+                       struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
+                       senderAddr.type = mDNSAddrType_IPv6;
+                       senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
+                       senderPort.NotAnInteger = sin6->sin6_port;
+                       //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
+                       }
+               else
+                       {
+                       LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
+                       return;
+                       }
 
-Revision 1.520  2007/12/10 23:01:01  cheshire
-Remove some unnecessary log messages
+               // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
+               mDNSInterfaceID InterfaceID = mDNSNULL;
+               //NetworkInterfaceInfo *intf = m->HostInterfaces;
+               //while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
 
-Revision 1.519  2007/12/06 00:22:27  mcguire
-<rdar://problem/5604567> BTMM: Doesn't work with Linksys WAG300N 1.01.06 (sending from 1026/udp)
+               NetworkInterfaceInfoOSX *intf = m->p->InterfaceList;
+               while (intf && strcmp(intf->ifinfo.ifname, packetifname)) intf = intf->next;
 
-Revision 1.518  2007/12/05 01:52:30  cheshire
-<rdar://problem/5624763> BTMM: getaddrinfo_async_start returns EAI_NONAME when resolving BTMM hostname
-Delay returning IPv4 address ("A") results for autotunnel names until after we've set up the tunnel (or tried to)
+               // When going to sleep we deregister all our interfaces, but if the machine
+               // takes a few seconds to sleep we may continue to receive multicasts
+               // during that time, which would confuse mDNSCoreReceive, because as far
+               // as it's concerned, we should have no active interfaces any more.
+               // Hence we ignore multicasts for which we can find no matching InterfaceID.
+               if (intf) InterfaceID = intf->ifinfo.InterfaceID;
+               else if (mDNSAddrIsDNSMulticast(&destAddr)) continue;
 
-Revision 1.517  2007/12/03 18:37:26  cheshire
-Moved mDNSPlatformWriteLogMsg & mDNSPlatformWriteDebugMsg
-from mDNSMacOSX.c to PlatformCommon.c, so that Posix build can use them
+//             LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
+//                     &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
 
-Revision 1.516  2007/12/01 01:21:27  jgraessley
-<rdar://problem/5623140> mDNSResponder unicast DNS improvements
+               // mDNSCoreReceive may close the socket we're reading from.  We must break out of our
+               // loop when that happens, or we may try to read from an invalid FD.  We do this by
+               // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
+               // if it closes the socketset.
+               ss->closeFlag = &closed;
 
-Revision 1.515  2007/12/01 00:40:00  cheshire
-Add mDNSPlatformWriteLogMsg & mDNSPlatformWriteDebugMsg abstractions, to facilitate EFI conversion
+               mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID);
 
-Revision 1.514  2007/12/01 00:38:32  cheshire
-Fixed compile warning: declaration of 'index' shadows a global declaration
+               // if we didn't close, we can safely dereference the socketset, and should to
+               // reset the closeFlag, since it points to something on the stack
+               if (!closed) ss->closeFlag = mDNSNULL;
+               }
 
-Revision 1.513  2007/11/27 00:08:49  jgraessley
-<rdar://problem/5613538> Interface-specific resolvers not setup correctly
-
-Revision 1.512  2007/11/16 22:09:26  cheshire
-Added missing type information in mDNSPlatformTCPCloseConnection debugging log message
-
-Revision 1.511  2007/11/14 23:06:13  cheshire
-<rdar://problem/5585972> IP_ADD_MEMBERSHIP fails for previously-connected removable interfaces
-
-Revision 1.510  2007/11/14 22:29:19  cheshire
-Updated comments and debugging log messages
-
-Revision 1.509  2007/11/14 01:07:53  cheshire
-Updated comments
-
-Revision 1.508  2007/11/02 21:59:37  cheshire
-Added comment about locking
-
-Revision 1.507  2007/11/02 20:18:13  cheshire
-<rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
-
-Revision 1.506  2007/10/30 20:46:45  cheshire
-<rdar://problem/5496734> BTMM: Need to retry registrations after failures
-
-Revision 1.505  2007/10/29 23:55:10  cheshire
-<rdar://problem/5526791> BTMM: Changing Local Hostname doesn't update Back to My Mac registered records
-Don't need to manually fake another AutoTunnelNATCallback if it has not yet received its first callback
-(and indeed should not, since the result fields will not yet be set up correctly in this case)
-
-Revision 1.504  2007/10/26 00:50:37  cheshire
-<rdar://problem/5526791> BTMM: Changing Local Hostname doesn't update Back to My Mac registered records
-
-Revision 1.503  2007/10/25 23:11:42  cheshire
-Ignore IPv6 ULA addresses configured on lo0 loopback interface
-
-Revision 1.502  2007/10/22 20:07:07  cheshire
-Moved mDNSPlatformSourceAddrForDest from mDNSMacOSX.c to PlatformCommon.c so
-Posix build can share the code (better than just pasting it into mDNSPosix.c)
+       if (err < 0 && (errno != EWOULDBLOCK || count == 0))
+               {
+               // Something is busted here.
+               // kqueue says there is a packet, but myrecvfrom says there is not.
+               // Try calling select() to get another opinion.
+               // Find out about other socket parameter that can help understand why select() says the socket is ready for read
+               // All of this is racy, as data may have arrived after the call to select()
+               static unsigned int numLogMessages = 0;
+               int save_errno = errno;
+               int so_error = -1;
+               int so_nread = -1;
+               int fionread = -1;
+               socklen_t solen = sizeof(int);
+               fd_set readfds;
+               struct timeval timeout;
+               int selectresult;
+               FD_ZERO(&readfds);
+               FD_SET(s1, &readfds);
+               timeout.tv_sec  = 0;
+               timeout.tv_usec = 0;
+               selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
+               if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
+                       LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
+               if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
+                       LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
+               if (ioctl(s1, FIONREAD, &fionread) == -1)
+                       LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
+               if (numLogMessages++ < 100)
+                       LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
+                               s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
+               if (numLogMessages > 5)
+                       NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
+                               "Congratulations, you've reproduced an elusive bug.\r"
+                               "Please contact the current assignee of <rdar://problem/3375328>.\r"
+                               "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
+                               "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
 
-Revision 1.501  2007/10/22 19:40:30  cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
-Made subroutine mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst)
+               sleep(1);               // After logging this error, rate limit so we don't flood syslog
+               }
+       }
 
-Revision 1.500  2007/10/17 22:49:55  cheshire
-<rdar://problem/5519458> BTMM: Machines don't appear in the sidebar on wake from sleep
+// TCP socket support
 
-Revision 1.499  2007/10/17 19:47:54  cheshire
-Improved debugging messages
+typedef enum
+       {
+       handshake_required,
+       handshake_in_progress,
+       handshake_completed,
+       handshake_to_be_closed
+       } handshakeStatus;
+       
+struct TCPSocket_struct
+       {
+       TCPSocketFlags flags;           // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
+       TCPConnectionCallback callback;
+       int fd;
+       KQueueEntry *kqEntry;   
+       KQSocketSet ss;
+#ifndef NO_SECURITYFRAMEWORK
+       SSLContextRef tlsContext;
+       pthread_t handshake_thread;
+#endif /* NO_SECURITYFRAMEWORK */
+       domainname hostname;
+       void *context;
+       mDNSBool setup;
+       mDNSBool connected;
+       handshakeStatus handshake;
+       mDNS *m; // So we can call KQueueLock from the SSLHandshake thread
+       mStatus err;
+       };
 
-Revision 1.498  2007/10/17 18:42:06  cheshire
-Export SetDomainSecrets so its callable from other files
+mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
+       {
+       mDNSBool c = !sock->connected;
+       sock->connected = mDNStrue;
+       sock->callback(sock, sock->context, c, sock->err);
+       // Note: the callback may call CloseConnection here, which frees the context structure!
+       }
 
-Revision 1.497  2007/10/16 17:03:07  cheshire
-<rdar://problem/3557903> Performance: Core code will not work on platforms with small stacks
-Cut SetDomainSecrets stack from 3792 to 1760 bytes
+#ifndef NO_SECURITYFRAMEWORK
 
-Revision 1.496  2007/10/04 20:33:05  mcguire
-<rdar://problem/5518845> BTMM: Racoon configuration removed when network changes
+mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
+       {
+       int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
+       if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
+       if (ret >= 0)                              { *dataLength = ret; return(noErr); }
+       *dataLength = 0;
+       if (errno == EAGAIN                      ) return(errSSLWouldBlock);
+       if (errno == ENOENT                      ) return(errSSLClosedGraceful);
+       if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
+       LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno));
+       return(errSSLClosedAbort);
+       }
 
-Revision 1.495  2007/10/02 05:03:38  cheshire
-Fix bogus indentation in mDNSPlatformDynDNSHostNameStatusChanged
+mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
+       {
+       int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
+       if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
+       if (ret > 0)                              { *dataLength = ret; return(noErr); }
+       *dataLength = 0;
+       if (ret == 0 || errno == ENOENT    ) return(errSSLClosedGraceful);
+       if (            errno == EAGAIN    ) return(errSSLWouldBlock);
+       if (            errno == ECONNRESET) return(errSSLClosedAbort);
+       LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno));
+       return(errSSLClosedAbort);
+       }
 
-Revision 1.494  2007/09/29 20:40:19  cheshire
-<rdar://problem/5513378> Crash in ReissueBlockedQuestions
+mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, mDNSBool server)
+       {
+       char domname_cstr[MAX_ESCAPED_DOMAIN_NAME];
 
-Revision 1.493  2007/09/29 03:16:45  cheshire
-<rdar://problem/5513168> BTMM: mDNSResponder memory corruption in GetAuthInfoForName_internal
-When AutoTunnel information changes, wait for record deregistrations to complete before registering new data
+       mStatus err = SSLNewContext(server, &sock->tlsContext);
+       if (err) { LogMsg("ERROR: tlsSetupSock: SSLNewContext failed with error code: %d", err); return(err); }
 
-Revision 1.492  2007/09/28 23:58:35  mcguire
-<rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
-Fix locking issue.
+       err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
+       if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err); return(err); }
 
-Revision 1.491  2007/09/27 23:28:53  mcguire
-<rdar://problem/5508042> BTMM: Anonymous racoon configuration not always cleaned up correctly
+       err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
+       if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err); return(err); }
 
-Revision 1.490  2007/09/26 23:01:21  mcguire
-<rdar://problem/5505280> BTMM: v6 address and security policies being setup too soon
+       // Instead of listing all the acceptable ciphers, we just disable the bad ciphers. It does not disable
+       // all the bad ciphers like RC4_MD5, but it assumes that the servers don't offer them.
+       err = SSLSetAllowAnonymousCiphers(sock->tlsContext, 0);
+       if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetAllowAnonymousCiphers failed with error code: %d", err); return(err); }
 
-Revision 1.489  2007/09/26 22:58:16  mcguire
-<rdar://problem/5505092> BTMM: Client tunnels being created to ::0 via 0.0.0.0
+       // We already checked for NULL in hostname and this should never happen. Hence, returning -1
+       // (error not in OSStatus space) is okay.
+       if (!sock->hostname.c[0]) {LogMsg("ERROR: tlsSetupSock: hostname NULL"); return -1; }
 
-Revision 1.488  2007/09/26 00:32:45  cheshire
-Rearrange struct TCPSocket_struct so "TCPSocketFlags flags" comes first (needed for debug logging)
+       ConvertDomainNameToCString(&sock->hostname, domname_cstr);
+       err = SSLSetPeerDomainName(sock->tlsContext, domname_cstr, strlen(domname_cstr));
+       if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetPeerDomainname: %s failed with error code: %d", domname_cstr, err); return(err); }
 
-Revision 1.487  2007/09/21 17:07:41  mcguire
-<rdar://problem/5487354> BTMM: Need to modify IPSec tunnel setup files when shared secret changes (server-role)
+       return(err);
+       }
 
-Revision 1.486  2007/09/19 23:17:38  cheshire
-<rdar://problem/5482131> BTMM: Crash when switching .Mac accounts
+#ifdef __LIB_DISPATCH__
+mDNSlocal void doSSLHandshake(void *ctx)
+       {
+       TCPSocket *sock = (TCPSocket*)ctx;
+       mStatus err = SSLHandshake(sock->tlsContext);
+       
+       //Can't have multiple threads in mDNS core. When __LIB_DISPATCH__ is
+       //defined, KQueueLock is a noop. Hence we need to serialize here
+       //
+       //NOTE: We just can't serialize doTcpSocketCallback alone on the main queue.
+       //We need the rest of the logic also. Otherwise, we can enable the READ
+       //events below, dispatch a doTcpSocketCallback on the main queue. Assume it is
+       //ConnFailed which means we are going to free the tcpInfo. While it
+       //is waiting to be dispatched, another read event can come into tcpKQSocketCallback
+       //and potentially call doTCPCallback with error which can close the fd and free the
+       //tcpInfo. Later when the thread gets dispatched it will crash because the tcpInfo
+       //is already freed.
 
-Revision 1.485  2007/09/19 21:44:29  cheshire
-Improved "mDNSKeychainGetSecrets failed" error message
+       dispatch_async(dispatch_get_main_queue(), ^{
 
-Revision 1.484  2007/09/18 21:44:55  cheshire
-<rdar://problem/5469006> Crash in GetAuthInfoForName_internal
-Code was using n->ExtPort (now n->RequestedPort) when it should have been using n->ExternalPort
+               LogInfo("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
 
-Revision 1.483  2007/09/17 22:19:39  mcguire
-<rdar://problem/5482519> BTMM: Tunnel is getting configured too much which causes long delays
-No need to configure a tunnel again if all the parameters are the same -- just remove the older duplicate tunnel from the list.
+               if (sock->handshake == handshake_to_be_closed)
+                       {
+                       LogInfo("SSLHandshake completed after close");
+                       mDNSPlatformTCPCloseConnection(sock);
+                       }
+               else
+                       {
+                       if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
+                       else LogMsg("doSSLHandshake: sock->fd is -1");
+       
+                       if (err == errSSLWouldBlock)
+                               sock->handshake = handshake_required;
+                       else
+                               {
+                               if (err)
+                                       {
+                                       LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
+                                       SSLDisposeContext(sock->tlsContext);
+                                       sock->tlsContext = NULL;
+                                       }
+                               
+                               sock->err = err ? mStatus_ConnFailed : 0;
+                               sock->handshake = handshake_completed;
+                               
+                               LogInfo("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
+                               doTcpSocketCallback(sock);
+                               }
+                       }
+       
+               LogInfo("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
+               return;
+               });
+       }
+#else
+mDNSlocal void *doSSLHandshake(void *ctx)
+       {
+       // Warning: Touching sock without the kqueue lock!
+       // We're protected because sock->handshake == handshake_in_progress
+       TCPSocket *sock = (TCPSocket*)ctx;
+       mDNS * const m = sock->m; // Get m now, as we may free sock if marked to be closed while we're waiting on SSLHandshake
+       mStatus err = SSLHandshake(sock->tlsContext);
+       
+       KQueueLock(m);
+       debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
 
-Revision 1.482  2007/09/14 21:16:03  cheshire
-<rdar://problem/5413170> mDNSResponder using 100% CPU spinning in tlsReadSock
+       if (sock->handshake == handshake_to_be_closed)
+               {
+               LogInfo("SSLHandshake completed after close");
+               mDNSPlatformTCPCloseConnection(sock);
+               }
+       else
+               {
+               if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
+               else LogMsg("doSSLHandshake: sock->fd is -1");
 
-Revision 1.481  2007/09/14 21:14:56  mcguire
-<rdar://problem/5481318> BTMM: Need to modify IPSec tunnel setup files when shared secret changes
+               if (err == errSSLWouldBlock)
+                       sock->handshake = handshake_required;
+               else
+                       {
+                       if (err)
+                               {
+                               LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
+                               SSLDisposeContext(sock->tlsContext);
+                               sock->tlsContext = NULL;
+                               }
+                       
+                       sock->err = err ? mStatus_ConnFailed : 0;
+                       sock->handshake = handshake_completed;
+                       
+                       debugf("doSSLHandshake: %p calling doTcpSocketCallback fd %d", sock, sock->fd);
+                       doTcpSocketCallback(sock);
+                       }
+               }
+       
+       debugf("SSLHandshake %p: dropping lock for fd %d", sock, sock->fd);
+       KQueueUnlock(m, "doSSLHandshake");
+       return NULL;
+       }
+#endif
 
-Revision 1.480  2007/09/13 00:16:42  cheshire
-<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
+mDNSlocal mStatus spawnSSLHandshake(TCPSocket* sock)
+       {
+       debugf("spawnSSLHandshake %p: entry", sock);
+       mStatus err;
 
-Revision 1.479  2007/09/12 19:22:20  cheshire
-Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
-Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
+       if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
+       sock->handshake = handshake_in_progress;
+       KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, sock->kqEntry);
+#ifdef __LIB_DISPATCH__
 
-Revision 1.478  2007/09/07 22:21:45  vazquez
-<rdar://problem/5460830> BTMM: Connection stops working after connecting VPN
+       // Dispatch it on a separate serial queue to avoid deadlocks with threads running on main queue
+       dispatch_async(SSLqueue, ^{doSSLHandshake(sock);});
+       err = 0;
+#else
+       pthread_attr_t attr;
+       pthread_attr_init(&attr);
+       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+       err = pthread_create(&sock->handshake_thread, &attr, doSSLHandshake, sock);
+       pthread_attr_destroy(&attr);
+       if (err)
+               {
+               LogMsg("Could not start SSLHandshake thread: (%d) %s", err, strerror(err));
+               sock->handshake = handshake_completed;
+               sock->err = err;
+               KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
+               }
+#endif
+       debugf("spawnSSLHandshake %p: done for %d", sock, sock->fd);
+       return err;
+       }
 
-Revision 1.477  2007/09/07 21:22:30  cheshire
-<rdar://problem/5460210> BTMM: SetupSocket 5351 failed; Can't allocate UDP multicast socket spew on wake from sleep with internet sharing on
-Don't log failures binding to port 5351
+mDNSlocal mDNSBool IsTunnelModeDomain(const domainname *d)
+       {
+       static const domainname *mmc = (const domainname*) "\x7" "members" "\x3" "mac" "\x3" "com";
+       const domainname *d1 = mDNSNULL;        // TLD
+       const domainname *d2 = mDNSNULL;        // SLD
+       const domainname *d3 = mDNSNULL;
+       while (d->c[0]) { d3 = d2; d2 = d1; d1 = d; d = (const domainname*)(d->c + 1 + d->c[0]); }
+       return(d3 && SameDomainName(d3, mmc));
+       }
 
-Revision 1.476  2007/09/06 20:38:08  cheshire
-<rdar://problem/5439021> Only call SetDomainSecrets() for Keychain changes that are relevant to mDNSResponder
+#endif /* NO_SECURITYFRAMEWORK */
 
-Revision 1.475  2007/09/05 02:24:28  cheshire
-<rdar://problem/5457287> mDNSResponder taking up 100% CPU in ReissueBlockedQuestions
-In ReissueBlockedQuestions, only restart questions marked NoAnswer_Suspended, not those marked NoAnswer_Fail
+mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context)
+       {
+       TCPSocket *sock = context;
+       sock->err = mStatus_NoError;
 
-Revision 1.474  2007/09/04 22:32:58  mcguire
-<rdar://problem/5453633> BTMM: BTMM overwrites /etc/racoon/remote/anonymous.conf
+       //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
+       //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
+       // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
+       if (filter == EVFILT_WRITE) KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, sock->kqEntry);
 
-Revision 1.473  2007/08/31 19:53:15  cheshire
-<rdar://problem/5431151> BTMM: IPv6 address lookup should not succeed if autotunnel cannot be setup
-If AutoTunnel setup fails, the code now generates a fake NXDomain error saying that the requested AAAA record does not exist
+       if (sock->flags & kTCPSocketFlags_UseTLS)
+               {
+#ifndef NO_SECURITYFRAMEWORK
+               if (!sock->setup) { sock->setup = mDNStrue; tlsSetupSock(sock, mDNSfalse); }
+               
+               if (sock->handshake == handshake_required) { if (spawnSSLHandshake(sock) == 0) return; }
+               else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed) return;
+               else if (sock->handshake != handshake_completed)
+                       {
+                       if (!sock->err) sock->err = mStatus_UnknownErr;
+                       LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
+                       }
+#else
+               sock->err = mStatus_UnsupportedErr;
+#endif /* NO_SECURITYFRAMEWORK */
+               }
+       
+       doTcpSocketCallback(sock);
+       }
 
-Revision 1.472  2007/08/31 18:49:49  vazquez
-<rdar://problem/5393719> BTMM: Need to properly deregister when stopping BTMM
+#ifdef __LIB_DISPATCH__
+mDNSexport int KQueueSet(int fd, u_short flags, short filter, KQueueEntry *const entryRef)
+       {
+       dispatch_queue_t queue = dispatch_get_main_queue();
+       dispatch_source_t source;
+       if (flags == EV_DELETE)
+               {
+               if (filter == EVFILT_READ)
+                       {
+                       dispatch_source_cancel(entryRef->readSource);
+                       dispatch_release(entryRef->readSource);
+                       entryRef->readSource = mDNSNULL;
+                       debugf("KQueueSet: source cancel for read %p, %p", entryRef->readSource, entryRef->writeSource);
+                       }
+               else if (filter == EVFILT_WRITE)
+                       {
+                       dispatch_source_cancel(entryRef->writeSource);
+                       dispatch_release(entryRef->writeSource);
+                       entryRef->writeSource = mDNSNULL;
+                       debugf("KQueueSet: source cancel for write %p, %p", entryRef->readSource, entryRef->writeSource);
+                       }
+               else
+                       LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_DELETE", filter);
+               return 0;
+               }
+       if (flags != EV_ADD) LogMsg("KQueueSet: Invalid flags %d", flags);
 
-Revision 1.471  2007/08/31 02:05:46  cheshire
-Need to hold mDNS_Lock when calling mDNS_AddDynDNSHostName
+       if (filter == EVFILT_READ)
+               {
+               source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue);
+               }
+       else if (filter == EVFILT_WRITE)
+               {
+               source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, queue);
+               }
+       else 
+               {
+               LogMsg("KQueueSet: ERROR: Wrong filter value %d for EV_ADD", filter);
+               return -1;
+               }
+       if (!source) return -1;
+       dispatch_source_set_event_handler(source, ^{
 
-Revision 1.470  2007/08/30 22:50:04  mcguire
-<rdar://problem/5430628> BTMM: Tunneled services are registered when autotunnel can't be setup
+               mDNSs32 stime = mDNSPlatformRawTime();
+               entryRef->KQcallback(fd, filter, entryRef->KQcontext);
+               mDNSs32 etime = mDNSPlatformRawTime();
+               if (etime - stime >= WatchDogReportingThreshold)
+                       LogInfo("KQEntryCallback Block: WARNING: took %dms to complete", etime - stime);
 
-Revision 1.469  2007/08/30 19:40:51  cheshire
-Added syslog messages to report various initialization failures
+               // Trigger the event delivery to the application. Even though we trigger the
+               // event completion after handling every event source, these all will hopefully
+               // get merged
+               TriggerEventCompletion();
 
-Revision 1.468  2007/08/30 00:12:20  cheshire
-Check error codes and log failures during AutoTunnel setup
+               });
+    dispatch_source_set_cancel_handler(source, ^{
+               if (entryRef->fdClosed)
+                       {
+                       //LogMsg("CancelHandler: closing fd %d", fd);
+                       close(fd);
+                       }
+               });
+       dispatch_resume(source);
+       if (filter == EVFILT_READ)
+               entryRef->readSource = source;
+       else
+               entryRef->writeSource = source;
+               
+       return 0;
+       }
 
-Revision 1.467  2007/08/28 00:33:04  jgraessley
-<rdar://problem/5423932> Selective compilation options
-
-Revision 1.466  2007/08/24 23:25:55  cheshire
-Debugging messages to help track down duplicate items being read from system keychain
-
-Revision 1.465  2007/08/24 00:39:12  cheshire
-Added comment explaining why we set info->AutoTunnelService.resrec.RecordType to kDNSRecordTypeUnregistered
+mDNSexport void KQueueLock(mDNS *const m)
+       {
+       (void)m; //unused
+       }
+mDNSexport void KQueueUnlock(mDNS *const m, const char const *task)
+       {
+       (void)m; //unused
+       (void)task; //unused
+       }
+#else
+mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
+       {
+       struct kevent new_event;
+       EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
+       return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
+       }
 
-Revision 1.464  2007/08/24 00:15:21  cheshire
-Renamed GetAuthInfoForName() to GetAuthInfoForName_internal() to make it clear that it may only be called with the lock held
+mDNSexport void KQueueLock(mDNS *const m)
+       {
+       pthread_mutex_lock(&m->p->BigMutex);
+       m->p->BigMutexStartTime = mDNSPlatformRawTime();
+       }
 
-Revision 1.463  2007/08/23 21:02:35  cheshire
-SecKeychainSetPreferenceDomain() call should be in platform-support layer, not daemon.c
+mDNSexport void KQueueUnlock(mDNS *const m, const char const *task)
+       {
+       mDNSs32 end = mDNSPlatformRawTime();
+       (void)task;
+       if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
+               LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
 
-Revision 1.462  2007/08/18 01:02:03  mcguire
-<rdar://problem/5415593> No Bonjour services are getting registered at boot
+       pthread_mutex_unlock(&m->p->BigMutex);
 
-Revision 1.461  2007/08/10 22:25:57  mkrochma
-<rdar://problem/5396302> mDNSResponder continually complains about slow UDP packet reception -- about 400 msecs
+       char wake = 1;
+       if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
+               LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno));
+       }
+#endif
 
-Revision 1.460  2007/08/08 22:34:59  mcguire
-<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
+mDNSexport void mDNSPlatformCloseFD(KQueueEntry *kq, int fd)
+       {
+#ifdef __LIB_DISPATCH__
+       (void)fd; //unused
+       if (kq->readSource)
+               {
+               dispatch_source_cancel(kq->readSource);
+               kq->readSource = mDNSNULL;
+               }
+       if (kq->writeSource)
+               {       
+               dispatch_source_cancel(kq->writeSource);
+               kq->writeSource = mDNSNULL;
+               }
+       // Close happens in the cancellation handler
+       debugf("mDNSPlatformCloseFD: resetting sources for %d", fd);
+       kq->fdClosed = mDNStrue;
+#else
+       (void)kq; //unused
+       close(fd);
+#endif
+       }
 
-Revision 1.459  2007/08/08 21:07:48  vazquez
-<rdar://problem/5244687> BTMM: Need to advertise model information via wide-area bonjour
+mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort *port)
+       {
+       KQSocketSet *cp = &sock->ss;
+#ifndef NO_IPV6
+    int         *s        = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
+    KQueueEntry *k        = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
+#else
+    int         *s        = &cp->sktv4;
+    KQueueEntry *k        = &cp->kqsv4;
+#endif
+       const int on = 1;  // "on" for setsockopt
+       mStatus err;
 
-Revision 1.458  2007/08/03 02:18:41  mcguire
-<rdar://problem/5381687> BTMM: Use port numbers in IPsec policies & configuration files
+    int skt = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
+    if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
+       if (sa_family == AF_INET)
+               {
+               // Bind it
+               struct sockaddr_in addr;
+               mDNSPlatformMemZero(&addr, sizeof(addr));
+               addr.sin_family = AF_INET;
+               addr.sin_port = port->NotAnInteger;
+               err = bind(skt, (struct sockaddr*) &addr, sizeof(addr));
+               if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); return err; }
+       
+               // Receive interface identifiers
+               err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
+               if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); return err; }
+       
+               mDNSPlatformMemZero(&addr, sizeof(addr));
+               socklen_t len = sizeof(addr);
+               err = getsockname(skt, (struct sockaddr*) &addr, &len);
+               if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); return err; }
+       
+               port->NotAnInteger = addr.sin_port;
+               }
+       else
+               {
+               // Bind it
+               struct sockaddr_in6 addr6;
+               mDNSPlatformMemZero(&addr6, sizeof(addr6));
+               addr6.sin6_family = AF_INET6;
+               addr6.sin6_port = port->NotAnInteger;
+               err = bind(skt, (struct sockaddr*) &addr6, sizeof(addr6));
+               if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); return err; }
 
-Revision 1.457  2007/08/02 16:48:45  mcguire
-<rdar://problem/5329526> BTMM: Don't try to create tunnel back to same machine
+               // We want to receive destination addresses and receive interface identifiers
+        err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
+               if (err < 0) { LogMsg("ERROR: setsockopt IPV6_PKTINFO %s", strerror(errno)); return err; }
 
-Revision 1.456  2007/08/02 03:28:30  vazquez
-Make ExternalAddress and err unused to fix build warnings
+               mDNSPlatformMemZero(&addr6, sizeof(addr6));
+               socklen_t len = sizeof(addr6);
+               err = getsockname(skt, (struct sockaddr *) &addr6, &len);
+               if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); return err; }
+       
+               port->NotAnInteger = addr6.sin6_port;
 
-Revision 1.455  2007/08/01 03:09:22  cheshire
-<rdar://problem/5344587> BTMM: Create NAT port mapping for autotunnel port
+               }
+       *s = skt;
+       k->KQcallback = tcpKQSocketCallback;
+       k->KQcontext  = sock;
+       k->KQtask     = "mDNSPlatformTCPSocket";
+#ifdef __LIB_DISPATCH__
+       k->readSource = mDNSNULL;
+       k->writeSource = mDNSNULL;
+       k->fdClosed = mDNSfalse;
+#endif
+       return mStatus_NoError;
+       }
 
-Revision 1.454  2007/07/31 23:08:34  mcguire
-<rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
+mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port)
+       {
+       mStatus err;
+       (void) m;
 
-Revision 1.453  2007/07/31 19:13:58  mkrochma
-No longer need to include "btmm" in hostname to avoid name conflicts
+       TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
+       if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
 
-Revision 1.452  2007/07/27 19:30:41  cheshire
-Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
-to properly reflect tri-state nature of the possible responses
+       mDNSPlatformMemZero(sock, sizeof(TCPSocket));
 
-Revision 1.451  2007/07/25 22:25:45  cheshire
-<rdar://problem/5360853> BTMM: Code not cleaning up old racoon files
+       sock->ss.m     = m;
+       sock->ss.sktv4 = -1;
+#ifndef NO_IPV6
+       sock->ss.sktv6 = -1;
+#endif
+       err = SetupTCPSocket(sock, AF_INET, port);
+#ifndef NO_IPV6
+       if (!err)
+               {
+               err = SetupTCPSocket(sock, AF_INET6, port);
+               if (err) { mDNSPlatformCloseFD(&sock->ss.kqsv4, sock->ss.sktv4); sock->ss.sktv4 = -1; }
+               }
+#endif
+       if (err)
+               {
+               LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
+               freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
+               return(mDNSNULL);
+               }
 
-Revision 1.450  2007/07/25 21:19:10  cheshire
-<rdar://problem/5359507> Fails to build with NO_SECURITYFRAMEWORK: 'IsTunnelModeDomain' defined but not used
+       sock->callback          = mDNSNULL;
+       sock->flags             = flags;
+       sock->context           = mDNSNULL;
+       sock->setup             = mDNSfalse;
+       sock->connected         = mDNSfalse;
+       sock->handshake         = handshake_required;
+       sock->m                 = m;
+       sock->err               = mStatus_NoError;
+       
+       return sock;
+       }
 
-Revision 1.449  2007/07/25 01:36:09  mcguire
-<rdar://problem/5345290> BTMM: Replace popen() `setkey` calls to setup/teardown ipsec policies
+mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
+       {
+       KQSocketSet *cp = &sock->ss;
+#ifndef NO_IPV6
+    int         *s        = (dst->type == mDNSAddrType_IPv4) ? &cp->sktv4 : &cp->sktv6;
+    KQueueEntry *k        = (dst->type == mDNSAddrType_IPv4) ? &cp->kqsv4 : &cp->kqsv6;
+#else
+    int         *s        = &cp->sktv4;
+    KQueueEntry *k        = &cp->kqsv4;
+#endif
+       mStatus err = mStatus_NoError;
+       struct sockaddr_storage ss;
 
-Revision 1.448  2007/07/24 21:30:09  cheshire
-Added "AutoTunnel server listening for connections..." diagnostic message
+       sock->callback          = callback;
+       sock->context           = context;
+       sock->setup             = mDNSfalse;
+       sock->connected         = mDNSfalse;
+       sock->handshake         = handshake_required;
+       sock->err               = mStatus_NoError;
 
-Revision 1.447  2007/07/24 20:24:18  cheshire
-Only remove AutoTunnel address if we have created it.
-Otherwise, we get "errno 49 (Can't assign requested address)" errors on exit.
+       if (hostname) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname->c); AssignDomainName(&sock->hostname, hostname); }
 
-Revision 1.446  2007/07/24 03:00:09  cheshire
-SetDomainSecrets() should call SetupLocalAutoTunnelInterface_internal(), not SetupLocalAutoTunnelInterface()
+       if (dst->type == mDNSAddrType_IPv4)
+               {
+               struct sockaddr_in *saddr = (struct sockaddr_in *)&ss;
+               mDNSPlatformMemZero(saddr, sizeof(*saddr));
+               saddr->sin_family      = AF_INET;
+               saddr->sin_port        = dstport.NotAnInteger;
+               saddr->sin_len         = sizeof(*saddr);
+               saddr->sin_addr.s_addr = dst->ip.v4.NotAnInteger;
+               }
+       else
+               {
+               struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)&ss;
+               mDNSPlatformMemZero(saddr6, sizeof(*saddr6));
+               saddr6->sin6_family      = AF_INET6;
+               saddr6->sin6_port        = dstport.NotAnInteger;
+               saddr6->sin6_len         = sizeof(*saddr6);
+               saddr6->sin6_addr        = *(struct in6_addr *)&dst->ip.v6;
+               }
 
-Revision 1.445  2007/07/23 20:26:26  cheshire
-<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-Move code that reads "Setup:/Network/BackToMyMac" preferences outside the check
-for existence of "Setup:/Network/DynamicDNS" settings
+       // Watch for connect complete (write is ready)
+       // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
+       if (KQueueSet(*s, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, k))
+               {
+               LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
+               return errno;
+               }
 
-Revision 1.444  2007/07/21 00:54:49  cheshire
-<rdar://problem/5344576> Delay IPv6 address callback until AutoTunnel route and policy is configured
+       // Watch for incoming data
+       if (KQueueSet(*s, EV_ADD, EVFILT_READ, k))
+               {
+               LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
+               return errno;
+               }
 
-Revision 1.443  2007/07/20 23:23:11  cheshire
-Rename out-of-date name "atq" (was AutoTunnelQuery) to simpler "tun"
+       if (fcntl(*s, F_SETFL, fcntl(*s, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
+               {
+               LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
+               return mStatus_UnknownErr;
+               }
 
-Revision 1.442  2007/07/20 20:23:24  cheshire
-<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-Fixed errors reading the Setup:/Network/BackToMyMac preferences
+       // We bind to the interface and all subsequent packets including the SYN will be sent out
+       // on this interface
+       //
+       // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
+       // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
+       if (InterfaceID && InterfaceID != mDNSInterface_Unicast)
+               {
+               extern mDNS mDNSStorage;
+               NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
+               if (dst->type == mDNSAddrType_IPv4)
+                       {
+               #ifdef IP_BOUND_IF
+                       if (info) setsockopt(*s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
+                       else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
+               #else
+                       (void)InterfaceID; // Unused
+                       (void)info; // Unused
+               #endif
+                       }
+               else
+                       {
+               #ifdef IPV6_BOUND_IF
+                       if (info) setsockopt(*s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
+                       else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
+               #else
+                       (void)InterfaceID; // Unused
+                       (void)info; // Unused
+               #endif
+                       }
+               }
 
-Revision 1.441  2007/07/20 16:46:45  mcguire
-<rdar://problem/5345233> BTMM: Replace system() `route` calls to setup/teardown routes
+       // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
+       // from which we can infer the destination address family. Hence we need to remember that here.
+       // Instead of remembering the address family, we remember the right fd.
+       sock->fd = *s;
+       sock->kqEntry = k;
+       // initiate connection wth peer
+       if (connect(*s, (struct sockaddr *)&ss, ss.ss_len) < 0)
+               {
+               if (errno == EINPROGRESS) return mStatus_ConnPending;
+               if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
+                       LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
+               else
+                       LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d", sock->fd, errno, strerror(errno), ss.ss_len);
+               return mStatus_ConnFailed;
+               }
 
-Revision 1.440  2007/07/20 16:22:07  mcguire
-<rdar://problem/5344584> BTMM: Replace system() `ifconfig` calls to setup/teardown IPv6 address
+       LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
+       // kQueue should notify us, but this LogMsg is to help track down if it doesn't
+       return err;
+       }
 
-Revision 1.439  2007/07/20 01:14:56  cheshire
-<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-Cleaned up log messages
+// Why doesn't mDNSPlatformTCPAccept actually call accept() ?
+mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
+       {
+       mStatus err = mStatus_NoError;
 
-Revision 1.438  2007/07/20 00:54:21  cheshire
-<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
+       TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
+       if (!sock) return(mDNSNULL);
 
-Revision 1.437  2007/07/19 22:01:27  cheshire
-Added "#pragma mark" sections headings to divide code into related function groups
+       mDNSPlatformMemZero(sock, sizeof(*sock));
+       sock->fd = fd;
+       sock->flags = flags;
 
-Revision 1.436  2007/07/18 03:25:25  cheshire
-<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
-Bring up server-side tunnel on demand, when necessary
+       if (flags & kTCPSocketFlags_UseTLS)
+               {
+#ifndef NO_SECURITYFRAMEWORK
+               if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
 
-Revision 1.435  2007/07/18 01:05:08  cheshire
-<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
-Add list of client tunnels so we can automatically reconfigure when local address changes
+               err = tlsSetupSock(sock, mDNStrue);
+               if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
 
-Revision 1.434  2007/07/16 20:16:00  vazquez
-<rdar://problem/3867231> LegacyNATTraversal: Need complete rewrite
-Remove unnecessary LNT init code
+               err = SSLSetCertificate(sock->tlsContext, ServerCerts);
+               if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
+#else
+               err = mStatus_UnsupportedErr;
+#endif /* NO_SECURITYFRAMEWORK */
+               }
+#ifndef NO_SECURITYFRAMEWORK
+exit:
+#endif
 
-Revision 1.433  2007/07/14 00:36:07  cheshire
-Remove temporary IPv4LL tunneling mode now that IPv6-over-IPv4 is working
+       if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
+       return(sock);
+       }
 
-Revision 1.432  2007/07/12 23:55:11  cheshire
-<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
-Don't need two separate DNSQuestion structures when looking up tunnel endpoint
+mDNSlocal void CloseSocketSet(KQSocketSet *ss)
+       {
+       if (ss->sktv4 != -1)
+               {
+               mDNSPlatformCloseFD(&ss->kqsv4,  ss->sktv4);
+               ss->sktv4 = -1;
+               }
+#ifndef NO_IPV6
+       if (ss->sktv6 != -1)
+               {
+               mDNSPlatformCloseFD(&ss->kqsv6,  ss->sktv6);
+               ss->sktv6 = -1;
+               }
+#endif
+       if (ss->closeFlag) *ss->closeFlag = 1;
+       }
 
-Revision 1.431  2007/07/12 23:34:48  cheshire
-Removed 'LogOperation' message to reduce verbosity in syslog
+mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
+       {
+       if (sock)
+               {       
+#ifndef NO_SECURITYFRAMEWORK
+               if (sock->tlsContext)
+                       {
+                       if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext)
+                               {
+                               LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
+                               sock->handshake = handshake_to_be_closed;
+                               }
+                       if (sock->handshake == handshake_to_be_closed)
+                               return;
 
-Revision 1.430  2007/07/12 22:16:46  cheshire
-Improved "could not convert shared secret from base64" log message so it doesn't reveal key data in syslog
+                       SSLClose(sock->tlsContext);
+                       SSLDisposeContext(sock->tlsContext);
+                       sock->tlsContext = NULL;
+                       }
+#endif /* NO_SECURITYFRAMEWORK */
+                       if (sock->ss.sktv4 != -1) shutdown(sock->ss.sktv4, 2);
+#ifndef NO_IPV6
+                       if (sock->ss.sktv6 != -1) shutdown(sock->ss.sktv6, 2);
+#endif
+                       CloseSocketSet(&sock->ss);
+                       sock->fd = -1;
 
-Revision 1.429  2007/07/12 02:51:28  cheshire
-<rdar://problem/5303834> Automatically configure IPSec policy when resolving services
+               freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
+               }
+       }
 
-Revision 1.428  2007/07/11 23:17:31  cheshire
-<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
-Improve log message to indicate if we're starting or restarting racoon
+mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
+       {
+       size_t nread = 0;
+       *closed = mDNSfalse;
 
-Revision 1.427  2007/07/11 22:50:30  cheshire
-<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
-Write /etc/racoon/remote/anonymous.conf configuration file and start up /usr/sbin/racoon
+       if (sock->flags & kTCPSocketFlags_UseTLS)
+               {
+#ifndef NO_SECURITYFRAMEWORK
+               if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
+               else if (sock->handshake == handshake_in_progress) return 0;
+               else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake);
 
-Revision 1.426  2007/07/11 20:40:49  cheshire
-<rdar://problem/5304766> Register IPSec tunnel with IPv4-only hostname and create NAT port mappings
-In mDNSPlatformGetPrimaryInterface(), prefer routable IPv4 address to IPv4LL
+               //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
+               mStatus err = SSLRead(sock->tlsContext, buf, buflen, &nread);
+               //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
+               if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
+               else if (err && err != errSSLWouldBlock)
+                       { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
+#else
+               nread = -1;
+               *closed = mDNStrue;
+#endif /* NO_SECURITYFRAMEWORK */
+               }
+       else
+               {
+               static int CLOSEDcount = 0;
+               static int EAGAINcount = 0;
+               nread = recv(sock->fd, buf, buflen, 0);
 
-Revision 1.425  2007/07/11 19:24:19  cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for services
-Configure internal AutoTunnel address
-(For temporary testing we're faking up an IPv4LL address instead of IPv6 ULA, and we're
-assigning it with "system(commandstring);" which probably isn't the most efficient way to do it)
+               if (nread > 0) { CLOSEDcount = 0; EAGAINcount = 0; } // On success, clear our error counters
+               else if (nread == 0)
+                       {
+                       *closed = mDNStrue;
+                       if ((++CLOSEDcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount); sleep(1); }
+                       }
+               // else nread is negative -- see what kind of error we got
+               else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
+               else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; }
+               else // errno is EAGAIN (EWOULDBLOCK) -- no data available
+                       {
+                       nread = 0;
+                       if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
+                       }
+               }
 
-Revision 1.424  2007/07/11 19:00:27  cheshire
-Only need to set up m->AutoTunnelHostAddr first time through UpdateInterfaceList()
+       return nread;
+       }
 
-Revision 1.423  2007/07/11 03:00:59  cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-Add AutoTunnel parameter to mDNS_SetSecretForDomain; Generate IPv6 ULA address for tunnel endpoint
+mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
+       {
+       int nsent;
 
-Revision 1.422  2007/07/10 01:21:20  cheshire
-Added (commented out) line for displaying key data for debugging
-
-Revision 1.421  2007/06/25 20:58:11  cheshire
-<rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
-Additional refinement: Add mDNS domain list new new DynamicStore entity "State:/Network/MulticastDNS"
-
-Revision 1.420  2007/06/22 21:52:14  cheshire
-<rdar://problem/5234463> Write the Multicast DNS domains to the DynamicStore
-
-Revision 1.419  2007/06/22 21:32:00  cheshire
-<rdar://problem/5239020> Use SecKeychainCopyDefault instead of SecKeychainOpen
-
-Revision 1.418  2007/06/21 16:37:43  jgraessley
-Bug #: 5280520
-Reviewed by: Stuart Cheshire
-Additional changes to get this compiling on the embedded platform.
-
-Revision 1.417  2007/06/20 01:44:00  cheshire
-More information in "Network Configuration Change" message
-
-Revision 1.416  2007/06/20 01:10:12  cheshire
-<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-
-Revision 1.415  2007/06/15 19:23:38  cheshire
-<rdar://problem/5254053> mDNSResponder renames my host without asking
-Improve log messages, to distinguish user-initiated renames from automatic (name conflict) renames
-
-Revision 1.414  2007/05/17 22:00:59  cheshire
-<rdar://problem/5210966> Lower network change delay from two seconds to one second
-
-Revision 1.413  2007/05/16 16:43:27  cheshire
-Only log "bind" failures for our shared mDNS port and for binding to zero
--- other attempts to bind to a particular port may legitimately fail
-
-Revision 1.412  2007/05/15 21:49:21  cheshire
-Get rid of "#pragma unused"
-
-Revision 1.411  2007/05/14 23:54:55  cheshire
-Instead of sprintf, use safer length-limited mDNS_snprintf
-
-Revision 1.410  2007/05/12 01:05:00  cheshire
-Updated debugging messages
-
-Revision 1.409  2007/05/10 22:39:48  cheshire
-<rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
-Only define CountMaskBits for builds with debugging messages
-
-Revision 1.408  2007/05/10 22:19:00  cheshire
-<rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
-Don't deliver multicast packets for which we can't find an associated InterfaceID
-
-Revision 1.407  2007/05/10 21:40:28  cheshire
-Don't log unnecessary "Address already in use" errors when joining multicast groups
-
-Revision 1.406  2007/05/08 00:56:17  cheshire
-<rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
-
-Revision 1.405  2007/05/04 20:21:39  cheshire
-Improve "connect failed" error message
-
-Revision 1.404  2007/05/02 19:41:53  cheshire
-No need to alarm people with "Connection reset by peer" syslog message
-
-Revision 1.403  2007/04/28 01:31:59  cheshire
-Improve debugging support for catching memory corruption problems
-
-Revision 1.402  2007/04/26 22:54:57  cheshire
-Debugging messages to help track down <rdar://problem/5164206> mDNSResponder takes 50%+ CPU
-
-Revision 1.401  2007/04/26 00:35:16  cheshire
-<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
-Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
-inside the firewall may give answers where a public one gives none, and vice versa.)
-
-Revision 1.400  2007/04/24 21:50:27  cheshire
-Debugging: Show list of changedKeys in NetworkChanged callback
-
-Revision 1.399  2007/04/23 22:28:47  cheshire
-Allan Nathanson informs us we should only be looking at the search list for resolver[0], not all of them
-
-Revision 1.398  2007/04/23 04:57:00  cheshire
-Log messages for debugging <rdar://problem/4570952> IPv6 multicast not working properly
-
-Revision 1.397  2007/04/22 06:02:03  cheshire
-<rdar://problem/4615977> Query should immediately return failure when no server
-
-Revision 1.396  2007/04/21 21:47:47  cheshire
-<rdar://problem/4376383> Daemon: Add watchdog timer
-
-Revision 1.395  2007/04/18 20:58:34  cheshire
-<rdar://problem/5140339> Domain discovery not working over VPN
-Needed different code to handle the case where there's only a single search domain
-
-Revision 1.394  2007/04/17 23:05:50  cheshire
-<rdar://problem/3957358> Shouldn't send domain queries when we have 169.254 or loopback address
-
-Revision 1.393  2007/04/17 19:21:29  cheshire
-<rdar://problem/5140339> Domain discovery not working over VPN
-
-Revision 1.392  2007/04/17 17:15:09  cheshire
-Change NO_CFUSERNOTIFICATION code so it still logs to syslog
-
-Revision 1.391  2007/04/07 01:01:48  cheshire
-<rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
-
-Revision 1.390  2007/04/06 18:45:02  cheshire
-Fix SetupActiveInterfaces() -- accidentally changed SetupSocket parameter
-
-Revision 1.389  2007/04/05 21:39:49  cheshire
-Debugging messages to help diagnose <rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
-
-Revision 1.388  2007/04/05 21:09:52  cheshire
-Condense sprawling code
-
-Revision 1.387  2007/04/05 20:40:37  cheshire
-Remove unused mDNSPlatformTCPGetFlags()
-
-Revision 1.386  2007/04/05 19:50:56  cheshire
-Fixed memory leak: GetCertChain() was not releasing cert returned by SecIdentityCopyCertificate()
-
-Revision 1.385  2007/04/03 19:39:19  cheshire
-Fixed intel byte order bug in mDNSPlatformSetDNSServers()
-
-Revision 1.384  2007/03/31 01:10:53  cheshire
-Add debugging
-
-Revision 1.383  2007/03/31 00:13:48  cheshire
-Remove LogMsg
-
-Revision 1.382  2007/03/28 21:01:29  cheshire
-<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
-
-Revision 1.381  2007/03/28 15:56:37  cheshire
-<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
-
-Revision 1.380  2007/03/26 22:54:46  cheshire
-Fix compile error
-
-Revision 1.379  2007/03/22 18:31:48  cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.378  2007/03/22 00:49:20  cheshire
-<rdar://problem/4848295> Advertise model information via Bonjour
-
-Revision 1.377  2007/03/21 00:30:05  cheshire
-<rdar://problem/4789455> Multiple errors in DNameList-related code
-
-Revision 1.376  2007/03/20 17:07:15  cheshire
-Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-
-Revision 1.375  2007/03/20 00:50:57  cheshire
-<rdar://problem/4530644> Remove logic to disable IPv6 discovery on interfaces which have a routable IPv4 address
-
-Revision 1.374  2007/03/06 23:29:50  cheshire
-<rdar://problem/4331696> Need to call IONotificationPortDestroy on shutdown
-
-Revision 1.373  2007/02/28 01:51:20  cheshire
-Added comment about reverse-order IP address
-
-Revision 1.372  2007/02/28 01:06:48  cheshire
-Use %#a format code instead of %d.%d.%d.%d
-
-Revision 1.371  2007/02/08 21:12:28  cheshire
-<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
-
-Revision 1.370  2007/01/16 22:59:58  cheshire
-Error code ioErr is from wrong conceptual namespace; use errSSLClosedAbort instead
-
-Revision 1.369  2007/01/10 02:09:32  cheshire
-Better LogOperation record of keys read from System Keychain
-
-Revision 1.368  2007/01/10 01:25:31  cheshire
-Use symbol kDNSServiceCompPrivateDNS instead of fixed string "State:/Network/PrivateDNS"
-
-Revision 1.367  2007/01/10 01:22:01  cheshire
-Make sure c1, c2, c3 are initialized
-
-Revision 1.366  2007/01/09 22:37:20  cheshire
-Provide ten-second grace period for deleted keys, to give mDNSResponder
-time to delete host name before it gives up access to the required key.
-
-Revision 1.365  2007/01/09 21:09:20  cheshire
-Need locking in KeychainChanged()
-
-Revision 1.364  2007/01/09 20:17:04  cheshire
-mDNSPlatformGetDNSConfig() needs to initialize fields even when no "Setup:/Network/DynamicDNS" entity exists
-
-Revision 1.363  2007/01/09 02:41:18  cheshire
-uDNS_SetupDNSConfig() shouldn't be called from mDNSMacOSX.c (platform support layer);
-moved it to mDNS_Init() in mDNS.c (core code)
-
-Revision 1.362  2007/01/08 23:54:01  cheshire
-Made mDNSPlatformGetDNSConfig() more selective -- only reads prefs for non-null parameters
-
-Revision 1.361  2007/01/05 08:30:48  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.360  2007/01/04 00:12:24  cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.359  2006/12/22 21:14:37  cheshire
-Added comment explaining why we allow both "ddns" and "sndd" as valid item types
-The Keychain APIs on Intel appear to store the four-character item type backwards (at least some of the time)
-
-Revision 1.358  2006/12/22 20:59:50  cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.357  2006/12/21 00:09:45  cheshire
-Use mDNSPlatformMemZero instead of bzero
-
-Revision 1.356  2006/12/20 23:15:53  mkrochma
-Fix the private domain list code so that it actually works
-
-Revision 1.355  2006/12/20 23:04:36  mkrochma
-Fix crash when adding private domain list to Dynamic Store
-
-Revision 1.354  2006/12/19 22:43:55  cheshire
-Fix compiler warnings
-
-Revision 1.353  2006/12/14 22:08:29  cheshire
-Fixed memory leak: need to call SecKeychainItemFreeAttributesAndData()
-to release data allocated by SecKeychainItemCopyAttributesAndData()
-
-Revision 1.352  2006/12/14 02:33:26  cheshire
-<rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
-
-Revision 1.351  2006/11/28 21:37:51  mkrochma
-Tweak where the private DNS data is written
-
-Revision 1.350  2006/11/28 07:55:02  herscher
-<rdar://problem/4742743> dnsextd has a slow memory leak
-
-Revision 1.349  2006/11/28 07:45:58  herscher
-<rdar://problem/4787010> Daemon: Need to write list of private domain names to the DynamicStore
-
-Revision 1.348  2006/11/16 21:47:20  mkrochma
-<rdar://problem/4841422> uDNS: Wide-area registrations sometimes fail
-
-Revision 1.347  2006/11/10 00:54:16  cheshire
-<rdar://problem/4816598> Changing case of Computer Name doesn't work
-
-Revision 1.346  2006/10/31 02:34:58  cheshire
-<rdar://problem/4692130> Stop creating HINFO records
-
-Revision 1.345  2006/09/21 20:04:38  mkrochma
-Accidently changed function name while checking in previous fix
-
-Revision 1.344  2006/09/21 19:04:13  mkrochma
-<rdar://problem/4733803> uDNS: Update keychain format of DNS key to include prefix
-
-Revision 1.343  2006/09/15 21:20:16  cheshire
-Remove uDNS_info substructure from mDNS_struct
-
-Revision 1.342  2006/08/16 00:31:50  mkrochma
-<rdar://problem/4386944> Get rid of NotAnInteger references
-
-Revision 1.341  2006/08/14 23:24:40  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.340  2006/07/29 19:11:13  mkrochma
-Change GetUserSpecifiedDDNSConfig LogMsg to debugf
-
-Revision 1.339  2006/07/27 03:24:35  cheshire
-<rdar://problem/4049048> Convert mDNSResponder to use kqueue
-Further refinement: Declare KQueueEntry parameter "const"
-
-Revision 1.338  2006/07/27 02:59:25  cheshire
-<rdar://problem/4049048> Convert mDNSResponder to use kqueue
-Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
-after releasing BigMutex, in case actions it took have resulted in new work for the
-kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
-add new active interfaces to its list, and consequently schedule queries to be sent).
-
-Revision 1.337  2006/07/22 06:11:37  cheshire
-<rdar://problem/4049048> Convert mDNSResponder to use kqueue
-
-Revision 1.336  2006/07/15 02:01:32  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Fix broken "empty string" browsing
-
-Revision 1.335  2006/07/14 05:25:11  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Fixed crash in mDNSPlatformGetDNSConfig() reading BrowseDomains array
+       if (sock->flags & kTCPSocketFlags_UseTLS)
+               {
+#ifndef NO_SECURITYFRAMEWORK
+               size_t  processed;
+               if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
+               if (sock->handshake == handshake_in_progress) return 0;
+               else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake);
+               
+               mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
 
-Revision 1.334  2006/07/05 23:42:00  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
+               if (!err) nsent = (int) processed;
+               else if (err == errSSLWouldBlock) nsent = 0;
+               else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
+#else
+               nsent = -1;
+#endif /* NO_SECURITYFRAMEWORK */
+               }
+       else
+               {
+               nsent = send(sock->fd, msg, len, 0);
+               if (nsent < 0)
+                       {
+                       if (errno == EAGAIN) nsent = 0;
+                       else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
+                       }
+               }
 
-Revision 1.333  2006/06/29 05:33:30  cheshire
-<rdar://problem/4607043> mDNSResponder conditional compilation options
+       return nsent;
+       }
 
-Revision 1.332  2006/06/28 09:10:36  cheshire
-Extra debugging messages
+mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
+       {
+       return sock->fd;
+       }
 
-Revision 1.331  2006/06/21 22:29:42  cheshire
-Make _CFCopySystemVersionDictionary() call more defensive on systems that have no build information set
+// If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
+// If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
+mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
+       {
+#ifndef NO_IPV6
+       int         *s        = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
+       KQueueEntry     *k        = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
+#else
+       int         *s        = &cp->sktv4;
+       KQueueEntry     *k        = &cp->kqsv4;
+#endif
+       const int on = 1;
+       const int twofivefive = 255;
+       mStatus err = mStatus_NoError;
+       char *errstr = mDNSNULL;
 
-Revision 1.330  2006/06/20 23:06:00  cheshire
-Fix some keychain API type mismatches (was mDNSu32 instead of UInt32)
+#ifdef NO_IPV6
+       if (sa_family != AF_INET) return -1;
+#endif
+       
+       cp->closeFlag = mDNSNULL;
 
-Revision 1.329  2006/06/08 23:22:33  cheshire
-Comment changes
+       int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
+       if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
 
-Revision 1.328  2006/03/19 03:27:49  cheshire
-<rdar://problem/4118624> Suppress "interface flapping" logic for loopback
+       // ... with a shared UDP port, if it's for multicast receiving
+       if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort)) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
+       if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
 
-Revision 1.327  2006/03/19 02:00:09  cheshire
-<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
+       if (sa_family == AF_INET)
+               {
+               // We want to receive destination addresses
+               err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
+               if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
 
-Revision 1.326  2006/03/08 22:42:23  cheshire
-Fix spelling mistake: LocalReverseMapomain -> LocalReverseMapDomain
+               // We want to receive interface identifiers
+               err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
+               if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
 
-Revision 1.325  2006/01/10 00:39:17  cheshire
-Add comments explaining how IPv6 link-local addresses sometimes have an embedded scope_id
+               // We want to receive packet TTL value so we can check it
+               err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
+               // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
 
-Revision 1.324  2006/01/09 19:28:59  cheshire
-<rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log
+               // Send unicast packets with TTL 255
+               err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
+               if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
 
-Revision 1.323  2006/01/05 21:45:27  cheshire
-<rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
+               // And multicast packets with TTL 255 too
+               err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
+               if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
 
-Revision 1.322  2006/01/05 21:41:50  cheshire
-<rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
+               // And start listening for packets
+               struct sockaddr_in listening_sockaddr;
+               listening_sockaddr.sin_family      = AF_INET;
+               listening_sockaddr.sin_port        = port.NotAnInteger;         // Pass in opaque ID without any byte swapping
+               listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllHosts_v4.NotAnInteger : 0;
+               err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
+               if (err) { errstr = "bind"; goto fail; }
+               if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
+               }
+#ifndef NO_IPV6
+       else if (sa_family == AF_INET6)
+               {
+               // NAT-PMP Announcements make no sense on IPv6, so bail early w/o error
+               if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort; return mStatus_NoError; }
+               
+               // We want to receive destination addresses and receive interface identifiers
+               err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
+               if (err < 0) { errstr = "setsockopt - IPV6_PKTINFO"; goto fail; }
 
-Revision 1.321  2006/01/05 21:35:06  cheshire
-Add (commented out) trigger value for testing "mach_absolute_time went backwards" notice
+               // We want to receive packet hop count value so we can check it
+               err = setsockopt(skt, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
+               if (err < 0) { errstr = "setsockopt - IPV6_HOPLIMIT"; goto fail; }
 
-*/
+               // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
+               // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
+               err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
+               if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
 
-// ***************************************************************************
-// mDNSMacOSX.c:
-// Supporting routines to run mDNS on a CFRunLoop platform
-// ***************************************************************************
+               // Send unicast packets with TTL 255
+               err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
+               if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
 
-// For debugging, set LIST_ALL_INTERFACES to 1 to display all found interfaces,
-// including ones that mDNSResponder chooses not to use.
-#define LIST_ALL_INTERFACES 0
+               // And multicast packets with TTL 255 too
+               err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
+               if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
 
-// For enabling AAAA records over IPv4. Setting this to 0 sends only
-// A records over IPv4 and AAAA over IPv6. Setting this to 1 sends both
-// AAAA and A records over both IPv4 and IPv6.
-#define AAAA_OVER_V4 1
+               // Want to receive our own packets
+               err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
+               if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
 
-// In Mac OS X 10.4 and earlier, to reduce traffic, we would send and receive using IPv6 only on interfaces that had no routable
-// IPv4 address. Having a routable IPv4 address assigned is a reasonable indicator of being on a large configured network,
-// which means there's a good chance that most or all the other devices on that network should also have IPv4.
-// By doing this we lost the ability to talk to true IPv6-only devices on that link, but we cut the packet rate in half.
-// At that time, reducing the packet rate was more important than v6-only devices on a large configured network,
-// so were willing to make that sacrifice.
-// In Mac OS X 10.5, in 2007, two things have changed:
-// 1. IPv6-only devices are starting to become more common, so we can't ignore them.
-// 2. Other efficiency improvements in the code mean that crude hacks like this should no longer be necessary.
+               // And start listening for packets
+               struct sockaddr_in6 listening_sockaddr6;
+               mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
+               listening_sockaddr6.sin6_len         = sizeof(listening_sockaddr6);
+               listening_sockaddr6.sin6_family      = AF_INET6;
+               listening_sockaddr6.sin6_port        = port.NotAnInteger;               // Pass in opaque ID without any byte swapping
+               listening_sockaddr6.sin6_flowinfo    = 0;
+               listening_sockaddr6.sin6_addr        = in6addr_any; // Want to receive multicasts AND unicasts on this socket
+               listening_sockaddr6.sin6_scope_id    = 0;
+               err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
+               if (err) { errstr = "bind"; goto fail; }
+               if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
+               }
+#endif
 
-#define USE_V6_ONLY_WHEN_NO_ROUTABLE_V4 0
+       fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
+       fcntl(skt, F_SETFD, 1); // set close-on-exec
+       *s = skt;
+       k->KQcallback = myKQSocketCallBack;
+       k->KQcontext  = cp;
+       k->KQtask     = "UDP packet reception";
+#ifdef __LIB_DISPATCH__
+       k->readSource = mDNSNULL;
+       k->writeSource = mDNSNULL;
+       k->fdClosed = mDNSfalse;
+#endif
+       KQueueSet(*s, EV_ADD, EVFILT_READ, k);
 
-#include "mDNSEmbeddedAPI.h"           // Defines the interface provided to the client layer above
-#include "DNSCommon.h"
-#include "uDNS.h"
-#include "mDNSMacOSX.h"                                // Defines the specific types needed to run mDNS on this platform
-#include "dns_sd.h"                                    // For mDNSInterface_LocalOnly etc.
-#include "PlatformCommon.h"
+       return(err);
 
-#include <stdio.h>
-#include <stdarg.h>                 // For va_list support
-#include <stdlib.h>                 // For arc4random
-#include <net/if.h>
-#include <net/if_types.h>                      // For IFT_ETHER
-#include <net/if_dl.h>
-#include <net/bpf.h>                           // For BIOCSETIF etc.
-#include <sys/uio.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/sysctl.h>
-#include <sys/event.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <time.h>                   // platform support for UTC time
-#include <arpa/inet.h>              // for inet_aton
-#include <pthread.h>
-
-#include <netinet/in.h>             // For IP_RECVTTL
-#ifndef IP_RECVTTL
-#define IP_RECVTTL 24               // bool; receive reception TTL w/dgram
-#endif
-
-#include <netinet/in_systm.h>       // For n_long, required by <netinet/ip.h> below
-#include <netinet/ip.h>             // For IPTOS_LOWDELAY etc.
-#include <netinet6/in6_var.h>       // For IN6_IFF_NOTREADY etc.
-#include <netinet6/nd6.h>           // For ND6_INFINITE_LIFETIME etc.
-
-#if TARGET_OS_EMBEDDED
-#define NO_SECURITYFRAMEWORK 1
-#define NO_CFUSERNOTIFICATION 1
-#endif
-
-#ifndef NO_SECURITYFRAMEWORK
-#include <Security/SecureTransport.h>
-#include <Security/Security.h>
-#endif /* NO_SECURITYFRAMEWORK */
-
-#include <DebugServices.h>
-#include "dnsinfo.h"
-
-// Code contributed by Dave Heller:
-// Define RUN_ON_PUMA_WITHOUT_IFADDRS to compile code that will
-// work on Mac OS X 10.1, which does not have the getifaddrs call.
-#define RUN_ON_PUMA_WITHOUT_IFADDRS 0
-#if RUN_ON_PUMA_WITHOUT_IFADDRS
-#include "mDNSMacOSXPuma.c"
-#else
-#include <ifaddrs.h>
-#endif
-
-#include <IOKit/IOKitLib.h>
-#include <IOKit/IOMessage.h>
-
-#if USE_IOPMCOPYACTIVEPMPREFERENCES
-#include <IOKit/ps/IOPowerSources.h>
-#include <IOKit/ps/IOPowerSourcesPrivate.h>
-#endif
-
-#include <mach/mach_error.h>
-#include <mach/mach_port.h>
-#include <mach/mach_time.h>
-#include "helper.h"
-
-#include <asl.h>
-
-#define kInterfaceSpecificOption "interface="
-
-// ***************************************************************************
-// Globals
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark - Globals
-#endif
-
-// By default we don't offer sleep proxy service
-// If OfferSleepProxyService is set non-zero (typically via command-line switch),
-// then we'll offer sleep proxy service on desktop Macs that are set to never sleep.
-// We currently do not offer sleep proxy service on laptops, or on machines that are set to go to sleep.
-mDNSexport int OfferSleepProxyService = 0;
-
-mDNSexport int OSXVers;
-mDNSexport int KQueueFD;
-
-#ifndef NO_SECURITYFRAMEWORK
-static CFArrayRef ServerCerts;
-#endif /* NO_SECURITYFRAMEWORK */
-
-static CFStringRef NetworkChangedKey_IPv4;
-static CFStringRef NetworkChangedKey_IPv6;
-static CFStringRef NetworkChangedKey_Hostnames;
-static CFStringRef NetworkChangedKey_Computername;
-static CFStringRef NetworkChangedKey_DNS;
-static CFStringRef NetworkChangedKey_DynamicDNS  = CFSTR("Setup:/Network/DynamicDNS");
-static CFStringRef NetworkChangedKey_BackToMyMac = CFSTR("Setup:/Network/BackToMyMac");
-
-static char  HINFO_HWstring_buffer[32];
-static char *HINFO_HWstring = "Device";
-static int   HINFO_HWstring_prefixlen = 6;
-
-mDNSexport int WatchDogReportingThreshold = 250;
-
-#if APPLE_OSX_mDNSResponder
-static mDNSu8 SPMetricPortability   = 99;
-static mDNSu8 SPMetricMarginalPower = 99;
-static mDNSu8 SPMetricTotalPower    = 99;
-mDNSexport domainname ActiveDirectoryPrimaryDomain;
-mDNSexport int        ActiveDirectoryPrimaryDomainLabelCount;
-mDNSexport mDNSAddr   ActiveDirectoryPrimaryDomainServer;
-#endif // APPLE_OSX_mDNSResponder
-
-// ***************************************************************************
-// Functions
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - Utility Functions
-#endif
-
-// We only attempt to send and receive multicast packets on interfaces that are
-// (a) flagged as multicast-capable
-// (b) *not* flagged as point-to-point (e.g. modem)
-// Typically point-to-point interfaces are modems (including mobile-phone pseudo-modems), and we don't want
-// to run up the user's bill sending multicast traffic over a link where there's only a single device at the
-// other end, and that device (e.g. a modem bank) is probably not answering Multicast DNS queries anyway.
-#define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
-
-mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg) // Both strings are UTF-8 text
-       {
-       static int notifyCount = 0;
-       if (notifyCount) return;
-
-       // If we display our alert early in the boot process, then it vanishes once the desktop appears.
-       // To avoid this, we don't try to display alerts in the first three minutes after boot.
-       if ((mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return;
-
-       // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
-       #if !ForceAlerts
-               {
-               // Determine if we're at Apple (17.*.*.*)
-               extern mDNS mDNSStorage;
-               NetworkInterfaceInfoOSX *i;
-               for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
-                       if (i->ifinfo.ip.type == mDNSAddrType_IPv4 && i->ifinfo.ip.ip.v4.b[0] == 17)
-                               break;
-               if (!i) return; // If not at Apple, don't show the alert
-               }
-       #endif
-
-       LogMsg("%s", title);
-       LogMsg("%s", msg);
-       // Display a notification to the user
-       notifyCount++;
-
-#ifndef NO_CFUSERNOTIFICATION
-       mDNSNotify(title, msg);
-#endif /* NO_CFUSERNOTIFICATION */
-       }
-
-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;
-       }
-
-// To match *either* a v4 or v6 instance of this interface name, pass AF_UNSPEC for type
-mDNSlocal NetworkInterfaceInfoOSX *SearchForInterfaceByName(mDNS *const m, const char *ifname, int type)
-       {
-       NetworkInterfaceInfoOSX *i;
-       for (i = m->p->InterfaceList; i; i = i->next)
-               if (i->Exists && !strcmp(i->ifinfo.ifname, ifname) &&
-                       ((type == AF_UNSPEC                                         ) ||
-                        (type == AF_INET  && i->ifinfo.ip.type == mDNSAddrType_IPv4) ||
-                        (type == AF_INET6 && i->ifinfo.ip.type == mDNSAddrType_IPv6))) return(i);
-       return(NULL);
-       }
-
-mDNSlocal int myIfIndexToName(u_short ifindex, char *name)
-       {
-       struct ifaddrs *ifa;
-       for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
-               if (ifa->ifa_addr->sa_family == AF_LINK)
-                       if (((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == ifindex)
-                               { strlcpy(name, ifa->ifa_name, IF_NAMESIZE); return 0; }
-       return -1;
-       }
-
-mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(const mDNS *const m, mDNSInterfaceID ifindex)
-{
-       mDNSu32 scope_id = (mDNSu32)(uintptr_t)ifindex;
-       NetworkInterfaceInfoOSX *i;
-
-       // Don't get tricked by inactive interfaces
-       for (i = m->p->InterfaceList; i; i = i->next)
-               if (i->Registered && i->scope_id == scope_id) return(i);
-
-       return mDNSNULL;
-}
-
-mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
-       {
-       if (ifindex == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
-       if (ifindex == kDNSServiceInterfaceIndexAny      ) return(mDNSNULL);
-
-       NetworkInterfaceInfoOSX* ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
-       if (!ifi)
-               {
-               // Not found. Make sure our interface list is up to date, then try again.
-               LogInfo("mDNSPlatformInterfaceIDfromInterfaceIndex: InterfaceID for interface index %d not found; Updating interface list", ifindex);
-               mDNSMacOSXNetworkChanged(m);
-               ifi = IfindexToInterfaceInfoOSX(m, (mDNSInterfaceID)(uintptr_t)ifindex);
-               }
-
-       if (!ifi) return(mDNSNULL);     
-       
-       return(ifi->ifinfo.InterfaceID);
-       }
-
-
-mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id)
-       {
-       NetworkInterfaceInfoOSX *i;
-       if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
-       if (id == mDNSInterface_Any      ) return(0);
-
-       mDNSu32 scope_id = (mDNSu32)(uintptr_t)id;
-
-       // Don't use i->Registered here, because we DO want to find inactive interfaces, which have no Registered set
-       for (i = m->p->InterfaceList; i; i = i->next)
-               if (i->scope_id == scope_id) return(i->scope_id);
-
-       // Not found. Make sure our interface list is up to date, then try again.
-       LogInfo("Interface index for InterfaceID %p not found; Updating interface list", id);
-       mDNSMacOSXNetworkChanged(m);
-       for (i = m->p->InterfaceList; i; i = i->next)
-               if (i->scope_id == scope_id) return(i->scope_id);
-
-       return(0);
-       }
-
-#if APPLE_OSX_mDNSResponder
-mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...)
-       {
-       if (OSXVers < OSXVers_10_6_SnowLeopard)         return;
-
-       static char             buffer[512];
-       aslmsg                  asl_msg = asl_new(ASL_TYPE_MSG);
-
-       if (!asl_msg)   { LogMsg("mDNSASLLog: asl_new failed"); return; }
-       if (uuid)
-               {
-               char            uuidStr[37];
-               uuid_unparse(*uuid, uuidStr);
-               asl_set         (asl_msg, "com.apple.message.uuid", uuidStr);
-               }
-
-       static char     domainBase[] = "com.apple.mDNSResponder.%s";
-       mDNS_snprintf   (buffer, sizeof(buffer), domainBase, subdomain);
-       asl_set                 (asl_msg, "com.apple.message.domain", buffer);
-
-       if (result)             asl_set(asl_msg, "com.apple.message.result", result);
-       if (signature)  asl_set(asl_msg, "com.apple.message.signature", signature);
-
-       va_list ptr;
-       va_start(ptr,fmt);
-       mDNS_vsnprintf(buffer, sizeof(buffer), fmt, ptr);
-       va_end(ptr);
-
-       int     old_filter = asl_set_filter(NULL,ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG));
-       asl_log(NULL, asl_msg, ASL_LEVEL_DEBUG, "%s", buffer);
-       asl_set_filter(NULL, old_filter);
-       asl_free(asl_msg);
-       }
-#endif // APPLE_OSX_mDNSResponder
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - UDP & TCP send & receive
-#endif
-
-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
-// UPDATE: The UDPSocket *src parameter now allows the caller to specify the source socket
-mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
-       mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstPort)
-       {
-       NetworkInterfaceInfoOSX *info = mDNSNULL;
-       struct sockaddr_storage to;
-       int s = -1, err;
-       mStatus result = mStatus_NoError;
-
-       if (InterfaceID)
-               {
-               info = IfindexToInterfaceInfoOSX(m, InterfaceID);
-               if (info == NULL)
-                       {
-                       LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
-                       return mStatus_BadParamErr;
-                       }
-               }
-
-       char *ifa_name = InterfaceID ? info->ifinfo.ifname : "unicast";
-
-       if (dst->type == mDNSAddrType_IPv4)
-               {
-               struct sockaddr_in *sin_to = (struct sockaddr_in*)&to;
-               sin_to->sin_len            = sizeof(*sin_to);
-               sin_to->sin_family         = AF_INET;
-               sin_to->sin_port           = dstPort.NotAnInteger;
-               sin_to->sin_addr.s_addr    = dst->ip.v4.NotAnInteger;
-               s = (src ? src->ss : m->p->permanentsockets).sktv4;
-
-               if (info)       // Specify outgoing interface
-                       {
-                       if (!mDNSAddrIsDNSMulticast(dst))
-                               {
-                               #ifdef IP_BOUND_IF
-                                       if (info->scope_id == 0)
-                                               LogInfo("IP_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name);
-                                       else
-                                               setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
-                               #else
-                                       {
-                                       static int displayed = 0;
-                                       if (displayed < 1000)
-                                               {
-                                               displayed++;
-                                               LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
-                                               }
-                                       }
-                               #endif
-                               }
-                       else
-                               {
-                               err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
-                               if (err < 0 && !m->p->NetworkChanged)
-                                       LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
-                               }
-                       }
-               }
-       else if (dst->type == mDNSAddrType_IPv6)
-               {
-               struct sockaddr_in6 *sin6_to = (struct sockaddr_in6*)&to;
-               sin6_to->sin6_len            = sizeof(*sin6_to);
-               sin6_to->sin6_family         = AF_INET6;
-               sin6_to->sin6_port           = dstPort.NotAnInteger;
-               sin6_to->sin6_flowinfo       = 0;
-               sin6_to->sin6_addr           = *(struct in6_addr*)&dst->ip.v6;
-               sin6_to->sin6_scope_id       = info ? info->scope_id : 0;
-               s = (src ? src->ss : m->p->permanentsockets).sktv6;
-               if (info && mDNSAddrIsDNSMulticast(dst))        // Specify outgoing interface
-                       {
-                       err = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &info->scope_id, sizeof(info->scope_id));
-                       if (err < 0) LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, errno, strerror(errno));
-                       }
-               }
-       else
-               {
-               LogMsg("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
-#if ForceAlerts
-               *(long*)0 = 0;
-#endif
-               return mStatus_BadParamErr;
-               }
-
-       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);
-       else
-               verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
-                       InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
-
-       // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
-       // If we don't have the corresponding type of socket available, then return mStatus_Invalid
-       if (s < 0) return(mStatus_Invalid);
-
-       err = sendto(s, msg, (UInt8*)end - (UInt8*)msg, 0, (struct sockaddr *)&to, to.ss_len);
-       if (err < 0)
-               {
-               static int MessageCount = 0;
-               // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
-               if (!mDNSAddressIsAllDNSLinkGroup(dst))
-                       if (errno == EHOSTDOWN || errno == ENETDOWN || errno == EHOSTUNREACH || errno == ENETUNREACH) return(mStatus_TransientErr);
-               // Don't report EHOSTUNREACH in the first three minutes after boot
-               // This is because mDNSResponder intentionally starts up early in the boot process (See <rdar://problem/3409090>)
-               // but this means that sometimes it starts before configd has finished setting up the multicast routing entries.
-               if (errno == EHOSTUNREACH && (mDNSu32)(mDNSPlatformRawTime()) < (mDNSu32)(mDNSPlatformOneSecond * 180)) return(mStatus_TransientErr);
-               // 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(mStatus_TransientErr);
-               if (MessageCount < 1000)
-                       {
-                       MessageCount++;
-                       if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
-                               LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
-                                       s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
-                       else
-                               LogMsg("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
-                                       s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, errno, strerror(errno), (mDNSu32)(m->timenow));
-                       }
-               result = mStatus_UnknownErr;
-               }
-
-#ifdef IP_BOUND_IF
-       if (dst->type == mDNSAddrType_IPv4 && info && !mDNSAddrIsDNSMulticast(dst))
-               {
-               static const mDNSu32 ifindex = 0;
-               setsockopt(s, IPPROTO_IP, IP_BOUND_IF, &ifindex, sizeof(ifindex));
-               }
-#endif
-
-       return(result);
-       }
-
-mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
-       struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
-       {
-       static unsigned int numLogMessages = 0;
-       struct iovec databuffers = { (char *)buffer, max };
-       struct msghdr   msg;
-       ssize_t         n;
-       struct cmsghdr *cmPtr;
-       char            ancillary[1024];
-
-       *ttl = 255;  // If kernel fails to provide TTL data (e.g. Jaguar doesn't) then assume the TTL was 255 as it should be
-
-       // Set up the message
-       msg.msg_name       = (caddr_t)from;
-       msg.msg_namelen    = *fromlen;
-       msg.msg_iov        = &databuffers;
-       msg.msg_iovlen     = 1;
-       msg.msg_control    = (caddr_t)&ancillary;
-       msg.msg_controllen = sizeof(ancillary);
-       msg.msg_flags      = 0;
-
-       // Receive the data
-       n = recvmsg(s, &msg, 0);
-       if (n<0)
-               {
-               if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
-               return(-1);
-               }
-       if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
-               {
-               if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu",
-                       s, n, msg.msg_controllen, sizeof(struct cmsghdr));
-               return(-1);
-               }
-       if (msg.msg_flags & MSG_CTRUNC)
-               {
-               if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
-               return(-1);
-               }
-
-       *fromlen = msg.msg_namelen;
-
-       // Parse each option out of the ancillary data.
-       for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
-               {
-               // debugf("myrecvfrom cmsg_level %d cmsg_type %d", cmPtr->cmsg_level, cmPtr->cmsg_type);
-               if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVDSTADDR)
-                       {
-                       dstaddr->type = mDNSAddrType_IPv4;
-                       dstaddr->ip.v4 = *(mDNSv4Addr*)CMSG_DATA(cmPtr);
-                       //LogMsg("mDNSMacOSX.c: recvmsg IP_RECVDSTADDR %.4a", &dstaddr->ip.v4);
-                       }
-               if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVIF)
-                       {
-                       struct sockaddr_dl *sdl = (struct sockaddr_dl *)CMSG_DATA(cmPtr);
-                       if (sdl->sdl_nlen < IF_NAMESIZE)
-                               {
-                               mDNSPlatformMemCopy(ifname, sdl->sdl_data, sdl->sdl_nlen);
-                               ifname[sdl->sdl_nlen] = 0;
-                               // debugf("IP_RECVIF sdl_index %d, sdl_data %s len %d", sdl->sdl_index, ifname, sdl->sdl_nlen);
-                               }
-                       }
-               if (cmPtr->cmsg_level == IPPROTO_IP && cmPtr->cmsg_type == IP_RECVTTL)
-                       *ttl = *(u_char*)CMSG_DATA(cmPtr);
-               if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_PKTINFO)
-                       {
-                       struct in6_pktinfo *ip6_info = (struct in6_pktinfo*)CMSG_DATA(cmPtr);
-                       dstaddr->type = mDNSAddrType_IPv6;
-                       dstaddr->ip.v6 = *(mDNSv6Addr*)&ip6_info->ipi6_addr;
-                       myIfIndexToName(ip6_info->ipi6_ifindex, ifname);
-                       }
-               if (cmPtr->cmsg_level == IPPROTO_IPV6 && cmPtr->cmsg_type == IPV6_HOPLIMIT)
-                       *ttl = *(int*)CMSG_DATA(cmPtr);
-               }
-
-       return(n);
-       }
-
-mDNSlocal void myKQSocketCallBack(int s1, short filter, void *context)
-       {
-       KQSocketSet *const ss = (KQSocketSet *)context;
-       mDNS *const m = ss->m;
-       int err = 0, count = 0, closed = 0;
-
-       if (filter != EVFILT_READ)
-               LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
-
-       if (s1 != ss->sktv4 && s1 != ss->sktv6)
-               {
-               LogMsg("myKQSocketCallBack: native socket %d", s1);
-               LogMsg("myKQSocketCallBack: sktv4 %d", ss->sktv4);
-               LogMsg("myKQSocketCallBack: sktv6 %d", ss->sktv6);
-               }
-
-       while (!closed)
-               {
-               mDNSAddr senderAddr, destAddr;
-               mDNSIPPort senderPort;
-               struct sockaddr_storage from;
-               size_t fromlen = sizeof(from);
-               char packetifname[IF_NAMESIZE] = "";
-               mDNSu8 ttl;
-               err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
-               if (err < 0) break;
-
-               count++;
-               if (from.ss_family == AF_INET)
-                       {
-                       struct sockaddr_in *s = (struct sockaddr_in*)&from;
-                       senderAddr.type = mDNSAddrType_IPv4;
-                       senderAddr.ip.v4.NotAnInteger = s->sin_addr.s_addr;
-                       senderPort.NotAnInteger = s->sin_port;
-                       //LogInfo("myKQSocketCallBack received IPv4 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
-                       }
-               else if (from.ss_family == AF_INET6)
-                       {
-                       struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&from;
-                       senderAddr.type = mDNSAddrType_IPv6;
-                       senderAddr.ip.v6 = *(mDNSv6Addr*)&sin6->sin6_addr;
-                       senderPort.NotAnInteger = sin6->sin6_port;
-                       //LogInfo("myKQSocketCallBack received IPv6 packet from %#-15a to %#-15a on skt %d %s", &senderAddr, &destAddr, s1, packetifname);
-                       }
-               else
-                       {
-                       LogMsg("myKQSocketCallBack from is unknown address family %d", from.ss_family);
-                       return;
-                       }
-
-               // Note: When handling multiple packets in a batch, MUST reset InterfaceID before handling each packet
-               mDNSInterfaceID InterfaceID = mDNSNULL;
-               //NetworkInterfaceInfo *intf = m->HostInterfaces;
-               //while (intf && strcmp(intf->ifname, packetifname)) intf = intf->next;
-
-               NetworkInterfaceInfoOSX *intf = m->p->InterfaceList;
-               while (intf && strcmp(intf->ifinfo.ifname, packetifname)) intf = intf->next;
-
-               // When going to sleep we deregister all our interfaces, but if the machine
-               // takes a few seconds to sleep we may continue to receive multicasts
-               // during that time, which would confuse mDNSCoreReceive, because as far
-               // as it's concerned, we should have no active interfaces any more.
-               // Hence we ignore multicasts for which we can find no matching InterfaceID.
-               if (intf) InterfaceID = intf->ifinfo.InterfaceID;
-               else if (mDNSAddrIsDNSMulticast(&destAddr)) continue;
-
-//             LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
-//                     &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
-
-               // mDNSCoreReceive may close the socket we're reading from.  We must break out of our
-               // loop when that happens, or we may try to read from an invalid FD.  We do this by
-               // setting the closeFlag pointer in the socketset, so CloseSocketSet can inform us
-               // if it closes the socketset.
-               ss->closeFlag = &closed;
-
-               mDNSCoreReceive(m, &m->imsg, (unsigned char*)&m->imsg + err, &senderAddr, senderPort, &destAddr, ss->port, InterfaceID);
-
-               // if we didn't close, we can safely dereference the socketset, and should to
-               // reset the closeFlag, since it points to something on the stack
-               if (!closed) ss->closeFlag = mDNSNULL;
-               }
-
-       if (err < 0 && (errno != EWOULDBLOCK || count == 0))
-               {
-               // Something is busted here.
-               // kqueue says there is a packet, but myrecvfrom says there is not.
-               // Try calling select() to get another opinion.
-               // Find out about other socket parameter that can help understand why select() says the socket is ready for read
-               // All of this is racy, as data may have arrived after the call to select()
-               static unsigned int numLogMessages = 0;
-               int save_errno = errno;
-               int so_error = -1;
-               int so_nread = -1;
-               int fionread = -1;
-               socklen_t solen = sizeof(int);
-               fd_set readfds;
-               struct timeval timeout;
-               int selectresult;
-               FD_ZERO(&readfds);
-               FD_SET(s1, &readfds);
-               timeout.tv_sec  = 0;
-               timeout.tv_usec = 0;
-               selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
-               if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
-                       LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
-               if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
-                       LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
-               if (ioctl(s1, FIONREAD, &fionread) == -1)
-                       LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
-               if (numLogMessages++ < 100)
-                       LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
-                               s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
-               if (numLogMessages > 5)
-                       NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
-                               "Congratulations, you've reproduced an elusive bug.\r"
-                               "Please contact the current assignee of <rdar://problem/3375328>.\r"
-                               "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
-                               "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
-
-               sleep(1);               // After logging this error, rate limit so we don't flood syslog
-               }
-       }
-
-// TCP socket support
-
-typedef enum
-       {
-       handshake_required,
-       handshake_in_progress,
-       handshake_completed,
-       handshake_to_be_closed
-       } handshakeStatus;
-       
-struct TCPSocket_struct
-       {
-       TCPSocketFlags flags;           // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
-       TCPConnectionCallback callback;
-       int fd;
-       KQueueEntry kqEntry;
-#ifndef NO_SECURITYFRAMEWORK
-       SSLContextRef tlsContext;
-       pthread_t handshake_thread;
-#endif /* NO_SECURITYFRAMEWORK */
-       void *context;
-       mDNSBool setup;
-       mDNSBool connected;
-       handshakeStatus handshake;
-       mDNS *m; // So we can call KQueueLock from the SSLHandshake thread
-       mStatus err;
-       };
-
-mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
-       {
-       mDNSBool c = !sock->connected;
-       sock->connected = mDNStrue;
-       sock->callback(sock, sock->context, c, sock->err);
-       // Note: the callback may call CloseConnection here, which frees the context structure!
-       }
-
-#ifndef NO_SECURITYFRAMEWORK
-
-mDNSlocal OSStatus tlsWriteSock(SSLConnectionRef connection, const void *data, size_t *dataLength)
-       {
-       int ret = send(((TCPSocket *)connection)->fd, data, *dataLength, 0);
-       if (ret >= 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
-       if (ret >= 0)                              { *dataLength = ret; return(noErr); }
-       *dataLength = 0;
-       if (errno == EAGAIN                      ) return(errSSLWouldBlock);
-       if (errno == ENOENT                      ) return(errSSLClosedGraceful);
-       if (errno == EPIPE || errno == ECONNRESET) return(errSSLClosedAbort);
-       LogMsg("ERROR: tlsWriteSock: %d error %d (%s)\n", ((TCPSocket *)connection)->fd, errno, strerror(errno));
-       return(errSSLClosedAbort);
-       }
-
-mDNSlocal OSStatus tlsReadSock(SSLConnectionRef connection, void *data, size_t *dataLength)
-       {
-       int ret = recv(((TCPSocket *)connection)->fd, data, *dataLength, 0);
-       if (ret > 0 && (size_t)ret < *dataLength) { *dataLength = ret; return(errSSLWouldBlock); }
-       if (ret > 0)                              { *dataLength = ret; return(noErr); }
-       *dataLength = 0;
-       if (ret == 0 || errno == ENOENT    ) return(errSSLClosedGraceful);
-       if (            errno == EAGAIN    ) return(errSSLWouldBlock);
-       if (            errno == ECONNRESET) return(errSSLClosedAbort);
-       LogMsg("ERROR: tlsSockRead: error %d (%s)\n", errno, strerror(errno));
-       return(errSSLClosedAbort);
-       }
-
-mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, mDNSBool server)
-       {
-       mStatus err = SSLNewContext(server, &sock->tlsContext);
-       if (err) { LogMsg("ERROR: tlsSetupSock: SSLNewContext failed with error code: %d", err); return(err); }
-
-       err = SSLSetIOFuncs(sock->tlsContext, tlsReadSock, tlsWriteSock);
-       if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetIOFuncs failed with error code: %d", err); return(err); }
+       fail:
+       // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
+       if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
+               LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, errno, strerror(errno));
 
-       err = SSLSetConnection(sock->tlsContext, (SSLConnectionRef) sock);
-       if (err) { LogMsg("ERROR: tlsSetupSock: SSLSetConnection failed with error code: %d", err); return(err); }
+       // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
+       if (!strcmp(errstr, "bind") && errno == EADDRINUSE)
+               {
+               err = EADDRINUSE;
+               if (mDNSSameIPPort(port, MulticastDNSPort))
+                       NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
+                               "Congratulations, you've reproduced an elusive bug.\r"
+                               "Please contact the current assignee of <rdar://problem/3814904>.\r"
+                               "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
+                               "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
+               }
 
+       mDNSPlatformCloseFD(k, skt);
        return(err);
        }
 
-mDNSlocal void *doSSLHandshake(void *ctx)
+mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
        {
-       // Warning: Touching sock without the kqueue lock!
-       // We're protected because sock->handshake == handshake_in_progress
-       TCPSocket *sock = (TCPSocket*)ctx;
-       mDNS * const m = sock->m; // Get m now, as we may free sock if marked to be closed while we're waiting on SSLHandshake
-       mStatus err = SSLHandshake(sock->tlsContext);
-       
-       KQueueLock(m);
-       debugf("doSSLHandshake %p: got lock", sock); // Log *after* we get the lock
+       mStatus err;
+       mDNSIPPort port = requestedport;
+       mDNSBool randomizePort = mDNSIPPortIsZero(requestedport);
+       int i = 10000; // Try at most 10000 times to get a unique random port
+       UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
+       if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
+       mDNSPlatformMemZero(p, sizeof(UDPSocket));
+       p->ss.port  = zeroIPPort;
+       p->ss.m     = m;
+       p->ss.sktv4 = -1;
+#ifndef NO_IPV6
+       p->ss.sktv6 = -1;
+#endif
 
-       if (sock->handshake == handshake_to_be_closed)
-               {
-               LogInfo("SSLHandshake completed after close");
-               mDNSPlatformTCPCloseConnection(sock);
-               }
-       else
+       do
                {
-               if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry);
-               else LogMsg("doSSLHandshake: sock->fd is -1");
-
-               if (err == errSSLWouldBlock)
-                       sock->handshake = handshake_required;
-               else
+               // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
+               if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
+               err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port);
+#ifndef NO_IPV6
+               if (!err)
                        {
-                       if (err)
-                               {
-                               LogMsg("SSLHandshake failed: %d%s", err, err == errSSLPeerInternalError ? " (server busy)" : "");
-                               SSLDisposeContext(sock->tlsContext);
-                               sock->tlsContext = NULL;
-                               }
-                       
-                       sock->err = err ? mStatus_ConnFailed : 0;
-                       sock->handshake = handshake_completed;
-                       
-                       debugf("doSSLHandshake: %p calling doTcpSocketCallback", sock);
-                       doTcpSocketCallback(sock);
+                       err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port);
+                       if (err) { mDNSPlatformCloseFD(&p->ss.kqsv4, p->ss.sktv4); p->ss.sktv4 = -1; }
                        }
-               }
-       
-       debugf("SSLHandshake %p: dropping lock", sock);
-       KQueueUnlock(m, "doSSLHandshake");
-       return NULL;
-       }
+#endif
+               i--;
+               } while (err == EADDRINUSE && randomizePort && i);
 
-mDNSlocal mStatus spawnSSLHandshake(TCPSocket* sock)
-       {
-       debugf("spawnSSLHandshake %p: entry", sock);
-       if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
-       sock->handshake = handshake_in_progress;
-       KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, &sock->kqEntry);
-       pthread_attr_t attr;
-       pthread_attr_init(&attr);
-       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-       mStatus err = pthread_create(&sock->handshake_thread, &attr, doSSLHandshake, sock);
-       pthread_attr_destroy(&attr);
        if (err)
                {
-               LogMsg("Could not start SSLHandshake thread: (%d) %s", err, strerror(err));
-               sock->handshake = handshake_completed;
-               sock->err = err;
-               KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry);
+               // In customer builds we don't want to log failures with port 5351, because this is a known issue
+               // of failing to bind to this port when Internet Sharing has already bound to it
+               // We also don't want to log about port 5350, due to a known bug when some other
+               // process is bound to it.
+               if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort))
+                       LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
+               else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
+               freeL("UDPSocket", p);
+               return(mDNSNULL);
                }
-       debugf("spawnSSLHandshake %p: done", sock);
-       return err;
+       return(p);
        }
 
-mDNSlocal mDNSBool IsTunnelModeDomain(const domainname *d)
+mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
        {
-       static const domainname *mmc = (const domainname*) "\x7" "members" "\x3" "mac" "\x3" "com";
-       const domainname *d1 = mDNSNULL;        // TLD
-       const domainname *d2 = mDNSNULL;        // SLD
-       const domainname *d3 = mDNSNULL;
-       while (d->c[0]) { d3 = d2; d2 = d1; d1 = d; d = (const domainname*)(d->c + 1 + d->c[0]); }
-       return(d3 && SameDomainName(d3, mmc));
+       CloseSocketSet(&sock->ss);
+       freeL("UDPSocket", sock);
        }
 
-#endif /* NO_SECURITYFRAMEWORK */
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - BPF Raw packet sending/receiving
+#endif
 
-mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context)
-       {
-       TCPSocket *sock = context;
-       sock->err = mStatus_NoError;
+#if APPLE_OSX_mDNSResponder
 
-       //if (filter == EVFILT_READ ) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_READ", filter);
-       //if (filter == EVFILT_WRITE) LogMsg("myKQSocketCallBack: tcpKQSocketCallback %d is EVFILT_WRITE", filter);
-       // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it here with EV_DELETE
-       if (filter == EVFILT_WRITE) KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, &sock->kqEntry);
+mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
+       {
+       if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
+       NetworkInterfaceInfoOSX *info;
 
-       if (sock->flags & kTCPSocketFlags_UseTLS)
+       extern mDNS mDNSStorage;
+       info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
+       if (info == NULL)
                {
-#ifndef NO_SECURITYFRAMEWORK
-               if (!sock->setup) { sock->setup = mDNStrue; tlsSetupSock(sock, mDNSfalse); }
-               
-               if (sock->handshake == handshake_required) { if (spawnSSLHandshake(sock) == 0) return; }
-               else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed) return;
-               else if (sock->handshake != handshake_completed)
-                       {
-                       if (!sock->err) sock->err = mStatus_UnknownErr;
-                       LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
-                       }
-#else
-               sock->err = mStatus_UnsupportedErr;
-#endif /* NO_SECURITYFRAMEWORK */
+               LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
+               return;
+               }
+       if (info->BPF_fd < 0)
+               LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
+       else
+               {
+               //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
+               if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0)
+                       LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno));
                }
-       
-       doTcpSocketCallback(sock);
        }
 
-mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
+mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
        {
-       struct kevent new_event;
-       EV_SET(&new_event, fd, filter, flags, 0, 0, (void*)entryRef);
-       return (kevent(KQueueFD, &new_event, 1, NULL, 0, NULL) < 0) ? errno : 0;
+       if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: No InterfaceID specified"); return; }
+       NetworkInterfaceInfoOSX *info;
+       info = IfindexToInterfaceInfoOSX(m, InterfaceID);
+       if (info == NULL) { LogMsg("mDNSPlatformSetLocalAddressCacheEntry: Invalid interface index %p", InterfaceID); return; }
+       // Manually inject an entry into our local ARP cache.
+       // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
+       if (!mDNS_AddressIsLocalSubnet(m, InterfaceID, tpa))
+               LogSPS("Don't need address cache entry for %s %#a %.6a",            info->ifinfo.ifname, tpa, tha);
+       else
+               {
+               int result = mDNSSetLocalAddressCacheEntry(info->scope_id, tpa->type, tpa->ip.v6.b, tha->b);
+               if (result) LogMsg("Set local address cache entry for %s %#a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result);
+               else        LogSPS("Set local address cache entry for %s %#a %.6a",            info->ifinfo.ifname, tpa, tha);
+               }
        }
 
-mDNSexport void KQueueLock(mDNS *const m)
+mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
        {
-       pthread_mutex_lock(&m->p->BigMutex);
-       m->p->BigMutexStartTime = mDNSPlatformRawTime();
+       LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd);
+#ifdef __LIB_DISPATCH__
+       // close will happen in the cancel handler
+       dispatch_source_cancel(i->BPF_source);
+#else
+
+       // Note: MUST NOT close() the underlying native BSD sockets.
+       // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
+       // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
+       CFRunLoopRemoveSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
+       CFRelease(i->BPF_rls);
+       CFSocketInvalidate(i->BPF_cfs);
+       CFRelease(i->BPF_cfs);
+#endif
+       i->BPF_fd = -1;
+       if (i->BPF_mcfd >= 0) { close(i->BPF_mcfd); i->BPF_mcfd = -1; }
        }
 
-mDNSexport void KQueueUnlock(mDNS *const m, const char const *task)
+mDNSlocal void bpf_callback_common(NetworkInterfaceInfoOSX *info)
        {
-       mDNSs32 end = mDNSPlatformRawTime();
-       (void)task;
-       if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
-               LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
-
-       pthread_mutex_unlock(&m->p->BigMutex);
+       KQueueLock(info->m);
 
-       char wake = 1;
-       if (send(m->p->WakeKQueueLoopFD, &wake, sizeof(wake), 0) == -1)
-               LogMsg("ERROR: KQueueWake: send failed with error code: %d (%s)", errno, strerror(errno));
-       }
+       // Now we've got the lock, make sure the kqueue thread didn't close the fd out from under us (will not be a problem once the OS X
+       // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
+       if (info->BPF_fd < 0) goto exit;
 
-mDNSexport TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port)
-       {
-       (void) m;
+       ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len);
+       const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg;
+       const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n;
+       debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname);
 
-       TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
-       if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
+       if (n<0)
+               {
+               LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno));
+               CloseBPF(info);
+               goto exit;
+               }
 
-       mDNSPlatformMemZero(sock, sizeof(TCPSocket));
-       sock->callback          = mDNSNULL;
-       sock->fd                = socket(AF_INET, SOCK_STREAM, 0);
-       sock->kqEntry.KQcallback= tcpKQSocketCallback;
-       sock->kqEntry.KQcontext = sock;
-       sock->kqEntry.KQtask    = "mDNSPlatformTCPSocket";
-       sock->flags             = flags;
-       sock->context           = mDNSNULL;
-       sock->setup             = mDNSfalse;
-       sock->connected         = mDNSfalse;
-       sock->handshake         = handshake_required;
-       sock->m                 = m;
-       sock->err               = mStatus_NoError;
-       
-       if (sock->fd == -1)
+       while (ptr < end)
                {
-               LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
-               freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
-               return(mDNSNULL);
+               const struct bpf_hdr *const bh = (const struct bpf_hdr *)ptr;
+               debugf("%3d: bpf_callback ptr %p bh_hdrlen %d data %p bh_caplen %4d bh_datalen %4d next %p remaining %4d",
+                       info->BPF_fd, ptr, bh->bh_hdrlen, ptr + bh->bh_hdrlen, bh->bh_caplen, bh->bh_datalen,
+                       ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen), end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen)));
+               // Note that BPF guarantees that the NETWORK LAYER header will be word aligned, not the link-layer header.
+               // Given that An Ethernet header is 14 bytes, this means that if the network layer header (e.g. IP header,
+               // ARP message, etc.) is 4-byte aligned, then necessarily the Ethernet header will be NOT be 4-byte aligned.
+               mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID);
+               ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
                }
+exit:
+       KQueueUnlock(info->m, "bpf_callback");
+       }
+#ifdef __LIB_DISPATCH__
+mDNSlocal void bpf_callback_dispatch(NetworkInterfaceInfoOSX *const info)
+       {
+       bpf_callback_common(info);
+       }
+#else
+mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
+       {
+       (void)cfs;
+       (void)CallBackType;
+       (void)address;
+       (void)data;
+       bpf_callback_common((NetworkInterfaceInfoOSX *)context);
+       }
+#endif
 
-       // Bind it
-       struct sockaddr_in addr;
-       mDNSPlatformMemZero(&addr, sizeof(addr));
-       addr.sin_family = AF_INET;
-       addr.sin_addr.s_addr = htonl(INADDR_ANY);
-       addr.sin_port = port->NotAnInteger;
-       if (bind(sock->fd, (struct sockaddr*) &addr, sizeof(addr)) < 0)
-               { LogMsg("ERROR: bind %s", strerror(errno)); goto error; }
+#define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
 
-       // Receive interface identifiers
-       const int on = 1;  // "on" for setsockopt
-       if (setsockopt(sock->fd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on)) < 0)
-               { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); goto error; }
+mDNSlocal int CountProxyTargets(mDNS *const m, NetworkInterfaceInfoOSX *x, int *p4, int *p6)
+       {
+       int numv4 = 0, numv6 = 0;
+       AuthRecord *rr;
 
-       mDNSPlatformMemZero(&addr, sizeof(addr));
-       socklen_t len = sizeof(addr);
-       if (getsockname(sock->fd, (struct sockaddr*) &addr, &len) < 0)
-               { LogMsg("getsockname - %s", strerror(errno)); goto error; }
+       for (rr = m->ResourceRecords; rr; rr=rr->next)
+               if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
+                       {
+                       if (p4) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
+                       numv4++;
+                       }
 
-       port->NotAnInteger = addr.sin_port;
-       return sock;
+       for (rr = m->ResourceRecords; rr; rr=rr->next)
+               if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
+                       {
+                       if (p6) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
+                       numv6++;
+                       }
 
-error:
-       close(sock->fd);
-       freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
-       return(mDNSNULL);
+       if (p4) *p4 = numv4;
+       if (p6) *p6 = numv6;
+       return(numv4 + numv6);
        }
 
-mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
-                                          TCPConnectionCallback callback, void *context)
+mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
        {
-       struct sockaddr_in saddr;
-       mStatus err = mStatus_NoError;
+       NetworkInterfaceInfoOSX *x;
 
-       sock->callback          = callback;
-       sock->context           = context;
-       sock->setup             = mDNSfalse;
-       sock->connected         = mDNSfalse;
-       sock->handshake         = handshake_required;
-       sock->err               = mStatus_NoError;
+       // Note: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
+       for (x = m->p->InterfaceList; x; x = x->next) if (x->ifinfo.InterfaceID == InterfaceID) break;
 
-       (void) InterfaceID;     //!!!KRS use this if non-zero!!!
+       if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
+
+       #define MAX_BPF_ADDRS 250
+       int numv4 = 0, numv6 = 0;
 
-       if (dst->type != mDNSAddrType_IPv4)
+       if (CountProxyTargets(m, x, &numv4, &numv6) > MAX_BPF_ADDRS)
                {
-               LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: opperation not supported");
-               return mStatus_UnknownErr;
+               LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6);
+               if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS;
+               numv6 = MAX_BPF_ADDRS - numv4;
                }
 
-       mDNSPlatformMemZero(&saddr, sizeof(saddr));
-       saddr.sin_family      = AF_INET;
-       saddr.sin_port        = dstport.NotAnInteger;
-       saddr.sin_len         = sizeof(saddr);
-       saddr.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
-
-       sock->kqEntry.KQcallback = tcpKQSocketCallback;
-       sock->kqEntry.KQcontext  = sock;
-       sock->kqEntry.KQtask     = "Outgoing TCP";
+       LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC  %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6);
 
-       // Watch for connect complete (write is ready)
-       // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
-       if (KQueueSet(sock->fd, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, &sock->kqEntry))
+       // Caution: This is a static structure, so we need to be careful that any modifications we make to it
+       // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
+       static struct bpf_insn filter[17 + MAX_BPF_ADDRS] =
                {
-               LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
-               close(sock->fd);
-               return errno;
-               }
+               BPF_STMT(BPF_LD  + BPF_H   + BPF_ABS, 12),                              // 0 Read Ethertype (bytes 12,13)
 
-       // Watch for incoming data
-       if (KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry))
-               {
-               LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
-               close(sock->fd); // Closing the descriptor removes all filters from the kqueue
-               return errno;
-               }
+               BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1),              // 1 If Ethertype == ARP goto next, else 3
+               BPF_STMT(BPF_RET + BPF_K,             42),                              // 2 Return 42-byte ARP
 
-       if (fcntl(sock->fd, F_SETFL, fcntl(sock->fd, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
-               {
-               LogMsg("ERROR: setsockopt O_NONBLOCK - %s", strerror(errno));
-               return mStatus_UnknownErr;
-               }
+               BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0),              // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
 
-       // initiate connection wth peer
-       if (connect(sock->fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
-               {
-               if (errno == EINPROGRESS) return mStatus_ConnPending;
-               if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
-                       LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
-               else
-                       LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)", sock->fd, errno, strerror(errno));
-               close(sock->fd);
-               return mStatus_ConnFailed;
-               }
+               BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9),              // 4 If Ethertype == IPv6 goto next, else exit
+               BPF_STMT(BPF_LD  + BPF_H   + BPF_ABS, 20),                              // 5 Read Protocol and Hop Limit (bytes 20,21)
+               BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9),              // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
+               BPF_STMT(BPF_RET + BPF_K,             86),                              // 7 Return 86-byte ND
 
-       LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
-       // kQueue should notify us, but this LogMsg is to help track down if it doesn't
-       return err;
-       }
+               // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
+               BPF_STMT(BPF_LD  + BPF_W   + BPF_ABS, 30),                              // 8 Read IPv4 Dst (bytes 30,31,32,33)
+               };
 
-// Why doesn't mDNSPlatformTCPAccept actually call accept() ?
-mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
-       {
-       mStatus err = mStatus_NoError;
+       struct bpf_insn *pc   = &filter[9];
+       struct bpf_insn *chk6 = pc   + numv4 + 1;       // numv4 address checks, plus a "return 0"
+       struct bpf_insn *fail = chk6 + 1 + numv6;       // Get v6 Dst LSW, plus numv6 address checks
+       struct bpf_insn *ret4 = fail + 1;
+       struct bpf_insn *ret6 = ret4 + 4;
 
-       TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
-       if (!sock) return(mDNSNULL);
+       static const struct bpf_insn rf  = BPF_STMT(BPF_RET + BPF_K, 0);                                // No match: Return nothing
 
-       mDNSPlatformMemZero(sock, sizeof(*sock));
-       sock->fd = fd;
-       sock->flags = flags;
+       static const struct bpf_insn g6  = BPF_STMT(BPF_LD  + BPF_W   + BPF_ABS, 50);   // Read IPv6 Dst LSW (bytes 50,51,52,53)
 
-       if (flags & kTCPSocketFlags_UseTLS)
-               {
-#ifndef NO_SECURITYFRAMEWORK
-               if (!ServerCerts) { LogMsg("ERROR: mDNSPlatformTCPAccept: unable to find TLS certificates"); err = mStatus_UnknownErr; goto exit; }
+       static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B   + BPF_MSH, 14);   // Get IP Header length (normally 20)
+       static const struct bpf_insn r4b = BPF_STMT(BPF_LD  + BPF_IMM,           54);   // A = 54 (14-byte Ethernet plus 20-byte TCP + 20 bytes spare)
+       static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X,    0);   // A += IP Header length
+       static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0);                                // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
 
-               err = tlsSetupSock(sock, mDNStrue);
-               if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: tlsSetupSock failed with error code: %d", err); goto exit; }
+       static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94);                               // Success: Return Eth + IPv6 + TCP + 20 bytes spare
 
-               err = SSLSetCertificate(sock->tlsContext, ServerCerts);
-               if (err) { LogMsg("ERROR: mDNSPlatformTCPAccept: SSLSetCertificate failed with error code: %d", err); goto exit; }
-#else
-               err = mStatus_UnsupportedErr;
-#endif /* NO_SECURITYFRAMEWORK */
-               }
-#ifndef NO_SECURITYFRAMEWORK
-exit:
-#endif
+       BPF_SetOffset(&filter[4], jf, fail);    // If Ethertype not ARP, IPv4, or IPv6, fail
+       BPF_SetOffset(&filter[6], jf, chk6);    // If IPv6 but not ICMPv6, go to IPv6 address list check
 
-       if (err) { freeL("TCPSocket/mDNSPlatformTCPAccept", sock); return(mDNSNULL); }
-       return(sock);
-       }
+       // BPF Byte-Order Note
+       // The BPF API designers apparently thought that programmers would not be smart enough to use htons
+       // and htonl correctly to convert numeric values to network byte order on little-endian machines,
+       // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
+       // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
+       // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
+       // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
+       // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
+       // so that when the BPF API goes through and swaps them all, they end up back as they should be.
+       // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
+       // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
 
-mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
-       {
-       if (sock)
-               {       
-#ifndef NO_SECURITYFRAMEWORK
-               if (sock->tlsContext)
-                       {
-                       if (sock->handshake == handshake_in_progress) // SSLHandshake thread using this sock (esp. tlsContext)
-                               {
-                               LogInfo("mDNSPlatformTCPCloseConnection: called while handshake in progress");
-                               sock->handshake = handshake_to_be_closed;
-                               }
-                       if (sock->handshake == handshake_to_be_closed)
-                               return;
+       // IPSEC capture size notes:
+       //  8 bytes UDP header
+       //  4 bytes Non-ESP Marker
+       // 28 bytes IKE Header
+       // --
+       // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
 
-                       SSLClose(sock->tlsContext);
-                       SSLDisposeContext(sock->tlsContext);
-                       sock->tlsContext = NULL;
+       AuthRecord *rr;
+       for (rr = m->ResourceRecords; rr; rr=rr->next)
+               if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
+                       {
+                       mDNSv4Addr a = rr->AddressProxy.ip.v4;
+                       pc->code = BPF_JMP + BPF_JEQ + BPF_K;
+                       BPF_SetOffset(pc, jt, ret4);
+                       pc->jf   = 0;
+                       pc->k    = (bpf_u_int32)a.b[0] << 24 | (bpf_u_int32)a.b[1] << 16 | (bpf_u_int32)a.b[2] << 8 | (bpf_u_int32)a.b[3];
+                       pc++;
                        }
-#endif /* NO_SECURITYFRAMEWORK */
-               if (sock->fd != -1)
+       *pc++ = rf;
+
+       if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
+       *pc++ = g6;     // chk6 points here
+
+       // First cancel any previous ND group memberships we had, then create a fresh socket
+       if (x->BPF_mcfd >= 0) close(x->BPF_mcfd);
+       x->BPF_mcfd = socket(AF_INET6, SOCK_DGRAM, 0);
+
+       for (rr = m->ResourceRecords; rr; rr=rr->next)
+               if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
                        {
-                       shutdown(sock->fd, 2);
-                       close(sock->fd);
-                       sock->fd = -1;
+                       const mDNSv6Addr *const a = &rr->AddressProxy.ip.v6;
+                       pc->code = BPF_JMP + BPF_JEQ + BPF_K;
+                       BPF_SetOffset(pc, jt, ret6);
+                       pc->jf   = 0;
+                       pc->k    = (bpf_u_int32)a->b[0x0C] << 24 | (bpf_u_int32)a->b[0x0D] << 16 | (bpf_u_int32)a->b[0x0E] << 8 | (bpf_u_int32)a->b[0x0F];
+                       pc++;
+
+                       struct ipv6_mreq i6mr;
+                       i6mr.ipv6mr_interface = x->scope_id;
+                       i6mr.ipv6mr_multiaddr = *(const struct in6_addr*)&NDP_prefix;
+                       i6mr.ipv6mr_multiaddr.s6_addr[0xD] = a->b[0xD];
+                       i6mr.ipv6mr_multiaddr.s6_addr[0xE] = a->b[0xE];
+                       i6mr.ipv6mr_multiaddr.s6_addr[0xF] = a->b[0xF];
+
+                       // Do precautionary IPV6_LEAVE_GROUP first, necessary to clear stale kernel state
+                       mStatus err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &i6mr, sizeof(i6mr));
+                       if (err < 0 && (errno != EADDRNOTAVAIL))
+                               LogMsg("mDNSPlatformUpdateProxyList: IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
+
+                       err = setsockopt(x->BPF_mcfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &i6mr, sizeof(i6mr));
+                       if (err < 0 && (errno != EADDRINUSE))   // Joining same group twice can give "Address already in use" error -- no need to report that
+                               LogMsg("mDNSPlatformUpdateProxyList: IPV6_JOIN_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
+                       
+                       LogSPS("Joined IPv6 ND multicast group %.16a for %.16a", &i6mr.ipv6mr_multiaddr, a);
                        }
 
-               freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
-               }
-       }
+       if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
+       *pc++ = rf;             // fail points here
 
-mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed)
-       {
-       long nread = 0;
-       *closed = mDNSfalse;
+       if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
+       *pc++ = r4a;    // ret4 points here
+       *pc++ = r4b;
+       *pc++ = r4c;
+       *pc++ = r4d;
 
-       if (sock->flags & kTCPSocketFlags_UseTLS)
-               {
-#ifndef NO_SECURITYFRAMEWORK
-               if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformReadTCP called while handshake required"); return 0; }
-               else if (sock->handshake == handshake_in_progress) return 0;
-               else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformReadTCP called with unexpected SSLHandshake status: %d", sock->handshake);
+       if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
+       *pc++ = r6a;    // ret6 points here
 
-               //LogMsg("Starting SSLRead %d %X", sock->fd, fcntl(sock->fd, F_GETFL, 0));
-               mStatus err = SSLRead(sock->tlsContext, buf, buflen, (size_t*)&nread);
-               //LogMsg("SSLRead returned %d (%d) nread %d buflen %d", err, errSSLWouldBlock, nread, buflen);
-               if (err == errSSLClosedGraceful) { nread = 0; *closed = mDNStrue; }
-               else if (err && err != errSSLWouldBlock)
-                       { LogMsg("ERROR: mDNSPlatformReadTCP - SSLRead: %d", err); nread = -1; *closed = mDNStrue; }
-#else
-               nread = -1;
-               *closed = mDNStrue;
-#endif /* NO_SECURITYFRAMEWORK */
+       struct bpf_program prog = { pc - filter, filter };
+
+#if 0
+       // For debugging BPF filter program
+       unsigned int q;
+       for (q=0; q<prog.bf_len; q++)
+               LogSPS("mDNSPlatformUpdateProxyList: %2d { 0x%02x, %d, %d, 0x%08x },", q, prog.bf_insns[q].code, prog.bf_insns[q].jt, prog.bf_insns[q].jf, prog.bf_insns[q].k);
+#endif
+
+       if (!numv4 && !numv6)
+               {
+               LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
+               if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
+               // Schedule check to see if we can close this BPF_fd now
+               if (!m->p->NetworkChanged) m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
+               // prog.bf_len = 0; This seems to panic the kernel
+               if (x->BPF_fd < 0) return;              // If we've already closed our BPF_fd, no need to generate an error message below
                }
+
+       if (ioctl(x->BPF_fd, BIOCSETF, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETF(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno));
+       else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETF(%d) successful", prog.bf_len);
+       }
+
+mDNSexport void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd)
+       {
+       mDNS_Lock(m);
+       
+       NetworkInterfaceInfoOSX *i;
+       for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break;
+       if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); }
        else
                {
-               static int CLOSEDcount = 0;
-               static int EAGAINcount = 0;
-               nread = recv(sock->fd, buf, buflen, 0);
-
-               if (nread > 0) { CLOSEDcount = 0; EAGAINcount = 0; } // On success, clear our error counters
-               else if (nread == 0)
+               LogSPS("%s using   BPF fd %d", i->ifinfo.ifname, fd);
+       
+               struct bpf_version v;
+               if (ioctl(fd, BIOCVERSION, &v) < 0)
+                       LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+               else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor)
+                       LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
+                               fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor);
+       
+               if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0)
+                       LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+       
+               if (i->BPF_len > sizeof(m->imsg))
                        {
-                       *closed = mDNStrue;
-                       if ((++CLOSEDcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got CLOSED %d times", sock->fd, CLOSEDcount); sleep(1); }
+                       i->BPF_len = sizeof(m->imsg);
+                       if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0)
+                               LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+                       else LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", i->BPF_len);
                        }
-               // else nread is negative -- see what kind of error we got
-               else if (errno == ECONNRESET) { nread = 0; *closed = mDNStrue; }
-               else if (errno != EAGAIN) { LogMsg("ERROR: mDNSPlatformReadTCP - recv: %d (%s)", errno, strerror(errno)); nread = -1; }
-               else // errno is EAGAIN (EWOULDBLOCK) -- no data available
+       
+               static const u_int opt_one = 1;
+               if (ioctl(fd, BIOCIMMEDIATE, &opt_one) < 0)
+                       LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+       
+               //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
+               //      LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+       
+               //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
+               //      LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+       
+               struct ifreq ifr;
+               mDNSPlatformMemZero(&ifr, sizeof(ifr));
+               strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
+               if (ioctl(fd, BIOCSETIF, &ifr) < 0)
+                       { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; }
+               else
                        {
-                       nread = 0;
-                       if ((++EAGAINcount % 1000) == 0) { LogMsg("ERROR: mDNSPlatformReadTCP - recv %d got EAGAIN %d times", sock->fd, EAGAINcount); sleep(1); }
+#ifdef __LIB_DISPATCH__
+                       i->BPF_fd  = fd;
+                       i->BPF_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dispatch_get_main_queue());
+                       if (!i->BPF_source) {LogMsg("mDNSPlatformReceiveBPF_fd: dispatch source create failed");return;}
+                       dispatch_source_set_event_handler(i->BPF_source, ^{bpf_callback_dispatch(i);});
+                       dispatch_source_set_cancel_handler(i->BPF_source, ^{close(fd);});
+                       dispatch_resume(i->BPF_source);
+#else
+                       CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL };
+                       i->BPF_fd  = fd;
+                       i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext);
+                       i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
+                       CFRunLoopAddSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
+#endif
+                       mDNSPlatformUpdateProxyList(m, i->ifinfo.InterfaceID);
                        }
                }
 
-       return nread;
+       mDNS_Unlock(m);
        }
 
-mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
-       {
-       int nsent;
+#endif // APPLE_OSX_mDNSResponder
 
-       if (sock->flags & kTCPSocketFlags_UseTLS)
-               {
-#ifndef NO_SECURITYFRAMEWORK
-               size_t  processed;
-               if (sock->handshake == handshake_required) { LogMsg("mDNSPlatformWriteTCP called while handshake required"); return 0; }
-               if (sock->handshake == handshake_in_progress) return 0;
-               else if (sock->handshake != handshake_completed) LogMsg("mDNSPlatformWriteTCP called with unexpected SSLHandshake status: %d", sock->handshake);
-               
-               mStatus err = SSLWrite(sock->tlsContext, msg, len, &processed);
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - Key Management
+#endif
 
-               if (!err) nsent = (int) processed;
-               else if (err == errSSLWouldBlock) nsent = 0;
-               else { LogMsg("ERROR: mDNSPlatformWriteTCP - SSLWrite returned %d", err); nsent = -1; }
-#else
-               nsent = -1;
-#endif /* NO_SECURITYFRAMEWORK */
-               }
+#ifndef NO_SECURITYFRAMEWORK
+mDNSlocal CFArrayRef GetCertChain(SecIdentityRef identity)
+       {
+       CFMutableArrayRef certChain = NULL;
+       if (!identity) { LogMsg("getCertChain: identity is NULL"); return(NULL); }
+       SecCertificateRef cert;
+       OSStatus err = SecIdentityCopyCertificate(identity, &cert);
+       if (err || !cert) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
        else
                {
-               nsent = send(sock->fd, msg, len, 0);
-               if (nsent < 0)
+               SecPolicySearchRef searchRef;
+               err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
+               if (err || !searchRef) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err);
+               else
                        {
-                       if (errno == EAGAIN) nsent = 0;
-                       else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
+                       SecPolicyRef policy;
+                       err = SecPolicySearchCopyNext(searchRef, &policy);
+                       if (err || !policy) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
+                       else
+                               {
+                               CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
+                               if (!wrappedCert) LogMsg("getCertChain: wrappedCert is NULL");
+                               else
+                                       {
+                                       SecTrustRef trust;
+                                       err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
+                                       if (err || !trust) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
+                                       else
+                                               {
+                                               err = SecTrustEvaluate(trust, NULL);
+                                               if (err) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err);
+                                               else
+                                                       {
+                                                       CFArrayRef rawCertChain;
+                                                       CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
+                                                       err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
+                                                       if (err || !rawCertChain || !statusChain) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err);
+                                                       else
+                                                               {
+                                                               certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
+                                                               if (!certChain) LogMsg("getCertChain: certChain is NULL");
+                                                               else
+                                                                       {
+                                                                       // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
+                                                                       // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
+                                                                       CFArraySetValueAtIndex(certChain, 0, identity);
+                                                                       // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
+                                                                       if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
+                                                                       }
+                                                               CFRelease(rawCertChain);
+                                                               // Do not free statusChain:
+                                                               // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
+                                                               // certChain: Call the CFRelease function to release this object when you are finished with it.
+                                                               // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
+                                                               }
+                                                       }
+                                               CFRelease(trust);
+                                               }
+                                       CFRelease(wrappedCert);
+                                       }
+                               CFRelease(policy);
+                               }
+                       CFRelease(searchRef);
                        }
+               CFRelease(cert);
                }
-
-       return nsent;
-       }
-
-mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
-       {
-       return sock->fd;
+       return certChain;
        }
+#endif /* NO_SECURITYFRAMEWORK */
 
-// If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
-// If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
-mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
+mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
        {
-       int         *s        = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
-       KQueueEntry     *k        = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
-       const int on = 1;
-       const int twofivefive = 255;
-       mStatus err = mStatus_NoError;
-       char *errstr = mDNSNULL;
-       
-       cp->closeFlag = mDNSNULL;
-
-       int skt = socket(sa_family, SOCK_DGRAM, IPPROTO_UDP);
-       if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno)); return(skt); }
+#ifdef NO_SECURITYFRAMEWORK
+       return mStatus_UnsupportedErr;
+#else
+       SecIdentityRef                  identity = nil;
+       SecIdentitySearchRef    srchRef = nil;
+       OSStatus                                err;
 
-       // ... with a shared UDP port, if it's for multicast receiving
-       if (mDNSSameIPPort(port, MulticastDNSPort) || mDNSSameIPPort(port, NATPMPAnnouncementPort)) err = setsockopt(skt, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
-       if (err < 0) { errstr = "setsockopt - SO_REUSEPORT"; goto fail; }
+       // search for "any" identity matching specified key use
+       // In this app, we expect there to be exactly one
+       err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
+       if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
 
-       if (sa_family == AF_INET)
-               {
-               // We want to receive destination addresses
-               err = setsockopt(skt, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof(on));
-               if (err < 0) { errstr = "setsockopt - IP_RECVDSTADDR"; goto fail; }
+       err = SecIdentitySearchCopyNext(srchRef, &identity);
+       if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
 
-               // We want to receive interface identifiers
-               err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
-               if (err < 0) { errstr = "setsockopt - IP_RECVIF"; goto fail; }
+       if (CFGetTypeID(identity) != SecIdentityGetTypeID())
+               { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
 
-               // We want to receive packet TTL value so we can check it
-               err = setsockopt(skt, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on));
-               // We ignore errors here -- we already know Jaguar doesn't support this, but we can get by without it
+       // Found one. Call getCertChain to create the correct certificate chain.
+       ServerCerts = GetCertChain(identity);
+       if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr; }
 
-               // Send unicast packets with TTL 255
-               err = setsockopt(skt, IPPROTO_IP, IP_TTL, &twofivefive, sizeof(twofivefive));
-               if (err < 0) { errstr = "setsockopt - IP_TTL"; goto fail; }
+       return mStatus_NoError;
+#endif /* NO_SECURITYFRAMEWORK */
+       }
 
-               // And multicast packets with TTL 255 too
-               err = setsockopt(skt, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive));
-               if (err < 0) { errstr = "setsockopt - IP_MULTICAST_TTL"; goto fail; }
+mDNSexport  void  mDNSPlatformTLSTearDownCerts(void)
+       {
+#ifndef NO_SECURITYFRAMEWORK
+       if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
+#endif /* NO_SECURITYFRAMEWORK */
+       }
 
-               // And start listening for packets
-               struct sockaddr_in listening_sockaddr;
-               listening_sockaddr.sin_family      = AF_INET;
-               listening_sockaddr.sin_port        = port.NotAnInteger;         // Pass in opaque ID without any byte swapping
-               listening_sockaddr.sin_addr.s_addr = mDNSSameIPPort(port, NATPMPAnnouncementPort) ? AllSystemsMcast.NotAnInteger : 0;
-               err = bind(skt, (struct sockaddr *) &listening_sockaddr, sizeof(listening_sockaddr));
-               if (err) { errstr = "bind"; goto fail; }
-               if (outport) outport->NotAnInteger = listening_sockaddr.sin_port;
-               }
-       else if (sa_family == AF_INET6)
+// This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
+mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
+       {
+       CFStringEncoding encoding = kCFStringEncodingUTF8;
+       CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
+       if (cfs)
                {
-               // NAT-PMP Announcements make no sense on IPv6, so bail early w/o error
-               if (mDNSSameIPPort(port, NATPMPAnnouncementPort)) { if (outport) *outport = zeroIPPort; return mStatus_NoError; }
-               
-               // We want to receive destination addresses and receive interface identifiers
-               err = setsockopt(skt, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on));
-               if (err < 0) { errstr = "setsockopt - IPV6_PKTINFO"; goto fail; }
-
-               // We want to receive packet hop count value so we can check it
-               err = setsockopt(skt, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
-               if (err < 0) { errstr = "setsockopt - IPV6_HOPLIMIT"; goto fail; }
-
-               // We want to receive only IPv6 packets. Without this option we get IPv4 packets too,
-               // with mapped addresses of the form 0:0:0:0:0:FFFF:xxxx:xxxx, where xxxx:xxxx is the IPv4 address
-               err = setsockopt(skt, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
-               if (err < 0) { errstr = "setsockopt - IPV6_V6ONLY"; goto fail; }
-
-               // Send unicast packets with TTL 255
-               err = setsockopt(skt, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &twofivefive, sizeof(twofivefive));
-               if (err < 0) { errstr = "setsockopt - IPV6_UNICAST_HOPS"; goto fail; }
-
-               // And multicast packets with TTL 255 too
-               err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &twofivefive, sizeof(twofivefive));
-               if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_HOPS"; goto fail; }
-
-               // Want to receive our own packets
-               err = setsockopt(skt, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &on, sizeof(on));
-               if (err < 0) { errstr = "setsockopt - IPV6_MULTICAST_LOOP"; goto fail; }
-
-               // And start listening for packets
-               struct sockaddr_in6 listening_sockaddr6;
-               mDNSPlatformMemZero(&listening_sockaddr6, sizeof(listening_sockaddr6));
-               listening_sockaddr6.sin6_len         = sizeof(listening_sockaddr6);
-               listening_sockaddr6.sin6_family      = AF_INET6;
-               listening_sockaddr6.sin6_port        = port.NotAnInteger;               // Pass in opaque ID without any byte swapping
-               listening_sockaddr6.sin6_flowinfo    = 0;
-               listening_sockaddr6.sin6_addr        = in6addr_any; // Want to receive multicasts AND unicasts on this socket
-               listening_sockaddr6.sin6_scope_id    = 0;
-               err = bind(skt, (struct sockaddr *) &listening_sockaddr6, sizeof(listening_sockaddr6));
-               if (err) { errstr = "bind"; goto fail; }
-               if (outport) outport->NotAnInteger = listening_sockaddr6.sin6_port;
+               CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
+               CFRelease(cfs);
                }
+       }
 
-       fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
-       fcntl(skt, F_SETFD, 1); // set close-on-exec
-       *s = skt;
-       k->KQcallback = myKQSocketCallBack;
-       k->KQcontext  = cp;
-       k->KQtask     = "UDP packet reception";
-       KQueueSet(*s, EV_ADD, EVFILT_READ, k);
-
-       return(err);
-
-       fail:
-       // For "bind" failures, only write log messages for our shared mDNS port, or for binding to zero
-       if (strcmp(errstr, "bind") || mDNSSameIPPort(port, MulticastDNSPort) || mDNSIPPortIsZero(port))
-               LogMsg("%s skt %d port %d error %d errno %d (%s)", errstr, skt, mDNSVal16(port), err, errno, strerror(errno));
-
-       // If we got a "bind" failure of EADDRINUSE, inform the caller as it might need to try another random port
-       if (!strcmp(errstr, "bind") && errno == EADDRINUSE)
+// This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
+mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
+       {
+       CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
+       if (cfs)
                {
-               err = EADDRINUSE;
-               if (mDNSSameIPPort(port, MulticastDNSPort))
-                       NotifyOfElusiveBug("Setsockopt SO_REUSEPORT failed",
-                               "Congratulations, you've reproduced an elusive bug.\r"
-                               "Please contact the current assignee of <rdar://problem/3814904>.\r"
-                               "Alternatively, you can send email to radar-3387020@group.apple.com. (Note number is different.)\r"
-                               "If possible, please leave your machine undisturbed so that someone can come to investigate the problem.");
+               CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
+               CFRelease(cfs);
                }
+       }
 
-       close(skt);
-       return(err);
+mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
+       {
+       mDNSs32 val;
+       CFNumberRef state = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("Enabled"));
+       if (!state) return mDNSfalse;
+       if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
+               { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
+       return val ? mDNStrue : mDNSfalse;
        }
 
-mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
+mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
        {
-       mStatus err;
-       mDNSIPPort port = requestedport;
-       mDNSBool randomizePort = mDNSIPPortIsZero(requestedport);
-       int i = 10000; // Try at most 10000 times to get a unique random port
-       UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
-       if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
-       mDNSPlatformMemZero(p, sizeof(UDPSocket));
-       p->ss.port  = zeroIPPort;
-       p->ss.m     = m;
-       p->ss.sktv4 = -1;
-       p->ss.sktv6 = -1;
+       if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
 
-       do
+       if (sa->sa_family == AF_INET)
                {
-               // The kernel doesn't do cryptographically strong random port allocation, so we do it ourselves here
-               if (randomizePort) port = mDNSOpaque16fromIntVal(0xC000 + mDNSRandom(0x3FFF));
-               err = SetupSocket(&p->ss, port, AF_INET, &p->ss.port);
-               if (!err)
-                       {
-                       err = SetupSocket(&p->ss, port, AF_INET6, &p->ss.port);
-                       if (err) { close(p->ss.sktv4); p->ss.sktv4 = -1; }
-                       }
-               i--;
-               } while (err == EADDRINUSE && randomizePort && i);
+               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 (err)
+       if (sa->sa_family == AF_INET6)
                {
-               // In customer builds we don't want to log failures with port 5351, because this is a known issue
-               // of failing to bind to this port when Internet Sharing has already bound to it
-               // We also don't want to log about port 5350, due to a known bug when some other
-               // process is bound to it.
-               if (mDNSSameIPPort(requestedport, NATPMPPort) || mDNSSameIPPort(requestedport, NATPMPAnnouncementPort))
-                       LogInfo("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
-               else LogMsg("mDNSPlatformUDPSocket: SetupSocket %d failed error %d errno %d (%s)", mDNSVal16(requestedport), err, errno, strerror(errno));
-               freeL("UDPSocket", p);
-               return(mDNSNULL);
+               struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
+               // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
+               // value into the second word of the IPv6 link-local address, so they can just
+               // pass around IPv6 address structures instead of full sockaddr_in6 structures.
+               // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
+               // To work around this we always whack the second word of any IPv6 link-local address back to zero.
+               if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
+               ip->type = mDNSAddrType_IPv6;
+               ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
+               return(mStatus_NoError);
                }
-       return(p);
+
+       LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
+       return(mStatus_Invalid);
        }
 
-mDNSlocal void CloseSocketSet(KQSocketSet *ss)
+mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
        {
-       if (ss->sktv4 != -1)
-               {
-               close(ss->sktv4);
-               ss->sktv4 = -1;
-               }
-       if (ss->sktv6 != -1)
+       mDNSEthAddr eth = zeroEthAddr;
+       SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetBSSID"), NULL, NULL);
+       if (!store)
+               LogMsg("GetBSSID: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
+       else
                {
-               close(ss->sktv6);
-               ss->sktv6 = -1;
+               CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
+               if (entityname)
+                       {
+                       CFDictionaryRef dict = SCDynamicStoreCopyValue(store, entityname);
+                       if (dict)
+                               {
+                               CFRange range = { 0, 6 };               // Offset, length
+                               CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
+                               if (data && CFDataGetLength(data) == 6) CFDataGetBytes(data, range, eth.b);
+                               CFRelease(dict);
+                               }
+                       CFRelease(entityname);
+                       }
+               CFRelease(store);
                }
-       if (ss->closeFlag) *ss->closeFlag = 1;
+       return(eth);
        }
 
-mDNSexport void mDNSPlatformUDPClose(UDPSocket *sock)
+mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex)
        {
-       CloseSocketSet(&sock->ss);
-       freeL("UDPSocket", sock);
+       struct ifaddrs *ifa;
+       for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
+               if (ifa->ifa_addr->sa_family == AF_LINK)
+                       {
+                       const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
+                       if (sdl->sdl_index == ifindex)
+                               { mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; }
+                       }
+       *eth = zeroEthAddr;
+       return -1;
        }
 
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - BPF Raw packet sending/receiving
+#ifndef SIOCGIFWAKEFLAGS
+#define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
 #endif
 
-#if APPLE_OSX_mDNSResponder
+#ifndef IF_WAKE_ON_MAGIC_PACKET
+#define IF_WAKE_ON_MAGIC_PACKET 0x01
+#endif
 
-mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
+#ifndef ifr_wake_flags
+#define ifr_wake_flags ifr_ifru.ifru_intval
+#endif
+
+mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
        {
-       if (!InterfaceID) { LogMsg("mDNSPlatformSendRawPacket: No InterfaceID specified"); return; }
-       NetworkInterfaceInfoOSX *info;
+       if (!MulticastInterface(i)     ) return(mDNSfalse);     // We only use Sleep Proxy Service on multicast-capable interfaces
+       if (i->ifa_flags & IFF_LOOPBACK) return(mDNSfalse);     // except loopback
 
-       extern mDNS mDNSStorage;
-       info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
-       if (info == NULL)
-               {
-               LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
-               return;
-               }
-       if (info->BPF_fd < 0)
-               LogMsg("mDNSPlatformSendRawPacket: %s BPF_fd %d not ready", info->ifinfo.ifname, info->BPF_fd);
-       else
+       int s = socket(AF_INET, SOCK_DGRAM, 0);
+       if (s < 0) { LogMsg("NetWakeInterface socket failed %s error %d errno %d (%s)", i->ifinfo.ifname, s, errno, strerror(errno)); return(mDNSfalse); }
+
+       struct ifreq ifr;
+       strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
+       if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
                {
-               //LogMsg("mDNSPlatformSendRawPacket %d bytes on %s", end - (mDNSu8 *)msg, info->ifinfo.ifname);
-               if (write(info->BPF_fd, msg, end - (mDNSu8 *)msg) < 0)
-                       LogMsg("mDNSPlatformSendRawPacket: BPF write(%d) failed %d (%s)", info->BPF_fd, errno, strerror(errno));
+               // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
+               // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
+               // error code is being returned from the kernel, we need to use the kernel version.
+               #define KERNEL_EOPNOTSUPP 102
+               if (errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier
+                       LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, errno, strerror(errno));
+               // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
+               // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
+               ifr.ifr_wake_flags = (errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
                }
+
+       close(s);
+
+       // ifr.ifr_wake_flags = IF_WAKE_ON_MAGIC_PACKET;        // For testing with MacBook Air, using a USB dongle that doesn't actually support Wake-On-LAN
+
+       LogSPS("%-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
+
+       return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
        }
 
-mDNSexport void mDNSPlatformSetLocalARP(const mDNSv4Addr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
+// Returns pointer to newly created NetworkInterfaceInfoOSX object, or
+// pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
+// may return NULL if out of memory (unlikely) or parameters are invalid for some reason
+// (e.g. sa_family not AF_INET or AF_INET6)
+mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc)
        {
-       if (!InterfaceID) { LogMsg("mDNSPlatformSetLocalARP: No InterfaceID specified"); return; }
-       NetworkInterfaceInfoOSX *info;
-       extern mDNS mDNSStorage;
-       info = IfindexToInterfaceInfoOSX(&mDNSStorage, InterfaceID);
-       if (info == NULL)
-               {
-               LogMsg("mDNSPlatformSendUDP: Invalid interface index %p", InterfaceID);
-               return;
-               }
-       // Manually inject an entry into our local ARP cache.
-       // (We can't do this by sending an ARP broadcast, because the kernel only pays attention to incoming ARP packets, not outgoing.)
-       mDNSBool makearp = mDNSv4AddressIsLinkLocal(tpa);
-       if (!makearp)
-               {
-               NetworkInterfaceInfoOSX *i;
-               for (i = info->m->p->InterfaceList; i; i = i->next)
-                       if (i->Exists && i->ifinfo.InterfaceID == InterfaceID && i->ifinfo.ip.type == mDNSAddrType_IPv4)
-                               if (((i->ifinfo.ip.ip.v4.NotAnInteger ^ tpa->NotAnInteger) & i->ifinfo.mask.ip.v4.NotAnInteger) == 0)
-                                       makearp = mDNStrue;
-               }
-       if (!makearp)
-               LogInfo("Don't need ARP entry for %s %.4a %.6a",            info->ifinfo.ifname, tpa, tha);
-       else
-               {
-               int result = mDNSSetARP(info->scope_id, tpa->b, tha->b);
-               if (result) LogMsg("Set local ARP entry for %s %.4a %.6a failed: %d", info->ifinfo.ifname, tpa, tha, result);
-               else debugf       ("Set local ARP entry for %s %.4a %.6a",            info->ifinfo.ifname, tpa, tha);
-               }
-       }
+       mDNSu32 scope_id  = if_nametoindex(ifa->ifa_name);
+       mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
+
+       mDNSAddr ip, mask;
+       if (SetupAddr(&ip,   ifa->ifa_addr   ) != mStatus_NoError) return(NULL);
+       if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
+
+       NetworkInterfaceInfoOSX **p;
+       for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
+               if (scope_id == (*p)->scope_id &&
+                       mDNSSameAddress(&ip, &(*p)->ifinfo.ip) &&
+                       mDNSSameEthAddress(&bssid, &(*p)->BSSID))
+                       {
+                       debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, *p);
+                       (*p)->Exists = mDNStrue;
+                       // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
+                       if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
+
+                       // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
+                       // we may need to start or stop or sleep proxy browse operation
+                       const mDNSBool NetWake = NetWakeInterface(*p);
+                       if ((*p)->ifinfo.NetWake != NetWake)
+                               {
+                               (*p)->ifinfo.NetWake = NetWake;
+                               // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
+                               // If this interface is not already registered (i.e. it's a dormant interface we had in our list
+                               // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
+                               // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
+                               if ((*p)->Registered)
+                                       {
+                                       mDNS_Lock(m);
+                                       if (NetWake) mDNS_ActivateNetWake_internal  (m, &(*p)->ifinfo);
+                                       else         mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo);
+                                       mDNS_Unlock(m);
+                                       }
+                               }
+
+                       return(*p);
+                       }
+
+       NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
+       debugf("AddInterfaceToList: Making   new   interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
+       if (!i) return(mDNSNULL);
+       mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
+       i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id;
+       i->ifinfo.ip          = ip;
+       i->ifinfo.mask        = mask;
+       strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
+       i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
+       // We can be configured to disable multicast advertisement, but we want to to support
+       // local-only services, which need a loopback address record.
+       i->ifinfo.Advertise   = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses;
+       i->ifinfo.McastTxRx   = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
+
+       i->next            = mDNSNULL;
+       i->m               = m;
+       i->Exists          = mDNStrue;
+       i->Flashing        = mDNSfalse;
+       i->Occulting       = mDNSfalse;
+       i->AppearanceTime  = utc;               // Brand new interface; AppearanceTime is now
+       i->LastSeen        = utc;
+       i->ifa_flags       = ifa->ifa_flags;
+       i->scope_id        = scope_id;
+       i->BSSID           = bssid;
+       i->sa_family       = ifa->ifa_addr->sa_family;
+       i->BPF_fd          = -1;
+       i->BPF_mcfd        = -1;
+       i->BPF_len         = 0;
+       i->Registered      = mDNSNULL;
 
-mDNSlocal void CloseBPF(NetworkInterfaceInfoOSX *const i)
-       {
-       LogSPS("%s closing BPF fd %d", i->ifinfo.ifname, i->BPF_fd);
+       // Do this AFTER i->BSSID has been set up
+       i->ifinfo.NetWake  = NetWakeInterface(i);
+       GetMAC(&i->ifinfo.MAC, scope_id);
+       if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
+               LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
 
-       // Note: MUST NOT close() the underlying native BSD sockets.
-       // CFSocketInvalidate() will do that for us, in its own good time, which may not necessarily be immediately, because
-       // it first has to unhook the sockets from its select() call on its other thread, before it can safely close them.
-       CFRunLoopRemoveSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
-       CFRelease(i->BPF_rls);
-       CFSocketInvalidate(i->BPF_cfs);
-       CFRelease(i->BPF_cfs);
-       i->BPF_fd = -1;
+       *p = i;
+       return(i);
        }
 
-mDNSlocal void bpf_callback(const CFSocketRef cfs, const CFSocketCallBackType CallBackType, const CFDataRef address, const void *const data, void *const context)
+#if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
+mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id)
        {
-       (void)cfs;
-       (void)CallBackType;
-       (void)address;
-       (void)data;
+       NetworkInterfaceInfoOSX *i;
+       for (i = m->p->InterfaceList; i; i = i->next)
+               if (i->Exists && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4)
+                       if (!mDNSv4AddressIsLinkLocal(&i->ifinfo.ip.ip.v4))
+                               return(i);
+       return(mDNSNULL);
+       }
+#endif
 
-       NetworkInterfaceInfoOSX *const info = (NetworkInterfaceInfoOSX *)context;
-       KQueueLock(info->m);
+#if APPLE_OSX_mDNSResponder
 
-       // Now we've got the lock, make sure the kqueue thread didn't close the fd out from under us (will not be a problem once the OS X
-       // kernel has a mechanism for dispatching all events to a single thread, but for now we have to guard against this race condition).
-       if (info->BPF_fd < 0) goto exit;
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - AutoTunnel
+#endif
 
-       ssize_t n = read(info->BPF_fd, &info->m->imsg, info->BPF_len);
-       const mDNSu8 *ptr = (const mDNSu8 *)&info->m->imsg;
-       const mDNSu8 *end = (const mDNSu8 *)&info->m->imsg + n;
-       debugf("%3d: bpf_callback got %d bytes on %s", info->BPF_fd, n, info->ifinfo.ifname);
+#define kRacoonPort 4500
 
-       if (n<0)
-               {
-               LogMsg("Closing %s BPF fd %d due to error %d (%s)", info->ifinfo.ifname, info->BPF_fd, errno, strerror(errno));
-               CloseBPF(info);
-               goto exit;
-               }
+static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
 
-       while (ptr < end)
+// We arbitrarily limit the message size to 128 bytes (which seems sufficient now) so that
+// freeing ELogContext is simpler which is treated as opaque quantity in many places
+typedef struct
+       {
+       char subdomain[32];
+       char message[128];
+       uuid_t uuid;
+       int result;
+       } ELogContext;
+
+typedef enum { HTTPGet = 1, HTTPPost } HTTPOperation;
+typedef enum { ConfigInvalid = 0, ConfigFetching, ConfigValid } ConfigState;
+typedef void (*HTTPClientCallback)(CFMutableDataRef responseData, ELogContext *context);
+#define        kReadStreamBufferSize                   4096
+#define        kMaximumResponseSize                    32768
+#define        kHTTPResponseCodeOK                             200
+#define        kHTTPResponseCodeAuthFailure    401
+#define        kHTTPResponseCodeForbidden              403
+#define        kHTTPResponseCodeNotFound               404
+
+// eReporter configuration needs to be fetched whenever it becomes stale. We fetch it lazily
+// when we send the report.
+struct eReporterConfiguration {
+       CFDictionaryRef eRDict;
+       ConfigState eRState;
+} eReporterConfig;
+
+typedef struct
+       {
+       mDNSBool                                authChecked;
+       CFHTTPAuthenticationRef authentication;
+       CFMutableDataRef                responseData;
+       HTTPClientCallback              callback;
+       ELogContext                             cbcontext;
+       HTTPOperation                   op;
+       CFStringRef                     headerFieldName;
+       CFStringRef                     headerFieldValue;
+       CFDataRef                               bodyData;
+       CFStringRef                             url;
+       } HTTPDataStreamContext;
+
+
+// Forward declarations
+mDNSlocal void HTTPDataStream(CFStringRef url, HTTPOperation op, CFDataRef bodyData, CFStringRef headerFieldName,
+       CFStringRef headerFieldValue, CFHTTPAuthenticationRef auth, CFMutableDictionaryRef credentials,
+       HTTPClientCallback callback, ELogContext *context);
+mDNSlocal void mDNSReporterLogValidConfig(ELogContext *elog);
+
+mDNSlocal void CancelReadStream(CFReadStreamRef readStream)
+       {
+       if (readStream)
                {
-               const struct bpf_hdr *bh = (const struct bpf_hdr *)ptr;
-               debugf("%3d: bpf_callback bh_caplen %4d bh_datalen %4d remaining %4d", info->BPF_fd, bh->bh_caplen, bh->bh_datalen, end - (ptr + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen)));
-               mDNSCoreReceiveRawPacket(info->m, ptr + bh->bh_hdrlen, ptr + bh->bh_hdrlen + bh->bh_caplen, info->ifinfo.InterfaceID);
-               ptr += BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
+               CFReadStreamSetClient(readStream, kCFStreamEventNone, NULL, NULL);
+               CFReadStreamUnscheduleFromRunLoop(readStream, CFRunLoopGetMain(), kCFRunLoopCommonModes);
+               CFReadStreamClose(readStream);
+               CFRelease(readStream);
                }
-exit:
-       KQueueUnlock(info->m, "bpf_callback");
        }
 
-#define BPF_SetOffset(from, cond, to) (from)->cond = (to) - 1 - (from)
-
-mDNSlocal int CountProxyTargets(mDNS *const m, NetworkInterfaceInfoOSX *x, int *p4, int *p6)
+mDNSlocal void CancelHTTPDataStream(CFReadStreamRef stream, HTTPDataStreamContext *context)
        {
-       int numv4 = 0, numv6 = 0;
-       AuthRecord *rr;
-
-       for (rr = m->ResourceRecords; rr; rr=rr->next)
-               if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
-                       {
-                       if (p4) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.4a", x->BPF_fd, x->ifinfo.ifname, numv4, &rr->AddressProxy.ip.v4);
-                       numv4++;
-                       }
-
-       for (rr = m->ResourceRecords; rr; rr=rr->next)
-               if (rr->resrec.InterfaceID == x->ifinfo.InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
-                       {
-                       if (p6) LogSPS("CountProxyTargets: fd %d %-7s IP%2d %.16a", x->BPF_fd, x->ifinfo.ifname, numv6, &rr->AddressProxy.ip.v6);
-                       numv6++;
-                       }
-
-       if (p4) *p4 = numv4;
-       if (p6) *p6 = numv6;
-       return(numv4 + numv6);
+       LogInfo("CancelHTTPDataStream: called");
+       if (context)
+               {
+               if (context->authentication) CFRelease(context->authentication);
+               if (context->responseData) CFRelease(context->responseData);
+               if (context->headerFieldName) CFRelease(context->headerFieldName);
+               if (context->headerFieldValue) CFRelease(context->headerFieldValue);
+               if (context->bodyData) CFRelease(context->bodyData);
+               if (context->url) CFRelease(context->url);
+               freeL("HTTPDataStreamContext", context);
+               }
+       CancelReadStream(stream);
        }
 
-mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
+mDNSlocal CFIndex HTTPResponseCode(CFReadStreamRef stream)
        {
-       NetworkInterfaceInfoOSX *x;
-
-       //NOTE: We can't use IfIndexToInterfaceInfoOSX because that looks for Registered also.
-       for (x = m->p->InterfaceList; x; x = x->next) if (x->ifinfo.InterfaceID == InterfaceID) break;
-
-       if (!x) { LogMsg("mDNSPlatformUpdateProxyList: ERROR InterfaceID %p not found", InterfaceID); return; }
-
-       #define MAX_BPF_ADDRS 250
-       int numv4 = 0, numv6 = 0;
-
-       if (CountProxyTargets(m, x, &numv4, &numv6) > MAX_BPF_ADDRS)
+       CFIndex errorCode = 0;
+       CFHTTPMessageRef responseHeaders = (CFHTTPMessageRef)CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPResponseHeader);
+       if (responseHeaders)
                {
-               LogMsg("mDNSPlatformUpdateProxyList: ERROR Too many address proxy records v4 %d v6 %d", numv4, numv6);
-               if (numv4 > MAX_BPF_ADDRS) numv4 = MAX_BPF_ADDRS;
-               numv6 = MAX_BPF_ADDRS - numv4;
+               errorCode = CFHTTPMessageGetResponseStatusCode(responseHeaders);
+               CFRelease(responseHeaders);
                }
+       return errorCode;
+       }
 
-       LogSPS("mDNSPlatformUpdateProxyList: fd %d %-7s MAC  %.6a %d v4 %d v6", x->BPF_fd, x->ifinfo.ifname, &x->ifinfo.MAC, numv4, numv6);
+mDNSlocal void RetryWithHTTPAuth(HTTPDataStreamContext *context, CFReadStreamRef stream)
+       {
+    CFStreamError err;
+       DomainAuthInfo *FoundInList;
+       CFMutableDictionaryRef  credentials = NULL;
 
-       // Caution: This is a static structure, so we need to be careful that any modifications we make to it
-       // are done in such a way that they work correctly when mDNSPlatformUpdateProxyList is called multiple times
-       static struct bpf_insn filter[17 + MAX_BPF_ADDRS] =
+       // Need to use the same authentication object till it goes invalid
+       if (!context->authentication)
                {
-               BPF_STMT(BPF_LD  + BPF_H   + BPF_ABS, 12),                              // 0 Read Ethertype (bytes 12,13)
-
-               BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0806, 0, 1),              // 1 If Ethertype == ARP goto next, else 3
-               BPF_STMT(BPF_RET + BPF_K,             42),                              // 2 Return 42-byte ARP
-
-               BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0800, 4, 0),              // 3 If Ethertype == IPv4 goto 8 (IPv4 address list check) else next
-
-               BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x86DD, 0, 9),              // 4 If Ethertype == IPv6 goto next, else exit
-               BPF_STMT(BPF_LD  + BPF_H   + BPF_ABS, 20),                              // 5 Read Protocol and Hop Limit (bytes 20,21)
-               BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x3AFF, 0, 9),              // 6 If (Prot,TTL) == (3A,FF) goto next, else IPv6 address list check
-               BPF_STMT(BPF_RET + BPF_K,             78),                              // 7 Return 78-byte ND
-
-               // Is IPv4 packet; check if it's addressed to any IPv4 address we're proxying for
-               BPF_STMT(BPF_LD  + BPF_W   + BPF_ABS, 30),                              // 8 Read IPv4 Dst (bytes 30,31,32,33)
-               };
-
-       struct bpf_insn *pc   = &filter[9];
-       struct bpf_insn *chk6 = pc   + numv4 + 1;       // numv4 address checks, plus a "return 0"
-       struct bpf_insn *fail = chk6 + 1 + numv6;       // Get v6 Dst LSW, plus numv6 address checks
-       struct bpf_insn *ret4 = fail + 1;
-       struct bpf_insn *ret6 = ret4 + 4;
-
-       static const struct bpf_insn rf  = BPF_STMT(BPF_RET + BPF_K, 0);                                // No match: Return nothing
-
-       static const struct bpf_insn g6  = BPF_STMT(BPF_LD  + BPF_W   + BPF_ABS, 50);   // Read IPv6 Dst LSW (bytes 50,51,52,53)
-
-       static const struct bpf_insn r4a = BPF_STMT(BPF_LDX + BPF_B   + BPF_MSH, 14);   // Get IP Header length (normally 20)
-       static const struct bpf_insn r4b = BPF_STMT(BPF_LD  + BPF_IMM,           54);   // A = 54 (14-byte Ethernet plus 20-byte TCP + 20 bytes spare)
-       static const struct bpf_insn r4c = BPF_STMT(BPF_ALU + BPF_ADD + BPF_X,    0);   // A += IP Header length
-       static const struct bpf_insn r4d = BPF_STMT(BPF_RET + BPF_A, 0);                                // Success: Return Ethernet + IP + TCP + 20 bytes spare (normally 74)
-
-       static const struct bpf_insn r6a = BPF_STMT(BPF_RET + BPF_K, 94);                               // Success: Return Eth + IPv6 + TCP + 20 bytes spare
-
-       BPF_SetOffset(&filter[4], jf, fail);    // If Ethertype not ARP, IPv4, or IPv6, fail
-       BPF_SetOffset(&filter[6], jf, chk6);    // If IPv6 but not ICMPv6, go to IPv6 address list check
-
-       // BPF Byte-Order Note
-       // The BPF API designers apparently thought that programmers would not be smart enough to use htons
-       // and htonl correctly to convert numeric values to network byte order on little-endian machines,
-       // so instead they chose to make the API implicitly byte-swap *ALL* values, even literal byte strings
-       // that shouldn't be byte-swapped, like ASCII text, Ethernet addresses, IP addresses, etc.
-       // As a result, if we put Ethernet addresses and IP addresses in the right byte order, the BPF API
-       // will byte-swap and make them backwards, and then our filter won't work. So, we have to arrange
-       // that on little-endian machines we deliberately put addresses in memory with the bytes backwards,
-       // so that when the BPF API goes through and swaps them all, they end up back as they should be.
-       // In summary, if we byte-swap all the non-numeric fields that shouldn't be swapped, and we *don't*
-       // swap any of the numeric values that *should* be byte-swapped, then the filter will work correctly.
-
-       // IPSEC capture size notes:
-       //  8 bytes UDP header
-       //  4 bytes Non-ESP Marker
-       // 28 bytes IKE Header
-       // --
-       // 40 Total. Capturing TCP Header + 20 gets us enough bytes to receive the IKE Header in a UDP-encapsulated IKE packet.
-
-       AuthRecord *rr;
-       for (rr = m->ResourceRecords; rr; rr=rr->next)
-               if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv4)
-                       {
-                       mDNSv4Addr a = rr->AddressProxy.ip.v4;
-                       pc->code = BPF_JMP + BPF_JEQ + BPF_K;
-                       BPF_SetOffset(pc, jt, ret4);
-                       pc->jf   = 0;
-                       pc->k    = (bpf_u_int32)a.b[0] << 24 | (bpf_u_int32)a.b[1] << 16 | (bpf_u_int32)a.b[2] << 8 | (bpf_u_int32)a.b[3];
-                       pc++;
-                       }
-       *pc++ = rf;
-
-       if (pc != chk6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != chk6 %p", pc, chk6);
-       *pc++ = g6;     // chk6 points here
+               CFHTTPMessageRef responseHeader = (CFHTTPMessageRef)CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPResponseHeader);
+               // Get the authentication information from the response.
+               context->authentication = CFHTTPAuthenticationCreateFromResponse(NULL, responseHeader);
+               CFRelease(responseHeader);
+               }
 
-       for (rr = m->ResourceRecords; rr; rr=rr->next)
-               if (rr->resrec.InterfaceID == InterfaceID && rr->AddressProxy.type == mDNSAddrType_IPv6)
+       // Check to see if the authentication is valid for use. Anything could have gone wrong
+       // from bad credentials to wrong type of authentication etc.
+       if (!context->authentication || !CFHTTPAuthenticationIsValid(context->authentication, &err))
+               {
+               LogMsg("RetryWithHTTPAuth: ERROR!! Authentication failed");
+               if (context->authentication)
                        {
-                       mDNSv6Addr a = rr->AddressProxy.ip.v6;
-                       pc->code = BPF_JMP + BPF_JEQ + BPF_K;
-                       BPF_SetOffset(pc, jt, ret6);
-                       pc->jf   = 0;
-                       pc->k    = (bpf_u_int32)a.b[12] << 24 | (bpf_u_int32)a.b[13] << 16 | (bpf_u_int32)a.b[14] << 8 | (bpf_u_int32)a.b[15];
-                       pc++;
+                       // Check for bad credentials and treat these separately
+                       if (err.domain == kCFStreamErrorDomainHTTP && (err.error == kCFStreamErrorHTTPAuthenticationBadUserName ||
+                               err.error == kCFStreamErrorHTTPAuthenticationBadPassword))
+                               {
+                               LogMsg("RetryWithHTTPAuth: ERROR!! Bad credentials %d", err.error); 
+                               }
                        }
+               CancelHTTPDataStream(stream, context);
+               return;
+       }
 
-       if (pc != fail) LogMsg("mDNSPlatformUpdateProxyList: pc %p != fail %p", pc, fail);
-       *pc++ = rf;     // fail points here
-
-       if (pc != ret4) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret4 %p", pc, ret4);
-       *pc++ = r4a;    // ret4 points here
-       *pc++ = r4b;
-       *pc++ = r4c;
-       *pc++ = r4d;
-
-       if (pc != ret6) LogMsg("mDNSPlatformUpdateProxyList: pc %p != ret6 %p", pc, ret6);
-       *pc++ = r6a;    // ret6 points here
-
-       struct bpf_program prog = { pc - filter, filter };
+       // Do we need username & password?  Not all authentication types require them.
+       if (CFHTTPAuthenticationRequiresUserNameAndPassword(context->authentication))
+               {
+               char username[MAX_DOMAIN_LABEL + 1];
 
-#if 0
-       // For debugging BPF filter program
-       unsigned int q;
-       for (q=0; q<prog.bf_len; q++)
-               LogSPS("mDNSPlatformUpdateProxyList: %2d { 0x%02x, %d, %d, 0x%08x },", q, prog.bf_insns[q].code, prog.bf_insns[q].jt, prog.bf_insns[q].jf, prog.bf_insns[q].k);
-#endif
 
-       if (!numv4 && !numv6)
-               {
-               LogSPS("mDNSPlatformUpdateProxyList: No need for filter");
-               if (m->timenow == 0) LogMsg("mDNSPlatformUpdateProxyList: m->timenow == 0");
-               // Schedule check to see if we can close this BPF_fd now
-               if (!m->p->NetworkChanged) m->p->NetworkChanged = NonZeroTime(m->timenow + mDNSPlatformOneSecond * 2);
-               // prog.bf_len = 0; This seems to panic the kernel
-               }
+               // Use the first BTMM username and password
+               for (FoundInList = (&mDNSStorage)->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
+                       if (!FoundInList->deltime && FoundInList->AutoTunnel) break;
 
-       if (ioctl(x->BPF_fd, BIOCSETF, &prog) < 0) LogMsg("mDNSPlatformUpdateProxyList: BIOCSETF(%d) failed %d (%s)", prog.bf_len, errno, strerror(errno));
-       else LogSPS("mDNSPlatformUpdateProxyList: BIOCSETF(%d) successful", prog.bf_len);
-       }
+               if (!FoundInList)
+                       {
+                       LogInfo("RetryHTTPWithAuth:  No BTMM credentials");
+                       CancelHTTPDataStream(stream, context);
+                       return;
+                       }
 
-mDNSexport void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd)
-       {
-       mDNS_Lock(m);
-       
-       NetworkInterfaceInfoOSX *i;
-       for (i = m->p->InterfaceList; i; i = i->next) if (i->BPF_fd == -2) break;
-       if (!i) { LogSPS("mDNSPlatformReceiveBPF_fd: No Interfaces awaiting BPF fd %d; closing", fd); close(fd); }
-       else
-               {
-               LogSPS("%s using   BPF fd %d", i->ifinfo.ifname, fd);
-       
-               struct bpf_version v;
-               if (ioctl(fd, BIOCVERSION, &v) < 0)
-                       LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
-               else if (BPF_MAJOR_VERSION != v.bv_major || BPF_MINOR_VERSION != v.bv_minor)
-                       LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCVERSION header %d.%d kernel %d.%d",
-                               fd, i->ifinfo.ifname, BPF_MAJOR_VERSION, BPF_MINOR_VERSION, v.bv_major, v.bv_minor);
-       
-               if (ioctl(fd, BIOCGBLEN, &i->BPF_len) < 0)
-                       LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCGBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
-       
-               if (i->BPF_len > sizeof(m->imsg))
+               ConvertDomainLabelToCString_unescaped((domainlabel *)FoundInList->domain.c, username);
+               CFStringRef user = CFStringCreateWithBytes(NULL, (const mDNSu8 *)username, strlen(username), kCFStringEncodingASCII, false);
+               if (!user)
                        {
-                       i->BPF_len = sizeof(m->imsg);
-                       if (ioctl(fd, BIOCSBLEN, &i->BPF_len) < 0)
-                               LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
-                       else LogSPS("mDNSPlatformReceiveBPF_fd: %d %s BIOCSBLEN %d", i->BPF_len);
+                       LogMsg("RetryHTTPWithAuth: ERROR!! CFStringCreateWithBytes error");
+                       CancelHTTPDataStream(stream, context);
+                       return;
                        }
-       
-               static const u_int opt_immediate = 1;
-               if (ioctl(fd, BIOCIMMEDIATE, &opt_immediate) < 0)
-                       LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
-       
-               struct ifreq ifr;
-               mDNSPlatformMemZero(&ifr, sizeof(ifr));
-               strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
-               if (ioctl(fd, BIOCSETIF, &ifr) < 0)
-                       { LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSETIF failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno)); i->BPF_fd = -3; }
-               else
+               CFStringRef pass = CFStringCreateWithBytes(NULL, (const mDNSu8 *)FoundInList->b64keydata, strlen(FoundInList->b64keydata),
+                       kCFStringEncodingASCII, false);
+               if (!pass)
                        {
-                       CFSocketContext myCFSocketContext = { 0, i, NULL, NULL, NULL };
-                       i->BPF_fd  = fd;
-                       i->BPF_cfs = CFSocketCreateWithNative(kCFAllocatorDefault, fd, kCFSocketReadCallBack, bpf_callback, &myCFSocketContext);
-                       i->BPF_rls = CFSocketCreateRunLoopSource(kCFAllocatorDefault, i->BPF_cfs, 0);
-                       CFRunLoopAddSource(i->m->p->CFRunLoop, i->BPF_rls, kCFRunLoopDefaultMode);
-                       mDNSPlatformUpdateProxyList(m, i->ifinfo.InterfaceID);
+                       LogMsg("RetryHTTPWithAuth: ERROR!! CFStringCreateWithBytes error");
+                       CFRelease(user);
+                       CancelHTTPDataStream(stream, context);
+                       return;
                        }
+               // Build the credentials dictionary
+               credentials = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+               if (!credentials)
+                       {
+                       LogMsg("RetryHTTPWithAuth: ERROR!! cannot allocate credentials");
+                       CFRelease(user);
+                       CFRelease(pass);
+                       CancelHTTPDataStream(stream, context);
+                       return;
+                       }
+               CFDictionarySetValue(credentials, kCFHTTPAuthenticationUsername, user);
+               CFDictionarySetValue(credentials, kCFHTTPAuthenticationPassword, pass);
+               CFRelease(user);
+               CFRelease(pass);
+        }
+       else
+               {
+               LogMsg("RetryHTTPWithAuth: ERROR!! Unknown authentication method");
+               CancelHTTPDataStream(stream, context);
+               return;
                }
 
-       mDNS_Unlock(m);
-       }
+       HTTPDataStream(context->url, context->op, context->bodyData, context->headerFieldName, context->headerFieldValue,
+               context->authentication, credentials, context->callback, &context->cbcontext);
 
-#endif // APPLE_OSX_mDNSResponder
+       if (credentials) CFRelease(credentials);
 
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - Key Management
-#endif
+       // Cancel the old one
+       CancelHTTPDataStream(stream, context);
+       }
 
-#ifndef NO_SECURITYFRAMEWORK
-mDNSlocal CFArrayRef GetCertChain(SecIdentityRef identity)
+mDNSlocal void HTTPDataStreamCallback(CFReadStreamRef stream, CFStreamEventType type, void *info)
        {
-       CFMutableArrayRef certChain = NULL;
-       if (!identity) { LogMsg("getCertChain: identity is NULL"); return(NULL); }
-       SecCertificateRef cert;
-       OSStatus err = SecIdentityCopyCertificate(identity, &cert);
-       if (err || !cert) LogMsg("getCertChain: SecIdentityCopyCertificate() returned %d", (int) err);
-       else
+       HTTPDataStreamContext *context = (HTTPDataStreamContext *)info;
+       CFIndex status;
+
+       status = HTTPResponseCode(stream);
+
+       // if we are forbidden to access, we need to refetch the configuration file.
+       // For keeping it simple, we don't retry immediately. When the next message
+       // is logged, we will try getting the config file. If we want to modify this
+       // in the future to retry now, then we need to know to stop retrying after a
+       // few times.
+       if ((status == kHTTPResponseCodeNotFound) || (status == kHTTPResponseCodeForbidden))
+               {
+               if (status == kHTTPResponseCodeNotFound)
+                       LogMsg("HTTPDataStreamCallback: ERROR!! Config plist cannot be found");
+               else if (status == kHTTPResponseCodeForbidden)
+                       LogInfo("HTTPDataStreamCallback: Config plist Forbidden by server");
+               if (context->callback) context->callback(context->responseData, &context->cbcontext);
+               CancelHTTPDataStream(stream, context);
+               return;
+               }
+
+       switch (type)
                {
-               SecPolicySearchRef searchRef;
-               err = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
-               if (err || !searchRef) LogMsg("getCertChain: SecPolicySearchCreate() returned %d", (int) err);
-               else
+               case kCFStreamEventHasBytesAvailable:
                        {
-                       SecPolicyRef policy;
-                       err = SecPolicySearchCopyNext(searchRef, &policy);
-                       if (err || !policy) LogMsg("getCertChain: SecPolicySearchCopyNext() returned %d", (int) err);
-                       else
+                       mDNSu8 buffer[kReadStreamBufferSize];
+                       CFIndex bytesRead;
+                               
+                       if (!context->authChecked)
                                {
-                               CFArrayRef wrappedCert = CFArrayCreate(NULL, (const void**) &cert, 1, &kCFTypeArrayCallBacks);
-                               if (!wrappedCert) LogMsg("getCertChain: wrappedCert is NULL");
-                               else
+                               context->authChecked = mDNStrue;
+                               if (status == kHTTPResponseCodeAuthFailure)
                                        {
-                                       SecTrustRef trust;
-                                       err = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
-                                       if (err || !trust) LogMsg("getCertChain: SecTrustCreateWithCertificates() returned %d", (int) err);
-                                       else
-                                               {
-                                               err = SecTrustEvaluate(trust, NULL);
-                                               if (err) LogMsg("getCertChain: SecTrustEvaluate() returned %d", (int) err);
-                                               else
-                                                       {
-                                                       CFArrayRef rawCertChain;
-                                                       CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
-                                                       err = SecTrustGetResult(trust, NULL, &rawCertChain, &statusChain);
-                                                       if (err || !rawCertChain || !statusChain) LogMsg("getCertChain: SecTrustGetResult() returned %d", (int) err);
-                                                       else
-                                                               {
-                                                               certChain = CFArrayCreateMutableCopy(NULL, 0, rawCertChain);
-                                                               if (!certChain) LogMsg("getCertChain: certChain is NULL");
-                                                               else
-                                                                       {
-                                                                       // Replace the SecCertificateRef at certChain[0] with a SecIdentityRef per documentation for SSLSetCertificate:
-                                                                       // <http://devworld.apple.com/documentation/Security/Reference/secureTransportRef/index.html>
-                                                                       CFArraySetValueAtIndex(certChain, 0, identity);
-                                                                       // Remove root from cert chain, but keep any and all intermediate certificates that have been signed by the root certificate
-                                                                       if (CFArrayGetCount(certChain) > 1) CFArrayRemoveValueAtIndex(certChain, CFArrayGetCount(certChain) - 1);
-                                                                       }
-                                                               CFRelease(rawCertChain);
-                                                               // Do not free statusChain:
-                                                               // <http://developer.apple.com/documentation/Security/Reference/certifkeytrustservices/Reference/reference.html> says:
-                                                               // certChain: Call the CFRelease function to release this object when you are finished with it.
-                                                               // statusChain: Do not attempt to free this pointer; it remains valid until the trust management object is released...
-                                                               }
-                                                       }
-                                               CFRelease(trust);
-                                               }
-                                       CFRelease(wrappedCert);
+                                       RetryWithHTTPAuth(context, stream);
+                                       return;
                                        }
-                               CFRelease(policy);
                                }
-                       CFRelease(searchRef);
+                               
+                       bytesRead = CFReadStreamRead(stream, buffer, sizeof(buffer));
+                       if (bytesRead > 0)
+                               {
+                               CFDataAppendBytes(context->responseData, buffer, bytesRead);
+                               if (CFDataGetLength(context->responseData) > kMaximumResponseSize)
+                                       {
+                                       LogMsg("HTTPDataStreamCallback: ERROR!! Appended max data %d", kMaximumResponseSize);
+                                       }
+                               else { LogInfo("HTTPDataStreamCallback: successfully appended data of size %ld", bytesRead); return; }
+                               }
+                       else if (bytesRead < 0)
+                               {
+                               LogMsg("HTTPDataStreamCallback: ERROR!! CFReadStreamRead returned %ld", bytesRead);
+                               }
                        }
-               CFRelease(cert);
+                       break;
+               case kCFStreamEventEndEncountered:
+                       {
+                       if (!context->authChecked)
+                               {
+                               context->authChecked = mDNStrue;
+                               if (status == kHTTPResponseCodeAuthFailure)
+                                       {
+                                       RetryWithHTTPAuth(context, stream);
+                                       return;
+                                       }
+                               }
+                       if (status != kHTTPResponseCodeOK)
+                               LogMsg("HTTPDataStreamCallback: ERROR!! EndEncountered, statusCode %d, Operation %d", status, context->op);
+                       else
+                               LogInfo("HTTPDataStreamCallback: HTTP Ok for Operation %d", context->op);
+                       if (context->callback) context->callback(context->responseData, &context->cbcontext);
+                       }
+                       break;
+               case kCFStreamEventErrorOccurred:
+                       LogInfo("HTTPDataStreamCallback: ERROR!! kCFStreamEventErrorOccurred for Operation %d", context->op);
+                       if (context->callback) context->callback(context->responseData, &context->cbcontext);
+                       break;
+               default:
+                       LogMsg("HTTPDataStreamCallback: ERROR!! default case");
+                       if (context->callback) context->callback(context->responseData, &context->cbcontext);
+                       break;
                }
-       return certChain;
-       }
-#endif /* NO_SECURITYFRAMEWORK */
+       CancelHTTPDataStream(stream, context);
+}
 
-mDNSexport mStatus mDNSPlatformTLSSetupCerts(void)
+// Everything needs to be copied or retained locally if need to be accessed beyond function scope
+mDNSlocal void HTTPDataStream(CFStringRef url, HTTPOperation op, CFDataRef bodyData, CFStringRef headerFieldName,
+       CFStringRef headerFieldValue, CFHTTPAuthenticationRef authentication, CFMutableDictionaryRef credentials,
+       HTTPClientCallback callback, ELogContext *cbcontext)
        {
-#ifdef NO_SECURITYFRAMEWORK
-       return mStatus_UnsupportedErr;
-#else
-       SecIdentityRef                  identity = nil;
-       SecIdentitySearchRef    srchRef = nil;
-       OSStatus                                err;
-
-       // search for "any" identity matching specified key use
-       // In this app, we expect there to be exactly one
-       err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_DECRYPT, &srchRef);
-       if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCreate returned %d", (int) err); return err; }
+       CFURLRef myURL = NULL;
+       CFHTTPMessageRef myRequest = NULL;
+       CFReadStreamRef readStream = NULL;
+       HTTPDataStreamContext *contextInfo = NULL;
+       CFDictionaryRef proxyDict = NULL;
+
+       contextInfo = mallocL("HTTPDataStreamContext", sizeof(HTTPDataStreamContext));
+       if (!contextInfo) { LogMsg("HTTPDataStream: mallocL failure"); return; }
+
+       mDNSPlatformMemZero(contextInfo, sizeof(*contextInfo));
+       // Need to remember the state, so that if we need to retry with authentication, we can
+       // reissue the request
+       contextInfo->url = CFRetain(url);
+       contextInfo->callback = callback;
+       if(cbcontext) memcpy(&contextInfo->cbcontext, cbcontext, sizeof(ELogContext));
+       contextInfo->authChecked = mDNSfalse;
+       contextInfo->op = op;
+       if (authentication) contextInfo->authentication = (CFHTTPAuthenticationRef) CFRetain(authentication);
+       if (headerFieldName) contextInfo->headerFieldName = CFRetain(headerFieldName);
+       if (headerFieldValue) contextInfo->headerFieldValue = CFRetain(headerFieldValue);
+       if (bodyData) contextInfo->bodyData = CFRetain(bodyData);
+
+       myURL = CFURLCreateWithString(kCFAllocatorDefault, url, NULL);
+       if (!myURL) { LogMsg("HTTPDataStream: CFURLCreateWithString error"); goto cleanup; }
+
+       CFStringRef requestMethod = op == HTTPGet ? CFSTR("GET") : CFSTR("POST");
+       myRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, requestMethod, myURL, kCFHTTPVersion1_1);
+       if (!myRequest) { LogMsg("HTTPDataStream: CFHTTPMessageCreateRequest error"); goto cleanup; }
+
+       if (bodyData) CFHTTPMessageSetBody(myRequest, bodyData);
+       if (headerFieldName) CFHTTPMessageSetHeaderFieldValue(myRequest, headerFieldName, headerFieldValue);
+
+       if (credentials)
+               {
+               if (!CFHTTPMessageApplyCredentialDictionary(myRequest, contextInfo->authentication, credentials, NULL))
+                       {
+                       LogMsg("HTTPDataStream: ERROR!! CFHTTPMessageApplyCredentialDictionary error");
+                       goto cleanup;
+                       }
+               }
 
-       err = SecIdentitySearchCopyNext(srchRef, &identity);
-       if (err) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext returned %d", (int) err); return err; }
+       readStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, myRequest);
+       if (!readStream) { LogMsg("HTTPDataStream: CFStringCreateWithBytes error"); goto cleanup; }
 
-       if (CFGetTypeID(identity) != SecIdentityGetTypeID())
-               { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: SecIdentitySearchCopyNext CFTypeID failure"); return mStatus_UnknownErr; }
+       proxyDict = SCDynamicStoreCopyProxies(NULL);
+       if (proxyDict)
+               {
+               mDNSBool ret = CFReadStreamSetProperty(readStream, kCFStreamPropertyHTTPProxy, proxyDict);
+               CFRelease(proxyDict);
+               if (!ret)
+                       {
+                       LogMsg("HTTPDataStream: CFReadStreamSetProperty HTTP proxy failed");
+                       goto cleanup;
+                       }
+               }
 
-       // Found one. Call getCertChain to create the correct certificate chain.
-       ServerCerts = GetCertChain(identity);
-       if (ServerCerts == nil) { LogMsg("ERROR: mDNSPlatformTLSSetupCerts: getCertChain error"); return mStatus_UnknownErr; }
+       CFOptionFlags events = kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered;
 
-       return mStatus_NoError;
-#endif /* NO_SECURITYFRAMEWORK */
+       CFStreamClientContext readContext = {0, contextInfo, NULL, NULL, NULL};
+       CFReadStreamSetClient(readStream, events, HTTPDataStreamCallback, &readContext);
+       CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetMain(), kCFRunLoopCommonModes);
+       if (CFReadStreamOpen(readStream))
+               {
+               contextInfo->responseData = CFDataCreateMutable(NULL, 0);
+               if (contextInfo->responseData)
+                       {
+                       // Release the things that we don't need
+                       CFRelease(myURL);
+                       CFRelease(myRequest);
+                       return;
+                       }
+               LogMsg("HTTPDataStream: ERROR!! responseData allocation failed");
+               }
+       else LogMsg("HTTPDataStream: ERROR!! CFReadStreamOpen failed");
+cleanup:
+       if (readStream) CancelReadStream(readStream);
+       if (myRequest) CFRelease(myRequest);
+       if (myURL) CFRelease(myURL);
+       if (contextInfo)
+               {
+               if (contextInfo->authentication) CFRelease(contextInfo->authentication);
+               if (contextInfo->headerFieldName) CFRelease(contextInfo->headerFieldName);
+               if (contextInfo->headerFieldValue) CFRelease(contextInfo->headerFieldValue);
+               if (contextInfo->bodyData) CFRelease(contextInfo->bodyData);
+               if (contextInfo->url) CFRelease(contextInfo->url);
+               freeL("HTTPDataStreamContext", contextInfo);
+               }
        }
 
-mDNSexport  void  mDNSPlatformTLSTearDownCerts(void)
+mDNSlocal CFStringRef eReporterGetValueForKey(CFDictionaryRef dict, char *keyCString)
        {
-#ifndef NO_SECURITYFRAMEWORK
-       if (ServerCerts) { CFRelease(ServerCerts); ServerCerts = NULL; }
-#endif /* NO_SECURITYFRAMEWORK */
-       }
+       CFStringRef value;
+       CFStringRef key;
 
-// This gets the text of the field currently labelled "Computer Name" in the Sharing Prefs Control Panel
-mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel)
-       {
-       CFStringEncoding encoding = kCFStringEncodingUTF8;
-       CFStringRef cfs = SCDynamicStoreCopyComputerName(NULL, &encoding);
-       if (cfs)
+       key = CFStringCreateWithCString(NULL, keyCString, kCFStringEncodingUTF8);
+       if (!CFDictionaryContainsKey(dict, key))
                {
-               CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
-               CFRelease(cfs);
+               LogMsg("eReporterGetValueForKey: ERROR!! key %s not found", keyCString);
+               return NULL;
                }
-       }
-
-// This gets the text of the field currently labelled "Local Hostname" in the Sharing Prefs Control Panel
-mDNSlocal void GetUserSpecifiedLocalHostName(domainlabel *const namelabel)
-       {
-       CFStringRef cfs = SCDynamicStoreCopyLocalHostName(NULL);
-       if (cfs)
+       value = (CFStringRef)CFDictionaryGetValue(dict, key);
+       CFRelease(key);
+       if (!value)
                {
-               CFStringGetPascalString(cfs, namelabel->c, sizeof(*namelabel), kCFStringEncodingUTF8);
-               CFRelease(cfs);
+               LogMsg("eReporterGetValueForKey: ERROR!! value not found for %s", keyCString);
+               return NULL;
                }
+       return value;
        }
-
-mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
-       {
-       mDNSs32 val;
-       CFNumberRef state = CFDictionaryGetValue(dict, CFSTR("Enabled"));
-       if (!state) return mDNSfalse;
-       if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
-               { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
-       return val ? mDNStrue : mDNSfalse;
-       }
-
-mDNSlocal mStatus SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa)
+       
+mDNSlocal void eReporterConfigCallback(CFMutableDataRef responseData, ELogContext *context)
        {
-       if (!sa) { LogMsg("SetupAddr ERROR: NULL sockaddr"); return(mStatus_Invalid); }
+       CFDictionaryRef dict = NULL;
+       char *plistKeys[] = {"URL", "Publish", "LoadText", "URI", NULL};
+       int i;
+       CFErrorRef error;
 
-       if (sa->sa_family == AF_INET)
+       if (!CFDataGetLength(responseData))
                {
-               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);
+               LogInfo("eReporterConfigCallback: Zero length data");
+               eReporterConfig.eRState = ConfigInvalid;
+               return;
                }
-
-       if (sa->sa_family == AF_INET6)
+       CFPropertyListFormat format = kCFPropertyListXMLFormat_v1_0;
+       dict = CFPropertyListCreateWithData(0, responseData, kCFPropertyListImmutable, &format, &error);
+       if ( dict == NULL )
                {
-               struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)sa;
-               // Inside the BSD kernel they use a hack where they stuff the sin6->sin6_scope_id
-               // value into the second word of the IPv6 link-local address, so they can just
-               // pass around IPv6 address structures instead of full sockaddr_in6 structures.
-               // Those hacked IPv6 addresses aren't supposed to escape the kernel in that form, but they do.
-               // To work around this we always whack the second word of any IPv6 link-local address back to zero.
-               if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr)) ifa_addr->sin6_addr.__u6_addr.__u6_addr16[1] = 0;
-               ip->type = mDNSAddrType_IPv6;
-               ip->ip.v6 = *(mDNSv6Addr*)&ifa_addr->sin6_addr;
-               return(mStatus_NoError);
+               LogMsg("eReporterConfigCallback: Parsing property list failed");
+               eReporterConfig.eRState = ConfigInvalid;
+               CFRelease(error);
+               return;
                }
-
-       LogMsg("SetupAddr invalid sa_family %d", sa->sa_family);
-       return(mStatus_Invalid);
-       }
-
-mDNSlocal mDNSEthAddr GetBSSID(char *ifa_name)
-       {
-       mDNSEthAddr eth = zeroEthAddr;
-       SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:GetBSSID"), NULL, NULL);
-       if (!store)
-               LogMsg("GetBSSID: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
-       else
+       i = 0;
+       while (plistKeys[i] != NULL)
                {
-               CFStringRef entityname = CFStringCreateWithFormat(NULL, NULL, CFSTR("State:/Network/Interface/%s/AirPort"), ifa_name);
-               if (entityname)
+               if (eReporterGetValueForKey(dict, plistKeys[i]) == NULL)
                        {
-                       CFDictionaryRef dict = SCDynamicStoreCopyValue(store, entityname);
-                       if (dict)
-                               {
-                               CFRange range = { 0, 6 };               // Offset, length
-                               CFDataRef data = CFDictionaryGetValue(dict, CFSTR("BSSID"));
-                               if (data && CFDataGetLength(data) == 6) CFDataGetBytes(data, range, eth.b);
-                               CFRelease(dict);
-                               }
-                       CFRelease(entityname);
+                       LogMsg("eReporterConfigCallback: ERROR!! problem accessing key %s", plistKeys[i]);
+                       CFRelease(dict);
+                       eReporterConfig.eRState = ConfigInvalid;
+                       return;
                        }
-               CFRelease(store);
+               i++;
                }
-       return(eth);
+       if (eReporterConfig.eRDict) CFRelease(eReporterConfig.eRDict);
+       eReporterConfig.eRDict = dict;
+       eReporterConfig.eRState = ConfigValid;
+       mDNSReporterLogValidConfig(context);
        }
 
-mDNSlocal int GetMAC(mDNSEthAddr *eth, u_short ifindex)
+mDNSlocal mDNSBool FetchEReporterConfiguration(ELogContext *context)
        {
-       struct ifaddrs *ifa;
-       for (ifa = myGetIfAddrs(0); ifa; ifa = ifa->ifa_next)
-               if (ifa->ifa_addr->sa_family == AF_LINK)
-                       {
-                       const struct sockaddr_dl *const sdl = (const struct sockaddr_dl *)ifa->ifa_addr;
-                       if (sdl->sdl_index == ifindex)
-                               { mDNSPlatformMemCopy(eth->b, sdl->sdl_data + sdl->sdl_nlen, 6); return 0; }
-                       }
-       *eth = zeroEthAddr;
-       return -1;
-       }
+       const char *urlString = "https://configuration.apple.com./configurations/internetservices/e3/mDNSResponder/Configurations1.0.plist";
+       //const char *urlString = "http://isdev02:9702/configuration/configurations/internetservices/e3/btmm/Configurations1.0.plist"; //dev server
 
-#ifndef SIOCGIFWAKEFLAGS
-#define SIOCGIFWAKEFLAGS _IOWR('i', 136, struct ifreq) /* get interface wake property flags */
-#endif
+       CFStringRef url = CFStringCreateWithBytes(NULL, (const mDNSu8 *)urlString, strlen(urlString), kCFStringEncodingASCII, false);
+       if (!url) { LogMsg("FetchEReporterConfiguration: CFStringCreateWithBytes error"); return mDNSfalse; }
 
-#ifndef IF_WAKE_ON_MAGIC_PACKET
-#define IF_WAKE_ON_MAGIC_PACKET 0x01
-#endif
+       if (eReporterConfig.eRState == ConfigValid || eReporterConfig.eRState == ConfigFetching)
+               {
+               CFRelease(url);
+               return mDNSfalse;
+               }
 
-#ifndef ifr_wake_flags
-#define ifr_wake_flags ifr_ifru.ifru_intval
-#endif
+       eReporterConfig.eRState = ConfigFetching;
+       HTTPDataStream(url, HTTPGet, NULL, NULL, NULL, NULL, NULL, eReporterConfigCallback, context);
+       CFRelease(url);
+       return mDNStrue;
+       }
 
-mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
+// Builds an element of type : <key name="nameAttr"> value </key> and attaches it to
+// xmlTree
+mDNSlocal mDNSBool AddElementToTree(CFXMLTreeRef xmlTree, char *nameAttr, char *value)
        {
-       if (!MulticastInterface(i)     ) return(mDNSfalse);     // We only use Sleep Proxy Service on multicast-capable interfaces
-       if (i->ifa_flags & IFF_LOOPBACK) return(mDNSfalse);     // except loopback
+       /* <key name="BTMM domain"> domain </key> */
+
+       CFStringRef textval = CFStringCreateWithCString(NULL, value, kCFStringEncodingUTF8);
+       if (!textval) { LogMsg("AddElementToTree: cannot create CString for value %s", value); return mDNSfalse; }
 
-       int s = socket(AF_INET, SOCK_DGRAM, 0);
-       if (s < 0) { LogMsg("NetWakeInterface %s socket failed %s errno %d (%s)", i->ifinfo.ifname, errno, strerror(errno)); return(mDNSfalse); }
+       CFStringRef keys[1] = { CFSTR("name") };
+       CFStringRef values[1] = { CFStringCreateWithCString(NULL, nameAttr, kCFStringEncodingUTF8) };
 
-       struct ifreq ifr;
-       strlcpy(ifr.ifr_name, i->ifinfo.ifname, sizeof(ifr.ifr_name));
-       if (ioctl(s, SIOCGIFWAKEFLAGS, &ifr) < 0)
+       CFDictionaryRef dict = CFDictionaryCreate(NULL, (void*)keys, (void*)values, 1, &kCFTypeDictionaryKeyCallBacks,
+               &kCFTypeDictionaryValueCallBacks);
+       if (!dict)
                {
-               // For some strange reason, in /usr/include/sys/errno.h, EOPNOTSUPP is defined to be
-               // 102 when compiling kernel code, and 45 when compiling user-level code. Since this
-               // error code is being returned from the kernel, we need to use the kernel version.
-               #define KERNEL_EOPNOTSUPP 102
-               if (errno != KERNEL_EOPNOTSUPP) // "Operation not supported on socket", the expected result on Leopard and earlier
-                       LogMsg("NetWakeInterface SIOCGIFWAKEFLAGS %s errno %d (%s)", i->ifinfo.ifname, errno, strerror(errno));
-               // If on Leopard or earlier, we get EOPNOTSUPP, so in that case
-               // we enable WOL if this interface is not AirPort and "Wake for Network access" is turned on.
-               ifr.ifr_wake_flags = (errno == KERNEL_EOPNOTSUPP && !(i)->BSSID.l[0] && i->m->SystemWakeOnLANEnabled) ? IF_WAKE_ON_MAGIC_PACKET : 0;
+               LogMsg("AddElementToTree: ERROR!! CFDictionaryCreate failed for %s", nameAttr);
+               CFRelease(textval);
+               CFRelease(values[0]);
+               return mDNSfalse;
                }
-#if ASSUME_SNOWLEOPARD_INCORRECTLY_REPORTS_AIRPORT_INCAPABLE_OF_WAKE_ON_LAN
-       else
+
+       CFMutableArrayRef attr = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+       if (!attr)
                {
-               // Call succeeded.
-               // However, on SnowLeopard, it currently indicates incorrectly that AirPort is incapable of Wake-on-LAN.
-               // Therefore, for AirPort interfaces, we just track the system-wide Wake-on-LAN setting.
-               if ((i)->BSSID.l[0]) ifr.ifr_wake_flags = i->m->SystemWakeOnLANEnabled ? IF_WAKE_ON_MAGIC_PACKET : 0;
+               LogMsg("AddElementToTree: ERROR!! CFArrayCreateMutable failed for %s", nameAttr);
+               CFRelease(textval);
+               CFRelease(dict);
+               CFRelease(values[0]);
+               return mDNSfalse;
                }
-#endif
 
-       close(s);
+       CFArrayAppendValue(attr, keys[0]);
 
-       // ifr.ifr_wake_flags = IF_WAKE_ON_MAGIC_PACKET;        // For testing with MacBook Air, using a USB dongle that doesn't actually support Wake-On-LAN
+       /* Build <key name="nameAttr"> */
 
-       LogSPS("%-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
+       CFXMLElementInfo nameInfo;
+       nameInfo.attributes = (CFDictionaryRef)dict;
+       nameInfo.attributeOrder = (CFArrayRef) attr;
+       nameInfo.isEmpty = mDNSfalse;   
+       CFXMLNodeRef nameNode = CFXMLNodeCreate(kCFAllocatorDefault, kCFXMLNodeTypeElement, CFSTR("key"), &nameInfo,
+               kCFXMLNodeCurrentVersion);      
+       CFXMLTreeRef nameTree = CFXMLTreeCreateWithNode(kCFAllocatorDefault, nameNode);
+       CFTreeAppendChild(xmlTree, nameTree);
+       CFRelease(nameNode);
+       CFRelease(attr);
+       CFRelease(dict);
+       CFRelease(values[0]);
 
-       return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
+       /* Build the rest: value </key> */
+
+       CFXMLNodeRef nameTextNode = CFXMLNodeCreate(kCFAllocatorDefault, kCFXMLNodeTypeText, textval, NULL,
+          kCFXMLNodeCurrentVersion);   
+       CFXMLTreeRef nameTextTree = CFXMLTreeCreateWithNode(kCFAllocatorDefault, nameTextNode);
+       CFTreeAppendChild(nameTree, nameTextTree);
+       CFRelease(nameTextTree);
+       CFRelease(nameTextNode);
+       CFRelease(textval);
+
+       // Now that we are done with nameTree, we can release it
+       CFRelease(nameTree);
+
+       return mDNStrue;
        }
 
-// Returns pointer to newly created NetworkInterfaceInfoOSX object, or
-// pointer to already-existing NetworkInterfaceInfoOSX object found in list, or
-// may return NULL if out of memory (unlikely) or parameters are invalid for some reason
-// (e.g. sa_family not AF_INET or AF_INET6)
-mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(mDNS *const m, struct ifaddrs *ifa, mDNSs32 utc)
+mDNSlocal void LogPOSTArgs(CFStringRef finalURL, CFStringRef LoadTextName, CFStringRef LoadTextValue, CFDataRef bodyData)
        {
-       mDNSu32 scope_id  = if_nametoindex(ifa->ifa_name);
-       mDNSEthAddr bssid = GetBSSID(ifa->ifa_name);
+       char buf1[128], buf2[64], buf3[64], buf4[1024];
 
-       mDNSAddr ip, mask;
-       if (SetupAddr(&ip,   ifa->ifa_addr   ) != mStatus_NoError) return(NULL);
-       if (SetupAddr(&mask, ifa->ifa_netmask) != mStatus_NoError) return(NULL);
+       if (!CFStringGetCString(finalURL, buf1, sizeof(buf1), kCFStringEncodingUTF8) ||
+               !CFStringGetCString(LoadTextName, buf2, sizeof(buf2), kCFStringEncodingUTF8) ||
+               !CFStringGetCString(LoadTextValue, buf3, sizeof(buf3), kCFStringEncodingUTF8))
+               {
+               LogMsg("mDNSEReportPOSTArgs: Error in parsing arguments");
+               return; 
+               }
+       CFStringRef bstr = CFStringCreateFromExternalRepresentation(NULL, bodyData, kCFStringEncodingUTF8);
+       buf4[0] = 0;
+       if (!CFStringGetCString(bstr, buf4, sizeof(buf4), kCFStringEncodingUTF8))
+               {
+               LogMsg("mDNSEReportPOSTArgs: buf4 cstring conversion problem");
+               }
+       if (bstr) CFRelease(bstr);
+       LogInfo("LogPOSTArgs: URL : %s, LoadTextName: %s, LoadTextValue: %s, bodyData %s", buf1, buf2, buf3, buf4);
+       }
 
-       NetworkInterfaceInfoOSX **p;
-       for (p = &m->p->InterfaceList; *p; p = &(*p)->next)
-               if (scope_id == (*p)->scope_id &&
-                       mDNSSameAddress(&ip, &(*p)->ifinfo.ip) &&
-                       mDNSSameEthAddress(&bssid, &(*p)->BSSID))
-                       {
-                       debugf("AddInterfaceToList: Found existing interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, *p);
-                       (*p)->Exists = mDNStrue;
-                       // If interface was not in getifaddrs list last time we looked, but it is now, update 'AppearanceTime' for this record
-                       if ((*p)->LastSeen != utc) (*p)->AppearanceTime = utc;
+// This function is called when there is a valid configuration for eReporter service
+// We add the following:
+//
+// <key name="uuid"> uuid </key>
+// <key name="Subdomain"> subdomain </key>
+// <key name="Message"> message </key>
+// <key name="Time"> YYYY-MM-DD HH24:MI:SS </key>
+// <key name="SPS"> True/False </key>
+// <key name="Result"> Success/Fail </key>
+//
+// if result is -1, result won't be added. 1 means "Failed" and 0 means "Success"
+//
+mDNSlocal void mDNSReporterLogValidConfig(ELogContext *elog)
+       {
+       CFMutableStringRef finalURL = NULL;
+       CFStringRef LoadTextName = NULL;
+       CFDataRef bodyData = NULL;
+       CFBooleanRef pub;
+       CFXMLTreeRef appTree = NULL;
 
-                       // If Wake-on-LAN capability of this interface has changed (e.g. because power cable on laptop has been disconnected)
-                       // we may need to start or stop or sleep proxy browse operation
-                       const mDNSBool NetWake = NetWakeInterface(*p);
-                       if ((*p)->ifinfo.NetWake != NetWake)
+       pub = (CFBooleanRef)eReporterGetValueForKey(eReporterConfig.eRDict, "Publish");
+       if (pub == NULL)
+               {
+               LogMsg("mDNSReporterLogValidConfig: Publish key does not exist");
+               return;
+               }
+
+       Boolean pubVal = CFBooleanGetValue(pub);
+       if (!pubVal)
+               {
+               // Set the config state to invalid so that we will refetch the configuration next time
+               // in case Publish value changes between now and then
+               eReporterConfig.eRState = ConfigInvalid;
+               LogInfo("mDNSReporterLogValidConfig: Value for Publish is %d", pubVal);
+               return;
+               }
+
+       CFXMLDocumentInfo documentInfo;
+       documentInfo.sourceURL = NULL;
+       documentInfo.encoding = kCFStringEncodingUTF8;
+       CFXMLNodeRef docNode = CFXMLNodeCreate( kCFAllocatorDefault, kCFXMLNodeTypeDocument, CFSTR(""), &documentInfo,
+               kCFXMLNodeCurrentVersion);
+       CFXMLTreeRef xmlDocument = CFXMLTreeCreateWithNode(kCFAllocatorDefault, docNode);
+       CFRelease(docNode);
+
+       /* <?xml version="1.0" encoding="utf-8"?> */
+       CFXMLProcessingInstructionInfo instructionInfo;
+       instructionInfo.dataString = CFSTR("version=\"1.0\" encoding=\"utf-8\"");
+       CFXMLNodeRef instructionNode = CFXMLNodeCreate(NULL, kCFXMLNodeTypeProcessingInstruction, CFSTR("xml"),
+               &instructionInfo, kCFXMLNodeCurrentVersion);
+       CFXMLTreeRef instructionTree = CFXMLTreeCreateWithNode(kCFAllocatorDefault, instructionNode);
+       CFTreeAppendChild(xmlDocument, instructionTree);
+       CFRelease(instructionTree);
+       CFRelease(instructionNode);
+
+       /* Root Element: <app name="mDNSResponder" version="XXX"> */
+
+       CFStringRef appKeys[2] = { CFSTR("name"), CFSTR("version") };
+       CFStringRef appValues[2] = { CFStringCreateWithCString(NULL, "mDNSResponder", kCFStringEncodingUTF8),
+                                                                CFStringCreateWithCString(NULL, STRINGIFY(mDNSResponderVersion), kCFStringEncodingUTF8) };
+
+       CFDictionaryRef appDict = CFDictionaryCreate(NULL, (void*)appKeys, (void*)appValues, 2, &kCFTypeDictionaryKeyCallBacks,
+               &kCFTypeDictionaryValueCallBacks);
+       if (!appDict) { LogMsg("mDNSEReporterLogValidConfig: CFDictionaryCreate App failed"); goto cleanup; }
+
+       CFMutableArrayRef appAttr = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+       if (!appAttr) { LogMsg("mDNSEReporterLogValidConfig: CFArrayCreateMutable App failed"); goto cleanup; }
+
+       CFArrayAppendValue(appAttr, appKeys[0]);
+       CFArrayAppendValue(appAttr, appKeys[1]);
+
+       CFXMLElementInfo appInfo;
+       appInfo.attributes = (CFDictionaryRef) appDict;
+       appInfo.attributeOrder = (CFArrayRef) appAttr;
+       appInfo.isEmpty = mDNSfalse;
+       CFXMLNodeRef appNode = CFXMLNodeCreate ( kCFAllocatorDefault, kCFXMLNodeTypeElement, CFSTR("app"), &appInfo,
+               kCFXMLNodeCurrentVersion);      
+       appTree = CFXMLTreeCreateWithNode(kCFAllocatorDefault, appNode);
+       CFTreeAppendChild(xmlDocument, appTree);
+       CFRelease(appNode);
+       CFRelease(appAttr);
+       CFRelease(appDict);
+       CFRelease(appValues[0]);
+       CFRelease(appValues[1]);
+       // appTree will be released at the end as we will be appeneding other nodes to appTree below
+
+       char            uuidStr[37];
+       uuid_unparse(elog->uuid, uuidStr);
+       AddElementToTree(appTree, "UUID", uuidStr);
+
+       AddElementToTree(appTree, "Subdomain", elog->subdomain);
+       AddElementToTree(appTree, "Message", elog->message);
+
+       char tm_buffer[128];
+       time_t t = time(NULL);
+       struct tm *tm_t = gmtime(&t);
+       mDNS_snprintf(tm_buffer, sizeof(tm_buffer), "%4d-%02d-%02d %02d:%02d:%02d", tm_t->tm_year + 1900, tm_t->tm_mon + 1,
+               tm_t->tm_mday, tm_t->tm_hour, tm_t->tm_min, tm_t->tm_sec);
+       AddElementToTree(appTree, "Time", tm_buffer);
+
+       const CacheRecord *sps[3] = { mDNSNULL };
+       NetworkInterfaceInfo *intf;
+       mDNSBool SleepProxy = mDNSfalse;
+       for (intf = GetFirstActiveInterface(mDNSStorage.HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next))
+               {
+               if (intf->NetWake)
+                       {
+                       FindSPSInCache(&mDNSStorage, &intf->NetWakeBrowse, sps);
+                       if (sps[0])
                                {
-                               (*p)->ifinfo.NetWake = NetWake;
-                               // If this interface is already registered with mDNSCore, then we need to start or stop its NetWake browse on-the-fly.
-                               // If this interface is not already registered (i.e. it's a dormant interface we had in our list
-                               // from when we previously saw it) then we mustn't do that, because mDNSCore doesn't know about it yet.
-                               // In this case, the mDNS_RegisterInterface() call will take care of starting the NetWake browse if necessary.
-                               if ((*p)->Registered)
-                                       {
-                                       mDNS_Lock(m);
-                                       if (NetWake) mDNS_ActivateNetWake_internal  (m, &(*p)->ifinfo);
-                                       else         mDNS_DeactivateNetWake_internal(m, &(*p)->ifinfo);
-                                       mDNS_Unlock(m);
-                                       }
+                               SleepProxy = mDNStrue;
+                               break;
                                }
-
-                       return(*p);
                        }
+               else { LogInfo("mDNSEReporterValidConfig: NetWake is not set %p", intf->InterfaceID); }
+               }
+       AddElementToTree(appTree, "SPS", (SleepProxy ? "True" : "False"));
 
-       NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
-       debugf("AddInterfaceToList: Making   new   interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
-       if (!i) return(mDNSNULL);
-       mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
-       i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id;
-       i->ifinfo.ip          = ip;
-       i->ifinfo.mask        = mask;
-       strlcpy(i->ifinfo.ifname, ifa->ifa_name, sizeof(i->ifinfo.ifname));
-       i->ifinfo.ifname[sizeof(i->ifinfo.ifname)-1] = 0;
-       // We can be configured to disable multicast advertisement, but we want to to support
-       // local-only services, which need a loopback address record.
-       i->ifinfo.Advertise   = m->DivertMulticastAdvertisements ? ((ifa->ifa_flags & IFF_LOOPBACK) ? mDNStrue : mDNSfalse) : m->AdvertiseLocalAddresses;
-       i->ifinfo.McastTxRx   = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList
+       if (elog->result != -1)
+               AddElementToTree(appTree, "Result", elog->result ? "fail" : "success");
 
-       i->next            = mDNSNULL;
-       i->m               = m;
-       i->Exists          = mDNStrue;
-       i->Flashing        = mDNSfalse;
-       i->Occulting       = mDNSfalse;
-       i->AppearanceTime  = utc;               // Brand new interface; AppearanceTime is now
-       i->LastSeen        = utc;
-       i->ifa_flags       = ifa->ifa_flags;
-       i->scope_id        = scope_id;
-       i->BSSID           = bssid;
-       i->sa_family       = ifa->ifa_addr->sa_family;
-       i->BPF_fd          = -1;
-       i->BPF_len         = 0;
-       i->Registered      = mDNSNULL;
+       bodyData = CFXMLTreeCreateXMLData(NULL, xmlDocument);
+       if (!bodyData) { LogMsg("mDNSEReporterLogValidConfig: CFXMLTreeCreateData failed for bodyData"); goto cleanup; }
 
-       // Do this AFTER i->BSSID has been set up
-       i->ifinfo.NetWake  = NetWakeInterface(i);
-       GetMAC(&i->ifinfo.MAC, scope_id);
-       if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
-               LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
+       CFStringRef url = eReporterGetValueForKey(eReporterConfig.eRDict, "URL");
+       if (!url) { LogMsg("mDNSEReporterLogValidConfig: eReporterGetValueForKey failed for URL"); goto cleanup; }
 
-       *p = i;
-       return(i);
-       }
+       CFStringRef uri = eReporterGetValueForKey(eReporterConfig.eRDict, "URI");
+       if (!uri) { LogMsg("mDNSEReporterLogValidConfig: eReporterGetValueForKey failed for URI"); goto cleanup; }
 
-#if USE_V6_ONLY_WHEN_NO_ROUTABLE_V4
-mDNSlocal NetworkInterfaceInfoOSX *FindRoutableIPv4(mDNS *const m, mDNSu32 scope_id)
-       {
-       NetworkInterfaceInfoOSX *i;
-       for (i = m->p->InterfaceList; i; i = i->next)
-               if (i->Exists && i->scope_id == scope_id && i->ifinfo.ip.type == mDNSAddrType_IPv4)
-                       if (!mDNSv4AddressIsLinkLocal(&i->ifinfo.ip.ip.v4))
-                               return(i);
-       return(mDNSNULL);
-       }
-#endif
+       finalURL = CFStringCreateMutable(NULL, 0);
+       if (!finalURL) { LogMsg("mDNSEReporterLogValidConfig: CFStringCreateMutable failed for finalURL"); goto cleanup; }
 
-#if APPLE_OSX_mDNSResponder
+       CFStringAppend(finalURL, url);
+       CFStringAppend(finalURL, uri);
 
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - AutoTunnel
-#endif
+       LoadTextName = CFStringCreateWithCString(NULL, "x-LoadText", kCFStringEncodingUTF8);
+       if (!LoadTextName) { LogMsg("mDNSEReporterLogValidConfig: CFStringCreateWithCString failed for LoadText"); goto cleanup; }
 
-#define kRacoonPort 4500
+       CFStringRef LoadTextValue = eReporterGetValueForKey(eReporterConfig.eRDict, "LoadText");        
+       if (!LoadTextValue) { LogMsg("mDNSEReporterLogValidConfig: eReporterGetValueForKey failed for LoadTextValue"); goto cleanup; }
 
-static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
+       LogPOSTArgs(finalURL, LoadTextName, LoadTextValue, bodyData);
+
+       // we don't have a callback for the POST. If there is an error in POST, it will be logged
+       // by the callback of HTTPDataStream
+       HTTPDataStream(finalURL, HTTPPost, bodyData, LoadTextName, LoadTextValue, NULL, NULL, NULL, NULL);
+
+cleanup:
+       // Free whatever was allocated in this function
+       if (bodyData) CFRelease(bodyData);
+       if (finalURL) CFRelease(finalURL);
+       if (LoadTextName) CFRelease(LoadTextName);
+       if (appTree) CFRelease(appTree);
+       CFRelease(xmlDocument);
+       }
+
+mDNSlocal void mDNSEReporterLog(uuid_t *uuid, const char *subdomain, int result, char *message)
+       {
+       // We allocate ELogContext and free it at the end of the function. It is the
+       // responsibility of the called function to copy it if it needs to hold
+       // on to it
+       ELogContext *info = mallocL("ELogContext", sizeof (ELogContext));
+       if (!info) { LogMsg("mDNSEReporterLog: malloc failed"); return; }
+
+       // Take a local copy of all the log information
+       strlcpy(info->subdomain, subdomain, sizeof(info->subdomain));
+       strlcpy(info->message, message, sizeof(info->message));
+       info->result = result;
+       uuid_copy(info->uuid, *uuid);
+       if (eReporterConfig.eRState != ConfigValid)
+               {
+               // Currently we can't have two outstanding configuration fetches. If we have two quick
+               // back to back logs while the configuration is being fetched, we log only the first
+               // message to EReporter. If the configuration is valid (common case), then we don't
+               // drop any messages
+               if (!FetchEReporterConfiguration(info))
+                       {
+                       LogInfo("mDNSEReporterLog: Configuration being fetched.., Not logging");
+                       }
+               freeL("ELogContext", info);
+               return;
+               }
+       mDNSReporterLogValidConfig(info);
+       freeL("ELogContext", info);
+       }
 
 #ifndef NO_SECURITYFRAMEWORK
 
@@ -3318,13 +3802,11 @@ mDNSlocal void RemoveAutoTunnelDomainStatus(const mDNS *const m, const DomainAut
        CFRelease(domain);
        }
 
-#endif // ndef NO_SECURITYFRAMEWORK
-
 mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
        {
        if (q->LongLived)
                {
-               if (q->nta || (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4)))
+               if (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4))
                        return mStatus_NoSuchRecord;
                else if (q->state == LLQ_Poll)
                        return mStatus_PollingMode;
@@ -3335,6 +3817,58 @@ mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
        return mStatus_NoError;
 }
 
+mDNSlocal mStatus UpdateLLQStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
+       {
+       mStatus status = mStatus_NoError;
+       DNSQuestion* q, *worst_q = mDNSNULL;
+       for (q = m->Questions; q; q=q->next)
+               if (q->AuthInfo == info)
+                       {
+                       mStatus newStatus = CheckQuestionForStatus(q);
+                       if              (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; }
+                       else if (newStatus == mStatus_PollingMode)  { status = newStatus; worst_q = q; }
+                       else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; }
+                       }
+       
+       if      (status == mStatus_NoError)      mDNS_snprintf(buffer, bufsz, "Success");
+       else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, bufsz, "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c);
+       else if (status == mStatus_PollingMode)  mDNS_snprintf(buffer, bufsz, "Query polling %##s", worst_q->qname.c);
+       else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, bufsz, "Query not yet established %##s", worst_q->qname.c);
+       return status;
+       }
+
+mDNSlocal mStatus UpdateRRStatus(const mDNS *const m, char *buffer, int bufsz, const DomainAuthInfo *const info)
+       {
+       AuthRecord *r;
+
+       if (info->deltime) return mStatus_NoError;
+       for (r = m->ResourceRecords; r; r = r->next)
+               {
+               // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
+               // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
+               // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
+               // has already checked
+               const domainname *n = r->resrec.name;
+               while (n->c[0])
+                       {
+                       DomainAuthInfo *ptr;
+                       for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
+                               if (SameDomainName(&ptr->domain, n))
+                                       {
+                                       if (ptr == info && r->updateError == mStatus_BadSig)
+                                               {
+                                               mDNS_snprintf(buffer, bufsz, "Resource record update failed for %##s", r->resrec.name);
+                                               return r->updateError;
+                                               }
+                                       }
+                       n = (const domainname *)(n->c + 1 + n->c[0]);
+                       }
+               }
+       return mStatus_NoError;
+       }
+
+#endif // ndef NO_SECURITYFRAMEWORK
+
 // MUST be called with lock held
 mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAuthInfo *const info)
        {
@@ -3351,6 +3885,7 @@ mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAut
        CFNumberRef num = NULL;
        mStatus status = mStatus_NoError;
        
+       if (!m->mDNS_busy) LogMsg("UpdateAutoTunnelDomainStatus: ERROR!! Lock not held");
        if (!domainStatusDict)
                {
                domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
@@ -3448,7 +3983,32 @@ mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAut
                        }
                }
        
-       if (!llq && !tun)
+       // If we have a relay address, check the LLQ status as they don't go over the relay connection.
+       // If LLQs fail, then report failure. In future, when LLQs go over the relay connection, we don't
+       // need this logic
+       if (!mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr))
+               {
+               // If we have a bad signature error updating RR, it overrides any error as
+               // the user needs to be notified immediately 
+               status = UpdateRRStatus(m, buffer, sizeof(buffer), info);
+               if (status == mStatus_NoError)  
+                       {
+                       status = UpdateLLQStatus(m, buffer, sizeof(buffer), info);
+                       if (status == mStatus_PollingMode)      
+                               {
+                               // If we have a relay connection and we are in polling mode, report as success.
+                               // This normally happens when we are behind Double NAT or NAT with UPnP/NAT-PMP
+                               // disabled but we are able to successfully file share/screen share with the help
+                               // of the relay connection. As it just affects the discovery/update of the other
+                               // BTMM hosts, we consider it as minor issue and report it as success.
+                               LogInfo("UpdateAutoTunnelDomainStatus:NonzeroRelayAddress: Polling reported as success");
+                               status = mStatus_NoError;
+                               mDNS_snprintf(buffer, sizeof(buffer), "Success");
+                               }
+                       }
+               LogInfo("UpdateAutoTunnelDomainStatus:NonzeroRelayAddress: Status %d, %s", status, buffer);
+               }
+       else if (!llq && !tun)
                {
                status = mStatus_NotInitializedErr;
                mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
@@ -3486,20 +4046,10 @@ mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAut
                }
        else
                {
-               DNSQuestion* q, *worst_q = mDNSNULL;
-               for (q = m->Questions; q; q=q->next)
-                       if (q->AuthInfo == info)
-                               {
-                               mStatus newStatus = CheckQuestionForStatus(q);
-                               if              (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; }
-                               else if (newStatus == mStatus_PollingMode)  { status = newStatus; worst_q = q; }
-                               else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; }
-                               }
-               
-               if      (status == mStatus_NoError)      mDNS_snprintf(buffer, sizeof(buffer), "Success");
-               else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, sizeof(buffer), "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c);
-               else if (status == mStatus_PollingMode)  mDNS_snprintf(buffer, sizeof(buffer), "Query polling %##s", worst_q->qname.c);
-               else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, sizeof(buffer), "Query not yet established %##s", worst_q->qname.c);
+               status = UpdateRRStatus(m, buffer, sizeof(buffer), info);
+               if (status == mStatus_NoError)  
+                       status = UpdateLLQStatus(m, buffer, sizeof(buffer), info);
+               LogInfo("UpdateAutoTunnelDomainStatus:ZeroRelayAddress: Status %d, %s", status, buffer);
                }
        
        num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
@@ -3529,6 +4079,7 @@ mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAut
                        static char statusBuf[16];
                        mDNS_snprintf(statusBuf, sizeof(statusBuf), "%d", (int)status);
                        mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.domainstatus", status ? "failure" : "success", statusBuf, "");
+                       mDNSEReporterLog((uuid_t *)&m->asl_uuid, "autotunnel.domainstatus", status, statusBuf);
                        mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
                        }
                }
@@ -3536,6 +4087,7 @@ mDNSlocal void UpdateAutoTunnelDomainStatus(const mDNS *const m, const DomainAut
        CFRelease(domain);
        CFRelease(dict);
 
+
        debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
 #endif // def NO_SECURITYFRAMEWORK
        }
@@ -3546,6 +4098,7 @@ mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
 #ifdef NO_SECURITYFRAMEWORK
        (void)m;
 #else
+       if (!m->mDNS_busy) LogMsg("UpdateAutoTunnelDomainStatuses: ERROR!! Lock not held");
        DomainAuthInfo* info;
        for (info = m->AuthInfoList; info; info = info->next)
                if (info->AutoTunnel && !info->deltime)
@@ -3556,13 +4109,6 @@ mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
 // MUST be called with lock held
 mDNSlocal mDNSBool TunnelServers(mDNS *const m)
        {
-       ServiceRecordSet *p;
-       for (p = m->ServiceRegistrations; p; p = p->uDNS_next)
-               {
-               DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, p->RR_SRV.resrec.name);
-               if (AuthInfo && AuthInfo->AutoTunnel && !AuthInfo->deltime) return(mDNStrue);
-               }
-
        AuthRecord *r;
        for (r = m->ResourceRecords; r; r = r->next)
                if (r->resrec.rrtype == kDNSType_SRV)
@@ -3584,46 +4130,151 @@ mDNSlocal mDNSBool TunnelClients(mDNS *const m)
        return(mDNSfalse);
        }
 
-mDNSlocal void RegisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info)
+mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m)            // Determine whether we need racoon to accept incoming connections
        {
-       if (info->AutoTunnelNAT.clientContext && !info->AutoTunnelNAT.Result && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort) && AutoTunnelUnregistered(info))
+       DomainAuthInfo *info;
+       
+       for (info = m->AuthInfoList; info; info = info->next)
+               if (info->AutoTunnel && !info->deltime && (!mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort) || !mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr)))
+                       break;
+       
+       if (info != AnonymousRacoonConfig)
                {
-               mStatus err;
-               LogInfo("RegisterAutoTunnelRecords %##s (%#s)", info->domain.c, m->hostlabel.c);
+               AnonymousRacoonConfig = info;
+               // Create or revert configuration file, and start (or SIGHUP) Racoon
+               (void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, AnonymousRacoonConfig ? &AnonymousRacoonConfig->domain : mDNSNULL);
+               }
+       }
+
+// Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
+// sometimes the caller may already be holding the lock e.g., RegisterAutoTunnel6Record and sometimes
+// not e.g., RegisterAutoTunnelServiceRecord
+mDNSlocal void RegisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
+       {
+       mStatus err;
+       mDNSBool NATProblem;
+
+       if (!m->mDNS_busy) LogMsg("RegisterAutoTunnelHostRecord: ERROR!! Lock not held");
+
+       // We use AutoTunnelNAT.clientContext to infer that SetupLocalAutoTunnelInterface_internal has been
+       // called at least once with some Services/Records in the domain and hence it is safe to register
+       // records when this function is called.
+       if (!info->AutoTunnelNAT.clientContext) { LogInfo("RegisterAutoTunnelHostRecord: No services registered, not registering the record\n"); return; }
+
+       // Are we behind a NAT with no NAT-PMP support or behind a Double NAT ? Double NATs may have
+       // NAT-PMP support but it still does not provide inbound connectivity. If there is no NAT-PMP
+       // support, ExternalPort is zero. If we are behind a Double NAT, then the NATResult is non-zero.
+
+       NATProblem = mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort) || info->AutoTunnelNAT.Result;
+
+       if (mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr))
+               {
+               // If we don't have a relay address, check to see if we are behind a Double NAT or NAT with no NAT-PMP
+               // support.  
+               if (NATProblem)
+                       {
+                       LogInfo("RegisterAutoTunnelHostRecord %##s, not registering the Host Record, Neither AutoTunnel6 nor NAT is available, ClientContext %p, ExternalPort %d, NAT Result %d", info->domain.c, info->AutoTunnelNAT.clientContext, mDNSVal16(info->AutoTunnelNAT.ExternalPort), info->AutoTunnelNAT.Result);
+                       return;
+                       }
+               }
+       else
+               {
+               // Relay address may be non-zero but we might be going to sleep as the utun interface is not removed
+               // when going to sleep. If we are awake, we don't care about the NATProblem as the relay connnection
+               // is up. If we are going to sleep, we should not register the host record if we have a NAT problem.
+               if (m->SleepState != SleepState_Awake && NATProblem)
+                       {
+                       LogInfo("RegisterAutoTunnelHostRecord %##s, not registering the Host Record, Not in awake state(%d), and some NAT Problem, ClientContext %p, ExternalPort %d, NAT Result %d", info->domain.c, m->SleepState, info->AutoTunnelNAT.clientContext, mDNSVal16(info->AutoTunnelNAT.ExternalPort), info->AutoTunnelNAT.Result);
+                       return;
+                       }
+               }
 
-               // 1. Set up our address record for the internal tunnel address
-               // (User-visible user-friendly host name, used as target in AutoTunnel SRV records)
+       // Note:
+       //
+       // We use zero Requested port to infer that we should not be calling Register anymore as it might
+       // be shutdown or the DomainAuthInfo is going away.
+       //
+       // We can use a different set of state variables to track the above as the records registered in
+       // this function is not dependent on NAT traversal info. For the sake of simplicity, we just
+       // reuse the NAT variables.
+
+       // Set up our address record for the internal tunnel address
+       // (User-visible user-friendly host name, used as target in AutoTunnel SRV records)
+       if (!mDNSIPPortIsZero(info->AutoTunnelNAT.RequestedPort) && info->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered)
+               {
                info->AutoTunnelHostRecord.namestorage.c[0] = 0;
                AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
                AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
                info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = m->AutoTunnelHostAddr;
                info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
-               err = mDNS_Register(m, &info->AutoTunnelHostRecord);
-               if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c);
 
-               // 2. Set up device info record
-               ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
-               mDNSu8 len = m->HIHardware.c[0] < 255 - 6 ? m->HIHardware.c[0] : 255 - 6;
-               mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 1, "model=", 6);
-               mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 7, m->HIHardware.c + 1, len);
-               info->AutoTunnelDeviceInfo.resrec.rdata->u.data[0] = 6 + len;   // "model=" plus the device string
-               info->AutoTunnelDeviceInfo.resrec.rdlength         = 7 + len;   // One extra for the length byte at the start of the string
-               info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
-               err = mDNS_Register(m, &info->AutoTunnelDeviceInfo);
-               if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
+               err = mDNS_Register_internal(m, &info->AutoTunnelHostRecord);
+
+               if (err) LogMsg("RegisterAutoTunnelHostRecord error %d registering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c);
+               else
+                       {
+                       // Make sure we trigger the registration of all SRV records in regState_NoTarget again
+                       m->NextSRVUpdate = NonZeroTime(m->timenow);
+                       LogInfo("RegisterAutoTunnelHostRecord registering AutoTunnelHostRecord %##s", info->AutoTunnelHostRecord.namestorage.c);
+                       }
+               }
+       else LogInfo("RegisterAutoTunnelHostRecord: Not registering Context %p Port %d Type %d", info->AutoTunnelNAT.clientContext, mDNSVal16(info->AutoTunnelNAT.RequestedPort), info->AutoTunnelHostRecord.resrec.RecordType);
+       }
+
+mDNSlocal void DeregisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
+       {
+       LogInfo("DeregisterAutoTunnelHostRecord %##s", info->domain.c);
+
+       // Don't deregister if we have the AutoTunnel6 or AutoTunnelService records are registered.
+       // They indicate that BTMM is working
+       if (info->AutoTunnel6Record.resrec.RecordType > kDNSRecordTypeDeregistering ||
+           info->AutoTunnelService.resrec.RecordType > kDNSRecordTypeDeregistering)
+               {
+               LogInfo("DeregisterAutoTunnelHostRecord %##s, not deregistering the Host Record AutoTunnel6 RecordType:%d AutoTunnel RecordType: %d", info->domain.c,
+                       info->AutoTunnel6Record.resrec.RecordType, info->AutoTunnelService.resrec.RecordType);
+               return;
+               }
+
+       if (info->AutoTunnelHostRecord.resrec.RecordType > kDNSRecordTypeDeregistering)
+               {
+               mStatus err = mDNS_Deregister(m, &info->AutoTunnelHostRecord);
+               if (err)
+                       {
+                       info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
+                       LogMsg("DeregisterAutoTunnelHostRecord error %d deregistering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c);
+                       }
+               else LogInfo("DeregisterAutoTunnelHostRecord: Deregistered AutoTunnel Host Record");
+               }
+       else LogInfo("DeregisterAutoTunnelHostRecord: Not deregistering Host Record state:%d", info->AutoTunnelHostRecord.resrec.RecordType);
+       }
+
+mDNSlocal void RegisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
+       {
+       mStatus err;
+
+       //if (m->mDNS_busy) LogMsg("RegisterAutoTunnelServiceRecords: ERROR!! Lock already held");
+
+       if (info->AutoTunnelNAT.clientContext && !info->AutoTunnelNAT.Result && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort) && info->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered)
+               {
+               LogInfo("RegisterAutoTunnelServiceRecords %##s (%#s)", info->domain.c, m->hostlabel.c);
 
-               // 3. Set up our address record for the external tunnel address
+               // 1. Set up our address record for the external tunnel address
                // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
                info->AutoTunnelTarget.namestorage.c[0] = 0;
                AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->AutoTunnelLabel);
                AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
+               info->AutoTunnelTarget.resrec.rdata->u.ipv4 = info->AutoTunnelNAT.ExternalAddress;
                info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
 
-               mDNS_Lock(m);
-               mDNS_AddDynDNSHostName(m, &info->AutoTunnelTarget.namestorage, mDNSNULL, info);
-               mDNS_Unlock(m);
+               err = mDNS_Register(m, &info->AutoTunnelTarget);
+               if (err) LogMsg("RegisterAutoTunnelServiceRecords error %d registering AutoTunnelTarget %##s", err, info->AutoTunnelTarget.namestorage.c);
+               else LogInfo("RegisterAutoTunnelServiceRecords registering AutoTunnelTarget %##s", info->AutoTunnelTarget.namestorage.c);
+
+               }
 
-               // 4. Set up IKE tunnel's SRV record: "AutoTunnelHostRecord SRV 0 0 port AutoTunnelTarget"
+       if (info->AutoTunnelNAT.clientContext && !info->AutoTunnelNAT.Result && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort) && info->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered)
+               {
+               // 2. Set up IKE tunnel's SRV record: "AutoTunnelHostRecord SRV 0 0 port AutoTunnelTarget"
                AssignDomainName (&info->AutoTunnelService.namestorage, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
                AppendDomainLabel(&info->AutoTunnelService.namestorage, &m->hostlabel);
                AppendDomainName (&info->AutoTunnelService.namestorage, &info->domain);
@@ -3633,40 +4284,91 @@ mDNSlocal void RegisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info)
                AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
                info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
                err = mDNS_Register(m, &info->AutoTunnelService);
-               if (err) LogMsg("RegisterAutoTunnelRecords error %d registering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
+               if (err) LogMsg("RegisterAutoTunnelServiceRecords error %d registering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
+               else LogInfo("RegisterAutoTunnelServiceRecords registering AutoTunnelService %##s", info->AutoTunnelService.namestorage.c);
 
                LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
                        info->AutoTunnelTarget.namestorage.c,     &m->AdvertisedV4.ip.v4, mDNSVal16(info->AutoTunnelNAT.IntPort),
                        info->AutoTunnelHostRecord.namestorage.c, &m->AutoTunnelHostAddr);
                }
+       mDNS_Lock(m);
+       RegisterAutoTunnelHostRecord(m, info);
+       mDNS_Unlock(m);
        }
 
-mDNSlocal void DeregisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info)
+mDNSlocal void DeregisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
        {
-       LogInfo("DeregisterAutoTunnelRecords %##s", info->domain.c);
-       if (info->AutoTunnelService.resrec.RecordType > kDNSRecordTypeDeregistering)
+       LogInfo("DeregisterAutoTunnelServiceRecords %##s", info->domain.c);
+       if (info->AutoTunnelTarget.resrec.RecordType > kDNSRecordTypeDeregistering)
                {
-               mStatus err = mDNS_Deregister(m, &info->AutoTunnelService);
+               mStatus err = mDNS_Deregister(m, &info->AutoTunnelTarget);
                if (err)
                        {
-                       info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeUnregistered;
-                       LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
+                       info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeUnregistered;
+                       LogMsg("DeregisterAutoTunnelServiceRecords error %d deregistering AutoTunnelTarget %##s", err, info->AutoTunnelTarget.namestorage.c);
                        }
+               else LogInfo("DeregisterAutoTunnelServiceRecords: Deregistered AutoTunnel Target  Record");
 
-               mDNS_Lock(m);
-               mDNS_RemoveDynDNSHostName(m, &info->AutoTunnelTarget.namestorage);
-               mDNS_Unlock(m);
                }
+       else LogInfo("DeregisterAutoTunnelServiceRecords: Not deregistering Target record state:%d", info->AutoTunnelService.resrec.RecordType);
 
-       if (info->AutoTunnelHostRecord.resrec.RecordType > kDNSRecordTypeDeregistering)
+       if (info->AutoTunnelService.resrec.RecordType > kDNSRecordTypeDeregistering)
                {
-               mStatus err = mDNS_Deregister(m, &info->AutoTunnelHostRecord);
+               mStatus err = mDNS_Deregister(m, &info->AutoTunnelService);
                if (err)
                        {
-                       info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeUnregistered;
-                       LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelHostRecord %##s", err, info->AutoTunnelHostRecord.namestorage.c);
+                       info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeUnregistered;
+                       LogMsg("DeregisterAutoTunnelServiceRecords error %d deregistering AutoTunnelService %##s", err, info->AutoTunnelService.namestorage.c);
                        }
+               else LogInfo("DeregisterAutoTunnelServiceRecords: Deregistered AutoTunnel Service Record");
+
+               }
+       else LogInfo("DeregisterAutoTunnelServiceRecords: Not deregistering service records state:%d", info->AutoTunnelService.resrec.RecordType);
+
+       DeregisterAutoTunnelHostRecord(m, info);
+       }
+
+// Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
+// sometimes the caller may already be holding the lock e.g., SetupLocalAutoTunnelInterface_internal and sometimes
+// not e.g., AutoTunnelHostNameChanged
+mDNSlocal void RegisterAutoTunnelDevInfoRecord(mDNS *m, DomainAuthInfo *info)
+       {
+       mStatus err;
+
+       if (!m->mDNS_busy) LogMsg("RegisterAutoTunnelDevInfoRecord: Lock not held");
+       // Note:
+       // a. We use AutoTunnelNAT.clientContext to infer that SetupLocalAutoTunnelInterface_internal has been
+       //    called at least once with some Services/Records in the domain and hence it is safe to register
+       //    records when this function is called.
+       //
+       // b. We use zero Requested port to infer that we should not be calling Register anymore as it might
+       //    be shutdown or the DomainAuthInfo is going away.
+       //
+       // We can use a different set of state variables to track the above as the records registered in
+       // this function is not dependent on NAT traversal info. For the sake of simplicity, we just
+       // reuse the NAT variables.
+
+       // Set up device info record
+       if (info->AutoTunnelNAT.clientContext && !mDNSIPPortIsZero(info->AutoTunnelNAT.RequestedPort) && info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
+               {
+               ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
+               mDNSu8 len = m->HIHardware.c[0] < 255 - 6 ? m->HIHardware.c[0] : 255 - 6;
+               mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 1, "model=", 6);
+               mDNSPlatformMemCopy(info->AutoTunnelDeviceInfo.resrec.rdata->u.data + 7, m->HIHardware.c + 1, len);
+               info->AutoTunnelDeviceInfo.resrec.rdata->u.data[0] = 6 + len;   // "model=" plus the device string
+               info->AutoTunnelDeviceInfo.resrec.rdlength         = 7 + len;   // One extra for the length byte at the start of the string
+               info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
+
+               err = mDNS_Register_internal(m, &info->AutoTunnelDeviceInfo);
+               if (err) LogMsg("RegisterAutoTunnelDevInfoRecord error %d registering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
+               else LogInfo("RegisterAutoTunnelDevInfoRecord registering AutoTunnelDeviceInfo %##s", info->AutoTunnelDeviceInfo.namestorage.c);
                }
+       }
+
+#ifndef NO_SECURITYFRAMEWORK
+mDNSlocal void DeregisterAutoTunnelDevInfoRecord(mDNS *m, DomainAuthInfo *info)
+       {
+       LogInfo("DeregisterAutoTunnelDevInfoRecord %##s", info->domain.c);
 
        if (info->AutoTunnelDeviceInfo.resrec.RecordType > kDNSRecordTypeDeregistering)
                {
@@ -3674,9 +4376,125 @@ mDNSlocal void DeregisterAutoTunnelRecords(mDNS *m, DomainAuthInfo *info)
                if (err)
                        {
                        info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeUnregistered;
-                       LogMsg("DeregisterAutoTunnelRecords error %d deregistering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
+                       LogMsg("DeregisterAutoTunnelDevInfoRecord error %d deregistering AutoTunnelDeviceInfo %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
+                       }
+               else LogInfo("DeregisterAutoTunnelDevInfoRecord: Deregistered AutoTunnel Device Info");
+               }
+       else LogInfo("DeregisterAutoTunnelDevInfoRecord: Not deregistering DeviceInfo  Record state:%d", info->AutoTunnelDeviceInfo.resrec.RecordType);
+       }
+#endif
+
+
+// Caller should hold the lock. We don't call mDNS_Register (which acquires the lock) in this function because
+// sometimes the caller may already be holding the lock e.g., SetupLocalAutoTunnelInterface_internal and sometimes
+// not e.g., AutoTunnelHostNameChanged
+mDNSlocal void RegisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
+       {
+       mStatus err;
+
+       if (!m->mDNS_busy) LogMsg("RegisterAutoTunnel6Record: ERROR!! Lock not held");
+
+       // We deregister the AutoTunnel6Record during sleep and come back here (AutoTunnelRecordCallback) to
+       // register the address if needed. During that time, we might get a network change event which finds
+       // that the utun interface exists and tries to register the AutoTunnel6Record which should be stopped.
+       // Also the RelayAddress is reinitialized during that process which in turn causes the AutoTunnelRecordCallback
+       // to re-register again. To stop these, we check for the SleepState and register only if we are awake.
+       if (m->SleepState != SleepState_Awake)
+               {
+               LogInfo("RegisterAutoTunnel6Record: Not in awake state, SleepState %d", m->SleepState);
+               return;
+               }
+
+       // if disabled administratively, don't register
+       // if disabled administratively, don't register
+       if (!m->RegisterAutoTunnel6 || DisableInboundRelayConnection)
+               {
+               LogInfo("RegisterAutoTunnel6Record: registration Disabled RegisterAutoTunnel6 %d, DisableInbound %d",
+                       m->RegisterAutoTunnel6, DisableInboundRelayConnection);
+               return;
+               }
+       //
+       // If we have a valid Relay address, we need to register it now. When we got a valid address, we may not
+       // have registered it because it was waiting for at least one service to become active in the BTMM domain.
+       // During network change event, we might be called multiple times while the "Connectivity" key did not
+       // change, so check to see if the value has changed. This can also be zero when we are deregistering and
+       // getting called from the AutoTunnelRecordCallback
+
+       if (mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr))
+               {
+               LogInfo("RegisterAutoTunnel6Record: Relay address is zero, not registering");
+               return;
+               }
+
+       if ((info->AutoTunnel6Record.resrec.RecordType > kDNSRecordTypeDeregistering) &&
+               (mDNSSameIPv6Address(info->AutoTunnel6Record.resrec.rdata->u.ipv6, m->AutoTunnelRelayAddr)))
+               {
+               LogInfo("RegisterAutoTunnel6Record: Relay address %.16a same, not registering", &m->AutoTunnelRelayAddr);
+               return;
+               }
+
+       // Note:
+       // a. We use AutoTunnelNAT.clientContext to infer that SetupLocalAutoTunnelInterface_internal has been
+       //    called at least once with some Services/Records in the domain and hence it is safe to register
+       //    records when this function is called.
+       //
+       // b. We use zero Requested port to infer that we should not be calling Register anymore as it might
+       //    be shutdown or the DomainAuthInfo is going away.
+       //
+       // We can use a different set of state variables to track the above as the records registered in
+       // this function is not dependent on NAT traversal info. For the sake of simplicity, we just
+       // reuse the NAT variables.
+
+       if (info->AutoTunnelNAT.clientContext && !mDNSIPPortIsZero(info->AutoTunnelNAT.RequestedPort) &&
+           info->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered)
+               {
+               AssignDomainName (&info->AutoTunnel6Record.namestorage, (const domainname*) "\x0C" "_autotunnel6");
+               AppendDomainLabel(&info->AutoTunnel6Record.namestorage, &m->hostlabel);
+               AppendDomainName (&info->AutoTunnel6Record.namestorage, &info->domain);
+               info->AutoTunnel6Record.resrec.rdata->u.ipv6 = m->AutoTunnelRelayAddr;
+               info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeKnownUnique;
+
+               err = mDNS_Register_internal(m, &info->AutoTunnel6Record);
+               if (err) LogMsg("RegisterAutoTunnel6Record error %d registering AutoTunnel6 Record %##s", err, info->AutoTunnel6Record.namestorage.c);
+               else LogInfo("RegisterAutoTunnel6Record registering AutoTunnel6 Record %##s", info->AutoTunnel6Record.namestorage.c);
+
+               LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
+                       info->AutoTunnel6Record.namestorage.c,     &m->AutoTunnelRelayAddr,
+                       info->AutoTunnelHostRecord.namestorage.c, &m->AutoTunnelHostAddr);
+
+               } else {LogInfo("RegisterAutoTunnel6Record: client context %p, RequestedPort %d, Address %.16a, record type %d", info->AutoTunnelNAT.clientContext, info->AutoTunnelNAT.RequestedPort, &m->AutoTunnelRelayAddr, info->AutoTunnel6Record.resrec.RecordType);}
+
+       RegisterAutoTunnelHostRecord(m, info);
+       // When the AutoTunnel6 record comes up, we need to kick racoon and update the status.
+       // If we had a port mapping, we would have done it in RegisterAutoTunnelServiceRecords.
+       // If we don't have a port mapping, we need to do it here.
+       UpdateAnonymousRacoonConfig(m);         // Determine whether we need racoon to accept incoming connections
+       UpdateAutoTunnelDomainStatus(m, info);
+       }
+
+mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
+       {
+       LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c);
+
+       if (info->AutoTunnel6Record.resrec.RecordType > kDNSRecordTypeDeregistering)
+               {
+               mStatus err = mDNS_Deregister(m, &info->AutoTunnel6Record);
+               if (err)
+                       {
+                       info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeUnregistered;
+                       info->AutoTunnel6Record.resrec.rdata->u.ipv6 = zerov6Addr;
+                       LogMsg("DeregisterAutoTunnel6Record error %d deregistering AutoTunnel6Record %##s", err, info->AutoTunnel6Record.namestorage.c);
                        }
+               else LogInfo("DeregisterAutoTunnel6Record: Deregistered AutoTunnel6 Record");
                }
+       else LogInfo("DeregisterAutoTunnel6Record: Not deregistering AuoTunnel6 record state:%d", info->AutoTunnel6Record.resrec.RecordType);
+
+       DeregisterAutoTunnelHostRecord(m, info);
+       // UpdateAutoTunnelDomainStatus is careful enough not to turn it on if we don't have
+       // a external port mapping. Otherwise, it will be turned off.
+       mDNS_Lock(m);
+       UpdateAutoTunnelDomainStatus(m, info);
+       mDNS_Unlock(m);
        }
 
 mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
@@ -3690,28 +4508,47 @@ mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mSt
                        {
                        rr->namestorage.c[0] = 0;
                        m->NextSRVUpdate = NonZeroTime(m->timenow);
+                       LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
+                       }
+               if (m->ShutdownTime) {LogInfo("AutoTunnelRecordCallback: Shutdown, returning");return;}
+               if (rr == &info->AutoTunnelHostRecord)
+                       {
+                       LogInfo("AutoTunnelRecordCallback: calling RegisterAutoTunnelHostRecord");
+                       RegisterAutoTunnelHostRecord(m,info);
+                       }
+               else if (rr == &info->AutoTunnelDeviceInfo)
+                       {
+                       LogInfo("AutoTunnelRecordCallback: Calling RegisterAutoTunnelDevInfoRecord");
+                       RegisterAutoTunnelDevInfoRecord(m,info);
+                       }
+               else if (rr == &info->AutoTunnelService || rr == &info->AutoTunnelTarget)
+                       {
+                       LogInfo("AutoTunnelRecordCallback: Calling RegisterAutoTunnelServiceRecords");
+                       RegisterAutoTunnelServiceRecords(m,info);
+                       }
+               else if (rr == &info->AutoTunnel6Record)
+                       {
+                       LogInfo("AutoTunnelRecordCallback: Calling RegisterAutoTunnel6Record");
+                       info->AutoTunnel6Record.resrec.rdata->u.ipv6 = zerov6Addr;
+                       RegisterAutoTunnel6Record(m,info);
                        }
-               RegisterAutoTunnelRecords(m,info);
                }
        }
 
-// Determine whether we need racoon to accept incoming connections
-mDNSlocal void UpdateConfigureServer(mDNS *m)
+#ifndef NO_SECURITYFRAMEWORK
+mDNSlocal void AutoTunnelDeleteAuthInfoState(mDNS *m, DomainAuthInfo *info)
        {
-       DomainAuthInfo *info;
-       
-       for (info = m->AuthInfoList; info; info = info->next)
-               if (info->AutoTunnel && !info->deltime && !mDNSIPPortIsZero(info->AutoTunnelNAT.ExternalPort))
-                       break;
-       
-       if (info != AnonymousRacoonConfig)
-               {
-               AnonymousRacoonConfig = info;
-               // Create or revert configuration file, and start (or SIGHUP) Racoon
-               (void)mDNSConfigureServer(AnonymousRacoonConfig ? kmDNSUp : kmDNSDown, AnonymousRacoonConfig ? &AnonymousRacoonConfig->domain : mDNSNULL);
-               }
+       LogInfo("AutoTunnelDeleteAuthInfoState: Cleaning up state releated to Domain AuthInfo %##s", info->domain.c);
+
+       m->NextSRVUpdate = NonZeroTime(m->timenow);
+       DeregisterAutoTunnelDevInfoRecord(m, info);
+       DeregisterAutoTunnelServiceRecords(m, info);
+       DeregisterAutoTunnel6Record(m, info);
+       UpdateAnonymousRacoonConfig(m);         // Determine whether we need racoon to accept incoming connections
+       UpdateAutoTunnelDomainStatus(m, info);
        }
-               
+#endif // ndef NO_SECURITYFRAMEWORK
+
 mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
        {
        DomainAuthInfo *info = (DomainAuthInfo *)n->clientContext;
@@ -3719,10 +4556,12 @@ mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
                n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort), m->hostlabel.c, info->domain.c);
 
        m->NextSRVUpdate = NonZeroTime(m->timenow);
-       DeregisterAutoTunnelRecords(m,info);
-       RegisterAutoTunnelRecords(m,info);
+       LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
+
+       DeregisterAutoTunnelServiceRecords(m, info);
+       RegisterAutoTunnelServiceRecords(m, info);
        
-       UpdateConfigureServer(m);
+       UpdateAnonymousRacoonConfig(m);         // Determine whether we need racoon to accept incoming connections
 
        UpdateAutoTunnelDomainStatus(m, (DomainAuthInfo *)n->clientContext);
        }
@@ -3738,205 +4577,475 @@ mDNSlocal void AbortDeregistration(mDNS *const m, AuthRecord *rr)
                LogMsg("AbortDeregistration ERROR RecordType %02X for %s", ARDisplayString(m, rr));
        }
 
+mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info)
+       {
+       LogInfo("AutoTunnelHostNameChanged %#s.%##s", m->hostlabel.c, info->domain.c);
+
+       DeregisterAutoTunnelDevInfoRecord(m, info);
+       DeregisterAutoTunnelServiceRecords(m, info);
+       DeregisterAutoTunnel6Record(m, info);
+       RegisterAutoTunnelServiceRecords(m, info);
+
+       mDNS_Lock(m);
+       RegisterAutoTunnelDevInfoRecord(m, info);
+       RegisterAutoTunnel6Record(m, info);
+       m->NextSRVUpdate = NonZeroTime(m->timenow);
+       mDNS_Unlock(m);
+       }
+
+mDNSlocal void SetupLocalAutoTunnel6Records(mDNS *const m, DomainAuthInfo *info)
+       {
+       AbortDeregistration(m, &info->AutoTunnelDeviceInfo);
+       AbortDeregistration(m, &info->AutoTunnel6Record);
+
+       // When the BTMM is turned on/off too quickly, following things happen.
+       //
+       // 1. Turning off BTMM triggers deregistration of the DevInfo/AutoTunnel6 etc. records
+       // 2. While (1) is in progress, the BTMM is turned on
+       //
+       // At step (2), mDNS_SetSecretForDomain clears info->deltime indicating that the domain is valid
+       // while we have not processed the turning off BTMM completely. Hence, we end up calling this
+       // function to re-register the records. AbortDeregistration above aborts the Deregistration as the
+       // records are still in Deregistering state and in AutoTunnelRecordCallback we end up registering
+       // again. So, we have to be careful below to not call mDNS_SetupResourceRecord again which will
+       // reset the state to Unregistered and registering again will lead to error as it is registered
+       // and already in the list. Hence, register below only if needed.
+
+       if (info->AutoTunnelDeviceInfo.resrec.RecordType != kDNSRecordTypeUnregistered ||
+           info->AutoTunnel6Record.resrec.RecordType != kDNSRecordTypeUnregistered)
+               {
+               LogInfo("SetupLocalAutoTunnel6Records: AutoTunnel Records not in Unregistered state: Device: %d, AutoTunnel6:%d",
+                       info->AutoTunnelDeviceInfo.resrec.RecordType, info->AutoTunnel6Record.resrec.RecordType);
+               }
+
+       if (info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
+               {
+               mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT,  kStandardTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
+               RegisterAutoTunnelDevInfoRecord(m, info);
+               }
+       if (info->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered)
+               {
+               mDNS_SetupResourceRecord(&info->AutoTunnel6Record, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
+               RegisterAutoTunnel6Record(m, info);
+               }
+
+       UpdateAnonymousRacoonConfig(m);         // Determine whether we need racoon to accept incoming connections
+       
+       UpdateAutoTunnelDomainStatus(m, info);
+       m->NextSRVUpdate = NonZeroTime(m->timenow);
+       }
+
 // Before SetupLocalAutoTunnelInterface_internal is called,
 // m->AutoTunnelHostAddr.b[0] must be non-zero, and there must be at least one TunnelClient or TunnelServer
 // Must be called with the lock held
-mDNSexport void SetupLocalAutoTunnelInterface_internal(mDNS *const m)
+mDNSexport void SetupLocalAutoTunnelInterface_internal(mDNS *const m, mDNSBool servicesStarting)
        {
-       LogInfo("SetupLocalAutoTunnelInterface");
-
-       // 1. Configure the local IPv6 address
+       // 1. Configure the local IPv6 ULA BTMM address
        if (!m->AutoTunnelHostAddrActive)
                {
                m->AutoTunnelHostAddrActive = mDNStrue;
-               LogInfo("Setting up AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
+               LogInfo("SetupLocalAutoTunnelInterface_internal: Setting up AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
                (void)mDNSAutoTunnelInterfaceUpDown(kmDNSUp, m->AutoTunnelHostAddr.b);
                }
 
        // 2. If we have at least one server (pending) listening, publish our records
-       if (TunnelServers(m))
+       // The services may not be in the list when it is first trying to resolve the target of the SRV record.
+       // servicesStarting is an indication of that. Use that instead of looking up in the list of Services/Records.
+       if (servicesStarting || TunnelServers(m))
                {
                DomainAuthInfo *info;
                for (info = m->AuthInfoList; info; info = info->next)
                        {
                        if (info->AutoTunnel && !info->deltime && !info->AutoTunnelNAT.clientContext)
                                {
-                               // If we just resurrected a DomainAuthInfo that is still deregistering, we need to abort the deregistration process before re-using the AuthRecord memory
-                               AbortDeregistration(m, &info->AutoTunnelHostRecord);
-                               AbortDeregistration(m, &info->AutoTunnelDeviceInfo);
+                               // If we just resurrected a DomainAuthInfo that is still deregistering, we need to abort the
+                               // deregistration process before re-using the AuthRecord memory
+                               //
+                               // Note: We don't need the same caution as in SetupLocalAutoTunnel6Records (see the comments there)
+                               // as AutoTunnelRecordCallback (called as a result of AbortDeregistration) will not end up registering
+                               // the records because clientContext is still NULL
+
+                               AbortDeregistration(m, &info->AutoTunnelTarget);
                                AbortDeregistration(m, &info->AutoTunnelService);
+                               AbortDeregistration(m, &info->AutoTunnelHostRecord);
 
-                               mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
-                               mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT,  kStandardTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
-                               mDNS_SetupResourceRecord(&info->AutoTunnelTarget,     mDNSNULL, mDNSInterface_Any, kDNSType_A,    kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
-                               mDNS_SetupResourceRecord(&info->AutoTunnelService,    mDNSNULL, mDNSInterface_Any, kDNSType_SRV,  kHostNameTTL, kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
+                               mDNS_SetupResourceRecord(&info->AutoTunnelTarget,     mDNSNULL, mDNSInterface_Any, kDNSType_A,    kHostNameTTL,
+                                       kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
+                               mDNS_SetupResourceRecord(&info->AutoTunnelService,    mDNSNULL, mDNSInterface_Any, kDNSType_SRV,  kHostNameTTL,
+                                       kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
+                               mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
+                                       kDNSRecordTypeUnregistered, AutoTunnelRecordCallback, info);
 
                                // Try to get a NAT port mapping for the AutoTunnelService
                                info->AutoTunnelNAT.clientCallback   = AutoTunnelNATCallback;
                                info->AutoTunnelNAT.clientContext    = info;
                                info->AutoTunnelNAT.Protocol         = NATOp_MapUDP;
-                               info->AutoTunnelNAT.IntPort          = mDNSOpaque16fromIntVal(kRacoonPort);
-                               info->AutoTunnelNAT.RequestedPort    = mDNSOpaque16fromIntVal(kRacoonPort);
+                               info->AutoTunnelNAT.IntPort          = IPSECPort;
+                               info->AutoTunnelNAT.RequestedPort    = IPSECPort;
                                info->AutoTunnelNAT.NATLease         = 0;
                                mStatus err = mDNS_StartNATOperation_internal(m, &info->AutoTunnelNAT);
-                               if (err) LogMsg("SetupLocalAutoTunnelInterface_internal error %d starting NAT mapping", err);
+                               if (err) LogMsg("SetupLocalAutoTunnelInterface_internal: error %d starting NAT mapping", err);
+
+                               // Register the records that can be done without communicating with the NAT
+                               //
+                               // Note: This should be done after we setup the AutoTunnelNAT information
+                               // as some of the fields in that structure are used to infer other information
+                               // e.g., is it okay to register now ?
+
+                               SetupLocalAutoTunnel6Records(m, info);
+
+                               }
+                       }
+               }
+       }
+
+mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
+       {
+       mDNSv6Addr loc_outer6;
+       mDNSv6Addr rmt_outer6;
+
+       // When we are tunneling over IPv6 Relay address, the port number is zero
+       if (mDNSIPPortIsZero(tun->rmt_outer_port))
+               {
+               loc_outer6 = tun->loc_outer6;
+               rmt_outer6 = tun->rmt_outer6;
+               }
+       else
+               {
+               loc_outer6 = zerov6Addr;
+               loc_outer6.b[0] = tun->loc_outer.b[0];
+               loc_outer6.b[1] = tun->loc_outer.b[1];
+               loc_outer6.b[2] = tun->loc_outer.b[2];
+               loc_outer6.b[3] = tun->loc_outer.b[3];
+
+               rmt_outer6 = zerov6Addr;
+               rmt_outer6.b[0] = tun->rmt_outer.b[0];
+               rmt_outer6.b[1] = tun->rmt_outer.b[1];
+               rmt_outer6.b[2] = tun->rmt_outer.b[2];
+               rmt_outer6.b[3] = tun->rmt_outer.b[3];
+               }
+
+       return(mDNSAutoTunnelSetKeys(AddNew ? kmDNSAutoTunnelSetKeysReplace : kmDNSAutoTunnelSetKeysDelete, tun->loc_inner.b, loc_outer6.b, kRacoonPort, tun->rmt_inner.b, rmt_outer6.b, mDNSVal16(tun->rmt_outer_port), SkipLeadingLabels(&tun->dstname, 1)));
+       }
+
+// If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
+#define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
+
+mDNSlocal void ReissueBlockedQuestionWithType(mDNS *const m, domainname *d, mDNSBool success, mDNSu16 qtype)
+       {
+       DNSQuestion *q = m->Questions;
+       while (q)
+               {
+               if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
+                       {
+                       LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+                       mDNSQuestionCallback *tmp = q->QuestionCallback;
+                       q->QuestionCallback = AutoTunnelCallback;       // Set QuestionCallback to suppress another call back to AddNewClientTunnel
+                       mDNS_StopQuery(m, q);
+                       mDNS_StartQuery(m, q);
+                       q->QuestionCallback = tmp;                                      // Restore QuestionCallback back to the real value
+                       if (!success) q->NoAnswer = NoAnswer_Fail;
+                       // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
+                       // In general we have to assume that the question list might have changed in arbitrary ways.
+                       // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
+                       // already in use. The safest solution is just to go back to the start of the list and start again.
+                       // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
+                       // just one suspended question, so it's really a 2n algorithm.
+                       q = m->Questions;
+                       }
+               else
+                       q = q->next;
+               }
+       }
+
+mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success)
+       {
+       // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
+       //    a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
+       // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
+       //    even if the name does have a valid AAAA record, we don't want clients trying to connect to it without a properly encrypted tunnel.
+       // 3. For A queries we never fabricate failures -- if a BTTM service is really using raw IPv4, then it doesn't need the IPv6 tunnel.
+       ReissueBlockedQuestionWithType(m, d, success, kDNSType_AAAA);
+       ReissueBlockedQuestionWithType(m, d, mDNStrue, kDNSType_A);
+       }
+
+mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success)
+       {
+       ClientTunnel **p = &m->TunnelClients;
+       while (*p != tun && *p) p = &(*p)->next;
+       if (*p) *p = tun->next;
+       ReissueBlockedQuestions(m, &tun->dstname, success);
+       LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
+       freeL("ClientTunnel", tun);
+       }
+
+mDNSlocal mDNSBool TunnelClientDeleteMatching(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
+       {
+       ClientTunnel **p;
+       mDNSBool needSetKeys = mDNStrue;
+
+       p = &tun->next;
+       while (*p)
+               {
+               // Is this a tunnel to the same host that we are trying to setup now?
+               if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
+               else
+                       {
+                       ClientTunnel *old = *p;
+                       if (v6Tunnel)
+                               {
+                               if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
+                               LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+                               if (old->q.ThisQInterval >= 0)
+                                       {
+                                       LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+                                       mDNS_StopQuery(m, &old->q);
+                                       }
+                               else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
+                                               !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner)   ||
+                                               !mDNSSameIPv6Address(old->loc_outer6, tun->loc_outer6) ||
+                                               !mDNSSameIPv6Address(old->rmt_outer6, tun->rmt_outer6))
+                                       {
+                                       // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
+                                       // the other parameters of the tunnel are different
+                                       LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+                                       AutoTunnelSetKeys(old, mDNSfalse);
+                                       }
+                               else
+                                       {
+                                       // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
+                                       // as "tun" and "old" are identical
+                                       LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c,
+                                               &old->rmt_inner);
+                                       needSetKeys = mDNSfalse;
+                                       }
+                               }
+                       else 
+                               {
+                               if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
+                               LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+                               if (old->q.ThisQInterval >= 0)
+                                       {
+                                       LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+                                       mDNS_StopQuery(m, &old->q);
+                                       }
+                               else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
+                                               !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner)   ||
+                                               !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer)   ||
+                                               !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer)   ||
+                                               !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
+                                       {
+                                       // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
+                                       // the other parameters of the tunnel are different
+                                       LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+                                       AutoTunnelSetKeys(old, mDNSfalse);
+                                       }
+                               else
+                                       {
+                                       // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
+                                       // as "tun" and "old" are identical
+                                       LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c,
+                                               &old->rmt_inner);
+                                       needSetKeys = mDNSfalse;
+                                       }
+                               }
+
+                       *p = old->next;
+                       LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old);
+                       freeL("ClientTunnel", old);
+                       }
+               }
+               return needSetKeys;
+       }
+
+// v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
+// tunnel will be deleted
+mDNSlocal void TunnelClientDeleteAny(mDNS *const m, ClientTunnel *tun, mDNSBool v6Tunnel)
+       {
+       ClientTunnel **p;
+
+       p = &tun->next;
+       while (*p)
+               {
+               // If there is more than one client tunnel to the same host, delete all of them.
+               // We do this by just checking against the EUI64 rather than the full address
+               if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
+               else
+                       {
+                       ClientTunnel *old = *p;
+                       if (v6Tunnel)
+                               {
+                               if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
+                               LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+                               }
+                       else 
+                               {
+                               if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
+                               LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+                               }
+                       if (old->q.ThisQInterval >= 0)
+                               {
+                               LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+                               mDNS_StopQuery(m, &old->q);
+                               }
+                       else 
+                               {
+                               LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
+                               AutoTunnelSetKeys(old, mDNSfalse);
                                }
+                       *p = old->next;
+                       LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old);
+                       freeL("ClientTunnel", old);
                        }
                }
        }
 
-mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
+mDNSlocal void TunnelClientFinish(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer)
        {
-       return(mDNSAutoTunnelSetKeys(AddNew ? kmDNSAutoTunnelSetKeysReplace : kmDNSAutoTunnelSetKeysDelete, tun->loc_inner.b, tun->loc_outer.b, kRacoonPort, tun->rmt_inner.b, tun->rmt_outer.b, mDNSVal16(tun->rmt_outer_port), SkipLeadingLabels(&tun->dstname, 1)));
-       }
+       mDNSBool needSetKeys = mDNStrue;
+       ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
+       mDNSBool v6Tunnel = mDNSfalse;
 
-// If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
-#define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
+       // If the port is zero, then we have a relay address of the peer
+       if (mDNSIPPortIsZero(tun->rmt_outer_port))
+               v6Tunnel = mDNStrue;
 
-mDNSlocal void ReissueBlockedQuestionWithType(mDNS *const m, domainname *d, mDNSBool success, mDNSu16 qtype)
-       {
-       DNSQuestion *q = m->Questions;
-       while (q)
+       if (v6Tunnel)
                {
-               if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
-                       {
-                       LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-                       mDNSQuestionCallback *tmp = q->QuestionCallback;
-                       q->QuestionCallback = AutoTunnelCallback;       // Set QuestionCallback to suppress another call back to AddNewClientTunnel
-                       mDNS_StopQuery(m, q);
-                       mDNS_StartQuery(m, q);
-                       q->QuestionCallback = tmp;                                      // Restore QuestionCallback back to the real value
-                       if (!success) q->NoAnswer = NoAnswer_Fail;
-                       // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
-                       // In general we have to assume that the question list might have changed in arbitrary ways.
-                       // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
-                       // already in use. The safest solution is just to go back to the start of the list and start again.
-                       // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
-                       // just one suspended question, so it's really a 2n algorithm.
-                       q = m->Questions;
-                       }
-               else
-                       q = q->next;
+               LogInfo("TunnelClientFinish: Relay address %.16a", &answer->rdata->u.ipv6);
+               tun->rmt_outer6 = answer->rdata->u.ipv6;
+               tun->loc_outer6 = m->AutoTunnelRelayAddr;
+               }
+       else
+               {
+               LogInfo("TunnelClientFinish: SRV target address %.4a", &answer->rdata->u.ipv4);
+               tun->rmt_outer = answer->rdata->u.ipv4;
+               mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
+               tmpDst.ip.v4 = tun->rmt_outer;
+               mDNSAddr tmpSrc = zeroAddr;
+               mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
+               if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
+               else tun->loc_outer = m->AdvertisedV4.ip.v4;
                }
-       }
 
-mDNSlocal void ReissueBlockedQuestions(mDNS *const m, domainname *d, mDNSBool success)
-       {
-       // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
-       //    a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
-       // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
-       //    even if the name does have a valid AAAA record, we don't want clients trying to connect to it without a properly encrypted tunnel.
-       // 3. For A queries we never fabricate failures -- if a BTTM service is really using raw IPv4, then it doesn't need the IPv6 tunnel.
-       ReissueBlockedQuestionWithType(m, d, success, kDNSType_AAAA);
-       ReissueBlockedQuestionWithType(m, d, mDNStrue, kDNSType_A);
-       }
+       question->ThisQInterval = -1;           // So we know this tunnel setup has completed
+       tun->loc_inner = m->AutoTunnelHostAddr;
 
-mDNSlocal void UnlinkAndReissueBlockedQuestions(mDNS *const m, ClientTunnel *tun, mDNSBool success)
-       {
-       ClientTunnel **p = &m->TunnelClients;
-       while (*p != tun && *p) p = &(*p)->next;
-       if (*p) *p = tun->next;
-       ReissueBlockedQuestions(m, &tun->dstname, success);
-       LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
-       freeL("ClientTunnel", tun);
+       // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
+       // look for existing tunnels to see whether they have the same information for our peer.
+       // If not, delete them and need to create a new tunnel. If they are same, just use the
+       // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
+       TunnelClientDeleteAny(m, tun, !v6Tunnel);
+       needSetKeys = TunnelClientDeleteMatching(m, tun, v6Tunnel);
+
+       if (needSetKeys) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
+       else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
+
+       if (m->AutoTunnelHostAddr.b[0]) { mDNS_Lock(m); SetupLocalAutoTunnelInterface_internal(m, mDNSfalse); mDNS_Unlock(m); };
+
+       mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
+       static char msgbuf[32];
+       mDNS_snprintf(msgbuf, sizeof(msgbuf), "Client AutoTunnel setup - %d", result);
+       mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", result ? "failure" : "success", msgbuf, "");
+       mDNSEReporterLog((uuid_t *)&m->asl_uuid, "autotunnel.config", result, msgbuf);
+       // Kick off any questions that were held pending this tunnel setup
+       ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
        }
 
 mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
        ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
+
        LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
 
        if (!AddRecord) return;
        mDNS_StopQuery(m, question);
 
-       if (!answer->rdlength)
+       // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
+       // The code below will look for _autotunnel._udp SRV record followed by A record
+       if (tun->tc_state != TC_STATE_AAAA_PEER_RELAY && !answer->rdlength)
                {
                LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
                static char msgbuf[16];
                mDNS_snprintf(msgbuf, sizeof(msgbuf), "%s lookup", DNSTypeName(question->qtype));
                mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", "failure", msgbuf, "");
+               mDNSEReporterLog((uuid_t *)&m->asl_uuid, "autotunnel.config", 1, msgbuf);
                UnlinkAndReissueBlockedQuestions(m, tun, mDNSfalse);
                return;
                }
 
-       if (question->qtype == kDNSType_AAAA)
-               {
-               if (mDNSSameIPv6Address(answer->rdata->u.ipv6, m->AutoTunnelHostAddr))
-                       {
-                       LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
-                       UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
-                       return;
-                       }
-
-               tun->rmt_inner = answer->rdata->u.ipv6;
-               LogInfo("AutoTunnelCallback: dst host %.16a", &tun->rmt_inner);
-               AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
-               AppendDomainName(&question->qname, &tun->dstname);
-               question->qtype = kDNSType_SRV;
-               mDNS_StartQuery(m, &tun->q);
-               }
-       else if (question->qtype == kDNSType_SRV)
+       switch (tun->tc_state)
                {
-               LogInfo("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
-               AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
-               tun->rmt_outer_port = answer->rdata->u.srv.port;
-               question->qtype = kDNSType_A;
-               mDNS_StartQuery(m, &tun->q);
-               }
-       else if (question->qtype == kDNSType_A)
-               {
-               ClientTunnel *old = mDNSNULL;
-               LogInfo("AutoTunnelCallback: SRV target addr %.4a", &answer->rdata->u.ipv4);
-               question->ThisQInterval = -1;           // So we know this tunnel setup has completed
-               tun->rmt_outer = answer->rdata->u.ipv4;
-               tun->loc_inner = m->AutoTunnelHostAddr;
-               mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
-               tmpDst.ip.v4 = tun->rmt_outer;
-               mDNSAddr tmpSrc = zeroAddr;
-               mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
-               if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
-               else tun->loc_outer = m->AdvertisedV4.ip.v4;
-
-               ClientTunnel **p = &tun->next;
-               mDNSBool needSetKeys = mDNStrue;
-               while (*p)
-                       {
-                       if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
+               case TC_STATE_AAAA_PEER:
+                       if (question->qtype != kDNSType_AAAA)
+                               {
+                               LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question->qtype);
+                               }
+                       if (mDNSSameIPv6Address(answer->rdata->u.ipv6, m->AutoTunnelHostAddr))
+                               {
+                               LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
+                               UnlinkAndReissueBlockedQuestions(m, tun, mDNStrue);
+                               return;
+                               }
+                       tun->rmt_inner = answer->rdata->u.ipv6;
+                       LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun->rmt_inner);
+                       if (!mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr))
+                               {
+                               LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
+                               tun->tc_state = TC_STATE_AAAA_PEER_RELAY;
+                               question->qtype = kDNSType_AAAA;
+                               AssignDomainName(&question->qname, (const domainname*) "\x0C" "_autotunnel6");
+                               }
                        else
                                {
-                               LogInfo("Found existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
-                               old = *p;
-                               *p = old->next;
-                               if (old->q.ThisQInterval >= 0) mDNS_StopQuery(m, &old->q);
-                               else if (!mDNSSameIPv6Address(old->loc_inner, tun->loc_inner) ||
-                                                !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer) ||
-                                                !mDNSSameIPv6Address(old->rmt_inner, tun->rmt_inner) ||
-                                                !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer) ||
-                                                !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
-                                       {
-                                       LogInfo("Deleting existing AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
-                                       AutoTunnelSetKeys(old, mDNSfalse);
-                                       }
-                               else needSetKeys = mDNSfalse;
-
-                               LogInfo("AutoTunnelCallback: Disposing ClientTunnel %p", tun);
-                               freeL("ClientTunnel", old);
+                               LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
+                               tun->tc_state = TC_STATE_SRV_PEER;
+                               question->qtype = kDNSType_SRV;
+                               AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
                                }
-                       }
-
-               if (needSetKeys) LogInfo("New AutoTunnel for %##s %.16a", tun->dstname.c, &tun->rmt_inner);
-
-               if (m->AutoTunnelHostAddr.b[0]) { mDNS_Lock(m); SetupLocalAutoTunnelInterface_internal(m); mDNS_Unlock(m); };
-
-               mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
-               static char msgbuf[32];
-               mDNS_snprintf(msgbuf, sizeof(msgbuf), "Tunnel setup - %d", result);
-               mDNSASLLog((uuid_t *)&m->asl_uuid, "autotunnel.config", result ? "failure" : "success", msgbuf, "");
-               // Kick off any questions that were held pending this tunnel setup
-               ReissueBlockedQuestions(m, &tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
+                       AppendDomainName(&question->qname, &tun->dstname);
+                       mDNS_StartQuery(m, &tun->q);
+                       return;
+               case TC_STATE_AAAA_PEER_RELAY:
+                       if (question->qtype != kDNSType_AAAA)
+                               {
+                               LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question->qtype);
+                               }
+                       // If it failed, look for the SRV record.
+                       if (!answer->rdlength)
+                               {
+                               LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
+                               tun->tc_state = TC_STATE_SRV_PEER;
+                               AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
+                               AppendDomainName(&question->qname, &tun->dstname);
+                               question->qtype = kDNSType_SRV;
+                               mDNS_StartQuery(m, &tun->q);
+                               return;
+                               }
+                       TunnelClientFinish(m, question, answer);
+                       return;
+               case TC_STATE_SRV_PEER:
+                       if (question->qtype != kDNSType_SRV)
+                               {
+                               LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question->qtype);
+                               }
+                       LogInfo("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
+                       tun->tc_state = TC_STATE_ADDR_PEER;
+                       AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
+                       tun->rmt_outer_port = answer->rdata->u.srv.port;
+                       question->qtype = kDNSType_A;
+                       mDNS_StartQuery(m, &tun->q);
+                       return;
+               case TC_STATE_ADDR_PEER:
+                       if (question->qtype != kDNSType_A)
+                               {
+                               LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question->qtype);
+                               }
+                       TunnelClientFinish(m, question, answer);
+                       return;
+               default:
+                       LogMsg("AutoTunnelCallback: Unknown question %p", question);
                }
-       else
-               LogMsg("AutoTunnelCallback: Unknown question %p", question);
        }
 
 // Must be called with the lock held
@@ -3948,9 +5057,12 @@ mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
        p->MarkedForDeletion = mDNSfalse;
        p->loc_inner      = zerov6Addr;
        p->loc_outer      = zerov4Addr;
+       p->loc_outer6     = zerov6Addr;
        p->rmt_inner      = zerov6Addr;
        p->rmt_outer      = zerov4Addr;
+       p->rmt_outer6     = zerov6Addr;
        p->rmt_outer_port = zeroIPPort;
+       p->tc_state = TC_STATE_AAAA_PEER;
        p->next = m->TunnelClients;
        m->TunnelClients = p;           // We intentionally build list in reverse order
 
@@ -3963,6 +5075,7 @@ mDNSexport void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q)
        p->q.ExpectUnique     = mDNStrue;
        p->q.ForceMCast       = mDNSfalse;
        p->q.ReturnIntermed   = mDNStrue;
+       p->q.SuppressUnusable = mDNSfalse;
        p->q.QuestionCallback = AutoTunnelCallback;
        p->q.QuestionContext  = p;
 
@@ -4193,8 +5306,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNS *const m, mDNSs32 utc)
                {
                DomainAuthInfo *info;
                for (info = m->AuthInfoList; info; info = info->next)
-                       if (info->AutoTunnelNAT.clientContext && !mDNSIPv4AddressIsOnes(info->AutoTunnelNAT.ExternalAddress))
-                               AutoTunnelNATCallback(m, &info->AutoTunnelNAT);
+                               if (info->AutoTunnel) AutoTunnelHostNameChanged(m, info);
                }
 #endif // APPLE_OSX_mDNSResponder
 
@@ -4420,6 +5532,165 @@ mDNSlocal int compare_dns_configs(const void *aa, const void *bb)
        return (a->search_order < b->search_order) ? -1 : (a->search_order == b->search_order) ? 0 : 1;
        }
 
+mDNSlocal void ConfigResolvers(mDNS *const m, dns_config_t *config, mDNSBool scope, mDNSBool setsearch, mDNSBool setservers)
+       {
+       int i;
+       domainname d;
+#if DNSINFO_VERSION >= 20091104
+       dns_resolver_t **resolver = scope ? config->scoped_resolver : config->resolver;
+       int nresolvers = scope ? config->n_scoped_resolver : config->n_resolver;
+#else
+       (void) scope; // unused
+       dns_resolver_t **resolver = config->resolver;
+       int nresolvers = config->n_resolver;
+#endif
+
+       // Currently we don't support search lists for scoped resolvers. The WAB support for this will be added later.
+       if (setsearch && !scope && nresolvers)
+               {
+               // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
+               // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
+               // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
+               // instead use the search domain list as the sole authority for what domains to search and in what order
+               // (and the domain from the "domain" field will also appear somewhere in that list).
+               // Also, all search domains get added to the search list for resolver[0], so the domains and/or
+               // search lists for other resolvers in the list need to be ignored.
+               //
+               // Note: Starting DNSINFO_VERSION 20091104, search list is present only in the first resolver (resolver 0).
+               // i.e., n_search for the first resolver is always non-zero. We don't guard it with #ifs for better readability
+
+               if (resolver[0]->n_search == 0)
+                       {
+                       LogInfo("ConfigResolvers: (%s) configuring zeroth domain as search list %s", scope ? "Scoped" : "Non-scoped", resolver[0]->domain);
+                       mDNS_AddSearchDomain_CString(resolver[0]->domain);
+                       }
+               else
+                       {
+                       for (i = 0; i < resolver[0]->n_search; i++)
+                               {
+                               LogInfo("ConfigResolvers: (%s) configuring search list %s", scope ? "Scoped" : "Non-scoped", resolver[0]->search[i]);
+                               mDNS_AddSearchDomain_CString(resolver[0]->search[i]);
+                               }
+                       }
+               }
+
+       if (!setservers) return;
+
+       // For the "default" resolver ("resolver #1") the "domain" value is bogus and we need to ignore it.
+       // e.g. the default resolver's "domain" value might say "apple.com", which indicates that this resolver
+       // is only for names that fall under "apple.com", but that's not correct. Actually the default resolver is
+       // for all names not covered by a more specific resolver (i.e. its domain should be ".", the root domain).
+       //
+       // Note: Starting DNSINFO_VERSION 20091104, domain value of this first resolver (resolver 0) is always NULL.
+       // We don't guard it with #ifs for better readability
+       // 
+       if ((nresolvers != 0) && resolver[0]->domain)
+               resolver[0]->domain[0] = 0; // don't stop pointing at the memory, just change the first byte
+
+       qsort(resolver, nresolvers, sizeof(dns_resolver_t*), compare_dns_configs);
+                               
+       for (i = 0; i < nresolvers; i++)
+               {       
+               int n;
+               dns_resolver_t *r = resolver[i];
+               mDNSInterfaceID interface = mDNSInterface_Any;
+               int disabled = 0;
+                                       
+               LogInfo("ConfigResolvers: %s resolver[%d] domain %s n_nameserver %d", scope ? "Scoped" : "", i, r->domain, r->n_nameserver);
+
+               // On Tiger, dnsinfo entries for mDNS domains have port 5353, the mDNS port.  Ignore them.
+               // Note: Unlike the BSD Sockets APIs (where TCP and UDP port numbers are universally in network byte order)
+               // in Apple's "dnsinfo.h" API the port number is declared to be a "uint16_t in host byte order"
+               // We also don't need to do any more work if there are no nameserver addresses
+               if (r->port == 5353 || r->n_nameserver == 0) continue;
+                                       
+               if (!r->domain || !*r->domain) d.c[0] = 0;
+               else if (!MakeDomainNameFromDNSNameString(&d, r->domain))
+                       { LogMsg("ConfigResolvers: config->resolver[%d] bad domain %s", i, r->domain); continue; }
+
+               // DNS server option parsing
+               if (r->options != NULL)
+                       {
+                       char *nextOption = r->options;
+                       char *currentOption = NULL;
+                       while ((currentOption = strsep(&nextOption, " ")) != NULL && currentOption[0] != 0)
+                               {
+                               // The option may be in the form of interface=xxx where xxx is an interface name.
+                               if (strncmp(currentOption, kInterfaceSpecificOption, sizeof(kInterfaceSpecificOption) - 1) == 0)
+                                       {
+                                       NetworkInterfaceInfoOSX *ni;
+                                       char    ifname[IF_NAMESIZE+1];
+                                       mDNSu32 ifindex = 0;
+                                       // If something goes wrong finding the interface, create the server entry anyhow but mark it as disabled.
+                                       // This allows us to block these special queries from going out on the wire.
+                                       strlcpy(ifname, currentOption + sizeof(kInterfaceSpecificOption)-1, sizeof(ifname));
+                                       ifindex = if_nametoindex(ifname);
+                                       if (ifindex == 0) { disabled = 1; LogMsg("ConfigResolvers: RegisterSplitDNS interface specific - interface %s not found", ifname); continue; }
+                                       LogInfo("ConfigResolvers: interface specific entry: %s on %s (%d)", r->domain, ifname, ifindex);
+                                       // Find the interface. Can't use mDNSPlatformInterfaceIDFromInterfaceIndex
+                                       // because that will call mDNSMacOSXNetworkChanged if the interface doesn't exist
+                                       for (ni = m->p->InterfaceList; ni; ni = ni->next)
+                                               if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex) break;
+                                       if (ni != NULL) interface = ni->ifinfo.InterfaceID;
+                                       if (interface == mDNSNULL)
+                                               {
+                                               disabled = 1;
+                                               LogMsg("ConfigResolvers: RegisterSplitDNS interface specific - index %d (%s) not found", ifindex, ifname);
+                                               continue;
+                                               }
+                                       }
+                               }
+                       }
+
+               // flags and if_index are defined only from this DNSINFO_VERSION onwards. Currently these
+               // fields are zero for non-scoped resolvers. For now, these fields have non-zero values only
+               // for scoped_resolvers.
+#if DNSINFO_VERSION >= 20091104
+               if (scope && (r->flags & DNS_RESOLVER_FLAGS_SCOPED) && (r->if_index != 0))
+                       {
+                       NetworkInterfaceInfoOSX *ni;
+                       interface = mDNSNULL;
+                       for (ni = m->p->InterfaceList; ni; ni = ni->next)
+                               if (ni->ifinfo.InterfaceID && ni->scope_id == r->if_index) break;
+                       if (ni != NULL) interface = ni->ifinfo.InterfaceID;
+                       if (interface == mDNSNULL)
+                               {
+                               disabled = 1;
+                               LogMsg("ConfigResolvers: interface specific index %d not found", r->if_index);
+                               continue;
+                               }
+                       }
+#endif
+
+               for (n = 0; n < r->n_nameserver; n++)
+                       if (r->nameserver[n]->sa_family == AF_INET || r->nameserver[n]->sa_family == AF_INET6)
+                               {
+                               mDNSAddr saddr;
+                               // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
+                               if (SetupAddr(&saddr, r->nameserver[n])) LogMsg("RegisterSplitDNS: bad IP address");
+                               else
+                                       {
+                                       mDNSBool scopedDNS = mDNSfalse;
+                                       DNSServer *s;
+#if DNSINFO_VERSION >= 20091104
+                                       // By setting scoped, this DNSServer can only be picked if the right interfaceID
+                                       // is given in the question
+                                       if (scope && (r->flags & DNS_RESOLVER_FLAGS_SCOPED) && (interface == mDNSNULL))
+                                               LogMsg("ConfigResolvers: ERROR: scoped is set but if_index %d is invalid for DNSServer %#a:%d", r->if_index, &saddr, mDNSVal16(r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort));
+                                       else
+                                               scopedDNS = (scope && (r->flags & DNS_RESOLVER_FLAGS_SCOPED)) ? mDNStrue : mDNSfalse;
+#endif
+                                       s = mDNS_AddDNSServer(m, &d, interface, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort, scopedDNS);
+                                       if (s)
+                                               {
+                                               if (disabled) s->teststate = DNSServer_Disabled;
+                                               LogInfo("ConfigResolvers: DNS server %#a:%d for domain %##s from slot %d,%d", &s->addr, mDNSVal16(s->port), d.c, i, n);
+                                               }
+                                       }
+                               }
+               }
+       }
+
 mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains)
        {
        int i;
@@ -4494,18 +5765,6 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN
                else
                        {
                        LogInfo("mDNSPlatformSetDNSConfig: config->n_resolver = %d", config->n_resolver);
-                       if (setsearch && config->n_resolver)
-                               {
-                               // Due to the vagaries of Apple's SystemConfiguration and dnsinfo.h APIs, if there are no search domains
-                               // listed, then you're supposed to interpret the "domain" field as also being the search domain, but if
-                               // there *are* search domains listed, then you're supposed to ignore the "domain" field completely and
-                               // instead use the search domain list as the sole authority for what domains to search and in what order
-                               // (and the domain from the "domain" field will also appear somewhere in that list).
-                               // Also, all search domains get added to the search list for resolver[0], so the domains and/or
-                               // search lists for other resolvers in the list need to be ignored.
-                               if (config->resolver[0]->n_search == 0) mDNS_AddSearchDomain_CString(config->resolver[0]->domain);
-                               else for (i = 0; i < config->resolver[0]->n_search; i++) mDNS_AddSearchDomain_CString(config->resolver[0]->search[i]);
-                               }
 
 #if APPLE_OSX_mDNSResponder
                                // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
@@ -4525,82 +5784,10 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN
                                        }
 #endif
 
-                       if (setservers)
-                               {
-                               // For the "default" resolver ("resolver #1") the "domain" value is bogus and we need to ignore it.
-                               // e.g. the default resolver's "domain" value might say "apple.com", which indicates that this resolver
-                               // is only for names that fall under "apple.com", but that's not correct. Actually the default resolver is
-                               // for all names not covered by a more specific resolver (i.e. its domain should be ".", the root domain).
-                               if (config->n_resolver && config->resolver[0]->domain)
-                                       config->resolver[0]->domain[0] = 0; // don't stop pointing at the memory, just change the first byte
-                               
-                               qsort(config->resolver, config->n_resolver, sizeof(dns_resolver_t*), compare_dns_configs);
-                               
-                               for (i = 0; i < config->n_resolver; i++)
-                                       {
-                                       int n;
-                                       dns_resolver_t *r = config->resolver[i];
-                                       mDNSInterfaceID interface = mDNSInterface_Any;
-                                       int disabled = 0;
-                                       
-                                       // On Tiger, dnsinfo entries for mDNS domains have port 5353, the mDNS port.  Ignore them.
-                                       // Note: Unlike the BSD Sockets APIs (where TCP and UDP port numbers are universally in network byte order)
-                                       // in Apple's "dnsinfo.h" API the port number is declared to be a "uint16_t in host byte order"
-                                       // We also don't need to do any more work if there are no nameserver addresses
-                                       if (r->port == 5353 || r->n_nameserver == 0) continue;
-                                       
-                                       if (!r->domain || !*r->domain) d.c[0] = 0;
-                                       else if (!MakeDomainNameFromDNSNameString(&d, r->domain)) { LogMsg("mDNSPlatformSetDNSConfig: bad domain %s", r->domain); continue; }
-
-                                       // DNS server option parsing
-                                       if (r->options != NULL)
-                                               {
-                                               char *nextOption = r->options;
-                                               char *currentOption = NULL;
-                                               while ((currentOption = strsep(&nextOption, " ")) != NULL && currentOption[0] != 0)
-                                                       {
-                                                       // The option may be in the form of interface=xxx where xxx is an interface name.
-                                                       if (strncmp(currentOption, kInterfaceSpecificOption, sizeof(kInterfaceSpecificOption) - 1) == 0)
-                                                               {
-                                                               NetworkInterfaceInfoOSX *ni;
-                                                               char    ifname[IF_NAMESIZE+1];
-                                                               mDNSu32 ifindex = 0;
-                                                               // If something goes wrong finding the interface, create the server entry anyhow but mark it as disabled.
-                                                               // This allows us to block these special queries from going out on the wire.
-                                                               strlcpy(ifname, currentOption + sizeof(kInterfaceSpecificOption)-1, sizeof(ifname));
-                                                               ifindex = if_nametoindex(ifname);
-                                                               if (ifindex == 0) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - interface %s not found", ifname); continue; }
-                                                               LogInfo("%s: Interface-specific entry: %s on %s (%d)", __FUNCTION__, r->domain, ifname, ifindex);
-                                                               // Find the interface, can't use mDNSPlatformInterfaceIDFromInterfaceIndex
-                                                               // because that will call mDNSMacOSXNetworkChanged if the interface doesn't exist
-                                                               for (ni = m->p->InterfaceList; ni; ni = ni->next)
-                                                                       if (ni->ifinfo.InterfaceID && ni->scope_id == ifindex) break;
-                                                               if (ni != NULL) interface = ni->ifinfo.InterfaceID;
-                                                               if (interface == mDNSNULL) { disabled = 1; LogMsg("RegisterSplitDNS: interfaceSpecific - index %d (%s) not found", ifindex, ifname); continue; }
-                                                               }
-                                                       }
-                                               }
-
-                                       for (n = 0; n < r->n_nameserver; n++)
-                                               if (r->nameserver[n]->sa_family == AF_INET || r->nameserver[n]->sa_family == AF_INET6)
-                                                       {
-                                                       mDNSAddr saddr;
-                                                       // mDNSAddr saddr = { mDNSAddrType_IPv4, { { { 192, 168, 1, 1 } } } }; // for testing
-                                                       if (SetupAddr(&saddr, r->nameserver[n])) LogMsg("RegisterSplitDNS: bad IP address");
-                                                       else
-                                                               {
-                                                               DNSServer *s = mDNS_AddDNSServer(m, &d, interface, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort);
-                                                               if (s)
-                                                                       {
-                                                                       if (disabled) s->teststate = DNSServer_Disabled;
-                                                                       LogInfo("Added dns server %#a:%d for domain %##s from slot %d,%d", &s->addr, mDNSVal16(s->port), d.c, i, n);
-                                                                       }
-                                                               }
-                                                       }
-                                               
-                                       }
-                               }
-
+                       ConfigResolvers(m, config, mDNSfalse, setsearch, setservers);
+#if DNSINFO_VERSION >= 20091104
+                       ConfigResolvers(m, config, mDNStrue, setsearch, setservers);
+#endif
                        dns_configuration_free(config);
                        setservers = mDNSfalse;  // Done these now -- no need to fetch the same data from SCDynamicStore
                        setsearch  = mDNSfalse;
@@ -4730,7 +5917,7 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN
                                        CFArrayRef values = CFDictionaryGetValue(dict, kSCPropNetDNSServerAddresses);
                                        if (values)
                                                {
-                                               LogInfo("DNS Server Address values: %d", CFArrayGetCount(values));
+                                               LogInfo("DNS Server Address values: %d", (int)CFArrayGetCount(values));
                                                for (i = 0; i < CFArrayGetCount(values); i++)
                                                        {
                                                        CFStringRef s = CFArrayGetValueAtIndex(values, i);
@@ -4739,7 +5926,7 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN
                                                                inet_aton(buf, (struct in_addr *) &addr.ip.v4))
                                                                {
                                                                LogInfo("Adding DNS server from dict: %s", buf);
-                                                               mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort);
+                                                               mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, &addr, UnicastDNSPort, mDNSfalse);
                                                                }
                                                        }
                                                }
@@ -4780,7 +5967,6 @@ mDNSexport void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDN
 mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *r)
        {
        char                            buf[256];
-       mStatus                         err             = 0;
        (void)m; // Unused
 
        SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:mDNSPlatformGetPrimaryInterface"), NULL, NULL);
@@ -4858,7 +6044,7 @@ mDNSexport mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4,
                        }
                CFRelease(store);
                }
-       return err;
+       return mStatus_NoError;
        }
 
 mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
@@ -4883,37 +6069,188 @@ mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const
        // The CFDictionary for each FQDN holds (at present) a single name/value pair,
        // where the name is "Status" and the value is a CFNumber giving an errror code (with zero meaning success).
 
-       const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
-       const CFStringRef HostKeys  [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
-       const CFStringRef StatusKeys[1] = { CFSTR("Status") };
-       if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
+       const CFStringRef StateKeys [1] = { CFSTR("HostNames") };
+       const CFStringRef HostKeys  [1] = { CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8) };
+       const CFStringRef StatusKeys[1] = { CFSTR("Status") };
+       if (!HostKeys[0]) LogMsg("SetDDNSNameStatus: CFStringCreateWithCString(%s) failed", uname);
+       else
+               {
+               const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
+               if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
+               else
+                       {
+                       const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
+                       if (HostVals[0])
+                               {
+                               const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
+                               if (StateVals[0])
+                                       {
+                                       CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+                                       if (StateDict)
+                                               {
+                                               mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict);
+                                               CFRelease(StateDict);
+                                               }
+                                       CFRelease(StateVals[0]);
+                                       }
+                               CFRelease(HostVals[0]);
+                               }
+                       CFRelease(StatusVals[0]);
+                       }
+               CFRelease(HostKeys[0]);
+               }
+       }
+
+#if APPLE_OSX_mDNSResponder
+#if ! NO_AWACS
+
+// checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
+// keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
+// help catch it
+mDNSlocal mDNSBool IsBTMMDomain(domainname *d)
+       {
+       SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:IsBTMMDomain"), NULL, NULL);
+       if (!store)
+               {
+               LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
+               return mDNSfalse;
+               }
+       CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
+       if (btmm)
+               {
+               CFIndex size = CFDictionaryGetCount(btmm);
+               char buf[MAX_ESCAPED_DOMAIN_NAME];      // Max legal C-string name, including terminating NUL
+               const void *key[size];
+               const void *val[size];
+               domainname dom;
+               int i;
+               CFDictionaryGetKeysAndValues(btmm, key, val);
+               for (i = 0; i < size; i++)
+                       {
+                       LogInfo("BackToMyMac %d", i);
+                       if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
+                               LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i, buf);
+                       else
+                               {
+                               mDNSu32 uid = atoi(buf);
+                               if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
+                                       LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i, buf);
+                               else if (MakeDomainNameFromDNSNameString(&dom, buf) && dom.c[0])
+                                       {
+                                       if (SameDomainName(&dom, d))
+                                               {
+                                               LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d->c, uid);
+                                               CFRelease(btmm);
+                                               CFRelease(store);
+                                               return mDNStrue;
+                                               }
+                                       }
+                               }
+                       }
+               CFRelease(btmm);
+               }
+       CFRelease(store);
+       LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d->c);
+       return mDNSfalse;
+       }
+
+// Appends data to the buffer
+mDNSlocal int AddOneItem(char *buf, int bufsz, char *data, int *currlen)
+       {
+       int len;
+
+       len = strlcpy(buf + *currlen, data, bufsz - *currlen);
+       if (len >= (bufsz - *currlen))
+               {
+               // if we have exceeded the space in buf, it has already been NULL terminated
+               // and we have nothing more to do. Set currlen to the last byte so that the caller
+               // knows to do the right thing
+               LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen, len);
+               *currlen = bufsz - 1;
+               return -1;
+               }
+       else { (*currlen) += len; }
+
+       buf[*currlen] = ',';
+       if (*currlen >= bufsz)
+               {
+               LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen);
+               *currlen = bufsz - 1;
+               buf[*currlen] = 0;
+               return -1;
+               }
+       // if we have filled up the buffer exactly, then there is no more work to do
+       if (*currlen == bufsz - 1) { buf[*currlen] = 0; return -1; }
+       (*currlen)++;
+       return *currlen;
+       }
+
+// If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
+// BTMM domains, then bring down the connection to the relay.
+mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
+       {
+       DomainAuthInfo *BTMMDomain = mDNSNULL;
+       DomainAuthInfo *FoundInList;
+       static mDNSBool AWACSDConnected = mDNSfalse;
+       char AllUsers[1024];    // maximum size of mach message
+       char AllPass[1024];     // maximum size of mach message
+       char username[MAX_DOMAIN_LABEL + 1];
+       int currulen = 0;
+       int currplen = 0;
+
+       // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
+       // we may not be able to send the dns queries over the relay connection which may be needed
+       // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
+       // need to make sure that we send the disconnect before attempting the next connect as the
+       // awacs connections are redirected based on usernames.
+       //
+       // For now we send a disconnect immediately. When we start sending dns queries over the relay
+       // connection, we will need to fix this.
+
+       for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
+               if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain))
+                       {
+                       // We need the passwd from the first domain.
+                       BTMMDomain = FoundInList;
+                       ConvertDomainLabelToCString_unescaped((domainlabel *)BTMMDomain->domain.c, username);
+                       LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username, BTMMDomain->domain.c);
+                       if (AddOneItem(AllUsers, sizeof(AllUsers), username, &currulen) == -1) break;
+                       if (AddOneItem(AllPass, sizeof(AllPass), BTMMDomain->b64keydata, &currplen) == -1) break;
+                       }
+
+       if (BTMMDomain) 
+               {
+               // In the normal case (where we neither exceed the buffer size nor write bytes that
+               // fit exactly into the buffer), currulen/currplen should be a different size than
+               // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
+
+               if (currulen != (int)(sizeof(AllUsers) - 1)) AllUsers[currulen - 1] = 0;
+               if (currplen != (int)(sizeof(AllPass) - 1)) AllPass[currplen - 1] = 0;
+
+               LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers);
+               AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com");
+               AWACSDConnected = mDNStrue;
+               }
        else
                {
-               const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
-               if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
-               else
+               // Disconnect only if we connected previously
+               if (AWACSDConnected)
                        {
-                       const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
-                       if (HostVals[0])
-                               {
-                               const CFDictionaryRef StateVals[1] = { CFDictionaryCreate(NULL, (void*)HostKeys, (void*)HostVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
-                               if (StateVals[0])
-                                       {
-                                       CFDictionaryRef StateDict = CFDictionaryCreate(NULL, (void*)StateKeys, (void*)StateVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-                                       if (StateDict)
-                                               {
-                                               mDNSDynamicStoreSetConfig(kmDNSDynamicConfig, mDNSNULL, StateDict);
-                                               CFRelease(StateDict);
-                                               }
-                                       CFRelease(StateVals[0]);
-                                       }
-                               CFRelease(HostVals[0]);
-                               }
-                       CFRelease(StatusVals[0]);
+                       LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
+                       AWACS_Disconnect();
+                       AWACSDConnected = mDNSfalse;
                        }
-               CFRelease(HostKeys[0]);
+               else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
                }
        }
+#else
+mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
+       {
+       (void) m; // Unused
+       LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
+       }
+#endif // ! NO_AWACS
+#endif // APPLE_OSX_mDNSResponder
 
 // MUST be called holding the lock -- this routine calls SetupLocalAutoTunnelInterface_internal()
 mDNSexport void SetDomainSecrets(mDNS *m)
@@ -5083,13 +6420,14 @@ mDNSexport void SetDomainSecrets(mDNS *m)
                                        mDNS_StopNATOperation_internal(m, &info->AutoTunnelNAT);
                                        if (info->AutoTunnelNAT.clientCallback)
                                                {
-                                               // Reset port and let the AutoTunnelNATCallback handle cleanup
+                                               // Reset port and cleanup the state
                                                info->AutoTunnelNAT.ExternalAddress = m->ExternalAddress;
                                                info->AutoTunnelNAT.ExternalPort    = zeroIPPort;
+                                               info->AutoTunnelNAT.RequestedPort    = zeroIPPort;
                                                info->AutoTunnelNAT.Lifetime        = 0;
                                                info->AutoTunnelNAT.Result          = mStatus_NoError;
                                                mDNS_DropLockBeforeCallback(); // Allow client to legally make mDNS API calls from the callback
-                                               info->AutoTunnelNAT.clientCallback(m, &info->AutoTunnelNAT);
+                                               AutoTunnelDeleteAuthInfoState(m, info);
                                                mDNS_ReclaimLockAfterCallback(); // Decrement mDNS_reentrancy to block mDNS API calls again
                                                }
                                        info->AutoTunnelNAT.clientContext = mDNSNULL;
@@ -5107,15 +6445,18 @@ mDNSexport void SetDomainSecrets(mDNS *m)
                        (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b);
                        mDNSPlatformMemZero(m->AutoTunnelHostAddr.b, sizeof(m->AutoTunnelHostAddr.b));
                        }
-
-               UpdateConfigureServer(m);
                
                if (m->AutoTunnelHostAddr.b[0])
                        if (TunnelClients(m) || TunnelServers(m))
-                               SetupLocalAutoTunnelInterface_internal(m);
+                               SetupLocalAutoTunnelInterface_internal(m, mDNSfalse);
+
+               UpdateAnonymousRacoonConfig(m);         // Determine whether we need racoon to accept incoming connections
+               UpdateBTMMRelayConnection(m);
                }
 #endif // APPLE_OSX_mDNSResponder
 
+       CheckSuppressUnusableQuestions(m);
+
 #endif /* NO_SECURITYFRAMEWORK */
        }
 
@@ -5175,7 +6516,7 @@ end:
        if (!store) LogMsg("GetCurrentPMSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
        else
                {
-               CFDictionaryRef dict = SCDynamicStoreCopyValue(store, CFSTR("State:/IOKit/PowerManagement/CurrentSettings"));
+               CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
                if (!dict) LogSPS("GetCurrentPMSetting: Could not get IOPM CurrentSettings dict");
                else
                        {
@@ -5261,10 +6602,13 @@ mDNSlocal CFComparisonResult CompareSPSEntries(const void *val1, const void *val
 
 mDNSlocal void UpdateSPSStatus(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
        {
-       (void)m;
        NetworkInterfaceInfo* info = (NetworkInterfaceInfo*)question->QuestionContext;
        debugf("UpdateSPSStatus: %s %##s %s %s", info->ifname, question->qname.c, AddRecord ? "Add" : "Rmv", answer ? RRDisplayString(m, answer) : "<null>");
 
+       mDNS_Lock(m);
+       mDNS_UpdateAllowSleep(m);
+       mDNS_Unlock(m);
+
        if (answer && SPSMetric(answer->rdata->u.name.c) > 999999) return;      // Ignore instances with invalid names
 
        if (!spsStatusDict)
@@ -5330,7 +6674,7 @@ mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void)
                LogMsg("GetSystemSleepTimerSetting: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
        else
                {
-               CFDictionaryRef dict = SCDynamicStoreCopyValue(store, CFSTR("State:/IOKit/PowerManagement/CurrentSettings"));
+               CFDictionaryRef dict = SCDynamicStoreCopyValue(store, NetworkChangedKey_PowerSettings);
                if (dict)
                        {
                        CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
@@ -5392,8 +6736,13 @@ mDNSlocal mStatus WatchForInternetSharingChanges(mDNS *const m)
        if (!SCPreferencesSetCallback(SCPrefs, InternetSharingChanged, &context))
                { LogMsg("SCPreferencesSetCallback failed: %s", SCErrorString(SCError())); CFRelease(SCPrefs); return(mStatus_NoMemoryErr); }
 
+#ifdef __LIB_DISPATCH__
+       if (!SCPreferencesSetDispatchQueue( SCPrefs, dispatch_get_main_queue()))
+               { LogMsg("SCPreferencesSetDispatchQueue failed: %s", SCErrorString(SCError())); return(mStatus_NoMemoryErr); }
+#else
        if (!SCPreferencesScheduleWithRunLoop(SCPrefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
                { LogMsg("SCPreferencesScheduleWithRunLoop failed: %s", SCErrorString(SCError())); CFRelease(SCPrefs); return(mStatus_NoMemoryErr); }
+#endif
 
        m->p->SCPrefs = SCPrefs;
        return(mStatus_NoError);
@@ -5443,7 +6792,7 @@ mDNSlocal mDNSu16 GetPortArray(mDNS *const m, int trans, mDNSIPPort *portarray)
                        }
 
        // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
-       if (trans == mDNSTransport_UDP && TunnelServers(m))     
+       if (trans == mDNSTransport_UDP && TunnelServers(m))
                {
                LogSPS("GetPortArray Back to My Mac at %d", count);
                if (portarray) portarray[count] = IPSECPort;
@@ -5521,7 +6870,7 @@ IOConnectCallStructMethod(
        }
 #endif
 
-mDNSexport mStatus ActivateLocalProxy(mDNS *const m, char *ifname)
+mDNSexport mStatus ActivateLocalProxy(mDNS *const m, char *ifname)     // Called with the lock held
        {
        mStatus result = mStatus_UnknownErr;
        io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, ifname));
@@ -5612,6 +6961,8 @@ mDNSlocal mDNSBool SystemWakeForNetworkAccess(void)
        CFBooleanRef clamshellStop = NULL;
        mDNSBool retnow = mDNSfalse;
 
+       if (DisableSleepProxyClient) { LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option"); return mDNSfalse; }
+
        GetCurrentPMSetting(CFSTR("Wake On LAN"), &val);
        LogSPS("SystemWakeForNetworkAccess: Wake On LAN: %d", val);
        if (!val) return mDNSfalse;
@@ -5627,14 +6978,271 @@ mDNSlocal mDNSBool SystemWakeForNetworkAccess(void)
        
        clamshellStop = (CFBooleanRef)IORegistryEntryCreateCFProperty(g_rootdomain, CFSTR(kAppleClamshellCausesSleepKey), kCFAllocatorDefault, 0);
        if (!clamshellStop) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellCausesSleepKey does not exist; assuming no clamshell so can WOMP"); return mDNStrue; }
-       retnow = clamshellStop == kCFBooleanFalse;
-       CFRelease(clamshellStop);       
+       retnow = (clamshellStop == kCFBooleanFalse);
+       CFRelease(clamshellStop);
        if (retnow) { LogSPS("SystemWakeForNetworkAccess: kAppleClamshellCausesSleepKey is false; clamshell is closed but can WOMP"); return mDNStrue; }
        
        LogSPS("SystemWakeForNetworkAccess: clamshell is closed and can't WOMP");
        return mDNSfalse;
        }
 
+mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void)
+       {
+       mDNSs32 val = 0;
+       GetCurrentPMSetting(CFSTR("Idle Sleep Requires Network Proxy"), &val);
+       return val != 0 ? mDNStrue : mDNSfalse;
+       }
+
+#if APPLE_OSX_mDNSResponder
+// If the _autotunnel6 record is still there in the list, we are waiting for the ack from
+// the server.
+//
+// If we are behind a double-NAT or NAT with no NAT-PMP support, we should make sure that all our
+// BTMM records are deregistered so that it does not appear on the Finder sidebar of our peers
+// when we go to sleep. First _autotunnel6 and the host record gets deregistered, then SRV
+// (UpdateAllSrvRecords) and then PTR and TXT
+//
+// Note: We wait up to a maximum of 10 seconds before we ack the sleep. So, returning "false"
+// here does not necessarily mean that it will be honored.
+mDNSexport mDNSBool RecordReadyForSleep(mDNS *const m, AuthRecord *rr)
+       {
+       if (!AuthRecord_uDNS(rr)) return mDNStrue;
+
+       if (SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0c_autotunnel6"))
+               {
+               LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
+               return mDNSfalse;
+               }
+       // Just check for the SRV record alone as the PTR and TXT records are dependent on SRV
+       // and will get deregistered together in a single update. We also don't check for TXT
+       // records  as _kerberos TXT record is always there even when there are no services
+       // and we don't want to delay the sleep in that case.
+       if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort) || m->LLQNAT.Result)
+               {
+               if ((rr->resrec.rrtype == kDNSType_SRV) && rr->state != regState_NoTarget && rr->zone)
+                       {
+                       DomainAuthInfo *info = GetAuthInfoForName_internal(m, rr->zone);
+                       if (info && info->AutoTunnel)
+                               {       
+                               LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
+                               return mDNSfalse;
+                               }
+                       }
+               }
+       return mDNStrue;
+       }
+
+// Note: BTMMDict needs to be retained by the caller if needed
+mDNSlocal CFDictionaryRef ParseBackToMyMacKey(CFDictionaryRef connd)
+       {
+       CFDictionaryRef BTMMDict = CFDictionaryGetValue(connd, CFSTR("BackToMyMac"));
+       if (!BTMMDict)
+               {
+               LogInfo("ParseBackToMyMacKey: CFDictionaryGetValue No value for BackToMyMac");
+               return NULL;
+               }
+
+       // Non-dictionary is treated as non-existent dictionary
+       if (CFGetTypeID(BTMMDict) != CFDictionaryGetTypeID())
+               {LogMsg("ERROR: ParseBackToMyMacKey: CFDictionaryGetValue BackToMyMac not a dictionary"); CFRelease(BTMMDict); return NULL;}
+
+       return BTMMDict;
+       }
+
+mDNSlocal void ParseBTMMInterfaceKey(CFDictionaryRef BTMMDict, char *buf, int buflen)
+       {
+       CFTypeRef string;
+       mDNSBool ifExists;
+
+       ifExists = CFDictionaryGetValueIfPresent(BTMMDict, CFSTR("Interface"), &string);
+       if (ifExists)
+               {
+               if (!CFStringGetCString(string, buf, buflen, kCFStringEncodingUTF8))
+                       {
+                       LogMsg("ERROR: ParseBTMMInterfaceKey: Could not convert Interface to CString");
+                       if (buflen) buf[0] = 0;
+                       return;
+                       }
+               else
+                       debugf("ParseBTMMInterfaceKey: Interface Key exists %s", buf);
+               }
+       else
+               {
+               if (buflen) buf[0] = 0;
+               debugf("ParseBTMMInterfaceKey: Interface Key does not exist");
+               }
+       }
+
+mDNSexport void RemoveAutoTunnel6Record(mDNS *const m)
+       {
+       DomainAuthInfo *info;
+       char buf[IFNAMSIZ];
+
+       // Did we parse a non-empty dictionary before ?
+       if (!m->p->ConndBTMMDict || (CFDictionaryGetCount(m->p->ConndBTMMDict) == 0))
+               {
+               LogInfo("RemoveAutoTunnel6Record: Never registered any records before, not deregistering %p", m->p->ConndBTMMDict);
+               return;
+               }
+
+       // Did we have a non-NULL Interface name before ?
+       ParseBTMMInterfaceKey(m->p->ConndBTMMDict, buf, sizeof(buf));
+       if (!strlen(buf))
+               {
+               LogInfo("RemoveAutoTunnel6Record: Interface name already NULL, not deregistering");
+               return;
+               }
+               
+       // Set the address to zero before calling DeregisterAutoTunnel6Record. If we call
+       // Deregister too quickly before the previous Register completed (just scheduled
+       // to be sent out) and when DeregisterAutoTunnel6Record calls mDNS_Register_internal,
+       // it invokes the AutoTunnelRecordCallback immediately and AutoTunnelRelayAddr should
+       // be zero so that we don't register again.
+       m->AutoTunnelRelayAddr = zerov6Addr;
+       if (!m->AuthInfoList) LogInfo("RemoveAutoTunnel6Record: No Domain AuthInfo");
+       for (info = m->AuthInfoList; info; info = info->next)
+               {
+               if (!info->AutoTunnel) { LogInfo("RemoveAutoTunnel6Record: Domain %##s not an AutoTunnel", info->domain.c); continue;}
+
+               if (info->deltime) {LogInfo("RemoveAutoTunnel6Record: Domain %##s about to be deleted", info->domain.c); continue;}
+
+               LogInfo("RemoveAutoTunnel6Record: Deregistering records for domain %##s", info->domain.c);
+               DeregisterAutoTunnel6Record(m, info);
+               }
+       CFRelease(m->p->ConndBTMMDict);
+       m->p->ConndBTMMDict = NULL;
+       }
+
+// Returns zero on success
+mDNSlocal int GetIPv6AddressForIfname(char *ifname, mDNSv6Addr *ipv6Addr)
+       {
+       struct ifaddrs  *ifa;
+       struct ifaddrs  *ifaddrs;
+       mDNSAddr addr;
+
+       if (if_nametoindex(ifname) == 0) {LogInfo("GetIPv6AddressForIfname: Invalid name %s", ifname); return (-1);}
+
+       if (getifaddrs(&ifaddrs) < 0) {LogInfo("GetIPv6AddressForIfname: getifaddrs failed"); return (-1);}
+
+       /*
+        * Find the ifaddr entry corresponding to the interface name,
+        * and return the first matching non-linklocal IPv6 address.
+        */
+       for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
+               {
+               if (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0)
+                       continue;
+               if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6)
+                       {
+                       struct sockaddr_in6 *ifa_addr = (struct sockaddr_in6 *)ifa->ifa_addr;
+                       if (IN6_IS_ADDR_LINKLOCAL(&ifa_addr->sin6_addr))
+                               continue;
+                       if (SetupAddr(&addr, ifa->ifa_addr) != mStatus_NoError)
+                               {
+                               LogInfo("GetIPv6AddressForIfname: SetupAddr error, continuing to the next address");
+                               continue;
+                               }
+                       else
+                               {
+                               *ipv6Addr = *(mDNSv6Addr *)&addr.ip.v6;
+                               LogInfo("GetIPv6AddressForIfname: Returning IPv6 address %.16a", ipv6Addr);
+                               freeifaddrs(ifaddrs);
+                               return 0;
+                               }
+                       }
+       }
+       LogInfo("GetIPv6AddressForIfname: No Valid IPv6 address");
+       freeifaddrs(ifaddrs);
+       return (-1);
+       }
+
+mDNSlocal void AddAutoTunnel6Record(mDNS *const m, char *ifname, CFDictionaryRef BTMMDict)
+       {
+       mDNSv6Addr v6addr;
+       DomainAuthInfo *info;
+
+       if (GetIPv6AddressForIfname(ifname, &v6addr) != 0)
+               {
+               LogInfo("AddAutoTunnel6Record: No Valid IPv6 addresses found for %s", ifname);
+               // If the interface does not exist but the dictionary has the value, we treat
+               // this case as though the dictionary does not have the value
+               RemoveAutoTunnel6Record(m);
+               // If awacsd crashes or exits for some reason, restart the relay connection
+               UpdateBTMMRelayConnection(m);
+               return;
+               }
+       
+       m->AutoTunnelRelayAddr = v6addr;
+
+       if (!m->AuthInfoList) LogInfo("AddAutoTunnel6Record: No Domain AuthInfo");
+       for (info = m->AuthInfoList; info; info = info->next)
+               {
+               // clientContext for a domain tells us that we are listening for at least one Service/Record
+               // in a domain and SetLocalAutoTunnelInterface_internal was called
+               if (!info->AutoTunnel) { LogInfo("AddAutoTunnel6Record: Domain %##s not an AutoTunnel", info->domain.c); continue;}
+
+               if (!info->AutoTunnelNAT.clientContext) {LogInfo("AddAutoTunnel6Record: Domain %##s has no services", info->domain.c); continue;}
+
+               if (info->deltime) {LogInfo("AddAutoTunnel6Record: Domain %##s about to be deleted", info->domain.c); continue;}
+
+               LogInfo("AddAutoTunnel6Record: Registering records for domain %##s", info->domain.c);
+               mDNS_Lock(m);
+               RegisterAutoTunnel6Record(m, info);
+               mDNS_Unlock(m);
+               }
+       if (m->p->ConndBTMMDict) CFRelease(m->p->ConndBTMMDict);
+       m->p->ConndBTMMDict = CFRetain(BTMMDict);
+       }
+
+mDNSlocal void ParseBackToMyMac(mDNS *const m, CFDictionaryRef connd)
+       {
+       CFDictionaryRef BTMMDict;
+       char buf[IFNAMSIZ];
+
+       BTMMDict = ParseBackToMyMacKey(connd);
+       if (!BTMMDict)
+               {
+               LogInfo("ParseBackToMyMac: CFDictionaryGetValue No value for BackToMyMac, Removing autotunnel6");
+               RemoveAutoTunnel6Record(m);
+               return;
+               }
+
+       ParseBTMMInterfaceKey(BTMMDict, buf, sizeof(buf));
+       if (!strlen(buf))
+               {
+               LogInfo("ParseBackToMyMac: NULL value for Interface, Removing autotunnel6"); 
+               RemoveAutoTunnel6Record(m);
+               // We don't have a utun interface, start the relay connection if possible
+               UpdateBTMMRelayConnection(m);
+               }
+       else
+               {
+               LogInfo("ParseBackToMyMac: non-NULL value for Interface, Adding autotunnel6"); 
+               AddAutoTunnel6Record(m, buf, BTMMDict);
+               }
+       }
+
+mDNSexport void SetupConndConfigChanges(mDNS *const m)
+       {
+       CFDictionaryRef connd;
+       SCDynamicStoreRef store;
+
+       store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:SetupConndConfigChanges"), NULL, NULL);
+       if (!store) {LogMsg("SetupConndConfigChanges: SCDynamicStoreCreate failed: %s", SCErrorString(SCError())); return;}
+
+       connd = SCDynamicStoreCopyValue(store, NetworkChangedKey_BTMMConnectivity);
+       if (!connd)
+               {LogInfo("SetupConndConfigChanges: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError())); CFRelease(store); return;}
+       else
+               {
+               ParseBackToMyMac(m, connd);
+               }
+       CFRelease(connd);
+       CFRelease(store);
+       }
+#endif /* APPLE_OSX_mDNSResponder */
+
+               
 mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
        {
        LogInfo("***   Network Configuration Change   ***  (%d)%s",
@@ -5643,6 +7251,7 @@ mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
        m->p->NetworkChanged = 0;               // If we received a network change event and deferred processing, we're now dealing with it
        mDNSs32 utc = mDNSPlatformUTC();
        m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
+       m->SystemSleepOnlyIfWakeOnLAN = SystemSleepOnlyIfWakeOnLAN();
        MarkAllInterfacesInactive(m, utc);
        UpdateInterfaceList(m, utc);
        ClearInactiveInterfaces(m, utc);
@@ -5650,11 +7259,13 @@ mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
 
 #if APPLE_OSX_mDNSResponder
 
+       SetupConndConfigChanges(m);
+
        if (m->AutoTunnelHostAddr.b[0])
                {
                mDNS_Lock(m);
                if (TunnelClients(m) || TunnelServers(m))
-                       SetupLocalAutoTunnelInterface_internal(m);
+                       SetupLocalAutoTunnelInterface_internal(m, mDNSfalse);
                mDNS_Unlock(m);
                }
        
@@ -5664,20 +7275,35 @@ mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
        for (p = m->TunnelClients; p; p = p->next)
                if (p->q.ThisQInterval < 0)
                        {
-                       mDNSAddr tmpSrc = zeroAddr;
-                       mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
-                       tmpDst.ip.v4 = p->rmt_outer;
-                       mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
-                       if (!mDNSSameIPv6Address(p->loc_inner, m->AutoTunnelHostAddr) ||
-                               !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
+                       if (!mDNSIPPortIsZero(p->rmt_outer_port))
                                {
-                               AutoTunnelSetKeys(p, mDNSfalse);
-                               p->loc_inner = m->AutoTunnelHostAddr;
-                               p->loc_outer = tmpSrc.ip.v4;
-                               AutoTunnelSetKeys(p, mDNStrue);
+                               mDNSAddr tmpSrc = zeroAddr;
+                               mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
+                               tmpDst.ip.v4 = p->rmt_outer;
+                               mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
+                               if (!mDNSSameIPv6Address(p->loc_inner, m->AutoTunnelHostAddr) ||
+                                       !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
+                                       {
+                                       AutoTunnelSetKeys(p, mDNSfalse);
+                                       p->loc_inner = m->AutoTunnelHostAddr;
+                                       p->loc_outer = tmpSrc.ip.v4;
+                                       AutoTunnelSetKeys(p, mDNStrue);
+                                       }
                                }
+                               else
+                                       {
+                                       if (!mDNSSameIPv6Address(p->loc_inner, m->AutoTunnelHostAddr) ||
+                                               !mDNSSameIPv6Address(p->loc_outer6, m->AutoTunnelRelayAddr))
+                                               {
+                                               AutoTunnelSetKeys(p, mDNSfalse);
+                                               p->loc_inner = m->AutoTunnelHostAddr;
+                                               p->loc_outer6 = m->AutoTunnelRelayAddr;
+                                               AutoTunnelSetKeys(p, mDNStrue);
+                                               }
+                                       }
                        }
 
+
        SetSPS(m);
 
        NetworkInterfaceInfoOSX *i;
@@ -5689,7 +7315,7 @@ mDNSexport void mDNSMacOSXNetworkChanged(mDNS *const m)
                        }
                else                                                            // else, we're Sleep Proxy Server; open BPF fds
                        {
-                       if (i->Exists && i->Registered == i && !(i->ifa_flags & IFF_LOOPBACK) && i->BPF_fd == -1)
+                       if (i->Exists && i->Registered == i && i->ifinfo.McastTxRx && !(i->ifa_flags & IFF_LOOPBACK) && i->BPF_fd == -1)
                                { LogSPS("%s requesting BPF", i->ifinfo.ifname); i->BPF_fd = -2; mDNSRequestBPF(); }
                        }
                }
@@ -5711,6 +7337,140 @@ mDNSlocal void SetNetworkChanged(mDNS *const m, mDNSs32 delay)
        }
 
 
+// Copy the fourth slash-delimited element from either:
+//   State:/Network/Interface/<bsdname>/IPv4
+// or
+//   Setup:/Network/Service/<servicename>/Interface
+mDNSlocal CFStringRef CopyNameFromKey(CFStringRef key)
+       {
+       CFArrayRef a;
+       CFStringRef name = NULL;
+
+       a = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
+       if (a && CFArrayGetCount(a) == 5) name = CFRetain(CFArrayGetValueAtIndex(a, 3));
+       if (a != NULL) CFRelease(a);
+
+       return name;
+       }
+
+// Whether a key from a network change notification corresponds to
+// an IP service that is explicitly configured for IPv4 Link Local
+mDNSlocal mDNSBool ChangedKeysHaveIPv4LL(CFArrayRef inkeys)
+       {
+       SCDynamicStoreRef store = NULL;
+       CFDictionaryRef dict = NULL;
+       CFMutableArrayRef a;
+       const void **keys = NULL, **vals = NULL;
+       CFStringRef pattern = NULL;
+       int i, ic, j, jc;
+       mDNSBool found = mDNSfalse;
+       
+       jc = CFArrayGetCount(inkeys);
+       if (!jc) goto done;
+
+       store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:ChangedKeysHaveIPv4LL"), NULL, NULL);
+       if (store == NULL) goto done;
+
+       a = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+       if (a == NULL) goto done;
+
+       // Setup:/Network/Service/[^/]+/Interface
+       pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface);
+       if (pattern == NULL) goto done;
+       CFArrayAppendValue(a, pattern);
+       CFRelease(pattern);
+
+       // Setup:/Network/Service/[^/]+/IPv4
+       pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetIPv4);
+       if (pattern == NULL) goto done;
+       CFArrayAppendValue(a, pattern);
+       CFRelease(pattern);
+
+       dict = SCDynamicStoreCopyMultiple(store, NULL, a);
+       CFRelease(a);
+
+       if (!dict)
+               {
+               LogMsg("ChangedKeysHaveIPv4LL: Empty dictionary");
+               goto done;
+               }
+
+       ic = CFDictionaryGetCount(dict);
+       vals = mDNSPlatformMemAllocate(sizeof (void *) * ic);
+       keys = mDNSPlatformMemAllocate(sizeof (void *) * ic);
+       CFDictionaryGetKeysAndValues(dict, keys, vals);
+       
+       for (j = 0; j < jc && !found; j++)
+               {
+               CFStringRef key = CFArrayGetValueAtIndex(inkeys, j);
+               CFStringRef ifname = NULL;
+
+               char buf[256];
+
+               // It would be nice to use a regex here
+               if (!CFStringHasPrefix(key, CFSTR("State:/Network/Interface/")) || !CFStringHasSuffix(key, kSCEntNetIPv4)) continue;
+               
+               if ((ifname = CopyNameFromKey(key)) == NULL) continue;
+               if (mDNS_LoggingEnabled)
+                       {
+                       if (!CFStringGetCString(ifname, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
+                       LogInfo("ChangedKeysHaveIPv4LL: potential ifname %s", buf);
+                       }
+
+               for (i = 0; i < ic; i++)
+                       {
+                       CFDictionaryRef ipv4dict;
+                       CFStringRef name;
+                       CFStringRef serviceid;
+                       CFStringRef configmethod;
+                       
+                       if (!CFStringHasSuffix(keys[i], kSCEntNetInterface)) continue;
+                       
+                       if (CFDictionaryGetTypeID() != CFGetTypeID(vals[i])) continue;
+       
+                       if ((name = CFDictionaryGetValue(vals[i], kSCPropNetInterfaceDeviceName)) == NULL) continue;
+       
+                       if (!CFEqual(ifname, name)) continue;
+                       
+                       if ((serviceid = CopyNameFromKey(keys[i])) == NULL) continue;
+                       if (mDNS_LoggingEnabled)
+                               {
+                               if (!CFStringGetCString(serviceid, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
+                               LogInfo("ChangedKeysHaveIPv4LL: found serviceid %s", buf);
+                               }
+                       
+                       pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceid, kSCEntNetIPv4);
+                       CFRelease(serviceid);
+                       if (pattern == NULL) continue;
+                       
+                       ipv4dict = CFDictionaryGetValue(dict, pattern);
+                       CFRelease(pattern);
+                       if (!ipv4dict || CFDictionaryGetTypeID() != CFGetTypeID(ipv4dict)) continue;
+                       
+                       configmethod = CFDictionaryGetValue(ipv4dict, kSCPropNetIPv4ConfigMethod);
+                       if (!configmethod) continue;
+
+                       if (mDNS_LoggingEnabled)
+                               {
+                               if (!CFStringGetCString(configmethod, buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
+                               LogInfo("ChangedKeysHaveIPv4LL: configmethod %s", buf);
+                               }
+                               
+                       if (CFEqual(configmethod, kSCValNetIPv4ConfigMethodLinkLocal)) { found = mDNStrue; break; }
+                       }
+               
+               CFRelease(ifname);
+               }
+
+       done:
+       if (vals != NULL) mDNSPlatformMemFree(vals);
+       if (keys != NULL) mDNSPlatformMemFree(keys);
+       if (dict != NULL) CFRelease(dict);
+       if (store != NULL) CFRelease(store);
+
+       return found;
+       }
+
 mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
        {
        (void)store;        // Parameter not used
@@ -5762,7 +7522,8 @@ mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, v
        mDNS_Unlock(m);
 
        // If DNS settings changed, immediately force a reconfig (esp. cache flush)
-       if (c4) mDNSMacOSXNetworkChanged(m);
+       // Similarly, if an interface changed that is explicitly IPv4 link local, immediately force a reconfig
+       if (c4 || ChangedKeysHaveIPv4LL(changedKeys)) mDNSMacOSXNetworkChanged(m);
 
        KQueueUnlock(m, "NetworkChanged");
        }
@@ -5787,17 +7548,22 @@ mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
        CFArrayAppendValue(keys, NetworkChangedKey_DNS);
        CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
        CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
-       CFArrayAppendValue(keys, CFSTR("State:/IOKit/PowerManagement/CurrentSettings")); // should remove as part of <rdar://problem/6751656>
+       CFArrayAppendValue(keys, NetworkChangedKey_PowerSettings); // should remove as part of <rdar://problem/6751656>
+       CFArrayAppendValue(keys, NetworkChangedKey_BTMMConnectivity);
        CFArrayAppendValue(patterns, pattern1);
        CFArrayAppendValue(patterns, pattern2);
        CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
        if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns))
                { LogMsg("SCDynamicStoreSetNotificationKeys failed: %s", SCErrorString(SCError())); goto error; }
 
+#ifdef __LIB_DISPATCH__
+       if (!SCDynamicStoreSetDispatchQueue(store, dispatch_get_main_queue()))
+               { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
+#else
        m->p->StoreRLS = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
        if (!m->p->StoreRLS) { LogMsg("SCDynamicStoreCreateRunLoopSource failed: %s", SCErrorString(SCError())); goto error; }
-
        CFRunLoopAddSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
+#endif
        m->p->Store = store;
        err = 0;
        goto exit;
@@ -5891,13 +7657,13 @@ mDNSlocal mStatus WatchForSysEvents(mDNS *const m)
        {
        m->p->SysEventNotifier = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
        if (m->p->SysEventNotifier < 0)
-               { LogMsg("WatchForNetworkChanges: socket failed %s errno %d (%s)", errno, strerror(errno)); return(mStatus_NoMemoryErr); }
+               { LogMsg("WatchForSysEvents: socket failed error %d errno %d (%s)", m->p->SysEventNotifier, errno, strerror(errno)); return(mStatus_NoMemoryErr); }
 
        struct kev_request kev_req = { KEV_VENDOR_APPLE, KEV_NETWORK_CLASS, KEV_DL_SUBCLASS };
        int err = ioctl(m->p->SysEventNotifier, SIOCSKEVFILT, &kev_req);
        if (err < 0)
                {
-               LogMsg("WatchForNetworkChanges: SIOCSKEVFILT failed %s errno %d (%s)", errno, strerror(errno));
+               LogMsg("WatchForSysEvents: SIOCSKEVFILT failed error %d errno %d (%s)", err, errno, strerror(errno));
                close(m->p->SysEventNotifier);
                m->p->SysEventNotifier = -1;
                return(mStatus_UnknownErr);
@@ -5959,7 +7725,6 @@ mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCa
        }
 #endif
 
-#ifndef NO_IOPOWER
 mDNSlocal void PowerOn(mDNS *const m)
        {
        mDNSCoreMachineSleep(m, false);         // Will set m->SleepState = SleepState_Awake;
@@ -6023,6 +7788,7 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag
                case kIOMessageSystemWillRestart:               LogInfo("PowerChanged kIOMessageSystemWillRestart     (no action)");    break;  // E0000310
                case kIOMessageSystemWillPowerOn:               LogInfo("PowerChanged kIOMessageSystemWillPowerOn");                                                    // E0000320
 
+                                                                                       #if ! TARGET_OS_EMBEDDED
                                                                                                // On Leopard and earlier, on wake from sleep, instead of reporting link state down, Apple
                                                                                                // Ethernet drivers report "hardware incapable of detecting link state", which the kernel
                                                                                                // interprets as "should assume we have networking", which results in the first 4-5 seconds
@@ -6034,6 +7800,7 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag
                                                                                                        LogMsg("Running on Mac OS X version 10.%d earlier than 10.6; "
                                                                                                                "PowerChanged did sleep(5) to wait for Ethernet hardware", OSXVers - OSXVers_Base);
                                                                                                        }
+                                                                                       #endif
 
                                                                                                // Make sure our interface list is cleared to the empty state, then tell mDNSCore to wake
                                                                                                if (m->SleepState != SleepState_Sleeping)
@@ -6053,7 +7820,9 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag
        KQueueUnlock(m, "PowerChanged Sleep/Wake");
        }
 
-#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+// iPhone OS doesn't currently have SnowLeopard's IO Power Management
+// but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+#if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
 mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
        {
        mDNS *const m = (mDNS *const)refcon;
@@ -6071,8 +7840,19 @@ mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection,
 
        if (eventDescriptor & kIOPMSystemPowerStateCapabilityCPU)
                {
+               // We might be in Sleeping or Transferring state. When we go from "wakeup" to "sleep" state, we don't
+               // go directly to sleep state, but transfer in to the sleep state during which SleepState is set to
+               // SleepState_Transferring. During that time, we might get another wakeup before we transition to Sleeping
+               // state. In that case, we need to acknowledge the previous "sleep" before we acknowledge the wakeup.
+               if (m->SleepLimit)
+                       {
+                       LogSPS("SnowLeopardPowerChanged: Waking up, Acking old Sleep, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
+                       IOPMConnectionAcknowledgeEvent(connection, m->p->SleepCookie);
+                       m->SleepLimit = 0;
+                       }
+               LogSPS("SnowLeopardPowerChanged: Waking up, Acking Wakeup, SleepLimit %d SleepState %d", m->SleepLimit, m->SleepState);
                // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
-               if (m->SleepState == SleepState_Sleeping) PowerOn(m);
+               if (m->SleepState != SleepState_Awake) PowerOn(m);
                IOPMConnectionAcknowledgeEvent(connection, token);
                }
        else
@@ -6091,8 +7871,6 @@ mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection,
        }
 #endif
 
-#endif /* NO_IOPOWER */
-
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
 #pragma mark - Initialization & Teardown
@@ -6187,12 +7965,18 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
 
        int    get_model[2] = { CTL_HW, HW_MODEL };
        size_t len_model = sizeof(HINFO_HWstring_buffer);
-       // Names that contain no commas are prototype model names, so we ignore those
-       if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
+       
+       // Normal Apple model names are of the form "iPhone2,1", and
+       // internal code names are strings containing no commas, e.g. "N88AP".
+       // We used to ignore internal code names, but Apple now uses these internal code names
+       // even in released shipping products, so we no longer ignore strings containing no commas.
+//     if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
+       if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
                HINFO_HWstring = HINFO_HWstring_buffer;
        HINFO_HWstring_prefixlen = strcspn(HINFO_HWstring, "0123456789");
 
        if (OSXVers <  OSXVers_10_3_Panther     ) m->KnownBugs |= mDNS_KnownBug_PhantomInterfaces;
+       if (OSXVers <= OSXVers_10_6_SnowLeopard ) m->KnownBugs |= mDNS_KnownBug_LimitedIPv6;
        if (OSXVers >= OSXVers_10_6_SnowLeopard ) m->KnownBugs |= mDNS_KnownBug_LossySyslog;
        if (mDNSPlatformInit_CanReceiveUnicast()) m->CanReceiveUnicastOn5353 = mDNStrue;
 
@@ -6208,10 +7992,16 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
 
        m->p->permanentsockets.port  = MulticastDNSPort;
        m->p->permanentsockets.m     = m;
-       m->p->permanentsockets.sktv4 = m->p->permanentsockets.sktv6 = -1;
-       m->p->permanentsockets.kqsv4.KQcallback = m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
-       m->p->permanentsockets.kqsv4.KQcontext  = m->p->permanentsockets.kqsv6.KQcontext  = &m->p->permanentsockets;
-       m->p->permanentsockets.kqsv4.KQtask     = m->p->permanentsockets.kqsv6.KQtask     = "UDP packet reception";
+       m->p->permanentsockets.sktv4 = -1;
+       m->p->permanentsockets.kqsv4.KQcallback = myKQSocketCallBack;
+       m->p->permanentsockets.kqsv4.KQcontext  = &m->p->permanentsockets;
+       m->p->permanentsockets.kqsv4.KQtask     = "UDP packet reception";
+#ifndef NO_IPV6
+       m->p->permanentsockets.sktv6 = -1;
+       m->p->permanentsockets.kqsv6.KQcallback = myKQSocketCallBack;
+       m->p->permanentsockets.kqsv6.KQcontext  = &m->p->permanentsockets;
+       m->p->permanentsockets.kqsv6.KQtask     = "UDP packet reception";
+#endif
 
        err = SetupSocket(&m->p->permanentsockets, MulticastDNSPort, AF_INET, mDNSNULL);
 #ifndef NO_IPV6
@@ -6235,6 +8025,10 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
        m->p->InterfaceList      = mDNSNULL;
        m->p->userhostlabel.c[0] = 0;
        m->p->usernicelabel.c[0] = 0;
+       m->p->prevoldnicelabel.c[0] = 0;
+       m->p->prevnewnicelabel.c[0] = 0;
+       m->p->prevoldhostlabel.c[0] = 0;
+       m->p->prevnewhostlabel.c[0] = 0;
        m->p->NotifyUser         = 0;
        m->p->KeyChainBugTimer   = 0;
        m->p->WakeAtUTC          = 0;
@@ -6245,6 +8039,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
 #endif
 
        m->AutoTunnelHostAddr.b[0] = 0;         // Zero out AutoTunnelHostAddr so UpdateInterfaceList() know it has to set it up
+       m->AutoTunnelRelayAddr = zerov6Addr;
 
        NetworkChangedKey_IPv4         = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
        NetworkChangedKey_IPv6         = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
@@ -6285,9 +8080,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
        if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
 #endif
 
-#ifndef NO_IOPOWER
-
-#ifndef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+#if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
        LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
 #else
        IOPMConnection c;
@@ -6309,30 +8102,51 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
                {
                m->p->PowerConnection = IORegisterForSystemPower(m, &m->p->PowerPortRef, PowerChanged, &m->p->PowerNotifier);
                if (!m->p->PowerConnection) { LogMsg("mDNSPlatformInit_setup: IORegisterForSystemPower failed"); return(-1); }
-               else CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
+               else
+                       {
+#ifdef __LIB_DISPATCH__
+                       IONotificationPortSetDispatchQueue(m->p->PowerPortRef, dispatch_get_main_queue());
+#else
+                       CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
+#endif /* __LIB_DISPATCH__ */
+                       }
                }
-#endif /* NO_IOPOWER */
 
 #if APPLE_OSX_mDNSResponder
        // Note: We use SPMetricPortability > 35 to indicate a laptop of some kind
        // SPMetricPortability <= 35 means nominally a non-portable machine (i.e. Mac mini or better)
-       // An Apple TV does not actually weigh 3kg, but we assign it a 'nominal' mass of 3kg to indicate that it's treated as being relatively less portable than a laptop
-       if      (!strncasecmp(HINFO_HWstring, "Xserve",   6)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
-       else if (!strncasecmp(HINFO_HWstring, "RackMac",  7)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
-       else if (!strncasecmp(HINFO_HWstring, "MacPro",   6)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
-       else if (!strncasecmp(HINFO_HWstring, "PowerMac", 8)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 82 /* 160W */; SPMetricTotalPower = 83 /* 200W */; }
-       else if (!strncasecmp(HINFO_HWstring, "iMac",     4)) { SPMetricPortability = 30 /* 10kg */; SPMetricMarginalPower = 77 /*  50W */; SPMetricTotalPower = 78 /*  60W */; }
-       else if (!strncasecmp(HINFO_HWstring, "Macmini",  7)) { SPMetricPortability = 33 /*  5kg */; SPMetricMarginalPower = 73 /*  20W */; SPMetricTotalPower = 74 /*  25W */; }
-       else if (!strncasecmp(HINFO_HWstring, "AppleTV",  7)) { SPMetricPortability = 35 /*  3kg */; SPMetricMarginalPower = 10 /*   0W */; SPMetricTotalPower = 73 /*  20W */; }
-       else if (!strncasecmp(HINFO_HWstring, "MacBook",  7)) { SPMetricPortability = 37 /*  2kg */; SPMetricMarginalPower = 71 /*  13W */; SPMetricTotalPower = 72 /*  15W */; }
-       else if (!strncasecmp(HINFO_HWstring, "PowerBook",9)) { SPMetricPortability = 37 /*  2kg */; SPMetricMarginalPower = 71 /*  13W */; SPMetricTotalPower = 72 /*  15W */; }
+       // Apple TVs, AirPort base stations, and Time Capsules do not actually weigh 3kg, but we assign them
+       // higher 'nominal' masses to indicate they should be treated as being relatively less portable than a laptop
+       if      (!strncasecmp(HINFO_HWstring, "Xserve",       6)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
+       else if (!strncasecmp(HINFO_HWstring, "RackMac",      7)) { SPMetricPortability = 25 /* 30kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
+       else if (!strncasecmp(HINFO_HWstring, "MacPro",       6)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 84 /* 250W */; SPMetricTotalPower = 85 /* 300W */; }
+       else if (!strncasecmp(HINFO_HWstring, "PowerMac",     8)) { SPMetricPortability = 27 /* 20kg */; SPMetricMarginalPower = 82 /* 160W */; SPMetricTotalPower = 83 /* 200W */; }
+       else if (!strncasecmp(HINFO_HWstring, "iMac",         4)) { SPMetricPortability = 30 /* 10kg */; SPMetricMarginalPower = 77 /*  50W */; SPMetricTotalPower = 78 /*  60W */; }
+       else if (!strncasecmp(HINFO_HWstring, "Macmini",      7)) { SPMetricPortability = 33 /*  5kg */; SPMetricMarginalPower = 73 /*  20W */; SPMetricTotalPower = 74 /*  25W */; }
+       else if (!strncasecmp(HINFO_HWstring, "TimeCapsule", 11)) { SPMetricPortability = 34 /*  4kg */; SPMetricMarginalPower = 10 /*  ~0W */; SPMetricTotalPower = 70 /*  13W */; }
+       else if (!strncasecmp(HINFO_HWstring, "AirPort",      7)) { SPMetricPortability = 35 /*  3kg */; SPMetricMarginalPower = 10 /*  ~0W */; SPMetricTotalPower = 70 /*  12W */; }
+       else if (!strncasecmp(HINFO_HWstring, "AppleTV",      7)) { SPMetricPortability = 35 /*  3kg */; SPMetricMarginalPower = 10 /*  ~0W */; SPMetricTotalPower = 73 /*  20W */; }
+       else if (!strncasecmp(HINFO_HWstring, "MacBook",      7)) { SPMetricPortability = 37 /*  2kg */; SPMetricMarginalPower = 71 /*  13W */; SPMetricTotalPower = 72 /*  15W */; }
+       else if (!strncasecmp(HINFO_HWstring, "PowerBook",    9)) { SPMetricPortability = 37 /*  2kg */; SPMetricMarginalPower = 71 /*  13W */; SPMetricTotalPower = 72 /*  15W */; }
        LogSPS("HW_MODEL: %.*s (%s) Portability %d Marginal Power %d Total Power %d",
                HINFO_HWstring_prefixlen, HINFO_HWstring, HINFO_HWstring, SPMetricPortability, SPMetricMarginalPower, SPMetricTotalPower);
 
        err = WatchForInternetSharingChanges(m);
        if (err) { LogMsg("WatchForInternetSharingChanges failed %d", err); return(err); }
+
+       m->p->ConndBTMMDict = mDNSNULL;
 #endif // APPLE_OSX_mDNSResponder
 
+#ifdef __LIB_DISPATCH__
+       // Currently this is not defined. SSL code will eventually fix this. If it becomes
+       // critical, we will define this to workaround the bug in SSL.
+#ifdef __SSL_NEEDS_SERIALIZATION__
+       SSLqueue = dispatch_queue_create("com.apple.mDNSResponder.SSLQueue", NULL);
+#else
+       SSLqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+#endif
+       if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL");
+#endif
        return(mStatus_NoError);
        }
 
@@ -6347,13 +8161,29 @@ mDNSexport mStatus mDNSPlatformInit(mDNS *const m)
        
 #if APPLE_OSX_mDNSResponder
        m->SPSBrowseCallback = UpdateSPSStatus;
-#endif
+#endif // APPLE_OSX_mDNSResponder
 
        mStatus result = mDNSPlatformInit_setup(m);
 
        // We don't do asynchronous initialization on OS X, so by the time we get here the setup will already
        // have succeeded or failed -- so if it succeeded, we should just call mDNSCoreInitComplete() immediately
-       if (result == mStatus_NoError) mDNSCoreInitComplete(m, mStatus_NoError);
+       if (result == mStatus_NoError)
+               {
+               mDNSCoreInitComplete(m, mStatus_NoError);
+
+#if ! NO_D2D
+               // We only initialize if mDNSCore successfully initialized.
+               CHECK_D2D_FUNCTION(D2DInitialize)
+                       {
+                       D2DStatus ds = D2DInitialize(m->p->CFRunLoop, xD2DServiceCallback, m) ;
+                       if (ds != kD2DSuccess)
+                               LogMsg("D2DInitialiize failed: %d", ds);
+                       else
+                               LogMsg("D2DInitialize succeeded");
+                       }
+#endif // ! NO_D2D
+                       
+               }
        return(result);
        }
 
@@ -6361,25 +8191,32 @@ mDNSexport void mDNSPlatformClose(mDNS *const m)
        {
        if (m->p->PowerConnection)
                {
+#ifdef __LIB_DISPATCH__
+               IONotificationPortSetDispatchQueue(m->p->PowerPortRef, NULL);           
+#else
                CFRunLoopRemoveSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(m->p->PowerPortRef), kCFRunLoopDefaultMode);
-#ifndef NO_IOPOWER
+#endif
                // According to <http://developer.apple.com/qa/qa2004/qa1340.html>, a single call
                // to IORegisterForSystemPower creates *three* objects that need to be disposed individually:
                IODeregisterForSystemPower(&m->p->PowerNotifier);
                IOServiceClose            ( m->p->PowerConnection);
                IONotificationPortDestroy ( m->p->PowerPortRef);
-#endif /* NO_IOPOWER */
                m->p->PowerConnection = 0;
                }
 
        if (m->p->Store)
                {
+#ifdef __LIB_DISPATCH__
+               if (!SCDynamicStoreSetDispatchQueue(m->p->Store, NULL))
+                       LogMsg("mDNSPlatformClose: SCDynamicStoreSetDispatchQueue failed");
+#else
                CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m->p->StoreRLS, kCFRunLoopDefaultMode);
                CFRunLoopSourceInvalidate(m->p->StoreRLS);
                CFRelease(m->p->StoreRLS);
+               m->p->StoreRLS = NULL;
+#endif
                CFRelease(m->p->Store);
                m->p->Store    = NULL;
-               m->p->StoreRLS = NULL;
                }
        
        if (m->p->PMRLS)
@@ -6392,6 +8229,17 @@ mDNSexport void mDNSPlatformClose(mDNS *const m)
 
        if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
 
+#if ! NO_D2D
+               CHECK_D2D_FUNCTION(D2DTerminate)
+               {
+               D2DStatus ds = D2DTerminate();
+               if (ds != kD2DSuccess)
+                       LogMsg("D2DTerminate failed: %d", ds);
+               else
+                       LogMsg("D2DTerminate succeeded");
+               }
+#endif // ! NO_D2D
+
        mDNSs32 utc = mDNSPlatformUTC();
        MarkAllInterfacesInactive(m, utc);
        ClearInactiveInterfaces(m, utc);
@@ -6422,6 +8270,7 @@ mDNSexport void mDNSPlatformClose(mDNS *const m)
                LogInfo("mDNSPlatformClose: Removing AutoTunnel address %.16a", &m->AutoTunnelHostAddr);
                (void)mDNSAutoTunnelInterfaceUpDown(kmDNSDown, m->AutoTunnelHostAddr.b);
                }
+       if (m->p->ConndBTMMDict) CFRelease(m->p->ConndBTMMDict);
 #endif // APPLE_OSX_mDNSResponder
        }
 
@@ -6508,3 +8357,18 @@ mDNSexport void     mDNSPlatformMemZero(      void *dst,                  mDNSu3
 mDNSexport void *   mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
 #endif
 mDNSexport void     mDNSPlatformMemFree    (void *mem)   { freeL("mDNSPlatformMemFree", mem); }
+
+mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep)
+       {
+       if (allowSleep && m->p->IOPMAssertion)
+               {
+               LogInfo("%s Destroying NoIdleSleep power assertion", __FUNCTION__);
+               IOPMAssertionRelease(m->p->IOPMAssertion);
+               m->p->IOPMAssertion = 0;
+               }
+       else if (!allowSleep && m->p->IOPMAssertion == 0)
+               {
+               IOPMAssertionCreateWithName(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, CFSTR("mDNSResponder"), &m->p->IOPMAssertion);
+               LogInfo("%s Creating NoIdleSleep power assertion", __FUNCTION__);
+               }
+       }
index 03db2357adfd8913e983ffab2d62c0b88e47a31a..522565e75efa60d2c2378b28111db2b021fe1cf7 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: mDNSMacOSX.h,v $
-Revision 1.104  2009/06/25 23:36:56  cheshire
-To facilitate testing, added command-line switch "-OfferSleepProxyService"
-to re-enable the previously-supported mode of operation where we offer
-sleep proxy service on desktop Macs that are set to never sleep.
-
-Revision 1.103  2009/04/11 00:20:13  jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.102  2009/04/06 22:14:02  cheshire
-Need to include IOKit/pwr_mgt/IOPM.h to build for AppleTV
-
-Revision 1.101  2009/04/02 22:21:17  mcguire
-<rdar://problem/6577409> Adopt IOPM APIs
-
-Revision 1.100  2009/02/12 20:57:26  cheshire
-Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
-
-Revision 1.99  2009/02/11 02:31:05  cheshire
-Move SystemWakeForNetworkAccessEnabled into mDNS structure so it's accessible to mDNSCore routines
-
-Revision 1.98  2009/02/07 02:52:19  cheshire
-<rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
-
-Revision 1.97  2009/02/02 22:13:01  cheshire
-Added SystemWakeForNetworkAccessEnabled setting
-
-Revision 1.96  2009/01/17 04:13:57  cheshire
-Added version symbols for Cheetah and Puma
-
-Revision 1.95  2009/01/16 02:32:55  cheshire
-Added SysEventNotifier and SysEventKQueue in mDNS_PlatformSupport_struct
-
-Revision 1.94  2009/01/15 22:24:53  cheshire
-Removed unused ifa_name field from NetworkInterfaceInfoOSX_struct
-
-Revision 1.93  2008/12/10 19:30:01  cheshire
-Added symbolic names for the various OS X versions
-
-Revision 1.92  2008/10/31 23:49:38  mkrochma
-Increased sizecheck limit
-
-Revision 1.91  2008/10/31 22:48:27  cheshire
-Added SCPreferencesRef to mDNS_PlatformSupport_struct
-
-Revision 1.90  2008/10/30 01:04:35  cheshire
-Added WakeAtUTC and SleepTime fields to mDNS_PlatformSupport_struct
-
-Revision 1.89  2008/10/29 18:38:33  mcguire
-Increase sizecheck limits to account for CFRunLoop added to mDNS_PlatformSupport_struct in 64bit builds
-
-Revision 1.88  2008/10/28 20:33:56  cheshire
-Added CFRunLoopRef in mDNS_PlatformSupport_struct, to hold reference to our main thread's CFRunLoop
-
-Revision 1.87  2008/10/28 18:32:09  cheshire
-Added CFSocketRef and CFRunLoopSourceRef in NetworkInterfaceInfoOSX_struct
-
-Revision 1.86  2008/10/22 23:23:53  cheshire
-Moved definition of OSXVers from daemon.c into mDNSMacOSX.c
-
-Revision 1.85  2008/10/21 00:12:00  cheshire
-Added BPF-related fields in NetworkInterfaceInfoOSX_struct
-
-Revision 1.84  2008/10/14 20:20:44  cheshire
-Increase sizecheck limits to account for DNSQuestions added to NetworkInterfaceInfo_struct
-
-Revision 1.83  2008/10/07 21:41:57  mcguire
-Increase sizecheck limits to account for DNSQuestion added to NetworkInterfaceInfo_struct in 64bit builds
-
-Revision 1.82  2008/10/07 15:56:24  cheshire
-Increase sizecheck limits to account for DNSQuestion added to NetworkInterfaceInfo_struct
-
-Revision 1.81  2008/10/03 00:26:25  cheshire
-Export DictionaryIsEnabled() so it's callable from other files
-
-Revision 1.80  2008/10/02 22:47:01  cheshire
-<rdar://problem/6134215> Sleep Proxy: Mac with Internet Sharing should also offer Sleep Proxy service
-Added SCPreferencesRef so we can track whether Internet Sharing is on or off
-
-Revision 1.79  2008/07/30 00:55:56  mcguire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-Additional fixes so that we know when a socket has been closed while in a loop reading from it
-
-Revision 1.78  2008/07/25 22:34:11  mcguire
-fix sizecheck issues for 64bit
-
-Revision 1.77  2008/07/24 20:23:04  cheshire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-
-Revision 1.76  2008/07/01 01:40:01  mcguire
-<rdar://problem/5823010> 64-bit fixes
-
-Revision 1.75  2007/12/14 00:45:21  cheshire
-Add SleepLimit and SleepCookie, for when we need to delay sleep until TLS/TCP record deregistration completes
-
-Revision 1.74  2007/11/02 20:18:13  cheshire
-<rdar://problem/5575583> BTMM: Work around keychain notification bug <rdar://problem/5124399>
-
-Revision 1.73  2007/10/17 18:42:06  cheshire
-Export SetDomainSecrets so its callable from other files
-
-Revision 1.72  2007/08/01 16:09:14  cheshire
-Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
-
-Revision 1.71  2007/07/27 23:57:23  cheshire
-Added compile-time structure size checks
-
-Revision 1.70  2007/07/11 02:55:50  cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-Remove unused DefaultRegDomainChanged/DefaultBrowseDomainChanged
-
-Revision 1.69  2007/05/08 00:56:17  cheshire
-<rdar://problem/4118503> Share single socket instead of creating separate socket for each active interface
-
-Revision 1.68  2007/04/24 00:10:15  cheshire
-Increase WatchDogReportingThreshold to 250ms for customer builds
-
-Revision 1.67  2007/04/21 21:47:47  cheshire
-<rdar://problem/4376383> Daemon: Add watchdog timer
-
-Revision 1.66  2007/04/07 01:01:48  cheshire
-<rdar://problem/5095167> mDNSResponder periodically blocks in SSLRead
-
-Revision 1.65  2007/03/07 02:50:50  cheshire
-<rdar://problem/4574528> Name conflict dialog doesn't appear if Bonjour is persistantly unable to find an available hostname
-
-Revision 1.64  2007/03/06 23:29:50  cheshire
-<rdar://problem/4331696> Need to call IONotificationPortDestroy on shutdown
-
-Revision 1.63  2007/02/07 19:32:00  cheshire
-<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
-
-Revision 1.62  2007/01/05 08:30:49  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.61  2006/08/14 23:24:40  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.60  2006/07/27 03:24:35  cheshire
-<rdar://problem/4049048> Convert mDNSResponder to use kqueue
-Further refinement: Declare KQueueEntry parameter "const"
-
-Revision 1.59  2006/07/27 02:59:25  cheshire
-<rdar://problem/4049048> Convert mDNSResponder to use kqueue
-Further refinements: CFRunLoop thread needs to explicitly wake the kqueue thread
-after releasing BigMutex, in case actions it took have resulted in new work for the
-kqueue thread (e.g. NetworkChanged events may result in the kqueue thread having to
-add new active interfaces to its list, and consequently schedule queries to be sent).
-
-Revision 1.58  2006/07/22 06:08:29  cheshire
-<rdar://problem/4049048> Convert mDNSResponder to use kqueue
-Further changes
-
-Revision 1.57  2006/07/22 03:43:26  cheshire
-<rdar://problem/4049048> Convert mDNSResponder to use kqueue
-
-Revision 1.56  2006/07/05 23:37:26  cheshire
-Remove unused LegacyNATInit/LegacyNATDestroy declarations
-
-Revision 1.55  2006/06/29 05:33:30  cheshire
-<rdar://problem/4607043> mDNSResponder conditional compilation options
-
-Revision 1.54  2006/03/19 03:27:49  cheshire
-<rdar://problem/4118624> Suppress "interface flapping" logic for loopback
-
-Revision 1.53  2006/03/19 02:00:09  cheshire
-<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-
-Revision 1.52  2006/01/05 21:41:49  cheshire
-<rdar://problem/4108164> Reword "mach_absolute_time went backwards" dialog
-
-*/
+ */
 
 #ifndef __mDNSOSX_h
 #define __mDNSOSX_h
@@ -205,6 +30,11 @@ Revision 1.52  2006/01/05 21:41:49  cheshire
 #include <netinet/in.h>
 #include "mDNSEmbeddedAPI.h"  // for domain name structure
 
+//#define __LIB_DISPATCH__
+#ifdef __LIB_DISPATCH__
+#include <dispatch/dispatch.h>
+#endif
+
 typedef struct NetworkInterfaceInfoOSX_struct NetworkInterfaceInfoOSX;
 
 typedef void (*KQueueEventCallback)(int fd, short filter, void *context);
@@ -213,6 +43,11 @@ typedef struct
        KQueueEventCallback      KQcallback;
        void                *KQcontext;
        const char const    *KQtask;            // For debugging messages
+#ifdef __LIB_DISPATCH__
+       dispatch_source_t readSource;
+       dispatch_source_t writeSource;
+       mDNSBool                  fdClosed;
+#endif
        } KQueueEntry;
 
 typedef struct
@@ -222,8 +57,10 @@ typedef struct
        mDNS                    *m;
        int                      sktv4;
        KQueueEntry                              kqsv4;
+#ifndef NO_IPV6
        int                      sktv6;
        KQueueEntry                  kqsv6;
+#endif
        int                     *closeFlag;
        } KQSocketSet;
 
@@ -252,9 +89,14 @@ struct NetworkInterfaceInfoOSX_struct
        mDNSEthAddr              BSSID;                         // BSSID of 802.11 base station, if applicable
        u_short                  sa_family;
        int                      BPF_fd;                        // -1 uninitialized; -2 requested BPF; -3 failed
+       int                      BPF_mcfd;                      // Socket for our IPv6 ND group membership
        u_int                    BPF_len;
+#ifdef __LIB_DISPATCH__
+       dispatch_source_t                BPF_source;
+#else
        CFSocketRef              BPF_cfs;
        CFRunLoopSourceRef       BPF_rls;
+#endif
        NetworkInterfaceInfoOSX *Registered;            // non-NULL means registered with mDNS Core
        };
 
@@ -264,6 +106,13 @@ struct mDNS_PlatformSupport_struct
        KQSocketSet              permanentsockets;
        domainlabel              userhostlabel;         // The hostlabel as it was set in System Preferences the last time we looked
        domainlabel              usernicelabel;         // The nicelabel as it was set in System Preferences the last time we looked
+       // Following four variables are used for optimization where the helper is not
+       // invoked when not needed. It records the state of what we told helper the
+       // last time we invoked mDNSPreferencesSetName
+       domainlabel              prevoldhostlabel;  // Previous m->p->userhostlabel
+       domainlabel              prevnewhostlabel;  // Previous m->hostlabel
+       domainlabel              prevoldnicelabel;  // Previous m->p->usernicelabel
+       domainlabel              prevnewnicelabel;  // Previous m->nicelabel
        mDNSs32                  NotifyUser;
        mDNSs32                  HostNameConflict;      // Time we experienced conflict on our link-local host name
        mDNSs32                  NetworkChanged;
@@ -287,16 +136,27 @@ struct mDNS_PlatformSupport_struct
 #ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
        IOPMConnection           IOPMConnection;
 #endif
+       IOPMAssertionID          IOPMAssertion;
        SCPreferencesRef         SCPrefs;
        long                     SleepCookie;           // Cookie we need to pass to IOAllowPowerChange()
        long                     WakeAtUTC;
        mDNSs32                  RequestReSleep;
+#ifdef __LIB_DISPATCH__
+       dispatch_source_t                timer;
+       dispatch_source_t                custom;
+#else
        pthread_mutex_t          BigMutex;
+#endif
        mDNSs32                  BigMutexStartTime;
        int                                              WakeKQueueLoopFD;
+#if APPLE_OSX_mDNSResponder
+       CFDictionaryRef                 ConndBTMMDict;                  // Dictionary of tunnel name/value pairs
+#endif
        };
 
 extern int OfferSleepProxyService;
+extern int DisableSleepProxyClient;
+extern mDNSBool DisableInboundRelayConnection;
 extern int OSXVers;
 #define OSXVers_Base              4
 #define OSXVers_10_0_Cheetah      4
@@ -315,12 +175,18 @@ extern void mDNSMacOSXNetworkChanged(mDNS *const m);
 extern int mDNSMacOSXSystemBuildNumber(char *HINFO_SWstring);
 extern NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(const mDNS *const m, mDNSInterfaceID ifindex);
 
+#ifdef __LIB_DISPATCH__
+extern int KQueueSet(int fd, u_short flags, short filter, KQueueEntry *const entryRef);
+mDNSexport void TriggerEventCompletion(void);
+#else
 extern int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef);
+#endif
 
 // When events are processed on the non-kqueue thread (i.e. CFRunLoop notifications like Sleep/Wake,
 // Interface changes, Keychain changes, etc.) they must use KQueueLock/KQueueUnlock to lock out the kqueue thread
 extern void KQueueLock(mDNS *const m);
 extern void KQueueUnlock(mDNS *const m, const char const *task);
+extern void mDNSPlatformCloseFD(KQueueEntry *kq, int fd);
 
 extern mDNSBool DictionaryIsEnabled(CFDictionaryRef dict);
 
@@ -348,7 +214,7 @@ struct CompileTimeAssertionChecks_mDNSMacOSX
        // other overly-large structures instead of having a pointer to them, can inadvertently
        // cause structure sizes (and therefore memory usage) to balloon unreasonably.
        char sizecheck_NetworkInterfaceInfoOSX[(sizeof(NetworkInterfaceInfoOSX) <=  7000) ? 1 : -1];
-       char sizecheck_mDNS_PlatformSupport   [(sizeof(mDNS_PlatformSupport)    <=   476) ? 1 : -1];
+       char sizecheck_mDNS_PlatformSupport   [(sizeof(mDNS_PlatformSupport)    <=   768) ? 1 : -1];
        };
 
 #ifdef  __cplusplus
index b4a09226070863b26cbffcbfd44ae8451ded0a6a..547f383d2a56c3c95eab9e748da3f14946982f5b 100644 (file)
 ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ;
-; $Log: mDNSResponder.sb,v $
-; Revision 1.38  2009/04/16 16:03:08  mcguire
-; <rdar://problem/6792024> abort() causes high CPU usage instead of crash & restart
-;
-; Revision 1.37  2009/04/02 22:21:17  mcguire
-; <rdar://problem/6577409> Adopt IOPM APIs
-;
-; Revision 1.36  2009/03/02 01:32:20  mcguire
-; <rdar://problem/6623264> Seatbelt: Add rule to allow raw sockets
-;
-; Revision 1.35  2009/02/07 02:51:10  cheshire
-; <rdar://problem/6084043> Sleep Proxy: Need to adopt IOPMConnection
-; Allow mDNSResponder to access IOPMConnection API
-;
-; Revision 1.34  2008/11/11 00:55:08  mcguire
-; <rdar://problem/6357957> sandbox: need to allow Mach port com.apple.system.DirectoryService.membership_v1
-;
-; Revision 1.33  2008/10/24 02:03:30  cheshire
-; So we can watch for Internet Sharing changes, allow read access to
-; /Library/Preferences/SystemConfiguration/com.apple.nat.plist
-;
-; Revision 1.32  2008/10/07 23:06:58  mcguire
-; <rdar://problem/6276444> Seatbelt: Policy denied Mach service lookup: com.apple.system.logger
-;
-; Revision 1.31  2008/09/24 23:57:27  mcguire
-; <rdar://problem/6227808> need read access to /private/var/db/crls/crlcache.db
-;
-; Revision 1.30  2008/09/11 22:01:51  mcguire
-; re-add accidentally removed log comment
-;
-; Revision 1.29  2008/09/11 20:46:08  mcguire
-; <rdar://problem/6208848> can't write to -Caches-
-;
-; Revision 1.28  2008/09/11 20:04:14  mcguire
-; <rdar://problem/6211355> Instances of \. in regex exprs don't do what is intended
-;
-; Revision 1.27  2008/07/24 21:18:14  cheshire
-; <rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-; Need to allow access to /dev/urandom
-;
-; Revision 1.26  2008/06/03 01:21:12  mcguire
-; <rdar://problem/5902470> add /var/db/mds to sb profile
-;
-; Revision 1.25  2008/03/17 18:04:41  mcguire
-; <rdar://problem/5800476> SC now reads preference file
-;
-; Revision 1.24  2007/09/20 22:33:17  cheshire
-; Tidied up inconsistent and error-prone naming -- used to be mDNSResponderHelper in
-; some places and mDNSResponder.helper in others; now mDNSResponderHelper everywhere
-;
-; Revision 1.23  2007/09/04 22:26:18  mcguire
-; <rdar://problem/5442826> Seatbelt: mDNSResponder needs to be allowed to access "/Library/Security/Trust Settings/" etc.
-;
-; Revision 1.22  2007/08/24 22:01:56  mcguire
-; <rdar://problem/5141606> BTMM: Task: Change mDNSResponder Seatbelt settings to "deny default" instead of "signal FPE" just prior to GM candidate
-;
-; Revision 1.21  2007/08/18 01:02:03  mcguire
-; <rdar://problem/5415593> No Bonjour services are getting registered at boot
-;
-; Revision 1.20  2007/08/08 22:34:59  mcguire
-; <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
-;
-; Revision 1.19  2007/07/02 23:37:50  cheshire
-; <rdar://problem/5267615> Need to list of allowed mach-lookup operations explicitly in mDNSResponder.sb
-;
-; Revision 1.18  2007/06/28 20:43:35  cheshire
-; <rdar://problem/5298202> Seatbelt: mDNSResponder needs to be able to access /dev/autofs_nowait
-;
-; Revision 1.17  2007/06/28 20:34:45  cheshire
-; Updated comments to reflect new seatbelt language syntax
-;
-; Revision 1.16  2007/05/29 23:32:46  cheshire
-; Rearrange file so SPI warning isn't deleted when CVS history is trimmed from installed copy
-;
-; Revision 1.15  2007/05/25 22:45:17  jvidrine
-; <rdar://problem/5227658> Update mDNSResponder.sb to Seatbelt Profile Language version 1
-;
-; Revision 1.14  2007/05/23 17:40:08  cheshire
-; <rdar://problem/5221397> Seatbelt killed mDNSResponder trying to read X509Anchors and X509Certificates
-;
-; Revision 1.13  2007/05/23 01:47:59  cheshire
-; Need to list fs_read_data permission explicitly --
-; unlike fs_read/fs_write, fs_read_data does NOT automatically inherit from fs_write_data
-;
-; Revision 1.12  2007/05/21 23:52:27  cheshire
-; <rdar://problem/5216638> Seatbelt killed mDNSResponder generating Module Directory Services cache
-;
-; Revision 1.11  2007/05/20 16:29:06  cheshire
-; <rdar://problem/5213725> Seatbelt killed mDNSResponder trying to access /usr/share/icu/icudt36l.dat
-;
-; Revision 1.10  2007/05/15 00:21:39  cheshire
-; <rdar://problem/5202374> Seatbelt killed mDNSResponder reading /private/var/root/Library/Preferences/com.apple.security.plist
-;
-; Revision 1.9  2007/05/14 22:08:26  cheshire
-; <rdar://problem/5200986> Seatbelt: Need to escape literal dots in filename patterns
-;
-; Revision 1.8  2007/05/14 19:39:31  cheshire
-; <rdar://problem/5198345> Seatbelt killed mDNSResponder in CFTimeZoneCopyDefault
-; <rdar://problem/5199456> Seatbelt killed mDNSResponder in SecKeychainOpen
-;
-; Revision 1.7  2007/05/12 01:57:56  cheshire
-; <rdar://problem/5197938> Seatbelt: mDNSResponder needs to be able to access preferences.plist-lock
-;
-; Revision 1.6  2007/05/10 21:12:14  cheshire
-; <rdar://problem/5149833> Start using "debug deny" mode in Seatbelt
-;
-; Revision 1.5  2007/05/10 19:41:25  cheshire
-; <rdar://problem/5182549> Have to use "deny mach_lookup_default" because "signal" doesn't work
-;
-; Revision 1.4  2007/04/27 20:46:31  cheshire
-; Additional requirements: allow mDNSResponder to read /dev/random and /System/Library/Keychains/System.*
-;
-; Revision 1.3  2007/04/20 19:42:14  cheshire
-; Condense rules a bit to bring file under Seatbelt's 4K limit
-;
-; Revision 1.2  2007/04/19 01:47:49  cheshire
-; Refinements to sandbox profile, e.g. allow writing to /dev/console early in the boot process
-;
-; Revision 1.1  2007/04/18 00:50:47  cheshire
-; <rdar://problem/5141540> Sandbox mDNSResponder
-;
 ;############################################################################
 
-; WARNING! SEATBELT CURRENTLY CAN'T HANDLE PROFILES LARGER THAN 16K
-; MAKE SURE THE SIZE OF THIS FILE FROM "version" TO THE END DOESN'T EXCEED 16K
-
 (version 1)
 
 ; WARNING: The sandbox rule capabilities and syntax used in this file are currently an
                                        "com.apple.system.DirectoryService.libinfo_v1"
                                        "com.apple.system.DirectoryService.membership_v1"
                                        "com.apple.system.notification_center"
-                                       "com.apple.system.logger"))
+                                       "com.apple.system.logger"
+                                       "com.apple.webcontentfilter.dns"
+                                       "com.apple.server.bluetooth"
+                                       "com.apple.awacs"
+                                       "com.apple.blued"))
 
 ; Rules to allow the operations mDNSResponder needs start here
 
 (if (defined? 'system-socket)
     (allow system-socket))  ; To create raw sockets
 (allow sysctl-read)                    ; To get hardware model information
+(allow sysctl-write)           ; Needed for CFSocket
 (allow file-read-metadata)     ; Needed for dyld to work
 (allow ipc-posix-shm)          ; Needed for POSIX shared memory
 
 (allow file-read-data                 (regex #"^/System/Library/Preferences/com\.apple\.crypto\.plist$"))
 (allow file-read-data                 (regex #"^/System/Library/SystemConfiguration/PowerManagement\.bundle(/|$)"))
 (allow file-read-data                 (regex #"^/Library/Preferences/SystemConfiguration/com\.apple\.PowerManagement\.plist$"))
+(allow file-read-data                 (regex #"^/private/var/preferences/SystemConfiguration/preferences\.plist$"))
 
 ; Allow access to System Keychain
 (allow file-read-data                 (regex #"^/System/Library/Security$"))
 (allow file-read* file-write*         (regex #"^/private/var/tmp/mds/[0-9]+(/|$)"))
 (allow file-read-data                 (regex #"^/private/var/db/mds/"))
 (allow file-read* file-write*         (regex #"^/private/var/db/mds/[0-9]+(/|$)"))
-(allow file-read* file-write*         (regex #"^/private/var/folders/[^/]+/[^/]+/-Caches-/mds(/|$)"))
+(allow file-read* file-write*         (regex #"^/private/var/folders/[^/]+/[^/]+/C/mds(/|$)"))
+(allow file-read* file-write*         (regex #"^/private/var/folders/[^/]+/[^/]+/-Caches-/mds(/|$)")) ; Required on 10.5 and 10.6
 ; CRL Cache for SSL/TLS connections
 (allow file-read-data                 (regex #"^/private/var/db/crls/crlcache\.db$"))
+
+; For mDNS sleep proxy offload
+(allow iokit-open (iokit-user-client-class "NVEthernetUserClientMDNS"))
+(allow iokit-open (iokit-user-client-class "mDNSOffloadUserClient"))
+
+; For IOPMConnectionCreate
+(allow iokit-open (iokit-user-client-class "RootDomainUserClient"))
+
+; For D2D
+(allow file-read-data (regex #"^/System/Library/PrivateFrameworks/DeviceToDeviceManager.framework(/|$)"))
+(allow file-read-data (regex #"^/System/Library/PrivateFrameworks/MobileBluetooth.framework(/|$)"))
+(allow file-read-data (regex #"^/System/Library/Frameworks/CoreFoundation.framework(/|$)"))
+(allow file-read-data (regex #"^/System/Library/Frameworks/CoreServices.framework(/|$)"))
+(allow file-read-data (regex #"^/System/Library/Frameworks/SystemConfiguration.framework(/|$)"))
+(allow file-read-data (regex #"^/System/Library/Frameworks/IOKit.framework(/|$)"))
+(allow file-read-data (regex #"^/System/Library/Frameworks/Security.framework(/|$)"))
+(allow file-read-data file-write-data file-ioctl (regex #"^/dev/dtracehelper$"))
+
+; For WebFilterDNS framework
+(allow file-read-data (regex #"^/System/Library/PrivateFrameworks/WebFilterDNS.framework(/|$)"))
index bf25e008352b8b21969ba240b9e9e68d4b9b1ce4..81d5baff3ac6adc95232ec0e126152197f1c9093 100644 (file)
@@ -3,7 +3,7 @@
        archiveVersion = 1;
        classes = {
        };
-       objectVersion = 42;
+       objectVersion = 45;
        objects = {
 
 /* Begin PBXAggregateTarget section */
@@ -66,6 +66,8 @@
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
+               21E53F0F1219D1B3003EEE05 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21E53F0E1219D1B3003EEE05 /* CoreServices.framework */; };
+               21E53F141219D1CA003EEE05 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21E53F0E1219D1B3003EEE05 /* CoreServices.framework */; };
                2E0405F50C3195F700F13B59 /* helper.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405F40C3195F700F13B59 /* helper.c */; };
                2E0405F60C31961100F13B59 /* helpermsg.defs in Sources */ = {isa = PBXBuildFile; fileRef = 2E0405EB0C3190DC00F13B59 /* helpermsg.defs */; settings = {ATTRIBUTES = (Server, Client, ); COMPILER_FLAGS = "-Wno-error"; }; };
                2E0406150C3197CB00F13B59 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E0406140C3197CB00F13B59 /* libbsm.dylib */; };
                FFA5724A0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
                FFA5724B0AF18FCC0055A0F1 /* DNSServiceDiscovery.c in Sources */ = {isa = PBXBuildFile; fileRef = FFA572480AF18FCC0055A0F1 /* DNSServiceDiscovery.c */; };
                FFA572610AF190940055A0F1 /* DNSServiceDiscovery.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFA572600AF1908D0055A0F1 /* DNSServiceDiscovery.h */; };
-               FFA572640AF190C80055A0F1 /* dns_sd.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = FFA572630AF190C20055A0F1 /* dns_sd.h */; };
+               FFAE66F0105F0CD900162116 /* ddnswriteconfig in Resources */ = {isa = PBXBuildFile; fileRef = D284BEE80ADD80A70027CCDF /* ddnswriteconfig */; };
                FFB437150EB165BD00E17C68 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
                FFC22AA20B00F42A00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
                FFC22AA30B00F42B00BAB070 /* DNSServiceDiscoveryRequest.defs in Sources */ = {isa = PBXBuildFile; fileRef = 6575FC01022EAFBA00000109 /* DNSServiceDiscoveryRequest.defs */; };
                        remoteGlobalIDString = FFA572650AF190F10055A0F1;
                        remoteInfo = SystemLibraries;
                };
+               FFAE66F8105F0CF100162116 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = D284BEDB0ADD80A70027CCDF;
+                       remoteInfo = ddnswriteconfig;
+               };
                FFB7657C0AEED97F00583A2C /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               FF93944E0AF193B900C5D655 /* CopyFiles */ = {
-                       isa = PBXCopyFilesBuildPhase;
-                       buildActionMask = 8;
-                       dstPath = /usr/include;
-                       dstSubfolderSpec = 0;
-                       files = (
-                               FFA572640AF190C80055A0F1 /* dns_sd.h in CopyFiles */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 1;
-               };
                FFA572500AF190070055A0F1 /* CopyFiles */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mDNSMacOSX.h; sourceTree = "<group>"; };
                00CA213D02786FC30CCA2C71 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
                09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
+               21E53F0E1219D1B3003EEE05 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = "<absolute>"; };
+               21F432971134AA6800581B69 /* WebFilterDNS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebFilterDNS.framework; path = /System/Library/PrivateFrameworks/WebFilterDNS.framework; sourceTree = "<absolute>"; };
                2E0405EB0C3190DC00F13B59 /* helpermsg.defs */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.mig; path = helpermsg.defs; sourceTree = "<group>"; };
                2E0405F00C31955500F13B59 /* mDNSResponderHelper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponderHelper; sourceTree = BUILT_PRODUCTS_DIR; };
                2E0405F40C3195F700F13B59 /* helper.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = helper.c; sourceTree = "<group>"; };
                2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "helper-stubs.c"; sourceTree = "<group>"; };
                2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "helpermsg-types.h"; sourceTree = "<group>"; };
                2EDC5E720C39EA640092701B /* helper-server.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "helper-server.h"; sourceTree = "<group>"; };
+               4A2E69DD0F5475A3004A87B0 /* uds_daemon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = uds_daemon.h; path = ../mDNSShared/uds_daemon.h; sourceTree = SOURCE_ROOT; };
+               4A3600DF0F34F8CD00453EFB /* DeviceToDeviceManager.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DeviceToDeviceManager.framework; path = /System/Library/PrivateFrameworks/DeviceToDeviceManager.framework; sourceTree = "<absolute>"; };
                4A8202510C56C36500DDFD48 /* ipsec_strerror.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ipsec_strerror.h; sourceTree = "<group>"; };
                4A8202520C56C36500DDFD48 /* libpfkey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libpfkey.h; sourceTree = "<group>"; };
                4A8202530C56C36600DDFD48 /* pfkey.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pfkey.c; sourceTree = "<group>"; };
                4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mDNSResponderHelper.8; sourceTree = SOURCE_ROOT; };
+               4ADB5F230F6AB9F400B95BF3 /* helper-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "helper-entitlements.plist"; sourceTree = "<group>"; };
                4AE9B0480F39448B0080B59D /* safe_vproc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = safe_vproc.c; sourceTree = "<group>"; };
                4AE9B0490F39448B0080B59D /* safe_vproc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = safe_vproc.h; sourceTree = "<group>"; };
                654BE64F02B63B93000001D1 /* mDNSEmbeddedAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mDNSEmbeddedAPI.h; path = ../mDNSCore/mDNSEmbeddedAPI.h; sourceTree = "<group>"; };
                D284BED90ADD80A20027CCDF /* dnsextd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnsextd; sourceTree = BUILT_PRODUCTS_DIR; };
                D284BEE80ADD80A70027CCDF /* ddnswriteconfig */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ddnswriteconfig; sourceTree = BUILT_PRODUCTS_DIR; };
                D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Bonjour.prefPane; sourceTree = BUILT_PRODUCTS_DIR; };
-               D284C04D0ADD95D30027CCDF /* Info-PreferencePane.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = "Info-PreferencePane.plist"; path = "PreferencePane/Info-PreferencePane.plist"; sourceTree = "<group>"; };
+               D284C04D0ADD95D30027CCDF /* Info-PreferencePane.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "Info-PreferencePane.plist"; path = "PreferencePane/Info-PreferencePane.plist"; sourceTree = "<group>"; };
                DB2CC4430662DD1100335AB3 /* BaseListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = BaseListener.java; path = ../mDNSShared/Java/BaseListener.java; sourceTree = SOURCE_ROOT; };
                DB2CC4440662DD1100335AB3 /* BrowseListener.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = BrowseListener.java; path = ../mDNSShared/Java/BrowseListener.java; sourceTree = SOURCE_ROOT; };
                DB2CC4450662DD1100335AB3 /* DNSRecord.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; name = DNSRecord.java; path = ../mDNSShared/Java/DNSRecord.java; sourceTree = SOURCE_ROOT; };
                                D284BE660ADD80740027CCDF /* SystemConfiguration.framework in Frameworks */,
                                D284BE670ADD80740027CCDF /* IOKit.framework in Frameworks */,
                                D284BE680ADD80740027CCDF /* Security.framework in Frameworks */,
+                               21E53F0F1219D1B3003EEE05 /* CoreServices.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                D284BE8E0ADD80800027CCDF /* SystemConfiguration.framework in Frameworks */,
                                D284BE8F0ADD80800027CCDF /* IOKit.framework in Frameworks */,
                                D284BE900ADD80800027CCDF /* Security.framework in Frameworks */,
+                               21E53F141219D1CA003EEE05 /* CoreServices.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                FFFB0DA407B43BED00B88D48 /* PreferencePane */,
                                08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
                                19C28FBDFE9D53C911CA2CBB /* Products */,
+                               21E53F0E1219D1B3003EEE05 /* CoreServices.framework */,
                        );
                        name = mDNSResponder;
                        sourceTree = "<group>";
                08FB7795FE84155DC02AAC07 /* mDNS Server Sources */ = {
                        isa = PBXGroup;
                        children = (
+                               4ADB5F230F6AB9F400B95BF3 /* helper-entitlements.plist */,
+                               4A2E69DD0F5475A3004A87B0 /* uds_daemon.h */,
                                4AE9B0480F39448B0080B59D /* safe_vproc.c */,
                                4AE9B0490F39448B0080B59D /* safe_vproc.h */,
                                4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */,
                08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
                        isa = PBXGroup;
                        children = (
+                               4A3600DF0F34F8CD00453EFB /* DeviceToDeviceManager.framework */,
                                2E8165F60C59835F00485EB2 /* libipsec.dylib */,
                                65713D46025A293200000109 /* SystemConfiguration.framework */,
                                2E0406140C3197CB00F13B59 /* libbsm.dylib */,
                                DB2CC4680662DFF500335AB3 /* JavaVM.framework */,
                                FF2609FA07B4433800CE10E5 /* Cocoa.framework */,
                                FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */,
+                               21F432971134AA6800581B69 /* WebFilterDNS.framework */,
                        );
                        name = "External Frameworks and Libraries";
                        sourceTree = "<group>";
                        buildRules = (
                        );
                        dependencies = (
+                               FFAE66F9105F0CF100162116 /* PBXTargetDependency */,
                        );
                        name = PreferencePane;
                        productInstallPath = "${SYSTEM_LIBRARY_DIR}/PreferencePanes";
                                FFB765810AEED9C700583A2C /* Sources */,
                                FFB765820AEED9C700583A2C /* Frameworks */,
                                FFA572500AF190070055A0F1 /* CopyFiles */,
-                               FF93944E0AF193B900C5D655 /* CopyFiles */,
+                               21DE714D115831CB00DD4BD1 /* ShellScript */,
                        );
                        buildRules = (
                        );
                08FB7793FE84155DC02AAC07 /* Project object */ = {
                        isa = PBXProject;
                        buildConfigurationList = D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */;
-                       compatibilityVersion = "Xcode 2.4";
+                       compatibilityVersion = "Xcode 3.1";
                        hasScannedForEncodings = 1;
                        mainGroup = 08FB7794FE84155DC02AAC07 /* mDNSResponder */;
                        projectDirPath = "";
                                D284BEF90ADD80B00027CCDF /* InfoPlist.strings in Resources */,
                                D284BEFB0ADD80B00027CCDF /* inprogress.tiff in Resources */,
                                D284BEFC0ADD80B00027CCDF /* installtool in Resources */,
+                               FFAE66F0105F0CD900162116 /* ddnswriteconfig in Resources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        shellPath = /bin/sh;
                        shellScript = "if [ -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/lib/libipsec.dylib\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/ipsec_options.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nelse\necho \"#define MDNS_NO_IPSEC 1\" > ${CONFIGURATION_TEMP_DIR}/ipsec_options.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libipsec.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n";
                };
+               21DE714D115831CB00DD4BD1 /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       inputPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/sh;
+                       shellScript = "sed 's/\\(^#define _DNS_SD_LIBDISPATCH \\)0$/\\1 1/' \"$SRCROOT/../mDNSShared/dns_sd.h\" > \"$DSTROOT/usr/include/dns_sd.h\"";
+               };
                D284BE510ADD80740027CCDF /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/Frameworks/IOKit.framework/PrivateHeaders/pwr_mgt/IOPMLibPrivate.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/IOKit\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt\"\ntouch \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt/IOPMLibPrivate.h\"\nfi\n";
+                       shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/Frameworks/IOKit.framework/PrivateHeaders/pwr_mgt/IOPMLibPrivate.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/IOKit\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt\"\ntouch \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt/IOPMLibPrivate.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/DeviceToDeviceManager.framework/Headers/DeviceToDeviceManager.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\necho \"#define NO_D2D 1\" > \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager/DeviceToDeviceManager.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/WebFilterDNS.framework/Headers/WebFilterDNS.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS\"\necho \"#define NO_WCF 1\" > \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS/WebFilterDNS.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/local/include/AWACS.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nelse\necho \"#define NO_AWACS 1\" > \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfi\n";
                };
                D284BE6C0ADD80740027CCDF /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        files = (
                        );
                        runOnlyForDeploymentPostprocessing = 1;
-                       shellPath = /bin/tcsh;
-                       shellScript = "# Install mDNSResponder.bundle containing language localizations\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices\ncp -R ${SRCROOT}/mDNSResponder-bundle ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle\n\n# Remove unwanted CVS directories\nfind ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -depth -name CVS -exec rm -rf {} \\;\n\n# Expand UTF-8 files to UTF-16 (at one time this appeared to be necessary, but it's not, so we don't do it any more)\n#foreach file (`find ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -name Localizable.strings`)\n#iconv -f utf-8 -t utf-16 ${file} > ${file}.new\n#mv -f ${file}.new ${file}\n#end\n\n# Remove French localization (not wanted for Apple B&I builds)\nrm -rf ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle/Resources/French.lproj\n\n# Copy Sandbox profile, stripping initial license header to make the file fit in the ~16kB Sandbox profile limit\n(umask 022; mkdir -p -m 0755 ${DSTROOT}/usr/share/sandbox)\n(umask 222; awk '/^\\(version 1\\)$/,EOF' ${SRCROOT}/mDNSResponder.sb > ${DSTROOT}/usr/share/sandbox/mDNSResponder.sb)\n";
+                       shellPath = /bin/bash;
+                       shellScript = "# Install mDNSResponder.bundle containing language localizations\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices\ncp -R ${SRCROOT}/mDNSResponder-bundle ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle\n\n# Remove unwanted CVS directories\nfind ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -depth -name CVS -exec rm -rf {} \\;\n\n# Expand UTF-8 files to UTF-16 (at one time this appeared to be necessary, but it's not, so we don't do it any more)\n#foreach file (`find ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -name Localizable.strings`)\n#iconv -f utf-8 -t utf-16 ${file} > ${file}.new\n#mv -f ${file}.new ${file}\n#end\n\n# Remove French localization (not wanted for Apple B&I builds)\nrm -rf ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle/Resources/French.lproj\n";
                };
                D284BE760ADD80800027CCDF /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/Frameworks/IOKit.framework/PrivateHeaders/pwr_mgt/IOPMLibPrivate.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/IOKit\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt\"\ntouch \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt/IOPMLibPrivate.h\"\nfi\n";
+                       shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/Frameworks/IOKit.framework/PrivateHeaders/pwr_mgt/IOPMLibPrivate.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/IOKit\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt\"\ntouch \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt/IOPMLibPrivate.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/DeviceToDeviceManager.framework/Headers/DeviceToDeviceManager.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\necho \"#define NO_D2D 1\" > \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager/DeviceToDeviceManager.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/WebFilterDNS.framework/Headers/WebFilterDNS.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS\"\necho \"#define NO_WCF 1\" > \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS/WebFilterDNS.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/local/include/AWACS.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nelse\necho \"#define NO_AWACS 1\" > \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfi";
                };
                FF045B6A0C7E4AA600448140 /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        outputPaths = (
                        );
                        runOnlyForDeploymentPostprocessing = 1;
-                       shellPath = /bin/tcsh;
-                       shellScript = "# Install plists to tell launchd how to start mDNSResponder and mDNSResponderHelper\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\n\nif (${MACOSX_DEPLOYMENT_TARGET} == \"10.4\") then\ncp ${SRCROOT}/LaunchDaemonInfo-Tiger.plist        ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponder.plist\ncp ${SRCROOT}/LaunchDaemonInfo-Tiger.helper.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponderHelper.plist\nelse\ncp ${SRCROOT}/LaunchDaemonInfo.plist              ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponder.plist\ncp ${SRCROOT}/LaunchDaemonInfo.helper.plist       ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponderHelper.plist\nendif\n";
+                       shellPath = /bin/sh;
+                       shellScript = "# Install plists to tell launchd how to start mDNSResponder and mDNSResponderHelper\n\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons\n\nif [ \"${MACOSX_DEPLOYMENT_TARGET}\" == \"10.4\" ] ; then\ncp ${SRCROOT}/LaunchDaemonInfo-Tiger.plist        ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponder.plist\ncp ${SRCROOT}/LaunchDaemonInfo-Tiger.helper.plist ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponderHelper.plist\nelse\ncp ${SRCROOT}/LaunchDaemonInfo.plist              ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponder.plist\ncp ${SRCROOT}/LaunchDaemonInfo.helper.plist       ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponderHelper.plist\nfi\n\nif [ ! -z \"${IPHONEOS_DEPLOYMENT_TARGET}\" ] ; then\nplutil -convert binary1 ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponder.plist\nplutil -convert binary1 ${DSTROOT}${SYSTEM_LIBRARY_DIR}/LaunchDaemons/com.apple.mDNSResponderHelper.plist\nfi\n\n\n# Install Sandbox profile\n\nif [ ! -z \"${IPHONEOS_DEPLOYMENT_TARGET}\" ] ; then\n  SANDBOXDST=\"${DSTROOT}/usr/local/share/sandbox/profiles/embedded/builtin\"\nelse\n  SANDBOXDST=\"${DSTROOT}/usr/share/sandbox\"\nfi\n\n(umask 022; mkdir -p -m 0755 \"$SANDBOXDST\")\n\nif [[ \"${MACOSX_DEPLOYMENT_TARGET}\" == 10.[0-6] ]] ; then\n  sed '/iokit-open/d' \"${SRCROOT}/mDNSResponder.sb\" > \"${SANDBOXDST}/mDNSResponder.sb\"\nelse\n  cp \"${SRCROOT}/mDNSResponder.sb\" \"${SANDBOXDST}/mDNSResponder.sb\"\nfi\n";
                };
                FF37FAAD0BC581780044A5CF /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        target = FFA572650AF190F10055A0F1 /* SystemLibraries */;
                        targetProxy = FFA572700AF191230055A0F1 /* PBXContainerItemProxy */;
                };
+               FFAE66F9105F0CF100162116 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = D284BEDB0ADD80A70027CCDF /* ddnswriteconfig */;
+                       targetProxy = FFAE66F8105F0CF100162116 /* PBXContainerItemProxy */;
+               };
                FFB7657D0AEED97F00583A2C /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 00AD62BB032D7A0C0CCA2C71 /* Build More */;
                2E0405F20C31955500F13B59 /* Development */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = "helper-entitlements.plist";
                                CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
                                CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)";
                                COPY_PHASE_STRIP = NO;
                                INSTALL_PATH = /usr/sbin;
                                LD_MAP_FILE_PATH = "$(TARGET_TEMP_DIR)/$(PRODUCT_NAME)-LinkMap-$(CURRENT_VARIANT)-$(CURRENT_ARCH).txt";
                                LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
-                               MACOSX_DEPLOYMENT_TARGET = 10.4;
+                               MACOSX_DEPLOYMENT_TARGET = 10.5;
+                               "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = (
+                                       "$(inherited)",
+                                       "-mthumb",
+                               );
                                OTHER_LDFLAGS = (
                                        "$(inherited)",
                                        "-lipsec",
                                CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
                                DEAD_CODE_STRIPPING = YES;
                                GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "_DNS_SD_LIBDISPATCH=1",
                                        "APPLE_OSX_mDNSResponder=1",
                                        "__MigTypeCheck=1",
                                        "mDNSResponderVersion=${MVERS}",
                        buildSettings = {
                                CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
                                CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
-                               FRAMEWORK_SEARCH_PATHS = "";
+                               FRAMEWORK_SEARCH_PATHS = (
+                                       "$(inherited)",
+                                       "\"$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"",
+                               );
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                );
                                INSTALL_PATH = /usr/sbin;
                                LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
-                               MACOSX_DEPLOYMENT_TARGET = 10.4;
+                               MACOSX_DEPLOYMENT_TARGET = 10.5;
                                ORDER_FILE = "${SRCROOT}/mDNSResponder.order";
                                OTHER_CFLAGS = (
                                        "$(inherited)",
                                        "-no-cpp-precomp",
                                );
-                               OTHER_LDFLAGS = "-ldnsinfo";
+                               "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = (
+                                       "$(inherited)",
+                                       "-mthumb",
+                               );
+                               OTHER_LDFLAGS = "";
+                               "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
+                                       "-weak_framework",
+                                       DeviceToDeviceManager,
+                               );
+                               "OTHER_LDFLAGS[sdk=macosx10.6][arch=*]" = "-lAWACS";
+                               "OTHER_LDFLAGS[sdk=macosx10.7][arch=*]" = (
+                                       "-lAWACS",
+                                       "-weak_framework",
+                                       WebFilterDNS,
+                                       "-weak_framework",
+                                       DeviceToDeviceManager,
+                               );
                                OTHER_REZFLAGS = "";
                                PRODUCT_NAME = mDNSResponder;
                                REZ_EXECUTABLE = YES;
                        buildSettings = {
                                CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
                                CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
-                               FRAMEWORK_SEARCH_PATHS = "";
+                               FRAMEWORK_SEARCH_PATHS = (
+                                       "$(inherited)",
+                                       "\"$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"",
+                               );
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_ENABLE_FIX_AND_CONTINUE = YES;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                        "${CONFIGURATION_TEMP_DIR}",
                                );
                                LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
-                               MACOSX_DEPLOYMENT_TARGET = 10.4;
+                               MACOSX_DEPLOYMENT_TARGET = 10.5;
                                OTHER_CFLAGS = (
                                        "$(inherited)",
                                        "-no-cpp-precomp",
                                );
-                               OTHER_LDFLAGS = "-ldnsinfo";
+                               OTHER_LDFLAGS = "";
+                               "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
+                                       "-weak_framework",
+                                       DeviceToDeviceManager,
+                               );
+                               "OTHER_LDFLAGS[sdk=macosx10.6][arch=*]" = "-lAWACS";
+                               "OTHER_LDFLAGS[sdk=macosx10.7][arch=*]" = (
+                                       "-lAWACS",
+                                       "-weak_framework",
+                                       WebFilterDNS,
+                                       "-weak_framework",
+                                       DeviceToDeviceManager,
+                               );
                                OTHER_REZFLAGS = "";
                                PRODUCT_NAME = mDNSResponder.debug;
                                REZ_EXECUTABLE = YES;
                                GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                INSTALL_PATH = /usr/bin;
-                               MACOSX_DEPLOYMENT_TARGET = 10.4;
                                OTHER_CFLAGS = "-no-cpp-precomp";
                                OTHER_LDFLAGS = "";
                                OTHER_REZFLAGS = "";
                                        "-no-cpp-precomp",
                                        "-UAPPLE_OSX_mDNSResponder",
                                );
-                               OTHER_LDFLAGS = "-ldnsinfo";
+                               OTHER_LDFLAGS = "";
                                OTHER_REZFLAGS = "";
                                PRODUCT_NAME = dnsextd;
                                REZ_EXECUTABLE = YES;
                D284BEE60ADD80A70027CCDF /* Development */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
                                CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
                                CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                INSTALL_PATH = "/Library/Application Support/Bonjour";
-                               MACOSX_DEPLOYMENT_TARGET = "";
+                               MACOSX_DEPLOYMENT_TARGET = 10.5;
                                OTHER_CFLAGS = "";
                                OTHER_LDFLAGS = "";
                                OTHER_REZFLAGS = "";
                D284BF090ADD80B00027CCDF /* Development */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
                                CONFIGURATION_BUILD_DIR = "${BUILD_DIR}";
                                CONFIGURATION_TEMP_DIR = "${BUILD_DIR}/mDNSResponder.build";
                                EXPORTED_SYMBOLS_FILE = "";
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               GCC_ENABLE_OBJC_GC = supported;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_SYMBOLS_PRIVATE_EXTERN = NO;
                                INFOPLIST_FILE = "PreferencePane/Info-PreferencePane.plist";
                                INSTALL_PATH = /AppleInternal/Library/PreferencePanes;
-                               MACOSX_DEPLOYMENT_TARGET = "";
+                               MACOSX_DEPLOYMENT_TARGET = 10.5;
                                OTHER_CFLAGS = "";
                                OTHER_LDFLAGS = "-twolevel_namespace";
                                OTHER_REZFLAGS = "";
                                        "$(inherited)",
                                        "__DARWIN_NON_CANCELABLE=1",
                                );
+                               HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/";
                                INSTALL_PATH = /usr/local/lib/system;
                                PRODUCT_NAME = dns_sd_debug;
                        };
                                        "__DARWIN_NON_CANCELABLE=1",
                                );
                                GENERATE_PROFILING_CODE = YES;
+                               HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/";
                                INSTALL_PATH = /usr/local/lib/system;
                                PRODUCT_NAME = dns_sd_profile;
                        };
                                        "$(inherited)",
                                        "__DARWIN_NON_CANCELABLE=1",
                                );
+                               HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/";
+                               INSTALLHDRS_COPY_PHASE = YES;
+                               INSTALLHDRS_SCRIPT_PHASE = YES;
                                INSTALL_PATH = /usr/local/lib/system;
                                PRODUCT_NAME = dns_sd;
                        };
index 8bb2cf8e4891b6efcc5f95d1b2d7e54e382e8544..6e959dbd3362837778ef559dd23d5044a8fef8d3 100644 (file)
 .\" See the License for the specific language governing permissions and
 .\" limitations under the License.
 .\"
-.\" $Log: mDNSResponderHelper.8,v $
-.\" Revision 1.1  2007/08/08 22:34:59  mcguire
-.\" <rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
-.\"
-.\"
-.\"
 .Dd August 2007             \" Date
 .Dt mDNSResponderHelper 8   \" Document Title
 .Os Darwin                  \" Operating System
index 09448102e4ba5cf821c07d39f9b9aeb57767c249..9d7541470513ac4aa1bee15e6ac9a18ed3922a37 100644 (file)
 #include <string.h>
 #include <errno.h>
 #include <stdio.h>
+#include <TargetConditionals.h>
 
 #include "ipsec_strerror.h"
 #include "libpfkey.h"
 #include "ipsec_options.h"
 
+#if TARGET_OS_EMBEDDED
+#ifndef MDNS_NO_IPSEC
+#define MDNS_NO_IPSEC 1
+#endif
+#endif
+
 #ifndef MDNS_NO_IPSEC
 
 #define CALLOC(size, cast) (cast)calloc(1, (size))
index eaf41c90da83da6c12fe84de8a63983a30970bef..a6b737eb65d9d43838a8de9d6479104068eba27f 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: safe_vproc.c,v $
-Revision 1.3  2009/02/14 00:09:53  cheshire
-Only log "Compiled without vproc_transaction support" when running on a system
-where we expect that to be available -- if running on a system that doesn't even
-have vproc_transaction, then it doesn't matter that the code was compiled without it.
-
-Revision 1.2  2009/02/09 21:16:17  mcguire
-<rdar://problem/5858533> Adopt vproc_transaction API in mDNSResponder
-additional cleanup: don't alloc memory since we currently only expect to have one transaction
-
-Revision 1.1  2009/02/06 03:06:49  mcguire
-<rdar://problem/5858533> Adopt vproc_transaction API in mDNSResponder
-
  */
 
 #include <stdlib.h>
@@ -36,8 +20,9 @@ Revision 1.1  2009/02/06 03:06:49  mcguire
 #include <vproc.h>
 #include "safe_vproc.h"
 #include "mDNSDebug.h"
+#include <TargetConditionals.h>
 
-#ifdef VPROC_HAS_TRANSACTIONS
+#if defined(VPROC_HAS_TRANSACTIONS) && !TARGET_OS_EMBEDDED
 
 static vproc_transaction_t transaction = NULL;
 
@@ -61,6 +46,7 @@ void safe_vproc_transaction_end(void)
 
 #else
 
+#if ! TARGET_OS_EMBEDDED
 #include <stdio.h>
 #include <CoreFoundation/CFString.h>
 
@@ -87,6 +73,12 @@ void safe_vproc_transaction_begin(void)
                }
        }
 
+#else
+
+void safe_vproc_transaction_begin(void) { }
+
+#endif
+
 void safe_vproc_transaction_end(void) { }
 
 #endif
index 79932d1c646f03206643ed7e29b4c1832929cbab..49ec2191f46bc0f7e709bee5d1a8ea196c177e12 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: safe_vproc.h,v $
-Revision 1.1  2009/02/06 03:06:49  mcguire
-<rdar://problem/5858533> Adopt vproc_transaction API in mDNSResponder
-
  */
 
 #ifndef __SAFE_VPROC_H
index bd6137da9cf950d4958c17bd905b453d57a1c4ed..c21b1eebee4a01c9ac1f2d4a2595695b645b8eea 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: Client.c,v $
-Revision 1.21  2008/11/04 19:46:01  cheshire
-Updated comment about MAX_ESCAPED_DOMAIN_NAME size (should be 1009, not 1005)
-
-Revision 1.20  2007/07/27 19:30:41  cheshire
-Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
-to properly reflect tri-state nature of the possible responses
-
-Revision 1.19  2007/04/16 20:49:39  cheshire
-Fix compile errors for mDNSPosix build
-
-Revision 1.18  2006/08/14 23:24:46  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.17  2006/06/12 18:22:42  cheshire
-<rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
-
-Revision 1.16  2005/02/04 01:00:53  cheshire
-Add '-d' command-line option to specify domain to browse
-
-Revision 1.15  2004/12/16 20:17:11  cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.14  2004/11/30 22:37:00  cheshire
-Update copyright dates and add "Mode: C; tab-width: 4" headers
-
-Revision 1.13  2004/10/19 21:33:20  cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
-doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
-
-Revision 1.12  2004/09/17 01:08:53  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.11  2003/11/17 20:14:32  cheshire
-Typo: Wrote "domC" where it should have said "domainC"
-
-Revision 1.10  2003/11/14 21:27:09  cheshire
-<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
-Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1009) instead of 256-byte buffers.
-
-Revision 1.9  2003/08/14 02:19:55  cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
-
-Revision 1.8  2003/08/12 19:56:26  cheshire
-Update to APSL 2.0
-
-Revision 1.7  2003/07/02 21:19:58  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.6  2003/06/18 05:48:41  cheshire
-Fix warnings
-
-Revision 1.5  2003/05/06 00:00:50  cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
-
-Revision 1.4  2002/12/23 22:13:31  jgraessl
-
-Reviewed by: Stuart Cheshire
-Initial IPv6 support for mDNSResponder.
-
-Revision 1.3  2002/09/21 20:44:53  zarzycki
-Added APSL info
-
-Revision 1.2  2002/09/19 04:20:44  cheshire
-Remove high-ascii characters that confuse some systems
-
-Revision 1.1  2002/09/17 06:24:35  cheshire
-First checkin
-
-*/
+ */
 
 #include <assert.h>
 #include <signal.h>
index 15bb86ad793187e5d8f4a75a5bfe484ff6b05754..e05b541331947665f3573bc49c7f3da6feea05f2 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: ExampleClientApp.c,v $
-Revision 1.14  2006/08/14 23:24:46  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.13  2006/02/23 23:38:43  cheshire
-<rdar://problem/4427969> On FreeBSD 4 "arpa/inet.h" requires "netinet/in.h" be included first
-
-Revision 1.12  2004/11/30 22:37:00  cheshire
-Update copyright dates and add "Mode: C; tab-width: 4" headers
-
-Revision 1.11  2004/09/17 01:08:53  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.10  2004/09/16 01:58:22  cheshire
-Fix compiler warnings
-
-Revision 1.9  2003/08/12 19:56:26  cheshire
-Update to APSL 2.0
-
-Revision 1.8  2003/07/02 21:19:58  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.7  2003/06/18 05:48:41  cheshire
-Fix warnings
-
-Revision 1.6  2003/03/31 22:44:36  cheshire
-Add log header
-
  */
 
 #include <stdio.h>                     // For printf()
index 3438260c5ec5aeb3cbe609e83989b4bd0306fd64..ab643af3604982264be8575d45664bab5c410638 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: ExampleClientApp.h,v $
-Revision 1.7  2006/08/14 23:24:46  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.6  2004/11/30 22:37:00  cheshire
-Update copyright dates and add "Mode: C; tab-width: 4" headers
-
-Revision 1.5  2003/08/12 19:56:26  cheshire
-Update to APSL 2.0
-
-Revision 1.4  2003/07/02 21:19:58  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.3  2003/03/31 22:49:35  cheshire
-Add "$Log" header
-
  */
 
 extern void ExampleClientEventLoop(mDNS *const m);
index c2a033fe8592fa7a2d6699ce45451499eb79cbfa..df83b8eb17511a4ed77898bc857acb062e5fc8dc 100644 (file)
  * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
  * understand why variable y is not of type "char*" just proves the point that poor code
  * layout leads people to unfortunate misunderstandings about how the C language really works.)
-
-    Change History (most recent first):
-
-$Log: Identify.c,v $
-Revision 1.44  2009/01/13 05:31:34  mkrochma
-<rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
-
-Revision 1.43  2008/09/05 22:51:21  cheshire
-Minor cleanup to bring code in sync with TOT, and make "_services" metaquery work again
-
-Revision 1.42  2007/07/27 19:30:41  cheshire
-Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
-to properly reflect tri-state nature of the possible responses
-
-Revision 1.41  2007/04/16 20:49:39  cheshire
-Fix compile errors for mDNSPosix build
-
-Revision 1.40  2007/02/28 01:51:22  cheshire
-Added comment about reverse-order IP address
-
-Revision 1.39  2007/01/05 08:30:51  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.38  2007/01/04 20:57:48  cheshire
-Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
-
-Revision 1.37  2006/10/27 01:32:08  cheshire
-Set ReturnIntermed to mDNStrue
-
-Revision 1.36  2006/08/14 23:24:46  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.35  2006/06/12 18:22:42  cheshire
-<rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
-
-*/
+ */
 
 //*************************************************************************************************************
 // Incorporate mDNS.c functionality
index 82e78b03a06ea9abfea45a1c49ba7ababbdf8609..9390f72ee1f6fb442e104f743f60ba82cbbb3eb5 100755 (executable)
 # If "make os=xxx" gives lots of errors like "Missing dependency operator",
 # then try typing "gmake os=xxx" instead.
 #
-# $Log: Makefile,v $
-# Revision 1.83  2009/02/02 19:44:06  cheshire
-# Use "-fwrapv" option to tell compiler that the code is written assuming that
-# signed arithmetic is implemented using the twos-complement representation
-# (this is pretty much universally true on today's processors).
-# <http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Code-Gen-Options.html>
-# Without this option, gcc may decide that because the C language
-# does not require processors to use twos-complement representation, that means
-# gcc is free to do some "creative" optimizations that don't preserve the overflow
-# behaviour of twos-complement arithmetic. See also "-fstrict-overflow":
-# <http://gcc.gnu.org/onlinedocs/gcc-4.2.1/gcc/Optimize-Options.html>
-#
-# Revision 1.82  2009/01/12 22:48:00  cheshire
-# Don't need to include "." in the "#include" search path
-#
-# Revision 1.81  2009/01/11 03:20:06  mkrochma
-# <rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris
-#
-# Revision 1.80  2008/11/03 23:27:51  cheshire
-# Defined __MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 to stop build failures on Leopard
-#
-# Revision 1.79  2008/10/24 01:59:59  mcguire
-# <rdar://problem/6257159> Build Failure: Need to stop using Jam
-#
-# Revision 1.78  2007/10/22 20:16:49  cheshire
-# Got rid of jaguar and panther from list of target platforms;
-# changed "os=tiger" to "os=x" (which works with both Tiger and Leopard)
-#
-# Revision 1.77  2007/10/22 20:04:51  cheshire
-# Need to include PlatformCommon.c.o in embedded targets
-#
-# Revision 1.76  2007/07/31 23:39:02  mcguire
-# Don't bail on errors in flex-generated .c files
-#
-# Revision 1.75  2006/08/24 22:41:23  herscher
-# <rdar://problem/4580067> POSIX: dnsextd_parser doesn't compile on Linux
-#
-# Revision 1.74  2006/08/14 23:07:11  cheshire
-# Added "tab-width" emacs header line
-#
-# Revision 1.73  2006/07/07 00:54:08  cheshire
-# <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-# Put intermediate files into "objects" folder instead of mDNSShared source code folder
-#
-# Revision 1.72  2006/07/05 23:53:58  cheshire
-# <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-#
-# Revision 1.71  2006/06/20 23:07:04  rpantos
-# <rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
-#
-# Revision 1.70  2006/05/03 23:35:10  cheshire
-# Add missing dependency: NetMonitor.c textually imports mDNS.c
-#
-# Revision 1.69  2006/02/26 23:18:50  cheshire
-# <rdar://problem/4427969> FreeBSD 4 requires "-pthread" option to compile threaded code
-#
-# Revision 1.68  2006/02/26 01:36:54  cheshire
-# Rename the poorly named "LIBFLAGS" as "LINKOPTS"
-#
-# Revision 1.67  2006/02/25 23:14:29  cheshire
-# Add comment suggesting using "gmake" command
-#
-# Revision 1.66  2006/01/06 01:06:17  cheshire
-# <rdar://problem/3978979> Compile library and client programs in one pass
-#
-# Revision 1.65  2005/12/21 21:15:57  cheshire
-# Add missing dependency: Identify.c textually imports mDNS.c
-#
-# Revision 1.64  2005/10/25 23:55:47  cheshire
-# Add tiger to list of target platforms
-#
-# Revision 1.63  2005/10/11 21:30:44  cheshire
-# Add "-Wunreachable-code" (commented out for now)
-#
-# Revision 1.62  2005/06/30 21:46:55  cheshire
-# <rdar://problem/4167287> Solaris should use unix domain sockets, not loopback
-#
-# Revision 1.61  2005/06/30 20:46:05  cheshire
-# Added Makefile rule to build threadsafe object files where necessary using "-D_REENTRANT".
-#
-# Revision 1.60  2005/06/30 10:42:38  cheshire
-# Turn on "-Werror" and "-O" for better error reporting
-#
-# Revision 1.59  2005/04/14 21:07:10  rpantos
-# Bug #: 4089257, Clean build broken for Java support on POSIX
-# Submitted by: Roger Pantos
-# Reviewed by: Kiren Sekar
-#
-# Revision 1.58  2005/04/08 21:37:57  ksekar
-# <rdar://problem/3792767> get_ifi_info doesn't return IPv6 interfaces on Linux
-#
-# Revision 1.57  2005/03/17 04:02:28  cheshire
-# <rdar://problem/3986419> mDNSResponder won't compile with gcc4 on Tiger
-# Changed Makefile to link using gcc instead of libtool
-#
-# Revision 1.56  2005/02/02 02:25:21  cheshire
-# <rdar://problem/3980388> /var/run/mDNSResponder should be /var/run/mdnsd on Linux
-#
-# 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
-#
-# Revision 1.52  2004/12/01 19:46:12  cheshire
-# Add install case for Suse 9 (rc*.d directories *inside* the init.d directory)
-#
-# Revision 1.51  2004/12/01 03:30:29  cheshire
-# <rdar://problem/3889346> Add Unicast DNS support to mDNSPosix
-#
-# Revision 1.50  2004/12/01 01:14:20  cheshire
-# Add $(LIBFLAGS) to cc command to build dnsextd (required for Solaris)
-#
-# Revision 1.49  2004/11/11 01:44:52  cheshire
-# Updated error message
-#
-# Revision 1.48  2004/10/06 02:22:19  cheshire
-# Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
-#
-# Revision 1.47  2004/10/01 22:15:54  rpantos
-# rdar://problem/3824265: Replace APSL in client lib with BSD license.
-#
-# Revision 1.46  2004/09/24 21:15:25  cheshire
-# <rdar://problem/3724985> Library "libmdns" misnamed; should be "libdns_sd"
-#
-# Revision 1.45  2004/09/22 16:23:41  cheshire
-# Modify installation for compatibility with Gentoo Linux
-# (Thanks to David Black for this information)
-#
-# Revision 1.44  2004/09/17 01:08:53  cheshire
-# Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-#   The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-#   declared in that file are ONLY appropriate to single-address-space embedded applications.
-#   For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-#
-# Revision 1.43  2004/09/17 00:30:11  cheshire
-# Added some '@' signs to make build output less verbose --
-# when there's too much on the screen it's easy to miss build errors and warnings
-#
-# Revision 1.42  2004/08/24 22:04:37  cheshire
-# Need to specify -lpthread for building dnsextd
-#
-# Revision 1.41  2004/08/11 00:43:26  ksekar
-# <rdar://problem/3722542>: DNS Extension daemon for DNS Update Lease
-#
-# Revision 1.40  2004/07/08 21:45:55  cheshire
-# Make nss_mdns only build on Linux. We can add it to other targets (Solaris,
-# FreeBSD, etc., as we verify them). In particular, NSS is NOT supported on
-# OS X, so including it for "os=jaguar" or "os=panther" broke those builds.
-#
-# Revision 1.39  2004/06/29 03:34:28  cheshire
-# Add 'dot-local' Name Service Switch support from Andrew White at NICTA
-#
-# Revision 1.38  2004/06/25 02:19:40  rpantos
-# And FreeBSD...
-#
-# Revision 1.37  2004/06/25 00:51:09  rpantos
-# And fix the Java build for Posix on Solaris, too.
-#
-# Revision 1.36  2004/06/25 00:26:27  rpantos
-# Changes to fix the Posix build on Solaris.
-#
-# Revision 1.35  2004/06/18 18:51:31  cheshire
-# Add (commented out) "-pedantic" for when we want to check for "mixed declarations and code" warnings
-#
-# Revision 1.34  2004/05/25 18:29:33  cheshire
-# Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
-# so that it's also accessible to dnssd_clientshim.c (single address space) clients.
-#
-# Revision 1.33  2004/04/30 16:46:32  rpantos
-# Add support for building Java libraries.
-#
-# Revision 1.32  2004/04/14 23:09:29  ksekar
-# Support for TSIG signed dynamic updates.
-#
-# Revision 1.31  2004/03/15 19:07:06  cheshire
-# Fix error message
-#
-# Revision 1.30  2004/03/11 18:58:29  rpantos
-# Fix Kill /etc/rc scripts so they run at halt & reboot.
-#
-# Revision 1.29  2004/03/04 23:35:41  cheshire
-# Instead of using a dummy target to generate an error message, use "$(error text...)"
-#
-# Revision 1.28  2004/03/04 23:33:42  cheshire
-# Fixes from Alfred Perlstein for FreeBSD's benefit
-#
-# Revision 1.27  2004/02/11 21:00:21  cheshire
-# Update URL for GNU Make manual page
-#
-# Revision 1.26  2004/02/05 21:28:30  cheshire
-# Fixes so that "sudo make install" works on *BSD
-#
-# Revision 1.25  2004/02/05 20:00:22  cheshire
-# Define mdnsd's PID file to be /var/run/mdnsd.pid on Posix builds
-#
-# Revision 1.24  2004/02/05 01:00:01  rpantos
-# Fix some issues that turned up when building for FreeBSD.
-#
-# Revision 1.23  2004/02/04 01:50:54  cheshire
-# Make InstalledStartup conditional, so it automatically installs into
-# either /etc/init.d/ or /etc/rc.d/init.d/ as appropriate
-#
-# Revision 1.22  2004/01/20 01:41:21  rpantos
-# Define USES_NETLINK for Linux builds.
-#
-# Revision 1.21  2003/12/17 00:51:22  cheshire
-# Changed mDNSNetMonitor and mDNSIdentify to link the object files
-# instead of #including the "DNSCommon.c" "uDNS.c" and source files
-#
-# Revision 1.20  2003/12/13 03:05:28  ksekar
-# Bug #: <rdar://problem/3192548>: DynDNS: Unicast query of service records
-#
-# Revision 1.19  2003/12/11 19:42:13  cheshire
-# Change name "mDNSResponderd" to "mdnsd" for consistency with standard Linux (Unix) naming conventions
-#
-# Revision 1.18  2003/12/11 19:38:34  cheshire
-# Add APSL
-#
-# Revision 1.17  2003/12/11 03:16:49  rpantos
-# One more change for OS X build: make install work a little better.
-#
-# Revision 1.16  2003/12/11 03:03:51  rpantos
-# Clean up mDNSPosix so that it builds on OS X again.
-#
-# Revision 1.15  2003/12/08 20:47:02  rpantos
-# Add support for mDNSResponder on Linux.
-#
-# Revision 1.14  2003/11/14 20:59:09  cheshire
-# Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
-# Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
-#
-# Revision 1.13  2003/08/06 18:20:51  cheshire
-# Makefile cleanup
-#
-# Revision 1.12  2003/08/01 02:20:02  cheshire
-# Add mDNSIdentify tool, used to discover what version of mDNSResponder a particular host is running
-#
-# Revision 1.11  2003/07/14 18:11:54  cheshire
-# Fix stricter compiler warnings
-#
-# Revision 1.10  2003/06/18 05:47:41  cheshire
-# Enable stricter warnings on Jaguar and Panther builds
-#
-# Revision 1.9  2003/06/04 18:34:45  ksekar
-# Bug #: <rdar://problem/3218120>: mDNSPosix does not build on Panther that has socklen_t
-# Changed build targets "osx10.2" and "osx10.3" to "jaguar" and "panther".
-#
-# Revision 1.8  2003/06/04 00:23:12  ksekar
-# Bug #: <rdar://problem/3218120>: mDNSPosix does not build on Panther that has socklen_t
-# Created separate target OS's for 10.2 and 10.3.
-#
-# Revision 1.7  2003/04/16 02:11:37  cheshire
-# Remove unnecessary $(CFLAGS) from linking rules
-#
-# Revision 1.6  2003/04/04 01:37:14  cheshire
-# Added NetMonitor.c
-#
-
 # This Makefile builds an mDNSResponder daemon and a libdns_sd.so shared library 
 # for Linux. It also builds several example programs for embedded systems. 
 #
index ed8124f73198f912d5dbc60231bf44c7c1382ab4..771d52d63d5d3dc0f266973fffbd680153d3374a 100644 (file)
  * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
  * understand why variable y is not of type "char*" just proves the point that poor code
  * layout leads people to unfortunate misunderstandings about how the C language really works.)
-
-    Change History (most recent first):
-
-$Log: NetMonitor.c,v $
-Revision 1.96  2009/07/16 00:08:57  cheshire
-Display any stray Update (Authority) records in query packets
-
-Revision 1.95  2009/07/09 22:24:52  herscher
-<rdar://problem/3775717> SDK: Port mDNSNetMonitor to Windows
-
-Revision 1.94  2009/04/24 00:31:56  cheshire
-<rdar://problem/3476350> Return negative answers when host knows authoritatively that no answer exists
-Added code to display NSEC records
-
-Revision 1.93  2009/01/13 05:31:34  mkrochma
-<rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
-
-Revision 1.92  2009/01/11 03:20:06  mkrochma
-<rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris
-
-Revision 1.91  2008/11/13 22:08:07  cheshire
-Show additional records in Query packets
-
-Revision 1.90  2008/09/05 22:20:26  cheshire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-Add "UDPSocket *src" parameter in mDNSPlatformSendUDP call
-
-Revision 1.89  2007/05/17 19:12:42  cheshire
-Tidy up code layout
-
-Revision 1.88  2007/04/22 20:16:25  cheshire
-Fix compiler errors (const parameter declarations)
-
-Revision 1.87  2007/04/16 20:49:39  cheshire
-Fix compile errors for mDNSPosix build
-
-Revision 1.86  2007/03/22 18:31:48  cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.85  2007/02/28 01:51:22  cheshire
-Added comment about reverse-order IP address
-
-Revision 1.84  2007/01/05 08:30:52  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.83  2006/11/18 05:01:32  cheshire
-Preliminary support for unifying the uDNS and mDNS code,
-including caching of uDNS answers
-
-Revision 1.82  2006/08/14 23:24:46  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.81  2006/07/06 00:01:44  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
-
-Revision 1.80  2006/06/12 18:22:42  cheshire
-<rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
-
-Revision 1.79  2006/04/26 20:48:33  cheshire
-Make final count of unique source addresses show IPv4 and IPv6 counts separately
-
-Revision 1.78  2006/04/25 00:42:24  cheshire
-Add ability to specify a single interface index to capture on,
-e.g. typically "-i 4" for Ethernet and "-i 5" for AirPort
-
-Revision 1.77  2006/03/02 21:50:45  cheshire
-Removed strange backslash at the end of a line
-
-Revision 1.76  2006/02/23 23:38:43  cheshire
-<rdar://problem/4427969> On FreeBSD 4 "arpa/inet.h" requires "netinet/in.h" be included first
-
-Revision 1.75  2006/01/05 22:33:58  cheshire
-Use IFNAMSIZ (more portable) instead of IF_NAMESIZE
-
-*/
+ */
 
 //*************************************************************************************************************
 // Incorporate mDNS.c functionality
@@ -122,18 +46,15 @@ Use IFNAMSIZ (more portable) instead of IF_NAMESIZE
 #include <time.h>                      // For "struct tm" etc.
 #include <signal.h>                    // For SIGINT, SIGTERM
 #if defined(WIN32)
+// Both mDNS.c and mDNSWin32.h declare UDPSocket_struct type resulting in a compile-time error, so 
+// trick the compiler when including mDNSWin32.h
+#      define UDPSocket_struct _UDPSocket_struct
 #      include <mDNSEmbeddedAPI.h>
 #      include <mDNSWin32.h>
-#      include <uds_daemon.h>
 #      include <PosixCompat.h>
-#      include <Service.h>
 #      define IFNAMSIZ 256
-
-// Stub these functions out
-mDNSexport int udsserver_init(dnssd_sock_t skts[], mDNSu32 count) { return 0; }
-mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent) { return 0; }
-mDNSexport void udsserver_handle_configchange(mDNS *const m) {}
-mDNSexport int udsserver_exit(void) { return 0; }
+static HANDLE gStopEvent = INVALID_HANDLE_VALUE;
+static BOOL WINAPI ConsoleControlHandler( DWORD inControlEvent ) { SetEvent( gStopEvent ); return TRUE; }
 void setlinebuf( FILE * fp ) {}
 #else
 #      include <netdb.h>                       // For gethostbyname()
@@ -545,7 +466,7 @@ mDNSlocal const mDNSu8 *FindUpdate(mDNS *const m, const DNSMessage *const query,
                const mDNSu8 *p2 = ptr;
                ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, pkt);
                if (!ptr) break;
-               if (ResourceRecordAnswersQuestion(&pkt->r.resrec, q)) return(p2);
+               if (m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && ResourceRecordAnswersQuestion(&pkt->r.resrec, q)) return(p2);
                }
        return(mDNSNULL);
        }
@@ -590,6 +511,10 @@ mDNSlocal void DisplayResourceRecord(const mDNSAddr *const srcaddr, const char *
        mDNSu8 *rdend = (mDNSu8 *)rd + pktrr->rdlength;
        int n = mprintf("%#-16a %-5s %-5s%5lu %##s -> ", srcaddr, op, DNSTypeName(pktrr->rrtype), pktrr->rroriginalttl, pktrr->name->c);
 
+       if (pktrr->RecordType == kDNSRecordTypePacketNegative) { mprintf("**** ERROR: FAILED TO READ RDATA ****\n"); return; }
+
+       // The kDNSType_OPT case below just calls GetRRDisplayString_rdb
+       // Perhaps more (or all?) of the cases should do that?
        switch(pktrr->rrtype)
                {
                case kDNSType_A:        n += mprintf("%.4a", &rd->ipv4); break;
@@ -621,6 +546,15 @@ mDNSlocal void DisplayResourceRecord(const mDNSAddr *const srcaddr, const char *
                                                        } break;
                case kDNSType_AAAA:     n += mprintf("%.16a", &rd->ipv6); break;
                case kDNSType_SRV:      n += mprintf("%##s:%d", rd->srv.target.c, mDNSVal16(rd->srv.port)); break;
+               case kDNSType_OPT:      {
+                                                       char b[MaxMsg];
+                                                       // Quick hack: we don't want the prefix that GetRRDisplayString_rdb puts at the start of its
+                                                       // string, because it duplicates the name and rrtype we already display, so we compute the
+                                                       // length of that prefix and strip that many bytes off the beginning of the string we display.
+                                                       mDNSu32 striplen = mDNS_snprintf(b, MaxMsg-1, "%4d %##s %s ", pktrr->rdlength, pktrr->name->c, DNSTypeName(pktrr->rrtype));
+                                                       GetRRDisplayString_rdb(pktrr, &pktrr->rdata->u, b);
+                                                       n += mprintf("%.*s", MaxWidth - n, b + striplen);
+                                                       } break;
                case kDNSType_NSEC:     {
                                                        int i;
                                                        for (i=0; i<255; i++)
@@ -829,7 +763,7 @@ mDNSlocal void ProcessUnicastResponse(mDNS *const m, const DNSMessage *const msg
                {
                LargeCacheRecord pkt;
                ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &pkt);
-               if (pkt.r.resrec.rroriginalttl && entry) RecordHostInfo(entry, &pkt.r.resrec);
+               if (ptr && pkt.r.resrec.rroriginalttl && entry) RecordHostInfo(entry, &pkt.r.resrec);
                }
        }
 
@@ -902,7 +836,16 @@ mDNSlocal mStatus mDNSNetMonitor(void)
        gettimeofday(&tv_start, NULL);
 
 #if defined( WIN32 )
-       RunDirect( 0, NULL );
+       status = SetupInterfaceList(&mDNSStorage);
+       if (status) return(status);
+       gStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+       if (gStopEvent == INVALID_HANDLE_VALUE) return mStatus_UnknownErr;
+       if (!SetConsoleCtrlHandler(ConsoleControlHandler, TRUE)) return mStatus_UnknownErr;
+       SetSocketEventsEnabled(&mDNSStorage, TRUE);
+       while (WaitForSingleObjectEx(gStopEvent, INFINITE, TRUE) == WAIT_IO_COMPLETION);
+       SetSocketEventsEnabled(&mDNSStorage, FALSE);
+       if (!SetConsoleCtrlHandler(ConsoleControlHandler, FALSE)) return mStatus_UnknownErr;
+       CloseHandle(gStopEvent);
 #else
        mDNSPosixListenForSignalInEventLoop(SIGINT);
        mDNSPosixListenForSignalInEventLoop(SIGTERM);
@@ -983,7 +926,11 @@ mDNSexport int main(int argc, char **argv)
        const char *progname = strrchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0];
        int i;
        mStatus status;
-       
+
+#if defined(WIN32)
+       HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
+#endif
+
        setlinebuf(stdout);                             // Want to see lines as they appear, not block buffered
 
        for (i=1; i<argc; i++)
@@ -1029,8 +976,9 @@ mDNSexport int main(int argc, char **argv)
 
 usage:
        fprintf(stderr, "\nmDNS traffic monitor\n");
-       fprintf(stderr, "Usage: %s (<host>)\n", progname);
-       fprintf(stderr, "Optional <host> parameter displays only packets from that host\n");
+       fprintf(stderr, "Usage: %s [-i index] [host]\n", progname);
+       fprintf(stderr, "Optional [-i index] parameter displays only packets from that interface index\n");
+       fprintf(stderr, "Optional [host] parameter displays only packets from that host\n");
 
        fprintf(stderr, "\nPer-packet header output:\n");
        fprintf(stderr, "-Q-            Multicast Query from mDNS client that accepts multicast responses\n");
index 4d1926535f910fed85810e49d4df4579132f8f96..76681eb6fd055d5159fea130f412f6bdd4abd723 100644 (file)
 
        Contains:       main & associated Application layer for mDNSResponder on Linux.
 
-       Change History (most recent first):
+ */
 
-$Log: PosixDaemon.c,v $
-Revision 1.49  2009/04/30 20:07:51  mcguire
-<rdar://problem/6822674> Support multiple UDSs from launchd
-
-Revision 1.48  2009/04/11 01:43:28  jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.47  2009/01/11 03:20:06  mkrochma
-<rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris
-
-Revision 1.46  2008/11/03 23:09:15  cheshire
-Don't need to include mDNSDebug.h as well as mDNSEmbeddedAPI.h
-
-Revision 1.45  2008/10/03 18:25:17  cheshire
-Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);"
-
-Revision 1.44  2008/09/15 23:52:30  cheshire
-<rdar://problem/6218902> mDNSResponder-177 fails to compile on Linux with .desc pseudo-op
-Made __crashreporter_info__ symbol conditional, so we only use it for OS X build
-
-Revision 1.43  2007/10/22 20:05:34  cheshire
-Use mDNSPlatformSourceAddrForDest instead of FindSourceAddrForIP
-
-Revision 1.42  2007/09/18 19:09:02  cheshire
-<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
-
-Revision 1.41  2007/09/04 17:02:25  cheshire
-<rdar://problem/5458929> False positives in changed files list in nightly builds
-Added MDNS_VERSIONSTR_NODTS option at the reqest of Rishi Srivatsavai (Sun)
-
-Revision 1.40  2007/07/31 23:08:34  mcguire
-<rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
-
-Revision 1.39  2007/03/21 00:30:44  cheshire
-Remove obsolete mDNS_DeleteDNSServers() call
-
-Revision 1.38  2007/02/14 01:58:19  cheshire
-<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
-
-Revision 1.37  2007/02/07 19:32:00  cheshire
-<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
-
-Revision 1.36  2007/02/06 19:06:48  cheshire
-<rdar://problem/3956518> Need to go native with launchd
-
-Revision 1.35  2007/01/05 08:30:52  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.34  2007/01/05 05:46:08  cheshire
-Add mDNS *const m parameter to udsserver_handle_configchange()
-
-Revision 1.33  2006/12/21 00:10:53  cheshire
-Make mDNS_PlatformSupport PlatformStorage a static global instead of a stack variable
-
-Revision 1.32  2006/11/03 22:28:50  cheshire
-PosixDaemon needs to handle mStatus_ConfigChanged and mStatus_GrowCache messages
-
-Revision 1.31  2006/08/14 23:24:46  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.30  2006/07/07 01:09:12  cheshire
-<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
-
-*/
+#if __APPLE__
+// In Mac OS X 10.5 and later trying to use the daemon function gives a “‘daemon’ is deprecated”
+// error, which prevents compilation because we build with "-Werror".
+// Since this is supposed to be portable cross-platform code, we don't care that daemon is
+// deprecated on Mac OS X 10.5, so we use this preprocessor trick to eliminate the error message.
+#define daemon yes_we_know_that_daemon_is_deprecated_in_os_x_10_5_thankyou
+#endif
 
 #include <stdio.h>
 #include <string.h>
@@ -97,6 +38,11 @@ Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsex
 #include <pwd.h>
 #include <sys/types.h>
 
+#if __APPLE__
+#undef daemon
+extern int daemon(int, int);
+#endif
+
 #include "mDNSEmbeddedAPI.h"
 #include "mDNSPosix.h"
 #include "mDNSUNP.h"           // For daemon()
@@ -267,16 +213,24 @@ int main(int argc, char **argv)
 
 //             uds_daemon support              ////////////////////////////////////////////////////////////
 
-mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context)
+mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback, void *context, void **platform_data)
 /* Support routine for uds_daemon.c */
        {
        // Depends on the fact that udsEventCallback == mDNSPosixEventCallback
+       (void) platform_data;
        return mDNSPosixAddFDToEventLoop(fd, callback, context);
        }
 
-mStatus udsSupportRemoveFDFromEventLoop(int fd)                // Note: This also CLOSES the file descriptor
+int udsSupportReadFD(dnssd_sock_t fd, char *buf, int len, int flags, void *platform_data)
+       {
+       (void) platform_data;
+       return recv(fd, buf, len, flags);
+       }
+
+mStatus udsSupportRemoveFDFromEventLoop(int fd, void *platform_data)           // Note: This also CLOSES the file descriptor
        {
        mStatus err = mDNSPosixRemoveFDFromEventLoop(fd);
+       (void) platform_data;
        close(fd);
        return err;
        }
index dd76ac718bc302ce228498fb3bf999f0c4f9463e..e91bcf3061e398a48776bba6c979d4f56867c0f0 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: ProxyResponder.c,v $
-Revision 1.45  2008/11/04 19:46:01  cheshire
-Updated comment about MAX_ESCAPED_DOMAIN_NAME size (should be 1009, not 1005)
-
-Revision 1.44  2007/04/22 20:16:25  cheshire
-Fix compiler errors (const parameter declarations)
-
-Revision 1.43  2007/04/16 20:49:39  cheshire
-Fix compile errors for mDNSPosix build
-
-Revision 1.42  2007/03/06 22:45:53  cheshire
-
-<rdar://problem/4138615> argv buffer overflow issues
-
-Revision 1.41  2007/02/28 01:51:22  cheshire
-Added comment about reverse-order IP address
-
-Revision 1.40  2007/01/05 04:32:13  cheshire
-Change "(domainname *)" cast to "(const domainname *)"
-
-Revision 1.39  2006/08/14 23:24:46  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.38  2006/06/12 18:22:42  cheshire
-<rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
-
-Revision 1.37  2006/02/23 23:38:43  cheshire
-<rdar://problem/4427969> On FreeBSD 4 "arpa/inet.h" requires "netinet/in.h" be included first
-
-Revision 1.36  2005/08/04 03:12:47  mkrochma
-<rdar://problem/4199236> Register reverse PTR record using multicast
-
-Revision 1.35  2004/12/16 20:17:11  cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.34  2004/12/01 04:27:28  cheshire
-<rdar://problem/3872803> Darwin patches for Solaris and Suse
-Don't use uint32_t, etc. -- they require stdint.h, which doesn't exist on FreeBSD 4.x, Solaris, etc.
-
-Revision 1.33  2004/11/30 22:37:01  cheshire
-Update copyright dates and add "Mode: C; tab-width: 4" headers
-
-Revision 1.32  2004/10/26 03:59:41  cheshire
-Update comments
-
-Revision 1.31  2004/09/17 01:08:53  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.30  2004/09/17 00:31:52  cheshire
-For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
-
-Revision 1.29  2004/09/16 01:58:22  cheshire
-Fix compiler warnings
-
-Revision 1.28  2004/06/25 00:26:27  rpantos
-Changes to fix the Posix build on Solaris.
-
-Revision 1.27  2004/03/12 08:03:14  cheshire
-Update comments
-
-Revision 1.26  2004/01/25 00:00:39  cheshire
-Change to use mDNSOpaque16fromIntVal() instead of shifting and masking
-
-Revision 1.25  2003/12/08 20:47:02  rpantos
-Add support for mDNSResponder on Linux.
-
-Revision 1.24  2003/11/14 21:27:09  cheshire
-<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
-Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1009) instead of 256-byte buffers.
-
-Revision 1.23  2003/10/30 19:39:28  cheshire
-Fix warnings on certain compilers
-
-Revision 1.22  2003/08/14 02:19:55  cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
-
-Revision 1.21  2003/08/12 19:56:26  cheshire
-Update to APSL 2.0
-
-Revision 1.20  2003/07/23 00:00:04  cheshire
-Add comments
-
-Revision 1.19  2003/07/15 01:55:16  cheshire
-<rdar://problem/3315777> Need to implement service registration with subtypes
-
-Revision 1.18  2003/07/02 21:19:58  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.17  2003/05/26 03:21:29  cheshire
-Tidy up address structure naming:
-mDNSIPAddr         => mDNSv4Addr (for consistency with mDNSv6Addr)
-mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
-mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
-
-Revision 1.16  2003/05/26 03:01:28  cheshire
-<rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
-
-Revision 1.15  2003/05/06 00:00:50  cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
-
-Revision 1.14  2003/04/25 01:45:57  cheshire
-<rdar://problem/3240002> mDNS_RegisterNoSuchService needs to include a host name
-
-Revision 1.13  2003/04/18 22:46:12  cheshire
-Fix mistake in 1.8 -- INADDR_NONE is 0xFFFFFFFF, not 0
-
-Revision 1.12  2003/04/16 02:11:07  cheshire
-Fixed mDNS_RegisterNoSuchService non-existence function so that it works again
-
-Revision 1.11  2003/03/31 22:49:35  cheshire
-Add "$Log" header
-
  */
 
 #include <stdio.h>                             // For printf()
index 67cc817472882a1b40260c42f78e02fda87cbbb9..9e04dd399187b8d915624bceac59cc82442a4e28 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: Responder.c,v $
-Revision 1.36  2009/01/15 03:39:08  mkrochma
-Fix warning about ignoring return value of daemon
-
-Revision 1.35  2009/01/13 05:31:34  mkrochma
-<rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
-
-Revision 1.34  2009/01/11 03:20:06  mkrochma
-<rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris
-
-Revision 1.33  2007/04/16 20:49:39  cheshire
-Fix compile errors for mDNSPosix build
-
-Revision 1.32  2006/08/14 23:24:46  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.31  2006/06/12 18:22:42  cheshire
-<rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
-
-Revision 1.30  2005/10/26 22:21:16  cheshire
-<rdar://problem/4149841> Potential buffer overflow in mDNSResponderPosix
-
-Revision 1.29  2005/03/04 21:35:33  cheshire
-<rdar://problem/4037201> Services.txt file not parsed properly when it contains more than one service
-
-Revision 1.28  2005/01/11 01:55:26  ksekar
-Fix compile errors in Posix debug build
-
-Revision 1.27  2004/12/01 04:28:43  cheshire
-<rdar://problem/3872803> Darwin patches for Solaris and Suse
-Use version of daemon() provided in mDNSUNP.c instead of local copy
-
-Revision 1.26  2004/11/30 22:37:01  cheshire
-Update copyright dates and add "Mode: C; tab-width: 4" headers
-
-Revision 1.25  2004/11/11 02:00:51  cheshire
-Minor fixes to getopt, error message
-
-Revision 1.24  2004/11/09 19:32:10  rpantos
-Suggestion from Ademar de Souza Reis Jr. to allow comments in services file
-
-Revision 1.23  2004/09/17 01:08:54  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.22  2004/09/16 01:58:22  cheshire
-Fix compiler warnings
-
-Revision 1.21  2004/06/15 03:48:07  cheshire
-Update mDNSResponderPosix to take multiple name=val arguments in a sane way
-
-Revision 1.20  2004/05/18 23:51:26  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
-
-Revision 1.19  2004/03/12 08:03:14  cheshire
-Update comments
-
-Revision 1.18  2004/01/25 00:00:55  cheshire
-Change to use mDNSOpaque16fromIntVal() instead of shifting and masking
-
-Revision 1.17  2003/12/11 19:11:55  cheshire
-Fix compiler warning
-
-Revision 1.16  2003/08/14 02:19:55  cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
-
-Revision 1.15  2003/08/12 19:56:26  cheshire
-Update to APSL 2.0
-
-Revision 1.14  2003/08/06 18:20:51  cheshire
-Makefile cleanup
-
-Revision 1.13  2003/07/23 00:00:04  cheshire
-Add comments
-
-Revision 1.12  2003/07/15 01:55:16  cheshire
-<rdar://problem/3315777> Need to implement service registration with subtypes
-
-Revision 1.11  2003/07/14 18:11:54  cheshire
-Fix stricter compiler warnings
-
-Revision 1.10  2003/07/10 20:27:31  cheshire
-<rdar://problem/3318717> mDNSResponder Posix version is missing a 'b' in the getopt option string
-
-Revision 1.9  2003/07/02 21:19:59  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.8  2003/06/18 05:48:41  cheshire
-Fix warnings
-
-Revision 1.7  2003/05/06 00:00:50  cheshire
-<rdar://problem/3248914> Rationalize naming of domainname manipulation functions
-
-Revision 1.6  2003/03/08 00:35:56  cheshire
-Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
-
-Revision 1.5  2003/02/20 06:48:36  cheshire
-<rdar://problem/3169535> Xserve RAID needs to do interface-specific registrations
-Reviewed by: Josh Graessley, Bob Bradley
-
-Revision 1.4  2003/01/28 03:07:46  cheshire
-Add extra parameter to mDNS_RenameAndReregisterService(),
-and add support for specifying a domain other than dot-local.
-
-Revision 1.3  2002/09/21 20:44:53  zarzycki
-Added APSL info
-
-Revision 1.2  2002/09/19 04:20:44  cheshire
-Remove high-ascii characters that confuse some systems
-
-Revision 1.1  2002/09/17 06:24:35  cheshire
-First checkin
-
-*/
-
-#include "mDNSEmbeddedAPI.h"// Defines the interface to the client layer above
-#include "mDNSPosix.h"    // Defines the specific types needed to run mDNS on this platform
-#include "mDNSUNP.h"           // For daemon()
+ */
+
+#if __APPLE__
+// In Mac OS X 10.5 and later trying to use the daemon function gives a “‘daemon’ is deprecated”
+// error, which prevents compilation because we build with "-Werror".
+// Since this is supposed to be portable cross-platform code, we don't care that daemon is
+// deprecated on Mac OS X 10.5, so we use this preprocessor trick to eliminate the error message.
+#define daemon yes_we_know_that_daemon_is_deprecated_in_os_x_10_5_thankyou
+#endif
 
 #include <assert.h>
 #include <stdio.h>                     // For printf()
@@ -146,6 +32,15 @@ First checkin
 #include <signal.h>
 #include <fcntl.h>
 
+#if __APPLE__
+#undef daemon
+extern int daemon(int, int);
+#endif
+
+#include "mDNSEmbeddedAPI.h"// Defines the interface to the client layer above
+#include "mDNSPosix.h"         // Defines the specific types needed to run mDNS on this platform
+#include "mDNSUNP.h"           // For daemon()
+
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark ***** Globals
 #endif
index 94d9e1776bc88463aabac15cd1d4afe33e11eb3b..9c00d4fbc3fd39588ebc7121a20ea6be6f0ef78b 100755 (executable)
@@ -1,4 +1,3 @@
-.\"    $Id: libnss_mdns.8,v 1.1 2004/06/29 03:34:28 cheshire Exp $
 .\"
 .\" See section LICENSE for license information.
 .\"
index 70defbda7f9b4ec2f68bd28e4c102928f2cc51e5..f205cd0c3b6cf37f6170b1ec3fa019a3a3922607 100755 (executable)
  * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
  * understand why variable y is not of type "char*" just proves the point that poor code
  * layout leads people to unfortunate misunderstandings about how the C language really works.)
-
-       Change History (most recent first):
-
-$Log: mDNSPosix.c,v $
-Revision 1.108  2009/01/25 03:16:46  mkrochma
-Added skeleton definition of mDNSPlatformSetLocalARP
-
-Revision 1.107  2009/01/07 08:25:03  mkrochma
-Added skeleton definition of mDNSPlatformUpdateProxyList
-
-Revision 1.106  2008/10/22 17:19:57  cheshire
-Don't need to define BPF_fd any more (it's now per-interface, not global)
-
-Revision 1.105  2008/10/03 23:34:08  cheshire
-Added skeleton definition of mDNSPlatformSendRawPacket
-
-Revision 1.104  2008/09/05 22:16:48  cheshire
-<rdar://problem/3988320> Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-Add "UDPSocket *src" parameter in mDNSPlatformSendUDP
-
-Revision 1.103  2007/10/02 19:31:17  cheshire
-In ParseDNSServers, should use strncasecmp for case-insensitive compare
-
-Revision 1.102  2007/09/12 19:23:17  cheshire
-Get rid of unnecessary mDNSPlatformTCPIsConnected() routine
-
-Revision 1.101  2007/07/20 00:54:23  cheshire
-<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-
-Revision 1.100  2007/07/19 21:45:30  cheshire
-Fixed code spacing
-
-Revision 1.99  2007/07/11 02:56:51  cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-Remove unused mDNSPlatformDefaultRegDomainChanged
-
-Revision 1.98  2007/06/20 01:10:13  cheshire
-<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-
-Revision 1.97  2007/04/26 00:35:16  cheshire
-<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
-Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
-inside the firewall may give answers where a public one gives none, and vice versa.)
-
-Revision 1.96  2007/04/22 20:29:59  cheshire
-Fix locking error
-
-Revision 1.95  2007/04/22 20:15:46  cheshire
-Add missing parameters for mDNSPosixEventCallback
-
-Revision 1.94  2007/04/17 19:21:29  cheshire
-<rdar://problem/5140339> Domain discovery not working over VPN
-
-Revision 1.93  2007/04/16 20:49:40  cheshire
-Fix compile errors for mDNSPosix build
-
-Revision 1.92  2007/04/05 20:40:37  cheshire
-Remove unused mDNSPlatformTCPGetFlags()
-
-Revision 1.91  2007/03/22 18:31:48  cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.90  2007/03/21 00:31:45  cheshire
-Remove unnecessary (and unimplemented) platform functions
-
-Revision 1.89  2007/03/20 17:07:15  cheshire
-Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-
-Revision 1.88  2007/03/07 00:30:18  mkrochma
-<rdar://problem/5034370> POSIX: kDNSServiceInterfaceIndexAny not correctly handled
-Thanks goes to Aidan Williams of Audinate who did a lot of work in diagnosing this
-
-Revision 1.87  2007/02/08 21:12:28  cheshire
-<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
-
-Revision 1.86  2007/01/05 08:30:52  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.85  2007/01/04 23:12:20  cheshire
-Remove unused mDNSPlatformDefaultBrowseDomainChanged
-
-Revision 1.84  2006/12/22 21:07:35  cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.83  2006/12/21 00:09:46  cheshire
-Use mDNSPlatformMemZero instead of bzero
-
-Revision 1.82  2006/12/19 22:43:55  cheshire
-Fix compiler warnings
-
-Revision 1.81  2006/08/14 23:24:46  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.80  2006/07/22 03:05:33  cheshire
-Improve error reporting for socket creation failures
-
-Revision 1.79  2006/07/06 00:02:16  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-
-Revision 1.78  2006/06/28 09:12:22  cheshire
-Added debugging message
-
-Revision 1.77  2006/03/19 02:00:11  cheshire
-<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-
-Revision 1.76  2006/01/09 19:29:16  cheshire
-<rdar://problem/4403128> Cap number of "sendto failed" messages we allow mDNSResponder to log
-
-Revision 1.75  2006/01/05 22:04:57  cheshire
-<rdar://problem/4399479> Log error message when send fails with "operation not permitted"
-
-Revision 1.74  2006/01/05 21:45:27  cheshire
-<rdar://problem/4400118> Fix uninitialized structure member in IPv6 code
-
-*/
+ */
 
 #include "mDNSEmbeddedAPI.h"           // Defines the interface provided to the client layer above
 #include "DNSCommon.h"
@@ -450,12 +334,13 @@ mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
        return -1;
        }
 
-mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
+mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID,
                                                                                  TCPConnectionCallback callback, void *context)
        {
        (void)sock;                     // Unused
        (void)dst;                      // Unused
        (void)dstport;          // Unused
+       (void)hostname;     // Unused
        (void)InterfaceID;      // Unused
        (void)callback;         // Unused
        (void)context;          // Unused
@@ -509,8 +394,9 @@ mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *c
        (void)InterfaceID;                      // Unused
        }
        
-mDNSexport void mDNSPlatformSetLocalARP(const mDNSv4Addr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
+mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
        {
+       (void)m;                        // Unused
        (void)tpa;                      // Unused
        (void)tha;                      // Unused
        (void)InterfaceID;                      // Unused
@@ -596,7 +482,7 @@ mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
                        mDNSAddr DNSAddr;
                        DNSAddr.type = mDNSAddrType_IPv4;
                        DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
-                       mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, &DNSAddr, UnicastDNSPort);
+                       mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, &DNSAddr, UnicastDNSPort, mDNSfalse);
                        numOfServers++;
                        }
                }  
@@ -626,6 +512,7 @@ mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const
        assert(m != NULL);
 
        if (index == kDNSServiceInterfaceIndexLocalOnly) return(mDNSInterface_LocalOnly);
+       if (index == kDNSServiceInterfaceIndexP2P      ) return(mDNSInterface_P2P);
        if (index == kDNSServiceInterfaceIndexAny      ) return(mDNSInterface_Any);
 
        intf = (PosixNetworkInterface*)(m->HostInterfaces);
@@ -642,6 +529,7 @@ mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNS
        assert(m != NULL);
 
        if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
+       if (id == mDNSInterface_P2P      ) return(kDNSServiceInterfaceIndexP2P);
        if (id == mDNSInterface_Any      ) return(kDNSServiceInterfaceIndexAny);
 
        intf = (PosixNetworkInterface*)(m->HostInterfaces);
index c47ac030a9bbe1be79efc2dcba50b7acfd616fec..dab4b11a4c58d455ccb47e8fce9d41b536da73f9 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: mDNSPosix.h,v $
-Revision 1.19  2007/04/22 20:15:46  cheshire
-Add missing parameters for mDNSPosixEventCallback
-
-Revision 1.18  2006/08/14 23:24:47  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.17  2005/02/04 00:39:59  cheshire
-Move ParseDNSServers() from PosixDaemon.c to mDNSPosix.c so all Posix client layers can use it
-
-Revision 1.16  2004/11/30 22:37:01  cheshire
-Update copyright dates and add "Mode: C; tab-width: 4" headers
-
-Revision 1.15  2004/02/06 01:19:51  cheshire
-Conditionally exclude IPv6 code unless HAVE_IPV6 is set
-
-Revision 1.14  2004/01/28 21:12:15  cheshire
-Reconcile mDNSIPv6Support & HAVE_IPV6 into a single flag (HAVE_IPV6)
-
-Revision 1.13  2004/01/24 05:12:03  cheshire
-<rdar://problem/3534352>: Need separate socket for issuing unicast queries
-
-Revision 1.12  2004/01/23 21:37:08  cheshire
-For consistency, rename multicastSocket to multicastSocket4, and multicastSocketv6 to multicastSocket6
-
-Revision 1.11  2003/12/11 03:03:51  rpantos
-Clean up mDNSPosix so that it builds on OS X again.
-
-Revision 1.10  2003/12/08 20:47:02  rpantos
-Add support for mDNSResponder on Linux.
-
-Revision 1.9  2003/10/30 19:25:19  cheshire
-Fix warning on certain compilers
-
-Revision 1.8  2003/08/12 19:56:26  cheshire
-Update to APSL 2.0
-
-Revision 1.7  2003/07/02 21:19:59  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.6  2003/03/13 03:46:21  cheshire
-Fixes to make the code build on Linux
-
-Revision 1.5  2003/03/08 00:35:56  cheshire
-Switched to using new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
-
-Revision 1.4  2002/12/23 22:13:31  jgraessl
-
-Reviewed by: Stuart Cheshire
-Initial IPv6 support for mDNSResponder.
-
-Revision 1.3  2002/09/21 20:44:53  zarzycki
-Added APSL info
-
-Revision 1.2  2002/09/19 04:20:44  cheshire
-Remove high-ascii characters that confuse some systems
-
-Revision 1.1  2002/09/17 06:24:34  cheshire
-First checkin
-
-*/
+ */
 
 #ifndef __mDNSPlatformPosix_h
 #define __mDNSPlatformPosix_h
index d32406e5bffbce5ef6164c2d4149ff396bae04a7..e8fc649a5d99a12588a82a6abd33c86161950e10 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: mDNSUNP.c,v $
-Revision 1.40  2009/01/13 05:31:34  mkrochma
-<rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
-
-Revision 1.39  2009/01/11 03:20:06  mkrochma
-<rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris
-
-Revision 1.38  2009/01/10 22:54:42  mkrochma
-<rdar://problem/5797544> Fixes from Igor Seleznev to get mdnsd working on Linux
-
-Revision 1.37  2008/10/23 22:33:24  cheshire
-Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
-
-Revision 1.36  2008/04/21 18:21:22  mkrochma
-<rdar://problem/5877307> Need to free ifi_netmask
-Submitted by Igor Seleznev
-
-Revision 1.35  2007/11/15 21:36:19  cheshire
-<rdar://problem/5289340> POSIX: Off by one overflow in get_ifi_info_linuxv6()
-
-Revision 1.34  2006/08/14 23:24:47  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.33  2006/03/13 23:14:21  cheshire
-<rdar://problem/4427969> Compile problems on FreeBSD
-Use <netinet/in_var.h> instead of <netinet6/in6_var.h>
-
-Revision 1.32  2005/12/21 02:56:43  cheshire
-<rdar://problem/4243433> get_ifi_info() should fake ifi_index when SIOCGIFINDEX undefined
-
-Revision 1.31  2005/12/21 02:46:05  cheshire
-<rdar://problem/4243514> mDNSUNP.c needs to include <sys/param.h> on 4.4BSD Lite
-
-Revision 1.30  2005/11/29 20:03:02  mkrochma
-Wrapped sin_len with #ifndef NOT_HAVE_SA_LEN
-
-Revision 1.29  2005/11/12 02:23:10  cheshire
-<rdar://problem/4317680> mDNSUNP.c needs to deal with lame results from SIOCGIFNETMASK, SIOCGIFBRDADDR and SIOCGIFDSTADDR
-
-Revision 1.28  2005/10/31 22:09:45  cheshire
-Buffer "char addr6[33]" was seven bytes too small
-
-Revision 1.27  2005/06/29 15:54:21  cheshire
-<rdar://problem/4113742> mDNSResponder-107.1 does not work on FreeBSD
-Refine last checkin so that it (hopefully) doesn't break get_ifi_info() for every other OS
-
-Revision 1.26  2005/04/08 21:43:59  ksekar
-<rdar://problem/4083426>  mDNSPosix (v98) retrieve interface list bug on AMD64 architecture
-Submitted by Andrew de Quincey
-
-Revision 1.25  2005/04/08 21:37:57  ksekar
-<rdar://problem/3792767> get_ifi_info doesn't return IPv6 interfaces on Linux
-
-Revision 1.24  2005/04/08 21:30:16  ksekar
-<rdar://problem/4007457> Compiling problems with mDNSResponder-98 on Solaris/Sparc v9
-Patch submitted by Bernd Kuhls
-
-Revision 1.23  2004/12/01 04:25:05  cheshire
-<rdar://problem/3872803> Darwin patches for Solaris and Suse
-Provide daemon() for platforms that don't have it
-
-Revision 1.22  2004/11/30 22:37:01  cheshire
-Update copyright dates and add "Mode: C; tab-width: 4" headers
-
-Revision 1.21  2004/11/08 22:13:59  rpantos
-Create sockf6 lazily when v6 interface found.
-
-Revision 1.20  2004/10/16 00:17:01  cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
-
-Revision 1.19  2004/07/20 01:47:36  rpantos
-NOT_HAVE_SA_LEN applies to v6, too. And use more-portable s6_addr.
-
-Revision 1.18  2004/07/08 21:30:21  rpantos
-
-Revision 1.17  2004/06/25 00:26:27  rpantos
-Changes to fix the Posix build on Solaris.
-
-Revision 1.16  2004/03/20 05:37:09  cheshire
-Fix contributed by Terry Lambert & Alfred Perlstein:
-Don't use uint8_t -- it requires stdint.h, which doesn't exist on FreeBSD 4.x
-
-Revision 1.15  2004/02/14 01:09:45  rpantos
-Just use HAVE_IPV6 rather than defined(HAVE_IPV6).
-
-Revision 1.14  2003/12/11 18:53:40  cheshire
-Fix compiler warning reported by Paul Guyot
-
-Revision 1.13  2003/12/08 20:47:02  rpantos
-Add support for mDNSResponder on Linux.
-
-Revision 1.12  2003/09/02 20:47:13  cheshire
-Fix signed/unsigned warning
-
-Revision 1.11  2003/08/12 19:56:26  cheshire
-Update to APSL 2.0
-
-Revision 1.10  2003/08/06 18:20:51  cheshire
-Makefile cleanup
-
-Revision 1.9  2003/07/14 18:11:54  cheshire
-Fix stricter compiler warnings
-
-Revision 1.8  2003/07/02 21:19:59  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.7  2003/03/20 21:10:31  cheshire
-Fixes done at IETF 56 to make mDNSProxyResponderPosix run on Solaris
-
-Revision 1.6  2003/03/13 03:46:21  cheshire
-Fixes to make the code build on Linux
-
-Revision 1.5  2003/02/07 03:02:02  cheshire
-Submitted by: Mitsutaka Watanabe
-The code saying "index += 1;" was effectively making up random interface index values.
-The right way to find the correct interface index is if_nametoindex();
-
-Revision 1.4  2002/12/23 22:13:31  jgraessl
-
-Reviewed by: Stuart Cheshire
-Initial IPv6 support for mDNSResponder.
-
-Revision 1.3  2002/09/21 20:44:53  zarzycki
-Added APSL info
-
-Revision 1.2  2002/09/19 04:20:44  cheshire
-Remove high-ascii characters that confuse some systems
-
-Revision 1.1  2002/09/17 06:24:34  cheshire
-First checkin
-
-*/
+ */
 
 #include "mDNSUNP.h"
 
@@ -205,8 +71,8 @@ void plen_to_mask(int plen, char *addr) {
        int bits_in_block=16; /* Bits per IPv6 block */
        for(i=0;i<=colons;i++) {
                int block, ones=0xffff, ones_in_block;
-               if(plen>bits_in_block) ones_in_block=bits_in_block;
-               else                   ones_in_block=plen;
+               if (plen>bits_in_block) ones_in_block=bits_in_block;
+               else                    ones_in_block=plen;
                block = ones & (ones << (bits_in_block-ones_in_block));
                i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
                plen -= ones_in_block;
@@ -336,7 +202,7 @@ struct ifi_info *get_ifi_info(int family, int doaliases)
 #endif
 
 #if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
- if(family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
+ if (family == AF_INET6) return get_ifi_info_linuxv6(family, doaliases);
 #endif
 
        sockfd = -1;
index d0d75c4e16d4ae30e402423d7f2d0ca8d5a64a1b..59b5501b37bf5c58a42879893a8f275f3eb94753 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: mDNSUNP.h,v $
-Revision 1.19  2006/08/14 23:24:47  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.18  2005/04/08 21:37:57  ksekar
-<rdar://problem/3792767> get_ifi_info doesn't return IPv6 interfaces on Linux
-
-Revision 1.17  2004/12/17 19:32:43  cheshire
-Add missing semicolon
-
-Revision 1.16  2004/12/01 04:25:05  cheshire
-<rdar://problem/3872803> Darwin patches for Solaris and Suse
-Provide daemon() for platforms that don't have it
-
-Revision 1.15  2004/11/30 22:37:01  cheshire
-Update copyright dates and add "Mode: C; tab-width: 4" headers
-
-Revision 1.14  2004/10/16 00:17:01  cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
-
-Revision 1.13  2004/03/20 05:37:09  cheshire
-Fix contributed by Terry Lambert & Alfred Perlstein:
-Don't use uint8_t -- it requires stdint.h, which doesn't exist on FreeBSD 4.x
-
-Revision 1.12  2004/01/28 21:12:15  cheshire
-Reconcile mDNSIPv6Support & HAVE_IPV6 into a single flag (HAVE_IPV6)
-
-Revision 1.11  2003/12/13 05:43:09  bradley
-Fixed non-sa_len and non-IPv6 version of GET_SA_LEN macro to cast as sockaddr to access
-sa_family so it works with any sockaddr-compatible address structure (e.g. sockaddr_storage).
-
-Revision 1.10  2003/12/11 03:03:51  rpantos
-Clean up mDNSPosix so that it builds on OS X again.
-
-Revision 1.9  2003/12/08 20:47:02  rpantos
-Add support for mDNSResponder on Linux.
-
-Revision 1.8  2003/08/12 19:56:26  cheshire
-Update to APSL 2.0
-
-Revision 1.7  2003/08/06 18:20:51  cheshire
-Makefile cleanup
-
-Revision 1.6  2003/07/02 21:19:59  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.5  2003/03/13 03:46:21  cheshire
-Fixes to make the code build on Linux
-
-Revision 1.4  2002/12/23 22:13:32  jgraessl
-
-Reviewed by: Stuart Cheshire
-Initial IPv6 support for mDNSResponder.
-
-Revision 1.3  2002/09/21 20:44:53  zarzycki
-Added APSL info
-
-Revision 1.2  2002/09/19 04:20:44  cheshire
-Remove high-ascii characters that confuse some systems
-
-Revision 1.1  2002/09/17 06:24:35  cheshire
-First checkin
-
-*/
+ */
 
 #ifndef __mDNSUNP_h
 #define __mDNSUNP_h
index d8b8ef40a184b1a889ec1885225f7f5e5fdb6e15..14fef9b4b89ecef567fb3ccb17d512a373dae095 100644 (file)
 #
 # Linux /etc/init.d script to start/stop the mdnsd daemon.
 #
-# $Log: mdnsd.sh,v $
-# Revision 1.9  2006/09/05 20:00:14  cheshire
-# Moved Emacs settings to second line of file
-#
-# Revision 1.8  2006/08/29 16:42:01  mkrochma
-# Fix POSIX startup script
-#
-# Revision 1.7  2006/08/14 23:24:47  cheshire
-# Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-#
-# Revision 1.6  2004/12/07 20:30:45  cheshire
-# Fix start-stop-daemon for Suse Linux (don't use -s TERM)
-#
-# Revision 1.5  2004/06/29 22:13:45  cheshire
-# Fix from Andrew White at NICTA
-#
-# Revision 1.4  2004/02/05 20:23:10  cheshire
-# Fix mdnsd.sh to work on *BSD distributions
-#
-# Revision 1.3  2004/01/19 22:47:17  cheshire
-# Define killprocterm() to do "killproc $1 -TERM" for Linux
-#
-# Revision 1.2  2003/12/11 19:42:13  cheshire
-# Change name "mDNSResponderd" to "mdnsd" for consistency with standard Linux (Unix) naming conventions
-#
-# Revision 1.1  2003/12/08 20:47:02  rpantos
-# Add support for mDNSResponder on Linux.
-#
 # The following lines are used by the *BSD rcorder system to decide
 # the order it's going to run the rc.d scripts at startup time.
 # PROVIDE: mdnsd
index 42dd995cea5425c4d705edecc75b83c2389dc299..7dbefa222bcf5b819c609da99b5504b077b47fdb 100755 (executable)
@@ -1,4 +1,3 @@
-.\"    $Id: nss_mdns.conf.5,v 1.1 2004/06/29 03:34:28 cheshire Exp $
 .\"
 .\" See section LICENSE for license information.
 .\"
index b58289f30573100f143dba7597c3d65d7d5ef7bf..f39d0f23f7395f321441af37ffe9f0f6ef1121f9 100755 (executable)
 # Filled orange circle: Probe (service starting)  Hollow orange circle: First probe (requesting unicast reply)
 # Filled green  circle: Normal answer             Hollow green  circle: Goodbye message (record going away)
 #                                                 Hollow blue   circle: Legacy query (from old client)
-# $Log: parselog.py,v $
-# Revision 1.4  2006/09/05 20:00:14  cheshire
-# Moved Emacs settings to second line of file
-#
-# Revision 1.3  2006/08/14 23:24:47  cheshire
-# Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-#
-# Revision 1.2  2003/12/01 21:47:44  cheshire
-# APSL
-#
-# Revision 1.1  2003/10/10 02:14:17  cheshire
-# First checkin of parselog.py, a tool to create graphical representations of mDNSNetMonitor logs
 
 from CoreGraphics import *
 import math   # for pi
index 98423dc3f31661fb4454bb3bb0273a0fd1e3ef76..741388596f8281b5241a8ef2d361b646b34593d2 100755 (executable)
@@ -21,11 +21,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PrinterSetupWizard", "Clien
                {3A2B6325-3053-4236-84BD-AA9BE2E323E5} = {3A2B6325-3053-4236-84BD-AA9BE2E323E5}\r
        EndProjectSection\r
 EndProject\r
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ControlPanel", "mDNSWindows\ControlPanel\ControlPanel.vcproj", "{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}"\r
-       ProjectSection(ProjectDependencies) = postProject\r
-               {AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E}\r
-       EndProjectSection\r
-EndProject\r
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PrinterSetupWizardLocRes", "Clients\PrinterSetupWizard\PrinterSetupWizardLocRes.vcproj", "{967F5375-0176-43D3-ADA3-22EE25551C37}"\r
        ProjectSection(ProjectDependencies) = postProject\r
                {AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E}\r
@@ -58,8 +53,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JavaSamples", "Clients\Java
                {9CE2568A-3170-41C6-9F20-A0188A9EC114} = {9CE2568A-3170-41C6-9F20-A0188A9EC114}\r
        EndProjectSection\r
 EndProject\r
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ControlPanel (Vista)", "mDNSWindows\ControlPanel\ControlPanelExe.vcproj", "{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}"\r
-EndProject\r
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DLLStub", "mDNSWindows\DLLStub\DLLStub.vcproj", "{3A2B6325-3053-4236-84BD-AA9BE2E323E5}"\r
        ProjectSection(ProjectDependencies) = postProject\r
                {AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E}\r
@@ -72,6 +65,23 @@ EndProject
 Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "DNSServiceBrowser.VB", "Clients\DNSServiceBrowser.VB\DNSServiceBrowser.VB.vbproj", "{FB79E297-5703-435C-A829-51AA51CD71C2}"\r
 EndProject\r
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mDNSNetMonitor", "Clients\mDNSNetMonitor.VisualStudio\mDNSNetMonitor.vcproj", "{AF35C285-528D-46A1-8A0E-47B0733DC718}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {C1D98254-BA27-4427-A3BE-A68CA2CC5F69} = {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}\r
+       EndProjectSection\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ControlPanelLocRes", "mDNSWindows\ControlPanel\ControlPanelLocRes.vcproj", "{4490229E-025A-478F-A2CF-51154DA83E39}"\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ControlPanelRes", "mDNSWindows\ControlPanel\ControlPanelRes.vcproj", "{5254AA9C-3D2E-4539-86D9-5EB0F4151215}"\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ControlPanel", "mDNSWindows\ControlPanel\ControlPanel.vcproj", "{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {3A2B6325-3053-4236-84BD-AA9BE2E323E5} = {3A2B6325-3053-4236-84BD-AA9BE2E323E5}\r
+       EndProjectSection\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FirefoxExtension", "Clients\FirefoxExtension\FirefoxExtension.vcproj", "{7826EA27-D4CC-4FAA-AD23-DF813823227B}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {3A2B6325-3053-4236-84BD-AA9BE2E323E5} = {3A2B6325-3053-4236-84BD-AA9BE2E323E5}\r
+       EndProjectSection\r
 EndProject\r
 Global\r
        GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
@@ -169,20 +179,6 @@ Global
                {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Release|Win32.Build.0 = Release|Win32\r
                {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Release|x64.ActiveCfg = Release|x64\r
                {B1D2CDA2-CC8F-45D5-A694-2EE45B0308CF}.Release|x64.Build.0 = Release|x64\r
-               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Any CPU.ActiveCfg = Debug|x64\r
-               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
-               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
-               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Win32.ActiveCfg = Debug|Win32\r
-               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Win32.Build.0 = Debug|Win32\r
-               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|x64.ActiveCfg = Debug|x64\r
-               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|x64.Build.0 = Debug|x64\r
-               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Any CPU.ActiveCfg = Release|x64\r
-               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
-               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Mixed Platforms.Build.0 = Release|x64\r
-               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Win32.ActiveCfg = Release|Win32\r
-               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Win32.Build.0 = Release|Win32\r
-               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|x64.ActiveCfg = Release|x64\r
-               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|x64.Build.0 = Release|x64\r
                {967F5375-0176-43D3-ADA3-22EE25551C37}.Debug|Any CPU.ActiveCfg = Debug|x64\r
                {967F5375-0176-43D3-ADA3-22EE25551C37}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
                {967F5375-0176-43D3-ADA3-22EE25551C37}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
@@ -259,12 +255,14 @@ Global
                {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Debug|Win32.ActiveCfg = Debug|Win32\r
                {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Debug|Win32.Build.0 = Debug|Win32\r
                {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Debug|x64.ActiveCfg = Debug|x64\r
+               {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Debug|x64.Build.0 = Debug|x64\r
                {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release|Any CPU.ActiveCfg = Release|x64\r
                {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
                {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release|Mixed Platforms.Build.0 = Release|x64\r
                {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release|Win32.ActiveCfg = Release|Win32\r
                {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release|Win32.Build.0 = Release|Win32\r
                {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release|x64.ActiveCfg = Release|x64\r
+               {9CE2568A-3170-41C6-9F20-A0188A9EC114}.Release|x64.Build.0 = Release|x64\r
                {A987A0C1-344F-475C-869C-F082EB11EEBA}.Debug|Any CPU.ActiveCfg = Debug|x64\r
                {A987A0C1-344F-475C-869C-F082EB11EEBA}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
                {A987A0C1-344F-475C-869C-F082EB11EEBA}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
@@ -277,20 +275,6 @@ Global
                {A987A0C1-344F-475C-869C-F082EB11EEBA}.Release|Win32.ActiveCfg = Release|Win32\r
                {A987A0C1-344F-475C-869C-F082EB11EEBA}.Release|Win32.Build.0 = Release|Win32\r
                {A987A0C1-344F-475C-869C-F082EB11EEBA}.Release|x64.ActiveCfg = Release|x64\r
-               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|Any CPU.ActiveCfg = Debug|x64\r
-               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
-               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
-               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|Win32.ActiveCfg = Debug|Win32\r
-               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|Win32.Build.0 = Debug|Win32\r
-               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|x64.ActiveCfg = Debug|x64\r
-               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Debug|x64.Build.0 = Debug|x64\r
-               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|Any CPU.ActiveCfg = Release|x64\r
-               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
-               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|Mixed Platforms.Build.0 = Release|x64\r
-               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|Win32.ActiveCfg = Release|Win32\r
-               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|Win32.Build.0 = Release|Win32\r
-               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|x64.ActiveCfg = Release|x64\r
-               {0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}.Release|x64.Build.0 = Release|x64\r
                {3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Debug|Any CPU.ActiveCfg = Debug|x64\r
                {3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
                {3A2B6325-3053-4236-84BD-AA9BE2E323E5}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
@@ -355,6 +339,60 @@ Global
                {AF35C285-528D-46A1-8A0E-47B0733DC718}.Release|Win32.ActiveCfg = Release|Win32\r
                {AF35C285-528D-46A1-8A0E-47B0733DC718}.Release|Win32.Build.0 = Release|Win32\r
                {AF35C285-528D-46A1-8A0E-47B0733DC718}.Release|x64.ActiveCfg = Release|Win32\r
+               {4490229E-025A-478F-A2CF-51154DA83E39}.Debug|Any CPU.ActiveCfg = Debug|x64\r
+               {4490229E-025A-478F-A2CF-51154DA83E39}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
+               {4490229E-025A-478F-A2CF-51154DA83E39}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
+               {4490229E-025A-478F-A2CF-51154DA83E39}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {4490229E-025A-478F-A2CF-51154DA83E39}.Debug|Win32.Build.0 = Debug|Win32\r
+               {4490229E-025A-478F-A2CF-51154DA83E39}.Debug|x64.ActiveCfg = Debug|x64\r
+               {4490229E-025A-478F-A2CF-51154DA83E39}.Debug|x64.Build.0 = Debug|x64\r
+               {4490229E-025A-478F-A2CF-51154DA83E39}.Release|Any CPU.ActiveCfg = Release|x64\r
+               {4490229E-025A-478F-A2CF-51154DA83E39}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
+               {4490229E-025A-478F-A2CF-51154DA83E39}.Release|Mixed Platforms.Build.0 = Release|x64\r
+               {4490229E-025A-478F-A2CF-51154DA83E39}.Release|Win32.ActiveCfg = Release|Win32\r
+               {4490229E-025A-478F-A2CF-51154DA83E39}.Release|Win32.Build.0 = Release|Win32\r
+               {4490229E-025A-478F-A2CF-51154DA83E39}.Release|x64.ActiveCfg = Release|x64\r
+               {4490229E-025A-478F-A2CF-51154DA83E39}.Release|x64.Build.0 = Release|x64\r
+               {5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Debug|Any CPU.ActiveCfg = Debug|x64\r
+               {5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
+               {5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
+               {5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Debug|Win32.Build.0 = Debug|Win32\r
+               {5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Debug|x64.ActiveCfg = Debug|x64\r
+               {5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Debug|x64.Build.0 = Debug|x64\r
+               {5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Release|Any CPU.ActiveCfg = Release|x64\r
+               {5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
+               {5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Release|Mixed Platforms.Build.0 = Release|x64\r
+               {5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Release|Win32.ActiveCfg = Release|Win32\r
+               {5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Release|Win32.Build.0 = Release|Win32\r
+               {5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Release|x64.ActiveCfg = Release|x64\r
+               {5254AA9C-3D2E-4539-86D9-5EB0F4151215}.Release|x64.Build.0 = Release|x64\r
+               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Any CPU.ActiveCfg = Debug|x64\r
+               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Mixed Platforms.ActiveCfg = Debug|x64\r
+               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Mixed Platforms.Build.0 = Debug|x64\r
+               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|Win32.Build.0 = Debug|Win32\r
+               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|x64.ActiveCfg = Debug|x64\r
+               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Debug|x64.Build.0 = Debug|x64\r
+               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Any CPU.ActiveCfg = Release|x64\r
+               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Mixed Platforms.ActiveCfg = Release|x64\r
+               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Mixed Platforms.Build.0 = Release|x64\r
+               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Win32.ActiveCfg = Release|Win32\r
+               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|Win32.Build.0 = Release|Win32\r
+               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|x64.ActiveCfg = Release|x64\r
+               {F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}.Release|x64.Build.0 = Release|x64\r
+               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Any CPU.ActiveCfg = Debug|Win32\r
+               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32\r
+               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Mixed Platforms.Build.0 = Debug|Win32\r
+               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Win32.Build.0 = Debug|Win32\r
+               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|x64.ActiveCfg = Debug|Win32\r
+               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Any CPU.ActiveCfg = Release|Win32\r
+               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Mixed Platforms.ActiveCfg = Release|Win32\r
+               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Mixed Platforms.Build.0 = Release|Win32\r
+               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Win32.ActiveCfg = Release|Win32\r
+               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Win32.Build.0 = Release|Win32\r
+               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|x64.ActiveCfg = Release|Win32\r
        EndGlobalSection\r
        GlobalSection(SolutionProperties) = preSolution\r
                HideSolutionNode = FALSE\r
index e0ab8a461cf1f505c7fb6bbbd4424dbb73cb3a3d..1261f1d5ab3e0e3cb5ce4f65bbeff6f7ac6dadf7 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: CommonServices.h,v $
-Revision 1.11  2009/03/30 19:51:29  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.10  2009/01/11 03:20:06  mkrochma
-<rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris
-
-Revision 1.9  2009/01/10 22:03:43  mkrochma
-<rdar://problem/5797507> dnsextd fails to build on Linux
-
-Revision 1.8  2007/01/17 19:16:59  cheshire
-Only define ssize_t if it's not already defined
-
-Revision 1.7  2007/01/16 23:00:45  cheshire
-Don't need to include CoreServices.h
-
-Revision 1.6  2006/08/24 22:41:53  herscher
-<rdar://problem/4580067> POSIX: dnsextd_parser doesn't compile on Linux
-
-Revision 1.5  2006/08/14 23:24:56  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.4  2006/07/05 22:43:21  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-
-Revision 1.3  2004/04/08 09:27:12  bradley
-Added macro for portable specification of callback calling conventions.
-
-Revision 1.2  2004/03/07 05:53:39  bradley
-Fixed NumVersion extraction macros. Updated error code mappings to match latest internal version.
-
-Revision 1.1  2004/01/30 02:25:59  bradley
-Common Services and portability support for various platforms.
-
-*/
+ */
 
 //---------------------------------------------------------------------------------------------------------------------------
 /*!    @header         CommonServices
index 164310ae93b873a564dddcf120de496952ee0daa..647329628ce831bfb54273dcb5cdf1385e179d48 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
 
-    Change History (most recent first):
-    
-$Log: DebugServices.c,v $
-Revision 1.6  2006/08/14 23:24:56  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.5  2004/09/17 01:08:57  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.4  2004/04/15 08:59:08  bradley
-Removed deprecated debug and log levels and replaced them with modern equivalents.
-
-Revision 1.3  2004/04/08 09:29:55  bradley
-Manually do host->network byte order conversion to avoid needing libraries for htons/htonl. Changed
-hex dumps to better separate hex and ASCII. Added support for %.8a syntax in DebugSNPrintF for Fibre
-Channel addresses (00:11:22:33:44:55:66:77). Fixed a few places where HeaderDoc was incorrect.
-
-Revision 1.2  2004/03/07 05:59:34  bradley
-Sync'd with internal version: Added expect macros, error codes, and CoreServices exclusion.
-
-Revision 1.1  2004/01/30 02:27:30  bradley
-Debugging support for various platforms.
-
-
        To Do:
        
        - Use StackWalk on Windows to optionally print stack frames.
index 7111fa2a183dd60a23de057f89d45627b7b7666c..28cd2e7c71ea0ef0600767b4551f09ca45264811 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: DebugServices.h,v $
-Revision 1.5  2006/08/14 23:24:56  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.4  2004/04/15 08:59:08  bradley
-Removed deprecated debug and log levels and replaced them with modern equivalents.
-
-Revision 1.3  2004/04/08 09:29:55  bradley
-Manually do host->network byte order conversion to avoid needing libraries for htons/htonl. Changed
-hex dumps to better separate hex and ASCII. Added support for %.8a syntax in DebugSNPrintF for Fibre
-Channel addresses (00:11:22:33:44:55:66:77). Fixed a few places where HeaderDoc was incorrect.
-
-Revision 1.2  2004/03/07 05:59:34  bradley
-Sync'd with internal version: Added expect macros, error codes, and CoreServices exclusion.
-
-Revision 1.1  2004/01/30 02:27:30  bradley
-Debugging support for various platforms.
-
-*/
+ */
 
 //---------------------------------------------------------------------------------------------------------------------------
 /*!    @header         DebugServices
@@ -521,7 +500,9 @@ typedef uint32_t            DebugPropertyTag;
        work with GCC due to GCC allow a zero-length array. Using a -1 condition turned out to be more portable.
 */
 
+#ifndef check_compile_time
 #define        check_compile_time( X )         extern int debug_compile_time_name[ ( X ) ? 1 : -1 ]
+#endif
 
 //---------------------------------------------------------------------------------------------------------------------------
 /*!    @defined        check_compile_time_code
index d9f9033425e1a05a10e2bcacb800e091d173db1d..6e371b9db52994208a6ed6422b79de156e8db1e8 100644 (file)
 
        Version:        1.0
        Tabs:           4 spaces
-
-    Change History (most recent first):
-
-$Log: GenLinkedList.c,v $
-Revision 1.4  2006/08/14 23:24:56  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2004/04/22 21:14:42  cheshire
-Fix comment spelling mistake
-
-Revision 1.2  2004/02/05 07:41:08  cheshire
-Add Log header
-
-*/
+ */
 
 #include "GenLinkedList.h"
 
index 4df6e67c47f15360ee7e2aadce3f772394849082..4e177083c75cc19adc3e1b40ab53444b1f6c31dd 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-       File:           GenLinkedList.c
-
-       Contains:       interface to generic linked lists.
-
-       Version:        1.0
-       Tabs:           4 spaces
-
-    Change History (most recent first):
-
-$Log: GenLinkedList.h,v $
-Revision 1.3  2006/08/14 23:24:56  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/02/05 07:41:08  cheshire
-Add Log header
-
-*/
+ */
 
 #ifndef __GenLinkedList__
 #define __GenLinkedList__
index 85e9d0297bae1aeda3e5b9fd37a01499e7196302..b99d341c2fa2a1ba711e49332b1d1f0b5ae23e69 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: BaseListener.java,v $
-Revision 1.3  2006/08/14 23:25:08  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/04/30 21:48:27  rpantos
-Change line endings for CVS.
-
-Revision 1.1  2004/04/30 16:29:35  rpantos
-First checked in.
-
  */
 
 
index b254c9752e00a2efb0a3239345f37a9b75c9ceeb..b92b9dc59f91084f2f8340d161c8795cd79014c1 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: BrowseListener.java,v $
-Revision 1.3  2006/08/14 23:25:08  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/04/30 21:48:27  rpantos
-Change line endings for CVS.
-
-Revision 1.1  2004/04/30 16:29:35  rpantos
-First checked in.
-
  */
 
 
index 5050a7a60ef9ac33d9d27c7b8c3886197638e5a3..a853d091fa2dc7f08411495f6095f4b5774a05e8 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: DNSRecord.java,v $
-Revision 1.3  2006/08/14 23:25:08  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/12/11 03:00:59  rpantos
-<rdar://problem/3907498> Java DNSRecord API should be cleaned up
-
-Revision 1.1  2004/04/30 16:32:34  rpantos
-First checked in.
-
-
  */
 
 
index e608869f8618b47239f317e0f3cd74ee6eab73c6..f749a88ead863f01f0c8db155e988c908f061ae8 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
 
-    Change History (most recent first):
-
-$Log: DNSSD.java,v $
-Revision 1.16  2008/11/04 20:06:20  cheshire
-<rdar://problem/6186231> Change MAX_DOMAIN_NAME to 256
-
-Revision 1.15  2007/03/13 00:28:03  vazquez
-<rdar://problem/4625928> Java: Rename exported symbols in libjdns_sd.jnilib
-
-Revision 1.14  2007/03/13 00:10:14  vazquez
-<rdar://problem/4455206> Java: 64 bit JNI patch
-
-Revision 1.13  2007/02/24 23:08:02  mkrochma
-<rdar://problem/5001673> Typo in Bonjour Java API document
-
-Revision 1.12  2007/02/09 00:33:02  cheshire
-Add missing error codes to kMessages array
-
-Revision 1.11  2006/08/14 23:25:08  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.10  2006/06/20 23:05:55  rpantos
-<rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
-
-Revision 1.9  2005/10/26 01:52:24  cheshire
-<rdar://problem/4316286> Race condition in Java code (doesn't work at all on Linux)
-
-Revision 1.8  2005/07/11 01:55:21  cheshire
-<rdar://problem/4175511> Race condition in Java API
-
-Revision 1.7  2005/07/05 13:01:52  cheshire
-<rdar://problem/4169791> If mDNSResponder daemon is stopped, Java API spins, burning CPU time
-
-Revision 1.6  2005/07/05 00:02:25  cheshire
-Add missing comma
-
-Revision 1.5  2005/07/04 21:13:47  cheshire
-Add missing error message strings
-
-Revision 1.4  2004/12/11 03:00:59  rpantos
-<rdar://problem/3907498> Java DNSRecord API should be cleaned up
-
-Revision 1.3  2004/11/12 03:23:08  rpantos
-rdar://problem/3809541 implement getIfIndexForName, getNameForIfIndex.
-
-Revision 1.2  2004/05/20 17:43:18  cheshire
-Fix invalid UTF-8 characters in file
-
-Revision 1.1  2004/04/30 16:32:34  rpantos
-First checked in.
-
-
        This file declares and implements DNSSD, the central Java factory class
        for doing DNS Service Discovery. It includes the mostly-abstract public
        interface, as well as the Apple* implementation subclasses.
@@ -481,7 +429,7 @@ abstract public class       DNSSD
        static protected final DNSSD    getInstance()
        {
                SecurityManager sm = System.getSecurityManager();
-        if ( sm != null)
+        if (sm != null)
             sm.checkPermission( new RuntimePermission( "getDNSSDInstance"));
                 return fInstance;
        }
@@ -524,9 +472,9 @@ abstract public class       DNSSD
                try
                {
                        String name = System.getProperty( "com.apple.dnssd.DNSSD" );
-                       if( name == null )
+                       if (name == null)
                                name = "com.apple.dnssd.AppleDNSSD";    // Fall back to Apple-provided class.
-                       fInstance = (DNSSD) Class.forName( name ).newInstance();
+                       fInstance = (DNSSD) Class.forName(name).newInstance();
                }
                catch( Exception e )
                {
@@ -577,7 +525,7 @@ class       AppleDNSSDException extends DNSSDException
                        "NATPORTMAPPINGDISABLED"
                };
        
-               if ( fErrorCode <= UNKNOWN && fErrorCode > ( UNKNOWN - kMessages.length))
+               if (fErrorCode <= UNKNOWN && fErrorCode > ( UNKNOWN - kMessages.length))
                {
                        return "DNS-SD Error " + String.valueOf( fErrorCode) + ": " + kMessages[ UNKNOWN - fErrorCode];
                }
@@ -597,7 +545,7 @@ class       AppleDNSSD extends DNSSD
        
                int             libInitResult = InitLibrary( 2);        // Current version number (must be sync'd with jnilib version)
 
-               if ( libInitResult != DNSSDException.NO_ERROR)
+               if (libInitResult != DNSSDException.NO_ERROR)
                        throw new InternalError( "cannot instantiate DNSSD: " + new AppleDNSSDException( libInitResult).getMessage());
        }
 
@@ -649,7 +597,7 @@ class       AppleDNSSD extends DNSSD
                String[]        responseHolder = new String[1]; // lame maneuver to get around Java's lack of reference parameters
 
                int rc = ConstructName( serviceName, regType, domain, responseHolder);
-               if ( rc != 0)
+               if (rc != 0)
                        throw new AppleDNSSDException( rc);
 
                return responseHolder[0];
@@ -700,7 +648,7 @@ class       AppleService implements DNSSDService, Runnable
 
        protected void                  ThrowOnErr( int rc) throws DNSSDException
        {
-               if ( rc != 0)
+               if (rc != 0)
                        throw new AppleDNSSDException( rc);
        }
 
@@ -754,7 +702,7 @@ class       AppleBrowser extends AppleService
        {
                super(client);
                this.ThrowOnErr( this.CreateBrowser( flags, ifIndex, regType, domain));
-               if ( !AppleDNSSD.hasAutoCallbacks)
+               if (!AppleDNSSD.hasAutoCallbacks)
                        new Thread(this).start();
        }
 
@@ -770,7 +718,7 @@ class       AppleResolver extends AppleService
        {
                super(client);
                this.ThrowOnErr( this.CreateResolver( flags, ifIndex, serviceName, regType, domain));
-               if ( !AppleDNSSD.hasAutoCallbacks)
+               if (!AppleDNSSD.hasAutoCallbacks)
                        new Thread(this).start();
        }
 
@@ -805,7 +753,7 @@ class       AppleDNSRecord implements DNSRecord
 
        protected void                  ThrowOnErr( int rc) throws DNSSDException
        {
-               if ( rc != 0)
+               if (rc != 0)
                        throw new AppleDNSSDException( rc);
        }
 
@@ -822,7 +770,7 @@ class       AppleRegistration extends AppleService implements DNSSDRegistration
        {
                super(client);
                this.ThrowOnErr( this.BeginRegister( ifIndex, flags, serviceName, regType, domain, host, port, txtRecord));
-               if ( !AppleDNSSD.hasAutoCallbacks)
+               if (!AppleDNSSD.hasAutoCallbacks)
                        new Thread(this).start();
        }
 
@@ -856,7 +804,7 @@ class       AppleRecordRegistrar extends AppleService implements DNSSDRecordRegistrar
        {
                super(listener);
                this.ThrowOnErr( this.CreateConnection());
-               if ( !AppleDNSSD.hasAutoCallbacks)
+               if (!AppleDNSSD.hasAutoCallbacks)
                        new Thread(this).start();
        }
 
@@ -886,7 +834,7 @@ class       AppleQuery extends AppleService
        {
                super(client);
                this.ThrowOnErr( this.CreateQuery( flags, ifIndex, serviceName, rrtype, rrclass));
-               if ( !AppleDNSSD.hasAutoCallbacks)
+               if (!AppleDNSSD.hasAutoCallbacks)
                        new Thread(this).start();
        }
 
@@ -901,7 +849,7 @@ class       AppleDomainEnum extends AppleService
        {
                super(client);
                this.ThrowOnErr( this.BeginEnum( flags, ifIndex));
-               if ( !AppleDNSSD.hasAutoCallbacks)
+               if (!AppleDNSSD.hasAutoCallbacks)
                        new Thread(this).start();
        }
 
index 1c1e9d8fabb0219d0b397ef1ba773b5e95be80a2..99549b5d68a769ea99e0257bc075978f551976df 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: DNSSDException.java,v $
-Revision 1.6  2007/02/08 23:58:17  cheshire
-Added comment about updating kMessages array in AppleDNSSDException (DNSSD.java)
-
-Revision 1.5  2007/02/07 01:19:36  cheshire
-<rdar://problem/4849427> API: Reconcile conflicting error code values
-
-Revision 1.4  2006/08/14 23:25:08  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2005/07/10 22:19:01  cheshire
-Add missing error codes to list of public static final ints
-
-Revision 1.2  2004/04/30 21:48:27  rpantos
-Change line endings for CVS.
-
-Revision 1.1  2004/04/30 16:29:35  rpantos
-First checked in.
-
-*/
+ */
 
 package        com.apple.dnssd;
 
index 825634f0c3eae7e1b7623b42c235b51000a3a93c..3baac677b19cfa780c699dbc351d9941e35cd650 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-       This file declares the public interface to DNSSDRecordRegistrar, a DNSSDService
-       subclass that allows efficient registration of multiple individual records.
-
-    Change History (most recent first):
-
-$Log: DNSSDRecordRegistrar.java,v $
-Revision 1.2  2006/08/14 23:25:08  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.1  2006/06/20 23:00:12  rpantos
-<rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
-
  */
 
 
index 86f2d831cd702d06f0f5ed95d3b5d784b69a41fa..720df0b8471c22ed130bea593b3593f462a5dfc1 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: DNSSDRegistration.java,v $
-Revision 1.3  2006/08/14 23:25:08  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/12/11 03:01:00  rpantos
-<rdar://problem/3907498> Java DNSRecord API should be cleaned up
-
-Revision 1.1  2004/04/30 16:32:34  rpantos
-First checked in.
-
-
-       This file declares the public interface to DNSSDRegistration, a DNSSDService
-       subclass that allows a client to control a service registration.
  */
 
 
index d5a8a38825a7ef93d95ef44a06d4629db245009d..10f74021e6ab930e3974cc8949d55129e301a3f6 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: DNSSDService.java,v $
-Revision 1.3  2006/08/14 23:25:08  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/04/30 21:48:27  rpantos
-Change line endings for CVS.
-
-Revision 1.1  2004/04/30 16:32:34  rpantos
-First checked in.
-
  */
 
 
index 233c188da00dbd05a5b2caec7f92c4397974044e..852f6430e5f410029a53223e9f56337e348bc8ef 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: DomainListener.java,v $
-Revision 1.3  2006/08/14 23:25:08  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/04/30 21:48:27  rpantos
-Change line endings for CVS.
-
-Revision 1.1  2004/04/30 16:29:35  rpantos
-First checked in.
-
  */
 
 
index c1d3b66687bd8f1f5c445eddd0dbb29ef56ab89b..fef5c981b2948928613c6febc04702957379e661 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
 
-    Change History (most recent first):
-
-$Log: JNISupport.c,v $
-Revision 1.22  2007/11/30 23:38:53  cheshire
-Fix compiler warning:
-/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers/jni.h:609: warning: declaration of 'index' shadows a global declaration
-
-Revision 1.21  2007/09/18 19:09:02  cheshire
-<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
-
-Revision 1.20  2007/03/13 01:41:46  cheshire
-Fixed compile warnings when building 32-bit
-
-Revision 1.19  2007/03/13 00:28:03  vazquez
-<rdar://problem/4625928> Java: Rename exported symbols in libjdns_sd.jnilib
-
-Revision 1.18  2007/03/13 00:10:14  vazquez
-<rdar://problem/4455206> Java: 64 bit JNI patch
-
-Revision 1.17  2006/08/14 23:25:08  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.16  2006/07/14 02:35:47  cheshire
-Added (commented out) syslog debugging messages
-
-Revision 1.15  2006/06/27 19:34:43  cheshire
-<rdar://problem/4430023> txtRecord parameter of DNSServiceResolveReply() should be unsigned char *
-
-Revision 1.14  2006/06/20 23:03:35  rpantos
-<rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
-
-Revision 1.13  2005/10/26 01:52:24  cheshire
-<rdar://problem/4316286> Race condition in Java code (doesn't work at all on Linux)
-
-Revision 1.12  2005/07/13 19:20:32  cheshire
-<rdar://problem/4175511> Race condition in Java API
-Additional cleanup suggested by Roger -- NewContext() doesn't need ownerClass parameter any more
-
-Revision 1.11  2005/07/11 01:55:21  cheshire
-<rdar://problem/4175511> Race condition in Java API
-
-Revision 1.10  2005/07/05 13:01:52  cheshire
-<rdar://problem/4169791> If mDNSResponder daemon is stopped, Java API spins, burning CPU time
-
-Revision 1.9  2004/12/11 03:01:00  rpantos
-<rdar://problem/3907498> Java DNSRecord API should be cleaned up
-
-Revision 1.8  2004/11/30 23:51:05  cheshire
-Remove double semicolons
-
-Revision 1.7  2004/11/23 08:12:04  shersche
-Implement if_nametoindex and if_indextoname for Win32 platforms
-
-Revision 1.6  2004/11/23 03:41:14  cheshire
-Change JNISupport.c to call if_indextoname & if_nametoindex directly.
-(May require some additional glue code to work on Windows.)
-
-Revision 1.5  2004/11/17 17:07:44  cheshire
-Updated comment about AUTO_CALLBACKS
-
-Revision 1.4  2004/11/12 03:23:09  rpantos
-rdar://problem/3809541 implement getIfIndexForName, getNameForIfIndex.
-
-Revision 1.3  2004/06/18 04:44:17  rpantos
-Adapt to API unification on Windows
-
-Revision 1.2  2004/05/28 23:34:42  ksekar
-<rdar://problem/3672903>: Java project build errors
-
-Revision 1.1  2004/04/30 16:29:35  rpantos
-First checked in.
-
-
        This file contains the platform support for DNSSD and related Java classes.
        It is used to shim through to the underlying <dns_sd.h> API.
  */
@@ -988,13 +915,16 @@ JNIEXPORT void JNICALL Java_com_apple_dnssd_AppleDNSSD_ReconfirmRecord( JNIEnv *
 }
 
 #define LOCAL_ONLY_NAME "loo"
+#define P2P_NAME "p2p"
 
 JNIEXPORT jstring JNICALL Java_com_apple_dnssd_AppleDNSSD_GetNameForIfIndex( JNIEnv *pEnv, jobject pThis _UNUSED,
                                                        jint ifIndex)
 {
        char                                    *p = LOCAL_ONLY_NAME, nameBuff[IF_NAMESIZE];
 
-       if (ifIndex != (jint) kDNSServiceInterfaceIndexLocalOnly)
+       if (ifIndex == (jint) kDNSServiceInterfaceIndexP2P)
+               p = P2P_NAME;
+       else if (ifIndex != (jint) kDNSServiceInterfaceIndexLocalOnly)
                p = if_indextoname( ifIndex, nameBuff );
 
        return (*pEnv)->NewStringUTF( pEnv, p);
@@ -1007,7 +937,9 @@ JNIEXPORT jint JNICALL Java_com_apple_dnssd_AppleDNSSD_GetIfIndexForName( JNIEnv
        uint32_t                                ifIndex = kDNSServiceInterfaceIndexLocalOnly;
        const char                              *nameStr = SafeGetUTFChars( pEnv, ifName);
 
-       if (strcmp(nameStr, LOCAL_ONLY_NAME))
+       if (strcmp(nameStr, P2P_NAME) == 0)
+               ifIndex = kDNSServiceInterfaceIndexP2P;
+       else if (strcmp(nameStr, LOCAL_ONLY_NAME))
                ifIndex = if_nametoindex( nameStr);
 
        SafeReleaseUTFChars( pEnv, ifName, nameStr);
index 712a6ee5280f0f18da256f50d3591a6af03ccdae..0decb7fc4a2ec5d1afe3a0869bb5826248c14b9a 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: QueryListener.java,v $
-Revision 1.4  2007/03/12 23:43:08  vazquez
-<rdar://problem/4169128> Documentation: Error in Java queryAnswered doc
-
-Revision 1.3  2006/08/14 23:25:08  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/04/30 21:48:27  rpantos
-Change line endings for CVS.
-
-Revision 1.1  2004/04/30 16:29:35  rpantos
-First checked in.
-
  */
 
 
index ea573f0152d626661f8e0670368e609cca5967c3..00fa1a63443765549b89a530082c46100272dc3d 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: RegisterListener.java,v $
-Revision 1.3  2006/08/14 23:25:08  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/04/30 21:48:27  rpantos
-Change line endings for CVS.
-
-Revision 1.1  2004/04/30 16:29:35  rpantos
-First checked in.
-
  */
 
 
index 247e5d5ccf112469266a8b6d2c3639e330d58a71..6fecf8d81eba3a6e72936ab3e574af74d7e968c1 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: RegisterRecordListener.java,v $
-Revision 1.2  2006/08/14 23:25:08  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.1  2006/06/20 23:00:12  rpantos
-<rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
-
-
  */
 
 
index 168edb21f29d5a6f58240c20ff6780935019275f..33dafa38dfe3738989286e1c509bf41cf6d17a0d 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: ResolveListener.java,v $
-Revision 1.3  2006/08/14 23:25:08  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/04/30 21:48:27  rpantos
-Change line endings for CVS.
-
-Revision 1.1  2004/04/30 16:29:35  rpantos
-First checked in.
-
-*/
+ */
 
 
 package        com.apple.dnssd;
index 16aff3cc9aa01b8de1291c009cd360713ab7f28a..8d9df7a1496b0919772b71c6ec6a86c883944c8a 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
 
-    Change History (most recent first):
-
-$Log: TXTRecord.java,v $
-Revision 1.8  2007/03/16 23:39:40  vazquez
-<rdar://problem/4612778> Java: Coding error in java wrappers, limited TXTRecord length
-
-Revision 1.7  2006/12/13 07:13:23  mkrochma
-<rdar://problem/4612778> Java: Coding error in java wrappers, limited TXTRecord length
-
-Revision 1.6  2006/08/14 23:25:08  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.5  2004/08/25 21:54:36  rpantos
-<rdar://problem/3773973> Fix getValue() for values containing '='.
-
-Revision 1.4  2004/08/04 01:04:50  rpantos
-<rdar://problems/3731579&3731582> Fix set(); add remove() & toString().
-
-Revision 1.3  2004/07/13 21:24:25  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.2  2004/04/30 21:48:27  rpantos
-Change line endings for CVS.
-
-Revision 1.1  2004/04/30 16:29:35  rpantos
-First checked in.
-
        To do:
        - implement remove()
        - fix set() to replace existing values
index c3bf9ccf0218a7a361133ef07a143cbcb2f31176..a2c74091a3a1a46c358a195b5e6fffd155106daa 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: PlatformCommon.c,v $
-Revision 1.21  2009/04/11 00:20:24  jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.20  2008/10/09 22:26:05  cheshire
-Save space by not showing high-resolution timestamp in LogMsgNoIdent() lines
-
-Revision 1.19  2008/07/14 17:43:36  mkrochma
-Fix previous check in so connect still gets called
-
-Revision 1.18  2008/07/12 17:19:41  mkrochma
-<rdar://problem/6068351> mDNSResponder PlatformCommon.c uses sin_len even on non-compliant platforms
-
-Revision 1.17  2008/03/05 00:19:09  cheshire
-Conditionalize LogTimeStamps so it's specific to APPLE_OSX, for now
-
-Revision 1.16  2008/02/26 21:47:45  cheshire
-Added cast to avoid compiler warning
-
-Revision 1.15  2008/02/26 21:42:26  cheshire
-Added 'LogTimeStamps' option, to show ms-granularity timestamps on every log message
-
-Revision 1.14  2007/12/03 18:37:26  cheshire
-Moved mDNSPlatformWriteLogMsg & mDNSPlatformWriteDebugMsg
-from mDNSMacOSX.c to PlatformCommon.c, so that Posix build can use them
-
-Revision 1.13  2007/10/22 20:07:07  cheshire
-Moved mDNSPlatformSourceAddrForDest from mDNSMacOSX.c to PlatformCommon.c so
-Posix build can share the code (better than just pasting it into mDNSPosix.c)
-
-Revision 1.12  2007/10/16 17:19:53  cheshire
-<rdar://problem/3557903> Performance: Core code will not work on platforms with small stacks
-Cut ReadDDNSSettingsFromConfFile stack from 2112 to 1104 bytes
-
-Revision 1.11  2007/07/31 23:08:34  mcguire
-<rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
-
-Revision 1.10  2007/07/11 02:59:58  cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-Add AutoTunnel parameter to mDNS_SetSecretForDomain
-
-Revision 1.9  2007/01/09 22:37:44  cheshire
-Remove unused ClearDomainSecrets() function
-
-Revision 1.8  2006/12/22 20:59:51  cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.7  2006/08/14 23:24:56  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.6  2005/04/08 21:30:16  ksekar
-<rdar://problem/4007457> Compiling problems with mDNSResponder-98 on Solaris/Sparc v9
-Patch submitted by Bernd Kuhls
-
-Revision 1.5  2005/02/01 19:33:30  ksekar
-<rdar://problem/3985239> Keychain format too restrictive
-
-Revision 1.4  2005/01/19 19:19:21  ksekar
-<rdar://problem/3960191> Need a way to turn off domain discovery
-
-Revision 1.3  2004/12/13 17:46:52  cheshire
-Use sizeof(buf) instead of fixed constant 1024
-
-Revision 1.2  2004/12/01 03:30:29  cheshire
-<rdar://problem/3889346> Add Unicast DNS support to mDNSPosix
-
-Revision 1.1  2004/12/01 01:51:35  cheshire
-Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c
-
  */
 
 #include <stdio.h>                             // Needed for fopen() etc.
index 44beb1c0ea71838529ed5d751ad12682afe25f4f..631e3d731a686b91611236d0342fd6b30fcc2910 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: PlatformCommon.h,v $
-Revision 1.8  2007/10/22 20:07:52  cheshire
-Deleted unused FindSourceAddrForIP() function
-
-Revision 1.7  2007/07/31 23:08:34  mcguire
-<rdar://problem/5329542> BTMM: Make AutoTunnel mode work with multihoming
-
-Revision 1.6  2007/01/09 22:37:43  cheshire
-Remove unused ClearDomainSecrets() function
-
-Revision 1.5  2006/12/22 20:59:51  cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.4  2006/08/14 23:24:56  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2005/01/19 19:19:21  ksekar
-<rdar://problem/3960191> Need a way to turn off domain discovery
-
-Revision 1.2  2004/12/01 03:30:29  cheshire
-<rdar://problem/3889346> Add Unicast DNS support to mDNSPosix
-
-Revision 1.1  2004/12/01 01:51:35  cheshire
-Move ReadDDNSSettingsFromConfFile() from mDNSMacOSX.c to PlatformCommon.c
-
  */
 
 extern void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain, mDNSBool *DomainDiscoveryDisabled);
index 0e4e2b6ffe4fdf4be0b5c5c9ac36c5b7a2df4720..da9f37aeb7665e9931e08985dba9d7cffe284ae6 100644 (file)
 .\" See the License for the specific language governing permissions and
 .\" limitations under the License.
 .\"
-.\" $Log: dns-sd.1,v $
-.\" Revision 1.6  2006/08/14 23:24:56  cheshire
-.\" Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-.\"
-.\" Revision 1.5  2005/07/04 23:12:35  cheshire
-.\" <rdar://problem/4103628> The dns-sd command first appeared in Mac OS X 10.4 (Tiger)
-.\"
-.\" Revision 1.4  2005/02/16 02:29:32  cheshire
-.\" Update terminology
-.\"
-.\" Revision 1.3  2005/02/10 22:35:28  cheshire
-.\" <rdar://problem/3727944> Update name
-.\"
-.\" Revision 1.2  2004/09/24 18:33:05  cheshire
-.\" <rdar://problem/3561780> Update man pages to clarify that mDNS and dns-sd are not intended for script use
-.\"
-.\" Revision 1.1  2004/09/22 22:46:25  cheshire
-.\" Man page for dns-sd command-line tool
-.\"
-.\"
-.\"
 .Dd April 2004              \" Date
 .Dt dns-sd 1                \" Document Title
 .Os Darwin                  \" Operating System
index 1cffd7c2e844e5296806a6c168d3d508f9a2ac8b..2ed91f08e59036a421ecefe5fa8f6e540ed25ad5 100644 (file)
  */
 
 #ifndef _DNS_SD_H
-#define _DNS_SD_H 2140302
+#define _DNS_SD_H 2581300
 
 #ifdef  __cplusplus
     extern "C" {
 #endif
 
+/* Set to 1 if libdispatch is supported
+ * Note: May also be set by project and/or Makefile
+ */
+#ifndef _DNS_SD_LIBDISPATCH
+#define _DNS_SD_LIBDISPATCH 0
+#endif /* ndef _DNS_SD_LIBDISPATCH */
+
 /* standard calling convention under Win32 is __stdcall */
 /* Note: When compiling Intel EFI (Extensible Firmware Interface) under MS Visual Studio, the */
 /* _WIN32 symbol is defined by the compiler even though it's NOT compiling code for Windows32 */
@@ -129,6 +136,10 @@ typedef INT32       int32_t;
 #include <stdint.h>
 #endif
 
+#if _DNS_SD_LIBDISPATCH
+#include <dispatch/dispatch.h>
+#endif
+
 /* DNSServiceRef, DNSRecordRef
  *
  * Opaque internal data types.
@@ -331,8 +342,15 @@ enum
      */
 
     kDNSServiceFlagsSuppressUnusable    = 0x8000
-    /* Placeholder definition, for future use
-     */
+       /*
+        * This flag is meaningful only in DNSServiceQueryRecord which suppresses unusable queries on the
+        * wire. If "hostname" is a wide-area unicast DNS hostname (i.e. not a ".local." name)
+        * but this host has no routable IPv6 address, then the call will not try to look up IPv6 addresses
+        * for "hostname", since any addresses it found would be unlikely to be of any use anyway. Similarly,
+        * if this host has no routable IPv4 address, the call will not try to look up IPv4 addresses for
+        * "hostname".
+        */
+
     };
 
 /* Possible protocols for DNSServiceNATPortMappingCreate(). */
@@ -368,73 +386,73 @@ enum
 
 enum
     {
-    kDNSServiceType_A         = 1,      /* Host address. */
-    kDNSServiceType_NS        = 2,      /* Authoritative server. */
-    kDNSServiceType_MD        = 3,      /* Mail destination. */
-    kDNSServiceType_MF        = 4,      /* Mail forwarder. */
-    kDNSServiceType_CNAME     = 5,      /* Canonical name. */
-    kDNSServiceType_SOA       = 6,      /* Start of authority zone. */
-    kDNSServiceType_MB        = 7,      /* Mailbox domain name. */
-    kDNSServiceType_MG        = 8,      /* Mail group member. */
-    kDNSServiceType_MR        = 9,      /* Mail rename name. */
-    kDNSServiceType_NULL      = 10,     /* Null resource record. */
-    kDNSServiceType_WKS       = 11,     /* Well known service. */
-    kDNSServiceType_PTR       = 12,     /* Domain name pointer. */
-    kDNSServiceType_HINFO     = 13,     /* Host information. */
-    kDNSServiceType_MINFO     = 14,     /* Mailbox information. */
-    kDNSServiceType_MX        = 15,     /* Mail routing information. */
-    kDNSServiceType_TXT       = 16,     /* One or more text strings (NOT "zero or more..."). */
-    kDNSServiceType_RP        = 17,     /* Responsible person. */
-    kDNSServiceType_AFSDB     = 18,     /* AFS cell database. */
-    kDNSServiceType_X25       = 19,     /* X_25 calling address. */
-    kDNSServiceType_ISDN      = 20,     /* ISDN calling address. */
-    kDNSServiceType_RT        = 21,     /* Router. */
-    kDNSServiceType_NSAP      = 22,     /* NSAP address. */
-    kDNSServiceType_NSAP_PTR  = 23,     /* Reverse NSAP lookup (deprecated). */
-    kDNSServiceType_SIG       = 24,     /* Security signature. */
-    kDNSServiceType_KEY       = 25,     /* Security key. */
-    kDNSServiceType_PX        = 26,     /* X.400 mail mapping. */
-    kDNSServiceType_GPOS      = 27,     /* Geographical position (withdrawn). */
-    kDNSServiceType_AAAA      = 28,     /* IPv6 Address. */
-    kDNSServiceType_LOC       = 29,     /* Location Information. */
-    kDNSServiceType_NXT       = 30,     /* Next domain (security). */
-    kDNSServiceType_EID       = 31,     /* Endpoint identifier. */
-    kDNSServiceType_NIMLOC    = 32,     /* Nimrod Locator. */
-    kDNSServiceType_SRV       = 33,     /* Server Selection. */
-    kDNSServiceType_ATMA      = 34,     /* ATM Address */
-    kDNSServiceType_NAPTR     = 35,     /* Naming Authority PoinTeR */
-    kDNSServiceType_KX        = 36,     /* Key Exchange */
-    kDNSServiceType_CERT      = 37,     /* Certification record */
-    kDNSServiceType_A6        = 38,     /* IPv6 Address (deprecated) */
-    kDNSServiceType_DNAME     = 39,     /* Non-terminal DNAME (for IPv6) */
-    kDNSServiceType_SINK      = 40,     /* Kitchen sink (experimental) */
-    kDNSServiceType_OPT       = 41,     /* EDNS0 option (meta-RR) */
-    kDNSServiceType_APL       = 42,     /* Address Prefix List */
-    kDNSServiceType_DS        = 43,     /* Delegation Signer */
-    kDNSServiceType_SSHFP     = 44,     /* SSH Key Fingerprint */
-    kDNSServiceType_IPSECKEY  = 45,     /* IPSECKEY */
-    kDNSServiceType_RRSIG     = 46,     /* RRSIG */
-    kDNSServiceType_NSEC      = 47,     /* Denial of Existence */
-    kDNSServiceType_DNSKEY    = 48,     /* DNSKEY */
-    kDNSServiceType_DHCID     = 49,     /* DHCP Client Identifier */
-    kDNSServiceType_NSEC3     = 50,     /* Hashed Authenticated Denial of Existence */
-    kDNSServiceType_NSEC3PARAM= 51,     /* Hashed Authenticated Denial of Existence */
-
-    kDNSServiceType_HIP       = 55,     /* Host Identity Protocol */
-
-    kDNSServiceType_SPF       = 99,     /* Sender Policy Framework for E-Mail */
-    kDNSServiceType_UINFO     = 100,    /* IANA-Reserved */
-    kDNSServiceType_UID       = 101,    /* IANA-Reserved */
-    kDNSServiceType_GID       = 102,    /* IANA-Reserved */
-    kDNSServiceType_UNSPEC    = 103,    /* IANA-Reserved */
-
-    kDNSServiceType_TKEY      = 249,    /* Transaction key */
-    kDNSServiceType_TSIG      = 250,    /* Transaction signature. */
-    kDNSServiceType_IXFR      = 251,    /* Incremental zone transfer. */
-    kDNSServiceType_AXFR      = 252,    /* Transfer zone of authority. */
-    kDNSServiceType_MAILB     = 253,    /* Transfer mailbox records. */
-    kDNSServiceType_MAILA     = 254,    /* Transfer mail agent records. */
-    kDNSServiceType_ANY       = 255     /* Wildcard match. */
+    kDNSServiceType_A          = 1,      /* Host address. */
+    kDNSServiceType_NS         = 2,      /* Authoritative server. */
+    kDNSServiceType_MD         = 3,      /* Mail destination. */
+    kDNSServiceType_MF         = 4,      /* Mail forwarder. */
+    kDNSServiceType_CNAME      = 5,      /* Canonical name. */
+    kDNSServiceType_SOA        = 6,      /* Start of authority zone. */
+    kDNSServiceType_MB         = 7,      /* Mailbox domain name. */
+    kDNSServiceType_MG         = 8,      /* Mail group member. */
+    kDNSServiceType_MR         = 9,      /* Mail rename name. */
+    kDNSServiceType_NULL       = 10,     /* Null resource record. */
+    kDNSServiceType_WKS        = 11,     /* Well known service. */
+    kDNSServiceType_PTR        = 12,     /* Domain name pointer. */
+    kDNSServiceType_HINFO      = 13,     /* Host information. */
+    kDNSServiceType_MINFO      = 14,     /* Mailbox information. */
+    kDNSServiceType_MX         = 15,     /* Mail routing information. */
+    kDNSServiceType_TXT        = 16,     /* One or more text strings (NOT "zero or more..."). */
+    kDNSServiceType_RP         = 17,     /* Responsible person. */
+    kDNSServiceType_AFSDB      = 18,     /* AFS cell database. */
+    kDNSServiceType_X25        = 19,     /* X_25 calling address. */
+    kDNSServiceType_ISDN       = 20,     /* ISDN calling address. */
+    kDNSServiceType_RT         = 21,     /* Router. */
+    kDNSServiceType_NSAP       = 22,     /* NSAP address. */
+    kDNSServiceType_NSAP_PTR   = 23,     /* Reverse NSAP lookup (deprecated). */
+    kDNSServiceType_SIG        = 24,     /* Security signature. */
+    kDNSServiceType_KEY        = 25,     /* Security key. */
+    kDNSServiceType_PX         = 26,     /* X.400 mail mapping. */
+    kDNSServiceType_GPOS       = 27,     /* Geographical position (withdrawn). */
+    kDNSServiceType_AAAA       = 28,     /* IPv6 Address. */
+    kDNSServiceType_LOC        = 29,     /* Location Information. */
+    kDNSServiceType_NXT        = 30,     /* Next domain (security). */
+    kDNSServiceType_EID        = 31,     /* Endpoint identifier. */
+    kDNSServiceType_NIMLOC     = 32,     /* Nimrod Locator. */
+    kDNSServiceType_SRV        = 33,     /* Server Selection. */
+    kDNSServiceType_ATMA       = 34,     /* ATM Address */
+    kDNSServiceType_NAPTR      = 35,     /* Naming Authority PoinTeR */
+    kDNSServiceType_KX         = 36,     /* Key Exchange */
+    kDNSServiceType_CERT       = 37,     /* Certification record */
+    kDNSServiceType_A6         = 38,     /* IPv6 Address (deprecated) */
+    kDNSServiceType_DNAME      = 39,     /* Non-terminal DNAME (for IPv6) */
+    kDNSServiceType_SINK       = 40,     /* Kitchen sink (experimental) */
+    kDNSServiceType_OPT        = 41,     /* EDNS0 option (meta-RR) */
+    kDNSServiceType_APL        = 42,     /* Address Prefix List */
+    kDNSServiceType_DS         = 43,     /* Delegation Signer */
+    kDNSServiceType_SSHFP      = 44,     /* SSH Key Fingerprint */
+    kDNSServiceType_IPSECKEY   = 45,     /* IPSECKEY */
+    kDNSServiceType_RRSIG      = 46,     /* RRSIG */
+    kDNSServiceType_NSEC       = 47,     /* Denial of Existence */
+    kDNSServiceType_DNSKEY     = 48,     /* DNSKEY */
+    kDNSServiceType_DHCID      = 49,     /* DHCP Client Identifier */
+    kDNSServiceType_NSEC3      = 50,     /* Hashed Authenticated Denial of Existence */
+    kDNSServiceType_NSEC3PARAM = 51,     /* Hashed Authenticated Denial of Existence */
+
+    kDNSServiceType_HIP        = 55,     /* Host Identity Protocol */
+
+    kDNSServiceType_SPF        = 99,     /* Sender Policy Framework for E-Mail */
+    kDNSServiceType_UINFO      = 100,    /* IANA-Reserved */
+    kDNSServiceType_UID        = 101,    /* IANA-Reserved */
+    kDNSServiceType_GID        = 102,    /* IANA-Reserved */
+    kDNSServiceType_UNSPEC     = 103,    /* IANA-Reserved */
+
+    kDNSServiceType_TKEY       = 249,    /* Transaction key */
+    kDNSServiceType_TSIG       = 250,    /* Transaction signature. */
+    kDNSServiceType_IXFR       = 251,    /* Incremental zone transfer. */
+    kDNSServiceType_AXFR       = 252,    /* Transfer zone of authority. */
+    kDNSServiceType_MAILB      = 253,    /* Transfer mailbox records. */
+    kDNSServiceType_MAILA      = 254,    /* Transfer mail agent records. */
+    kDNSServiceType_ANY        = 255     /* Wildcard match. */
     };
 
 /* possible error code values */
@@ -514,7 +532,7 @@ enum
  *
  * The servicename may be up to 63 bytes of UTF-8 text (not counting the C-String
  * terminating NULL at the end). The regtype is of the form _service._tcp or
- * _service._udp, where the "service" part is 1-14 characters, which may be
+ * _service._udp, where the "service" part is 1-15 characters, which may be
  * letters, digits, or hyphens. The domain part of the three-part name may be
  * any legal domain, providing that the resulting servicename+regtype+domain
  * name does not exceed 256 bytes.
@@ -567,11 +585,30 @@ enum
  * 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.
+ *
+ * kDNSServiceInterfaceIndexP2P is meaningful only in Browse, QueryRecord,
+ * and Resolve operations. It should not be used in other DNSService APIs.
+ *
+ * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceBrowse or
+ *   DNSServiceQueryRecord, it restricts the operation to P2P.
+ *
+ * - If kDNSServiceInterfaceIndexP2P is passed to DNSServiceResolve, it is
+ *   mapped internally to kDNSServiceInterfaceIndexAny, because resolving
+ *   a P2P service may create and/or enable an interface whose index is not
+ *   known a priori. The resolve callback will indicate the index of the
+ *   interface via which the service can be accessed.
+ *
+ * If applications pass kDNSServiceInterfaceIndexAny to DNSServiceBrowse
+ * or DNSServiceQueryRecord, the operation will also include P2P. In this
+ * case, if a service instance or the record being queried is found over P2P,
+ * the resulting ADD event will indicate kDNSServiceInterfaceIndexP2P as the
+ * interface index.
  */
 
 #define kDNSServiceInterfaceIndexAny 0
 #define kDNSServiceInterfaceIndexLocalOnly ((uint32_t)-1)
 #define kDNSServiceInterfaceIndexUnicast   ((uint32_t)-2)
+#define kDNSServiceInterfaceIndexP2P       ((uint32_t)-3)
 
 typedef uint32_t DNSServiceFlags;
 typedef uint32_t DNSServiceProtocol;
@@ -886,7 +923,7 @@ typedef void (DNSSD_API *DNSServiceRegisterReply)
  *
  * regtype:         The service type followed by the protocol, separated by a dot
  *                  (e.g. "_ftp._tcp"). The service type must be an underscore, followed
- *                  by 1-14 characters, which may be letters, digits, or hyphens.
+ *                  by 1-15 characters, which may be letters, digits, or hyphens.
  *                  The transport protocol must be "_tcp" or "_udp". New service types
  *                  should be registered at <http://www.dns-sd.org/ServiceTypes.html>.
  *
@@ -912,6 +949,13 @@ typedef void (DNSSD_API *DNSServiceRegisterReply)
  *                  % dns-sd -B _test._tcp,HasFeatureA # finds "Better" and "Best"
  *                  % dns-sd -B _test._tcp,HasFeatureB # finds only "Best"
  *
+ *                  Subtype labels may be up to 63 bytes long, and may contain any eight-
+ *                  bit byte values, including zero bytes. However, due to the nature of
+ *                  using a C-string-based API, conventional DNS escaping must be used for
+ *                  dots ('.'), commas (','), backslashes ('\') and zero bytes, as shown below:
+ *                  
+ *                  % dns-sd -R Test '_test._tcp,s\.one,s\,two,s\\three,s\000four' local 123
+ *
  * domain:          If non-NULL, specifies the domain on which to advertise the service.
  *                  Most applications will not specify a domain, instead automatically
  *                  registering in the default domain(s).
@@ -965,7 +1009,7 @@ DNSServiceErrorType DNSSD_API DNSServiceRegister
     const char                          *regtype,
     const char                          *domain,       /* may be NULL */
     const char                          *host,         /* may be NULL */
-    uint16_t                            port,
+    uint16_t                            port,          /* In network byte order */
     uint16_t                            txtLen,
     const void                          *txtRecord,    /* may be NULL */
     DNSServiceRegisterReply             callBack,      /* may be NULL */
@@ -1267,7 +1311,7 @@ typedef void (DNSSD_API *DNSServiceResolveReply)
     DNSServiceErrorType                 errorCode,
     const char                          *fullname,
     const char                          *hosttarget,
-    uint16_t                            port,
+    uint16_t                            port,        /* In network byte order */
     uint16_t                            txtLen,
     const unsigned char                 *txtRecord,
     void                                *context
@@ -1528,11 +1572,6 @@ typedef void (DNSSD_API *DNSServiceGetAddrInfoReply)
  *                     unlikely to be of any use anyway. Similarly, if this host has no routable
  *                     IPv4 address, the call will not try to look up IPv4 addresses for "hostname".
  *
- *                   * If "hostname" is a link-local multicast DNS hostname (i.e. a ".local." name)
- *                     but this host has no IPv6 address of any kind, then it will not try to look
- *                     up IPv6 addresses for "hostname". Similarly, if this host has no IPv4 address
- *                     of any kind, the call will not try to look up IPv4 addresses for "hostname".
- *
  * hostname:        The fully qualified domain name of the host to be queried for.
  *
  * callBack:        The function to be called when the query succeeds or fails asynchronously.
@@ -1735,7 +1774,8 @@ DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
 /* DNSServiceNATPortMappingCreate
  *
  * Request a port mapping in the NAT gateway, which maps a port on the local machine
- * to an external port on the NAT.
+ * to an external port on the NAT. The NAT should support either the NAT-PMP or the UPnP IGD
+ * protocol for this API to create a successful mapping.
  *
  * The port mapping will be renewed indefinitely until the client process exits, or
  * explicitly terminates the port mapping request by calling DNSServiceRefDeallocate().
@@ -1836,9 +1876,9 @@ typedef void (DNSSD_API *DNSServiceNATPortMappingReply)
     DNSServiceErrorType              errorCode,
     uint32_t                         externalAddress,   /* four byte IPv4 address in network byte order */
     DNSServiceProtocol               protocol,
-    uint16_t                         internalPort,
-    uint16_t                         externalPort,      /* may be different than the requested port     */
-    uint32_t                         ttl,               /* may be different than the requested ttl      */
+    uint16_t                         internalPort,      /* In network byte order */
+    uint16_t                         externalPort,      /* In network byte order and may be different than the requested port */
+    uint32_t                         ttl,               /* may be different than the requested ttl */
     void                             *context
     );
 
@@ -1940,10 +1980,10 @@ DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
 
 DNSServiceErrorType DNSSD_API DNSServiceConstructFullName
     (
-    char                            *fullName,
-    const char                      *service,      /* may be NULL */
-    const char                      *regtype,
-    const char                      *domain
+    char                            * const fullName,
+    const char                      * const service,      /* may be NULL */
+    const char                      * const regtype,
+    const char                      * const domain
     );
 
 
@@ -2299,41 +2339,56 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
     const void       **value
     );
 
-#ifdef __APPLE_API_PRIVATE
-
+#if _DNS_SD_LIBDISPATCH
 /*
- * Mac OS X specific functionality
- * 3rd party clients of this API should not depend on future support or availability of this routine
- */
+* DNSServiceSetDispatchQueue
+*
+* Allows you to schedule a DNSServiceRef on a serial dispatch queue for receiving asynchronous
+* callbacks.  It's the clients responsibility to ensure that the provided dispatch queue is running.
+*
+* A typical application that uses CFRunLoopRun or dispatch_main on its main thread will
+* usually schedule DNSServiceRefs on its main queue (which is always a serial queue)
+* using "DNSServiceSetDispatchQueue(sdref, dispatch_get_main_queue());"
+*
+* If there is any error during the processing of events, the application callback will
+* be called with an error code. For shared connections, each subordinate DNSServiceRef
+* will get its own error callback. Currently these error callbacks only happen
+* if the mDNSResponder daemon is manually terminated or crashes, and the error
+* code in this case is kDNSServiceErr_ServiceNotRunning. The application must call
+* DNSServiceRefDeallocate to free the DNSServiceRef when it gets such an error code.
+* These error callbacks are rare and should not normally happen on customer machines,
+* but application code should be written defensively to handle such error callbacks
+* gracefully if they occur.
+*
+* After using DNSServiceSetDispatchQueue on a DNSServiceRef, calling DNSServiceProcessResult
+* on the same DNSServiceRef will result in undefined behavior and should be avoided.
+*
+* Once the application successfully schedules a DNSServiceRef on a serial dispatch queue using
+* DNSServiceSetDispatchQueue, it cannot remove the DNSServiceRef from the dispatch queue, or use
+* DNSServiceSetDispatchQueue a second time to schedule the DNSServiceRef onto a different serial dispatch
+* queue. Once scheduled onto a dispatch queue a DNSServiceRef will deliver events to that queue until
+* the application no longer requires that operation and terminates it using DNSServiceRefDeallocate.
+*
+* service:         DNSServiceRef that was allocated and returned to the application, when the
+*                  application calls one of the DNSService API.
+*
+* queue:           dispatch queue where the application callback will be scheduled
+*
+* return value:    Returns kDNSServiceErr_NoError on success.
+*                  Returns kDNSServiceErr_NoMemory if it cannot create a dispatch source
+*                  Returns kDNSServiceErr_BadParam if the service param is invalid or the
+*                  queue param is invalid
+*/
+
+DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
+  (
+  DNSServiceRef service,
+  dispatch_queue_t queue
+  );
+#endif //_DNS_SD_LIBDISPATCH
 
-/* DNSServiceSetDefaultDomainForUser()
- *
- * Set the default domain for the caller's UID. Future browse and registration
- * calls by this user that do not specify an explicit domain will browse and
- * register in this wide-area domain in addition to .local. In addition, this
- * domain will be returned as a Browse domain via domain enumeration calls.
- *
- * Parameters:
- *
- * flags:           Pass kDNSServiceFlagsAdd to add a domain for a user. Call without
- *                  this flag set to clear a previously added domain.
- *
- * domain:          The domain to be used for the caller's UID.
- *
- * return value:    Returns kDNSServiceErr_NoError on success, otherwise returns
- *                  an error code indicating the error that occurred.
- */
-
-DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser
-    (
-    DNSServiceFlags                    flags,
-    const char                         *domain
-    );
+#ifdef __APPLE_API_PRIVATE
 
-/* Symbol defined to tell System Configuration Framework where to look in the Dynamic Store
- * for the list of PrivateDNS domains that need to be handed off to mDNSResponder
- * (the complete key is "State:/Network/PrivateDNS")
- */
 #define kDNSServiceCompPrivateDNS   "PrivateDNS"
 #define kDNSServiceCompMulticastDNS "MulticastDNS"
 
index 796ca84ce56e632ea1ec6ae4ce98cb22d3fce30c..796caaba11eba11ec3fc352578beb5ee7745fbec 100644 (file)
 .\" See the License for the specific language governing permissions and
 .\" limitations under the License.
 .\"
-.\" $Log: dnsextd.8,v $
-.\" Revision 1.2  2006/08/14 23:24:56  cheshire
-.\" Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-.\"
-.\" Revision 1.1  2004/08/15 18:49:18  cheshire
-.\" <rdar://problem/3763030> No man page for dnsextd
-.\"
-.\"
-.\"
 .Dd August 2004             \" Date
 .Dt dnsextd 8               \" Document Title
 .Os Darwin                  \" Operating System
index d272f0f0c55aae952dd35437ee9f3279da61810b..ecce4fc23cd32cdb610525509343837ffb111423 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
+
+#if __APPLE__
+// In Mac OS X 10.5 and later trying to use the daemon function gives a “‘daemon’ is deprecated”
+// error, which prevents compilation because we build with "-Werror".
+// Since this is supposed to be portable cross-platform code, we don't care that daemon is
+// deprecated on Mac OS X 10.5, so we use this preprocessor trick to eliminate the error message.
+#define daemon yes_we_know_that_daemon_is_deprecated_in_os_x_10_5_thankyou
+#endif
 
-    Change History (most recent first):
-
-$Log: dnsextd.c,v $
-Revision 1.97  2009/01/13 05:31:34  mkrochma
-<rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
-
-Revision 1.96  2009/01/13 00:45:41  cheshire
-Uncommented "#ifdef NOT_HAVE_DAEMON" check
-
-Revision 1.95  2009/01/12 22:47:13  cheshire
-Only include "mDNSUNP.h" when building on a system that requires the "daemon()" definition (currently only Solaris)
-
-Revision 1.94  2009/01/11 03:20:06  mkrochma
-<rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris
-
-Revision 1.93  2008/12/17 05:06:53  cheshire
-Increased maximum DNS Update lifetime from 20 minutes to 2 hours -- now that we have Sleep Proxy,
-having clients wake every fifteen minutes to renew their record registrations is no longer reasonable.
-
-Revision 1.92  2008/11/13 19:09:36  cheshire
-Updated rdataOPT code
-
-Revision 1.91  2008/11/04 23:06:51  cheshire
-Split RDataBody union definition into RDataBody and RDataBody2, and removed
-SOA from the normal RDataBody union definition, saving 270 bytes per AuthRecord
-
-Revision 1.90  2008/10/03 18:18:57  cheshire
-Define dummy "mDNS_ConfigChanged(mDNS *const m)" routine to avoid link errors
-
-Revision 1.89  2008/09/15 23:52:30  cheshire
-<rdar://problem/6218902> mDNSResponder-177 fails to compile on Linux with .desc pseudo-op
-Made __crashreporter_info__ symbol conditional, so we only use it for OS X build
-
-Revision 1.88  2008/03/06 21:26:11  cheshire
-Moved duplicated STRINGIFY macro from individual C files to DNSCommon.h
-
-Revision 1.87  2007/12/17 23:34:50  cheshire
-Don't need to set ptr to result of DNSDigest_SignMessage -- ptr is updated anyway (it's passed by reference)
-
-Revision 1.86  2007/12/13 20:22:34  cheshire
-Got rid of redundant SameResourceRecord() routine; replaced calls to this
-with calls to IdenticalResourceRecord() which does exactly the same thing.
-
-Revision 1.85  2007/12/01 00:30:36  cheshire
-Fixed compile warning: declaration of 'time' shadows a global declaration
-
-Revision 1.84  2007/10/24 18:19:37  cheshire
-Fixed header byte order bug sending update responses
-
-Revision 1.83  2007/10/17 22:52:26  cheshire
-Get rid of unused mDNS_UpdateLLQs()
-
-Revision 1.82  2007/09/27 17:42:49  cheshire
-Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
-
-Revision 1.81  2007/09/21 21:12:37  cheshire
-DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter
-
-Revision 1.80  2007/09/18 19:09:02  cheshire
-<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
-
-Revision 1.79  2007/07/11 02:59:58  cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-Add AutoTunnel parameter to mDNS_SetSecretForDomain
-
-Revision 1.78  2007/06/20 01:10:13  cheshire
-<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-
-Revision 1.77  2007/05/15 21:57:17  cheshire
-<rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
-assuming that all negative values (or zero!) are invalid socket numbers
-
-Revision 1.76  2007/05/01 23:53:26  cheshire
-<rdar://problem/5175318> dnsextd should refuse updates without attached lease
-
-Revision 1.75  2007/05/01 00:18:12  cheshire
-Use "-launchd" instead of "-d" when starting via launchd
-(-d sets foreground mode, which writes errors to stderr, which is ignored when starting via launchd)
-
-Revision 1.74  2007/04/26 00:35:16  cheshire
-<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
-Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
-inside the firewall may give answers where a public one gives none, and vice versa.)
-
-Revision 1.73  2007/04/22 06:02:03  cheshire
-<rdar://problem/4615977> Query should immediately return failure when no server
-
-Revision 1.72  2007/04/05 22:55:37  cheshire
-<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
-
-Revision 1.71  2007/04/05 19:43:56  cheshire
-Added ProgramName and comment about '-d' option
-
-Revision 1.70  2007/04/05 18:34:40  cheshire
-<rdar://problem/4838930> dnsextd gives "bind - Address already in use" error
-
-Revision 1.69  2007/03/28 21:14:08  cheshire
-The rrclass field of an OPT pseudo-RR holds the sender's UDP payload size
-
-Revision 1.68  2007/03/28 18:20:50  cheshire
-Textual tidying
-
-Revision 1.67  2007/03/21 00:30:07  cheshire
-<rdar://problem/4789455> Multiple errors in DNameList-related code
-
-Revision 1.66  2007/03/20 17:07:16  cheshire
-Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-
-Revision 1.65  2007/02/07 19:32:00  cheshire
-<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
-
-Revision 1.64  2007/01/20 01:43:26  cheshire
-<rdar://problem/4058383> Should not write log messages to /dev/console
-
-Revision 1.63  2007/01/20 01:31:56  cheshire
-Update comments
-
-Revision 1.62  2007/01/17 22:06:03  cheshire
-Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
-
-Revision 1.61  2007/01/05 08:30:54  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.60  2007/01/05 08:07:29  cheshire
-Remove unnecessary dummy udsserver_default_reg_domain_changed() routine
-
-Revision 1.59  2007/01/05 05:46:47  cheshire
-Remove unnecessary dummy udsserver_automatic_browse_domain_changed() routine
-
-Revision 1.58  2007/01/04 23:11:54  cheshire
-udsserver_default_browse_domain_changed renamed to udsserver_automatic_browse_domain_changed
-
-Revision 1.57  2007/01/04 01:41:48  cheshire
-Use _dns-update-tls/_dns-query-tls/_dns-llq-tls instead of creating a new "_tls" subdomain
-
-Revision 1.56  2006/12/22 20:59:51  cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.55  2006/11/30 23:08:39  herscher
-<rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
-
-Revision 1.54  2006/11/18 05:01:33  cheshire
-Preliminary support for unifying the uDNS and mDNS code,
-including caching of uDNS answers
-
-Revision 1.53  2006/11/17 23:55:09  cheshire
-<rdar://problem/4842494> dnsextd byte-order bugs on Intel
-
-Revision 1.52  2006/11/17 04:27:51  cheshire
-<rdar://problem/4842494> dnsextd byte-order bugs on Intel
-
-Revision 1.51  2006/11/17 03:50:18  cheshire
-Add debugging loggin in SendPacket and UDPServerTransaction
-
-Revision 1.50  2006/11/17 03:48:57  cheshire
-<rdar://problem/4842493> dnsextd replying on wrong port
-
-Revision 1.49  2006/11/03 06:12:44  herscher
-Make sure all buffers passed to GetRRDisplayString_rdb are of length MaxMsg
-
-Revision 1.48  2006/10/20 19:18:35  cheshire
-<rdar://problem/4669228> dnsextd generates bogus SRV record with null target
-
-Revision 1.47  2006/10/20 05:43:51  herscher
-LookupLLQ() needs to match on the port number when looking up the LLQ
-
-Revision 1.46  2006/10/11 22:56:07  herscher
-Tidy up the implementation of ZoneHandlesName
-
-Revision 1.45  2006/08/22 03:28:57  herscher
-<rdar://problem/4678717> Long-lived queries aren't working well in TOT.
-
-Revision 1.44  2006/08/14 23:24:56  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.43  2006/07/20 19:53:33  mkrochma
-<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-More fixes for private DNS
-
-Revision 1.42  2006/07/05 22:48:19  cheshire
-<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-
-*/
-
-#include "dnsextd.h"
-#include "../mDNSShared/uds_daemon.h"
-#include "../mDNSShared/dnssd_ipc.h"
-#include "../mDNSCore/uDNS.h"
-#include "../mDNSShared/DebugServices.h"
 #include <signal.h>
 #include <pthread.h>
 #include <stdlib.h>
@@ -221,11 +39,22 @@ Revision 1.42  2006/07/05 22:48:19  cheshire
 #include <time.h>
 #include <errno.h>
 
+#if __APPLE__
+#undef daemon
+extern int daemon(int, int);
+#endif
+
 // Solaris doesn't have daemon(), so we define it here
 #ifdef NOT_HAVE_DAEMON
 #include "../mDNSPosix/mDNSUNP.h"              // For daemon()
 #endif // NOT_HAVE_DAEMON
 
+#include "dnsextd.h"
+#include "../mDNSShared/uds_daemon.h"
+#include "../mDNSShared/dnssd_ipc.h"
+#include "../mDNSCore/uDNS.h"
+#include "../mDNSShared/DebugServices.h"
+
 // Compatibility workaround
 #ifndef AF_LOCAL
 #define AF_LOCAL AF_UNIX
@@ -1368,30 +1197,38 @@ SetupSockets
        self->llq_addr.sin_addr.s_addr  = zerov4Addr.NotAnInteger;
        self->llq_addr.sin_port                 = ( self->llq_port.NotAnInteger ) ? self->llq_port.NotAnInteger : DNSEXTPort.NotAnInteger;
 
-       self->llq_tcpsd = socket( AF_INET, SOCK_STREAM, 0 );
-       require_action( dnssd_SocketValid(self->llq_tcpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
-
+       if (self->llq_addr.sin_port == self->addr.sin_port)
+               {
+               self->llq_tcpsd = self->tcpsd;
+               self->llq_udpsd = self->udpsd;
+               }
+       else
+               {
+               self->llq_tcpsd = socket( AF_INET, SOCK_STREAM, 0 );
+               require_action( dnssd_SocketValid(self->llq_tcpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
+       
 #if defined(SO_REUSEADDR)
-       err = setsockopt(self->llq_tcpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
-       require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_tcpsd" ) );
+               err = setsockopt(self->llq_tcpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
+               require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_tcpsd" ) );
 #endif
-
-       err = bind( self->llq_tcpsd, ( struct sockaddr* ) &self->llq_addr, sizeof( self->llq_addr ) );
-       require_action( !err, exit, LogErr( "SetupSockets", "bind self->llq_tcpsd" ) );
-
-       err = listen( self->llq_tcpsd, LISTENQ );
-       require_action( !err, exit, LogErr( "SetupSockets", "listen" ) );
-
-       self->llq_udpsd = socket( AF_INET, SOCK_DGRAM, 0 );
-       require_action( dnssd_SocketValid(self->llq_udpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
-
+       
+               err = bind( self->llq_tcpsd, ( struct sockaddr* ) &self->llq_addr, sizeof( self->llq_addr ) );
+               require_action( !err, exit, LogErr( "SetupSockets", "bind self->llq_tcpsd" ) );
+       
+               err = listen( self->llq_tcpsd, LISTENQ );
+               require_action( !err, exit, LogErr( "SetupSockets", "listen" ) );
+       
+               self->llq_udpsd = socket( AF_INET, SOCK_DGRAM, 0 );
+               require_action( dnssd_SocketValid(self->llq_udpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
+       
 #if defined(SO_REUSEADDR)
-       err = setsockopt(self->llq_udpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
-       require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_udpsd" ) );
+               err = setsockopt(self->llq_udpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
+               require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_udpsd" ) );
 #endif
-
-       err = bind(self->llq_udpsd, ( struct sockaddr* ) &self->llq_addr, sizeof( self->llq_addr ) );
-       require_action( !err, exit, LogErr( "SetupSockets", "bind self->llq_udpsd" ) );
+       
+               err = bind(self->llq_udpsd, ( struct sockaddr* ) &self->llq_addr, sizeof( self->llq_addr ) );
+               require_action( !err, exit, LogErr( "SetupSockets", "bind self->llq_udpsd" ) );
+               }
 
        // set up Unix domain socket pair for LLQ polling thread to signal main thread that a change to the zone occurred
 
@@ -1559,7 +1396,7 @@ mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease)
                mDNSBool DeleteAllRRSets = mDNSfalse, DeleteOneRRSet = mDNSfalse, DeleteOneRR = mDNSfalse;
                
                ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
-               if (!ptr) { Log("UpdateLeaseTable: GetLargeResourceRecord returned NULL"); goto cleanup; }
+               if (!ptr || lcr.r.resrec.RecordType == kDNSRecordTypePacketNegative) { Log("UpdateLeaseTable: GetLargeResourceRecord failed"); goto cleanup; }
                bucket = rr->namehash % d->nbuckets;
                rptr = &d->table[bucket];
 
@@ -1688,7 +1525,7 @@ HandleRequest
                        {
                        LargeCacheRecord lcr;
                        ptr = GetLargeResourceRecord(NULL, &request->msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
-                       if (lcr.r.resrec.rroriginalttl) adds++; else dels++;
+                       if (lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative && lcr.r.resrec.rroriginalttl) adds++; else dels++;
                        }
                HdrHToN(request);
                if (adds && !lease)
@@ -1959,17 +1796,20 @@ mDNSlocal CacheRecord *AnswerQuestion(DaemonInfo *d, AnswerListElem *e)
                {
                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->type || lcr.r.resrec.rrclass != kDNSClass_IN || !SameDomainName(lcr.r.resrec.name, &e->name))
-                       {
-                       Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d.  Discarding",
-                                 lcr.r.resrec.name->c, lcr.r.resrec.rrtype, e->name.c, e->type);
-                       }
-               else
+               if (lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative)
                        {
-                       CacheRecord *cr = CopyCacheRecord(&lcr.r, &e->name);
-                       if (!cr) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end; }
-                       cr->next = AnswerList;
-                       AnswerList = cr;
+                       if (lcr.r.resrec.rrtype != e->type || lcr.r.resrec.rrclass != kDNSClass_IN || !SameDomainName(lcr.r.resrec.name, &e->name))
+                               {
+                               Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d.  Discarding",
+                                         lcr.r.resrec.name->c, lcr.r.resrec.rrtype, e->name.c, e->type);
+                               }
+                       else
+                               {
+                               CacheRecord *cr = CopyCacheRecord(&lcr.r, &e->name);
+                               if (!cr) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end; }
+                               cr->next = AnswerList;
+                               AnswerList = cr;
+                               }
                        }
                }
        
@@ -2510,7 +2350,7 @@ mDNSlocal int RecvLLQ( DaemonInfo *d, PktMsg *pkt, TCPSocket *sock )
                {
                aptr = GetLargeResourceRecord(NULL, &pkt->msg, aptr, end, 0, kDNSRecordTypePacketAdd, &opt);
                if (!aptr) { Log("Malformatted LLQ from %s: could not get Additional record %d", addr, i); goto end; }
-               if (opt.r.resrec.rrtype == kDNSType_OPT) break;
+               if (opt.r.resrec.RecordType != kDNSRecordTypePacketNegative && opt.r.resrec.rrtype == kDNSType_OPT) break;
                }
 
        // validate OPT
@@ -2579,7 +2419,7 @@ mDNSlocal mDNSBool IsAuthorized( DaemonInfo * d, PktMsg * pkt, DomainAuthInfo **
                                        }
                                }
 
-                               hasTSIG = ( ptr && lcr.r.resrec.rrtype == kDNSType_TSIG );
+                               hasTSIG = ( ptr && lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative && lcr.r.resrec.rrtype == kDNSType_TSIG );
                        }
                else
                        {
@@ -3219,7 +3059,7 @@ int main(int argc, char *argv[])
                Log("Using default file descriptor resource limit");
                }
        
-       if (!strcasecmp(argv[1], "-launchd"))
+       if (argc > 1 && !strcasecmp(argv[1], "-launchd"))
                {
                Log("started_via_launchd");
                started_via_launchd = 1;
@@ -3264,8 +3104,8 @@ void mDNSCoreReceive(mDNS *const m, void *const msg, const mDNSu8 *const end,
                                 const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
                                 const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID iid)
        { ( void ) m; ( void ) msg; ( void ) end; ( void ) srcaddr; ( void ) srcport; ( void ) dstaddr; ( void ) dstport; ( void ) iid; }
-DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port)
-       { ( void ) m; ( void ) d; ( void ) interface; ( void ) addr; ( void ) port; return(NULL); }
+DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped)
+       { ( void ) m; ( void ) d; ( void ) interface; ( void ) addr; ( void ) port; ( void ) scoped; return(NULL); }
 void mDNS_AddSearchDomain(const domainname *const domain) { (void)domain; }
 void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
        { ( void ) m; ( void ) fqdn; ( void ) StatusCallback; ( void ) StatusContext; }
@@ -3290,6 +3130,8 @@ mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
        const domainname *domain, const domainname *keyname, const char *b64keydata, mDNSBool AutoTunnel)
        { ( void ) m; ( void ) info; ( void ) domain; ( void ) keyname; ( void ) b64keydata; ( void ) AutoTunnel; return 0; }
 mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question) { ( void ) m; ( void ) question; return 0; }
+void TriggerEventCompletion(void);
+void TriggerEventCompletion() {}
 mDNS mDNSStorage;
 
 
index f72b164c3fc4458be73999cce41d00f31e5b5974..d75d69507c26b082a3662a1070b80efb3b9a4875 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: dnsextd.h,v $
-Revision 1.5  2007/03/20 17:07:16  cheshire
-Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-
-Revision 1.4  2006/12/22 20:59:51  cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.3  2006/11/18 05:01:33  cheshire
-Preliminary support for unifying the uDNS and mDNS code,
-including caching of uDNS answers
-
-Revision 1.2  2006/08/14 23:24:56  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.1  2006/07/06 00:09:05  cheshire
-<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-
-
  */
 
 
index 352828fedde6e1fae86dc50f73c09ebaaaeb4df6..2f614e56fbf2ab048f91919e598028466bf2d597 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: dnsextd_lexer.l,v $
-Revision 1.6  2008/07/18 17:40:46  cheshire
-Removed redundant definition of "YY_NO_UNPUT" (not needed now that we use "%option nounput" instead)
-
-Revision 1.5  2008/06/24 18:32:26  mcguire
-<rdar://problem/6024542> flex producing .c files that result in warnings
-
-Revision 1.4  2007/05/25 20:01:43  cheshire
-<rdar://problem/5226767> /usr/bin/flex failures prevent mDNSResponder from building
-Only define "int yylineno" on flex 2.5.4 and earlier
-
-Revision 1.3  2006/08/14 23:24:56  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2006/07/06 20:41:14  cheshire
-<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-Use derived filename "dnsextd_parser.h" instead of "dnsextd_parser.y.h"
-
-Revision 1.1  2006/07/06 00:09:05  cheshire
-<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-
  */
 
 %{
index 943be297f981a101275e884fe7210b8b0ac383ed..18c5990fba16dd5025773efe0c7eb6e3147c4cf2 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: dnsextd_parser.y,v $
-Revision 1.9  2009/01/11 03:20:06  mkrochma
-<rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris
-
-Revision 1.8  2007/03/21 19:47:50  cheshire
-<rdar://problem/4789463> Leak: On error path in ParseConfig
-
-Revision 1.7  2007/01/17 17:38:13  cheshire
-Need to include stdlib.h for malloc/free
-
-Revision 1.6  2006/12/22 20:59:51  cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.5  2006/10/20 05:47:09  herscher
-Set the DNSZone pointer to NULL in ParseConfig() before parsing the configuration file.
-
-Revision 1.4  2006/08/16 00:35:39  mkrochma
-<rdar://problem/4386944> Get rid of NotAnInteger references
-
-Revision 1.3  2006/08/14 23:24:56  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2006/07/14 02:03:37  cheshire
-<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-private_port and llq_port should use htons, not htonl
-
-Revision 1.1  2006/07/06 00:09:05  cheshire
-<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-
  */
 
 %{
@@ -218,12 +185,12 @@ optionsstatement:
                |
                PRIVATE PORT NUMBER
                {
-                       ( ( DaemonInfo* ) context )->private_port = mDNSOpaque16fromIntVal( NUMBER );
+                       ( ( DaemonInfo* ) context )->private_port = mDNSOpaque16fromIntVal( $3 );
                }
                |
                LLQ PORT NUMBER
                {
-                       ( ( DaemonInfo* ) context )->llq_port = mDNSOpaque16fromIntVal( NUMBER );
+                       ( ( DaemonInfo* ) context )->llq_port = mDNSOpaque16fromIntVal( $3 );
                }
                ;
 
index d5d46c8b02a1d0e763d470702cbc91d72754e78a..c3a3cfcc48a7ee170a30bf3a3cfc0fd83a042cac 100644 (file)
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-   Change History (most recent first):
-
-$Log: dnssd_clientlib.c,v $
-Revision 1.21  2009/04/01 21:10:11  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows. Use _stricmp and _strnicmp.
-
-Revision 1.20  2008/11/26 20:57:37  cheshire
-For consistency with other similar macros, renamed mdnsIsDigit/mdnsIsLetter/mdnsValidHostChar
-to mDNSIsDigit/mDNSIsLetter/mDNSValidHostChar
-
-Revision 1.19  2008/11/04 21:15:18  cheshire
-<rdar://problem/5969564> Potential buffer overflows in DNSServiceConstructFullName
-
-Revision 1.18  2007/11/30 23:06:10  cheshire
-Fixed compile warning: declaration of 'index' shadows a global declaration
-
-Revision 1.17  2007/10/02 19:36:04  cheshire
-<rdar://problem/5516444> TXTRecordGetValuePtr should be case-insenstive
-
-Revision 1.16  2007/09/18 19:09:02  cheshire
-<rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
-
-Revision 1.15  2007/07/28 00:00:43  cheshire
-Renamed CompileTimeAssertionCheck structure for consistency with others
-
-Revision 1.14  2007/03/20 17:07:16  cheshire
-Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-
-Revision 1.13  2007/02/27 00:25:03  cheshire
-<rdar://problem/5010640> DNSServiceConstructFullName() doesn't handle empty string for instance name
-
-Revision 1.12  2007/02/07 19:32:00  cheshire
-<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
-
-Revision 1.11  2006/08/14 23:05:53  cheshire
-Added "tab-width" emacs header line
-
-Revision 1.10  2005/04/06 02:06:56  shersche
-Add DNSSD_API macro to TXTRecord API calls
-
-Revision 1.9  2004/10/06 02:22:19  cheshire
-Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
-
-Revision 1.8  2004/10/01 22:15:55  rpantos
-rdar://problem/3824265: Replace APSL in client lib with BSD license.
-
-Revision 1.7  2004/06/26 03:16:34  shersche
-clean up warning messages on Win32 platform
-
-Submitted by: herscher
-
-Revision 1.6  2004/06/12 01:09:45  cheshire
-To be callable from the broadest range of clients on Windows (e.g. Visual Basic, C#, etc.)
-API routines have to be declared as "__stdcall", instead of the C default, "__cdecl"
-
-Revision 1.5  2004/05/25 18:29:33  cheshire
-Move DNSServiceConstructFullName() from dnssd_clientstub.c to dnssd_clientlib.c,
-so that it's also accessible to dnssd_clientshim.c (single address space) clients.
-
-Revision 1.4  2004/05/25 17:08:55  cheshire
-Fix compiler warning (doesn't make sense for function return type to be const)
-
-Revision 1.3  2004/05/21 21:41:35  cheshire
-Add TXT record building and parsing APIs
-
-Revision 1.2  2004/05/20 22:22:21  cheshire
-Enable code that was bracketed by "#if 0"
-
-Revision 1.1  2004/03/12 21:30:29  cheshire
-Build a System-Context Shared Library from mDNSCore, for the benefit of developers
-like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
-
  */
 
 #include <stdlib.h>
index 3bd7c1ff186757a172590d89bc6709ef59845d5a..17f2e93921941870822f5d64942111ea6a444a5b 100644 (file)
  * The shim is responsible for two main things:
  * - converting string parameters between C string format and native DNS format,
  * - and for allocating and freeing memory.
-
-       Change History (most recent first):
-
-$Log: dnssd_clientshim.c,v $
-Revision 1.16  2007/11/30 20:12:24  cheshire
-Removed unused "badparam:" label
-
-Revision 1.15  2007/07/27 19:30:41  cheshire
-Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
-to properly reflect tri-state nature of the possible responses
-
-Revision 1.14  2007/07/17 19:15:26  cheshire
-<rdar://problem/5297410> Crash in DNSServiceRegister() in dnssd_clientshim.c
-
-Revision 1.13  2007/01/04 20:57:49  cheshire
-Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
-
-Revision 1.12  2006/12/19 22:43:55  cheshire
-Fix compiler warnings
-
-Revision 1.11  2006/10/27 01:30:23  cheshire
-Need explicitly to set ReturnIntermed = mDNSfalse
-
-Revision 1.10  2006/08/14 23:24:56  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.9  2006/07/24 23:45:55  cheshire
-<rdar://problem/4605276> DNSServiceReconfirmRecord() should return error code
-
-Revision 1.8  2004/12/16 20:47:34  cheshire
-<rdar://problem/3324626> Cache memory management improvements
-
-Revision 1.7  2004/12/10 04:08:43  cheshire
-Added comments about autoname and autorename
-
-Revision 1.6  2004/10/19 21:33:22  cheshire
-<rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
-Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
-doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
-
-Revision 1.5  2004/09/21 23:29:51  cheshire
-<rdar://problem/3680045> DNSServiceResolve should delay sending packets
-
-Revision 1.4  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
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.3  2004/05/27 06:26:31  cheshire
-Add shim for DNSServiceQueryRecord()
-
-Revision 1.2  2004/05/20 18:41:24  cheshire
-Fix build broken by removal of 'kDNSServiceFlagsRemove' from dns_sd.h
-
-Revision 1.1  2004/03/12 21:30:29  cheshire
-Build a System-Context Shared Library from mDNSCore, for the benefit of developers
-like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
-
  */
 
 #include "dns_sd.h"                            // Defines the interface to the client layer above
@@ -581,6 +522,7 @@ DNSServiceErrorType DNSServiceResolve
        x->qTXT.ExpectUnique        = mDNStrue;
        x->qTXT.ForceMCast          = mDNSfalse;
        x->qTXT.ReturnIntermed      = mDNSfalse;
+       x->qTXT.SuppressUnusable    = mDNSfalse;
        x->qTXT.QuestionCallback    = FoundServiceInfo;
        x->qTXT.QuestionContext     = x;
 
@@ -704,6 +646,7 @@ DNSServiceErrorType DNSServiceQueryRecord
        x->q.ExpectUnique        = mDNSfalse;
        x->q.ForceMCast          = (flags & kDNSServiceFlagsForceMulticast) != 0;
        x->q.ReturnIntermed      = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+       x->q.SuppressUnsable     = (flags & kDNSServiceFlagsSuppressUnusable) != 0;
        x->q.QuestionCallback    = DNSServiceQueryRecordResponse;
        x->q.QuestionContext     = x;
 
@@ -719,6 +662,82 @@ fail:
        return(err);
        }
 
+//*************************************************************************************************************
+// DNSServiceGetAddrInfo
+
+static void DNSServiceGetAddrInfoDispose(mDNS_DirectOP *op)
+       {
+       mDNS_DirectOP_GetAddrInfo *x = (mDNS_DirectOP_GetAddrInfo*)op;
+       if (x->aQuery) DNSServiceRefDeallocate(x->aQuery);
+       mDNSPlatformMemFree(x);
+       }
+
+static void DNSSD_API DNSServiceGetAddrInfoResponse(
+       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 )
+       {
+       mDNS_DirectOP_GetAddrInfo *             x = (mDNS_DirectOP_GetAddrInfo*)inContext;
+       struct sockaddr_in                              sa4;
+       
+       mDNSPlatformMemZero(&sa4, sizeof(sa4));
+       if (inErrorCode == kDNSServiceErr_NoError && inRRType == kDNSServiceType_A)
+               {
+               sa4.sin_family = AF_INET;
+               mDNSPlatformMemCopy(&sa4.sin_addr.s_addr, inRData, 4);
+               }
+       
+       x->callback((DNSServiceRef)x, inFlags, inInterfaceIndex, inErrorCode, inFullName, 
+               (const struct sockaddr *) &sa4, inTTL, x->context);
+       }
+
+DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo(
+       DNSServiceRef *                         outRef,
+       DNSServiceFlags                         inFlags,
+       uint32_t                                        inInterfaceIndex,
+       DNSServiceProtocol                      inProtocol,
+       const char *                            inHostName,
+       DNSServiceGetAddrInfoReply      inCallback,
+       void *                                          inContext )
+       {
+       const char *                                    errormsg = "Unknown";
+       DNSServiceErrorType                             err;
+       mDNS_DirectOP_GetAddrInfo *             x;
+       
+       // Allocate memory, and handle failure
+       x = (mDNS_DirectOP_GetAddrInfo *)mDNSPlatformMemAllocate(sizeof(*x));
+       if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
+       
+       // Set up object
+       x->disposefn = DNSServiceGetAddrInfoDispose;
+       x->callback  = inCallback;
+       x->context   = inContext;
+       x->aQuery    = mDNSNULL;
+       
+       // Start the query.
+       // (It would probably be more efficient to code this using mDNS_StartQuery directly,
+       // instead of wrapping DNSServiceQueryRecord, which then unnecessarily allocates
+       // more memory and then just calls through to mDNS_StartQuery. -- SC June 2010)
+       err = DNSServiceQueryRecord(&x->aQuery, inFlags, inInterfaceIndex, inHostName, kDNSServiceType_A, 
+               kDNSServiceClass_IN, DNSServiceGetAddrInfoResponse, x);
+       if (err) { DNSServiceGetAddrInfoDispose((mDNS_DirectOP*)x); errormsg = "DNSServiceQueryRecord"; goto fail; }
+       
+       *outRef = (DNSServiceRef)x;
+       return(mStatus_NoError);
+       
+fail:
+       LogMsg("DNSServiceGetAddrInfo(\"%s\", %d) failed: %s (%ld)", inHostName, inProtocol, errormsg, err);
+       return(err);
+       }
+
 //*************************************************************************************************************
 // DNSServiceReconfirmRecord
 
index 832601921d19bef28e48f9698f1460ac2f7aeec1..62f640e252691278ef8fd2ea8655ca05fc058975 100644 (file)
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-       Change History (most recent first):
-
-$Log: dnssd_clientstub.c,v $
-Revision 1.134  2009/06/19 23:13:24  cheshire
-<rdar://problem/6990066> Library: crash at handle_resolve_response + 183
-Added check for NULL after calling get_string
-
-Revision 1.133  2009/05/27 22:19:12  cheshire
-Remove questionable uses of errno
-
-Revision 1.132  2009/05/26 21:31:07  herscher
-Fix compile errors on Windows
-
-Revision 1.131  2009/05/26 04:48:19  herscher
-<rdar://problem/6844819> ExplorerPlugin does not work in B4W 2.0
-
-Revision 1.130  2009/05/02 01:29:48  mcguire
-<rdar://problem/6847601> spin calling DNSServiceProcessResult if errno was set to EWOULDBLOCK by an unrelated call
-
-Revision 1.129  2009/05/01 19:18:50  cheshire
-<rdar://problem/6843645> Using duplicate DNSServiceRefs when sharing a connection should return an error
-
-Revision 1.128  2009/04/01 21:09:35  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows.
-
-Revision 1.127  2009/03/03 21:38:19  cheshire
-Improved "deliver_request ERROR" message
-
-Revision 1.126  2009/02/12 21:02:22  cheshire
-Commented out BPF "Sending fd" debugging message
-
-Revision 1.125  2009/02/12 20:28:32  cheshire
-Added some missing "const" declarations
-
-Revision 1.124  2009/02/10 01:44:39  cheshire
-<rdar://problem/6553729> DNSServiceUpdateRecord fails with kDNSServiceErr_BadReference for otherwise valid reference
-
-Revision 1.123  2009/01/19 00:49:21  mkrochma
-Type cast size_t values to unsigned long
-
-Revision 1.122  2009/01/18 03:51:37  mkrochma
-Fix warning in deliver_request on Linux
-
-Revision 1.121  2009/01/16 23:34:37  cheshire
-<rdar://problem/6504143> Uninitialized error code variable in error handling path in deliver_request
-
-Revision 1.120  2009/01/13 05:31:35  mkrochma
-<rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
-
-Revision 1.119  2009/01/11 03:45:08  mkrochma
-Stop type casting num_written and num_read to int
-
-Revision 1.118  2009/01/11 03:20:06  mkrochma
-<rdar://problem/5797526> Fixes from Igor Seleznev to get mdnsd working on Solaris
-
-Revision 1.117  2009/01/10 22:03:43  mkrochma
-<rdar://problem/5797507> dnsextd fails to build on Linux
-
-Revision 1.116  2009/01/05 16:55:24  cheshire
-<rdar://problem/6452199> Stuck in "Examining available disks"
-ConnectionResponse handler was accidentally matching the parent DNSServiceRef before
-finding the appropriate subordinate DNSServiceRef for the operation in question.
-
-Revision 1.115  2008/12/18 00:19:11  mcguire
-<rdar://problem/6452199> Stuck in "Examining available disks"
-
-Revision 1.114  2008/12/10 02:11:43  cheshire
-ARMv5 compiler doesn't like uncommented stuff after #endif
-
-Revision 1.113  2008/12/04 03:23:05  cheshire
-Preincrement UID counter before we use it -- it helps with debugging if we know the all-zeroes ID should never appear
-
-Revision 1.112  2008/11/25 22:56:54  cheshire
-<rdar://problem/6377257> Make library code more defensive when client calls DNSServiceProcessResult with bad DNSServiceRef repeatedly
-
-Revision 1.111  2008/10/28 17:58:44  cheshire
-If client code keeps calling DNSServiceProcessResult repeatedly after an error, rate-limit the
-"DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function" log messages
-
-Revision 1.110  2008/10/23 23:38:58  cheshire
-For Windows compatibility, instead of "strerror(errno)" use "dnssd_strerror(dnssd_errno)"
-
-Revision 1.109  2008/10/23 23:06:17  cheshire
-Removed () from dnssd_errno macro definition -- it's not a function and doesn't need any arguments
-
-Revision 1.108  2008/10/23 22:33:24  cheshire
-Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
-
-Revision 1.107  2008/10/20 21:50:11  cheshire
-Improved /dev/bpf error message
-
-Revision 1.106  2008/10/20 15:37:18  cheshire
-Log error message if opening /dev/bpf fails
-
-Revision 1.105  2008/09/27 01:26:34  cheshire
-Added handler to pass back BPF fd when requested
-
-Revision 1.104  2008/09/23 01:36:00  cheshire
-Updated code to use internalPort/externalPort terminology, instead of the old privatePort/publicPort
-terms (which could be misleading, because the word "private" suggests security).
-
-Revision 1.103  2008/07/24 18:51:13  cheshire
-Removed spurious spaces
-
-Revision 1.102  2008/02/25 19:16:19  cheshire
-<rdar://problem/5708953> Problems with DNSServiceGetAddrInfo API
-Was returning a bogus result (NULL pointer) when following a CNAME referral
-
-Revision 1.101  2008/02/20 21:18:21  cheshire
-<rdar://problem/5708953> DNSServiceGetAddrInfo doesn't set the scope ID of returned IPv6 link local addresses
-
-Revision 1.100  2007/11/02 17:56:37  cheshire
-<rdar://problem/5565787> Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails)
-Wrap hack code in "#if APPLE_OSX_mDNSResponder" since (as far as we know right now)
-we don't want to do this on 64-bit Linux, Solaris, etc.
-
-Revision 1.99  2007/11/02 17:29:40  cheshire
-<rdar://problem/5565787> Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails)
-To get 64-bit code that works, we need to NOT use the standard CMSG_* macros
-
-Revision 1.98  2007/11/01 19:52:43  cheshire
-Wrap debugging messages in "#if DEBUG_64BIT_SCM_RIGHTS"
-
-Revision 1.97  2007/11/01 19:45:55  cheshire
-Added "DEBUG_64BIT_SCM_RIGHTS" debugging code
-See <rdar://problem/5565787> Bonjour API broken for 64-bit apps (SCM_RIGHTS sendmsg fails)
-
-Revision 1.96  2007/11/01 15:59:33  cheshire
-umask not being set and restored properly in USE_NAMED_ERROR_RETURN_SOCKET code
-(no longer used on OS X, but relevant for other platforms)
-
-Revision 1.95  2007/10/31 20:07:16  cheshire
-<rdar://problem/5541498> Set SO_NOSIGPIPE on client socket
-Refinement: the cleanup code still needs to close listenfd when necesssary
-
-Revision 1.94  2007/10/15 22:34:27  cheshire
-<rdar://problem/5541498> Set SO_NOSIGPIPE on client socket
-
-Revision 1.93  2007/10/10 00:48:54  cheshire
-<rdar://problem/5526379> Daemon spins in an infinite loop when it doesn't get the control message it's expecting
-
-Revision 1.92  2007/10/06 03:44:44  cheshire
-Testing code for <rdar://problem/5526374> kqueue does not get a kevent to wake it up when a control message arrives on a socket
-
-Revision 1.91  2007/10/04 20:53:59  cheshire
-Improved debugging message when sendmsg fails
-
-Revision 1.90  2007/09/30 00:09:27  cheshire
-<rdar://problem/5492315> Pass socket fd via SCM_RIGHTS sendmsg instead of using named UDS in the filesystem
-
-Revision 1.89  2007/09/19 23:53:12  cheshire
-Fixed spelling mistake in comment
-
-Revision 1.88  2007/09/07 23:18:27  cheshire
-<rdar://problem/5467542> Change "client_context" to be an incrementing 64-bit counter
-
-Revision 1.87  2007/09/07 22:50:09  cheshire
-Added comment explaining moreptr field in DNSServiceOp structure
-
-Revision 1.86  2007/09/07 20:21:22  cheshire
-<rdar://problem/5462371> Make DNSSD library more resilient
-Add more comments explaining the moreptr/morebytes logic; don't allow DNSServiceRefSockFD or
-DNSServiceProcessResult for subordinate DNSServiceRefs created using kDNSServiceFlagsShareConnection
-
-Revision 1.85  2007/09/06 21:43:23  cheshire
-<rdar://problem/5462371> Make DNSSD library more resilient
-Allow DNSServiceRefDeallocate from within DNSServiceProcessResult callback
-
-Revision 1.84  2007/09/06 18:31:47  cheshire
-<rdar://problem/5462371> Make DNSSD library more resilient against client programming errors
-
-Revision 1.83  2007/08/28 20:45:45  cheshire
-Typo: ctrl_path needs to be 64 bytes, not 44 bytes
-
-Revision 1.82  2007/08/28 19:53:52  cheshire
-<rdar://problem/5437423> Bonjour failures when /tmp is not writable (e.g. when booted from installer disc)
-
-Revision 1.81  2007/07/27 00:03:20  cheshire
-Fixed compiler warnings that showed up now we're building optimized ("-Os")
-
-Revision 1.80  2007/07/23 22:12:53  cheshire
-<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
-
-Revision 1.79  2007/07/23 19:58:24  cheshire
-<rdar://problem/5351640> Library: Leak in DNSServiceRefDeallocate
-
-Revision 1.78  2007/07/12 20:42:27  cheshire
-<rdar://problem/5280735> If daemon is killed, return kDNSServiceErr_ServiceNotRunning
-to clients instead of kDNSServiceErr_Unknown
-
-Revision 1.77  2007/07/02 23:07:13  cheshire
-<rdar://problem/5308280> Reduce DNS-SD client syslog error messages
-
-Revision 1.76  2007/06/22 20:12:18  cheshire
-<rdar://problem/5277024> Leak in DNSServiceRefDeallocate
-
-Revision 1.75  2007/05/23 18:59:22  cheshire
-Remove unnecessary IPC_FLAGS_REUSE_SOCKET
-
-Revision 1.74  2007/05/22 18:28:38  cheshire
-Fixed compile errors in posix build
-
-Revision 1.73  2007/05/22 01:20:47  cheshire
-To determine current operation, need to check hdr->op, not sdr->op
-
-Revision 1.72  2007/05/22 01:07:42  cheshire
-<rdar://problem/3563675> API: Need a way to get version/feature information
-
-Revision 1.71  2007/05/18 23:55:22  cheshire
-<rdar://problem/4454655> Allow multiple register/browse/resolve operations to share single Unix Domain Socket
-
-Revision 1.70  2007/05/17 20:58:22  cheshire
-<rdar://problem/4647145> DNSServiceQueryRecord should return useful information with NXDOMAIN
-
-Revision 1.69  2007/05/16 16:58:27  cheshire
-<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
-As long as select indicates that data is waiting, loop within DNSServiceProcessResult delivering additional results
-
-Revision 1.68  2007/05/16 01:06:52  cheshire
-<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
-
-Revision 1.67  2007/05/15 21:57:16  cheshire
-<rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
-assuming that all negative values (or zero!) are invalid socket numbers
-
-Revision 1.66  2007/03/27 22:23:04  cheshire
-Add "dnssd_clientstub" prefix onto syslog messages
-
-Revision 1.65  2007/03/21 22:25:23  cheshire
-<rdar://problem/4172796> Remove client retry logic now that mDNSResponder uses launchd for its Unix Domain Socket
-
-Revision 1.64  2007/03/21 19:01:56  cheshire
-<rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits
-
-Revision 1.63  2007/03/12 21:48:21  cheshire
-<rdar://problem/5000162> Scary unlink errors in system.log
-Code was using memory after it had been freed
-
-Revision 1.62  2007/02/28 01:44:30  cheshire
-<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
-
-Revision 1.61  2007/02/09 03:09:42  cheshire
-<rdar://problem/3869251> Cleanup: Stop returning kDNSServiceErr_Unknown so often
-<rdar://problem/4177924> API: Should return kDNSServiceErr_ServiceNotRunning
-
-Revision 1.60  2007/02/08 20:33:44  cheshire
-<rdar://problem/4985095> Leak on error path in DNSServiceProcessResult
-
-Revision 1.59  2007/01/05 08:30:55  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.58  2006/10/27 00:38:22  cheshire
-Strip accidental trailing whitespace from lines
-
-Revision 1.57  2006/09/30 01:06:54  cheshire
-Protocol field should be uint32_t
-
-Revision 1.56  2006/09/27 00:44:16  herscher
-<rdar://problem/4249761> API: Need DNSServiceGetAddrInfo()
-
-Revision 1.55  2006/09/26 01:52:01  herscher
-<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
-
-Revision 1.54  2006/09/21 21:34:09  cheshire
-<rdar://problem/4100000> Allow empty string name when using kDNSServiceFlagsNoAutoRename
-
-Revision 1.53  2006/09/07 04:43:12  herscher
-Fix compile error on Win32 platform by moving inclusion of syslog.h
-
-Revision 1.52  2006/08/15 23:04:21  mkrochma
-<rdar://problem/4090354> Client should be able to specify service name w/o callback
-
-Revision 1.51  2006/07/24 23:45:55  cheshire
-<rdar://problem/4605276> DNSServiceReconfirmRecord() should return error code
-
-Revision 1.50  2006/06/28 08:22:27  cheshire
-<rdar://problem/4605264> dnssd_clientstub.c needs to report unlink failures in syslog
-
-Revision 1.49  2006/06/28 07:58:59  cheshire
-Minor textual tidying
-
-*/
+ */
 
 #include <errno.h>
 #include <stdlib.h>
@@ -345,6 +62,7 @@ Minor textual tidying
                int len;
                char * buffer;
                DWORD err = WSAGetLastError();
+               (void) priority;
                va_start( args, message );
                len = _vscprintf( message, args ) + 1;
                buffer = malloc( len * sizeof(char) );
@@ -394,25 +112,34 @@ typedef void (*ProcessReplyFn)(DNSServiceOp *const sdr, const CallbackHeader *co
 // When using kDNSServiceFlagsShareConnection, there is one primary _DNSServiceOp_t, and zero or more subordinates
 // For the primary, the 'next' field points to the first subordinate, and its 'next' field points to the next, and so on.
 // For the primary, the 'primary' field is NULL; for subordinates the 'primary' field points back to the associated primary
+//
+// _DNS_SD_LIBDISPATCH is defined where libdispatch/GCD is available. This does not mean that the application will use the
+// DNSServiceSetDispatchQueue API. Hence any new code guarded with _DNS_SD_LIBDISPATCH should still be backwards compatible.
 struct _DNSServiceRef_t
        {
-       DNSServiceOp    *next;                          // For shared connection
-       DNSServiceOp    *primary;                       // For shared connection
-       dnssd_sock_t     sockfd;                        // Connected socket between client and daemon
-       dnssd_sock_t     validator;                     // Used to detect memory corruption, double disposals, etc.
-       client_context_t uid;                           // For shared connection requests, each subordinate DNSServiceRef has its own ID,
+       DNSServiceOp     *next;                         // For shared connection
+       DNSServiceOp     *primary;                      // For shared connection
+       dnssd_sock_t      sockfd;                       // Connected socket between client and daemon
+       dnssd_sock_t      validator;            // Used to detect memory corruption, double disposals, etc.
+       client_context_t  uid;                          // For shared connection requests, each subordinate DNSServiceRef has its own ID,
                                                                                // unique within the scope of the same shared parent DNSServiceRef
-       uint32_t         op;                            // request_op_t or reply_op_t
-       uint32_t         max_index;                     // Largest assigned record index - 0 if no additional records registered
-       uint32_t         logcounter;            // Counter used to control number of syslog messages we write
-       int             *moreptr;                       // Set while DNSServiceProcessResult working on this particular DNSServiceRef
-       ProcessReplyFn   ProcessReply;          // Function pointer to the code to handle received messages
-       void            *AppCallback;           // Client callback function and context
-       void            *AppContext;
+       uint32_t          op;                           // request_op_t or reply_op_t
+       uint32_t          max_index;            // Largest assigned record index - 0 if no additional records registered
+       uint32_t          logcounter;           // Counter used to control number of syslog messages we write
+       int              *moreptr;                      // Set while DNSServiceProcessResult working on this particular DNSServiceRef
+       ProcessReplyFn    ProcessReply;         // Function pointer to the code to handle received messages
+       void             *AppCallback;          // Client callback function and context
+       void             *AppContext;
+       DNSRecord        *rec;
+#if _DNS_SD_LIBDISPATCH
+       dispatch_source_t disp_source;
+       dispatch_queue_t  disp_queue;
+#endif
        };
 
 struct _DNSRecordRef_t
        {
+       DNSRecord               *recnext;
        void *AppContext;
        DNSServiceRegisterRecordReply AppCallback;
        DNSRecordRef recref;
@@ -421,20 +148,35 @@ struct _DNSRecordRef_t
        };
 
 // Write len bytes. Return 0 on success, -1 on error
-static int write_all(dnssd_sock_t sd, char *buf, int len)
+static int write_all(dnssd_sock_t sd, char *buf, size_t len)
        {
        // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
        //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
        while (len)
                {
-               ssize_t num_written = send(sd, buf, len, 0);
-               if (num_written < 0 || num_written > len)
+               ssize_t num_written = send(sd, buf, (long)len, 0);
+               if (num_written < 0 || (size_t)num_written > len)
                        {
                        // Should never happen. If it does, it indicates some OS bug,
                        // or that the mDNSResponder daemon crashed (which should never happen).
-                       syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%d %d %s", sd, num_written, len,
+                       #if !defined(__ppc__) && defined(SO_ISDEFUNCT)
+                       int defunct;
+                       socklen_t dlen = sizeof (defunct);
+                       if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
+                               syslog(LOG_WARNING, "dnssd_clientstub write_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+                       if (!defunct)
+                               syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
+                                       (long)num_written, (long)len,
+                                       (num_written < 0) ? dnssd_errno                 : 0,
+                                       (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
+                       else
+                               syslog(LOG_INFO, "dnssd_clientstub write_all(%d) DEFUNCT", sd);
+                       #else
+                       syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
+                               (long)num_written, (long)len,
                                (num_written < 0) ? dnssd_errno                 : 0,
                                (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
+                       #endif
                        return -1;
                        }
                buf += num_written;
@@ -445,7 +187,7 @@ static int write_all(dnssd_sock_t sd, char *buf, int len)
 
 enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2 };
 
-// Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for 
+// Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for
 static int read_all(dnssd_sock_t sd, char *buf, int len)
        {
        // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
@@ -456,11 +198,32 @@ static int read_all(dnssd_sock_t sd, char *buf, int len)
                ssize_t num_read = recv(sd, buf, len, 0);
                if ((num_read == 0) || (num_read < 0) || (num_read > len))
                        {
+                       int printWarn = 0;
+                       int defunct = 0;
                        // Should never happen. If it does, it indicates some OS bug,
                        // or that the mDNSResponder daemon crashed (which should never happen).
-                       syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %ld/%d %d %s", sd, num_read, len,
-                               (num_read < 0) ? dnssd_errno                 : 0,
-                               (num_read < 0) ? dnssd_strerror(dnssd_errno) : "");
+#if defined(WIN32)
+                       // <rdar://problem/7481776> Suppress logs for "A non-blocking socket operation
+                       //                          could not be completed immediately"
+                       if (WSAGetLastError() != WSAEWOULDBLOCK)
+                               printWarn = 1;
+#endif
+#if !defined(__ppc__) && defined(SO_ISDEFUNCT)
+                       {
+                       socklen_t dlen = sizeof (defunct);
+                       if (getsockopt(sd, SOL_SOCKET, SO_ISDEFUNCT, &defunct, &dlen) < 0)
+                               syslog(LOG_WARNING, "dnssd_clientstub read_all: SO_ISDEFUNCT failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+                       }
+                       if (!defunct)
+                               printWarn = 1;
+#endif
+                       if (printWarn)
+                               syslog(LOG_WARNING, "dnssd_clientstub read_all(%d) failed %ld/%ld %d %s", sd,
+                                       (long)num_read, (long)len,
+                                       (num_read < 0) ? dnssd_errno                 : 0,
+                                       (num_read < 0) ? dnssd_strerror(dnssd_errno) : "");
+                       else if (defunct)
+                               syslog(LOG_INFO, "dnssd_clientstub read_all(%d) DEFUNCT", sd);
                        return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : read_all_fail;
                        }
                buf += num_read;
@@ -474,9 +237,29 @@ static int more_bytes(dnssd_sock_t sd)
        {
        struct timeval tv = { 0, 0 };
        fd_set readfds;
-       FD_ZERO(&readfds);
-       FD_SET(sd, &readfds);
-       return(select(sd+1, &readfds, (fd_set*)NULL, (fd_set*)NULL, &tv) > 0);
+       fd_set *fs;
+       int ret;
+
+       if (sd < FD_SETSIZE)
+               {
+               fs = &readfds;
+               FD_ZERO(fs);
+               }
+       else 
+               {
+               // Compute the number of integers needed for storing "sd". Internally fd_set is stored
+               // as an array of ints with one bit for each fd and hence we need to compute
+               // the number of ints needed rather than the number of bytes. If "sd" is 32, we need
+               // two ints and not just one.
+               int nfdbits = sizeof (int) * 8;
+               int nints = (sd/nfdbits) + 1;
+               fs = (fd_set *)calloc(nints, sizeof(int));
+               if (fs == NULL) { syslog(LOG_WARNING, "dnssd_clientstub more_bytes: malloc failed"); return 0; }
+               }
+       FD_SET(sd, fs);
+       ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv);
+       if (fs != &readfds) free(fs);
+       return (ret > 0);
        }
 
 /* create_hdr
@@ -503,11 +286,11 @@ static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int
 #if defined(USE_TCP_LOOPBACK)
                *len += 2;  // Allocate space for two-byte port number
 #elif defined(USE_NAMED_ERROR_RETURN_SOCKET)
-               struct timeval time;
-               if (gettimeofday(&time, NULL) < 0)
+               struct timeval tv;
+               if (gettimeofday(&tv, NULL) < 0)
                        { syslog(LOG_WARNING, "dnssd_clientstub create_hdr: gettimeofday failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno)); return NULL; }
                sprintf(ctrl_path, "%s%d-%.3lx-%.6lu", CTL_PATH_PREFIX, (int)getpid(),
-                       (unsigned long)(time.tv_sec & 0xFFF), (unsigned long)(time.tv_usec));
+                       (unsigned long)(tv.tv_sec & 0xFFF), (unsigned long)(tv.tv_usec));
                *len += strlen(ctrl_path) + 1;
 #else
                *len += 1;              // Allocate space for single zero byte (empty C string)
@@ -540,9 +323,20 @@ static ipc_msg_hdr *create_hdr(uint32_t op, size_t *len, char **data_start, int
        return hdr;
        }
 
+static void FreeDNSRecords(DNSServiceOp *sdRef)
+       {
+       DNSRecord *rec = sdRef->rec;
+       while (rec)
+               {
+               DNSRecord *next = rec->recnext;
+               free(rec);
+               rec = next;
+               }
+       }
+
 static void FreeDNSServiceOp(DNSServiceOp *x)
        {
-       // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed 
+       // We don't use our DNSServiceRefValid macro here because if we're cleaning up after a socket() call failed
        // then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket)
        if ((x->sockfd ^ x->validator) != ValidatorBits)
                syslog(LOG_WARNING, "dnssd_clientstub attempt to dispose invalid DNSServiceRef %p %08X %08X", x, x->sockfd, x->validator);
@@ -559,6 +353,16 @@ static void FreeDNSServiceOp(DNSServiceOp *x)
                x->ProcessReply = NULL;
                x->AppCallback  = NULL;
                x->AppContext   = NULL;
+               x->rec          = NULL;
+#if _DNS_SD_LIBDISPATCH
+               if (x->disp_source)     dispatch_release(x->disp_source);
+               x->disp_source  = NULL;
+               x->disp_queue   = NULL;
+#endif
+               // DNSRecords may have been added to subordinate sdRef e.g., DNSServiceRegister/DNSServiceAddRecord
+               // or on the main sdRef e.g., DNSServiceCreateConnection/DNSServiveRegisterRecord. DNSRecords may have
+               // been freed if the application called DNSRemoveRecord
+               FreeDNSRecords(x);
                free(x);
                }
        }
@@ -619,6 +423,11 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
        sdr->ProcessReply  = ProcessReply;
        sdr->AppCallback   = AppCallback;
        sdr->AppContext    = AppContext;
+       sdr->rec           = NULL;
+#if _DNS_SD_LIBDISPATCH
+       sdr->disp_source   = NULL;
+       sdr->disp_queue    = NULL;
+#endif
 
        if (flags & kDNSServiceFlagsShareConnection)
                {
@@ -659,6 +468,13 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
                #else
                saddr.sun_family      = AF_LOCAL;
                strcpy(saddr.sun_path, MDNS_UDS_SERVERPATH);
+               #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
+               {
+               int defunct = 1;
+               if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
+                       syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+               }
+               #endif  
                #endif
        
                while (1)
@@ -758,6 +574,13 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
                                {
                                errsd    = sp[0];       // We'll read our four-byte error code from sp[0]
                                listenfd = sp[1];       // We'll send sp[1] to the daemon
+                               #if !defined(__ppc__) && defined(SO_DEFUNCTOK)
+                               {
+                               int defunct = 1;
+                               if (setsockopt(errsd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
+                                       syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+                               }
+                               #endif  
                                }
                        }
                #endif
@@ -932,6 +755,69 @@ int DNSSD_API DNSServiceRefSockFD(DNSServiceRef sdRef)
        return (int) sdRef->sockfd;
        }
 
+#if _DNS_SD_LIBDISPATCH
+static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error)
+       {
+       DNSServiceOp *sdr = sdRef;
+       DNSServiceOp *sdrNext;
+       DNSRecord *rec;
+       DNSRecord *recnext;
+       int morebytes;
+       
+       while (sdr)
+               {
+               // We can't touch the sdr after the callback as it can be deallocated in the callback
+               sdrNext = sdr->next;
+               morebytes = 1;
+               sdr->moreptr = &morebytes;
+               switch (sdr->op)
+                       {
+                       case resolve_request:
+                               if (sdr->AppCallback)((DNSServiceResolveReply)    sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL,    sdr->AppContext);
+                               break;
+                       case query_request:
+                               if (sdr->AppCallback)((DNSServiceQueryRecordReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, 0, 0, NULL, 0, sdr->AppContext);
+                               break;
+                       case addrinfo_request:
+                               if (sdr->AppCallback)((DNSServiceGetAddrInfoReply)sdr->AppCallback)(sdr, 0, 0, error, NULL, NULL, 0,          sdr->AppContext);
+                               break;
+                       case browse_request:
+                               if (sdr->AppCallback)((DNSServiceBrowseReply)     sdr->AppCallback)(sdr, 0, 0, error, NULL, 0, NULL,          sdr->AppContext);
+                               break;
+                       case reg_service_request:
+                               if (sdr->AppCallback)((DNSServiceRegisterReply)   sdr->AppCallback)(sdr, 0,    error, NULL, 0, NULL,          sdr->AppContext);
+                               break;
+                       case enumeration_request:
+                               if (sdr->AppCallback)((DNSServiceDomainEnumReply) sdr->AppCallback)(sdr, 0, 0, error, NULL,                   sdr->AppContext);
+                               break;
+                       case connection_request:
+                               // This means Register Record, walk the list of DNSRecords to do the callback
+                               rec = sdr->rec;
+                               while (rec)
+                                       {
+                                       recnext = rec->recnext;
+                                       if (rec->AppCallback) ((DNSServiceRegisterRecordReply)rec->AppCallback)(sdr, 0, 0, error, rec->AppContext);
+                                       // The Callback can call DNSServiceRefDeallocate which in turn frees sdr and all the records.
+                                       // Detect that and return early
+                                       if (!morebytes){syslog(LOG_WARNING, "dnssdclientstub:Record: CallbackwithError morebytes zero"); return;}
+                                       rec = recnext;
+                                       }
+                               break;
+                       case port_mapping_request:
+                               if (sdr->AppCallback)((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, 0, 0, error, 0, 0, 0, 0, 0, sdr->AppContext);
+                               break;
+                       default:
+                               syslog(LOG_WARNING, "dnssd_clientstub CallbackWithError called with bad op %d", sdr->op);
+                       }
+               // If DNSServiceRefDeallocate was called in the callback, morebytes will be zero. It means
+               // all other sdrefs have been freed. This happens for shared connections where the
+               // DNSServiceRefDeallocate on the first sdRef frees all other sdrefs.
+               if (!morebytes){syslog(LOG_WARNING, "dnssdclientstub:sdRef: CallbackwithError morebytes zero"); return;}
+               sdr = sdrNext;
+               }
+       }
+#endif // _DNS_SD_LIBDISPATCH
+
 // Handle reply from server, calling application client callback. If there is no reply
 // from the daemon on the socket contained in sdRef, the call will block.
 DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
@@ -968,11 +854,26 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
                // return NoError on EWOULDBLOCK. This will handle the case
                // where a non-blocking socket is told there is data, but it was a false positive.
                // On error, read_all will write a message to syslog for us, so don't need to duplicate that here
-               // Note: If we want to properly support using non-blocking sockets in the future 
+               // Note: If we want to properly support using non-blocking sockets in the future
                int result = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr));
                if (result == read_all_fail)
                        {
+                       // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
+                       // in the callback.
                        sdRef->ProcessReply = NULL;
+#if _DNS_SD_LIBDISPATCH
+                       // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
+                       // is not called by the application and hence need to communicate the error. Cancel the
+                       // source so that we don't get any more events
+                       if (sdRef->disp_source)
+                               {
+                               dispatch_source_cancel(sdRef->disp_source);
+                               dispatch_release(sdRef->disp_source);
+                               sdRef->disp_source = NULL;
+                               CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
+                               }
+#endif
+                       // Don't touch sdRef anymore as it might have been deallocated
                        return kDNSServiceErr_ServiceNotRunning;
                        }
                else if (result == read_all_wouldblock)
@@ -997,8 +898,23 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
                if (!data) return kDNSServiceErr_NoMemory;
                if (read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen) < 0) // On error, read_all will write a message to syslog for us
                        {
-                       free(data);
+                       // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
+                       // in the callback.
                        sdRef->ProcessReply = NULL;
+#if _DNS_SD_LIBDISPATCH
+                       // Call the callbacks with an error if using the dispatch API, as DNSServiceProcessResult
+                       // is not called by the application and hence need to communicate the error. Cancel the
+                       // source so that we don't get any more events
+                       if (sdRef->disp_source)
+                               {
+                               dispatch_source_cancel(sdRef->disp_source);
+                               dispatch_release(sdRef->disp_source);
+                               sdRef->disp_source = NULL;
+                               CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
+                               }
+#endif
+                       // Don't touch sdRef anymore as it might have been deallocated
+                       free(data);
                        return kDNSServiceErr_ServiceNotRunning;
                        }
                else
@@ -1056,16 +972,43 @@ void DNSSD_API DNSServiceRefDeallocate(DNSServiceRef sdRef)
                        char *ptr;
                        size_t len = 0;
                        ipc_msg_hdr *hdr = create_hdr(cancel_request, &len, &ptr, 0, sdRef);
-                       ConvertHeaderBytes(hdr);
-                       write_all(sdRef->sockfd, (char *)hdr, len);
-                       free(hdr);
+                       if (hdr)
+                               {
+                               ConvertHeaderBytes(hdr);
+                               write_all(sdRef->sockfd, (char *)hdr, len);
+                               free(hdr);
+                               }
                        *p = sdRef->next;
                        FreeDNSServiceOp(sdRef);
                        }
                }
        else                                    // else, make sure to terminate all subordinates as well
                {
+#if _DNS_SD_LIBDISPATCH
+               // The cancel handler will close the fd if a dispatch source has been set
+               if (sdRef->disp_source)
+                       {
+                       // By setting the ProcessReply to NULL, we make sure that we never call
+                       // the application callbacks ever, after returning from this function. We
+                       // assume that DNSServiceRefDeallocate is called from the serial queue
+                       // that was passed to DNSServiceSetDispatchQueue. Hence, dispatch_source_cancel
+                       // should cancel all the blocks on the queue and hence there should be no more
+                       // callbacks when we return from this function. Setting ProcessReply to NULL
+                       // provides extra protection.
+                       sdRef->ProcessReply = NULL;
+                       dispatch_source_cancel(sdRef->disp_source);
+                       dispatch_release(sdRef->disp_source);
+                       sdRef->disp_source = NULL;
+                       }
+                       // if disp_queue is set, it means it used the DNSServiceSetDispatchQueue API. In that case,
+                       // when the source was cancelled, the fd was closed in the handler. Currently the source
+                       // is cancelled only when the mDNSResponder daemon dies
+               else if (!sdRef->disp_queue) dnssd_close(sdRef->sockfd);
+#else
                dnssd_close(sdRef->sockfd);
+#endif
+               // Free DNSRecords added in DNSRegisterRecord if they have not
+               // been freed in DNSRemoveRecord
                while (sdRef)
                        {
                        DNSServiceOp *p = sdRef;
@@ -1117,18 +1060,19 @@ static void handle_resolve_response(DNSServiceOp *const sdr, const CallbackHeade
 
        get_string(&data, end, fullname, kDNSServiceMaxDomainName);
        get_string(&data, end, target,   kDNSServiceMaxDomainName);
-       if (!data || data + 2 > end) data = NULL;
-       else
-               {
-               port.b[0] = *data++;
-               port.b[1] = *data++;
-               }
+       if (!data || data + 2 > end) goto fail;
+
+       port.b[0] = *data++;
+       port.b[1] = *data++;
        txtlen = get_uint16(&data, end);
        txtrecord = (unsigned char *)get_rdata(&data, end, txtlen);
 
-       if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
-       else ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext);
+       if (!data) goto fail;
+       ((DNSServiceResolveReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, fullname, target, port.s, txtlen, txtrecord, sdr->AppContext);
+       return;
        // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+fail:
+       syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
        }
 
 DNSServiceErrorType DNSSD_API DNSServiceResolve
@@ -1375,6 +1319,7 @@ DNSServiceErrorType DNSSD_API DNSServiceBrowse
        return err;
        }
 
+DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain);
 DNSServiceErrorType DNSSD_API DNSServiceSetDefaultDomainForUser(DNSServiceFlags flags, const char *domain)
        {
        DNSServiceOp *tmp;
@@ -1576,6 +1521,7 @@ DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
        size_t len;
        ipc_msg_hdr *hdr = NULL;
        DNSRecordRef rref = NULL;
+       DNSRecord **p;
        int f1 = (flags & kDNSServiceFlagsShared) != 0;
        int f2 = (flags & kDNSServiceFlagsUnique) != 0;
        if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
@@ -1620,10 +1566,15 @@ DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
        rref->AppCallback = callBack;
        rref->record_index = sdRef->max_index++;
        rref->sdr = sdRef;
+       rref->recnext = NULL;
        *RecordRef = rref;
        hdr->client_context.context = rref;
        hdr->reg_index = rref->record_index;
 
+       p = &(sdRef)->rec;
+       while (*p) p = &(*p)->recnext;
+       *p = rref;
+
        return deliver_request(hdr, sdRef);             // Will free hdr for us
        }
 
@@ -1643,6 +1594,7 @@ DNSServiceErrorType DNSSD_API DNSServiceAddRecord
        size_t len = 0;
        char *ptr;
        DNSRecordRef rref;
+       DNSRecord **p;
 
        if (!sdRef)     { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSServiceRef");        return kDNSServiceErr_BadParam; }
        if (!RecordRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceAddRecord called with NULL DNSRecordRef pointer"); return kDNSServiceErr_BadParam; }
@@ -1679,9 +1631,14 @@ DNSServiceErrorType DNSSD_API DNSServiceAddRecord
        rref->AppCallback = NULL;
        rref->record_index = sdRef->max_index++;
        rref->sdr = sdRef;
+       rref->recnext = NULL;
        *RecordRef = rref;
        hdr->reg_index = rref->record_index;
 
+       p = &(sdRef)->rec;
+       while (*p) p = &(*p)->recnext;
+       *p = rref;
+
        return deliver_request(hdr, sdRef);             // Will free hdr for us
        }
 
@@ -1753,7 +1710,15 @@ DNSServiceErrorType DNSSD_API DNSServiceRemoveRecord
        hdr->reg_index = RecordRef->record_index;
        put_flags(flags, &ptr);
        err = deliver_request(hdr, sdRef);              // Will free hdr for us
-       if (!err) free(RecordRef);
+       if (!err)
+               {
+               // This RecordRef could have been allocated in DNSServiceRegisterRecord or DNSServiceAddRecord.
+               // If so, delink from the list before freeing
+               DNSRecord **p = &sdRef->rec;
+               while (*p && *p != RecordRef) p = &(*p)->recnext;
+               if (*p) *p = RecordRef->recnext;
+               free(RecordRef);
+               }
        return err;
        }
 
@@ -1800,29 +1765,31 @@ DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
 static void handle_port_mapping_response(DNSServiceOp *const sdr, const CallbackHeader *const cbh, const char *data, const char *const end)
        {
        union { uint32_t l; u_char b[4]; } addr;
-       uint8_t protocol = 0;
+       uint8_t protocol;
        union { uint16_t s; u_char b[2]; } internalPort;
        union { uint16_t s; u_char b[2]; } externalPort;
-       uint32_t ttl = 0;
-
-       if (!data || data + 13 > end) data = NULL;
-       else
-               {
-               addr        .b[0] = *data++;
-               addr        .b[1] = *data++;
-               addr        .b[2] = *data++;
-               addr        .b[3] = *data++;
-               protocol          = *data++;
-               internalPort.b[0] = *data++;
-               internalPort.b[1] = *data++;
-               externalPort.b[0] = *data++;
-               externalPort.b[1] = *data++;
-               ttl               = get_uint32(&data, end);
-               }
+       uint32_t ttl;
 
-       if (!data) syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon");
-       else ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, internalPort.s, externalPort.s, ttl, sdr->AppContext);
+       if (!data || data + 13 > end) goto fail;
+
+       addr        .b[0] = *data++;
+       addr        .b[1] = *data++;
+       addr        .b[2] = *data++;
+       addr        .b[3] = *data++;
+       protocol          = *data++;
+       internalPort.b[0] = *data++;
+       internalPort.b[1] = *data++;
+       externalPort.b[0] = *data++;
+       externalPort.b[1] = *data++;
+       ttl               = get_uint32(&data, end);
+       if (!data) goto fail;
+
+       ((DNSServiceNATPortMappingReply)sdr->AppCallback)(sdr, cbh->cb_flags, cbh->cb_interface, cbh->cb_err, addr.l, protocol, internalPort.s, externalPort.s, ttl, sdr->AppContext);
+       return;
        // MUST NOT touch sdr after invoking AppCallback -- client is allowed to dispose it from within callback function
+
+fail:
+       syslog(LOG_WARNING, "dnssd_clientstub handle_port_mapping_response: error reading result from daemon");
        }
 
 DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
@@ -1870,3 +1837,41 @@ DNSServiceErrorType DNSSD_API DNSServiceNATPortMappingCreate
        if (err) { DNSServiceRefDeallocate(*sdRef); *sdRef = NULL; }
        return err;
        }
+
+#if _DNS_SD_LIBDISPATCH
+DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
+       (
+       DNSServiceRef service,
+       dispatch_queue_t queue
+       )
+       {
+       int dnssd_fd  = DNSServiceRefSockFD(service);
+       if (dnssd_fd == dnssd_InvalidSocket) return kDNSServiceErr_BadParam;
+       if (!queue)
+               {
+               syslog(LOG_WARNING, "dnssd_clientstub: DNSServiceSetDispatchQueue dispatch queue NULL");
+               return kDNSServiceErr_BadParam;
+               }
+       if (service->disp_queue)
+               {
+               syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch queue set already");
+               return kDNSServiceErr_BadParam;
+               }
+       if (service->disp_source)
+               {
+               syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch source set already");
+               return kDNSServiceErr_BadParam;
+               }
+       service->disp_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, dnssd_fd, 0, queue);
+       if (!service->disp_source)
+               {
+               syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch_source_create failed");
+               return kDNSServiceErr_NoMemory;
+               }
+       service->disp_queue = queue;
+       dispatch_source_set_event_handler(service->disp_source, ^{DNSServiceProcessResult(service);});
+       dispatch_source_set_cancel_handler(service->disp_source, ^{dnssd_close(dnssd_fd);});
+       dispatch_resume(service->disp_source);
+       return kDNSServiceErr_NoError;
+       }
+#endif // _DNS_SD_LIBDISPATCH
index f929ec0402a90373cb5ba05928d55f28c3b9e261..131510c80e44b31aeaf949a1080d92132d3b523f 100644 (file)
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-       Change History (most recent first):
-
-$Log: dnssd_ipc.c,v $
-Revision 1.23  2009/04/01 21:10:34  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-
-Revision 1.22  2009/02/12 20:28:31  cheshire
-Added some missing "const" declarations
-
-Revision 1.21  2008/10/23 23:21:31  cheshire
-Moved definition of dnssd_strerror() to be with the definition of dnssd_errno, in dnssd_ipc.h
-
-Revision 1.20  2007/07/23 22:12:53  cheshire
-<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
-
-Revision 1.19  2007/05/16 01:06:52  cheshire
-<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
-
-Revision 1.18  2007/03/21 19:01:57  cheshire
-<rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits
-
-Revision 1.17  2006/10/27 00:38:22  cheshire
-Strip accidental trailing whitespace from lines
-
-Revision 1.16  2006/08/14 23:05:53  cheshire
-Added "tab-width" emacs header line
-
-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)"
-
-Revision 1.13  2004/10/01 22:15:55  rpantos
-rdar://problem/3824265: Replace APSL in client lib with BSD license.
-
-Revision 1.12  2004/09/16 23:14:24  cheshire
-Changes for Windows compatibility
-
-Revision 1.11  2004/06/18 04:56:09  rpantos
-casting goodness
-
-Revision 1.10  2004/06/12 01:08:14  cheshire
-Changes for Windows compatibility
-
-Revision 1.9  2004/05/18 23:51:27  cheshire
-Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
-
-Revision 1.8  2003/11/05 22:44:57  ksekar
-<rdar://problem/3335230>: No bounds checking when reading data from client
-Reviewed by: Stuart Cheshire
-
-Revision 1.7  2003/08/12 19:56:25  cheshire
-Update to APSL 2.0
-
  */
 
 #include "dnssd_ipc.h"
index 92976f7465ad2872cd35af2560afa93ed236ec94..760e1b4bc7c777da8115efe2825f46c801dee55c 100644 (file)
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-    Change History (most recent first):
-
-$Log: dnssd_ipc.h,v $
-Revision 1.46  2009/05/27 22:20:44  cheshire
-Removed unused dnssd_errno_assign() (we have no business writing to errno -- we should only read it)
-
-Revision 1.45  2009/05/26 21:31:07  herscher
-Fix compile errors on Windows
-
-Revision 1.44  2009/02/12 20:28:31  cheshire
-Added some missing "const" declarations
-
-Revision 1.43  2008/10/23 23:21:31  cheshire
-Moved definition of dnssd_strerror() to be with the definition of dnssd_errno, in dnssd_ipc.h
-
-Revision 1.42  2008/10/23 23:06:17  cheshire
-Removed () from dnssd_errno macro definition -- it's not a function and doesn't need any arguments
-
-Revision 1.41  2008/09/27 01:04:09  cheshire
-Added "send_bpf" to list of request_op_t operation codes
-
-Revision 1.40  2007/09/07 20:56:03  cheshire
-Renamed uint32_t field in client_context_t from "ptr64" to more accurate name "u32"
-
-Revision 1.39  2007/08/18 01:02:04  mcguire
-<rdar://problem/5415593> No Bonjour services are getting registered at boot
-
-Revision 1.38  2007/08/08 22:34:59  mcguire
-<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
-
-Revision 1.37  2007/07/28 00:00:43  cheshire
-Renamed CompileTimeAssertionCheck structure for consistency with others
-
-Revision 1.36  2007/07/23 22:12:53  cheshire
-<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
-
-Revision 1.35  2007/05/23 18:59:22  cheshire
-Remove unnecessary IPC_FLAGS_REUSE_SOCKET
-
-Revision 1.34  2007/05/22 01:07:42  cheshire
-<rdar://problem/3563675> API: Need a way to get version/feature information
-
-Revision 1.33  2007/05/18 23:55:22  cheshire
-<rdar://problem/4454655> Allow multiple register/browse/resolve operations to share single Unix Domain Socket
-
-Revision 1.32  2007/05/18 20:31:20  cheshire
-Rename port_mapping_create_request to port_mapping_request
-
-Revision 1.31  2007/05/18 17:56:20  cheshire
-Rename port_mapping_create_reply_op to port_mapping_reply_op
-
-Revision 1.30  2007/05/16 01:06:52  cheshire
-<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
-
-Revision 1.29  2007/05/15 21:57:16  cheshire
-<rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
-assuming that all negative values (or zero!) are invalid socket numbers
-
-Revision 1.28  2007/03/21 19:01:57  cheshire
-<rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits
-
-Revision 1.27  2006/10/27 00:38:22  cheshire
-Strip accidental trailing whitespace from lines
-
-Revision 1.26  2006/09/27 00:44:36  herscher
-<rdar://problem/4249761> API: Need DNSServiceGetAddrInfo()
-
-Revision 1.25  2006/09/26 01:51:07  herscher
-<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
-
-Revision 1.24  2006/09/18 19:21:42  cheshire
-<rdar://problem/4737048> gcc's structure padding breaks Bonjour APIs on
-64-bit clients; need to declare ipc_msg_hdr structure "packed"
-
-Revision 1.23  2006/08/14 23:05:53  cheshire
-Added "tab-width" emacs header line
-
-Revision 1.22  2006/06/28 08:56:26  cheshire
-Added "_op" to the end of the operation code enum values,
-to differentiate them from the routines with the same names
-
-Revision 1.21  2005/09/29 06:38:13  herscher
-Remove #define MSG_WAITALL on Windows.  We don't use this macro anymore, and it's presence causes warnings to be emitted when compiling against the latest Microsoft Platform SDK.
-
-Revision 1.20  2005/03/21 00:39:31  shersche
-<rdar://problem/4021486> Fix build warnings on Win32 platform
-
-Revision 1.19  2005/02/02 02:25:22  cheshire
-<rdar://problem/3980388> /var/run/mDNSResponder should be /var/run/mdnsd on Linux
-
-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.
-
-Revision 1.16  2004/11/12 03:21:41  rpantos
-rdar://problem/3809541 Add DNSSDMapIfIndexToName, DNSSDMapNameToIfIndex.
-
-Revision 1.15  2004/10/06 02:22:20  cheshire
-Changed MacRoman copyright symbol (should have been UTF-8 in any case :-) to ASCII-compatible "(c)"
-
-Revision 1.14  2004/10/01 22:15:55  rpantos
-rdar://problem/3824265: Replace APSL in client lib with BSD license.
-
-Revision 1.13  2004/09/16 23:14:25  cheshire
-Changes for Windows compatibility
-
-Revision 1.12  2004/09/16 21:46:38  ksekar
-<rdar://problem/3665304> Need SPI for LoginWindow to associate a UID with a Wide Area domain
-
-Revision 1.11  2004/08/10 06:24:56  cheshire
-Use types with precisely defined sizes for 'op' and 'reg_index', for better
-compatibility if the daemon and the client stub are built using different compilers
-
-Revision 1.10  2004/07/07 17:39:25  shersche
-Change MDNS_SERVERPORT from 5533 to 5354.
-
-Revision 1.9  2004/06/25 00:26:27  rpantos
-Changes to fix the Posix build on Solaris.
-
-Revision 1.8  2004/06/18 04:56:51  rpantos
-Add layer for platform code
-
-Revision 1.7  2004/06/12 01:08:14  cheshire
-Changes for Windows compatibility
-
-Revision 1.6  2003/08/12 19:56:25  cheshire
-Update to APSL 2.0
-
  */
 
 #ifndef DNSSD_IPC_H
@@ -179,6 +47,8 @@ Update to APSL 2.0
 #      define dnssd_strerror(X)        win32_strerror(X)
 #      define ssize_t                          int
 #      define getpid                           _getpid
+#      define unlink                           _unlink
+extern char *win32_strerror(int inErrorCode);
 #else
 #      include <sys/types.h>
 #      include <unistd.h>
@@ -246,7 +116,7 @@ Update to APSL 2.0
 typedef enum
     {
     request_op_none = 0,       // No request yet received on this connection
-    connection_request = 1,    // connected socket via DNSServiceConnect()
+    connection_request = 1,    // connected socket via DNSServiceCreateConnection()
     reg_record_request,                // reg/remove record only valid for connected sockets
     remove_record_request,
     enumeration_request,
@@ -300,7 +170,7 @@ typedef packedstruct
     uint32_t op;               // request_op_t or reply_op_t
     client_context_t client_context; // context passed from client, returned by server in corresponding reply
     uint32_t reg_index;            // identifier for a record registered via DNSServiceRegisterRecord() on a
-    // socket connected by DNSServiceConnect().  Must be unique in the scope of the connection, such that and
+    // socket connected by DNSServiceCreateConnection().  Must be unique in the scope of the connection, such that and
     // index/socket pair uniquely identifies a record.  (Used to select records for removal by DNSServiceRemoveRecord())
     } ipc_msg_hdr;
 
index 38ae2db0a1c1e972e568da1b8bb57be53e350e3a..fd85c9cd35a470fff66196a34f3e8fa49825a143 100644 (file)
 .\" See the License for the specific language governing permissions and
 .\" limitations under the License.
 .\"
-.\" $Log: mDNS.1,v $
-.\" Revision 1.8  2006/08/14 23:24:56  cheshire
-.\" Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-.\"
-.\" Revision 1.7  2005/02/16 02:29:32  cheshire
-.\" Update terminology
-.\"
-.\" Revision 1.6  2005/02/10 22:35:28  cheshire
-.\" <rdar://problem/3727944> Update name
-.\"
-.\" Revision 1.5  2004/09/24 18:33:05  cheshire
-.\" <rdar://problem/3561780> Update man pages to clarify that mDNS and dns-sd are not intended for script use
-.\"
-.\" Revision 1.4  2004/09/22 22:18:48  cheshire
-.\" Update man page to cross-reference new dns-sd man page
-.\"
-.\" Revision 1.3  2004/05/19 00:31:28  cheshire
-.\" Add missing "name type domain" for -L option
-.\"
-.\" Revision 1.2  2004/05/18 18:58:29  cheshire
-.\" Refinements from Soren Spies
-.\"
-.\" Revision 1.1  2004/04/22 02:52:53  cheshire
-.\" <rdar://problem/3597463>: mDNSResponder missing man pages: mDNS
-.\"
-.\"
-.\"
 .Dd April 2004              \" Date
 .Dt mDNS 1                  \" Document Title
 .Os Darwin                  \" Operating System
index 60154d12194fcd2512140c966e908d06fa6f21fc..f111a5dd7b5832f3f768418e55ed47e3adec4558 100644 (file)
 
        Version:        1.0
 
-    Change History (most recent first):
-
-$Log: mDNSDebug.c,v $
-Revision 1.16  2009/04/11 01:43:28  jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.15  2009/04/11 00:20:26  jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.14  2008/11/26 00:01:08  cheshire
-Get rid of "Unknown" tag in SIGINFO output on Leopard
-
-Revision 1.13  2007/12/01 00:40:30  cheshire
-Fixes from Bob Bradley for building on EFI
-
-Revision 1.12  2007/10/01 19:06:19  cheshire
-Defined symbolic constant MDNS_LOG_INITIAL_LEVEL to set the logging level we start out at
-
-Revision 1.11  2007/07/27 20:19:56  cheshire
-For now, comment out unused log levels MDNS_LOG_ERROR, MDNS_LOG_WARN, MDNS_LOG_INFO, MDNS_LOG_DEBUG
-
-Revision 1.10  2007/06/15 21:54:51  cheshire
-<rdar://problem/4883206> Add packet logging to help debugging private browsing over TLS
-
-Revision 1.9  2007/04/05 19:52:32  cheshire
-Display correct ident in syslog messages (i.e. in dnsextd, ProgramName is not "mDNSResponder")
-
-Revision 1.8  2007/01/20 01:43:27  cheshire
-<rdar://problem/4058383> Should not write log messages to /dev/console
-
-Revision 1.7  2006/08/14 23:24:56  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-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
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.4  2004/06/11 22:36:51  cheshire
-Fixes for compatibility with Windows
-
-Revision 1.3  2004/01/28 21:14:23  cheshire
-Reconcile debug_mode and gDebugLogging into a single flag (mDNS_DebugMode)
-
-Revision 1.2  2003/12/09 01:30:40  rpantos
-Fix usage of ARGS... macros to build properly on Windows.
-
-Revision 1.1  2003/12/08 21:11:42;  rpantos
-Changes necessary to support mDNSResponder on Linux.
-
-*/
+ */
 
 #include "mDNSDebug.h"
 
@@ -132,7 +78,6 @@ mDNSlocal void LogMsgWithLevelv(mDNSLogLevel_t logLevel, const char *format, va_
 
 // see mDNSDebug.h
 #if !MDNS_HAS_VA_ARG_MACROS
-void debug_noop(const char *format, ...)  { (void) format; }
 void LogMsg_(const char *format, ...)       LOG_HELPER_BODY(MDNS_LOG_MSG)
 void LogOperation_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_OPERATION)
 void LogSPS_(const char *format, ...)       LOG_HELPER_BODY(MDNS_LOG_SPS)
@@ -140,7 +85,7 @@ void LogInfo_(const char *format, ...)      LOG_HELPER_BODY(MDNS_LOG_INFO)
 #endif
 
 #if MDNS_DEBUGMSGS
-void debugf_(const char *format, ...)      LOG_HELPER_BODY(MDNS_LOG_DEBUG)
+void debugf_(const char *format, ...)       LOG_HELPER_BODY(MDNS_LOG_DEBUG)
 #endif
 
 // Log message with default "mDNSResponder" ident string at the start
index e383eb641c221e51ba522f08a1e375e4ba73b56f..48fcbd5a8dde03842c8d4e0457129f2217772c53 100644 (file)
 .\" See the License for the specific language governing permissions and
 .\" limitations under the License.
 .\"
-.\" $Log: mDNSResponder.8,v $
-.\" Revision 1.10  2009/04/20 16:12:13  mcguire
-.\" <rdar://problem/6807798> manpage: roff errors
-.\"
-.\" Revision 1.9  2009/04/11 00:20:27  jessic2
-.\" <rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-.\"
-.\" Revision 1.8  2006/10/06 17:31:33  mkrochma
-.\" <rdar://problem/4769407> Typo in man page for mDNSResponder(8)
-.\"
-.\" Revision 1.7  2006/08/14 23:24:56  cheshire
-.\" Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-.\"
-.\" Revision 1.6  2005/02/10 22:35:28  cheshire
-.\" <rdar://problem/3727944> Update name
-.\"
-.\" Revision 1.5  2004/06/29 02:41:38  cheshire
-.\" Add note that mDNSResponder is called mdnsd on some systems
-.\"
-.\" Revision 1.4  2004/05/18 18:14:36  cheshire
-.\" Minor wording update
-.\"
-.\" Revision 1.3  2004/04/22 02:56:08  cheshire
-.\" <rdar://problem/3619494>: mDNSResponder man page format error
-.\"
-.\" Revision 1.2  2004/04/12 18:03:24  ksekar
-.\" <rdar://problem/3619494>: mDNSResponder man page format error
-.\"
-.\" Revision 1.1  2003/11/13 03:21:38  cheshire
-.\" <rdar://problem/3086886>: No man page for mDNSResponder
-.\"
-.\"
-.\"
 .Dd April 2004              \" Date
 .Dt mDNSResponder 8         \" Document Title
 .Os Darwin                  \" Operating System
index 8b89b151a3e218499992729b47ee89b2f2912036..aff5ff0f0d535abddebc9cd2047235c1bc59a10a 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-       Change History (most recent first):
-
-$Log: uds_daemon.c,v $
-Revision 1.463  2009/07/10 22:25:47  cheshire
-Updated syslog messages for debugging unresponsive clients:
-Will now log a warning message about an unresponsive client every ten seconds,
-and then after 60 messagess (10 minutes) will terminate connection to that client.
-
-Revision 1.462  2009/07/09 22:43:31  cheshire
-Improved log messages for debugging unresponsive clients
-
-Revision 1.461  2009/06/19 23:15:07  cheshire
-<rdar://problem/6990066> Library: crash at handle_resolve_response + 183
-Made resolve_result_callback code more defensive and improved LogOperation messages
-
-Revision 1.460  2009/05/26 21:31:07  herscher
-Fix compile errors on Windows
-
-Revision 1.459  2009/04/30 20:07:51  mcguire
-<rdar://problem/6822674> Support multiple UDSs from launchd
-
-Revision 1.458  2009/04/25 00:59:06  mcguire
-Change a few stray LogInfo to LogOperation
-
-Revision 1.457  2009/04/22 01:19:57  jessic2
-<rdar://problem/6814585> Daemon: mDNSResponder is logging garbage for error codes because it's using %ld for int 32
-
-Revision 1.456  2009/04/21 01:56:34  jessic2
-<rdar://problem/6803941> BTMM: Back out change for preventing other local users from sending packets to your BTMM machines
-
-Revision 1.455  2009/04/20 19:19:57  cheshire
-<rdar://problem/6803941> BTMM: If multiple local users are logged in to same BTMM account, all but one fail
-Don't need "empty info->u.browser.browsers list" debugging message, now that we expect this to be
-a case that can legitimately happen.
-
-Revision 1.454  2009/04/18 20:56:43  jessic2
-<rdar://problem/6803941> BTMM: If multiple local users are logged in to same BTMM account, all but one fail
-
-Revision 1.453  2009/04/11 00:20:29  jessic2
-<rdar://problem/4426780> Daemon: Should be able to turn on LogOperation dynamically
-
-Revision 1.452  2009/04/07 01:17:42  jessic2
-<rdar://problem/6747917> BTMM: Multiple accounts lets me see others' remote services & send packets to others' remote hosts
-
-Revision 1.451  2009/04/02 22:34:26  jessic2
-<rdar://problem/6305347> Race condition: If fd has already been closed, SO_NOSIGPIPE returns errno 22 (Invalid argument)
-
-Revision 1.450  2009/04/01 21:11:28  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows. Workaround use of recvmsg.
-
-Revision 1.449  2009/03/17 19:44:25  cheshire
-<rdar://problem/6688927> Don't let negative unicast answers block Multicast DNS responses
-
-Revision 1.448  2009/03/17 04:53:40  cheshire
-<rdar://problem/6688927> Don't let negative unicast answers block Multicast DNS responses
-
-Revision 1.447  2009/03/17 04:41:32  cheshire
-Moved LogOperation message to after check for "if (answer->RecordType == kDNSRecordTypePacketNegative)"
-
-Revision 1.446  2009/03/04 01:47:35  cheshire
-Include m->ProxyRecords in SIGINFO output
-
-Revision 1.445  2009/03/03 23:04:44  cheshire
-For clarity, renamed "MAC" field to "HMAC" (Host MAC, as opposed to Interface MAC)
-
-Revision 1.444  2009/03/03 22:51:55  cheshire
-<rdar://problem/6504236> Sleep Proxy: Waking on same network but different interface will cause conflicts
-
-Revision 1.443  2009/02/27 02:28:41  cheshire
-Need to declare "const AuthRecord *ar;"
-
-Revision 1.442  2009/02/27 00:58:17  cheshire
-Improved detail of SIGINFO logging for m->DuplicateRecords
-
-Revision 1.441  2009/02/24 22:18:59  cheshire
-Include interface name for interface-specific AuthRecords
-
-Revision 1.440  2009/02/21 01:38:08  cheshire
-Added report of m->SleepState value in SIGINFO output
-
-Revision 1.439  2009/02/18 23:38:44  cheshire
-<rdar://problem/6600780> Could not write data to client 13 - aborting connection
-Eliminated unnecessary "request_state *request" field from the reply_state structure.
-
-Revision 1.438  2009/02/18 23:23:14  cheshire
-Cleaned up debugging log messages
-
-Revision 1.437  2009/02/17 23:29:05  cheshire
-Throttle logging to a slower rate when running on SnowLeopard
-
-Revision 1.436  2009/02/13 06:28:02  cheshire
-Converted LogOperation messages to LogInfo
-
-Revision 1.435  2009/02/12 20:57:26  cheshire
-Renamed 'LogAllOperation' switch to 'LogClientOperations'; added new 'LogSleepProxyActions' switch
-
-Revision 1.434  2009/02/12 20:28:31  cheshire
-Added some missing "const" declarations
-
-Revision 1.433  2009/02/10 01:44:39  cheshire
-<rdar://problem/6553729> DNSServiceUpdateRecord fails with kDNSServiceErr_BadReference for otherwise valid reference
-
-Revision 1.432  2009/02/10 01:38:56  cheshire
-Move regservice_termination_callback() earlier in file in preparation for subsequent work
-
-Revision 1.431  2009/02/07 01:48:55  cheshire
-In SIGINFO output include sequence number for proxied records
-
-Revision 1.430  2009/01/31 21:58:05  cheshire
-<rdar://problem/4786302> Implement logic to determine when to send dot-local lookups via Unicast
-Only want to do unicast dot-local lookups for address queries and conventional (RFC 2782) SRV queries
-
-Revision 1.429  2009/01/31 00:45:26  cheshire
-<rdar://problem/4786302> Implement logic to determine when to send dot-local lookups via Unicast
-Further refinements
-
-Revision 1.428  2009/01/30 19:52:31  cheshire
-Eliminated unnecessary duplicated "dnssd_sock_t sd" fields in service_instance and reply_state structures
-
-Revision 1.427  2009/01/24 01:48:43  cheshire
-<rdar://problem/4786302> Implement logic to determine when to send dot-local lookups via Unicast
-
-Revision 1.426  2009/01/16 21:07:08  cheshire
-In SIGINFO "Duplicate Records" list, show expiry time for Sleep Proxy records
-
-Revision 1.425  2009/01/16 20:53:16  cheshire
-Include information about Sleep Proxy records in SIGINFO output
-
-Revision 1.424  2009/01/12 22:43:50  cheshire
-Fixed "unused variable" warning when SO_NOSIGPIPE is not defined
-
-Revision 1.423  2009/01/10 22:54:42  mkrochma
-<rdar://problem/5797544> Fixes from Igor Seleznev to get mdnsd working on Linux
-
-Revision 1.422  2009/01/10 01:52:48  cheshire
-Include DuplicateRecords and LocalOnlyQuestions in SIGINFO output
-
-Revision 1.421  2008/12/17 05:05:26  cheshire
-Fixed alignment of NAT mapping syslog messages
-
-Revision 1.420  2008/12/12 00:52:05  cheshire
-mDNSPlatformSetBPF is now called mDNSPlatformReceiveBPF_fd
-
-Revision 1.419  2008/12/10 02:11:44  cheshire
-ARMv5 compiler doesn't like uncommented stuff after #endif
-
-Revision 1.418  2008/12/09 05:12:53  cheshire
-Updated debugging messages
-
-Revision 1.417  2008/12/04 03:38:12  cheshire
-Miscellaneous defensive coding changes and improvements to debugging log messages
-
-Revision 1.416  2008/12/02 22:02:12  cheshire
-<rdar://problem/6320621> Adding domains after TXT record updates registers stale TXT record data
-
-Revision 1.415  2008/11/26 20:35:59  cheshire
-Changed some "LogOperation" debugging messages to "debugf"
-
-Revision 1.414  2008/11/26 00:02:25  cheshire
-Improved SIGINFO output to list AutoBrowseDomains and AutoRegistrationDomains
-
-Revision 1.413  2008/11/25 04:48:58  cheshire
-Added logging to show whether Sleep Proxy Service is active
-
-Revision 1.412  2008/11/24 23:05:43  cheshire
-Additional checking in uds_validatelists()
-
-Revision 1.411  2008/11/05 21:41:39  cheshire
-Updated LogOperation message
-
-Revision 1.410  2008/11/04 20:06:20  cheshire
-<rdar://problem/6186231> Change MAX_DOMAIN_NAME to 256
-
-Revision 1.409  2008/10/31 23:44:22  cheshire
-Fixed compile error in Posix build
-
-Revision 1.408  2008/10/29 21:32:33  cheshire
-Align "DNSServiceEnumerateDomains ... RESULT" log messages
-
-Revision 1.407  2008/10/27 07:34:36  cheshire
-Additional sanity checks for debugging
-
-Revision 1.406  2008/10/23 23:55:56  cheshire
-Fixed some missing "const" declarations
-
-Revision 1.405  2008/10/23 23:21:31  cheshire
-Moved definition of dnssd_strerror() to be with the definition of dnssd_errno, in dnssd_ipc.h
-
-Revision 1.404  2008/10/23 23:06:17  cheshire
-Removed () from dnssd_errno macro definition -- it's not a function and doesn't need any arguments
-
-Revision 1.403  2008/10/23 22:33:25  cheshire
-Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
-
-Revision 1.402  2008/10/22 19:47:59  cheshire
-Instead of SameRData(), use equivalent IdenticalSameNameRecord() macro
-
-Revision 1.401  2008/10/22 17:20:40  cheshire
-Don't give up if setsockopt SO_NOSIGPIPE fails
-
-Revision 1.400  2008/10/21 01:06:57  cheshire
-Pass BPF fd to mDNSMacOSX.c using mDNSPlatformSetBPF() instead of just writing it into a shared global variable
-
-Revision 1.399  2008/10/20 22:06:42  cheshire
-Updated debugging log messages
-
-Revision 1.398  2008/10/03 18:25:17  cheshire
-Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);"
-
-Revision 1.397  2008/10/02 22:26:21  cheshire
-Moved declaration of BPF_fd from uds_daemon.c to mDNSMacOSX.c, where it really belongs
-
-Revision 1.396  2008/09/30 01:04:55  cheshire
-Made BPF code a bit more defensive, to ignore subsequent BPF fds if we get passed more than one
-
-Revision 1.395  2008/09/27 01:28:43  cheshire
-Added code to receive and store BPF fd when passed via a send_bpf message
-
-Revision 1.394  2008/09/23 04:12:40  cheshire
-<rdar://problem/6238774> Remove "local" from the end of _services._dns-sd._udp PTR records
-Added a special-case to massage these new records for Bonjour Browser's benefit
-
-Revision 1.393  2008/09/23 03:01:58  cheshire
-Added operation logging of domain enumeration results
-
-Revision 1.392  2008/09/18 22:30:06  cheshire
-<rdar://problem/6230679> device-info record not removed when last service deregisters
-
-Revision 1.391  2008/09/18 22:05:44  cheshire
-Fixed "DNSServiceRegister ... ADDED" message to have escaping consistent with
-the other DNSServiceRegister operation messages
-
-Revision 1.390  2008/09/16 21:06:56  cheshire
-Improved syslog output to show if q->LongLived flag is set for multicast questions
-
-Revision 1.389  2008/07/25 22:34:11  mcguire
-fix sizecheck issues for 64bit
-
-Revision 1.388  2008/07/01 01:40:02  mcguire
-<rdar://problem/5823010> 64-bit fixes
-
-Revision 1.387  2008/02/26 21:24:13  cheshire
-Fixed spelling mistake in comment
-
-Revision 1.386  2008/02/26 20:23:15  cheshire
-Updated comments
-
-Revision 1.385  2008/02/19 21:50:52  cheshire
-Shortened some overly-long lines
-
-Revision 1.384  2007/12/22 01:38:05  cheshire
-Improve display of "Auth Records" SIGINFO output
-
-Revision 1.383  2007/12/07 00:45:58  cheshire
-<rdar://problem/5526800> BTMM: Need to deregister records and services on shutdown/sleep
-
-Revision 1.382  2007/11/30 20:11:48  cheshire
-Fixed compile warning: declaration of 'remove' shadows a global declaration
-
-Revision 1.381  2007/11/28 22:02:52  cheshire
-Remove pointless "if (!domain)" check (domain is an array on the stack, so its address can never be null)
-
-Revision 1.380  2007/11/28 18:38:41  cheshire
-Fixed typo in log message: "DNSServiceResolver" -> "DNSServiceResolve"
-
-Revision 1.379  2007/11/01 19:32:14  cheshire
-Added "DEBUG_64BIT_SCM_RIGHTS" debugging code
-
-Revision 1.378  2007/10/31 19:21:40  cheshire
-Don't show Expire time for records and services that aren't currently registered
-
-Revision 1.377  2007/10/30 23:48:20  cheshire
-Improved SIGINFO listing of question state
-
-Revision 1.376  2007/10/30 20:43:54  cheshire
-Fixed compiler warning when LogClientOperations is turned off
-
-Revision 1.375  2007/10/26 22:51:38  cheshire
-Improved SIGINFO output to show timers for AuthRecords and ServiceRegistrations
-
-Revision 1.374  2007/10/25 22:45:02  cheshire
-Tidied up code for DNSServiceRegister callback status messages
-
-Revision 1.373  2007/10/25 21:28:43  cheshire
-Add ServiceRegistrations to SIGINFO output
-
-Revision 1.372  2007/10/25 21:21:45  cheshire
-<rdar://problem/5496734> BTMM: Need to retry registrations after failures
-Don't unlink_and_free_service_instance at the first error
-
-Revision 1.371  2007/10/18 23:34:40  cheshire
-<rdar://problem/5532821> Need "considerable burden on the network" warning in uds_daemon.c
-
-Revision 1.370  2007/10/17 18:44:23  cheshire
-<rdar://problem/5539930> Goodbye packets not being sent for services on shutdown
-
-Revision 1.369  2007/10/16 17:18:27  cheshire
-Fixed Posix compile errors
-
-Revision 1.368  2007/10/16 16:58:58  cheshire
-Improved debugging error messages in read_msg()
-
-Revision 1.367  2007/10/15 22:55:14  cheshire
-Make read_msg return "void" (since request_callback just ignores the redundant return value anyway)
-
-Revision 1.366  2007/10/10 00:48:54  cheshire
-<rdar://problem/5526379> Daemon spins in an infinite loop when it doesn't get the control message it's expecting
-
-Revision 1.365  2007/10/06 03:25:23  cheshire
-<rdar://problem/5525267> MacBuddy exits abnormally when clicking "Continue" in AppleConnect pane
-
-Revision 1.364  2007/10/06 03:20:16  cheshire
-Improved LogOperation debugging messages
-
-Revision 1.363  2007/10/05 23:24:52  cheshire
-Improved LogOperation messages about separate error return socket
-
-Revision 1.362  2007/10/05 22:11:58  cheshire
-Improved "send_msg ERROR" debugging message
-
-Revision 1.361  2007/10/04 20:45:18  cheshire
-<rdar://problem/5518381> Race condition in kDNSServiceFlagsShareConnection-mode call handling
-
-Revision 1.360  2007/10/01 23:24:46  cheshire
-SIGINFO output was mislabeling mDNSInterface_Any queries as unicast queries
-
-Revision 1.359  2007/09/30 00:09:27  cheshire
-<rdar://problem/5492315> Pass socket fd via SCM_RIGHTS sendmsg instead of using named UDS in the filesystem
-
-Revision 1.358  2007/09/29 20:08:06  cheshire
-Fixed typo in comment
-
-Revision 1.357  2007/09/27 22:10:04  cheshire
-Add LogOperation line for DNSServiceRegisterRecord callbacks
-
-Revision 1.356  2007/09/26 21:29:30  cheshire
-Improved question list SIGINFO output
-
-Revision 1.355  2007/09/26 01:54:34  mcguire
-Debugging: In SIGINFO output, show ClientTunnel query interval, which is how we determine whether a query is still active
-
-Revision 1.354  2007/09/26 01:26:31  cheshire
-<rdar://problem/5501567> BTMM: mDNSResponder crashes in free_service_instance enabling/disabling BTMM
-Need to call SendServiceRemovalNotification *before* backpointer is cleared
-
-Revision 1.353  2007/09/25 20:46:33  cheshire
-Include DNSServiceRegisterRecord operations in SIGINFO output
-
-Revision 1.352  2007/09/25 20:23:40  cheshire
-<rdar://problem/5501567> BTMM: mDNSResponder crashes in free_service_instance enabling/disabling BTMM
-Need to clear si->request backpointer before calling mDNS_DeregisterService(&mDNSStorage, &si->srs);
-
-Revision 1.351  2007/09/25 18:20:34  cheshire
-Changed name of "free_service_instance" to more accurate "unlink_and_free_service_instance"
-
-Revision 1.350  2007/09/24 23:54:52  mcguire
-Additional list checking in uds_validatelists()
-
-Revision 1.349  2007/09/24 06:01:00  cheshire
-Debugging: In SIGINFO output, show NAT Traversal time values in seconds rather than platform ticks
-
-Revision 1.348  2007/09/24 05:02:41  cheshire
-Debugging: In SIGINFO output, indicate explicitly when a given section is empty
-
-Revision 1.347  2007/09/21 02:04:33  cheshire
-<rdar://problem/5440831> BTMM: mDNSResponder crashes in free_service_instance enabling/disabling BTMM
-
-Revision 1.346  2007/09/19 22:47:25  cheshire
-<rdar://problem/5490182> Memory corruption freeing a "no such service" service record
-
-Revision 1.345  2007/09/19 20:32:29  cheshire
-<rdar://problem/5482322> BTMM: Don't advertise SMB with BTMM because it doesn't support IPv6
-
-Revision 1.344  2007/09/19 19:27:50  cheshire
-<rdar://problem/5492182> Improved diagnostics when daemon can't connect to error return path socket
-
-Revision 1.343  2007/09/18 21:42:30  cheshire
-To reduce programming mistakes, renamed ExtPort to RequestedPort
-
-Revision 1.342  2007/09/14 22:38:20  cheshire
-Additional list checking in uds_validatelists()
-
-Revision 1.341  2007/09/13 00:16:43  cheshire
-<rdar://problem/5468706> Miscellaneous NAT Traversal improvements
-
-Revision 1.340  2007/09/12 23:03:08  cheshire
-<rdar://problem/5476978> DNSServiceNATPortMappingCreate callback not giving correct interface index
-
-Revision 1.339  2007/09/12 19:22:21  cheshire
-Variable renaming in preparation for upcoming fixes e.g. priv/pub renamed to intport/extport
-Made NAT Traversal packet handlers take typed data instead of anonymous "mDNSu8 *" byte pointers
-
-Revision 1.338  2007/09/12 01:22:13  cheshire
-Improve validatelists() checking to detect when 'next' pointer gets smashed to ~0
-
-Revision 1.337  2007/09/07 23:05:04  cheshire
-Add display of client_context field in handle_cancel_request() LogOperation message
-While loop was checking client_context.u32[2] instead of client_context.u32[1]
-
-Revision 1.336  2007/09/07 20:56:03  cheshire
-Renamed uint32_t field in client_context_t from "ptr64" to more accurate name "u32"
-
-Revision 1.335  2007/09/05 22:25:01  vazquez
-<rdar://problem/5400521> update_record mDNSResponder leak
-
-Revision 1.334  2007/09/05 20:43:57  cheshire
-Added LogOperation message showing fd of socket listening for incoming Unix Domain Socket client requests
-
-Revision 1.333  2007/08/28 23:32:35  cheshire
-Added LogOperation messages for DNSServiceNATPortMappingCreate() operations
-
-Revision 1.332  2007/08/27 22:59:31  cheshire
-Show reg_index in DNSServiceRegisterRecord/DNSServiceRemoveRecord messages
-
-Revision 1.331  2007/08/27 20:29:57  cheshire
-Added SIGINFO listing of TunnelClients
-
-Revision 1.330  2007/08/24 23:46:50  cheshire
-Added debugging messages and SIGINFO listing of DomainAuthInfo records
-
-Revision 1.329  2007/08/18 01:02:04  mcguire
-<rdar://problem/5415593> No Bonjour services are getting registered at boot
-
-Revision 1.328  2007/08/15 20:18:28  vazquez
-<rdar://problem/5400521> update_record mDNSResponder leak
-Make sure we free all ExtraResourceRecords
-
-Revision 1.327  2007/08/08 22:34:59  mcguire
-<rdar://problem/5197869> Security: Run mDNSResponder as user id mdnsresponder instead of root
-
-Revision 1.326  2007/08/01 16:09:14  cheshire
-Removed unused NATTraversalInfo substructure from AuthRecord; reduced structure sizecheck values accordingly
-
-Revision 1.325  2007/07/31 21:29:41  cheshire
-<rdar://problem/5372207> System Default registration domain(s) not listed in Domain Enumeration ("dns-sd -E")
-
-Revision 1.324  2007/07/31 01:56:21  cheshire
-Corrected function name in log message
-
-Revision 1.323  2007/07/27 23:57:23  cheshire
-Added compile-time structure size checks
-
-Revision 1.322  2007/07/27 19:37:19  cheshire
-Moved AutomaticBrowseDomainQ into main mDNS object
-
-Revision 1.321  2007/07/27 19:30:41  cheshire
-Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
-to properly reflect tri-state nature of the possible responses
-
-Revision 1.320  2007/07/27 00:48:27  cheshire
-<rdar://problem/4700198> BTMM: Services should only get registered in .Mac domain of current user
-<rdar://problem/4731180> BTMM: Only browse in the current user's .Mac domain by default
-
-Revision 1.319  2007/07/24 17:23:33  cheshire
-<rdar://problem/5357133> Add list validation checks for debugging
-
-Revision 1.318  2007/07/23 23:09:51  cheshire
-<rdar://problem/5351997> Reject oversized client requests
-
-Revision 1.317  2007/07/23 22:24:47  cheshire
-<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
-Additional refinements
-
-Revision 1.316  2007/07/23 22:12:53  cheshire
-<rdar://problem/5352299> Make mDNSResponder more defensive against malicious local clients
-
-Revision 1.315  2007/07/21 01:36:13  cheshire
-Need to also add ".local" as automatic browsing domain
-
-Revision 1.314  2007/07/20 20:12:37  cheshire
-Rename "mDNS_DomainTypeBrowseLegacy" as "mDNS_DomainTypeBrowseAutomatic"
-
-Revision 1.313  2007/07/20 00:54:21  cheshire
-<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-
-Revision 1.312  2007/07/11 03:06:43  cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-
-Revision 1.311  2007/07/06 21:19:18  cheshire
-Add list of NAT traversals to SIGINFO output
-
-Revision 1.310  2007/07/03 19:56:50  cheshire
-Add LogOperation message for DNSServiceSetDefaultDomainForUser
-
-Revision 1.309  2007/06/29 23:12:49  vazquez
-<rdar://problem/5294103> Stop using generate_final_fatal_reply_with_garbage
-
-Revision 1.308  2007/06/29 00:10:07  vazquez
-<rdar://problem/5301908> Clean up NAT state machine (necessary for 6 other fixes)
-
-Revision 1.307  2007/05/25 00:25:44  cheshire
-<rdar://problem/5227737> Need to enhance putRData to output all current known types
-
-Revision 1.306  2007/05/24 22:31:35  vazquez
-Bug #: 4272956
-Reviewed by: Stuart Cheshire
-<rdar://problem/4272956> WWDC API: Return ADD/REMOVE events in registration callback
-
-Revision 1.305  2007/05/23 18:59:22  cheshire
-Remove unnecessary IPC_FLAGS_REUSE_SOCKET
-
-Revision 1.304  2007/05/22 01:07:42  cheshire
-<rdar://problem/3563675> API: Need a way to get version/feature information
-
-Revision 1.303  2007/05/22 00:32:58  cheshire
-Make a send_all() subroutine -- will be helpful for implementing DNSServiceGetProperty(DaemonVersion)
-
-Revision 1.302  2007/05/21 18:54:54  cheshire
-Add "Cancel" LogOperation message when we get a cancel_request command over the UDS
-
-Revision 1.301  2007/05/18 23:55:22  cheshire
-<rdar://problem/4454655> Allow multiple register/browse/resolve operations to share single Unix Domain Socket
-
-Revision 1.300  2007/05/18 21:27:11  cheshire
-Rename connected_registration_termination to connection_termination
-
-Revision 1.299  2007/05/18 21:24:34  cheshire
-Rename rstate to request
-
-Revision 1.298  2007/05/18 21:22:35  cheshire
-Convert uint16_t etc. to their locally-defined equivalents, like the rest of the core code
-
-Revision 1.297  2007/05/18 20:33:11  cheshire
-Avoid declaring lots of uninitialized variables in read_rr_from_ipc_msg
-
-Revision 1.296  2007/05/18 19:04:19  cheshire
-Rename msgdata to msgptr (may be modified); rename (currently unused) bufsize to msgend
-
-Revision 1.295  2007/05/18 17:57:13  cheshire
-Reorder functions in file to arrange them in logical groups; added "#pragma mark" headers for each group
-
-Revision 1.294  2007/05/17 20:58:22  cheshire
-<rdar://problem/4647145> DNSServiceQueryRecord should return useful information with NXDOMAIN
-
-Revision 1.293  2007/05/17 19:46:20  cheshire
-Routine name deliver_async_error() is misleading. What it actually does is write a message header
-(containing an error code) followed by 256 bytes of garbage zeroes onto a client connection,
-thereby trashing it and making it useless for any subsequent communication. It's destructive,
-and not very useful. Changing name to generate_final_fatal_reply_with_garbage().
-
-Revision 1.292  2007/05/16 01:06:52  cheshire
-<rdar://problem/4471320> Improve reliability of kDNSServiceFlagsMoreComing flag on multiprocessor machines
-
-Revision 1.291  2007/05/15 21:57:16  cheshire
-<rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
-assuming that all negative values (or zero!) are invalid socket numbers
-
-Revision 1.290  2007/05/10 23:30:57  cheshire
-<rdar://problem/4084490> Only one browse gets remove events when disabling browse domain
-
-Revision 1.289  2007/05/02 22:18:08  cheshire
-Renamed NATTraversalInfo_struct context to NATTraversalContext
-
-Revision 1.288  2007/04/30 21:33:39  cheshire
-Fix crash when a callback unregisters a service while the UpdateSRVRecords() loop
-is iterating through the m->ServiceRegistrations list
-
-Revision 1.287  2007/04/27 19:03:22  cheshire
-Check q->LongLived not q->llq to tell if a query is LongLived
-
-Revision 1.286  2007/04/26 16:00:01  cheshire
-Show interface number in DNSServiceBrowse RESULT output
-
-Revision 1.285  2007/04/22 19:03:39  cheshire
-Minor code tidying
-
-Revision 1.284  2007/04/22 06:02:03  cheshire
-<rdar://problem/4615977> Query should immediately return failure when no server
-
-Revision 1.283  2007/04/21 21:47:47  cheshire
-<rdar://problem/4376383> Daemon: Add watchdog timer
-
-Revision 1.282  2007/04/20 21:17:24  cheshire
-For naming consistency, kDNSRecordTypeNegative should be kDNSRecordTypePacketNegative
-
-Revision 1.281  2007/04/19 23:25:20  cheshire
-Added debugging message
-
-Revision 1.280  2007/04/17 19:21:29  cheshire
-<rdar://problem/5140339> Domain discovery not working over VPN
-
-Revision 1.279  2007/04/16 21:53:49  cheshire
-Improve display of negative cache entries
-
-Revision 1.278  2007/04/16 20:49:40  cheshire
-Fix compile errors for mDNSPosix build
-
-Revision 1.277  2007/04/05 22:55:36  cheshire
-<rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
-
-Revision 1.276  2007/04/05 19:20:13  cheshire
-Non-blocking mode not being set correctly -- was clobbering other flags
-
-Revision 1.275  2007/04/04 21:21:25  cheshire
-<rdar://problem/4546810> Fix crash: In regservice_callback service_instance was being referenced after being freed
-
-Revision 1.274  2007/04/04 01:30:42  cheshire
-<rdar://problem/5075200> DNSServiceAddRecord is failing to advertise NULL record
-Add SIGINFO output lising our advertised Authoritative Records
-
-Revision 1.273  2007/04/04 00:03:27  cheshire
-<rdar://problem/5089862> DNSServiceQueryRecord is returning kDNSServiceErr_NoSuchRecord for empty rdata
-
-Revision 1.272  2007/04/03 20:10:32  cheshire
-Show ADD/RMV in DNSServiceQueryRecord log message instead of just "RESULT"
-
-Revision 1.271  2007/04/03 19:22:32  cheshire
-Use mDNSSameIPv4Address (and similar) instead of accessing internal fields directly
-
-Revision 1.270  2007/03/30 21:55:30  cheshire
-Added comments
-
-Revision 1.269  2007/03/29 01:31:44  cheshire
-Faulty logic was incorrectly suppressing some NAT port mapping callbacks
-
-Revision 1.268  2007/03/29 00:13:58  cheshire
-Remove unnecessary fields from service_instance structure: autoname, autorename, allowremotequery, name
-
-Revision 1.267  2007/03/28 20:59:27  cheshire
-<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
-
-Revision 1.266  2007/03/28 15:56:37  cheshire
-<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
-
-Revision 1.265  2007/03/27 22:52:07  cheshire
-Fix crash in udsserver_automatic_browse_domain_changed
-
-Revision 1.264  2007/03/27 00:49:40  cheshire
-Should use mallocL, not plain malloc
-
-Revision 1.263  2007/03/27 00:45:01  cheshire
-Removed unnecessary "void *termination_context" pointer
-
-Revision 1.262  2007/03/27 00:40:43  cheshire
-Eliminate resolve_termination_t as a separately-allocated structure, and make it part of the request_state union
-
-Revision 1.261  2007/03/27 00:29:00  cheshire
-Eliminate queryrecord_request data as a separately-allocated structure, and make it part of the request_state union
-
-Revision 1.260  2007/03/27 00:18:42  cheshire
-Eliminate enum_termination_t and domain_enum_t as separately-allocated structures,
-and make them part of the request_state union
-
-Revision 1.259  2007/03/26 23:48:16  cheshire
-<rdar://problem/4848295> Advertise model information via Bonjour
-Refinements to reduce unnecessary transmissions of the DeviceInfo TXT record
-
-Revision 1.258  2007/03/24 00:40:04  cheshire
-Minor code cleanup
-
-Revision 1.257  2007/03/24 00:23:12  cheshire
-Eliminate port_mapping_info_t as a separately-allocated structure, and make it part of the request_state union
-
-Revision 1.256  2007/03/24 00:07:18  cheshire
-Eliminate addrinfo_info_t as a separately-allocated structure, and make it part of the request_state union
-
-Revision 1.255  2007/03/23 23:56:14  cheshire
-Move list of record registrations into the request_state union
-
-Revision 1.254  2007/03/23 23:48:56  cheshire
-Eliminate service_info as a separately-allocated structure, and make it part of the request_state union
-
-Revision 1.253  2007/03/23 23:04:29  cheshire
-Eliminate browser_info_t as a separately-allocated structure, and make it part of request_state
-
-Revision 1.252  2007/03/23 22:59:58  cheshire
-<rdar://problem/4848295> Advertise model information via Bonjour
-Use kStandardTTL, not kHostNameTTL
-
-Revision 1.251  2007/03/23 22:44:07  cheshire
-Instead of calling AbortUnlinkAndFree() haphazardly all over the place, make the handle* routines
-return an error code, and then request_callback() does all necessary cleanup in one place.
-
-Revision 1.250  2007/03/22 20:30:07  cheshire
-Remove pointless "if (request->ts != t_complete) ..." checks
-
-Revision 1.249  2007/03/22 20:13:27  cheshire
-Delete unused client_context field
-
-Revision 1.248  2007/03/22 20:03:37  cheshire
-Rename variables for clarity: instead of using variable rs for both request_state
-and reply_state, use req for request_state and rep for reply_state
-
-Revision 1.247  2007/03/22 19:31:42  cheshire
-<rdar://problem/4848295> Advertise model information via Bonjour
-Add missing "model=" at start of DeviceInfo data
-
-Revision 1.246  2007/03/22 18:31:48  cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.245  2007/03/22 00:49:20  cheshire
-<rdar://problem/4848295> Advertise model information via Bonjour
-
-Revision 1.244  2007/03/21 21:01:48  cheshire
-<rdar://problem/4789793> Leak on error path in regrecord_callback, uds_daemon.c
-
-Revision 1.243  2007/03/21 19:01:57  cheshire
-<rdar://problem/5078494> IPC code not 64-bit-savvy: assumes long=32bits, and short=16bits
-
-Revision 1.242  2007/03/21 18:51:21  cheshire
-<rdar://problem/4549320> Code in uds_daemon.c passes function name instead of type name to mallocL/freeL
-
-Revision 1.241  2007/03/20 00:04:50  cheshire
-<rdar://problem/4837929> Should allow "udp" or "tcp" for protocol command-line arg
-Fix LogOperation("DNSServiceNATPortMappingCreate(...)") message to actually show client arguments
-
-Revision 1.240  2007/03/16 23:25:35  cheshire
-<rdar://problem/5067001> NAT-PMP: Parameter validation not working correctly
-
-Revision 1.239  2007/03/10 02:29:36  cheshire
-Added comment about port_mapping_create_reply()
-
-Revision 1.238  2007/03/07 00:26:48  cheshire
-<rdar://problem/4426754> DNSServiceRemoveRecord log message should include record type
-
-Revision 1.237  2007/02/28 01:44:29  cheshire
-<rdar://problem/5027863> Byte order bugs in uDNS.c, uds_daemon.c, dnssd_clientstub.c
-
-Revision 1.236  2007/02/14 01:58:19  cheshire
-<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
-
-Revision 1.235  2007/02/08 21:12:28  cheshire
-<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
-
-Revision 1.234  2007/02/06 19:06:49  cheshire
-<rdar://problem/3956518> Need to go native with launchd
-
-Revision 1.233  2007/01/10 20:49:37  cheshire
-Remove unnecessary setting of q->Private fields
-
-Revision 1.232  2007/01/09 00:03:23  cheshire
-Call udsserver_handle_configchange() once at the end of udsserver_init()
-to set up the automatic registration and browsing domains.
-
-Revision 1.231  2007/01/06 02:50:19  cheshire
-<rdar://problem/4632919> Instead of copying SRV and TXT record data, just store pointers to cache entities
-
-Revision 1.230  2007/01/06 01:00:35  cheshire
-Improved SIGINFO output
-
-Revision 1.229  2007/01/05 08:30:56  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.228  2007/01/05 08:09:05  cheshire
-Reorder code into functional sections, with "#pragma mark" headers
-
-Revision 1.227  2007/01/05 07:04:24  cheshire
-Minor code tidying
-
-Revision 1.226  2007/01/05 05:44:35  cheshire
-Move automatic browse/registration management from uDNS.c to mDNSShared/uds_daemon.c,
-so that mDNSPosix embedded clients will compile again
-
-Revision 1.225  2007/01/04 23:11:15  cheshire
-<rdar://problem/4720673> uDNS: Need to start caching unicast records
-When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
-
-Revision 1.224  2007/01/04 20:57:49  cheshire
-Rename ReturnCNAME to ReturnIntermed (for ReturnIntermediates)
-
-Revision 1.223  2006/12/21 01:25:49  cheshire
-Tidy up SIGINFO state log
-
-Revision 1.222  2006/12/21 00:15:22  cheshire
-Get rid of gmDNS macro; fixed a crash in udsserver_info()
-
-Revision 1.221  2006/12/20 04:07:38  cheshire
-Remove uDNS_info substructure from AuthRecord_struct
-
-Revision 1.220  2006/12/19 22:49:25  cheshire
-Remove uDNS_info substructure from ServiceRecordSet_struct
-
-Revision 1.219  2006/12/14 03:02:38  cheshire
-<rdar://problem/4838433> Tools: dns-sd -G 0 only returns IPv6 when you have a routable IPv6 address
-
-Revision 1.218  2006/11/18 05:01:33  cheshire
-Preliminary support for unifying the uDNS and mDNS code,
-including caching of uDNS answers
-
-Revision 1.217  2006/11/15 19:27:53  mkrochma
-<rdar://problem/4838433> Tools: dns-sd -G 0 only returns IPv6 when you have a routable IPv6 address
-
-Revision 1.216  2006/11/10 00:54:16  cheshire
-<rdar://problem/4816598> Changing case of Computer Name doesn't work
-
-Revision 1.215  2006/10/27 01:30:23  cheshire
-Need explicitly to set ReturnIntermed = mDNSfalse
-
-Revision 1.214  2006/10/20 05:37:23  herscher
-Display question list information in udsserver_info()
-
-Revision 1.213  2006/10/05 03:54:31  herscher
-Remove embedded uDNS_info struct from DNSQuestion_struct
-
-Revision 1.212  2006/09/30 01:22:35  cheshire
-Put back UTF-8 curly quotes in log messages
-
-Revision 1.211  2006/09/27 00:44:55  herscher
-<rdar://problem/4249761> API: Need DNSServiceGetAddrInfo()
-
-Revision 1.210  2006/09/26 01:52:41  herscher
-<rdar://problem/4245016> NAT Port Mapping API (for both NAT-PMP and UPnP Gateway Protocol)
-
-Revision 1.209  2006/09/21 21:34:09  cheshire
-<rdar://problem/4100000> Allow empty string name when using kDNSServiceFlagsNoAutoRename
-
-Revision 1.208  2006/09/21 21:28:24  cheshire
-Code cleanup to make it consistent with daemon.c: change rename_on_memfree to renameonmemfree
-
-Revision 1.207  2006/09/15 21:20:16  cheshire
-Remove uDNS_info substructure from mDNS_struct
-
-Revision 1.206  2006/08/14 23:24:56  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.205  2006/07/20 22:07:30  mkrochma
-<rdar://problem/4633196> Wide-area browsing is currently broken in TOT
-More fixes for uninitialized variables
-
-Revision 1.204  2006/07/15 02:01:33  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-Fix broken "empty string" browsing
-
-Revision 1.203  2006/07/07 01:09:13  cheshire
-<rdar://problem/4472013> Add Private DNS server functionality to dnsextd
-Only use mallocL/freeL debugging routines when building mDNSResponder, not dnsextd
-
-Revision 1.202  2006/07/05 22:00:10  cheshire
-Wide-area cleanup: Rename mDNSPlatformGetRegDomainList() to uDNS_GetDefaultRegDomainList()
-
-Revision 1.201  2006/06/29 03:02:47  cheshire
-<rdar://problem/4607042> mDNSResponder NXDOMAIN and CNAME support
-
-Revision 1.200  2006/06/28 08:56:26  cheshire
-Added "_op" to the end of the operation code enum values,
-to differentiate them from the routines with the same names
-
-Revision 1.199  2006/06/28 08:53:39  cheshire
-Added (commented out) debugging messages
-
-Revision 1.198  2006/06/27 20:16:07  cheshire
-Fix code layout
-
-Revision 1.197  2006/05/18 01:32:35  cheshire
-<rdar://problem/4472706> iChat: Lost connection with Bonjour
-(mDNSResponder insufficiently defensive against malformed browsing PTR responses)
-
-Revision 1.196  2006/05/05 07:07:13  cheshire
-<rdar://problem/4538206> mDNSResponder fails when UDS reads deliver partial data
-
-Revision 1.195  2006/04/25 20:56:28  mkrochma
-Added comment about previous checkin
-
-Revision 1.194  2006/04/25 18:29:36  mkrochma
-Workaround for warning: unused variable 'status' when building mDNSPosix
-
-Revision 1.193  2006/03/19 17:14:38  cheshire
-<rdar://problem/4483117> Need faster purging of stale records
-read_rr_from_ipc_msg was not setting namehash and rdatahash
-
-Revision 1.192  2006/03/18 20:58:32  cheshire
-Misplaced curly brace
-
-Revision 1.191  2006/03/10 22:19:43  cheshire
-Update debugging message in resolve_result_callback() to indicate whether event is ADD or RMV
-
-Revision 1.190  2006/03/10 21:56:12  cheshire
-<rdar://problem/4111464> After record update, old record sometimes remains in cache
-When service TXT and SRV record both change, clients with active resolve calls get *two* callbacks, one
-when the TXT data changes, and then immediately afterwards a second callback with the new port number
-This change suppresses the first unneccessary (and confusing) callback
-
-Revision 1.189  2006/01/06 00:56:31  cheshire
-<rdar://problem/4400573> Should remove PID file on exit
-
-*/
+ */
 
 #if defined(_WIN32)
 #include <process.h>
@@ -920,6 +43,23 @@ Revision 1.189  2006/01/06 00:56:31  cheshire
 #endif
 #endif
 
+#if APPLE_OSX_mDNSResponder
+#include <WebFilterDNS/WebFilterDNS.h>
+
+#if ! NO_WCF
+
+int WCFIsServerRunning(WCFConnection *conn) __attribute__((weak_import));
+int WCFNameResolvesToAddr(WCFConnection *conn, char* domainName, struct sockaddr* address, uid_t userid) __attribute__((weak_import));
+int WCFNameResolvesToName(WCFConnection *conn, char* fromName, char* toName, uid_t userid) __attribute__((weak_import));
+
+// Do we really need to define a macro for "if"?
+#define CHECK_WCF_FUNCTION(X) if (X)
+#endif // ! NO_WCF
+
+#else
+#define NO_WCF 1
+#endif // APPLE_OSX_mDNSResponder
+
 // User IDs 0-500 are system-wide processes, not actual users in the usual sense
 // User IDs for real user accounts start at 501 and count up from there
 #define SystemUID(X) ((X) <= 500)
@@ -947,9 +87,11 @@ typedef struct registered_record_entry
        {
        struct registered_record_entry *next;
        mDNSu32 key;
-       AuthRecord *rr;                         // Pointer to variable-sized AuthRecord
        client_context_t regrec_client_context;
        request_state *request;
+       mDNSBool external_advertise;
+       mDNSInterfaceID origInterfaceID;
+       AuthRecord *rr;                         // Pointer to variable-sized AuthRecord (Why a pointer? Why not just embed it here?)
        } registered_record_entry;
 
 // A single registered service: ServiceRecordSet + bookkeeping
@@ -963,6 +105,7 @@ typedef struct service_instance
        mDNSBool renameonmemfree;               // Set on config change when we deregister original name
     mDNSBool clientnotified;           // Has client been notified of successful registration yet?
        mDNSBool default_local;                 // is this the "local." from an empty-string registration?
+       mDNSBool external_advertise;    // is this is being advertised externally?
        domainname domain;
        ServiceRecordSet srs;                   // note -- variable-sized object -- must be last field in struct
        } service_instance;
@@ -979,10 +122,11 @@ struct request_state
        {
        request_state *next;
        request_state *primary;                 // If this operation is on a shared socket, pointer to primary
-                                                                       // request_state for the original DNSServiceConnect() operation
+                                                                       // request_state for the original DNSServiceCreateConnection() operation
        dnssd_sock_t sd;
        dnssd_sock_t errsd;
        mDNSu32 uid;
+       void * platform_data;
 
        // Note: On a shared connection these fields in the primary structure, including hdr, are re-used
        // for each new request. This is because, until we've read the ipc_msg_hdr to find out what the
@@ -1063,6 +207,7 @@ struct request_state
                        const ResourceRecord *txt;
                        const ResourceRecord *srv;
                        mDNSs32 ReportTime;
+                       mDNSBool external_advertise;
                        } resolve;
                } u;
        };
@@ -1097,12 +242,21 @@ mDNSexport const char ProgramName[] = "mDNSResponder";
 static dnssd_sock_t listenfd = dnssd_InvalidSocket;
 static request_state *all_requests = NULL;
 
+// Note asymmetry here between registration and browsing.
+// For service registrations we only automatically register in domains that explicitly appear in local configuration data
+// (so AutoRegistrationDomains could equally well be called SCPrefRegDomains)
+// For service browsing we also learn automatic browsing domains from the network, so for that case we have:
+// 1. SCPrefBrowseDomains (local configuration data)
+// 2. LocalDomainEnumRecords (locally-generated local-only PTR records -- equivalent to slElem->AuthRecs in uDNS.c)
+// 3. AutoBrowseDomains, which is populated by tracking add/rmv events in AutomaticBrowseDomainChange, the callback function for our mDNS_GetDomains call.
+// By creating and removing our own LocalDomainEnumRecords, we trigger AutomaticBrowseDomainChange callbacks just like domains learned from the network would.
+
+mDNSexport DNameListElem *AutoRegistrationDomains;     // Domains where we automatically register for empty-string registrations
+
 static DNameListElem *SCPrefBrowseDomains;                     // List of automatic browsing domains read from SCPreferences for "empty string" browsing
 static ARListElem    *LocalDomainEnumRecords;          // List of locally-generated PTR records to augment those we learn from the network
 mDNSexport DNameListElem *AutoBrowseDomains;           // List created from those local-only PTR records plus records we get from the network
 
-mDNSexport DNameListElem *AutoRegistrationDomains;     // Domains where we automatically register for empty-string registrations
-
 #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
 // initialization, setup/teardown functions
@@ -1145,6 +299,8 @@ mDNSlocal void abort_request(request_state *req)
                { LogMsg("abort_request: ERROR: Attempt to abort operation %p with req->terminate %p", req, req->terminate); return; }
        
        // First stop whatever mDNSCore operation we were doing
+       // If this is actually a shared connection operation, then its req->terminate function will scan
+       // the all_requests list and terminate any subbordinate operations sharing this file descriptor
        if (req->terminate) req->terminate(req);
 
        if (!dnssd_SocketValid(req->sd))
@@ -1155,7 +311,7 @@ mDNSlocal void abort_request(request_state *req)
                {
                if (req->errsd != req->sd) LogOperation("%3d: Removing FD and closing errsd %d", req->sd, req->errsd);
                else                       LogOperation("%3d: Removing FD", req->sd);
-               udsSupportRemoveFDFromEventLoop(req->sd);               // Note: This also closes file descriptor req->sd for us
+               udsSupportRemoveFDFromEventLoop(req->sd, req->platform_data);           // Note: This also closes file descriptor req->sd for us
                if (req->errsd != req->sd) { dnssd_close(req->errsd); req->errsd = req->sd; }
 
                while (req->replies)    // free pending replies
@@ -1201,11 +357,11 @@ mDNSlocal reply_state *create_reply(const reply_op_t op, const size_t datalen, r
        if (!reply) FatalError("ERROR: malloc");
        
        reply->next     = mDNSNULL;
-       reply->totallen = datalen + sizeof(ipc_msg_hdr);
+       reply->totallen = (mDNSu32)datalen + sizeof(ipc_msg_hdr);
        reply->nwriten  = 0;
 
        reply->mhdr->version        = VERSION;
-       reply->mhdr->datalen        = datalen;
+       reply->mhdr->datalen        = (mDNSu32)datalen;
        reply->mhdr->ipc_flags      = 0;
        reply->mhdr->op             = op;
        reply->mhdr->client_context = request->hdr.client_context;
@@ -1416,6 +572,58 @@ mDNSlocal mDNSBool AuthorizedDomain(const request_state * const request, const d
 }
 #endif
 
+// ***************************************************************************
+#if COMPILER_LIKES_PRAGMA_MARK
+#pragma mark -
+#pragma mark - external helpers
+#endif
+
+mDNSlocal void external_start_advertising_helper(service_instance *const instance)
+       {
+       AuthRecord *st = instance->subtypes;
+       ExtraResourceRecord *e;
+       int i;
+       
+       if (mDNSIPPortIsZero(instance->request->u.servicereg.port))
+               {
+               LogInfo("external_start_advertising_helper: Not registering service with port number zero");
+               return;
+               }
+
+       if (instance->external_advertise) LogMsg("external_start_advertising_helper: external_advertise already set!");
+       
+       for ( i = 0; i < instance->request->u.servicereg.num_subtypes; i++)
+               external_start_advertising_service(&st[i].resrec);
+       
+       external_start_advertising_service(&instance->srs.RR_PTR.resrec);
+       external_start_advertising_service(&instance->srs.RR_TXT.resrec);
+       
+       for (e = instance->srs.Extras; e; e = e->next)
+               external_start_advertising_service(&e->r.resrec);
+       
+       instance->external_advertise = mDNStrue;
+       }
+
+mDNSlocal void external_stop_advertising_helper(service_instance *const instance)
+       {
+       AuthRecord *st = instance->subtypes;
+       ExtraResourceRecord *e;
+       int i;
+       
+       if (!instance->external_advertise) return;
+       
+       for ( i = 0; i < instance->request->u.servicereg.num_subtypes; i++)
+               external_start_advertising_service(&st[i].resrec);
+       
+       external_stop_advertising_service(&instance->srs.RR_PTR.resrec);
+       external_stop_advertising_service(&instance->srs.RR_TXT.resrec);
+       
+       for (e = instance->srs.Extras; e; e = e->next)
+               external_stop_advertising_service(&e->r.resrec);
+       
+       instance->external_advertise = mDNSfalse;
+       }
+
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -1440,6 +648,8 @@ mDNSlocal void unlink_and_free_service_instance(service_instance *srv)
        {
        ExtraResourceRecord *e = srv->srs.Extras, *tmp;
 
+       external_stop_advertising_helper(srv);
+
        // clear pointers from parent struct
        if (srv->request)
                {
@@ -1474,16 +684,11 @@ mDNSexport int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs
        int count = 0;
        ResourceRecord *r = &srs->RR_SRV.resrec;
        AuthRecord *rr;
-       ServiceRecordSet *s;
 
        for (rr = m->ResourceRecords; rr; rr=rr->next)
                if (rr->resrec.rrtype == kDNSType_SRV && SameDomainName(rr->resrec.name, r->name) && !IdenticalSameNameRecord(&rr->resrec, r))
                        count++;
 
-       for (s = m->ServiceRegistrations; s; s = s->uDNS_next)
-               if (s->state != regState_Unregistered && SameDomainName(s->RR_SRV.resrec.name, r->name) && !IdenticalSameNameRecord(&s->RR_SRV.resrec, r))
-                       count++;
-
        verbosedebugf("%d peer registrations for %##s", count, r->name->c);
        return(count);
        }
@@ -1515,16 +720,13 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
        {
        mStatus err;
        mDNSBool SuppressError = mDNSfalse;
-       service_instance *instance = srs->ServiceContext;
+       service_instance *instance;
        reply_state         *rep;
-       char *fmt = "";
-       if (mDNS_LoggingEnabled)
-               fmt = (result == mStatus_NoError)      ? "%3d: DNSServiceRegister(%##s, %u) REGISTERED"    :
-                         (result == mStatus_MemFree)      ? "%3d: DNSServiceRegister(%##s, %u) DEREGISTERED"  :
-                         (result == mStatus_NameConflict) ? "%3d: DNSServiceRegister(%##s, %u) NAME CONFLICT" :
-                                                            "%3d: DNSServiceRegister(%##s, %u) %s %d";
        (void)m; // Unused
+
        if (!srs)      { LogMsg("regservice_callback: srs is NULL %d",                 result); return; }
+
+       instance = srs->ServiceContext;
        if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; }
 
        // don't send errors up to client for wide-area, empty-string registrations
@@ -1533,8 +735,18 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
                !instance->default_local)
                SuppressError = mDNStrue;
 
-       LogOperation(fmt, instance->request ? instance->request->sd : -99,
-               srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), SuppressError ? "suppressed error" : "CALLBACK", result);
+       if (mDNS_LoggingEnabled)
+               {
+               const char *const fmt =
+                       (result == mStatus_NoError)      ? "%s DNSServiceRegister(%##s, %u) REGISTERED"    :
+                       (result == mStatus_MemFree)      ? "%s DNSServiceRegister(%##s, %u) DEREGISTERED"  :
+                       (result == mStatus_NameConflict) ? "%s DNSServiceRegister(%##s, %u) NAME CONFLICT" :
+                                                          "%s DNSServiceRegister(%##s, %u) %s %d";
+               char prefix[16] = "---:";
+               if (instance->request) mDNS_snprintf(prefix, sizeof(prefix), "%3d:", instance->request->sd);
+               LogOperation(fmt, prefix, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port),
+                       SuppressError ? "suppressed error" : "CALLBACK", result);
+               }
 
        if (!instance->request && result != mStatus_MemFree) { LogMsg("regservice_callback: instance->request is NULL %d", result); return; }
 
@@ -1554,6 +766,8 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
                        LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", instance->request->sd, srs->RR_SRV.resrec.name->c);
                else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
 
+               if (instance->request->u.servicereg.InterfaceID == mDNSInterface_P2P || (!instance->request->u.servicereg.InterfaceID && SameDomainName(&instance->domain, &localdomain)))
+                       external_start_advertising_helper(instance);
                if (instance->request->u.servicereg.autoname && CountPeerRegistrations(m, srs) == 0)
                        RecordUpdatedNiceLabel(m, 0);   // Successfully got new name, tell user immediately
                }
@@ -1561,6 +775,7 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
                {
                if (instance->request && instance->renameonmemfree)
                        {
+                       external_stop_advertising_helper(instance);
                        instance->renameonmemfree = 0;
                        err = mDNS_RenameAndReregisterService(m, srs, &instance->request->u.servicereg.name);
                        if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err);
@@ -1573,6 +788,7 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
                {
                if (instance->request->u.servicereg.autorename)
                        {
+                       external_stop_advertising_helper(instance);
                        if (instance->request->u.servicereg.autoname && CountPeerRegistrations(m, srs) == 0)
                                {
                                // On conflict for an autoname service, rename and reregister *all* autoname services
@@ -1596,7 +812,7 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
                        unlink_and_free_service_instance(instance);
                        }
                }
-       else
+       else            // Not mStatus_NoError, mStatus_MemFree, or mStatus_NameConflict
                {
                if (!SuppressError) 
                        {
@@ -1613,7 +829,7 @@ mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
        if (!rr->RecordContext)         // parent struct already freed by termination callback
                {
                if (result == mStatus_NoError)
-                       LogMsg("Error: regrecord_callback: successful registration of orphaned record");
+                       LogMsg("Error: regrecord_callback: successful registration of orphaned record %s", ARDisplayString(m, rr));
                else
                        {
                        if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
@@ -1624,14 +840,27 @@ mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
                {
                registered_record_entry *re = rr->RecordContext;
                request_state *request = re->request;
-               int len = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + sizeof(DNSServiceErrorType);
-               reply_state *reply = create_reply(reg_record_reply_op, len, request);
-               reply->mhdr->client_context = re->regrec_client_context;
-               reply->rhdr->flags = dnssd_htonl(0);
-               reply->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, rr->resrec.InterfaceID));
-               reply->rhdr->error = dnssd_htonl(result);
-
-               LogOperation("%3d: DNSServiceRegisterRecord(%u) result %d", request->sd, request->hdr.reg_index, result);
+
+               if (mDNS_LoggingEnabled)
+                       {
+                       char *fmt = (result == mStatus_NoError)      ? "%3d: DNSServiceRegisterRecord(%u %s) REGISTERED"    :
+                                               (result == mStatus_MemFree)      ? "%3d: DNSServiceRegisterRecord(%u %s) DEREGISTERED"  :
+                                               (result == mStatus_NameConflict) ? "%3d: DNSServiceRegisterRecord(%u %s) NAME CONFLICT" :
+                                                                                                                  "%3d: DNSServiceRegisterRecord(%u %s) %d";
+                       LogOperation(fmt, request->sd, re->key, RRDisplayString(m, &rr->resrec), result);
+                       }
+
+               if (result != mStatus_MemFree)
+                       {
+                       int len = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + sizeof(DNSServiceErrorType);
+                       reply_state *reply = create_reply(reg_record_reply_op, len, request);
+                       reply->mhdr->client_context = re->regrec_client_context;
+                       reply->rhdr->flags = dnssd_htonl(0);
+                       reply->rhdr->ifi   = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(m, rr->resrec.InterfaceID));
+                       reply->rhdr->error = dnssd_htonl(result);
+                       append_reply(request, reply);
+                       }
+
                if (result)
                        {
                        // unlink from list, free memory
@@ -1642,13 +871,26 @@ mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
                        freeL("registered_record_entry AuthRecord regrecord_callback", re->rr);
                        freeL("registered_record_entry regrecord_callback", re);
                        }
-               append_reply(request, reply);
+               else
+                       {
+                       if (re->external_advertise) LogMsg("regrecord_callback: external_advertise already set!");
+                       if (re->origInterfaceID == mDNSInterface_P2P || (!re->origInterfaceID && IsLocalDomain(&rr->namestorage)))
+                               {
+                               external_start_advertising_service(&rr->resrec);
+                               re->external_advertise = mDNStrue;
+                               }
+                       }
                }
        }
 
 mDNSlocal void connection_termination(request_state *request)
        {
+       // When terminating a shared connection, we need to scan the all_requests list
+       // and terminate any subbordinate operations sharing this file descriptor
        request_state **req = &all_requests;
+       
+       LogOperation("%3d: DNSServiceCreateConnection STOP", request->sd);
+       
        while (*req)
                {
                if ((*req)->primary == request)
@@ -1668,8 +910,14 @@ mDNSlocal void connection_termination(request_state *request)
        while (request->u.reg_recs)
                {
                registered_record_entry *ptr = request->u.reg_recs;
+               LogOperation("%3d: DNSServiceRegisterRecord(%u %s) STOP", request->sd, ptr->key, RRDisplayString(&mDNSStorage, &ptr->rr->resrec));
                request->u.reg_recs = request->u.reg_recs->next;
                ptr->rr->RecordContext = NULL;
+               if (ptr->external_advertise)
+                       {
+                       ptr->external_advertise = mDNSfalse;
+                       external_stop_advertising_service(&ptr->rr->resrec);
+                       }
                mDNS_Deregister(&mDNSStorage, ptr->rr);         // Will free ptr->rr for us
                freeL("registered_record_entry/connection_termination", ptr);
                }
@@ -1705,22 +953,26 @@ mDNSlocal mStatus handle_regrecord_request(request_state *request)
                // allocate registration entry, link into list
                registered_record_entry *re = mallocL("registered_record_entry", sizeof(registered_record_entry));
                if (!re) FatalError("ERROR: malloc");
-               re->key = request->hdr.reg_index;
-               re->rr = rr;
-               re->request = request;
+               re->key                   = request->hdr.reg_index;
+               re->rr                    = rr;
                re->regrec_client_context = request->hdr.client_context;
-               rr->RecordContext = re;
-               rr->RecordCallback = regrecord_callback;
+               re->request               = request;
+               re->external_advertise    = mDNSfalse;
+               rr->RecordContext         = re;
+               rr->RecordCallback        = regrecord_callback;
+
                re->next = request->u.reg_recs;
                request->u.reg_recs = re;
-       
+
+               re->origInterfaceID = rr->resrec.InterfaceID;
+               if (rr->resrec.InterfaceID == mDNSInterface_P2P) rr->resrec.InterfaceID = mDNSInterface_Any;    
 #if 0
                if (!AuthorizedDomain(request, rr->resrec.name, AutoRegistrationDomains))       return (mStatus_NoError);
 #endif
                if (rr->resrec.rroriginalttl == 0)
                        rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
        
-               LogOperation("%3d: DNSServiceRegisterRecord(%u %s)", request->sd, request->hdr.reg_index, RRDisplayString(&mDNSStorage, &rr->resrec));
+               LogOperation("%3d: DNSServiceRegisterRecord(%u %s) START", request->sd, re->key, RRDisplayString(&mDNSStorage, &rr->resrec));
                err = mDNS_Register(&mDNSStorage, rr);
                }
        return(err);
@@ -1738,6 +990,8 @@ mDNSlocal void regservice_termination_callback(request_state *request)
                // only safe to free memory if registration is not valid, i.e. deregister fails (which invalidates p)
                LogOperation("%3d: DNSServiceRegister(%##s, %u) STOP",
                        request->sd, p->srs.RR_SRV.resrec.name->c, mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port));
+               
+               external_stop_advertising_helper(p);
 
                // Clear backpointer *before* calling mDNS_DeregisterService/unlink_and_free_service_instance
                // We don't need unlink_and_free_service_instance to cut its element from the list, because we're already advancing
@@ -1786,6 +1040,8 @@ mDNSlocal mStatus add_record_to_service(request_state *request, service_instance
        if (result) { freeL("ExtraResourceRecord/add_record_to_service", extra); return result; }
 
        extra->ClientID = request->hdr.reg_index;
+       if (instance->external_advertise && (instance->request->u.servicereg.InterfaceID == mDNSInterface_P2P || (!instance->request->u.servicereg.InterfaceID && SameDomainName(&instance->domain, &localdomain))))
+               external_start_advertising_service(&extra->r.resrec);
        return result;
        }
 
@@ -1822,21 +1078,37 @@ mDNSlocal mStatus handle_add_request(request_state *request)
        return(result);
        }
 
-mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
+mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd, mDNSu16 oldrdlen)
        {
+       mDNSBool external_advertise = (rr->UpdateContext) ? *((mDNSBool *)rr->UpdateContext) : mDNSfalse;
        (void)m; // Unused
+       
+       // There are three cases.
+       //
+       // 1. We have updated the primary TXT record of the service
+       // 2. We have updated the TXT record that was added to the service using DNSServiceAddRecord
+       // 3. We have updated the TXT record that was registered using DNSServiceRegisterRecord
+       //
+       // external_advertise is set if we have advertised at least once during the initial addition
+       // of the record in all of the three cases above. We should have checked for InterfaceID/LocalDomain
+       // checks during the first time and hence we don't do any checks here
+       if (external_advertise)
+               {
+               ResourceRecord ext = rr->resrec;
+               if (ext.rdlength == oldrdlen && mDNSPlatformMemSame(&ext.rdata->u, &oldrd->u, oldrdlen)) goto exit;
+               SetNewRData(&ext, oldrd, oldrdlen);
+               external_stop_advertising_service(&ext);
+               external_start_advertising_service(&rr->resrec);
+               }
+exit:
        if (oldrd != &rr->rdatastorage) freeL("RData/update_callback", oldrd);
        }
 
-mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, const char *rdata, mDNSu32 ttl)
+mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, const char *rdata, mDNSu32 ttl, const mDNSBool *const external_advertise)
        {
-       int rdsize;
-       RData *newrd;
        mStatus result;
-
-       if (rdlen > sizeof(RDataBody)) rdsize = rdlen;
-       else rdsize = sizeof(RDataBody);
-       newrd = mallocL("RData/update_record", sizeof(RData) - sizeof(RDataBody) + rdsize);
+       const int rdsize = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
+       RData *newrd = mallocL("RData/update_record", sizeof(RData) - sizeof(RDataBody) + rdsize);
        if (!newrd) FatalError("ERROR: malloc");
        newrd->MaxRDLength = (mDNSu16) rdsize;
        mDNSPlatformMemCopy(&newrd->u, rdata, rdlen);
@@ -1845,9 +1117,11 @@ mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, const char *rdata
        // since RFC 1035 specifies a TXT record as "One or more <character-string>s", not "Zero or more <character-string>s".
        // Since some legacy apps try to create zero-length TXT records, we'll silently correct it here.
        if (rr->resrec.rrtype == kDNSType_TXT && rdlen == 0) { rdlen = 1; newrd->u.txt.c[0] = 0; }
-
+       
+       if (external_advertise) rr->UpdateContext = (void *)external_advertise;
+       
        result = mDNS_Update(&mDNSStorage, rr, ttl, rdlen, newrd, update_callback);
-       if (result) { LogMsg("ERROR: mDNS_Update - %d", result); freeL("RData/update_record", newrd); }
+       if (result) { LogMsg("update_record: Error %d for %s", (int)result, ARDisplayString(&mDNSStorage, rr)); freeL("RData/update_record", newrd); }
        return result;
        }
 
@@ -1878,7 +1152,9 @@ mDNSlocal mStatus handle_update_request(request_state *request)
                        {
                        if (reptr->key == hdr->reg_index)
                                {
-                               result = update_record(reptr->rr, rdlen, rdata, ttl);
+                               result = update_record(reptr->rr, rdlen, rdata, ttl, &reptr->external_advertise);
+                               LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s)",
+                                       request->sd, reptr->rr->resrec.name->c, reptr->rr ? DNSTypeName(reptr->rr->resrec.rrtype) : "<NONE>");
                                goto end;
                                }
                        }
@@ -1915,7 +1191,7 @@ mDNSlocal mStatus handle_update_request(request_state *request)
                        }
 
                if (!rr) { result = mStatus_BadReferenceErr; goto end; }
-               result = update_record(rr, rdlen, rdata, ttl);
+               result = update_record(rr, rdlen, rdata, ttl, &i->external_advertise);
                if (result && i->default_local) goto end;
                else result = mStatus_NoError;  // suppress non-local default errors
                }
@@ -1940,14 +1216,20 @@ mDNSlocal mStatus remove_record(request_state *request)
        e = *ptr;
        *ptr = e->next; // unlink
 
-       LogOperation("%3d: DNSServiceRemoveRecord(%u %s)", request->sd, request->hdr.reg_index, RRDisplayString(&mDNSStorage, &e->rr->resrec));
+       LogOperation("%3d: DNSServiceRemoveRecord(%u %s)", request->sd, e->key, RRDisplayString(&mDNSStorage, &e->rr->resrec));
        e->rr->RecordContext = NULL;
-       err = mDNS_Deregister(&mDNSStorage, e->rr);
+       if (e->external_advertise)
+               {
+               external_stop_advertising_service(&e->rr->resrec);
+               e->external_advertise = mDNSfalse;
+               }
+       err = mDNS_Deregister(&mDNSStorage, e->rr);             // Will free e->rr for us; we're responsible for freeing e
        if (err)
                {
                LogMsg("ERROR: remove_record, mDNS_Deregister: %d", err);
                freeL("registered_record_entry AuthRecord remove_record", e->rr);
                }
+               
        freeL("registered_record_entry remove_record", e);
        return err;
        }
@@ -1962,7 +1244,9 @@ mDNSlocal mStatus remove_extra(const request_state *const request, service_insta
                if (ptr->ClientID == request->hdr.reg_index) // found match
                        {
                        *rrtype = ptr->r.resrec.rrtype;
-                       return mDNS_RemoveRecordFromService(&mDNSStorage, &serv->srs, ptr, FreeExtraRR, ptr);
+                       if (serv->external_advertise) external_stop_advertising_service(&ptr->r.resrec);
+                       err = mDNS_RemoveRecordFromService(&mDNSStorage, &serv->srs, ptr, FreeExtraRR, ptr);
+                       break;
                        }
                }
        return err;
@@ -2074,8 +1358,19 @@ mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
 mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain)
        {
        service_instance **ptr, *instance;
-       int instance_size;
+       const int extra_size = (request->u.servicereg.txtlen > sizeof(RDataBody)) ? (request->u.servicereg.txtlen - sizeof(RDataBody)) : 0;
+       const mDNSBool DomainIsLocal = SameDomainName(domain, &localdomain);
        mStatus result;
+       mDNSInterfaceID interfaceID = request->u.servicereg.InterfaceID;
+
+       if (interfaceID == mDNSInterface_P2P) interfaceID = mDNSInterface_Any;
+
+       // If the client specified an interface, but no domain, then we honor the specified interface for the "local" (mDNS)
+       // registration but for the wide-area registrations we don't (currently) have any concept of a wide-area unicast
+       // registrations scoped to a specific interface, so for the automatic domains we add we must *not* specify an interface.
+       // (Specifying an interface with an apparently wide-area domain (i.e. something other than "local")
+       // currently forces the registration to use mDNS multicast despite the apparently wide-area domain.)
+       if (request->u.servicereg.default_domain && !DomainIsLocal) interfaceID = mDNSInterface_Any;
 
        for (ptr = &request->u.servicereg.instances; *ptr; ptr = &(*ptr)->next)
                {
@@ -2087,26 +1382,28 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain
                        }
                }
 
-       // Special-case hack: We don't advertise SMB service in AutoTunnel domains, because AutoTunnel
-       // services have to support IPv6, and our SMB server does not
-       // <rdar://problem/5482322> BTMM: Don't advertise SMB with BTMM because it doesn't support IPv6
-       if (SameDomainName(&request->u.servicereg.type, (const domainname *) "\x4" "_smb" "\x4" "_tcp"))
+       if (mDNSStorage.KnownBugs & mDNS_KnownBug_LimitedIPv6)
                {
-               DomainAuthInfo *AuthInfo = GetAuthInfoForName(&mDNSStorage, domain);
-               if (AuthInfo && AuthInfo->AutoTunnel) return(kDNSServiceErr_Unsupported);
+               // Special-case hack: On Mac OS X 10.6.x and earlier we don't advertise SMB service in AutoTunnel domains,
+               // because AutoTunnel services have to support IPv6, and in Mac OS X 10.6.x the SMB server does not.
+               // <rdar://problem/5482322> BTMM: Don't advertise SMB with BTMM because it doesn't support IPv6
+               if (SameDomainName(&request->u.servicereg.type, (const domainname *) "\x4" "_smb" "\x4" "_tcp"))
+                       {
+                       DomainAuthInfo *AuthInfo = GetAuthInfoForName(&mDNSStorage, domain);
+                       if (AuthInfo && AuthInfo->AutoTunnel) return(kDNSServiceErr_Unsupported);
+                       }
                }
 
-       instance_size = sizeof(*instance);
-       if (request->u.servicereg.txtlen > sizeof(RDataBody)) instance_size += (request->u.servicereg.txtlen - sizeof(RDataBody));
-       instance = mallocL("service_instance", instance_size);
+       instance = mallocL("service_instance", sizeof(*instance) + extra_size);
        if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
 
-       instance->next            = mDNSNULL;
-       instance->request         = request;
-       instance->subtypes        = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string);
-       instance->renameonmemfree = 0;
-       instance->clientnotified  = mDNSfalse;
-       instance->default_local   = (request->u.servicereg.default_domain && SameDomainName(domain, &localdomain));
+       instance->next                                                  = mDNSNULL;
+       instance->request                                               = request;
+       instance->subtypes                                              = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string);
+       instance->renameonmemfree                               = 0;
+       instance->clientnotified                                = mDNSfalse;
+       instance->default_local                                 = (request->u.servicereg.default_domain && DomainIsLocal);
+       instance->external_advertise            = mDNSfalse;
        AssignDomainName(&instance->domain, domain);
 
        if (request->u.servicereg.num_subtypes && !instance->subtypes)
@@ -2118,7 +1415,7 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain
                request->u.servicereg.port,
                request->u.servicereg.txtdata, request->u.servicereg.txtlen,
                instance->subtypes, request->u.servicereg.num_subtypes,
-               request->u.servicereg.InterfaceID, regservice_callback, instance);
+               interfaceID, regservice_callback, instance);
 
        if (!result)
                {
@@ -2402,6 +1699,12 @@ mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d
                b->next = info->u.browser.browsers;
                info->u.browser.browsers = b;
                LogOperation("%3d: DNSServiceBrowse(%##s) START", info->sd, b->q.qname.c);
+               if (info->u.browser.interface_id == mDNSInterface_P2P || (!info->u.browser.interface_id && SameDomainName(&b->domain, &localdomain)))
+                       {
+                       domainname tmp;
+                       ConstructServiceName(&tmp, NULL, &info->u.browser.regtype, &b->domain);
+                       external_start_browsing_for_service(&mDNSStorage, &tmp, kDNSType_PTR);
+                       }
                }
        return err;
        }
@@ -2411,6 +1714,14 @@ mDNSlocal void browse_termination_callback(request_state *info)
        while (info->u.browser.browsers)
                {
                browser_t *ptr = info->u.browser.browsers;
+               
+               if (info->u.browser.interface_id == mDNSInterface_P2P || (!info->u.browser.interface_id && SameDomainName(&ptr->domain, &localdomain)))
+                       {
+                       domainname tmp;
+                       ConstructServiceName(&tmp, NULL, &info->u.browser.regtype, &ptr->domain);
+                       external_stop_browsing_for_service(&mDNSStorage, &tmp, kDNSType_PTR);
+                       }
+               
                info->u.browser.browsers = ptr->next;
                LogOperation("%3d: DNSServiceBrowse(%##s) STOP", info->sd, ptr->q.qname.c);
                mDNS_StopBrowse(&mDNSStorage, &ptr->q);  // no need to error-check result
@@ -2472,13 +1783,20 @@ mDNSlocal void FreeARElemCallback(mDNS *const m, AuthRecord *const rr, mStatus r
                // On shutdown, mDNS_Close automatically deregisters all records
                // Since in this case no one has called DeregisterLocalOnlyDomainEnumPTR to cut the record
                // from the LocalDomainEnumRecords list, we do this here before we free the memory.
+               // (This should actually no longer be necessary, now that we do the proper cleanup in
+               // udsserver_exit. To confirm this, we'll log an error message if we do find a record that
+               // hasn't been cut from the list yet. If these messages don't appear, we can delete this code.)
                ARListElem **ptr = &LocalDomainEnumRecords;
                while (*ptr && &(*ptr)->ar != rr) ptr = &(*ptr)->next;
-               if (*ptr) *ptr = (*ptr)->next;
+               if (*ptr) { *ptr = (*ptr)->next; LogMsg("FreeARElemCallback: Have to cut %s", ARDisplayString(m, rr)); }
                mDNSPlatformMemFree(rr->RecordContext);
                }
        }
 
+// RegisterLocalOnlyDomainEnumPTR and DeregisterLocalOnlyDomainEnumPTR largely duplicate code in
+// "FoundDomain" in uDNS.c for creating and destroying these special mDNSInterface_LocalOnly records.
+// We may want to turn the common code into a subroutine.
+
 mDNSlocal void RegisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, int type)
        {
        // allocate/register legacy and non-legacy _browse PTR record
@@ -2628,8 +1946,9 @@ mDNSexport void udsserver_handle_configchange(mDNS *const m)
                                        {
                                        ptr->renameonmemfree = 1;
                                        if (ptr->clientnotified) SendServiceRemovalNotification(&ptr->srs);
-                                       if (mDNS_DeregisterService(m, &ptr->srs)) // If service was deregistered already
-                                               regservice_callback(m, &ptr->srs, mStatus_MemFree); // we can re-register immediately
+                                       LogInfo("udsserver_handle_configchange: Calling deregister for Service %##s", ptr->srs.RR_PTR.resrec.name->c);
+                                       if (mDNS_DeregisterService_drt(m, &ptr->srs, mDNS_Dereg_rapid))
+                                               regservice_callback(m, &ptr->srs, mStatus_MemFree);     // If service deregistered already, we can re-register immediately
                                        }
                                }
 
@@ -2840,6 +2159,7 @@ mDNSlocal void resolve_termination_callback(request_state *request)
        LogOperation("%3d: DNSServiceResolve(%##s) STOP", request->sd, request->u.resolve.qtxt.qname.c);
        mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qtxt);
        mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
+       if (request->u.resolve.external_advertise) external_stop_resolving_service(&request->u.resolve.qsrv.qname);
        }
 
 mDNSlocal mStatus handle_resolve_request(request_state *request)
@@ -2851,7 +2171,13 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
        // extract the data from the message
        DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
        mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
-       mDNSInterfaceID InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+       mDNSInterfaceID InterfaceID;
+       mDNSBool wasP2P = (interfaceIndex == kDNSServiceInterfaceIndexP2P);
+       
+       
+       if (wasP2P) interfaceIndex = kDNSServiceInterfaceIndexAny;
+       
+       InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
        if (interfaceIndex && !InterfaceID)
                { LogMsg("ERROR: handle_resolve_request bad interfaceIndex %d", interfaceIndex); return(mStatus_BadParamErr); }
 
@@ -2889,11 +2215,14 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
        request->u.resolve.qtxt.ExpectUnique     = mDNStrue;
        request->u.resolve.qtxt.ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
        request->u.resolve.qtxt.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+       request->u.resolve.qtxt.SuppressUnusable = mDNSfalse;
        request->u.resolve.qtxt.QuestionCallback = resolve_result_callback;
        request->u.resolve.qtxt.QuestionContext  = request;
 
        request->u.resolve.ReportTime            = NonZeroTime(mDNS_TimeNow(&mDNSStorage) + 130 * mDNSPlatformOneSecond);
 
+       request->u.resolve.external_advertise    = mDNSfalse;
+
 #if 0
        if (!AuthorizedDomain(request, &fqdn, AutoBrowseDomains))       return(mStatus_NoError);
 #endif
@@ -2905,7 +2234,13 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
                {
                err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qtxt);
                if (err) mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
-               else request->terminate = resolve_termination_callback;
+               else
+                       {
+                       request->terminate = resolve_termination_callback;
+                       // If the user explicitly passed in P2P, we don't restrict the domain in which we resolve.
+                       if (wasP2P || (!InterfaceID && IsLocalDomain(&fqdn)))
+                               { request->u.resolve.external_advertise    = mDNStrue; external_start_resolving_service(&fqdn);}
+                       }
                }
 
        return(err);
@@ -2933,21 +2268,19 @@ mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question,
        (void)m; // Unused
 
 #if APPLE_OSX_mDNSResponder
-       if (question == &req->u.queryrecord.q2)
+       if (question == &req->u.queryrecord.q2 && question->qtype != req->u.queryrecord.q.qtype && !SameDomainName(&question->qname, &req->u.queryrecord.q.qname))
                {
                mDNS_StopQuery(&mDNSStorage, question);
+               question->QuestionCallback = mDNSNULL;
                // If we got a non-negative answer for our "local SOA" test query, start an additional parallel unicast query
-               if (answer->RecordType == kDNSRecordTypePacketNegative ||
-                       (question->qtype == req->u.queryrecord.q.qtype && SameDomainName(&question->qname, &req->u.queryrecord.q.qname)))
-                       question->QuestionCallback = mDNSNULL;
-               else
+               if (answer->RecordType != kDNSRecordTypePacketNegative)
                        {
                        *question              = req->u.queryrecord.q;
                        question->InterfaceID  = mDNSInterface_Unicast;
                        question->ExpectUnique = mDNStrue;
+                       LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast", req->sd, question->qname.c, DNSTypeName(question->qtype));
                        mStatus err = mDNS_StartQuery(&mDNSStorage, question);
-                       if (!err) LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast", req->sd, question->qname.c, DNSTypeName(question->qtype));
-                       else LogMsg("%3d: ERROR: queryrecord_result_callback %##s %s mDNS_StartQuery: %d", req->sd, question->qname.c, DNSTypeName(question->qtype), (int)err);
+                       if (err) LogMsg("%3d: ERROR: queryrecord_result_callback %##s %s mDNS_StartQuery: %d", req->sd, question->qname.c, DNSTypeName(question->qtype), (int)err);
                        }
                return;
                }
@@ -2999,6 +2332,77 @@ mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question,
        put_uint32(AddRecord ? answer->rroriginalttl : 0, &data);
 
        append_reply(req, rep);
+#if APPLE_OSX_mDNSResponder
+#if ! NO_WCF
+       CHECK_WCF_FUNCTION(WCFIsServerRunning)
+               {
+               struct xucred x;
+               socklen_t xucredlen = sizeof(x);
+       
+               if (WCFIsServerRunning((WCFConnection *)m->WCF) && answer->rdlength != 0)
+                       {
+                       if (getsockopt(req->sd, 0, LOCAL_PEERCRED, &x, &xucredlen) >= 0 &&
+                               (x.cr_version == XUCRED_VERSION))
+                               {
+                               struct sockaddr_storage addr;
+                               const RDataBody2 *const rdb = (RDataBody2 *)answer->rdata->u.data;
+                               addr.ss_len = 0;
+                               if (answer->rrtype == kDNSType_A || answer->rrtype == kDNSType_AAAA)
+                                       {
+                                       if (answer->rrtype == kDNSType_A)
+                                               {
+                                               struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
+                                               sin->sin_port = 0;
+                                               if (!putRData(mDNSNULL, (mDNSu8 *)&sin->sin_addr, (mDNSu8 *)(&sin->sin_addr + sizeof(rdb->ipv4)), answer))
+                                                       LogMsg("queryrecord_result_callback: WCF AF_INET putRData failed");
+                                               else
+                                                       {
+                                                       addr.ss_len = sizeof (struct sockaddr_in);
+                                                       addr.ss_family = AF_INET;
+                                                       }
+                                               }
+                                       else if (answer->rrtype == kDNSType_AAAA)
+                                               {
+                                               struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr;
+                                               sin6->sin6_port = 0;
+                                               if (!putRData(mDNSNULL, (mDNSu8 *)&sin6->sin6_addr, (mDNSu8 *)(&sin6->sin6_addr + sizeof(rdb->ipv6)), answer))
+                                                       LogMsg("queryrecord_result_callback: WCF AF_INET6 putRData failed");
+                                               else
+                                                       {
+                                                       addr.ss_len = sizeof (struct sockaddr_in6);
+                                                       addr.ss_family = AF_INET6;
+                                                       }
+                                               }
+                                       if (addr.ss_len)
+                                               {       
+                                               debugf("queryrecord_result_callback: Name %s, uid %u, addr length %d", name, x.cr_uid, addr.ss_len);
+                                               CHECK_WCF_FUNCTION((WCFConnection *)WCFNameResolvesToAddr)
+                                                       {
+                                                       WCFNameResolvesToAddr(m->WCF, name, (struct sockaddr *)&addr, x.cr_uid);
+                                                       }
+                                               }
+                                       }
+                               else if (answer->rrtype == kDNSType_CNAME)
+                                       {
+                                       domainname cname;
+                                       char cname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+                                       if (!putRData(mDNSNULL, cname.c, (mDNSu8 *)(cname.c + MAX_DOMAIN_NAME), answer))
+                                                       LogMsg("queryrecord_result_callback: WCF CNAME putRData failed");
+                                       else
+                                               {
+                                               ConvertDomainNameToCString(&cname, cname_cstr);
+                                               CHECK_WCF_FUNCTION((WCFConnection *)WCFNameResolvesToAddr)
+                                                       {
+                                                       WCFNameResolvesToName(m->WCF, name, cname_cstr, x.cr_uid);
+                                                       }
+                                               }
+                                       }
+                               }
+                       else my_perror("queryrecord_result_callback: ERROR: getsockopt LOCAL_PEERCRED");
+                       }
+               }
+#endif
+#endif
        }
 
 mDNSlocal void queryrecord_termination_callback(request_state *request)
@@ -3006,6 +2410,8 @@ mDNSlocal void queryrecord_termination_callback(request_state *request)
        LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP",
                request->sd, request->u.queryrecord.q.qname.c, DNSTypeName(request->u.queryrecord.q.qtype));
        mDNS_StopQuery(&mDNSStorage, &request->u.queryrecord.q);  // no need to error check
+       if (request->u.queryrecord.q.InterfaceID == mDNSInterface_P2P || (!request->u.queryrecord.q.InterfaceID && SameDomainName((const domainname *)LastLabel(&request->u.queryrecord.q.qname), &localdomain)))
+               external_stop_browsing_for_service(&mDNSStorage, &request->u.queryrecord.q.qname, request->u.queryrecord.q.qtype);
        if (request->u.queryrecord.q2.QuestionCallback) mDNS_StopQuery(&mDNSStorage, &request->u.queryrecord.q2);
        }
 
@@ -3042,13 +2448,19 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request)
        q->ExpectUnique     = mDNSfalse;
        q->ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
        q->ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+       q->SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable) != 0;
        q->QuestionCallback = queryrecord_result_callback;
        q->QuestionContext  = request;
 
-       LogOperation("%3d: DNSServiceQueryRecord(%##s, %s, %X) START", request->sd, q->qname.c, DNSTypeName(q->qtype), flags);
+       LogOperation("%3d: DNSServiceQueryRecord(%X, %d, %##s, %s) START", request->sd, flags, interfaceIndex, q->qname.c, DNSTypeName(q->qtype));
        err = mDNS_StartQuery(&mDNSStorage, q);
        if (err) LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q->qname.c, DNSTypeName(q->qtype), (int)err);
-       else request->terminate = queryrecord_termination_callback;
+       else 
+               {
+               request->terminate = queryrecord_termination_callback;
+               if (q->InterfaceID == mDNSInterface_P2P || (!q->InterfaceID && SameDomainName((const domainname *)LastLabel(&q->qname), &localdomain)))
+                       external_start_browsing_for_service(&mDNSStorage, &q->qname, q->qtype);
+               }
 
 #if APPLE_OSX_mDNSResponder
        // Workaround for networks using Microsoft Active Directory using "local" as a private internal top-level domain
@@ -3072,6 +2484,8 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request)
                        // then that's a hint that it's worth doing a unicast query. Otherwise, we first check to see if the
                        // site's DNS server claims there's an SOA record for "local", and if so, that's also a hint that queries
                        // for names in the "local" domain will be safely answered privately before they hit the root name servers.
+                       // Note that in the "my-small-company.local" example above there will typically be an SOA record for
+                       // "my-small-company.local" but *not* for "local", which is why the "local SOA" check would fail in that case.
                        if (labels == 2 && !SameDomainName(&q->qname, &ActiveDirectoryPrimaryDomain))
                                {
                                AssignDomainName(&q2->qname, &localdomain);
@@ -3080,9 +2494,9 @@ mDNSlocal mStatus handle_queryrecord_request(request_state *request)
                                q2->ForceMCast     = mDNSfalse;
                                q2->ReturnIntermed = mDNStrue;
                                }
+                       LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast", request->sd, q2->qname.c, DNSTypeName(q2->qtype));
                        err = mDNS_StartQuery(&mDNSStorage, q2);
-                       if (!err) LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast", request->sd, q2->qname.c, DNSTypeName(q2->qtype));
-                       else LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q2->qname.c, DNSTypeName(q2->qtype), (int)err);
+                       if (err) LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q2->qname.c, DNSTypeName(q2->qtype), (int)err);
                        }
 #endif // APPLE_OSX_mDNSResponder
 
@@ -3251,7 +2665,7 @@ typedef packedstruct
 
 mDNSlocal void handle_getproperty_request(request_state *request)
        {
-       const mStatus BadParamErr = dnssd_htonl(mStatus_BadParamErr);
+       const mStatus BadParamErr = dnssd_htonl((mDNSu32)mStatus_BadParamErr);
        char prop[256];
        if (get_string(&request->msgptr, request->msgend, prop, sizeof(prop)) >= 0)
                {
@@ -3336,7 +2750,7 @@ mDNSlocal mStatus handle_port_mapping_request(request_state *request)
        DNSServiceFlags flags          = get_flags(&request->msgptr, request->msgend);
        mDNSu32         interfaceIndex = get_uint32(&request->msgptr, request->msgend);
        mDNSInterfaceID InterfaceID    = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
-       mDNSu8          protocol       = get_uint32(&request->msgptr, request->msgend);
+       mDNSu8          protocol       = (mDNSu8)get_uint32(&request->msgptr, request->msgend);
        (void)flags; // Unused
        if (interfaceIndex && !InterfaceID) return(mStatus_BadParamErr);
        if (request->msgptr + 8 > request->msgend) request->msgptr = NULL;
@@ -3386,6 +2800,8 @@ mDNSlocal mStatus handle_port_mapping_request(request_state *request)
 
 mDNSlocal void addrinfo_termination_callback(request_state *request)
        {
+       LogOperation("%3d: DNSServiceGetAddrInfo(%##s) STOP", request->sd, request->u.addrinfo.q4.qname.c);
+
        if (request->u.addrinfo.q4.QuestionContext)
                {
                mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q4);
@@ -3405,7 +2821,7 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request)
        domainname d;
        mStatus err = 0;
 
-       DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
+       DNSServiceFlags flags  = get_flags(&request->msgptr, request->msgend);
        mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
 
        mDNSPlatformMemZero(&request->u.addrinfo, sizeof(request->u.addrinfo));
@@ -3429,39 +2845,25 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request)
 
        if (!request->u.addrinfo.protocol)
                {
-               NetworkInterfaceInfo *i;
-               if (IsLocalDomain(&d))
-                       {
-                       for (i = mDNSStorage.HostInterfaces; i; i = i->next)
-                               {
-                               if      ((i->ip.type == mDNSAddrType_IPv4) && !mDNSIPv4AddressIsZero(i->ip.ip.v4)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv4;
-                               else if ((i->ip.type == mDNSAddrType_IPv6) && !mDNSIPv6AddressIsZero(i->ip.ip.v6)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv6;
-                               }
-                       }
-               else
-                       {
-                       for (i = mDNSStorage.HostInterfaces; i; i = i->next)
-                               {
-                               if      ((i->ip.type == mDNSAddrType_IPv4) && !mDNSv4AddressIsLinkLocal(&i->ip.ip.v4)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv4;
-                               else if ((i->ip.type == mDNSAddrType_IPv6) && !mDNSv4AddressIsLinkLocal(&i->ip.ip.v6)) request->u.addrinfo.protocol |= kDNSServiceProtocol_IPv6;
-                               }
-                       }
+               flags |= kDNSServiceFlagsSuppressUnusable;
+               request->u.addrinfo.protocol = (kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6);
                }
 
+       request->u.addrinfo.q4.InterfaceID      = request->u.addrinfo.q6.InterfaceID      = request->u.addrinfo.interface_id;
+       request->u.addrinfo.q4.Target           = request->u.addrinfo.q6.Target           = zeroAddr;
+       request->u.addrinfo.q4.qname            = request->u.addrinfo.q6.qname            = d;
+       request->u.addrinfo.q4.qclass           = request->u.addrinfo.q6.qclass           = kDNSServiceClass_IN;
+       request->u.addrinfo.q4.LongLived        = request->u.addrinfo.q6.LongLived        = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
+       request->u.addrinfo.q4.ExpectUnique     = request->u.addrinfo.q6.ExpectUnique     = mDNSfalse;
+       request->u.addrinfo.q4.ForceMCast       = request->u.addrinfo.q6.ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
+       request->u.addrinfo.q4.ReturnIntermed   = request->u.addrinfo.q6.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+       request->u.addrinfo.q4.SuppressUnusable = request->u.addrinfo.q6.SuppressUnusable = (flags & kDNSServiceFlagsSuppressUnusable   ) != 0;
+
        if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4)
                {
-               request->u.addrinfo.q4.InterfaceID      = request->u.addrinfo.interface_id;
-               request->u.addrinfo.q4.Target           = zeroAddr;
-               request->u.addrinfo.q4.qname            = d;
                request->u.addrinfo.q4.qtype            = kDNSServiceType_A;
-               request->u.addrinfo.q4.qclass           = kDNSServiceClass_IN;
-               request->u.addrinfo.q4.LongLived        = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
-               request->u.addrinfo.q4.ExpectUnique     = mDNSfalse;
-               request->u.addrinfo.q4.ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
-               request->u.addrinfo.q4.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
                request->u.addrinfo.q4.QuestionCallback = queryrecord_result_callback;
                request->u.addrinfo.q4.QuestionContext  = request;
-
                err = mDNS_StartQuery(&mDNSStorage, &request->u.addrinfo.q4);
                if (err != mStatus_NoError)
                        {
@@ -3472,29 +2874,25 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request)
 
        if (!err && (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv6))
                {
-               request->u.addrinfo.q6.InterfaceID      = request->u.addrinfo.interface_id;
-               request->u.addrinfo.q6.Target           = zeroAddr;
-               request->u.addrinfo.q6.qname            = d;
                request->u.addrinfo.q6.qtype            = kDNSServiceType_AAAA;
-               request->u.addrinfo.q6.qclass           = kDNSServiceClass_IN;
-               request->u.addrinfo.q6.LongLived        = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
-               request->u.addrinfo.q6.ExpectUnique     = mDNSfalse;
-               request->u.addrinfo.q6.ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
-               request->u.addrinfo.q6.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
                request->u.addrinfo.q6.QuestionCallback = queryrecord_result_callback;
                request->u.addrinfo.q6.QuestionContext  = request;
-
                err = mDNS_StartQuery(&mDNSStorage, &request->u.addrinfo.q6);
                if (err != mStatus_NoError)
                        {
                        LogMsg("ERROR: mDNS_StartQuery: %d", (int)err);
                        request->u.addrinfo.q6.QuestionContext = mDNSNULL;
-                       if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4)    // If we started a query for IPv4,
-                               addrinfo_termination_callback(request);                                         // we need to cancel it
+                       if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4)
+                               {
+                               // If we started a query for IPv4, we need to cancel it
+                               mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q4);
+                               request->u.addrinfo.q4.QuestionContext = mDNSNULL;
+                               }
                        }
                }
 
-       LogOperation("%3d: DNSServiceGetAddrInfo(%##s) START", request->sd, d.c);
+       LogOperation("%3d: DNSServiceGetAddrInfo(%X, %d, %d, %##s) START",
+               request->sd, flags, interfaceIndex, request->u.addrinfo.protocol, d.c);
 
        if (!err) request->terminate = addrinfo_termination_callback;
 
@@ -3527,7 +2925,7 @@ mDNSlocal void read_msg(request_state *req)
        if (req->ts == t_complete)      // this must be death or something is wrong
                {
                char buf[4];    // dummy for death notification
-               int nread = recv(req->sd, buf, 4, 0);
+               int nread = udsSupportReadFD(req->sd, buf, 4, 0, req->platform_data);
                if (!nread) { req->ts = t_terminated; return; }
                if (nread < 0) goto rerror;
                LogMsg("%3d: ERROR: read data from a completed request", req->sd);
@@ -3541,7 +2939,7 @@ mDNSlocal void read_msg(request_state *req)
        if (req->hdr_bytes < sizeof(ipc_msg_hdr))
                {
                mDNSu32 nleft = sizeof(ipc_msg_hdr) - req->hdr_bytes;
-               int nread = recv(req->sd, (char *)&req->hdr + req->hdr_bytes, nleft, 0);
+               int nread = udsSupportReadFD(req->sd, (char *)&req->hdr + req->hdr_bytes, nleft, 0, req->platform_data);
                if (nread == 0) { req->ts = t_terminated; return; }
                if (nread < 0) goto rerror;
                req->hdr_bytes += nread;
@@ -3559,7 +2957,7 @@ mDNSlocal void read_msg(request_state *req)
                        // with 64kB of rdata. Adding 1009 byte for a maximal domain name, plus a safety margin
                        // for other overhead, this means any message above 70kB is definitely bogus.
                        if (req->hdr.datalen > 70000)
-                               { LogMsg("%3d: ERROR: read_msg - hdr.datalen %lu (%X) > 70000", req->sd, req->hdr.datalen, req->hdr.datalen); req->ts = t_error; return; }
+                               { LogMsg("%3d: ERROR: read_msg: hdr.datalen %u (0x%X) > 70000", req->sd, req->hdr.datalen, req->hdr.datalen); req->ts = t_error; return; }
                        req->msgbuf = mallocL("request_state msgbuf", req->hdr.datalen + MSG_PAD_BYTES);
                        if (!req->msgbuf) { my_perror("ERROR: malloc"); req->ts = t_error; return; }
                        req->msgptr = req->msgbuf;
@@ -3590,7 +2988,7 @@ mDNSlocal void read_msg(request_state *req)
                msg.msg_flags      = 0;
                nread = recvmsg(req->sd, &msg, 0);
 #else
-               nread = recv(req->sd, (char *)req->msgbuf + req->data_bytes, nleft, 0);
+               nread = udsSupportReadFD(req->sd, (char *)req->msgbuf + req->data_bytes, nleft, 0, req->platform_data);
 #endif
                if (nread == 0) { req->ts = t_terminated; return; }
                if (nread < 0) goto rerror;
@@ -3643,7 +3041,7 @@ mDNSlocal void read_msg(request_state *req)
                        dnssd_sockaddr_t cliaddr;
 #if defined(USE_TCP_LOOPBACK)
                        mDNSOpaque16 port;
-                       int opt = 1;
+                       u_long opt = 1;
                        port.b[0] = req->msgptr[0];
                        port.b[1] = req->msgptr[1];
                        req->msgptr += 2;
@@ -3685,7 +3083,9 @@ mDNSlocal void read_msg(request_state *req)
                                return;
                                }
        
+#if !defined(USE_TCP_LOOPBACK)
 got_errfd:
+#endif
                        LogOperation("%3d: Error socket %d created %08X %08X", req->sd, req->errsd, req->hdr.client_context.u32[1], req->hdr.client_context.u32[0]);
 #if defined(_WIN32)
                        if (ioctlsocket(req->errsd, FIONBIO, &opt) != 0)
@@ -3721,9 +3121,6 @@ mDNSlocal void request_callback(int fd, short filter, void *info)
        {
        mStatus err = 0;
        request_state *req = info;
-#if defined(_WIN32)
-       u_long opt = 1;
-#endif
        mDNSs32 min_size = sizeof(DNSServiceFlags);
        (void)fd; // Unused
        (void)filter; // Unused
@@ -3854,7 +3251,7 @@ mDNSlocal void connect_callback(int fd, short filter, void *info)
        dnssd_socklen_t len = (dnssd_socklen_t) sizeof(cliaddr);
        dnssd_sock_t sd = accept(fd, (struct sockaddr*) &cliaddr, &len);
 #if defined(SO_NOSIGPIPE) || defined(_WIN32)
-       const unsigned long optval = 1;
+       unsigned long optval = 1;
 #endif
 
        (void)filter; // Unused
@@ -3896,7 +3293,7 @@ mDNSlocal void connect_callback(int fd, short filter, void *info)
                debugf("LOCAL_PEERCRED %d %u %u %d", xucredlen, x.cr_version, x.cr_uid, x.cr_ngroups);
 #endif // APPLE_OSX_mDNSResponder
                LogOperation("%3d: Adding FD for uid %u", request->sd, request->uid);
-               udsSupportAddFDToEventLoop(sd, request_callback, request);
+               udsSupportAddFDToEventLoop(sd, request_callback, request, &request->platform_data);
                }
        }
 
@@ -3929,7 +3326,7 @@ mDNSlocal mDNSBool uds_socket_setup(dnssd_sock_t skt)
                return mDNSfalse;
                }
 
-       if (mStatus_NoError != udsSupportAddFDToEventLoop(skt, connect_callback, (void *) NULL))
+       if (mStatus_NoError != udsSupportAddFDToEventLoop(skt, connect_callback, (void *) NULL, (void **) NULL))
                {
                my_perror("ERROR: could not add listen socket to event loop");
                return mDNSfalse;
@@ -3944,9 +3341,6 @@ mDNSexport int udsserver_init(dnssd_sock_t skts[], mDNSu32 count)
        dnssd_sockaddr_t laddr;
        int ret;
        mDNSu32 i = 0;
-#if defined(_WIN32)
-       u_long opt = 1;
-#endif
 
        LogInfo("udsserver_init");
 
@@ -4038,8 +3432,8 @@ mDNSexport int udsserver_init(dnssd_sock_t skts[], mDNSu32 count)
 #endif
 
        // We start a "LocalOnly" query looking for Automatic Browse Domain records.
-       // When Domain Enumeration in uDNS.c finds an "lb" record from the network, it creates a
-       // "LocalOnly" record, which results in our AutomaticBrowseDomainChange callback being invoked
+       // When Domain Enumeration in uDNS.c finds an "lb" record from the network, its "FoundDomain" routine
+       // creates a "LocalOnly" record, which results in our AutomaticBrowseDomainChange callback being invoked
        mDNS_GetDomains(&mDNSStorage, &mDNSStorage.AutomaticBrowseDomainQ, mDNS_DomainTypeBrowseAutomatic,
                mDNSNULL, mDNSInterface_LocalOnly, AutomaticBrowseDomainChange, mDNSNULL);
 
@@ -4059,6 +3453,18 @@ error:
 
 mDNSexport int udsserver_exit(void)
        {
+       // Cancel all outstanding client requests
+       while (all_requests) AbortUnlinkAndFree(all_requests);
+
+       // Clean up any special mDNSInterface_LocalOnly records we created, both the entries for "local" we
+       // created in udsserver_init, and others we created as a result of reading local configuration data
+       while (LocalDomainEnumRecords)
+               {
+               ARListElem *rem = LocalDomainEnumRecords;
+               LocalDomainEnumRecords = LocalDomainEnumRecords->next;
+               mDNS_Deregister(&mDNSStorage, &rem->ar);
+               }
+
        // If the launching environment created no listening socket,
        // that means we created it ourselves, so we should clean it up on exit
        if (dnssd_SocketValid(listenfd))
@@ -4078,39 +3484,53 @@ mDNSexport int udsserver_exit(void)
        return 0;
        }
 
-mDNSlocal void LogClientInfo(mDNS *const m, request_state *req)
+mDNSlocal void LogClientInfo(mDNS *const m, const request_state *req)
        {
+       char prefix[16];
+       if (req->primary) mDNS_snprintf(prefix, sizeof(prefix), " -> ");
+       else mDNS_snprintf(prefix, sizeof(prefix), "%3d:", req->sd);
+
+       usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
+
        if (!req->terminate)
-               LogMsgNoIdent("%3d: No operation yet on this socket", req->sd);
+               LogMsgNoIdent("%s No operation yet on this socket", prefix);
        else if (req->terminate == connection_termination)
                {
-               registered_record_entry *p;
-               LogMsgNoIdent("%3d: DNSServiceCreateConnection", req->sd);
+               int num_records = 0, num_ops = 0;
+               const registered_record_entry *p;
+               const request_state *r;
+               for (p = req->u.reg_recs; p; p=p->next) num_records++;
+               for (r = req->next; r; r=r->next) if (r->primary == req) num_ops++;
+               LogMsgNoIdent("%s DNSServiceCreateConnection: %d registered record%s, %d kDNSServiceFlagsShareConnection operation%s", prefix,
+                       num_records, num_records != 1 ? "s" : "",
+                       num_ops,     num_ops     != 1 ? "s" : "");
                for (p = req->u.reg_recs; p; p=p->next)
                        LogMsgNoIdent(" ->  DNSServiceRegisterRecord %3d %s", p->key, ARDisplayString(m, p->rr));
+               for (r = req->next; r; r=r->next) if (r->primary == req) LogClientInfo(m, r);
                }
        else if (req->terminate == regservice_termination_callback)
                {
                service_instance *ptr;
                for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
-                       LogMsgNoIdent("%3d: DNSServiceRegister         %##s %u/%u",
-                               req->sd, ptr->srs.RR_SRV.resrec.name->c, mDNSVal16(req->u.servicereg.port), SRS_PORT(&ptr->srs));
+                       LogMsgNoIdent("%s DNSServiceRegister         %##s %u/%u",
+                               (ptr == req->u.servicereg.instances) ? prefix : "    ",
+                               ptr->srs.RR_SRV.resrec.name->c, mDNSVal16(req->u.servicereg.port), SRS_PORT(&ptr->srs));
                }
        else if (req->terminate == browse_termination_callback)
                {
                browser_t *blist;
                for (blist = req->u.browser.browsers; blist; blist = blist->next)
-                       LogMsgNoIdent("%3d: DNSServiceBrowse           %##s", req->sd, blist->q.qname.c);
+                       LogMsgNoIdent("%s DNSServiceBrowse           %##s", (blist == req->u.browser.browsers) ? prefix : "    ", blist->q.qname.c);
                }
        else if (req->terminate == resolve_termination_callback)
-               LogMsgNoIdent("%3d: DNSServiceResolve          %##s", req->sd, req->u.resolve.qsrv.qname.c);
+               LogMsgNoIdent("%s DNSServiceResolve          %##s", prefix, req->u.resolve.qsrv.qname.c);
        else if (req->terminate == queryrecord_termination_callback)
-               LogMsgNoIdent("%3d: DNSServiceQueryRecord      %##s (%s)", req->sd, req->u.queryrecord.q.qname.c, DNSTypeName(req->u.queryrecord.q.qtype));
+               LogMsgNoIdent("%s DNSServiceQueryRecord      %##s (%s)", prefix, req->u.queryrecord.q.qname.c, DNSTypeName(req->u.queryrecord.q.qtype));
        else if (req->terminate == enum_termination_callback)
-               LogMsgNoIdent("%3d: DNSServiceEnumerateDomains %##s", req->sd, req->u.enumeration.q_all.qname.c);
+               LogMsgNoIdent("%s DNSServiceEnumerateDomains %##s", prefix, req->u.enumeration.q_all.qname.c);
        else if (req->terminate == port_mapping_termination_callback)
-               LogMsgNoIdent("%3d: DNSServiceNATPortMapping   %.4a %s%s Int %d Req %d Ext %d Req TTL %d Granted TTL %d",
-                       req->sd,
+               LogMsgNoIdent("%s DNSServiceNATPortMapping   %.4a %s%s Int %d Req %d Ext %d Req TTL %d Granted TTL %d",
+                       prefix,
                        &req->u.pm.NATinfo.ExternalAddress,
                        req->u.pm.NATinfo.Protocol & NATOp_MapTCP ? "TCP" : "   ",
                        req->u.pm.NATinfo.Protocol & NATOp_MapUDP ? "UDP" : "   ",
@@ -4120,35 +3540,35 @@ mDNSlocal void LogClientInfo(mDNS *const m, request_state *req)
                        req->u.pm.NATinfo.NATLease,
                        req->u.pm.NATinfo.Lifetime);
        else if (req->terminate == addrinfo_termination_callback)
-               LogMsgNoIdent("%3d: DNSServiceGetAddrInfo      %s%s %##s", req->sd,
+               LogMsgNoIdent("%s DNSServiceGetAddrInfo      %s%s %##s", prefix,
                        req->u.addrinfo.protocol & kDNSServiceProtocol_IPv4 ? "v4" : "  ",
                        req->u.addrinfo.protocol & kDNSServiceProtocol_IPv6 ? "v6" : "  ",
                        req->u.addrinfo.q4.qname.c);
        else
-               LogMsgNoIdent("%3d: Unrecognized operation %p", req->sd, req->terminate);
+               LogMsgNoIdent("%s Unrecognized operation %p", prefix, req->terminate);
        }
 
 mDNSlocal void LogAuthRecords(mDNS *const m, const mDNSs32 now, AuthRecord *ResourceRecords, int *proxy)
        {
-       if (!ResourceRecords) LogMsgNoIdent("<None>");
-       else
+       mDNSBool showheader = mDNStrue;
+       const AuthRecord *ar;
+       OwnerOptData owner = zeroOwner;
+       for (ar = ResourceRecords; ar; ar=ar->next)
                {
-               const AuthRecord *ar;
-               mDNSEthAddr owner = zeroEthAddr;
-               LogMsgNoIdent("    Int    Next  Expire   State");
-               for (ar = ResourceRecords; ar; ar=ar->next)
+               const char *const ifname = InterfaceNameForID(m, ar->resrec.InterfaceID);
+               if ((ar->WakeUp.HMAC.l[0] != 0) == (proxy != mDNSNULL))
                        {
-                       char *ifname = InterfaceNameForID(m, ar->resrec.InterfaceID);
-                       if (ar->WakeUp.HMAC.l[0]) (*proxy)++;
-                       if (!mDNSSameEthAddress(&owner, &ar->WakeUp.HMAC))
+                       if (showheader) { showheader = mDNSfalse; LogMsgNoIdent("    Int    Next  Expire   State"); }
+                       if (proxy) (*proxy)++;
+                       if (!mDNSPlatformMemSame(&owner, &ar->WakeUp, sizeof(owner)))
                                {
-                               owner = ar->WakeUp.HMAC;
-                               if (ar->WakeUp.password.l[0])
-                                       LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &ar->WakeUp.HMAC, &ar->WakeUp.IMAC, &ar->WakeUp.password, ar->WakeUp.seq);
-                               else if (!mDNSSameEthAddress(&ar->WakeUp.HMAC, &ar->WakeUp.IMAC))
-                                       LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a seq %d",               &ar->WakeUp.HMAC, &ar->WakeUp.IMAC,                       ar->WakeUp.seq);
+                               owner = ar->WakeUp;
+                               if (owner.password.l[0])
+                                       LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner.HMAC, &owner.IMAC, &owner.password, owner.seq);
+                               else if (!mDNSSameEthAddress(&owner.HMAC, &owner.IMAC))
+                                       LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a seq %d",               &owner.HMAC, &owner.IMAC,                  owner.seq);
                                else
-                                       LogMsgNoIdent("Proxying for %.6a seq %d",                                &ar->WakeUp.HMAC,                                         ar->WakeUp.seq);
+                                       LogMsgNoIdent("Proxying for %.6a seq %d",                                &owner.HMAC,                               owner.seq);
                                }
                        if (AuthRecord_uDNS(ar))
                                LogMsgNoIdent("%7d %7d %7d %7d %s",
@@ -4156,18 +3576,21 @@ mDNSlocal void LogAuthRecords(mDNS *const m, const mDNSs32 now, AuthRecord *Reso
                                        (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond,
                                        ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0,
                                        ar->state, ARDisplayString(m, ar));
-                       else if (ar->resrec.InterfaceID != mDNSInterface_LocalOnly)
+                       else if (ar->resrec.InterfaceID == mDNSInterface_LocalOnly)
+                               LogMsgNoIdent("                             LO %s", ARDisplayString(m, ar));
+                       else if (ar->resrec.InterfaceID == mDNSInterface_P2P)
+                               LogMsgNoIdent("                             PP %s", ARDisplayString(m, ar));
+                       else
                                LogMsgNoIdent("%7d %7d %7d %7s %s",
                                        ar->ThisAPInterval / mDNSPlatformOneSecond,
                                        ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0,
                                        ar->TimeExpire    ? (ar->TimeExpire                      - now) / mDNSPlatformOneSecond : 0,
                                        ifname ? ifname : "ALL",
                                        ARDisplayString(m, ar));
-                       else
-                               LogMsgNoIdent("                             LO %s", ARDisplayString(m, ar));
                        usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
                        }
                }
+       if (showheader) LogMsgNoIdent("<None>");
        }
 
 mDNSexport void udsserver_info(mDNS *const m)
@@ -4179,10 +3602,11 @@ mDNSexport void udsserver_info(mDNS *const m)
        const CacheRecord *cr;
        const DNSQuestion *q;
        const DNameListElem *d;
+       const SearchListElem *s;
 
        LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32)now, now);
-       LogMsgNoIdent("------------ Cache -------------");
 
+       LogMsgNoIdent("------------ Cache -------------");
        LogMsgNoIdent("Slt Q     TTL if     U Type rdlen");
        for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
                for (cg = m->rrcache_hash[slot]; cg; cg=cg->next)
@@ -4190,8 +3614,12 @@ mDNSexport void udsserver_info(mDNS *const m)
                        CacheUsed++;    // Count one cache entity for the CacheGroup object
                        for (cr = cg->members; cr; cr=cr->next)
                                {
-                               mDNSs32 remain = cr->resrec.rroriginalttl - (now - cr->TimeRcvd) / mDNSPlatformOneSecond;
-                               char *ifname = InterfaceNameForID(m, cr->resrec.InterfaceID);
+                               const mDNSs32 remain = cr->resrec.rroriginalttl - (now - cr->TimeRcvd) / mDNSPlatformOneSecond;
+                               const char *ifname;
+                               mDNSInterfaceID InterfaceID = cr->resrec.InterfaceID;
+                               if (!InterfaceID && cr->resrec.rDNSServer)
+                                       InterfaceID = cr->resrec.rDNSServer->interface;
+                               ifname = InterfaceNameForID(m, InterfaceID);
                                CacheUsed++;
                                if (cr->CRActiveQuestion) CacheActive++;
                                LogMsgNoIdent("%3d %s%8ld %-7s%s %-6s%s",
@@ -4214,24 +3642,16 @@ mDNSexport void udsserver_info(mDNS *const m)
        LogMsgNoIdent("Cache currently contains %lu entities; %lu referenced by active questions", CacheUsed, CacheActive);
 
        LogMsgNoIdent("--------- Auth Records ---------");
-       LogAuthRecords(m, now, m->ResourceRecords, &ProxyA);
+       LogAuthRecords(m, now, m->ResourceRecords, mDNSNULL);
 
        LogMsgNoIdent("------ Duplicate Records -------");
-       LogAuthRecords(m, now, m->DuplicateRecords, &ProxyD);
+       LogAuthRecords(m, now, m->DuplicateRecords, mDNSNULL);
 
-       LogMsgNoIdent("----- ServiceRegistrations -----");
-       if (!m->ServiceRegistrations) LogMsgNoIdent("<None>");
-       else
-               {
-               ServiceRecordSet *s;
-               LogMsgNoIdent("    Int    Next  Expire   State");
-               for (s = m->ServiceRegistrations; s; s = s->uDNS_next)
-                       LogMsgNoIdent("%7d %7d %7d %7d %s",
-                               s->RR_SRV.ThisAPInterval / mDNSPlatformOneSecond,
-                               (s->RR_SRV.LastAPTime + s->RR_SRV.ThisAPInterval - now) / mDNSPlatformOneSecond,
-                               s->RR_SRV.expire ? (s->RR_SRV.expire - now) / mDNSPlatformOneSecond : 0,
-                               s->state, ARDisplayString(m, &s->RR_SRV));
-               }
+       LogMsgNoIdent("----- Auth Records Proxied -----");
+       LogAuthRecords(m, now, m->ResourceRecords, &ProxyA);
+
+       LogMsgNoIdent("-- Duplicate Records Proxied ---");
+       LogAuthRecords(m, now, m->DuplicateRecords, &ProxyD);
 
        LogMsgNoIdent("---------- Questions -----------");
        if (!m->Questions) LogMsgNoIdent("<None>");
@@ -4239,21 +3659,21 @@ mDNSexport void udsserver_info(mDNS *const m)
                {
                CacheUsed = 0;
                CacheActive = 0;
-               LogMsgNoIdent("   Int  Next if     T  NumAns Type  Name");
+               LogMsgNoIdent("   Int  Next if     T  NumAns VDNS    Qptr     DupOf    SU SQ Type Name");
                for (q = m->Questions; q; q=q->next)
                        {
                        mDNSs32 i = q->ThisQInterval / mDNSPlatformOneSecond;
-                       mDNSs32 n = (q->LastQTime + q->ThisQInterval - now) / mDNSPlatformOneSecond;
+                       mDNSs32 n = (NextQSendTime(q) - now) / mDNSPlatformOneSecond;
                        char *ifname = InterfaceNameForID(m, q->InterfaceID);
                        CacheUsed++;
                        if (q->ThisQInterval) CacheActive++;
-                       LogMsgNoIdent("%6d%6d %-7s%s%s %5d  %-6s%##s%s",
+                       LogMsgNoIdent("%6d%6d %-7s%s%s %5d 0x%x%x 0x%p 0x%p %1d %2d %-5s%##s%s",
                                i, n,
                                ifname ? ifname : mDNSOpaque16IsZero(q->TargetQID) ? "" : "-U-",
                                mDNSOpaque16IsZero(q->TargetQID) ? (q->LongLived ? "l" : " ") : (q->LongLived ? "L" : "O"),
-                               q->AuthInfo    ? "P" : " ",
-                               q->CurrentAnswers,
-                               DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : "");
+                               PrivateQuery(q)    ? "P" : " ",
+                               q->CurrentAnswers, q->validDNSServers.l[1], q->validDNSServers.l[0], q, q->DuplicateOf,
+                               q->SuppressUnusable, q->SuppressQuery, DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : "");
                        usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
                        }
                LogMsgNoIdent("%lu question%s; %lu active", CacheUsed, CacheUsed > 1 ? "s" : "", CacheActive);
@@ -4269,17 +3689,25 @@ mDNSexport void udsserver_info(mDNS *const m)
        if (!all_requests) LogMsgNoIdent("<None>");
        else
                {
-               request_state *req;
+               const request_state *req, *r;
                for (req = all_requests; req; req=req->next)
+                       {
+                       if (req->primary)       // If this is a subbordinate operation, check that the parent is in the list
+                               {
+                               for (r = all_requests; r && r != req; r=r->next) if (r == req->primary) goto foundparent;
+                               LogMsgNoIdent("%3d: Orhpan operation %p; parent %p not found in request list", req->sd);
+                               }
+                       // For non-subbordinate operations, and subbordinate operations that have lost their parent, write out their info
                        LogClientInfo(m, req);
-               usleep((m->KnownBugs & mDNS_KnownBug_LossySyslog) ? 3333 : 1000);
+                       foundparent:;
+                       }
                }
 
        LogMsgNoIdent("-------- NAT Traversals --------");
        if (!m->NATTraversals) LogMsgNoIdent("<None>");
        else
                {
-               NATTraversalInfo *nat;
+               const NATTraversalInfo *nat;
                for (nat = m->NATTraversals; nat; nat=nat->next)
                        {
                        if (nat->Protocol)
@@ -4301,7 +3729,7 @@ mDNSexport void udsserver_info(mDNS *const m)
        if (!m->AuthInfoList) LogMsgNoIdent("<None>");
        else
                {
-               DomainAuthInfo *a;
+               const DomainAuthInfo *a;
                for (a = m->AuthInfoList; a; a = a->next)
                        LogMsgNoIdent("%##s %##s%s", a->domain.c, a->keyname.c, a->AutoTunnel ? " AutoTunnel" : "");
                }
@@ -4311,10 +3739,10 @@ mDNSexport void udsserver_info(mDNS *const m)
        if (!m->TunnelClients) LogMsgNoIdent("<None>");
        else
                {
-               ClientTunnel *c;
+               const ClientTunnel *c;
                for (c = m->TunnelClients; c; c = c->next)
-                       LogMsgNoIdent("%##s local %.16a %.4a remote %.16a %.4a %5d interval %d",
-                               c->dstname.c, &c->loc_inner, &c->loc_outer, &c->rmt_inner, &c->rmt_outer, mDNSVal16(c->rmt_outer_port), c->q.ThisQInterval);
+                       LogMsgNoIdent("%##s local %.16a %.4a %.16a remote %.16a %.4a %5d %.16a interval %d",
+                               c->dstname.c, &c->loc_inner, &c->loc_outer, &c->loc_outer6, &c->rmt_inner, &c->rmt_outer, mDNSVal16(c->rmt_outer_port), &c->rmt_outer6, c->q.ThisQInterval);
                }
        #endif // APPLE_OSX_mDNSResponder
 
@@ -4342,6 +3770,68 @@ mDNSexport void udsserver_info(mDNS *const m)
        LogMsgNoIdent("--- Auto Registration Domains --");
        if (!AutoRegistrationDomains) LogMsgNoIdent("<None>");
        else for (d=AutoRegistrationDomains; d; d=d->next) LogMsgNoIdent("%##s", d->name.c);
+
+       LogMsgNoIdent("--- Search Domains --");
+       if (!SearchList) LogMsgNoIdent("<None>");
+       else
+               {
+               for (s=SearchList; s; s=s->next)
+                       {
+                       LogMsgNoIdent("%##s", s->domain.c);
+                       }
+               }
+       LogMsgNoIdent("---- Task Scheduling Timers ----");
+
+       if (!m->NewQuestions)
+               LogMsgNoIdent("NewQuestion <NONE>");
+       else
+               LogMsgNoIdent("NewQuestion DelayAnswering %d %d %##s (%s)",
+                       m->NewQuestions->DelayAnswering, m->NewQuestions->DelayAnswering-now,
+                       m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
+
+       if (!m->NewLocalOnlyQuestions)
+               LogMsgNoIdent("NewLocalOnlyQuestions <NONE>");
+       else
+               LogMsgNoIdent("NewLocalOnlyQuestions %##s (%s)",
+                       m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
+
+       if (!m->NewLocalRecords)
+               LogMsgNoIdent("NewLocalRecords <NONE>");
+       else
+               LogMsgNoIdent("NewLocalRecords %02X %s", m->NewLocalRecords->resrec.RecordType, ARDisplayString(m, m->NewLocalRecords));
+
+       LogMsgNoIdent("SPSProxyListChanged%s", m->SPSProxyListChanged ? "" : " <NONE>");
+       LogMsgNoIdent("LocalRemoveEvents%s",   m->LocalRemoveEvents   ? "" : " <NONE>");
+
+#define LogTimer(MSG,T) LogMsgNoIdent( MSG " %08X %11d  %08X %11d", (T), (T), (T)-now, (T)-now)
+
+       LogMsgNoIdent("                         ABS (hex)  ABS (dec)  REL (hex)  REL (dec)");
+       LogMsgNoIdent("m->timenow               %08X %11d", now, now);
+       LogMsgNoIdent("m->timenow_adjust        %08X %11d", m->timenow_adjust, m->timenow_adjust);
+       LogTimer("m->NextScheduledEvent   ", m->NextScheduledEvent);
+
+#ifndef UNICAST_DISABLED
+       LogTimer("m->NextuDNSEvent        ", m->NextuDNSEvent);
+       LogTimer("m->NextSRVUpdate        ", m->NextSRVUpdate);
+       LogTimer("m->NextScheduledNATOp   ", m->NextScheduledNATOp);
+       LogTimer("m->retryGetAddr         ", m->retryGetAddr);
+#endif
+
+       LogTimer("m->NextCacheCheck       ", m->NextCacheCheck);
+       LogTimer("m->NextScheduledSPS     ", m->NextScheduledSPS);
+       LogTimer("m->NextScheduledSPRetry ", m->NextScheduledSPRetry);
+       LogTimer("m->DelaySleep           ", m->DelaySleep);
+
+       LogTimer("m->NextScheduledQuery   ", m->NextScheduledQuery);
+       LogTimer("m->NextScheduledProbe   ", m->NextScheduledProbe);
+       LogTimer("m->NextScheduledResponse", m->NextScheduledResponse);
+
+       LogTimer("m->SuppressSending      ", m->SuppressSending);
+       LogTimer("m->SuppressProbes       ", m->SuppressProbes);
+       LogTimer("m->ProbeFailTime        ", m->ProbeFailTime);
+       LogTimer("m->DelaySleep           ", m->DelaySleep);
+       LogTimer("m->SleepLimit           ", m->SleepLimit);
+       LogMsgNoIdent("m->RegisterAutoTunnel6  %08X", m->RegisterAutoTunnel6);
        }
 
 #if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
@@ -4526,9 +4016,9 @@ struct CompileTimeAssertionChecks_uds_daemon
        // other overly-large structures instead of having a pointer to them, can inadvertently
        // cause structure sizes (and therefore memory usage) to balloon unreasonably.
        char sizecheck_request_state          [(sizeof(request_state)           <= 2000) ? 1 : -1];
-       char sizecheck_registered_record_entry[(sizeof(registered_record_entry) <=   40) ? 1 : -1];
+       char sizecheck_registered_record_entry[(sizeof(registered_record_entry) <=   60) ? 1 : -1];
        char sizecheck_service_instance       [(sizeof(service_instance)        <= 6552) ? 1 : -1];
-       char sizecheck_browser_t              [(sizeof(browser_t)               <=  992) ? 1 : -1];
+       char sizecheck_browser_t              [(sizeof(browser_t)               <=  1016) ? 1 : -1];
        char sizecheck_reply_hdr              [(sizeof(reply_hdr)               <=   12) ? 1 : -1];
        char sizecheck_reply_state            [(sizeof(reply_state)             <=   64) ? 1 : -1];
        };
index b6d966eae5ba4b1a920012a3cb0f043842c703c9..93cfd1e96598314da30bb7aa39479fcfb22a853a 100644 (file)
 
        Version:        1.0
 
-    Change History (most recent first):
-
-$Log: uds_daemon.h,v $
-Revision 1.27  2009/04/30 20:07:51  mcguire
-<rdar://problem/6822674> Support multiple UDSs from launchd
-
-Revision 1.26  2008/10/02 22:26:21  cheshire
-Moved declaration of BPF_fd from uds_daemon.c to mDNSMacOSX.c, where it really belongs
-
-Revision 1.25  2008/09/27 01:08:25  cheshire
-Added external declaration of "dnssd_sock_t BPF_fd"
-
-Revision 1.24  2007/09/19 20:25:17  cheshire
-Deleted outdated comment
-
-Revision 1.23  2007/07/24 17:23:02  cheshire
-Rename DefRegList as AutoRegistrationDomains
-
-Revision 1.22  2007/07/11 02:58:04  cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-
-Revision 1.21  2007/04/21 21:47:47  cheshire
-<rdar://problem/4376383> Daemon: Add watchdog timer
-
-Revision 1.20  2007/02/14 01:58:19  cheshire
-<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
-
-Revision 1.19  2007/02/07 19:32:00  cheshire
-<rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
-
-Revision 1.18  2007/02/06 19:06:49  cheshire
-<rdar://problem/3956518> Need to go native with launchd
-
-Revision 1.17  2007/01/05 05:46:07  cheshire
-Add mDNS *const m parameter to udsserver_handle_configchange()
-
-Revision 1.16  2007/01/04 23:11:15  cheshire
-<rdar://problem/4720673> uDNS: Need to start caching unicast records
-When an automatic browsing domain is removed, generate appropriate "remove" events for legacy queries
-
-Revision 1.15  2006/08/14 23:24:57  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.14  2005/01/27 17:48:39  cheshire
-Added comment about CFSocketInvalidate closing the underlying socket
-
-Revision 1.13  2004/12/10 05:27:26  cheshire
-<rdar://problem/3909147> Guard against multiple autoname services of the same type on the same machine
-
-Revision 1.12  2004/12/10 04:28:28  cheshire
-<rdar://problem/3914406> User not notified of name changes for services using new UDS API
-
-Revision 1.11  2004/12/06 21:15:23  ksekar
-<rdar://problem/3884386> mDNSResponder crashed in CheckServiceRegistrations
-
-Revision 1.10  2004/10/26 04:31:44  cheshire
-Rename CountSubTypes() as ChopSubTypes()
-
-Revision 1.9  2004/09/30 00:25:00  ksekar
-<rdar://problem/3695802> Dynamically update default registration domains on config change
-
-Revision 1.8  2004/09/21 21:05:11  cheshire
-Move duplicate code out of mDNSMacOSX/daemon.c and mDNSPosix/PosixDaemon.c,
-into mDNSShared/uds_daemon.c
-
-Revision 1.7  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
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.6  2004/08/11 01:58:49  cheshire
-Remove "mDNS *globalInstance" parameter from udsserver_init()
-
-Revision 1.5  2004/06/18 04:44:58  rpantos
-Use platform layer for socket types
-
-Revision 1.4  2004/06/12 00:51:58  cheshire
-Changes for Windows compatibility
-
-Revision 1.3  2004/01/25 00:03:21  cheshire
-Change to use mDNSVal16() instead of private PORT_AS_NUM() macro
-
-Revision 1.2  2004/01/24 08:46:26  bradley
-Added InterfaceID<->Index platform interfaces since they are now used by all platforms for the DNS-SD APIs.
-
-Revision 1.1  2003/12/08 21:11:42  rpantos;
-Changes necessary to support mDNSResponder on Linux.
-
-*/
+ */
 
 #include "mDNSEmbeddedAPI.h"
 #include "dnssd_ipc.h"
@@ -127,8 +38,9 @@ extern int udsserver_exit(void);     // should be called prior to app exit
 /* Routines that uds_daemon expects to link against: */
 
 typedef        void (*udsEventCallback)(int fd, short filter, void *context);
-extern mStatus udsSupportAddFDToEventLoop(dnssd_sock_t fd, udsEventCallback callback, void *context);
-extern mStatus udsSupportRemoveFDFromEventLoop(dnssd_sock_t fd); // Note: This also CLOSES the file descriptor as well
+extern mStatus udsSupportAddFDToEventLoop(dnssd_sock_t fd, udsEventCallback callback, void *context, void **platform_data);
+extern int     udsSupportReadFD(dnssd_sock_t fd, char* buf, int len, int flags, void *platform_data);
+extern mStatus udsSupportRemoveFDFromEventLoop(dnssd_sock_t fd, void *platform_data); // Note: This also CLOSES the file descriptor as well
 
 extern void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay);
 
@@ -147,7 +59,21 @@ extern int CountPeerRegistrations(mDNS *const m, ServiceRecordSet *const srs);
 #if APPLE_OSX_mDNSResponder
 extern void machserver_automatic_browse_domain_changed(const domainname *d, mDNSBool add);
 extern void machserver_automatic_registration_domain_changed(const domainname *d, mDNSBool add);
-#endif
+// External support
+extern void external_start_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype);
+extern void external_stop_browsing_for_service(mDNS *const m, const domainname *const type, DNS_TypeValues qtype);
+extern void external_start_advertising_service(const ResourceRecord *const resourceRecord);
+extern void external_stop_advertising_service(const ResourceRecord *const resourceRecord);
+extern void external_start_resolving_service(const domainname *const fqdn);
+extern void external_stop_resolving_service(const domainname *const fqdn);
+#else
+#define external_start_browsing_for_service(A,B,C) (void)(A)
+#define external_stop_browsing_for_service(A,B,C)  (void)(A)
+#define external_start_advertising_service(A)      (void)(A)
+#define external_stop_advertising_service(A)       (void)(A)
+#define external_start_resolving_service(A)        (void)(A)
+#define external_stop_resolving_service(A)         (void)(A)
+#endif // APPLE_OSX_mDNSResponder
 
 extern const char mDNSResponderVersionString_SCCS[];
 #define mDNSResponderVersionString (mDNSResponderVersionString_SCCS+5)
index 97a597b02541c77dbf0f3a1138ad23b8ba151a6d..04ecf1a543de310537003237c643c79b864385a4 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: mDNSVxWorks.c,v $
-Revision 1.35  2009/01/13 05:31:35  mkrochma
-<rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
-
-Revision 1.34  2008/10/03 18:25:18  cheshire
-Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);"
-
-Revision 1.33  2007/03/22 18:31:48  cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.32  2006/12/19 22:43:56  cheshire
-Fix compiler warnings
-
-Revision 1.31  2006/11/10 00:54:16  cheshire
-<rdar://problem/4816598> Changing case of Computer Name doesn't work
-
-Revision 1.30  2006/08/14 23:25:18  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.29  2006/03/19 02:00:12  cheshire
-<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-
-Revision 1.28  2005/05/30 07:36:38  bradley
-New implementation of the mDNS platform plugin for VxWorks 5.5 or later with IPv6 support.
-
-*/
+ */
 
 #if 0
 #pragma mark == Configuration ==
index eb62b4877ece633877a74aa87f343383a280218c..59871319ee93c6ce5d38104c837fa82a46f5bdf1 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: mDNSVxWorks.h,v $
-Revision 1.5  2006/08/14 23:25:18  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.4  2005/05/30 07:36:38  bradley
-New implementation of the mDNS platform plugin for VxWorks 5.5 or later with IPv6 support.
-
-*/
+ */
 
 #ifndef        __MDNS_VXWORKS_H__
 #define        __MDNS_VXWORKS_H__
index a4a30a33bff1831f5998ae8d6b8539659d65a422..83f23c1cc971f24d4aa9a002f91ad45bca0f4afe 100644 (file)
 
        Copyright:  Copyright (C) 2002-2004 Apple Computer, Inc., All Rights Reserved.
 
-       Change History (most recent first):
-
-$Log: mDNSVxWorksIPv4Only.c,v $
-Revision 1.34  2009/01/13 05:31:35  mkrochma
-<rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
-
-Revision 1.33  2008/11/04 19:51:13  cheshire
-Updated comment about MAX_ESCAPED_DOMAIN_NAME size (should be 1009, not 1005)
-
-Revision 1.32  2008/10/03 18:25:18  cheshire
-Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);"
-
-Revision 1.31  2007/03/22 18:31:49  cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.30  2006/12/19 22:43:56  cheshire
-Fix compiler warnings
-
-Revision 1.29  2006/08/14 23:25:18  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.28  2006/03/19 02:00:12  cheshire
-<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-
-Revision 1.27  2004/12/17 23:37:49  cheshire
-<rdar://problem/3485365> Guard against repeating wireless dissociation/re-association
-(and other repetitive configuration changes)
-
-Revision 1.26  2004/10/28 02:00:35  cheshire
-<rdar://problem/3841770> Call pipeDevDelete when disposing of commandPipe
-
-Revision 1.25  2004/10/16 00:17:01  cheshire
-<rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
-
-Revision 1.24  2004/09/21 21:02:56  cheshire
-Set up ifname before calling mDNS_RegisterInterface()
-
-Revision 1.23  2004/09/17 01:08:57  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.22  2004/09/17 00:19:11  cheshire
-For consistency with AllDNSLinkGroupv6, rename AllDNSLinkGroup to AllDNSLinkGroupv4
-
-Revision 1.21  2004/09/16 00:24:50  cheshire
-<rdar://problem/3803162> Fix unsafe use of mDNSPlatformTimeNow()
-
-Revision 1.20  2004/09/14 23:42:36  cheshire
-<rdar://problem/3801296> Need to seed random number generator from platform-layer data
-
-Revision 1.19  2004/09/14 23:16:09  cheshire
-mDNS_SetFQDNs has been renamed to mDNS_SetFQDN
-
-Revision 1.18  2004/08/14 03:22:42  cheshire
-<rdar://problem/3762579> Dynamic DNS UI <-> mDNSResponder glue
-Add GetUserSpecifiedDDNSName() routine
-Convert ServiceRegDomain to domainname instead of C string
-Replace mDNS_GenerateFQDN/mDNS_GenerateGlobalFQDN with mDNS_SetFQDNs
-
-Revision 1.17  2004/07/29 19:26:03  ksekar
-Plaform-level changes for NAT-PMP support
-
-Revision 1.16  2004/04/22 05:11:28  bradley
-Added mDNSPlatformUTC for TSIG signed dynamic updates.
-
-Revision 1.15  2004/04/21 02:49:12  cheshire
-To reduce future confusion, renamed 'TxAndRx' to 'McastTxRx'
-
-Revision 1.14  2004/04/09 17:43:04  cheshire
-Make sure to set the McastTxRx field so that duplicate suppression works correctly
-
-Revision 1.13  2004/01/27 20:15:24  cheshire
-<rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
-
-Revision 1.12  2004/01/24 09:12:37  bradley
-Avoid TOS socket options to workaround a TOS routing problem with VxWorks and multiple interfaces
-when sending unicast responses, which resulted in packets going out the wrong interface.
-
-Revision 1.11  2004/01/24 04:59:16  cheshire
-Fixes so that Posix/Linux, OS9, Windows, and VxWorks targets build again
-
-Revision 1.10  2003/11/14 21:27:09  cheshire
-<rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
-Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1009) instead of 256-byte buffers.
-
-Revision 1.9  2003/11/14 20:59:09  cheshire
-Clients can't use AssignDomainName macro because mDNSPlatformMemCopy is defined in mDNSPlatformFunctions.h.
-Best solution is just to combine mDNSEmbeddedAPI.h and mDNSPlatformFunctions.h into a single file.
-
-Revision 1.8  2003/10/28 10:08:27  bradley
-Removed legacy port 53 support as it is no longer needed.
-
-Revision 1.7  2003/08/20 05:58:54  bradley
-Removed dependence on modified mDNSCore: define structures/prototypes locally.
-
-Revision 1.6  2003/08/18 23:19:05  cheshire
-<rdar://problem/3382647> mDNSResponder divide by zero in mDNSPlatformRawTime()
-
-Revision 1.5  2003/08/15 00:05:04  bradley
-Updated to use name/InterfaceID from new AuthRecord resrec field. Added output of new record sizes.
-
-Revision 1.4  2003/08/14 02:19:55  cheshire
-<rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
-
-Revision 1.3  2003/08/12 19:56:27  cheshire
-Update to APSL 2.0
-
-Revision 1.2  2003/08/05 23:58:34  cheshire
-Update code to compile with the new mDNSCoreReceive() function that requires a TTL
-Right now this platform layer just reports 255 instead of returning the real value -- we should fix this
-
-Revision 1.1  2003/08/02 10:06:48  bradley
-mDNS platform plugin for VxWorks.
-
-
        Notes for non-Apple platforms:
 
                TARGET_NON_APPLE should be defined to 1 to avoid relying on Apple-only header files, macros, or functions.
index 9b24f19577fa06ddfd1a741b5689f546964e4c67..d24e3112ef068fd4bd6f14e4e70f20e58b98c7d2 100644 (file)
 
        Copyright:  Copyright (C) 2002-2003 Apple Computer, Inc., All Rights Reserved.
 
-       Change History (most recent first):
-
-$Log: mDNSVxWorksIPv4Only.h,v $
-Revision 1.4  2006/08/14 23:25:18  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2004/09/17 01:08:57  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.2  2003/08/12 19:56:27  cheshire
-Update to APSL 2.0
-
-Revision 1.1  2003/08/02 10:06:49  bradley
-mDNS platform plugin for VxWorks.
-
-*/
+ */
 
 #ifndef        __MDNS_VXWORKS__
 #define        __MDNS_VXWORKS__
diff --git a/mDNSWindows/ControlPanel/BrowsingPage.cpp b/mDNSWindows/ControlPanel/BrowsingPage.cpp
new file mode 100755 (executable)
index 0000000..20b5c6d
--- /dev/null
@@ -0,0 +1,441 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BrowsingPage.h"
+#include "resource.h"
+
+#include "ConfigPropertySheet.h"
+
+#include <WinServices.h>
+    
+#define MAX_KEY_LENGTH 255
+
+
+IMPLEMENT_DYNCREATE(CBrowsingPage, CPropertyPage)
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CBrowsingPage::CBrowsingPage
+//---------------------------------------------------------------------------------------------------------------------------
+
+CBrowsingPage::CBrowsingPage()
+:
+       CPropertyPage(CBrowsingPage::IDD)
+{
+       //{{AFX_DATA_INIT(CBrowsingPage)
+       //}}AFX_DATA_INIT
+
+       m_firstTime = true;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CBrowsingPage::~CBrowsingPage
+//---------------------------------------------------------------------------------------------------------------------------
+
+CBrowsingPage::~CBrowsingPage()
+{
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CBrowsingPage::DoDataExchange
+//---------------------------------------------------------------------------------------------------------------------------
+
+void CBrowsingPage::DoDataExchange(CDataExchange* pDX)
+{
+       CPropertyPage::DoDataExchange(pDX);
+       //{{AFX_DATA_MAP(CBrowsingPage)
+       //}}AFX_DATA_MAP
+       DDX_Control(pDX, IDC_BROWSE_LIST, m_browseListCtrl);
+       DDX_Control(pDX, IDC_REMOVE_BROWSE_DOMAIN, m_removeButton);
+}
+
+BEGIN_MESSAGE_MAP(CBrowsingPage, CPropertyPage)
+       //{{AFX_MSG_MAP(CBrowsingPage)
+       //}}AFX_MSG_MAP
+       ON_BN_CLICKED(IDC_ADD_BROWSE_DOMAIN, OnBnClickedAddBrowseDomain)
+       ON_BN_CLICKED(IDC_REMOVE_BROWSE_DOMAIN, OnBnClickedRemoveBrowseDomain)
+       ON_NOTIFY(LVN_ITEMCHANGED, IDC_BROWSE_LIST, OnLvnItemchangedBrowseList)
+END_MESSAGE_MAP()
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CBrowsingPage::SetModified
+//---------------------------------------------------------------------------------------------------------------------------
+
+void CBrowsingPage::SetModified( BOOL bChanged )
+{
+       m_modified = bChanged;
+
+       CPropertyPage::SetModified( bChanged );
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CBrowsingPage::OnSetActive
+//---------------------------------------------------------------------------------------------------------------------------
+
+BOOL
+CBrowsingPage::OnSetActive()
+{
+       CConfigPropertySheet    *       psheet;
+       HKEY                                            key = NULL;
+       HKEY                                            subKey = NULL;
+       DWORD                                           dwSize;
+       DWORD                                           enabled;
+       DWORD                                           err;
+       TCHAR                                           subKeyName[MAX_KEY_LENGTH];
+       DWORD                                           cSubKeys = 0;
+       DWORD                                           cbMaxSubKey;
+       DWORD                                           cchMaxClass;
+       int                                                     nIndex;
+    DWORD                                              i; 
+       BOOL                                            b = CPropertyPage::OnSetActive();
+
+       psheet = reinterpret_cast<CConfigPropertySheet*>(GetParent());
+       require_quiet( psheet, exit );
+       
+       m_modified = FALSE;
+
+       if ( m_firstTime )
+       {
+               m_browseListCtrl.SetExtendedStyle((m_browseListCtrl.GetStyle() & (~LVS_EX_GRIDLINES))|LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
+
+               m_browseListCtrl.InsertColumn(0, L"", LVCFMT_LEFT, 20 );
+               m_browseListCtrl.InsertColumn(1, L"", LVCFMT_LEFT, 345);
+
+               m_firstTime = false;
+       }
+
+       m_initialized = false;
+
+       // Clear out what's there
+
+       m_browseListCtrl.DeleteAllItems();
+
+       // Now populate the browse domain box
+
+       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSBrowseDomains, 0,
+                                 NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &key, NULL );
+       require_noerr( err, exit );
+
+       // Get information about this node
+
+    err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );       
+       require_noerr( err, exit );
+
+       for ( i = 0; i < cSubKeys; i++)
+       {       
+               dwSize = MAX_KEY_LENGTH;
+            
+               err = RegEnumKeyEx( key, i, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
+               require_noerr( err, exit );
+
+               err = RegOpenKey( key, subKeyName, &subKey );
+               require_noerr( err, exit );
+
+               dwSize = sizeof( DWORD );
+               err = RegQueryValueEx( subKey, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
+               require_noerr( err, exit );
+
+               nIndex = m_browseListCtrl.InsertItem( m_browseListCtrl.GetItemCount(), L"");
+               m_browseListCtrl.SetItemText( nIndex, 1, subKeyName );
+               m_browseListCtrl.SetCheck( nIndex, enabled );
+
+               RegCloseKey( subKey );
+               subKey = NULL;
+    }
+
+       m_browseListCtrl.SortItems( SortFunc, (DWORD_PTR) this );
+
+       m_removeButton.EnableWindow( FALSE );
+exit:
+
+       if ( subKey )
+       {
+               RegCloseKey( subKey );
+       }
+
+       if ( key )
+       {
+               RegCloseKey( key );
+       }
+
+       m_initialized = true;
+
+       return b;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CBrowsingPage::OnOK
+//---------------------------------------------------------------------------------------------------------------------------
+
+void
+CBrowsingPage::OnOK()
+{
+       if ( m_modified )
+       {
+               Commit();
+       }
+}
+
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CBrowsingPage::Commit
+//---------------------------------------------------------------------------------------------------------------------------
+
+void
+CBrowsingPage::Commit()
+{
+       HKEY            key             = NULL;
+       HKEY            subKey  = NULL;
+       TCHAR           subKeyName[MAX_KEY_LENGTH];
+       DWORD           cSubKeys = 0;
+       DWORD           cbMaxSubKey;
+       DWORD           cchMaxClass;
+       DWORD           dwSize;
+       int                     i;
+       DWORD           err;
+
+       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSBrowseDomains, 0,
+                             NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &key, NULL );
+       require_noerr( err, exit );
+
+       // First, remove all the entries that are there
+
+    err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );       
+       require_noerr( err, exit );
+
+       for ( i = 0; i < (int) cSubKeys; i++ )
+       {       
+               dwSize = MAX_KEY_LENGTH;
+            
+               err = RegEnumKeyEx( key, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
+               require_noerr( err, exit );
+                       
+               err = RegDeleteKey( key, subKeyName );
+               require_noerr( err, exit );
+       }
+
+       // Now re-populate
+
+       for ( i = 0; i < m_browseListCtrl.GetItemCount(); i++ )
+       {
+               DWORD enabled = (DWORD) m_browseListCtrl.GetCheck( i );
+
+               err = RegCreateKeyEx( key, m_browseListCtrl.GetItemText( i, 1 ), 0,
+                                     NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &subKey, NULL );
+               require_noerr( err, exit );
+
+               err = RegSetValueEx( subKey, L"Enabled", NULL, REG_DWORD, (LPBYTE) &enabled, sizeof( enabled ) );
+               require_noerr( err, exit );
+
+               RegCloseKey( subKey );
+               subKey = NULL;
+       }
+       
+exit:
+
+       if ( subKey )
+       {
+               RegCloseKey( subKey );
+       }
+
+       if ( key )
+       {
+               RegCloseKey( key );
+       }
+}
+
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CBrowsingPage::OnBnClickedAddBrowseDomain
+//---------------------------------------------------------------------------------------------------------------------------
+
+void
+CBrowsingPage::OnBnClickedAddBrowseDomain()
+{
+       CAddBrowseDomain dlg( GetParent() );
+
+       if ( ( dlg.DoModal() == IDOK ) && ( dlg.m_text.GetLength() > 0 ) )
+       {
+               int nIndex;
+
+               nIndex = m_browseListCtrl.InsertItem( m_browseListCtrl.GetItemCount(), L"");
+               m_browseListCtrl.SetItemText( nIndex, 1, dlg.m_text );
+               m_browseListCtrl.SetCheck( nIndex, 1 );
+
+               m_browseListCtrl.SortItems( SortFunc, (DWORD_PTR) this );
+
+               m_browseListCtrl.Invalidate();
+
+               SetModified( TRUE );
+       }
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CBrowsingPage::OnBnClickedRemoveBrowseDomain
+//---------------------------------------------------------------------------------------------------------------------------
+
+void
+CBrowsingPage::OnBnClickedRemoveBrowseDomain()
+{
+       UINT    selectedCount = m_browseListCtrl.GetSelectedCount();
+       int             nItem = -1;
+       UINT    i;
+
+       // Update all of the selected items.
+
+       for ( i = 0; i < selectedCount; i++ )
+       {
+               nItem = m_browseListCtrl.GetNextItem( -1, LVNI_SELECTED );
+               check( nItem != -1 );
+
+               m_browseListCtrl.DeleteItem( nItem );
+
+               SetModified( TRUE );
+       }
+
+       m_removeButton.EnableWindow( FALSE );
+}
+
+
+void
+CBrowsingPage::OnLvnItemchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult)
+{
+       if ( m_browseListCtrl.GetSelectedCount() )
+       {
+               m_removeButton.EnableWindow( TRUE );
+       }
+
+       if ( m_initialized )
+       {
+               NM_LISTVIEW * pNMListView = (NM_LISTVIEW*)pNMHDR; 
+        
+               BOOL bPrevState = (BOOL) ( ( ( pNMListView->uOldState & LVIS_STATEIMAGEMASK ) >> 12 ) - 1 ); 
+        
+               if ( bPrevState < 0 )
+               {
+                       bPrevState = 0;
+               }
+
+
+               BOOL bChecked = ( BOOL ) ( ( ( pNMListView->uNewState & LVIS_STATEIMAGEMASK ) >> 12) - 1 ); 
+        
+               if ( bChecked < 0 )
+               {
+                       bChecked = 0;
+               }
+
+               if ( bPrevState != bChecked )
+               {
+                       SetModified( TRUE );
+               }
+       }
+
+       *pResult = 0;
+}
+
+
+
+int CALLBACK 
+CBrowsingPage::SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+       CString str1;
+       CString str2;
+       int             ret = 0;
+
+       CBrowsingPage * self = reinterpret_cast<CBrowsingPage*>( lParamSort );
+       require_quiet( self, exit );
+
+       str1 = self->m_browseListCtrl.GetItemText( (int) lParam1, 1 );
+       str2 = self->m_browseListCtrl.GetItemText( (int) lParam2, 1 );
+
+       ret = str1.Compare( str2 );
+
+exit:
+
+       return ret;
+}
+
+
+// CAddBrowseDomain dialog
+
+IMPLEMENT_DYNAMIC(CAddBrowseDomain, CDialog)
+CAddBrowseDomain::CAddBrowseDomain(CWnd* pParent /*=NULL*/)
+       : CDialog(CAddBrowseDomain::IDD, pParent)
+{
+}
+
+CAddBrowseDomain::~CAddBrowseDomain()
+{
+}
+
+void CAddBrowseDomain::DoDataExchange(CDataExchange* pDX)
+{
+       CDialog::DoDataExchange(pDX);
+       DDX_Control(pDX, IDC_COMBO1, m_comboBox);
+}
+
+
+BOOL
+CAddBrowseDomain::OnInitDialog()
+{
+       CConfigPropertySheet    *       psheet;
+       CConfigPropertySheet::StringList::iterator              it;
+       
+       BOOL b = CDialog::OnInitDialog();
+
+       psheet = reinterpret_cast<CConfigPropertySheet*>(GetParent());
+       require_quiet( psheet, exit );
+
+       for ( it = psheet->m_browseDomains.begin(); it != psheet->m_browseDomains.end(); it++ )
+       {
+               CString text = *it;
+
+               if ( m_comboBox.FindStringExact( -1, *it ) == CB_ERR )
+               {
+                       m_comboBox.AddString( *it );
+               }
+       }
+
+exit:
+
+       return b;
+}
+
+
+void
+CAddBrowseDomain::OnOK()
+{
+       m_comboBox.GetWindowText( m_text );
+
+       CDialog::OnOK();
+}
+
+
+
+BEGIN_MESSAGE_MAP(CAddBrowseDomain, CDialog)
+END_MESSAGE_MAP()
+
diff --git a/mDNSWindows/ControlPanel/BrowsingPage.h b/mDNSWindows/ControlPanel/BrowsingPage.h
new file mode 100755 (executable)
index 0000000..4711b36
--- /dev/null
@@ -0,0 +1,156 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "stdafx.h"
+#include "resource.h"
+
+#include <DebugServices.h>
+#include <list>
+#include "afxcmn.h"
+
+#include "afxwin.h"
+
+
+
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CBrowsingPage
+//---------------------------------------------------------------------------------------------------------------------------
+
+class CBrowsingPage : public CPropertyPage
+{
+public:
+       CBrowsingPage();
+       ~CBrowsingPage();
+
+protected:
+
+       //{{AFX_DATA(CBrowsingPage)
+       enum { IDD = IDR_APPLET_PAGE3 };
+       //}}AFX_DATA
+
+       //{{AFX_VIRTUAL(CBrowsingPage)
+       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+       //}}AFX_VIRTUAL
+
+       DECLARE_DYNCREATE(CBrowsingPage)
+
+       //{{AFX_MSG(CBrowsingPage)
+       //}}AFX_MSG
+       DECLARE_MESSAGE_MAP()
+       
+private:
+       
+       typedef std::list<CString> StringList;
+
+       afx_msg BOOL
+       OnSetActive();
+       
+       afx_msg void
+       OnOK();
+       
+       void
+       SetModified( BOOL bChanged = TRUE );
+       
+       void
+       Commit();
+
+       BOOL                    m_modified;
+
+public:
+private:
+
+       static int CALLBACK 
+
+       SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
+
+
+
+       CListCtrl       m_browseListCtrl;
+
+       bool            m_initialized;
+
+       bool            m_firstTime;
+
+
+
+public:
+
+
+
+       afx_msg void OnBnClickedAddBrowseDomain();
+
+       afx_msg void OnBnClickedRemoveBrowseDomain();
+
+       afx_msg void OnLvnItemchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult);
+
+       CButton m_removeButton;
+
+};
+
+
+
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CAddBrowseDomain
+//---------------------------------------------------------------------------------------------------------------------------
+
+
+class CAddBrowseDomain : public CDialog
+
+{
+
+       DECLARE_DYNAMIC(CAddBrowseDomain)
+
+
+
+public:
+
+       CAddBrowseDomain(CWnd* pParent = NULL);   // standard constructor
+
+       virtual ~CAddBrowseDomain();
+
+
+
+// Dialog Data
+
+       enum { IDD = IDR_ADD_BROWSE_DOMAIN };
+
+
+
+protected:
+
+       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+
+       virtual BOOL OnInitDialog();
+
+       virtual void OnOK();
+
+       DECLARE_MESSAGE_MAP()
+
+public:
+
+       CComboBox       m_comboBox;
+
+       CString         m_text;
+
+};
+
index 3b280a4cfcd9c7d22f5b9653a70c261c97ba752e..ad590660313274c4cc5cecd51dd0072836f90350 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: ConfigDialog.cpp,v $
-Revision 1.3  2006/08/14 23:25:28  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2005/03/03 19:55:21  shersche
-<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-
-
-*/
+ */
 
 
 #include "ConfigDialog.h"
index 0a38b16d5dff324e789520300e68cae953a954db..fa8df5f9b5afeeaa8f534fdaaf013d441028a227 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: ConfigDialog.h,v $
-Revision 1.3  2006/08/14 23:25:28  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2005/03/03 19:55:21  shersche
-<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-
-
-*/
+ */
 
 #pragma once
 
index ea2d9b76203c69928b28c5a9621347048316bb23..5fae9555268d2da87df0e5affb5089e4f0411a44 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: ConfigPropertySheet.cpp,v $
-Revision 1.7  2009/07/01 19:20:37  herscher
-<rdar://problem/6713286> UI changes for configuring sleep proxy settings.
-
-Revision 1.6  2009/03/30 19:57:45  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.5  2006/08/14 23:25:28  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.4  2005/10/05 20:46:50  herscher
-<rdar://problem/4192011> Move Wide-Area preferences to another part of the registry so they don't removed during an update-install.
-
-Revision 1.3  2005/03/03 19:55:22  shersche
-<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-
-
-*/
+ */
 
 #include "ConfigPropertySheet.h"
 #include <WinServices.h>
+extern "C"
+{
+#include <ClientCommon.h>
+}
 #include <process.h>
 
 // Custom events
 
 #define WM_DATAREADY           ( WM_USER + 0x100 )
-#define WM_REGISTRYCHANGED     ( WM_USER + 0x101 )
 
 
 IMPLEMENT_DYNCREATE(CConfigPropertySheet, CPropertySheet)
@@ -57,14 +39,12 @@ CConfigPropertySheet::CConfigPropertySheet()
 :
        CPropertySheet(),
        m_browseDomainsRef( NULL ),
-       m_regDomainsRef( NULL ),
        m_thread( NULL ),
        m_threadExited( NULL )
 {
-       AddPage(&m_firstPage);
+       AddPage(&m_firstPage );
        AddPage(&m_secondPage);
        AddPage(&m_thirdPage);
-       AddPage(&m_fourthPage );
 
        InitializeCriticalSection( &m_lock );
 }
@@ -84,7 +64,6 @@ BEGIN_MESSAGE_MAP(CConfigPropertySheet, CPropertySheet)
        //{{AFX_MSG_MAP(CConfigPropertySheet)
        //}}AFX_MSG_MAP
        ON_MESSAGE( WM_DATAREADY, OnDataReady )
-       ON_MESSAGE( WM_REGISTRYCHANGED, OnRegistryChanged )
 END_MESSAGE_MAP()
 
 
@@ -102,9 +81,6 @@ CConfigPropertySheet::OnInitDialog()
        err = SetupBrowsing();
        require_noerr( err, exit );
 
-       err = SetupRegistryNotifications();
-       require_noerr( err, exit );     
-
 exit:
 
        return b;
@@ -148,29 +124,6 @@ CConfigPropertySheet::OnDataReady(WPARAM inWParam, LPARAM inLParam)
                {
                        DNSServiceProcessResult( m_browseDomainsRef );
                }
-               else if ( m_regDomainsRef && DNSServiceRefSockFD( m_regDomainsRef ) == (int) sock )
-               {
-                       DNSServiceProcessResult( m_regDomainsRef );
-               }
-       }
-
-       return 0;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigPropertySheet::OnRegistryChanged
-//---------------------------------------------------------------------------------------------------------------------------
-
-afx_msg LRESULT
-CConfigPropertySheet::OnRegistryChanged( WPARAM inWParam, LPARAM inLParam )
-{
-       DEBUG_UNUSED( inWParam );
-       DEBUG_UNUSED( inLParam );
-
-       if ( GetActivePage() == &m_firstPage )
-       {
-               m_firstPage.OnRegistryChanged();
        }
 
        return 0;
@@ -186,9 +139,6 @@ CConfigPropertySheet::OnEndDialog()
 {
        OSStatus err;
 
-       err = TearDownRegistryNotifications();
-       check_noerr( err );
-
        err = TearDownBrowsing();
        check_noerr( err );
 }
@@ -211,14 +161,6 @@ CConfigPropertySheet::SetupBrowsing()
        err = WSAAsyncSelect( DNSServiceRefSockFD( m_browseDomainsRef ), m_hWnd, WM_DATAREADY, FD_READ|FD_CLOSE );
        require_noerr( err, exit );
 
-       // Start browsing for registration domains
-
-       err = DNSServiceEnumerateDomains( &m_regDomainsRef, kDNSServiceFlagsRegistrationDomains, 0, RegDomainsReply, this );
-       require_noerr( err, exit );
-
-       err = WSAAsyncSelect( DNSServiceRefSockFD( m_regDomainsRef ), m_hWnd, WM_DATAREADY, FD_READ|FD_CLOSE );
-       require_noerr( err, exit );
-
 exit:
 
        if ( err )
@@ -249,97 +191,6 @@ CConfigPropertySheet::TearDownBrowsing()
                m_browseDomainsRef = NULL;
        }
 
-       if ( m_regDomainsRef )
-       {
-               err = WSAAsyncSelect( DNSServiceRefSockFD( m_regDomainsRef ), m_hWnd, 0, 0 );
-               check_noerr( err );
-
-               DNSServiceRefDeallocate( m_regDomainsRef );
-       
-               m_regDomainsRef = NULL;
-       }
-
-       return err;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigPropertySheet::SetupRegistryNotifications
-//---------------------------------------------------------------------------------------------------------------------------
-
-OSStatus
-CConfigPropertySheet::SetupRegistryNotifications()
-{
-       unsigned int    threadId;
-       OSStatus                err;
-
-       check( m_threadExited == NULL );
-       check( m_thread == NULL );
-
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\State\\Hostnames", &m_statusKey );
-       require_noerr( err, exit );
-       
-       m_threadExited = CreateEvent( NULL, FALSE, FALSE, NULL );
-       err = translate_errno( m_threadExited, (OSStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-       // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time 
-       // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
-       
-       m_thread = (HANDLE) _beginthreadex_compat( NULL, 0, WatchRegistry, this, 0, &threadId );
-       err = translate_errno( m_thread, (OSStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-exit:
-
-       if ( err )
-       {
-               TearDownRegistryNotifications();
-       }
-
-       return err;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigPropertySheet::TearDownRegistryNotifications
-//---------------------------------------------------------------------------------------------------------------------------
-
-OSStatus
-CConfigPropertySheet::TearDownRegistryNotifications()
-{
-       OSStatus err = kNoErr;
-
-       if ( m_statusKey )
-       {
-               EnterCriticalSection( &m_lock );
-
-               RegCloseKey( m_statusKey );
-               m_statusKey = NULL;
-
-               LeaveCriticalSection( &m_lock );
-       }
-
-       if ( m_threadExited )
-       {
-               err = WaitForSingleObject( m_threadExited, 5 * 1000 );
-               require_noerr( err, exit );
-       }
-
-exit:
-
-       if ( m_threadExited )
-       {
-               CloseHandle( m_threadExited );
-               m_threadExited = NULL;
-       }
-
-       if ( m_thread )
-       {
-               CloseHandle( m_thread );
-               m_thread = NULL;
-       }
-
        return err;
 }
 
@@ -392,38 +243,6 @@ CConfigPropertySheet::DecodeDomainName( const char * raw, CString & decoded )
 }
 
 
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigPropertySheet::GetNextLabel
-//---------------------------------------------------------------------------------------------------------------------------
-
-const char*
-CConfigPropertySheet::GetNextLabel( const char * cstr, char label[64] )
-{
-       char *ptr = label;
-       while (*cstr && *cstr != '.')                                                           // While we have characters in the label...
-               {
-               char c = *cstr++;
-               if (c == '\\')
-                       {
-                       c = *cstr++;
-                       if (isdigit(cstr[-1]) && isdigit(cstr[0]) && isdigit(cstr[1]))
-                               {
-                               int v0 = cstr[-1] - '0';                                                // then interpret as three-digit decimal
-                               int v1 = cstr[ 0] - '0';
-                               int v2 = cstr[ 1] - '0';
-                               int val = v0 * 100 + v1 * 10 + v2;
-                               if (val <= 255) { c = (char)val; cstr += 2; }   // If valid three-digit decimal value, use it
-                               }
-                       }
-               *ptr++ = c;
-               if (ptr >= label+64) return(NULL);
-               }
-       if (*cstr) cstr++;                                                                                      // Skip over the trailing dot (if present)
-       *ptr++ = 0;
-       return(cstr);
-}
-
-
 //---------------------------------------------------------------------------------------------------------------------------
 //     CConfigPropertySheet::BrowseDomainsReply
 //---------------------------------------------------------------------------------------------------------------------------
@@ -460,8 +279,6 @@ CConfigPropertySheet::BrowseDomainsReply
                goto exit;
        }
 
-
-
        err = self->DecodeDomainName( replyDomain, decoded );
        require_noerr( err, exit );
 
@@ -482,105 +299,3 @@ exit:
 
        return;
 }
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigPropertySheet::RegDomainsReply
-//---------------------------------------------------------------------------------------------------------------------------
-
-void DNSSD_API
-CConfigPropertySheet::RegDomainsReply
-                                                       (
-                                                       DNSServiceRef                   sdRef,
-                                                       DNSServiceFlags                 flags,
-                                                       uint32_t                                interfaceIndex,
-                                                       DNSServiceErrorType             errorCode,
-                                                       const char                      *       replyDomain,
-                                                       void                            *       context
-                                                       )
-{
-       CConfigPropertySheet    *       self = reinterpret_cast<CConfigPropertySheet*>(context);
-       CString                                         decoded;
-       OSStatus                                        err;
-
-       DEBUG_UNUSED( sdRef );
-       DEBUG_UNUSED( interfaceIndex );
-
-       if ( errorCode )
-       {
-               goto exit;
-       }
-
-       check( replyDomain );
-       
-       // Ignore local domains
-
-       if ( strcmp( replyDomain, "local." ) == 0 )
-       {
-               goto exit;
-       }
-
-       err = self->DecodeDomainName( replyDomain, decoded );
-       require_noerr( err, exit );
-
-       // Remove trailing '.'
-
-       decoded.TrimRight( '.' );
-
-       if ( flags & kDNSServiceFlagsAdd )
-       {
-               if ( self->GetActivePage() == &self->m_secondPage )
-               {
-                       self->m_secondPage.OnAddRegistrationDomain( decoded );
-               }
-
-               self->m_regDomains.push_back( decoded );
-       }
-       else
-       {
-               if ( self->GetActivePage() == &self->m_secondPage )
-               {
-                       self->m_secondPage.OnRemoveRegistrationDomain( decoded );
-               }
-
-               self->m_regDomains.remove( decoded );
-       }
-
-exit:
-
-       return;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigPropertySheet::WatchRegistry
-//---------------------------------------------------------------------------------------------------------------------------
-
-unsigned WINAPI
-CConfigPropertySheet::WatchRegistry ( LPVOID inParam )
-{
-       bool done = false;
-
-       CConfigPropertySheet * self = reinterpret_cast<CConfigPropertySheet*>(inParam);
-       check( self );
-
-       while ( !done )
-       {
-               RegNotifyChangeKeyValue( self->m_statusKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, NULL, FALSE );
-
-               EnterCriticalSection( &self->m_lock );
-
-               done = ( self->m_statusKey == NULL ) ? true : false;
-
-               if ( !done )
-               {
-                       self->PostMessage( WM_REGISTRYCHANGED, 0, 0 );
-               }
-
-               LeaveCriticalSection( &self->m_lock );
-       }
-
-       SetEvent( self->m_threadExited );
-
-       return 0;
-}
index 00dd137d032ed8c8eb4c8bfcb5e0bca9efbd42c5..9e4fda81c5fad0fbfc4cb223e890378c64deddcd 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: ConfigPropertySheet.h,v $
-Revision 1.7  2009/07/01 19:20:37  herscher
-<rdar://problem/6713286> UI changes for configuring sleep proxy settings.
-
-Revision 1.6  2009/03/30 19:58:47  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.5  2006/08/14 23:25:28  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.4  2005/03/03 19:55:21  shersche
-<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-
-
-*/
+ */
 
 #ifndef _ConfigPropertySheet_h
 #define _ConfigPropertySheet_h
 
 #include "stdafx.h"
-#include "FirstPage.h"
-#include "SecondPage.h"
-#include "ThirdPage.h"
-#include "FourthPage.h"
+#include "ServicesPage.h"
+#include "RegistrationPage.h"
+#include "BrowsingPage.h"
 
 #include <RegNames.h>
 #include <dns_sd.h>
@@ -61,14 +42,12 @@ public:
        typedef std::list<CString> StringList;
 
        StringList      m_browseDomains;
-       StringList      m_regDomains;
 
 protected:
 
-       CFirstPage      m_firstPage;
-       CSecondPage     m_secondPage;
-       CThirdPage m_thirdPage;
-       CFourthPage m_fourthPage;
+       CServicesPage           m_firstPage;
+       CRegistrationPage       m_secondPage;
+       CBrowsingPage           m_thirdPage;
 
        //{{AFX_VIRTUAL(CConfigPropertySheet)
        //}}AFX_VIRTUAL
@@ -93,18 +72,9 @@ private:
        OSStatus
        TearDownBrowsing();
 
-       OSStatus
-       SetupRegistryNotifications();
-
-       OSStatus
-       TearDownRegistryNotifications();
-
        OSStatus
        DecodeDomainName( const char * raw, CString & decoded );
 
-       const char*
-       GetNextLabel( const char * cstr, char label[64] );
-
        static void DNSSD_API
        BrowseDomainsReply
                                (
@@ -116,17 +86,6 @@ private:
                                void                            *       context
                                );
 
-       static void DNSSD_API
-       RegDomainsReply
-                               (
-                               DNSServiceRef                   sdRef,
-                               DNSServiceFlags                 flags,
-                               uint32_t                                interfaceIndex,
-                               DNSServiceErrorType             errorCode,
-                               const char                      *       replyDomain,
-                               void                            *       context
-                               );
-
        // This thread will watch for registry changes
 
        static unsigned WINAPI
@@ -139,7 +98,6 @@ private:
        HANDLE                          m_thread;
        HANDLE                          m_threadExited;
        DNSServiceRef           m_browseDomainsRef;
-       DNSServiceRef           m_regDomainsRef;
        CRITICAL_SECTION        m_lock;
 };
 
index fb85d9a1c78863312b9b6362cfcb98ed7e6b6538..4bf5df375322bde0783f18344dde592f28c797bf 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: ControlPanel.cpp,v $
-Revision 1.5  2009/03/30 20:00:19  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.4  2007/04/27 20:42:11  herscher
-<rdar://problem/5078828> mDNS: Bonjour Control Panel for Windows doesn't work on Vista
-
-Revision 1.3  2006/08/14 23:25:28  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2005/03/03 19:55:22  shersche
-<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-
-
-*/
+ */
 
     
 #include "ControlPanel.h"
index efb5c3b2fb79766f0d5e15e84e92ad5d41628f89..3cb05eb421f53fb0b085d4dd8696c1ecf857bd89 100644 (file)
 ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ; See the License for the specific language governing permissions and
 ; limitations under the License.
-;
-;  Change History (most recent first):
-;
-;  $Log: ControlPanel.def,v $
-;  Revision 1.4  2006/08/14 23:25:28  cheshire
-;  Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-;
-;  Revision 1.3  2005/03/03 19:55:22  shersche
-;  <rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-;
-;
-;
     
 LIBRARY        "Bonjour"
 
index 926ba94d0e946a4da9764b3c5537da47d5359295..dec5e58378985e055572c2d7afcec31a3bdd52fc 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: ControlPanel.h,v $
-Revision 1.3  2006/08/14 23:25:28  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2005/03/03 19:55:21  shersche
-<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-
-
-*/
+ */
 
     
 #pragma once
index 035b0d14f469740de11596850cb311b89e0bd0f9..1df3e9009396cc70699f820ef871fb09b5337cb5 100644 (file)
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.h"
-#include "WinVersRes.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE 
-BEGIN
-    "resource.h\0"
-END
-
-2 TEXTINCLUDE 
-BEGIN
-    "#include ""afxres.h""\r\n"
-    "\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"
-    "#ifdef _WIN32\r\n"
-    "LANGUAGE 9, 1\r\n"
-    "#pragma code_page(1252)\r\n"
-    "#endif\r\n"
-    "#include ""res\\ControlPanel.rc2""  // non-Microsoft Visual C++ edited resources\r\n"
-    "#include ""afxres.rc""         // Standard components\r\n"
-    "#endif\0"
-END
-
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDR_APPLET              ICON                    "res\\controlpanel.ico"
-IDI_FAILURE             ICON                    "res\\failure.ico"
-IDI_SUCCESS             ICON                    "res\\success.ico"
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Dialog
-//
-
-IDR_APPLET_PAGE1 DIALOGEX 0, 0, 262, 140
-STYLE DS_SETFONT | WS_CHILD | WS_CAPTION
-CAPTION "Hostname"
-FONT 8, "MS Sans Serif", 0, 0, 0x0
-BEGIN
-    LTEXT           "Enter a hostname for this computer. Other computers on the Internet will be able to reach your computer using this hostname.",
-                    IDC_STATIC,10,19,245,28
-    LTEXT           "Hostname:",IDC_STATIC,13,55,35,8
-    EDITTEXT        IDC_EDIT1,55,53,184,14,ES_AUTOHSCROLL
-    PUSHBUTTON      "Password...",IDC_BUTTON1,55,72,65,14
-    ICON            IDI_FAILURE,IDC_FAILURE,240,50,20,20,SS_CENTERIMAGE | 
-                    SS_REALSIZEIMAGE
-    ICON            IDI_SUCCESS,IDC_SUCCESS,240,50,20,20,SS_CENTERIMAGE | 
-                    SS_REALSIZEIMAGE | NOT WS_VISIBLE
-END
-
-IDR_APPLET_PAGE2 DIALOGEX 0, 0, 262, 140
-STYLE DS_SETFONT | WS_CHILD | WS_CAPTION
-CAPTION "Registration"
-FONT 8, "MS Sans Serif", 0, 0, 0x0
-BEGIN
-    CONTROL         "Domain:",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | 
-                    WS_TABSTOP,13,54,41,10
-    COMBOBOX        IDC_COMBO2,55,53,193,46,CBS_DROPDOWN | CBS_SORT | 
-                    WS_DISABLED | WS_VSCROLL | WS_TABSTOP
-    PUSHBUTTON      "Password...",IDC_BUTTON1,55,72,65,14
-    LTEXT           "Check the box and enter a registration domain to enable Bonjour advertising beyond the local subnet. ",
-                    IDC_STATIC,10,19,233,23
-END
-
-IDR_SECRET DIALOGEX 0, 0, 251, 90
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | 
-    WS_SYSMENU
-CAPTION "Password"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
-    DEFPUSHBUTTON   "OK",IDOK,139,69,50,14
-    PUSHBUTTON      "Cancel",IDCANCEL,194,69,50,14
-    LTEXT           "Name:",IDC_STATIC,9,28,22,8
-    EDITTEXT        IDC_KEY,49,26,195,14,ES_AUTOHSCROLL
-    LTEXT           "Password:",IDC_STATIC,9,44,32,8
-    EDITTEXT        IDC_SECRET,49,42,195,14,ES_PASSWORD | ES_AUTOHSCROLL
-    LTEXT           "Enter a Password if your DNS server requires authentication.",
-                    IDC_STATIC,7,7,237,15
-END
-
-IDR_APPLET_PAGE3 DIALOGEX 0, 0, 262, 140
-STYLE DS_SETFONT | WS_CHILD | WS_CAPTION
-CAPTION "Browsing"
-FONT 8, "MS Sans Serif", 0, 0, 0x0
-BEGIN
-    LTEXT           "Choose which domains to browse using Wide-Area Bonjour",
-                    -1,7,16,248,12
-    CONTROL         "",IDC_BROWSE_LIST,"SysListView32",LVS_REPORT | 
-                    LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | 
-                    WS_TABSTOP,7,37,248,57
-    PUSHBUTTON      "Add",IDC_ADD_BROWSE_DOMAIN,152,100,50,14
-    PUSHBUTTON      "Remove",IDC_REMOVE_BROWSE_DOMAIN,205,100,50,14
-END
-
-IDR_APPLET_PAGE4 DIALOGEX 0, 0, 262, 140
-STYLE DS_SETFONT | WS_CHILD | WS_CAPTION
-CAPTION "Power Management"
-FONT 8, "MS Sans Serif", 0, 0, 0x0
-BEGIN
-    CONTROL         "Allow Bonjour to wake this machine on network access.",IDC_POWER_MANAGEMENT,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,19,199,8
-    LTEXT           "Warning: Allowing Bonjour to bring the computer out of standby may cause this computer to periodically wakeup to refresh its network state.",IDC_STATIC,13,41,227,20
-END
-
-IDR_ADD_BROWSE_DOMAIN DIALOGEX 0, 0, 230, 95
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | 
-    WS_SYSMENU
-CAPTION "Add Browse Domain"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
-    DEFPUSHBUTTON   "OK",IDOK,117,74,50,14
-    PUSHBUTTON      "Cancel",IDCANCEL,173,74,50,14
-    COMBOBOX        IDC_COMBO1,35,42,188,100,CBS_DROPDOWN | CBS_SORT | 
-                    WS_VSCROLL | WS_TABSTOP
-    LTEXT           "Domain:",IDC_STATIC,7,43,27,8
-    LTEXT           "The following domain will be added to your list of Bonjour browse domains.",
-                    IDC_STATIC,7,15,216,16
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// DESIGNINFO
-//
-
-#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO 
-BEGIN
-    IDR_APPLET_PAGE1, DIALOG
-    BEGIN
-        LEFTMARGIN, 7
-        RIGHTMARGIN, 255
-        TOPMARGIN, 7
-        BOTTOMMARGIN, 133
-    END
-
-    IDR_APPLET_PAGE2, DIALOG
-    BEGIN
-        LEFTMARGIN, 7
-        RIGHTMARGIN, 255
-        TOPMARGIN, 7
-        BOTTOMMARGIN, 133
-    END
-
-    IDR_SECRET, DIALOG
-    BEGIN
-        LEFTMARGIN, 7
-        RIGHTMARGIN, 244
-        TOPMARGIN, 7
-        BOTTOMMARGIN, 83
-    END
-
-    IDR_APPLET_PAGE3, DIALOG
-    BEGIN
-        LEFTMARGIN, 7
-        RIGHTMARGIN, 255
-        TOPMARGIN, 7
-        BOTTOMMARGIN, 133
-    END
-
-    IDR_ADD_BROWSE_DOMAIN, DIALOG
-    BEGIN
-        LEFTMARGIN, 7
-        RIGHTMARGIN, 223
-        TOPMARGIN, 7
-        BOTTOMMARGIN, 88
-    END
-END
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// String Table
-//
-
-STRINGTABLE 
-BEGIN
-    IDR_APPLET              "Bonjour"
-    IDS_APPLET_DESCRIPTION  "Wide-Area Bonjour Control Panel"
-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)
-#ifdef _WIN32
-LANGUAGE 9, 1
-#pragma code_page(1252)
-#endif
-#include "res\ControlPanel.rc2"  // non-Microsoft Visual C++ edited resources
-#include "afxres.rc"         // Standard components
-#endif
-/////////////////////////////////////////////////////////////////////////////
-#endif    // not APSTUDIO_INVOKED
-
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+#include "WinVersRes.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+    "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+    "#include ""afxres.h""\r\n"\r
+    "#include ""WinVersRes.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
+    "#define _AFX_NO_OLE_RESOURCES\r\n"\r
+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
+    "\r\n"\r
+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
+    "LANGUAGE 9, 1\r\n"\r
+    "#pragma code_page(1252)\r\n"\r
+    "#include ""afxres.rc""     // Standard components\r\n"\r
+    "#endif\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Icon\r
+//\r
+\r
+// Icon with lowest ID value placed first to ensure application icon\r
+// remains consistent on all systems.\r
+IDR_APPLET              ICON                    "res\\controlpanel.ico"\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION MASTER_PROD_VERS\r
+ PRODUCTVERSION MASTER_PROD_VERS\r
+ FILEFLAGSMASK 0x3fL\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x2L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+        BLOCK "040904b0"\r
+        BEGIN\r
+            VALUE "CompanyName", MASTER_COMPANY_NAME\r
+            VALUE "FileDescription", "Bonjour Control Panel"\r
+            VALUE "FileVersion", MASTER_PROD_VERS_STR\r
+            VALUE "InternalName", "ControlPanel.cpl"\r
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
+            VALUE "OriginalFilename", "ControlPanel.cpl"\r
+            VALUE "ProductName", MASTER_PROD_NAME\r
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+        VALUE "Translation", 0x409, 1200\r
+    END\r
+END\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// String Table\r
+//\r
+\r
+STRINGTABLE\r
+BEGIN\r
+       IDS_REINSTALL    "Bonjour Control Panel cannot run because some of its required files are missing.  Please reinstall Bonjour Control Panel."\r
+       IDS_REINSTALL_CAPTION "Bonjour"\r
+END\r
+#endif    // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+#define _AFX_NO_SPLITTER_RESOURCES\r
+#define _AFX_NO_OLE_RESOURCES\r
+#define _AFX_NO_TRACKER_RESOURCES\r
+#define _AFX_NO_PROPERTY_RESOURCES\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 9, 1\r
+#pragma code_page(1252)\r
+#include "afxres.rc"     // Standard components\r
+#endif\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
+\r
index ffdb6ffd91ec41de0a6be7d37f03369542ddc8d8..2f2d0ab0cdccc33e6d755bc5d5460908954703d5 100755 (executable)
@@ -3,7 +3,8 @@
        ProjectType="Visual C++"\r
        Version="8.00"\r
        Name="ControlPanel"\r
-       ProjectGUID="{F5D703B6-5612-4381-8BE2-2B7AEBAE58FC}"\r
+       ProjectGUID="{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}"\r
+       RootNamespace="ControlPanel"\r
        Keyword="MFCProj"\r
        >\r
        <Platforms>\r
@@ -19,9 +20,9 @@
        <Configurations>\r
                <Configuration\r
                        Name="Debug|Win32"\r
-                       OutputDirectory="DLLBuild\$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="DLLBuild\$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
                        InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
                        UseOfMFC="1"\r
                        ATLMinimizesCRunTimeLibraryUsage="false"\r
                        <Tool\r
                                Name="VCMIDLTool"\r
                                PreprocessorDefinitions="_DEBUG"\r
-                               MkTypLibCompatible="true"\r
-                               SuppressStartupBanner="true"\r
-                               TargetEnvironment="1"\r
-                               TypeLibraryName=".\Debug/ControlPanel.tlb"\r
-                               HeaderFileName=""\r
+                               MkTypLibCompatible="false"\r
                        />\r
                        <Tool\r
                                Name="VCCLCompilerTool"\r
                                Optimization="0"\r
-                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
+                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared;../../Clients"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
+                               StringPooling="true"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
                                RuntimeLibrary="1"\r
                                UsePrecompiledHeader="0"\r
                                PrecompiledHeaderThrough=""\r
@@ -63,6 +63,7 @@
                                SuppressStartupBanner="true"\r
                                Detect64BitPortabilityProblems="true"\r
                                DebugInformationFormat="3"\r
+                               CallingConvention="0"\r
                                DisableSpecificWarnings="4311;4312"\r
                        />\r
                        <Tool\r
                        <Tool\r
                                Name="VCLinkerTool"\r
                                AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
-                               AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib"\r
-                               OutputFile="$(OutDir)/Bonjour.cpl"\r
+                               AdditionalDependencies="../DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib"\r
+                               OutputFile="$(OutDir)/ControlPanel.exe"\r
                                LinkIncremental="2"\r
                                SuppressStartupBanner="true"\r
-                               ModuleDefinitionFile=".\ControlPanel.def"\r
                                GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile=".\$(IntDir)\ControlPanel.pdb"\r
+                               ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
                                SubSystem="2"\r
-                               ImportLibrary=".\$(OutDir)\Bonjour.lib"\r
+                               EntryPointSymbol="wWinMainCRTStartup"\r
                                TargetMachine="1"\r
                        />\r
                        <Tool\r
                </Configuration>\r
                <Configuration\r
                        Name="Debug|x64"\r
-                       OutputDirectory="DLLBuild\$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="DLLBuild\$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
                        InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
                        UseOfMFC="1"\r
                        ATLMinimizesCRunTimeLibraryUsage="false"\r
                        <Tool\r
                                Name="VCMIDLTool"\r
                                PreprocessorDefinitions="_DEBUG"\r
-                               MkTypLibCompatible="true"\r
-                               SuppressStartupBanner="true"\r
+                               MkTypLibCompatible="false"\r
                                TargetEnvironment="3"\r
-                               TypeLibraryName=".\Debug/ControlPanel.tlb"\r
-                               HeaderFileName=""\r
                        />\r
                        <Tool\r
                                Name="VCCLCompilerTool"\r
                                Optimization="0"\r
-                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;_USRDLL;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
+                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared;../../Clients"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
+                               StringPooling="true"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
                                RuntimeLibrary="1"\r
                                UsePrecompiledHeader="0"\r
                                PrecompiledHeaderThrough=""\r
                                SuppressStartupBanner="true"\r
                                Detect64BitPortabilityProblems="true"\r
                                DebugInformationFormat="3"\r
+                               CallingConvention="0"\r
                                DisableSpecificWarnings="4311;4312"\r
                        />\r
                        <Tool\r
                        <Tool\r
                                Name="VCLinkerTool"\r
                                AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
-                               AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib"\r
-                               OutputFile="$(OutDir)/Bonjour.cpl"\r
+                               AdditionalDependencies="../DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib"\r
+                               OutputFile="$(OutDir)/ControlPanel.exe"\r
                                LinkIncremental="2"\r
                                SuppressStartupBanner="true"\r
-                               ModuleDefinitionFile=".\ControlPanel.def"\r
                                GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile=".\$(IntDir)\ControlPanel.pdb"\r
+                               ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
                                SubSystem="2"\r
-                               ImportLibrary=".\$(OutDir)\Bonjour.lib"\r
+                               EntryPointSymbol="wWinMainCRTStartup"\r
                                TargetMachine="17"\r
                        />\r
                        <Tool\r
                </Configuration>\r
                <Configuration\r
                        Name="Release|Win32"\r
-                       OutputDirectory="DLLBuild\$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="DLLBuild\$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
                        InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
                        UseOfMFC="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
+                       CharacterSet="2"\r
                        >\r
                        <Tool\r
                                Name="VCPreBuildEventTool"\r
                        <Tool\r
                                Name="VCMIDLTool"\r
                                PreprocessorDefinitions="NDEBUG"\r
-                               MkTypLibCompatible="true"\r
-                               SuppressStartupBanner="true"\r
-                               TargetEnvironment="1"\r
-                               TypeLibraryName=".\Release/ControlPanel.tlb"\r
-                               HeaderFileName=""\r
+                               MkTypLibCompatible="false"\r
                        />\r
                        <Tool\r
                                Name="VCCLCompilerTool"\r
                                Optimization="2"\r
                                InlineFunctionExpansion="1"\r
-                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
+                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared;../../Clients"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
                                StringPooling="true"\r
+                               MinimalRebuild="false"\r
                                RuntimeLibrary="0"\r
                                EnableFunctionLevelLinking="true"\r
+                               TreatWChar_tAsBuiltInType="true"\r
                                UsePrecompiledHeader="0"\r
                                AssemblerListingLocation="$(IntDir)\"\r
                                ObjectFile="$(IntDir)\"\r
                        <Tool\r
                                Name="VCLinkerTool"\r
                                AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
-                               AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib"\r
-                               OutputFile="$(OutDir)/Bonjour.cpl"\r
+                               AdditionalDependencies="../DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib"\r
+                               OutputFile="$(OutDir)/ControlPanel.exe"\r
                                LinkIncremental="1"\r
                                SuppressStartupBanner="true"\r
-                               ModuleDefinitionFile=".\ControlPanel.def"\r
-                               ProgramDatabaseFile=".\$(IntDir)\ControlPanel.pdb"\r
+                               ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
                                SubSystem="2"\r
-                               ImportLibrary=".\$(OutDir)\Bonjour.lib"\r
+                               OptimizeReferences="0"\r
+                               EnableCOMDATFolding="0"\r
+                               EntryPointSymbol="wWinMainCRTStartup"\r
                                TargetMachine="1"\r
                        />\r
                        <Tool\r
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                  &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
                <Configuration\r
                        Name="Release|x64"\r
-                       OutputDirectory="DLLBuild\$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="DLLBuild\$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="1"\r
                        InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
                        UseOfMFC="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
+                       CharacterSet="2"\r
                        >\r
                        <Tool\r
                                Name="VCPreBuildEventTool"\r
                        <Tool\r
                                Name="VCMIDLTool"\r
                                PreprocessorDefinitions="NDEBUG"\r
-                               MkTypLibCompatible="true"\r
-                               SuppressStartupBanner="true"\r
+                               MkTypLibCompatible="false"\r
                                TargetEnvironment="3"\r
-                               TypeLibraryName=".\Release/ControlPanel.tlb"\r
-                               HeaderFileName=""\r
                        />\r
                        <Tool\r
                                Name="VCCLCompilerTool"\r
                                Optimization="2"\r
                                InlineFunctionExpansion="1"\r
-                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
+                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared;../../Clients"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
                                StringPooling="true"\r
+                               MinimalRebuild="false"\r
                                RuntimeLibrary="0"\r
                                EnableFunctionLevelLinking="true"\r
+                               TreatWChar_tAsBuiltInType="true"\r
                                UsePrecompiledHeader="0"\r
                                AssemblerListingLocation="$(IntDir)\"\r
                                ObjectFile="$(IntDir)\"\r
                        <Tool\r
                                Name="VCLinkerTool"\r
                                AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
-                               AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib"\r
-                               OutputFile="$(OutDir)/Bonjour.cpl"\r
+                               AdditionalDependencies="../DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib"\r
+                               OutputFile="$(OutDir)/ControlPanel.exe"\r
                                LinkIncremental="1"\r
                                SuppressStartupBanner="true"\r
-                               ModuleDefinitionFile=".\ControlPanel.def"\r
-                               ProgramDatabaseFile=".\$(IntDir)\ControlPanel.pdb"\r
+                               ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
                                SubSystem="2"\r
-                               ImportLibrary=".\$(OutDir)\Bonjour.lib"\r
+                               OptimizeReferences="0"\r
+                               EnableCOMDATFolding="0"\r
+                               EntryPointSymbol="wWinMainCRTStartup"\r
                                TargetMachine="17"\r
                        />\r
                        <Tool\r
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                  &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
        </Configurations>\r
                                </FileConfiguration>\r
                        </File>\r
                        <File\r
-                               RelativePath="ControlPanel.cpp"\r
+                               RelativePath=".\ControlPanelExe.cpp"\r
                                >\r
-                               <FileConfiguration\r
-                                       Name="Debug|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Debug|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
                        </File>\r
                        <File\r
-                               RelativePath="ControlPanel.def"\r
+                               RelativePath=".\ServicesPage.cpp"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath="FirstPage.cpp"\r
+                               RelativePath="RegistrationPage.cpp"\r
                                >\r
                                <FileConfiguration\r
                                        Name="Debug|Win32"\r
                                </FileConfiguration>\r
                        </File>\r
                        <File\r
-                               RelativePath=".\FourthPage.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="SecondPage.cpp"\r
-                               >\r
-                               <FileConfiguration\r
-                                       Name="Debug|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Debug|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                       </File>\r
-                       <File\r
-                               RelativePath="SharedSecret.cpp"\r
+                               RelativePath="..\loclibrary.c"\r
                                >\r
                        </File>\r
                        <File\r
                                </FileConfiguration>\r
                        </File>\r
                        <File\r
-                               RelativePath="ThirdPage.cpp"\r
+                               RelativePath="BrowsingPage.cpp"\r
                                >\r
                        </File>\r
                </Filter>\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath="ControlPanel.h"\r
+                               RelativePath=".\ControlPanelExe.h"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath="FirstPage.h"\r
+                               RelativePath=".\ServicesPage.h"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\FourthPage.h"\r
+                               RelativePath="RegistrationPage.h"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath="Resource.h"\r
+                               RelativePath="..\loclibrary.h"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath="SecondPage.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="SharedSecret.h"\r
+                               RelativePath="Resource.h"\r
                                >\r
                        </File>\r
                        <File\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath="ThirdPage.h"\r
+                               RelativePath="BrowsingPage.h"\r
                                >\r
                        </File>\r
                </Filter>\r
                                RelativePath="res\controlpanel.ico"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\ControlPanel.rc"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath=".\res\ControlPanel.rc2"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath=".\ControlPanelDll.rc"\r
+                               RelativePath=".\res\EnergySaver.ico"\r
                                >\r
                        </File>\r
                        <File\r
                <Filter\r
                        Name="Support"\r
                        >\r
+                       <File\r
+                               RelativePath="..\..\Clients\ClientCommon.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\Clients\ClientCommon.h"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath="..\..\mDNSShared\CommonServices.h"\r
                                >\r
                </Filter>\r
        </Files>\r
        <Globals>\r
-               <Global\r
-                       Name="RESOURCE_FILE"\r
-                       Value="ControlPanelDll.rc"\r
-               />\r
        </Globals>\r
 </VisualStudioProject>\r
index b3300745ebad1934714f60a3af36f5bd39075845..36447d11ddc2f2b5718c00c52e33b207c856db52 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: ControlPanelExe.cpp,v $
-Revision 1.3  2007/04/27 21:43:00  herscher
-Update license info to Apache License, Version 2.0
-
-Revision 1.2  2007/04/27 20:42:12  herscher
-<rdar://problem/5078828> mDNS: Bonjour Control Panel for Windows doesn't work on Vista
-
-Revision 1.1.2.1  2007/04/27 18:13:55  herscher
-<rdar://problem/5078828> mDNS: Bonjour Control Panel for Windows doesn't work on Vista
-
-
-
-*/
+ */
 
     
 #include "ControlPanelExe.h"
@@ -37,6 +22,7 @@ Revision 1.1.2.1  2007/04/27 18:13:55  herscher
 #include "resource.h"
 
 #include <DebugServices.h>
+#include "loclibrary.h"
 
 
 #ifdef _DEBUG
@@ -45,17 +31,40 @@ Revision 1.1.2.1  2007/04/27 18:13:55  herscher
 static char THIS_FILE[] = __FILE__;
 #endif
 
+#ifndef HeapEnableTerminationOnCorruption
+#      define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS) 1
+#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;
+}
+
+
 //---------------------------------------------------------------------------------------------------------------------------
 //     Static Declarations
 //---------------------------------------------------------------------------------------------------------------------------
-DEFINE_GUID(CLSID_ControlPanel, \r
-0x1207552c, 0xe59, 0x4d9f, 0x85, 0x54, 0xf1, 0xf8, 0x6, 0xcd, 0x7f, 0xa9);\r
-\r
+DEFINE_GUID(CLSID_ControlPanel, 
+
+0x1207552c, 0xe59, 0x4d9f, 0x85, 0x54, 0xf1, 0xf8, 0x6, 0xcd, 0x7f, 0xa9);
+
 static LPCTSTR g_controlPanelGUID                      =       TEXT( "{1207552C-0E59-4d9f-8554-F1F806CD7FA9}" );
-static LPCTSTR g_controlPanelName                      =       TEXT( "Bonjour Control Panel" );
+static LPCTSTR g_controlPanelName                      =       TEXT( "Bonjour" );
+static LPCTSTR g_controlPanelCanonicalName     =       TEXT( "Apple.Bonjour" );
 static LPCTSTR g_controlPanelCategory          =       TEXT( "3,8" );
-static LPCTSTR g_controlPanelLocalizedName     =       g_controlPanelName;
-static LPCTSTR g_controlPanelInfoTip           =       TEXT( "Configures Wide-Area Bonjour" );
 
 static CCPApp theApp;
 
@@ -158,7 +167,7 @@ CCPApp::~CCPApp()
 
 
 void
-CCPApp::Register( LPCTSTR inClsidString, LPCTSTR inName, LPCTSTR inCategory, LPCTSTR inLocalizedName, LPCTSTR inInfoTip, LPCTSTR inIconPath, LPCTSTR inExePath )
+CCPApp::Register( LPCTSTR inClsidString, LPCTSTR inName, LPCTSTR inCanonicalName, LPCTSTR inCategory, LPCTSTR inLocalizedName, LPCTSTR inInfoTip, LPCTSTR inIconPath, LPCTSTR inExePath )
 {
        typedef struct  RegistryBuilder         RegistryBuilder;
        
@@ -180,7 +189,7 @@ CCPApp::Register( LPCTSTR inClsidString, LPCTSTR inName, LPCTSTR inCategory, LPC
        {
                { HKEY_LOCAL_MACHINE,   TEXT( "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace\\%s" ),  NULL,                                                                   REG_SZ,         inName },
                { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s" ),                                                                                                                                                    NULL,                                                                   NULL,           NULL },
-               { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s" ),                                                                                                                                                    TEXT( "System.ApplicationName" ),               REG_SZ,         inName },
+               { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s" ),                                                                                                                                                    TEXT( "System.ApplicationName" ),               REG_SZ,         inCanonicalName },
                { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s" ),                                                                                                                                                    TEXT( "System.ControlPanel.Category" ), REG_SZ,         inCategory },
                { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s" ),                                                                                                                                                    TEXT( "LocalizedString" ),                              REG_SZ,         inLocalizedName },
                { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s" ),                                                                                                                                                    TEXT( "InfoTip" ),                                              REG_SZ,         inInfoTip },
@@ -240,8 +249,43 @@ BOOL
 CCPApp::InitInstance()
 {
        CCommandLineInfo        commandLine;
+       wchar_t                         resource[MAX_PATH];
+       CString                         errorMessage;
+       CString                         errorCaption;
+       int                                     res;
        OSStatus                        err = kNoErr;
 
+       HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 );
+
+       //
+       // initialize the debugging framework
+       //
+       debug_initialize( kDebugOutputTypeWindowsDebugger, "ControlPanel", 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 );
+
+       res = PathForResource( NULL, L"ControlPanelResources.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"ControlPanelLocalized.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
        // visual styles.  Otherwise, any window creation will fail.
@@ -256,18 +300,25 @@ CCPApp::InitInstance()
 
        if ( commandLine.m_nShellCommand == CCommandLineInfo::AppRegister )
        {
+               CString         localizedName;
+               CString         toolTip;
                TCHAR           iconPath[ MAX_PATH + 12 ]       = TEXT( "" );
                TCHAR           exePath[ MAX_PATH ]                     = TEXT( "" );
                DWORD           nChars;
                OSStatus        err;
 
-               nChars = GetModuleFileName( NULL, exePath, sizeof_array( exePath ) );\r
-               err = translate_errno( nChars > 0, (OSStatus) GetLastError(), kUnknownErr );\r
+               nChars = GetModuleFileName( NULL, exePath, sizeof_array( exePath ) );
+
+               err = translate_errno( nChars > 0, (OSStatus) GetLastError(), kUnknownErr );
+
                require_noerr( err, exit );
 
                wsprintf( iconPath, L"%s,-%d", exePath, IDR_APPLET );
 
-               Register( g_controlPanelGUID, g_controlPanelName, g_controlPanelCategory, g_controlPanelName, g_controlPanelInfoTip, iconPath, exePath );
+               localizedName.LoadString( IDS_APPLET_NAME );
+               toolTip.LoadString( IDS_APPLET_TOOLTIP );
+
+               Register( g_controlPanelGUID, g_controlPanelName, g_controlPanelCanonicalName, g_controlPanelCategory, localizedName, toolTip, iconPath, exePath );
        }
        else if ( commandLine.m_nShellCommand == CCommandLineInfo::AppUnregister )
        {
@@ -311,6 +362,11 @@ CCPApp::InitInstance()
 
 exit:
 
+       if ( err )
+       {
+               MessageBox( NULL, errorMessage, errorCaption, MB_ICONERROR | MB_OK );
+       }
+
        // Since the dialog has been closed, return FALSE so that we exit the
        //  application, rather than start the application's message pump.
        return FALSE;
index 54bcd84d302b3dcb6075d8647fd15ae156e21a02..079422bb2a237aef581028cc19cf0395be75e8be 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: ControlPanelExe.h,v $
-Revision 1.3  2007/04/27 21:43:00  herscher
-Update license info to Apache License, Version 2.0
-
-Revision 1.2  2007/04/27 20:42:12  herscher
-<rdar://problem/5078828> mDNS: Bonjour Control Panel for Windows doesn't work on Vista
-
-Revision 1.1.2.1  2007/04/27 18:13:55  herscher
-<rdar://problem/5078828> mDNS: Bonjour Control Panel for Windows doesn't work on Vista
-
-
-*/
+ */
 
     
 #pragma once
 
-#include "stdafx.h"
+#include "stdafx.h"\r
 
+extern HINSTANCE       GetNonLocalizedResources();
+extern HINSTANCE       GetLocalizedResources();
 
 //-------------------------------------------------
 //     CCPApp
@@ -51,7 +39,7 @@ protected:
        virtual BOOL    InitInstance();
 
        void
-       Register( LPCTSTR inClsidString, LPCTSTR inName, LPCTSTR inCategory, LPCTSTR inLocalizedName, LPCTSTR inInfoTip, LPCTSTR inIconPath, LPCTSTR inExePath );
+       Register( LPCTSTR inClsidString, LPCTSTR inName, LPCTSTR inCanonicalName, LPCTSTR inCategory, LPCTSTR inLocalizedName, LPCTSTR inInfoTip, LPCTSTR inIconPath, LPCTSTR inExePath );
 
        void
        Unregister( LPCTSTR clsidString );
index c97f43045be6d73bd4d104ad7c43486182f34e23..8bc0b29b8099cd794993936919a5d4746c9594aa 100755 (executable)
                                RelativePath=".\ControlPanelExe.cpp"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\FifthPage.cpp"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath="FirstPage.cpp"\r
                                >\r
                                RelativePath=".\ControlPanelExe.h"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\FifthPage.h"\r
+                               >\r
+                       </File>\r
                        <File\r
                                RelativePath="FirstPage.h"\r
                                >\r
diff --git a/mDNSWindows/ControlPanel/ControlPanelLocRes.rc b/mDNSWindows/ControlPanel/ControlPanelLocRes.rc
new file mode 100755 (executable)
index 0000000..4ba22b4
--- /dev/null
@@ -0,0 +1,270 @@
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+#include "WinVersRes.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+    "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+    "#include ""afxres.h""\r\n"\r
+    "#include ""WinVersRes.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
+    "#define _AFX_NO_OLE_RESOURCES\r\n"\r
+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
+    "\r\n"\r
+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
+    "LANGUAGE 9, 1\r\n"\r
+    "#pragma code_page(1252)\r\n"\r
+    "#include ""afxres.rc""     // Standard components\r\n"\r
+    "#endif\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION MASTER_PROD_VERS\r
+ PRODUCTVERSION MASTER_PROD_VERS\r
+ FILEFLAGSMASK 0x3fL\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x2L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+        BLOCK "040904b0"\r
+        BEGIN\r
+            VALUE "CompanyName", MASTER_COMPANY_NAME\r
+            VALUE "FileDescription", "Bonjour Resource Module"\r
+            VALUE "FileVersion", MASTER_PROD_VERS_STR\r
+            VALUE "InternalName", "ControlPanelLocalized.dll"\r
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
+            VALUE "OriginalFilename", "ControlPanelLocalized.dll"\r
+            VALUE "ProductName", MASTER_PROD_NAME\r
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+        VALUE "Translation", 0x409, 1200\r
+    END\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Dialog\r
+//\r
+\r
+IDR_APPLET_PAGE1 DIALOGEX 0, 0, 262, 140\r
+STYLE DS_SETFONT | WS_CHILD | WS_CAPTION\r
+CAPTION "Registration"\r
+FONT 8, "MS Sans Serif", 0, 0, 0x0\r
+BEGIN\r
+    LTEXT           "Hostname:",IDC_STATIC,13,22,35,8\r
+    EDITTEXT        IDC_HOSTNAME,55,20,184,12,ES_AUTOHSCROLL\r
+    LTEXT           "User:",IDC_STATIC,13,38,35,8\r
+    EDITTEXT        IDC_USERNAME,55,36,184,12,ES_AUTOHSCROLL\r
+    LTEXT           "Password:",IDC_STATIC,13,54,35,8\r
+    EDITTEXT        IDC_PASSWORD,55,52,184,12,ES_PASSWORD | ES_AUTOHSCROLL\r
+    CONTROL         "Advertise services in this domain using Bonjour",IDC_ADVERTISE_SERVICES,\r
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,55,80,199,8\r
+END\r
+\r
+IDR_APPLET_PAGE3 DIALOGEX 0, 0, 262, 140\r
+STYLE DS_SETFONT | WS_CHILD | WS_CAPTION\r
+CAPTION "Browsing"\r
+FONT 8, "MS Sans Serif", 0, 0, 0x0\r
+BEGIN\r
+    LTEXT           "Choose which domains to browse using wide-area Bonjour",\r
+                    -1,7,16,248,12\r
+    CONTROL         "",IDC_BROWSE_LIST,"SysListView32",LVS_REPORT | \r
+                    LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | \r
+                    WS_TABSTOP,7,37,248,57\r
+    PUSHBUTTON      "Add",IDC_ADD_BROWSE_DOMAIN,152,100,50,14\r
+    PUSHBUTTON      "Remove",IDC_REMOVE_BROWSE_DOMAIN,205,100,50,14\r
+END\r
+\r
+IDR_APPLET_PAGE5 DIALOGEX 0, 0, 262, 140\r
+STYLE DS_SETFONT | WS_CHILD | WS_CAPTION\r
+CAPTION "Services"\r
+FONT 8, "MS Sans Serif", 0, 0, 0x0\r
+BEGIN\r
+    CONTROL         "Advertise shared folders using Bonjour",IDC_ADVERTISE_SMB,\r
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,19,199,8\r
+    CONTROL         "Enable Wake on Demand",IDC_POWER_MANAGEMENT,\r
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,34,199,8\r
+END\r
+\r
+IDR_POWER_MANAGEMENT_WARNING DIALOGEX 0, 0, 230, 95\r
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | \r
+    WS_SYSMENU\r
+CAPTION "Power Management"\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+    DEFPUSHBUTTON   "OK",IDOK,173,74,50,14\r
+    LTEXT           "When 'Wake On Demand' is enabled, you may hear your computer wake up occasionally.",\r
+                                       IDC_STATIC,50,12,175,26\r
+    LTEXT           "This informs other devices that your computer is still available on the network.",\r
+                    IDC_STATIC,50,38,175,26\r
+    ICON            IDI_ENERGY_SAVER,IDC_ENERGY_SAVER,2,10,64,64,SS_REALSIZEIMAGE\r
+END\r
+\r
+IDR_ADD_BROWSE_DOMAIN DIALOGEX 0, 0, 230, 95\r
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | \r
+    WS_SYSMENU\r
+CAPTION "Add Browse Domain"\r
+FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
+BEGIN\r
+    DEFPUSHBUTTON   "OK",IDOK,117,74,50,14\r
+    PUSHBUTTON      "Cancel",IDCANCEL,173,74,50,14\r
+    COMBOBOX        IDC_COMBO1,35,42,188,100,CBS_DROPDOWN | CBS_SORT | \r
+                    WS_VSCROLL | WS_TABSTOP\r
+    LTEXT           "Domain:",IDC_STATIC,7,43,27,8\r
+    LTEXT           "The following domain will be added to your list of Bonjour browse domains.",\r
+                    IDC_STATIC,7,15,216,16\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// DESIGNINFO\r
+//\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+GUIDELINES DESIGNINFO \r
+BEGIN\r
+    IDR_APPLET_PAGE1, DIALOG\r
+    BEGIN\r
+        LEFTMARGIN, 7\r
+        RIGHTMARGIN, 255\r
+        TOPMARGIN, 7\r
+        BOTTOMMARGIN, 133\r
+    END\r
+\r
+    IDR_APPLET_PAGE2, DIALOG\r
+    BEGIN\r
+        LEFTMARGIN, 7\r
+        RIGHTMARGIN, 255\r
+        TOPMARGIN, 7\r
+        BOTTOMMARGIN, 133\r
+    END\r
+\r
+    IDR_SECRET, DIALOG\r
+    BEGIN\r
+        LEFTMARGIN, 7\r
+        RIGHTMARGIN, 244\r
+        TOPMARGIN, 7\r
+        BOTTOMMARGIN, 83\r
+    END\r
+\r
+    IDR_APPLET_PAGE3, DIALOG\r
+    BEGIN\r
+        LEFTMARGIN, 7\r
+        RIGHTMARGIN, 255\r
+        TOPMARGIN, 7\r
+        BOTTOMMARGIN, 133\r
+    END\r
+\r
+       IDR_POWER_MANAGEMENT_WARNING, DIALOG\r
+       BEGIN\r
+               LEFTMARGIN, 7\r
+               RIGHTMARGIN, 223\r
+               TOPMARGIN, 7,\r
+               BOTTOMMARGIN, 88\r
+       END\r
+\r
+    IDR_ADD_BROWSE_DOMAIN, DIALOG\r
+    BEGIN\r
+        LEFTMARGIN, 7\r
+        RIGHTMARGIN, 223\r
+        TOPMARGIN, 7\r
+        BOTTOMMARGIN, 88\r
+    END\r
+END\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// String Table\r
+//\r
+\r
+STRINGTABLE \r
+BEGIN\r
+    IDR_APPLET              "Bonjour"\r
+       IDS_APPLET_NAME                 "Bonjour"\r
+    IDS_APPLET_DESCRIPTION  "Bonjour"\r
+       IDS_APPLET_TOOLTIP              "Change Bonjour settings for this computer."\r
+END\r
+\r
+#endif    // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+#define _AFX_NO_SPLITTER_RESOURCES\r
+#define _AFX_NO_OLE_RESOURCES\r
+#define _AFX_NO_TRACKER_RESOURCES\r
+#define _AFX_NO_PROPERTY_RESOURCES\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 9, 1\r
+#pragma code_page(1252)\r
+#include "afxres.rc"     // Standard components\r
+#endif\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
+\r
diff --git a/mDNSWindows/ControlPanel/ControlPanelLocRes.vcproj b/mDNSWindows/ControlPanel/ControlPanelLocRes.vcproj
new file mode 100755 (executable)
index 0000000..cdcee9b
--- /dev/null
@@ -0,0 +1,487 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="ControlPanelLocRes"\r
+       ProjectGUID="{4490229E-025A-478F-A2CF-51154DA83E39}"\r
+       RootNamespace="ControlPanelLocRes"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+               <Platform\r
+                       Name="x64"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       UseOfMFC="1"\r
+                       ATLMinimizesCRunTimeLibraryUsage="false"\r
+                       CharacterSet="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               MkTypLibCompatible="true"\r
+                               SuppressStartupBanner="true"\r
+                               TargetEnvironment="1"\r
+                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".."\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"\r
+                               StringPooling="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               ForceConformanceInForLoopScope="true"\r
+                               UsePrecompiledHeader="0"\r
+                               PrecompiledHeaderFile=""\r
+                               AssemblerListingLocation=".\Debug/"\r
+                               ObjectFile=".\Debug/"\r
+                               ProgramDataBaseFileName=".\Debug/"\r
+                               BrowseInformation="1"\r
+                               WarningLevel="4"\r
+                               WarnAsError="false"\r
+                               SuppressStartupBanner="true"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CallingConvention="2"\r
+                               CompileAs="0"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories=".."\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                               Description="Building Output Directories"\r
+                               CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;if not exist $(OutDir)\ControlPanel.Resources\en.lproj mkdir $(OutDir)\ControlPanel.Resources\en.lproj&#x0D;&#x0A;"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
+                               AdditionalDependencies=""\r
+                               OutputFile="$(OutDir)\ControlPanel.Resources\en.lproj\ControlPanelLocalized.dll"\r
+                               LinkIncremental="1"\r
+                               SuppressStartupBanner="true"\r
+                               IgnoreDefaultLibraryNames=""\r
+                               ModuleDefinitionFile=""\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"\r
+                               SubSystem="2"\r
+                               ResourceOnlyDLL="true"\r
+                               ImportLibrary="$(OutDir)/$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Debug|x64"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       UseOfMFC="1"\r
+                       ATLMinimizesCRunTimeLibraryUsage="false"\r
+                       CharacterSet="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               MkTypLibCompatible="true"\r
+                               SuppressStartupBanner="true"\r
+                               TargetEnvironment="3"\r
+                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".."\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"\r
+                               StringPooling="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               ForceConformanceInForLoopScope="true"\r
+                               UsePrecompiledHeader="0"\r
+                               PrecompiledHeaderFile=""\r
+                               AssemblerListingLocation=".\Debug/"\r
+                               ObjectFile=".\Debug/"\r
+                               ProgramDataBaseFileName=".\Debug/"\r
+                               BrowseInformation="1"\r
+                               WarningLevel="4"\r
+                               WarnAsError="false"\r
+                               SuppressStartupBanner="true"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CallingConvention="2"\r
+                               CompileAs="0"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories=".."\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                               Description="Building Output Directories"\r
+                               CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;if not exist $(OutDir)\ControlPanel.Resources\en.lproj mkdir $(OutDir)\ControlPanel.Resources\en.lproj&#x0D;&#x0A;"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
+                               AdditionalDependencies=""\r
+                               OutputFile="$(OutDir)\ControlPanel.Resources\en.lproj\ControlPanelLocalized.dll"\r
+                               LinkIncremental="1"\r
+                               SuppressStartupBanner="true"\r
+                               IgnoreDefaultLibraryNames=""\r
+                               ModuleDefinitionFile=""\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"\r
+                               SubSystem="2"\r
+                               ResourceOnlyDLL="true"\r
+                               ImportLibrary="$(OutDir)/$(ProjectName).lib"\r
+                               TargetMachine="17"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       UseOfMFC="1"\r
+                       ATLMinimizesCRunTimeLibraryUsage="false"\r
+                       CharacterSet="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               MkTypLibCompatible="true"\r
+                               SuppressStartupBanner="true"\r
+                               TargetEnvironment="1"\r
+                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="2"\r
+                               InlineFunctionExpansion="2"\r
+                               FavorSizeOrSpeed="2"\r
+                               OmitFramePointers="true"\r
+                               AdditionalIncludeDirectories=".."\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"\r
+                               StringPooling="true"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               EnableFunctionLevelLinking="false"\r
+                               ForceConformanceInForLoopScope="true"\r
+                               UsePrecompiledHeader="0"\r
+                               PrecompiledHeaderFile=""\r
+                               AssemblerListingLocation=".\Release/"\r
+                               ObjectFile=".\Release/"\r
+                               ProgramDataBaseFileName=".\Release/"\r
+                               BrowseInformation="1"\r
+                               WarningLevel="4"\r
+                               WarnAsError="false"\r
+                               SuppressStartupBanner="true"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               CompileAs="0"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories=".."\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                               Description="Building Output Directories"\r
+                               CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;if not exist $(OutDir)\ControlPanel.Resources\en.lproj mkdir $(OutDir)\ControlPanel.Resources\en.lproj&#x0D;&#x0A;"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
+                               AdditionalDependencies=""\r
+                               OutputFile="$(OutDir)\ControlPanel.Resources\en.lproj\ControlPanelLocalized.dll"\r
+                               LinkIncremental="1"\r
+                               SuppressStartupBanner="true"\r
+                               IgnoreDefaultLibraryNames=""\r
+                               ModuleDefinitionFile=""\r
+                               ProgramDatabaseFile=""\r
+                               SubSystem="2"\r
+                               OptimizeReferences="0"\r
+                               EnableCOMDATFolding="0"\r
+                               ResourceOnlyDLL="true"\r
+                               ImportLibrary="$(IntDir)/$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                                          &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|x64"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       UseOfMFC="1"\r
+                       ATLMinimizesCRunTimeLibraryUsage="false"\r
+                       CharacterSet="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               MkTypLibCompatible="true"\r
+                               SuppressStartupBanner="true"\r
+                               TargetEnvironment="3"\r
+                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="2"\r
+                               InlineFunctionExpansion="2"\r
+                               FavorSizeOrSpeed="2"\r
+                               OmitFramePointers="true"\r
+                               AdditionalIncludeDirectories=".."\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"\r
+                               StringPooling="true"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               EnableFunctionLevelLinking="false"\r
+                               ForceConformanceInForLoopScope="true"\r
+                               UsePrecompiledHeader="0"\r
+                               PrecompiledHeaderFile=""\r
+                               AssemblerListingLocation=".\Release/"\r
+                               ObjectFile=".\Release/"\r
+                               ProgramDataBaseFileName=".\Release/"\r
+                               BrowseInformation="1"\r
+                               WarningLevel="4"\r
+                               WarnAsError="false"\r
+                               SuppressStartupBanner="true"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               CompileAs="0"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories=".."\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                               Description="Building Output Directories"\r
+                               CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;if not exist $(OutDir)\ControlPanel.Resources\en.lproj mkdir $(OutDir)\ControlPanel.Resources\en.lproj&#x0D;&#x0A;"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
+                               AdditionalDependencies=""\r
+                               OutputFile="$(OutDir)\ControlPanel.Resources\en.lproj\ControlPanelLocalized.dll"\r
+                               LinkIncremental="1"\r
+                               SuppressStartupBanner="true"\r
+                               IgnoreDefaultLibraryNames=""\r
+                               ModuleDefinitionFile=""\r
+                               ProgramDatabaseFile=""\r
+                               SubSystem="2"\r
+                               OptimizeReferences="0"\r
+                               EnableCOMDATFolding="0"\r
+                               ResourceOnlyDLL="true"\r
+                               ImportLibrary="$(IntDir)/$(ProjectName).lib"\r
+                               TargetMachine="17"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                                          &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc"\r
+                       >\r
+                       <File\r
+                               RelativePath="resource_loc_res.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest"\r
+                       >\r
+                       <File\r
+                               RelativePath="ControlPanelLocRes.rc"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+               <Global\r
+                       Name="RESOURCE_FILE"\r
+                       Value="ControlPanelLocRes.rc"\r
+               />\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/mDNSWindows/ControlPanel/ControlPanelRes.rc b/mDNSWindows/ControlPanel/ControlPanelRes.rc
new file mode 100755 (executable)
index 0000000..b74c59b
--- /dev/null
@@ -0,0 +1,134 @@
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+#include "WinVersRes.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+    "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+    "#include ""afxres.h""\r\n"\r
+    "#include ""WinVersRes.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
+    "#define _AFX_NO_OLE_RESOURCES\r\n"\r
+    "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
+    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
+    "\r\n"\r
+    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
+    "LANGUAGE 9, 1\r\n"\r
+    "#pragma code_page(1252)\r\n"\r
+    "#include ""afxres.rc""     // Standard components\r\n"\r
+    "#endif\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION MASTER_PROD_VERS\r
+ PRODUCTVERSION MASTER_PROD_VERS\r
+ FILEFLAGSMASK 0x3fL\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x2L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+        BLOCK "040904b0"\r
+        BEGIN\r
+            VALUE "CompanyName", MASTER_COMPANY_NAME\r
+            VALUE "FileDescription", "Bonjour Resource Module"\r
+            VALUE "FileVersion", MASTER_PROD_VERS_STR\r
+            VALUE "InternalName", "ControlPanelResources.dll"\r
+            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
+            VALUE "OriginalFilename", "ControlPanelResources.dll"\r
+            VALUE "ProductName", MASTER_PROD_NAME\r
+            VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+        VALUE "Translation", 0x409, 1200\r
+    END\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Icon\r
+//\r
+\r
+// Icon with lowest ID value placed first to ensure application icon\r
+// remains consistent on all systems.\r
+IDR_APPLET              ICON                    "res\\controlpanel.ico"\r
+IDI_FAILURE             ICON                    "res\\failure.ico"\r
+IDI_SUCCESS             ICON                    "res\\success.ico"\r
+IDI_ENERGY_SAVER       ICON                    "res\\EnergySaver.ico"\r
+#endif    // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+#define _AFX_NO_SPLITTER_RESOURCES\r
+#define _AFX_NO_OLE_RESOURCES\r
+#define _AFX_NO_TRACKER_RESOURCES\r
+#define _AFX_NO_PROPERTY_RESOURCES\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE 9, 1\r
+#pragma code_page(1252)\r
+#include "afxres.rc"     // Standard components\r
+#endif\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
+\r
diff --git a/mDNSWindows/ControlPanel/ControlPanelRes.vcproj b/mDNSWindows/ControlPanel/ControlPanelRes.vcproj
new file mode 100755 (executable)
index 0000000..3e36161
--- /dev/null
@@ -0,0 +1,518 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="ControlPanelRes"\r
+       ProjectGUID="{5254AA9C-3D2E-4539-86D9-5EB0F4151215}"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+               <Platform\r
+                       Name="x64"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       UseOfMFC="1"\r
+                       ATLMinimizesCRunTimeLibraryUsage="false"\r
+                       CharacterSet="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               MkTypLibCompatible="true"\r
+                               SuppressStartupBanner="true"\r
+                               TargetEnvironment="1"\r
+                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".."\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"\r
+                               StringPooling="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               ForceConformanceInForLoopScope="true"\r
+                               UsePrecompiledHeader="0"\r
+                               PrecompiledHeaderFile=""\r
+                               AssemblerListingLocation=".\Debug/"\r
+                               ObjectFile=".\Debug/"\r
+                               ProgramDataBaseFileName=".\Debug/"\r
+                               BrowseInformation="1"\r
+                               WarningLevel="4"\r
+                               WarnAsError="false"\r
+                               SuppressStartupBanner="true"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CallingConvention="2"\r
+                               CompileAs="0"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories=".."\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                               Description="Building Output Directories"\r
+                               CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
+                               OutputFile="$(OutDir)\ControlPanel.Resources\ControlPanelResources.dll"\r
+                               LinkIncremental="1"\r
+                               SuppressStartupBanner="true"\r
+                               IgnoreDefaultLibraryNames=""\r
+                               ModuleDefinitionFile=""\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"\r
+                               SubSystem="2"\r
+                               ResourceOnlyDLL="true"\r
+                               ImportLibrary="$(OutDir)/$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Debug|x64"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       UseOfMFC="1"\r
+                       ATLMinimizesCRunTimeLibraryUsage="false"\r
+                       CharacterSet="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               MkTypLibCompatible="true"\r
+                               SuppressStartupBanner="true"\r
+                               TargetEnvironment="3"\r
+                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories=".."\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"\r
+                               StringPooling="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               ForceConformanceInForLoopScope="true"\r
+                               UsePrecompiledHeader="0"\r
+                               PrecompiledHeaderFile=""\r
+                               AssemblerListingLocation=".\Debug/"\r
+                               ObjectFile=".\Debug/"\r
+                               ProgramDataBaseFileName=".\Debug/"\r
+                               BrowseInformation="1"\r
+                               WarningLevel="4"\r
+                               WarnAsError="false"\r
+                               SuppressStartupBanner="true"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                               CallingConvention="2"\r
+                               CompileAs="0"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="_DEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories=".."\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                               Description="Building Output Directories"\r
+                               CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
+                               OutputFile="$(OutDir)\ControlPanel.Resources\ControlPanelResources.dll"\r
+                               LinkIncremental="1"\r
+                               SuppressStartupBanner="true"\r
+                               IgnoreDefaultLibraryNames=""\r
+                               ModuleDefinitionFile=""\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"\r
+                               SubSystem="2"\r
+                               ResourceOnlyDLL="true"\r
+                               ImportLibrary="$(OutDir)/$(ProjectName).lib"\r
+                               TargetMachine="17"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       UseOfMFC="1"\r
+                       ATLMinimizesCRunTimeLibraryUsage="false"\r
+                       CharacterSet="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               MkTypLibCompatible="true"\r
+                               SuppressStartupBanner="true"\r
+                               TargetEnvironment="1"\r
+                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="2"\r
+                               InlineFunctionExpansion="2"\r
+                               FavorSizeOrSpeed="2"\r
+                               OmitFramePointers="true"\r
+                               AdditionalIncludeDirectories="..\..\mDNSShared;.."\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"\r
+                               StringPooling="true"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               EnableFunctionLevelLinking="false"\r
+                               ForceConformanceInForLoopScope="true"\r
+                               UsePrecompiledHeader="0"\r
+                               PrecompiledHeaderFile=""\r
+                               AssemblerListingLocation=".\Release/"\r
+                               ObjectFile=".\Release/"\r
+                               ProgramDataBaseFileName=".\Release/"\r
+                               BrowseInformation="1"\r
+                               WarningLevel="4"\r
+                               WarnAsError="false"\r
+                               SuppressStartupBanner="true"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               CompileAs="0"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories=".."\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                               Description="Building Output Directories"\r
+                               CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
+                               OutputFile="$(OutDir)\ControlPanel.Resources\ControlPanelResources.dll"\r
+                               LinkIncremental="1"\r
+                               SuppressStartupBanner="true"\r
+                               IgnoreDefaultLibraryNames=""\r
+                               ModuleDefinitionFile=""\r
+                               ProgramDatabaseFile=""\r
+                               SubSystem="2"\r
+                               OptimizeReferences="0"\r
+                               EnableCOMDATFolding="0"\r
+                               ResourceOnlyDLL="true"\r
+                               ImportLibrary="$(IntDir)/$(ProjectName).lib"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                            &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|x64"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       UseOfMFC="1"\r
+                       ATLMinimizesCRunTimeLibraryUsage="false"\r
+                       CharacterSet="1"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               MkTypLibCompatible="true"\r
+                               SuppressStartupBanner="true"\r
+                               TargetEnvironment="3"\r
+                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="2"\r
+                               InlineFunctionExpansion="2"\r
+                               FavorSizeOrSpeed="2"\r
+                               OmitFramePointers="true"\r
+                               AdditionalIncludeDirectories="..\..\mDNSShared;.."\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"\r
+                               StringPooling="true"\r
+                               RuntimeLibrary="0"\r
+                               BufferSecurityCheck="false"\r
+                               EnableFunctionLevelLinking="false"\r
+                               ForceConformanceInForLoopScope="true"\r
+                               UsePrecompiledHeader="0"\r
+                               PrecompiledHeaderFile=""\r
+                               AssemblerListingLocation=".\Release/"\r
+                               ObjectFile=".\Release/"\r
+                               ProgramDataBaseFileName=".\Release/"\r
+                               BrowseInformation="1"\r
+                               WarningLevel="4"\r
+                               WarnAsError="false"\r
+                               SuppressStartupBanner="true"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               CompileAs="0"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                               PreprocessorDefinitions="NDEBUG"\r
+                               Culture="1033"\r
+                               AdditionalIncludeDirectories=".."\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                               Description="Building Output Directories"\r
+                               CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
+                               OutputFile="$(OutDir)\ControlPanel.Resources\ControlPanelResources.dll"\r
+                               LinkIncremental="1"\r
+                               SuppressStartupBanner="true"\r
+                               IgnoreDefaultLibraryNames=""\r
+                               ModuleDefinitionFile=""\r
+                               ProgramDatabaseFile=""\r
+                               SubSystem="2"\r
+                               OptimizeReferences="0"\r
+                               EnableCOMDATFolding="0"\r
+                               ResourceOnlyDLL="true"\r
+                               ImportLibrary="$(IntDir)/$(ProjectName).lib"\r
+                               TargetMachine="17"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                            &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc"\r
+                       >\r
+                       <File\r
+                               RelativePath="resource_res.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest"\r
+                       >\r
+                       <File\r
+                               RelativePath="res\about.bmp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\about.bmp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\button-2k.ico"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\button-xp.ico"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\res\cold.ico"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="ControlPanelRes.rc"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\hot.ico"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="res\logo.bmp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\logo.bmp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="Web.ico"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+               <Global\r
+                       Name="RESOURCE_FILE"\r
+                       Value="ControlPanelRes.rc"\r
+               />\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/mDNSWindows/ControlPanel/FirstPage.cpp b/mDNSWindows/ControlPanel/FirstPage.cpp
deleted file mode 100755 (executable)
index 3fc3180..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: FirstPage.cpp,v $
-Revision 1.7  2009/06/22 23:25:10  herscher
-<rdar://problem/5265747> ControlPanel doesn't display key and password in dialog box. Refactor Lsa calls into Secret.h and Secret.c, which is used by both the ControlPanel and mDNSResponder system service.
-
-Revision 1.6  2006/08/14 23:25:28  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.5  2005/10/05 20:46:50  herscher
-<rdar://problem/4192011> Move Wide-Area preferences to another part of the registry so they don't removed during an update-install.
-
-Revision 1.4  2005/04/05 03:52:14  shersche
-<rdar://problem/4066485> Registering with shared secret key doesn't work. Additionally, mDNSResponder wasn't dynamically re-reading it's DynDNS setup after setting a shared secret key.
-
-Revision 1.3  2005/03/07 18:27:42  shersche
-<rdar://problem/4037940> Fix problem when ControlPanel commits changes to the browse domain list
-
-Revision 1.2  2005/03/03 19:55:22  shersche
-<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-
-
-*/
-
-#include "FirstPage.h"
-#include "resource.h"
-
-#include "ConfigPropertySheet.h"
-#include "SharedSecret.h"
-
-#define MAX_KEY_LENGTH 255
-
-
-IMPLEMENT_DYNCREATE(CFirstPage, CPropertyPage)
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFirstPage::CFirstPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CFirstPage::CFirstPage()
-:
-       CPropertyPage(CFirstPage::IDD),
-       m_ignoreHostnameChange( false ),
-       m_statusKey( NULL ),
-       m_setupKey( NULL )
-{
-       //{{AFX_DATA_INIT(CFirstPage)
-       //}}AFX_DATA_INIT
-
-       OSStatus err;
-
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\State\\Hostnames", &m_statusKey );
-       check_noerr( err );
-
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\Hostnames", &m_setupKey );
-       check_noerr( err );
-}
-
-CFirstPage::~CFirstPage()
-{
-       if ( m_statusKey )
-       {
-               RegCloseKey( m_statusKey );
-               m_statusKey = NULL;
-       }
-
-       if ( m_setupKey )
-       {
-               RegCloseKey( m_setupKey );
-               m_setupKey = NULL;
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFirstPage::DoDataExchange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CFirstPage::DoDataExchange(CDataExchange* pDX)
-{
-       CPropertyPage::DoDataExchange(pDX);
-       //{{AFX_DATA_MAP(CFirstPage)
-       //}}AFX_DATA_MAP
-       DDX_Control(pDX, IDC_EDIT1, m_hostnameControl);
-       DDX_Control(pDX, IDC_FAILURE, m_failureIcon);
-       DDX_Control(pDX, IDC_SUCCESS, m_successIcon);
-}
-
-BEGIN_MESSAGE_MAP(CFirstPage, CPropertyPage)
-       //{{AFX_MSG_MAP(CFirstPage)
-       //}}AFX_MSG_MAP
-       ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedSharedSecret)
-       ON_EN_CHANGE(IDC_EDIT1, OnEnChangeHostname)
-END_MESSAGE_MAP()
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFirstPage::OnEnChangedHostname
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CFirstPage::OnEnChangeHostname()
-{
-       if ( !m_ignoreHostnameChange )
-       {
-               SetModified( TRUE );
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFirstPage::OnBnClickedSharedSecret
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CFirstPage::OnBnClickedSharedSecret()
-{
-       CString name;
-
-       m_hostnameControl.GetWindowText( name );
-
-       CSharedSecret dlg;
-
-       dlg.Load( name );
-
-       if ( dlg.DoModal() == IDOK )
-       {
-               DWORD           wakeup = 0;
-               DWORD           dwSize = sizeof( DWORD );
-               OSStatus        err;
-
-               dlg.Commit( name );
-
-               // We have now updated the secret, however the system service
-               // doesn't know about it yet.  So we're going to update the
-               // registry with a dummy value which will cause the system
-               // service to re-initialize it's DynDNS setup
-               //
-
-               RegQueryValueEx( m_setupKey, L"Wakeup", NULL, NULL, (LPBYTE) &wakeup, &dwSize );      
-
-               wakeup++;
-               
-               err = RegSetValueEx( m_setupKey, L"Wakeup", 0, REG_DWORD, (LPBYTE) &wakeup, sizeof( DWORD ) );
-               require_noerr( err, exit );
-       }
-
-exit:
-
-       return;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFirstPage::SetModified
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CFirstPage::SetModified( BOOL bChanged )
-{
-       m_modified = bChanged ? true : false;
-
-       CPropertyPage::SetModified( bChanged );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFirstPage::OnSetActive
-//---------------------------------------------------------------------------------------------------------------------------
-
-BOOL
-CFirstPage::OnSetActive()
-{
-       TCHAR   name[kDNSServiceMaxDomainName + 1];
-       DWORD   nameLen = ( kDNSServiceMaxDomainName + 1 ) * sizeof( TCHAR );
-       DWORD   err;
-
-       BOOL b = CPropertyPage::OnSetActive();
-
-       m_modified = FALSE;
-
-       if ( m_setupKey )
-       {
-               err = RegQueryValueEx( m_setupKey, L"", NULL, NULL, (LPBYTE) name, &nameLen );
-
-               if ( !err )
-               {
-                       m_ignoreHostnameChange = true;
-                       m_hostnameControl.SetWindowText( name );
-                       m_ignoreHostnameChange = false;
-               }
-       }
-
-       // Check the status of this hostname
-
-       err = CheckStatus();
-       check_noerr( err );
-
-       return b;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFirstPage::OnOK
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CFirstPage::OnOK()
-{
-       if ( m_modified )
-       {
-               Commit();
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFirstPage::Commit
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CFirstPage::Commit()
-{
-       DWORD   enabled = 1;
-       CString name;
-       DWORD   err;
-
-       m_hostnameControl.GetWindowText( name );
-
-       // Convert to lower case
-
-       name.MakeLower();
-
-       // Remove trailing dot
-
-       name.TrimRight( '.' );
-
-       err = RegSetValueEx( m_setupKey, L"", 0, REG_SZ, (LPBYTE) (LPCTSTR) name, ( name.GetLength() + 1 ) * sizeof( TCHAR ) );
-       require_noerr( err, exit );
-       
-       err = RegSetValueEx( m_setupKey, L"Enabled", 0, REG_DWORD, (LPBYTE) &enabled, sizeof( DWORD ) );
-       require_noerr( err, exit );
-
-exit:
-
-       return;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFirstPage::CheckStatus
-//---------------------------------------------------------------------------------------------------------------------------
-
-OSStatus
-CFirstPage::CheckStatus()
-{
-       DWORD           status = 0;
-       DWORD           dwSize = sizeof( DWORD );
-       OSStatus        err;
-
-       // Get the status field 
-
-       err = RegQueryValueEx( m_statusKey, L"Status", NULL, NULL, (LPBYTE) &status, &dwSize );      
-       require_noerr( err, exit );
-
-       ShowStatus( status );
-
-exit:
-
-       return kNoErr;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFirstPage::ShowStatus
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CFirstPage::ShowStatus( DWORD status )
-{
-       if ( status )
-       {
-               m_failureIcon.ShowWindow( SW_HIDE );
-               m_successIcon.ShowWindow( SW_SHOW );
-       }
-       else
-       {
-               m_failureIcon.ShowWindow( SW_SHOW );
-               m_successIcon.ShowWindow( SW_HIDE );
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFirstPage::OnRegistryChanged
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CFirstPage::OnRegistryChanged()
-{
-       CheckStatus();
-}
diff --git a/mDNSWindows/ControlPanel/FirstPage.h b/mDNSWindows/ControlPanel/FirstPage.h
deleted file mode 100755 (executable)
index b990f3d..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: FirstPage.h,v $
-Revision 1.4  2006/08/14 23:25:28  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2005/03/07 18:27:42  shersche
-<rdar://problem/4037940> Fix problem when ControlPanel commits changes to the browse domain list
-
-Revision 1.2  2005/03/03 19:55:21  shersche
-<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-
-
-*/
-
-#pragma once
-
-#include "stdafx.h"
-#include "resource.h"
-
-#include <DebugServices.h>
-#include "afxwin.h"
-
-    
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFirstPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CFirstPage : public CPropertyPage
-{
-public:
-       CFirstPage();
-       ~CFirstPage();
-
-protected:
-       //{{AFX_DATA(CFirstPage)
-       enum { IDD = IDR_APPLET_PAGE1 };
-       //}}AFX_DATA
-
-       //{{AFX_VIRTUAL(CFirstPage)
-       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
-       //}}AFX_VIRTUAL
-
-       DECLARE_DYNCREATE(CFirstPage)
-
-       //{{AFX_MSG(CFirstPage)
-       //}}AFX_MSG
-       DECLARE_MESSAGE_MAP()
-public:
-       afx_msg void    OnBnClickedSharedSecret();
-       void                    OnRegistryChanged();
-private:
-
-       afx_msg BOOL    OnSetActive();
-       afx_msg void    OnOK();
-
-       void                    SetModified( BOOL bChanged = TRUE );
-       void                    Commit();
-       
-       OSStatus                CheckStatus();
-       void                    ShowStatus( DWORD status );
-
-       CEdit                   m_hostnameControl;
-       bool                    m_ignoreHostnameChange;
-       bool                    m_modified;
-       HKEY                    m_statusKey;
-       HKEY                    m_setupKey;
-       
-public:
-       
-       afx_msg void OnEnChangeHostname();
-       CStatic m_failureIcon;
-       CStatic m_successIcon;
-};
index c1f9849187ed78c070b42662b27979b4b5bb5721..f748efd9ac92b47b490943bc4210ede999bfb8e8 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: FourthPage.cpp,v $
-Revision 1.1  2009/07/01 19:20:37  herscher
-<rdar://problem/6713286> UI changes for configuring sleep proxy settings.
-
-
-
-*/
+ */
 
 #include "FourthPage.h"
 #include "resource.h"
@@ -74,8 +65,10 @@ void CFourthPage::DoDataExchange(CDataExchange* pDX)
 
 BEGIN_MESSAGE_MAP(CFourthPage, CPropertyPage)
        //{{AFX_MSG_MAP(CFourthPage)
-       //}}AFX_MSG_MAP\r
-       ON_BN_CLICKED(IDC_POWER_MANAGEMENT, &CFourthPage::OnBnClickedPowerManagement)\r
+       //}}AFX_MSG_MAP
+
+       ON_BN_CLICKED(IDC_POWER_MANAGEMENT, &CFourthPage::OnBnClickedPowerManagement)
+
 END_MESSAGE_MAP()
 
 
@@ -112,7 +105,8 @@ CFourthPage::OnSetActive()
 
        // Now populate the browse domain box
 
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", &key );
+       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", 0,
+                                 NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &key, NULL );
        require_noerr( err, exit );
 
        dwSize = sizeof( DWORD );
@@ -158,7 +152,8 @@ CFourthPage::Commit()
        DWORD           enabled;
        DWORD           err;
 
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", &key );
+       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", 0,
+                                 NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &key, NULL );
        require_noerr( err, exit );
 
        enabled = m_checkBox.GetCheck();
@@ -178,14 +173,25 @@ exit:
 //     CFourthPage::OnBnClickedRemoveBrowseDomain
 //---------------------------------------------------------------------------------------------------------------------------
 
-\r
-void CFourthPage::OnBnClickedPowerManagement()\r
-{\r
-       char buf[ 256 ];\r
-\r
-       sprintf( buf, "check box: %d", m_checkBox.GetCheck() );\r
-       OutputDebugStringA( buf );\r
-       // TODO: Add your control notification handler code here\r
-\r
-       SetModified( TRUE );\r
-}\r
+
+
+void CFourthPage::OnBnClickedPowerManagement()
+
+{
+
+       char buf[ 256 ];
+
+
+
+       sprintf( buf, "check box: %d", m_checkBox.GetCheck() );
+
+       OutputDebugStringA( buf );
+
+       // TODO: Add your control notification handler code here
+
+
+
+       SetModified( TRUE );
+
+}
+
index 9ec8a294379d948a7497442f7ad62ff8d88cbe99..d595291635c61f73441bbae471cc6893ac301654 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: FourthPage.h,v $
-Revision 1.1  2009/07/01 19:20:37  herscher
-<rdar://problem/6713286> UI changes for configuring sleep proxy settings.
-
-
-*/
+ */
 
 #pragma once
 
@@ -88,6 +80,8 @@ private:
        CButton m_checkBox;
 
 public:
-\r
-       afx_msg void OnBnClickedPowerManagement();\r
+
+
+       afx_msg void OnBnClickedPowerManagement();
+
 };
diff --git a/mDNSWindows/ControlPanel/RegistrationPage.cpp b/mDNSWindows/ControlPanel/RegistrationPage.cpp
new file mode 100755 (executable)
index 0000000..9328a75
--- /dev/null
@@ -0,0 +1,387 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <Secret.h>
+#include "RegistrationPage.h"
+#include "resource.h"
+
+#include "ConfigPropertySheet.h"
+extern "C"
+{
+#include <ClientCommon.h>
+}
+#include <WinServices.h>
+
+#define MAX_KEY_LENGTH 255
+
+
+IMPLEMENT_DYNCREATE(CRegistrationPage, CPropertyPage)
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CRegistrationPage::CRegistrationPage
+//---------------------------------------------------------------------------------------------------------------------------
+
+CRegistrationPage::CRegistrationPage()
+:
+       CPropertyPage(CRegistrationPage::IDD),
+       m_ignoreChanges( false ),
+       m_hostnameSetupKey( NULL ),
+       m_registrationSetupKey( NULL ),
+       m_statusKey( NULL )
+{
+       //{{AFX_DATA_INIT(CRegistrationPage)
+       //}}AFX_DATA_INIT
+
+       OSStatus err;
+
+       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\Hostnames", 0,
+                             NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &m_hostnameSetupKey, NULL );
+       check_noerr( err );
+
+       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSRegistrationDomains, 0,
+                             NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &m_registrationSetupKey, NULL );
+       check_noerr( err );
+
+       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\State\\Hostnames", 0,
+                             NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &m_statusKey, NULL );
+       check_noerr( err );
+
+       
+}
+
+CRegistrationPage::~CRegistrationPage()
+{
+       if ( m_hostnameSetupKey )
+       {
+               RegCloseKey( m_hostnameSetupKey );
+               m_hostnameSetupKey = NULL;
+       }
+
+       if ( m_registrationSetupKey )
+       {
+               RegCloseKey( m_registrationSetupKey );
+               m_registrationSetupKey = NULL;
+       }
+
+       if ( m_statusKey )
+       {
+               RegCloseKey( m_statusKey );
+               m_statusKey = NULL;
+       }
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CRegistrationPage::DoDataExchange
+//---------------------------------------------------------------------------------------------------------------------------
+
+void CRegistrationPage::DoDataExchange(CDataExchange* pDX)
+{
+       CPropertyPage::DoDataExchange(pDX);
+       //{{AFX_DATA_MAP(CRegistrationPage)
+       //}}AFX_DATA_MAP
+       DDX_Control(pDX, IDC_HOSTNAME, m_hostnameControl);
+       DDX_Control(pDX, IDC_USERNAME, m_usernameControl);
+       DDX_Control(pDX, IDC_PASSWORD, m_passwordControl);
+       DDX_Control(pDX, IDC_ADVERTISE_SERVICES, m_advertiseServices);
+}
+
+BEGIN_MESSAGE_MAP(CRegistrationPage, CPropertyPage)
+       //{{AFX_MSG_MAP(CRegistrationPage)
+       //}}AFX_MSG_MAP
+       ON_EN_CHANGE(IDC_HOSTNAME, OnEnChangeHostname)
+       ON_EN_CHANGE(IDC_USERNAME, OnEnChangeUsername)
+       ON_EN_CHANGE(IDC_PASSWORD, OnEnChangePassword)
+       ON_BN_CLICKED(IDC_ADVERTISE_SERVICES, OnBnClickedAdvertiseServices)
+END_MESSAGE_MAP()
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CRegistrationPage::OnEnChangedHostname
+//---------------------------------------------------------------------------------------------------------------------------
+
+void CRegistrationPage::OnEnChangeHostname()
+{
+       if ( !m_ignoreChanges )
+       {
+               SetModified( TRUE );
+       }
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CRegistrationPage::OnEnChangedUsername
+//---------------------------------------------------------------------------------------------------------------------------
+
+void CRegistrationPage::OnEnChangeUsername()
+{
+       if ( !m_ignoreChanges )
+       {
+               SetModified( TRUE );
+       }
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CRegistrationPage::OnEnChangedPassword
+//---------------------------------------------------------------------------------------------------------------------------
+
+void CRegistrationPage::OnEnChangePassword()
+{
+       if ( !m_ignoreChanges )
+       {
+               SetModified( TRUE );
+       }
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CRegistrationPage::OnBnClickedAdvertiseServices
+//---------------------------------------------------------------------------------------------------------------------------
+
+void CRegistrationPage::OnBnClickedAdvertiseServices()
+{
+       if ( !m_ignoreChanges )
+       {
+               SetModified( TRUE );
+       }
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CRegistrationPage::SetModified
+//---------------------------------------------------------------------------------------------------------------------------
+
+void CRegistrationPage::SetModified( BOOL bChanged )
+{
+       m_modified = bChanged ? true : false;
+
+       CPropertyPage::SetModified( bChanged );
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CRegistrationPage::OnSetActive
+//---------------------------------------------------------------------------------------------------------------------------
+
+BOOL
+CRegistrationPage::OnSetActive()
+{
+       TCHAR   name[kDNSServiceMaxDomainName + 1];
+       DWORD   nameLen = ( kDNSServiceMaxDomainName + 1 ) * sizeof( TCHAR );
+       DWORD   err;
+
+       BOOL b = CPropertyPage::OnSetActive();
+
+       m_ignoreChanges = true;
+       m_modified = FALSE;
+       
+       if ( m_hostnameSetupKey )
+       {
+               err = RegQueryValueEx( m_hostnameSetupKey, L"", NULL, NULL, (LPBYTE) name, &nameLen );
+
+               if ( !err )
+               {
+                       char    hostnameUTF8[ 256 ];
+                       char    outDomain[ 256 ];
+                       char    outUsername[ 256 ];
+                       char    outPassword[ 256 ];
+                       CString hostname = name;
+                       CString username;
+                       CString password;
+
+                       m_hostnameControl.SetWindowText( hostname );
+
+                       StringObjectToUTF8String( hostname, hostnameUTF8, sizeof( hostnameUTF8 ) );
+
+                       if ( LsaGetSecret( hostnameUTF8, outDomain, sizeof( outDomain ) / sizeof( TCHAR ), outUsername, sizeof( outUsername ) / sizeof( TCHAR ), outPassword, sizeof( outPassword ) / sizeof( TCHAR ) ) )
+                       {
+                               username = outUsername;
+                               m_usernameControl.SetWindowText( username );
+
+                               password = outPassword;
+                               m_passwordControl.SetWindowText( password );
+                       }
+               }
+       }
+
+       m_advertiseServices.SetCheck( 0 );
+
+       if ( m_registrationSetupKey )
+       {
+               HKEY            subKey = NULL;
+               DWORD           dwSize;
+               DWORD           enabled = 0;
+               TCHAR           subKeyName[MAX_KEY_LENGTH];
+               DWORD           cSubKeys = 0;
+               DWORD           cbMaxSubKey;
+               DWORD           cchMaxClass;
+               OSStatus        err;
+
+               err = RegQueryInfoKey( m_registrationSetupKey, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );       
+               if ( !err )
+               {
+                       if ( cSubKeys > 0 )
+                       {       
+                               dwSize = MAX_KEY_LENGTH;
+                   
+                               err = RegEnumKeyEx( m_registrationSetupKey, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
+                               if ( !err )
+                               {
+                                       err = RegOpenKey( m_registrationSetupKey, subKeyName, &subKey );
+                                       if ( !err )
+                                       {
+                                               dwSize = sizeof( DWORD );
+                                               err = RegQueryValueEx( subKey, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
+                                               if ( !err && enabled )
+                                               {
+                                                       m_advertiseServices.SetCheck( enabled );
+                                               }
+
+                                               RegCloseKey( subKey );
+                                               subKey = NULL;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       m_ignoreChanges = false;
+
+       return b;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CRegistrationPage::OnOK
+//---------------------------------------------------------------------------------------------------------------------------
+
+void
+CRegistrationPage::OnOK()
+{
+       if ( m_modified )
+       {
+               Commit();
+       }
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CRegistrationPage::Commit
+//---------------------------------------------------------------------------------------------------------------------------
+
+void
+CRegistrationPage::Commit()
+{
+       CString hostname;
+       char    hostnameUTF8[ 256 ];
+       CString username;
+       char    usernameUTF8[ 256 ];
+       CString password;
+       char    passwordUTF8[ 256 ];
+       DWORD   enabled = 1;
+       BOOL    secret = FALSE;
+       DWORD   err;
+
+       m_hostnameControl.GetWindowText( hostname );
+       hostname.MakeLower();
+       hostname.TrimRight( '.' );
+       StringObjectToUTF8String( hostname, hostnameUTF8, sizeof( hostnameUTF8 ) );
+       
+       m_usernameControl.GetWindowText( username );
+       m_passwordControl.GetWindowText( password );
+       
+       if ( username.GetLength() && password.GetLength() )
+       {
+               StringObjectToUTF8String( username, usernameUTF8, sizeof( usernameUTF8 ) );     
+               StringObjectToUTF8String( password, passwordUTF8, sizeof( passwordUTF8 ) );
+               secret = TRUE;
+       }
+
+       if ( m_hostnameSetupKey != NULL )
+       {
+               err = RegSetValueEx( m_hostnameSetupKey, L"", 0, REG_SZ, (LPBYTE) (LPCTSTR) hostname, ( hostname.GetLength() + 1 ) * sizeof( TCHAR ) );
+               require_noerr( err, exit );
+               
+               err = RegSetValueEx( m_hostnameSetupKey, L"Enabled", 0, REG_DWORD, (LPBYTE) &enabled, sizeof( DWORD ) );
+               require_noerr( err, exit );
+
+               if ( secret )
+               {
+                       LsaSetSecret( hostnameUTF8, usernameUTF8, passwordUTF8 );
+               }
+       }
+
+       if ( m_registrationSetupKey != NULL )
+       {
+               TCHAR           subKeyName[MAX_KEY_LENGTH];
+               DWORD           cSubKeys = 0;
+               DWORD           cbMaxSubKey;
+               DWORD           cchMaxClass;
+               DWORD           dwSize;
+               int                     i;
+               OSStatus        err = kNoErr;
+
+               // First, remove all the entries that are there
+
+               err = RegQueryInfoKey( m_registrationSetupKey, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );       
+               if ( !err )
+               {
+                       for ( i = 0; i < (int) cSubKeys; i++ )
+                       {       
+                               dwSize = MAX_KEY_LENGTH;
+                           
+                               err = RegEnumKeyEx( m_registrationSetupKey, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
+                               require_noerr( err, exit );
+                                       
+                               err = RegDeleteKey( m_registrationSetupKey, subKeyName );
+                               require_noerr( err, exit );
+                       }
+               }
+
+               if ( m_advertiseServices.GetCheck() )
+               {
+                       const char      * domainUTF8;
+                       CString           domain;
+                       char              label[ 64 ];
+                       HKEY              subKey = NULL;
+
+                       domainUTF8      = GetNextLabel( hostnameUTF8, label );
+                       domain          = domainUTF8;
+
+                       err = RegCreateKeyEx( m_registrationSetupKey, domain, 0,
+                                                                        NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &subKey, NULL );
+                       if ( !err )
+                       {
+                               err = RegSetValueEx( subKey, L"Enabled", 0, REG_DWORD, (LPBYTE) &enabled, sizeof( DWORD ) );
+                               check_noerr( err );
+
+                               RegCloseKey( subKey );
+                               subKey = NULL;
+                       }
+
+                       if ( secret )
+                       {
+                               LsaSetSecret( domainUTF8, usernameUTF8, passwordUTF8 );
+                       }
+               }
+       }
+
+exit:
+
+       return;
+}
diff --git a/mDNSWindows/ControlPanel/RegistrationPage.h b/mDNSWindows/ControlPanel/RegistrationPage.h
new file mode 100755 (executable)
index 0000000..935a418
--- /dev/null
@@ -0,0 +1,75 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "stdafx.h"
+#include "resource.h"
+#include <DebugServices.h>
+#include "afxwin.h"
+
+    
+//---------------------------------------------------------------------------------------------------------------------------
+//     CRegistrationPage
+//---------------------------------------------------------------------------------------------------------------------------
+
+class CRegistrationPage : public CPropertyPage
+{
+public:
+       CRegistrationPage();
+       ~CRegistrationPage();
+
+protected:
+       //{{AFX_DATA(CRegistrationPage)
+       enum { IDD = IDR_APPLET_PAGE1 };
+       //}}AFX_DATA
+
+       //{{AFX_VIRTUAL(CRegistrationPage)
+       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+       //}}AFX_VIRTUAL
+
+       DECLARE_DYNCREATE(CRegistrationPage)
+
+       //{{AFX_MSG(CRegistrationPage)
+       //}}AFX_MSG
+       DECLARE_MESSAGE_MAP()
+
+private:
+
+       afx_msg BOOL    OnSetActive();
+       afx_msg void    OnOK();
+
+       void                    SetModified( BOOL bChanged = TRUE );
+       void                    Commit();
+
+       CEdit                   m_hostnameControl;
+       CEdit                   m_usernameControl;
+       CEdit                   m_passwordControl;
+       CButton                 m_advertiseServices;
+       bool                    m_ignoreChanges;
+       bool                    m_modified;
+       HKEY                    m_hostnameSetupKey;
+       HKEY                    m_registrationSetupKey;
+       HKEY                    m_statusKey;
+       
+public:
+       
+       afx_msg void OnEnChangeHostname();
+       afx_msg void OnEnChangeUsername();
+       afx_msg void OnEnChangePassword();
+       afx_msg void OnBnClickedAdvertiseServices();
+};
index eb830df113d35365d5954f919a0e19f495bed20e..d3bc1335d6197b9d91c2a857863a9f13cabd91d4 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: SecondPage.cpp,v $
-Revision 1.7  2006/08/14 23:25:28  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.6  2005/10/05 20:46:50  herscher
-<rdar://problem/4192011> Move Wide-Area preferences to another part of the registry so they don't removed during an update-install.
-
-Revision 1.5  2005/04/05 04:15:46  shersche
-RegQueryString was returning uninitialized strings if the registry key couldn't be found, so always initialize strings before checking the registry key.
-
-Revision 1.4  2005/04/05 03:52:14  shersche
-<rdar://problem/4066485> Registering with shared secret key doesn't work. Additionally, mDNSResponder wasn't dynamically re-reading it's DynDNS setup after setting a shared secret key.
-
-Revision 1.3  2005/03/03 19:55:22  shersche
-<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-
-
-*/
+ */
 
 #include "SecondPage.h"
 #include "resource.h"
@@ -43,6 +23,8 @@ Revision 1.3  2005/03/03 19:55:22  shersche
 
 #include <WinServices.h>
     
+#define MAX_KEY_LENGTH 255
+
 IMPLEMENT_DYNCREATE(CSecondPage, CPropertyPage)
 
 
@@ -60,7 +42,8 @@ CSecondPage::CSecondPage()
 
        OSStatus err;
 
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSRegistrationDomains, &m_setupKey );
+       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSRegistrationDomains, 0,
+                             NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &m_setupKey, NULL );
        check_noerr( err );
 }
 
@@ -126,8 +109,6 @@ BOOL
 CSecondPage::OnSetActive()
 {
        CConfigPropertySheet    *       psheet;
-       DWORD                                           dwSize;
-       DWORD                                           enabled;
        DWORD                                           err;
        BOOL                                            b = CPropertyPage::OnSetActive();
 
@@ -145,12 +126,6 @@ CSecondPage::OnSetActive()
        err = Populate( m_regDomainsBox, m_setupKey, psheet->m_regDomains );
        check_noerr( err );
 
-       dwSize = sizeof( DWORD );
-       err = RegQueryValueEx( m_setupKey, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
-       m_advertiseServicesButton.SetCheck( ( !err && enabled ) ? BST_CHECKED : BST_UNCHECKED );
-       m_regDomainsBox.EnableWindow( ( !err && enabled ) );
-       m_sharedSecretButton.EnableWindow( (!err && enabled ) );
-
 exit:
 
        return b;
@@ -197,8 +172,31 @@ OSStatus
 CSecondPage::Commit( CComboBox & box, HKEY key, DWORD enabled )
 {
        CString         selected;
+       HKEY            subKey  = NULL;
+       TCHAR           subKeyName[MAX_KEY_LENGTH];
+       DWORD           cSubKeys = 0;
+       DWORD           cbMaxSubKey;
+       DWORD           cchMaxClass;
+       DWORD           dwSize;
+       int                     i;
        OSStatus        err = kNoErr;
 
+       // First, remove all the entries that are there
+
+    err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );       
+       require_noerr( err, exit );
+
+       for ( i = 0; i < (int) cSubKeys; i++ )
+       {       
+               dwSize = MAX_KEY_LENGTH;
+            
+               err = RegEnumKeyEx( key, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
+               require_noerr( err, exit );
+                       
+               err = RegDeleteKey( key, subKeyName );
+               require_noerr( err, exit );
+       }
+
        // Get selected text
        
        box.GetWindowText( selected );
@@ -231,12 +229,21 @@ CSecondPage::Commit( CComboBox & box, HKEY key, DWORD enabled )
        // Save selected text in registry.  This will trigger mDNSResponder to setup
        // DynDNS config again
 
-       err = RegSetValueEx( key, L"", 0, REG_SZ, (LPBYTE) (LPCTSTR) selected, ( selected.GetLength() + 1 ) * sizeof( TCHAR ) );
-       check_noerr( err );
+       err = RegCreateKeyEx( key, selected, 0,
+                             NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &subKey, NULL );
+       require_noerr( err, exit );
 
-       err = RegSetValueEx( key, L"Enabled", 0, REG_DWORD, (LPBYTE) &enabled, sizeof( DWORD ) );
+       err = RegSetValueEx( subKey, L"Enabled", 0, REG_DWORD, (LPBYTE) &enabled, sizeof( DWORD ) );
        check_noerr( err );
 
+exit:
+
+       if ( subKey )
+       {
+               RegCloseKey( subKey );
+               subKey = NULL;
+       }
+
        return err;
 }
 
@@ -253,7 +260,7 @@ void CSecondPage::OnBnClickedSharedSecret()
 
        CSharedSecret dlg;
 
-       dlg.m_key = name;
+       dlg.Load( name );
 
        if ( dlg.DoModal() == IDOK )
        {
@@ -374,9 +381,14 @@ CSecondPage::EmptyComboBox( CComboBox & box )
 OSStatus
 CSecondPage::Populate( CComboBox & box, HKEY key, StringList & l )
 {
-       TCHAR           rawString[kDNSServiceMaxDomainName + 1];
-       DWORD           rawStringLen;
        CString         string;
+       HKEY            subKey = NULL;
+       DWORD           dwSize;
+       DWORD           enabled = 0;
+       TCHAR           subKeyName[MAX_KEY_LENGTH];
+       DWORD           cSubKeys = 0;
+       DWORD           cbMaxSubKey;
+       DWORD           cchMaxClass;
        OSStatus        err;
 
        err = RegQueryString( key, L"UserDefined", string );
@@ -416,31 +428,44 @@ CSecondPage::Populate( CComboBox & box, HKEY key, StringList & l )
                }
        }
 
-       // Now look to see if there is a selected string, and if so,
-       // select it
+       err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );       
+       require_noerr( err, exit );
 
-       rawString[0] = '\0';
+       if ( cSubKeys > 0 )
+       {       
+               dwSize = MAX_KEY_LENGTH;
+            
+               err = RegEnumKeyEx( key, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
+               require_noerr( err, exit );
 
-       rawStringLen = sizeof( rawString );
+               err = RegOpenKey( key, subKeyName, &subKey );
+               require_noerr( err, exit );
 
-       err = RegQueryValueEx( key, L"", 0, NULL, (LPBYTE) rawString, &rawStringLen );
+               dwSize = sizeof( DWORD );
+               err = RegQueryValueEx( subKey, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
+               require_noerr( err, exit );
 
-       string = rawString;
-       
-       if ( !err && ( string.GetLength() != 0 ) )
-       {
                // See if it's there
 
-               if ( box.SelectString( -1, string ) == CB_ERR )
+               if ( box.SelectString( -1, subKeyName ) == CB_ERR )
                {
                        // If not, add it
 
-                       box.AddString( string );
+                       box.AddString( subKeyName );
                }
 
-               box.SelectString( -1, string );
+               box.SelectString( -1, subKeyName );
+
+               RegCloseKey( subKey );
+               subKey = NULL;
        }
 
+exit:
+
+       m_advertiseServicesButton.SetCheck( ( !err && enabled ) ? BST_CHECKED : BST_UNCHECKED );
+       m_regDomainsBox.EnableWindow( ( !err && enabled ) );
+       m_sharedSecretButton.EnableWindow( (!err && enabled ) );
+
        return err;
 }
 
@@ -455,7 +480,8 @@ CSecondPage::CreateKey( CString & name, DWORD enabled )
        HKEY            key = NULL;
        OSStatus        err;
 
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, (LPCTSTR) name, &key );
+       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, (LPCTSTR) name, 0,
+                                 NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &key, NULL );
        require_noerr( err, exit );
 
        err = RegSetValueEx( key, L"Enabled", 0, REG_DWORD, (LPBYTE) &enabled, sizeof( DWORD ) );
index f60612ecfa381f65851857933b588177eadf1c09..3bd9e74444619adef1cf87fd01204c8059c07e17 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: SecondPage.h,v $
-Revision 1.5  2006/08/14 23:25:28  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.4  2005/04/05 03:52:14  shersche
-<rdar://problem/4066485> Registering with shared secret key doesn't work. Additionally, mDNSResponder wasn't dynamically re-reading it's DynDNS setup after setting a shared secret key.
-
-Revision 1.3  2005/03/03 19:55:21  shersche
-<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-
-
-*/
+ */
 
 #pragma once
 
diff --git a/mDNSWindows/ControlPanel/ServicesPage.cpp b/mDNSWindows/ControlPanel/ServicesPage.cpp
new file mode 100755 (executable)
index 0000000..e087157
--- /dev/null
@@ -0,0 +1,273 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ServicesPage.h"
+#include "resource.h"
+
+#include "ControlPanelExe.h"
+#include "ConfigPropertySheet.h"
+
+#include <WinServices.h>
+    
+#define MAX_KEY_LENGTH 255
+
+
+IMPLEMENT_DYNCREATE(CServicesPage, CPropertyPage)
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CServicesPage::CServicesPage
+//---------------------------------------------------------------------------------------------------------------------------
+
+CServicesPage::CServicesPage()
+:
+       CPropertyPage(CServicesPage::IDD)
+{
+       //{{AFX_DATA_INIT(CServicesPage)
+       //}}AFX_DATA_INIT
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CServicesPage::~CServicesPage
+//---------------------------------------------------------------------------------------------------------------------------
+
+CServicesPage::~CServicesPage()
+{
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CServicesPage::DoDataExchange
+//---------------------------------------------------------------------------------------------------------------------------
+
+void CServicesPage::DoDataExchange(CDataExchange* pDX)
+{
+       CPropertyPage::DoDataExchange(pDX);
+       //{{AFX_DATA_MAP(CServicesPage)
+       //}}AFX_DATA_MAP
+       DDX_Control(pDX, IDC_ADVERTISE_SMB, m_SMBCheckBox);
+       DDX_Control(pDX, IDC_POWER_MANAGEMENT, m_powerManagementCheckBox);
+}
+
+BEGIN_MESSAGE_MAP(CServicesPage, CPropertyPage)
+       //{{AFX_MSG_MAP(CServicesPage)
+       //}}AFX_MSG_MAP
+
+       ON_BN_CLICKED(IDC_ADVERTISE_SMB, &CServicesPage::OnBnClickedAdvertiseSMB)
+       ON_BN_CLICKED(IDC_POWER_MANAGEMENT, &CServicesPage::OnBnClickedPowerManagement)
+
+END_MESSAGE_MAP()
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CServicesPage::SetModified
+//---------------------------------------------------------------------------------------------------------------------------
+
+void CServicesPage::SetModified( BOOL bChanged )
+{
+       m_modified = bChanged;
+
+       CPropertyPage::SetModified( bChanged );
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CServicesPage::OnSetActive
+//---------------------------------------------------------------------------------------------------------------------------
+
+BOOL
+CServicesPage::OnSetActive()
+{
+       CConfigPropertySheet    *       psheet;
+       HKEY                                            key = NULL;
+       DWORD                                           dwSize;
+       DWORD                                           enabled;
+       DWORD                                           err;
+       BOOL                                            b = CPropertyPage::OnSetActive();
+
+       psheet = reinterpret_cast<CConfigPropertySheet*>(GetParent());
+       require_quiet( psheet, exit );
+
+       m_SMBCheckBox.SetCheck( 0 );
+
+       // Now populate the browse domain box
+
+       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Services\\SMB", 0,
+                                 NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &key, NULL );
+       require_noerr( err, exit );
+
+       dwSize = sizeof( DWORD );
+       err = RegQueryValueEx( key, L"Advertise", NULL, NULL, (LPBYTE) &enabled, &dwSize );
+       require_noerr( err, exit );
+
+       m_SMBCheckBox.SetCheck( enabled );
+
+       RegCloseKey( key );
+       key = NULL;
+
+       m_powerManagementCheckBox.SetCheck( 0 );
+
+       // Now populate the browse domain box
+
+       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", 0,
+                                 NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &key, NULL );
+       require_noerr( err, exit );
+
+       dwSize = sizeof( DWORD );
+       err = RegQueryValueEx( key, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
+       require_noerr( err, exit );
+
+       m_powerManagementCheckBox.SetCheck( enabled );
+exit:
+
+       if ( key )
+       {
+               RegCloseKey( key );
+       }
+
+       return b;
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CServicesPage::OnOK
+//---------------------------------------------------------------------------------------------------------------------------
+
+void
+CServicesPage::OnOK()
+{
+       if ( m_modified )
+       {
+               Commit();
+       }
+}
+
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CServicesPage::Commit
+//---------------------------------------------------------------------------------------------------------------------------
+
+void
+CServicesPage::Commit()
+{
+       HKEY            key             = NULL;
+       DWORD           enabled;
+       DWORD           err;
+
+       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Services\\SMB", 0,
+                               NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &key, NULL );
+       require_noerr( err, exit );
+
+       enabled = m_SMBCheckBox.GetCheck();
+       err = RegSetValueEx( key, L"Advertise", NULL, REG_DWORD, (LPBYTE) &enabled, sizeof( enabled ) );
+       require_noerr( err, exit );
+
+       RegCloseKey( key );
+       key = NULL;
+
+       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", 0,
+                                 NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE|KEY_WOW64_32KEY, NULL, &key, NULL );
+       require_noerr( err, exit );
+
+       enabled = m_powerManagementCheckBox.GetCheck();
+       err = RegSetValueEx( key, L"Enabled", NULL, REG_DWORD, (LPBYTE) &enabled, sizeof( enabled ) );
+       require_noerr( err, exit );
+       
+exit:
+
+       if ( key )
+       {
+               RegCloseKey( key );
+       }
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CServicesPage::OnBnClickedAdvertiseSMB
+//---------------------------------------------------------------------------------------------------------------------------
+
+void CServicesPage::OnBnClickedAdvertiseSMB()
+{
+       SetModified( TRUE );
+}
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CServicesPage::OnBnClickedPowerManagement
+//---------------------------------------------------------------------------------------------------------------------------
+
+void CServicesPage::OnBnClickedPowerManagement()
+{
+       SetModified( TRUE );
+
+       if ( m_powerManagementCheckBox.GetCheck() )
+       {
+               CPowerManagementWarning dlg( GetParent() );
+
+               dlg.DoModal();
+       }
+}
+
+
+// CPowerManagementWarning dialog
+
+IMPLEMENT_DYNAMIC(CPowerManagementWarning, CDialog)
+CPowerManagementWarning::CPowerManagementWarning(CWnd* pParent /*=NULL*/)
+       : CDialog(CPowerManagementWarning::IDD, pParent)
+{
+}
+
+CPowerManagementWarning::~CPowerManagementWarning()
+{
+}
+
+void CPowerManagementWarning::DoDataExchange(CDataExchange* pDX)
+{
+       CDialog::DoDataExchange(pDX);
+       DDX_Control(pDX, IDC_ENERGY_SAVER, m_energySaverIcon);
+}
+
+
+BOOL
+CPowerManagementWarning::OnInitDialog()
+{      
+       BOOL b = CDialog::OnInitDialog();
+
+       const HICON hIcon = ( HICON ) ::LoadImage( GetNonLocalizedResources(), MAKEINTRESOURCE( IDI_ENERGY_SAVER ), IMAGE_ICON, 0, 0, 0);
+       
+       if ( hIcon )
+       {
+               m_energySaverIcon.SetIcon( hIcon );
+       }
+
+       return b;
+}
+
+
+void
+CPowerManagementWarning::OnOK()
+{
+       CDialog::OnOK();
+}
+
+
+BEGIN_MESSAGE_MAP(CPowerManagementWarning, CDialog)
+END_MESSAGE_MAP()
+
diff --git a/mDNSWindows/ControlPanel/ServicesPage.h b/mDNSWindows/ControlPanel/ServicesPage.h
new file mode 100755 (executable)
index 0000000..d593a72
--- /dev/null
@@ -0,0 +1,123 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ *
+ * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "stdafx.h"
+#include "resource.h"
+
+#include <DebugServices.h>
+#include <list>
+#include "afxcmn.h"
+
+#include "afxwin.h"
+
+
+
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CServicesPage
+//---------------------------------------------------------------------------------------------------------------------------
+
+class CServicesPage : public CPropertyPage
+{
+public:
+       CServicesPage();
+       ~CServicesPage();
+
+protected:
+
+       //{{AFX_DATA(CServicesPage)
+       enum { IDD = IDR_APPLET_PAGE5 };
+       //}}AFX_DATA
+
+       //{{AFX_VIRTUAL(CServicesPage)
+       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+       //}}AFX_VIRTUAL
+
+       DECLARE_DYNCREATE(CServicesPage)
+
+       //{{AFX_MSG(CServicesPage)
+       //}}AFX_MSG
+       DECLARE_MESSAGE_MAP()
+       
+private:
+       
+       typedef std::list<CString> StringList;
+
+       afx_msg BOOL
+       OnSetActive();
+       
+       afx_msg void
+       OnOK();
+       
+       void
+       SetModified( BOOL bChanged = TRUE );
+       
+       void
+       Commit();
+
+       BOOL                    m_modified;
+
+public:
+private:
+
+       CButton m_SMBCheckBox;
+       CButton m_powerManagementCheckBox;
+
+public:
+
+
+       afx_msg void OnBnClickedAdvertiseSMB();
+       afx_msg void OnBnClickedPowerManagement();
+};
+
+
+//---------------------------------------------------------------------------------------------------------------------------
+//     CPowerManagementWarning
+//---------------------------------------------------------------------------------------------------------------------------
+
+class CPowerManagementWarning : public CDialog
+{
+       DECLARE_DYNAMIC(CPowerManagementWarning)
+
+public:
+
+       CPowerManagementWarning(CWnd* pParent = NULL);   // standard constructor
+
+       virtual ~CPowerManagementWarning();
+
+// Dialog Data
+
+       enum { IDD = IDR_POWER_MANAGEMENT_WARNING };
+
+protected:
+
+       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
+
+       virtual BOOL OnInitDialog();
+
+       virtual void OnOK();
+
+       DECLARE_MESSAGE_MAP()
+
+public:
+
+       CStatic m_energySaverIcon;
+};
+
index b74366ebfda0d03261c64fc42d6bf2099400f33b..3d1929588e8151ac23f19e1ab1857eb0790fe431 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: SharedSecret.cpp,v $
-Revision 1.7  2009/06/22 23:25:11  herscher
-<rdar://problem/5265747> ControlPanel doesn't display key and password in dialog box. Refactor Lsa calls into Secret.h and Secret.c, which is used by both the ControlPanel and mDNSResponder system service.
-
-Revision 1.6  2007/06/12 20:06:06  herscher
-<rdar://problem/5263387> ControlPanel was inadvertently adding a trailing dot to all key names.
-
-Revision 1.5  2006/08/14 23:25:28  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.4  2005/10/18 06:13:41  herscher
-<rdar://problem/4192119> Prepend "$" to key name to ensure that secure updates work if the domain name and key name are the same
-
-Revision 1.3  2005/04/06 02:04:49  shersche
-<rdar://problem/4066485> Registering with shared secret doesn't work
-
-Revision 1.2  2005/03/03 19:55:22  shersche
-<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-
-
-*/
+ */
 
     
 // SharedSecret.cpp : implementation file
index 73aef5b4c68cabfb79180c7b42d45bb77884c26b..be82d8b83c16877048b073320552b72cbe517698 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: SharedSecret.h,v $
-Revision 1.5  2009/06/22 23:25:11  herscher
-<rdar://problem/5265747> ControlPanel doesn't display key and password in dialog box. Refactor Lsa calls into Secret.h and Secret.c, which is used by both the ControlPanel and mDNSResponder system service.
-
-Revision 1.4  2006/08/14 23:25:28  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2005/04/06 02:04:49  shersche
-<rdar://problem/4066485> Registering with shared secret doesn't work
-
-Revision 1.2  2005/03/03 19:55:21  shersche
-<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-
-
-*/
+ */
 
     
 #pragma once
diff --git a/mDNSWindows/ControlPanel/ThirdPage.cpp b/mDNSWindows/ControlPanel/ThirdPage.cpp
deleted file mode 100755 (executable)
index a483418..0000000
+++ /dev/null
@@ -1,456 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: ThirdPage.cpp,v $
-Revision 1.5  2006/08/14 23:25:29  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.4  2005/10/05 20:46:50  herscher
-<rdar://problem/4192011> Move Wide-Area preferences to another part of the registry so they don't removed during an update-install.
-
-Revision 1.3  2005/03/07 18:27:42  shersche
-<rdar://problem/4037940> Fix problem when ControlPanel commits changes to the browse domain list
-
-Revision 1.2  2005/03/03 19:55:22  shersche
-<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-
-
-*/
-
-#include "ThirdPage.h"
-#include "resource.h"
-
-#include "ConfigPropertySheet.h"
-#include "SharedSecret.h"
-
-#include <WinServices.h>
-    
-#define MAX_KEY_LENGTH 255
-
-
-IMPLEMENT_DYNCREATE(CThirdPage, CPropertyPage)
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CThirdPage::CThirdPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CThirdPage::CThirdPage()
-:
-       CPropertyPage(CThirdPage::IDD)
-{
-       //{{AFX_DATA_INIT(CThirdPage)
-       //}}AFX_DATA_INIT
-
-       m_firstTime = true;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CThirdPage::~CThirdPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CThirdPage::~CThirdPage()
-{
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CThirdPage::DoDataExchange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CThirdPage::DoDataExchange(CDataExchange* pDX)
-{
-       CPropertyPage::DoDataExchange(pDX);
-       //{{AFX_DATA_MAP(CThirdPage)
-       //}}AFX_DATA_MAP
-       DDX_Control(pDX, IDC_BROWSE_LIST, m_browseListCtrl);
-       DDX_Control(pDX, IDC_REMOVE_BROWSE_DOMAIN, m_removeButton);
-}
-
-BEGIN_MESSAGE_MAP(CThirdPage, CPropertyPage)
-       //{{AFX_MSG_MAP(CThirdPage)
-       //}}AFX_MSG_MAP
-       ON_BN_CLICKED(IDC_ADD_BROWSE_DOMAIN, OnBnClickedAddBrowseDomain)
-       ON_BN_CLICKED(IDC_REMOVE_BROWSE_DOMAIN, OnBnClickedRemoveBrowseDomain)
-       ON_NOTIFY(LVN_ITEMCHANGED, IDC_BROWSE_LIST, OnLvnItemchangedBrowseList)
-END_MESSAGE_MAP()
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CThirdPage::SetModified
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CThirdPage::SetModified( BOOL bChanged )
-{
-       m_modified = bChanged;
-
-       CPropertyPage::SetModified( bChanged );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CThirdPage::OnSetActive
-//---------------------------------------------------------------------------------------------------------------------------
-
-BOOL
-CThirdPage::OnSetActive()
-{
-       CConfigPropertySheet    *       psheet;
-       HKEY                                            key = NULL;
-       HKEY                                            subKey = NULL;
-       DWORD                                           dwSize;
-       DWORD                                           enabled;
-       DWORD                                           err;
-       TCHAR                                           subKeyName[MAX_KEY_LENGTH];
-       DWORD                                           cSubKeys = 0;
-       DWORD                                           cbMaxSubKey;
-       DWORD                                           cchMaxClass;
-       int                                                     nIndex;
-    DWORD                                              i; 
-       BOOL                                            b = CPropertyPage::OnSetActive();
-
-       psheet = reinterpret_cast<CConfigPropertySheet*>(GetParent());
-       require_quiet( psheet, exit );
-       
-       m_modified = FALSE;
-
-       if ( m_firstTime )
-       {
-               m_browseListCtrl.SetExtendedStyle((m_browseListCtrl.GetStyle() & (~LVS_EX_GRIDLINES))|LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
-
-               m_browseListCtrl.InsertColumn(0, L"", LVCFMT_LEFT, 20 );
-               m_browseListCtrl.InsertColumn(1, L"", LVCFMT_LEFT, 345);
-
-               m_firstTime = false;
-       }
-
-       m_initialized = false;
-
-       // Clear out what's there
-
-       m_browseListCtrl.DeleteAllItems();
-
-       // Now populate the browse domain box
-
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSBrowseDomains, &key );
-       require_noerr( err, exit );
-
-       // Get information about this node
-
-    err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );       
-       require_noerr( err, exit );
-
-       for ( i = 0; i < cSubKeys; i++)
-       {       
-               dwSize = MAX_KEY_LENGTH;
-            
-               err = RegEnumKeyEx( key, i, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
-               require_noerr( err, exit );
-
-               err = RegOpenKey( key, subKeyName, &subKey );
-               require_noerr( err, exit );
-
-               dwSize = sizeof( DWORD );
-               err = RegQueryValueEx( subKey, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
-               require_noerr( err, exit );
-
-               nIndex = m_browseListCtrl.InsertItem( m_browseListCtrl.GetItemCount(), L"");
-               m_browseListCtrl.SetItemText( nIndex, 1, subKeyName );
-               m_browseListCtrl.SetCheck( nIndex, enabled );
-
-               RegCloseKey( subKey );
-               subKey = NULL;
-    }
-
-       m_browseListCtrl.SortItems( SortFunc, (DWORD_PTR) this );
-
-       m_removeButton.EnableWindow( FALSE );
-exit:
-
-       if ( subKey )
-       {
-               RegCloseKey( subKey );
-       }
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-
-       m_initialized = true;
-
-       return b;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CThirdPage::OnOK
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CThirdPage::OnOK()
-{
-       if ( m_modified )
-       {
-               Commit();
-       }
-}
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CThirdPage::Commit
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CThirdPage::Commit()
-{
-       HKEY            key             = NULL;
-       HKEY            subKey  = NULL;
-       TCHAR           subKeyName[MAX_KEY_LENGTH];
-       DWORD           cSubKeys = 0;
-       DWORD           cbMaxSubKey;
-       DWORD           cchMaxClass;
-       DWORD           dwSize;
-       int                     i;
-       DWORD           err;
-
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSBrowseDomains, &key );
-       require_noerr( err, exit );
-
-       // First, remove all the entries that are there
-
-    err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );       
-       require_noerr( err, exit );
-
-       for ( i = 0; i < (int) cSubKeys; i++ )
-       {       
-               dwSize = MAX_KEY_LENGTH;
-            
-               err = RegEnumKeyEx( key, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
-               require_noerr( err, exit );
-                       
-               err = RegDeleteKey( key, subKeyName );
-               require_noerr( err, exit );
-       }
-
-       // Now re-populate
-
-       for ( i = 0; i < m_browseListCtrl.GetItemCount(); i++ )
-       {
-               DWORD enabled = (DWORD) m_browseListCtrl.GetCheck( i );
-
-               err = RegCreateKey( key, m_browseListCtrl.GetItemText( i, 1 ), &subKey );
-               require_noerr( err, exit );
-
-               err = RegSetValueEx( subKey, L"Enabled", NULL, REG_DWORD, (LPBYTE) &enabled, sizeof( enabled ) );
-               require_noerr( err, exit );
-
-               RegCloseKey( subKey );
-               subKey = NULL;
-       }
-       
-exit:
-
-       if ( subKey )
-       {
-               RegCloseKey( subKey );
-       }
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-}
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CThirdPage::OnBnClickedAddBrowseDomain
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CThirdPage::OnBnClickedAddBrowseDomain()
-{
-       CAddBrowseDomain dlg( GetParent() );
-
-       if ( ( dlg.DoModal() == IDOK ) && ( dlg.m_text.GetLength() > 0 ) )
-       {
-               int nIndex;
-
-               nIndex = m_browseListCtrl.InsertItem( m_browseListCtrl.GetItemCount(), L"");
-               m_browseListCtrl.SetItemText( nIndex, 1, dlg.m_text );
-               m_browseListCtrl.SetCheck( nIndex, 1 );
-
-               m_browseListCtrl.SortItems( SortFunc, (DWORD_PTR) this );
-
-               m_browseListCtrl.Invalidate();
-
-               SetModified( TRUE );
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CThirdPage::OnBnClickedRemoveBrowseDomain
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CThirdPage::OnBnClickedRemoveBrowseDomain()
-{
-       UINT    selectedCount = m_browseListCtrl.GetSelectedCount();
-       int             nItem = -1;
-       UINT    i;
-
-       // Update all of the selected items.
-
-       for ( i = 0; i < selectedCount; i++ )
-       {
-               nItem = m_browseListCtrl.GetNextItem( -1, LVNI_SELECTED );
-               check( nItem != -1 );
-
-               m_browseListCtrl.DeleteItem( nItem );
-
-               SetModified( TRUE );
-       }
-
-       m_removeButton.EnableWindow( FALSE );
-}
-
-
-void
-CThirdPage::OnLvnItemchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult)
-{
-       if ( m_browseListCtrl.GetSelectedCount() )
-       {
-               m_removeButton.EnableWindow( TRUE );
-       }
-
-       if ( m_initialized )
-       {
-               NM_LISTVIEW * pNMListView = (NM_LISTVIEW*)pNMHDR; 
-        
-               BOOL bPrevState = (BOOL) ( ( ( pNMListView->uOldState & LVIS_STATEIMAGEMASK ) >> 12 ) - 1 ); 
-        
-               if ( bPrevState < 0 )
-               {
-                       bPrevState = 0;
-               }
-
-
-               BOOL bChecked = ( BOOL ) ( ( ( pNMListView->uNewState & LVIS_STATEIMAGEMASK ) >> 12) - 1 ); 
-        
-               if ( bChecked < 0 )
-               {
-                       bChecked = 0;
-               }
-
-               if ( bPrevState != bChecked )
-               {
-                       SetModified( TRUE );
-               }
-       }
-
-       *pResult = 0;
-}
-
-
-
-int CALLBACK 
-CThirdPage::SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
-{
-       CString str1;
-       CString str2;
-       int             ret = 0;
-
-       CThirdPage * self = reinterpret_cast<CThirdPage*>( lParamSort );
-       require_quiet( self, exit );
-
-       str1 = self->m_browseListCtrl.GetItemText( (int) lParam1, 1 );
-       str2 = self->m_browseListCtrl.GetItemText( (int) lParam2, 1 );
-
-       ret = str1.Compare( str2 );
-
-exit:
-
-       return ret;
-}
-
-
-// CAddBrowseDomain dialog
-
-IMPLEMENT_DYNAMIC(CAddBrowseDomain, CDialog)
-CAddBrowseDomain::CAddBrowseDomain(CWnd* pParent /*=NULL*/)
-       : CDialog(CAddBrowseDomain::IDD, pParent)
-{
-}
-
-CAddBrowseDomain::~CAddBrowseDomain()
-{
-}
-
-void CAddBrowseDomain::DoDataExchange(CDataExchange* pDX)
-{
-       CDialog::DoDataExchange(pDX);
-       DDX_Control(pDX, IDC_COMBO1, m_comboBox);
-}
-
-
-BOOL
-CAddBrowseDomain::OnInitDialog()
-{
-       CConfigPropertySheet    *       psheet;
-       CConfigPropertySheet::StringList::iterator              it;
-       
-       BOOL b = CDialog::OnInitDialog();
-
-       psheet = reinterpret_cast<CConfigPropertySheet*>(GetParent());
-       require_quiet( psheet, exit );
-
-       for ( it = psheet->m_browseDomains.begin(); it != psheet->m_browseDomains.end(); it++ )
-       {
-               CString text = *it;
-
-               if ( m_comboBox.FindStringExact( -1, *it ) == CB_ERR )
-               {
-                       m_comboBox.AddString( *it );
-               }
-       }
-
-exit:
-
-       return b;
-}
-
-
-void
-CAddBrowseDomain::OnOK()
-{
-       m_comboBox.GetWindowText( m_text );
-
-       CDialog::OnOK();
-}
-
-
-
-BEGIN_MESSAGE_MAP(CAddBrowseDomain, CDialog)
-END_MESSAGE_MAP()
-
diff --git a/mDNSWindows/ControlPanel/ThirdPage.h b/mDNSWindows/ControlPanel/ThirdPage.h
deleted file mode 100755 (executable)
index 6c1146c..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: ThirdPage.h,v $
-Revision 1.3  2006/08/14 23:25:29  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2005/03/03 19:55:21  shersche
-<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-
-
-*/
-
-#pragma once
-
-#include "stdafx.h"
-#include "resource.h"
-
-#include <DebugServices.h>
-#include <list>
-#include "afxcmn.h"
-
-#include "afxwin.h"
-
-
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CThirdPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CThirdPage : public CPropertyPage
-{
-public:
-       CThirdPage();
-       ~CThirdPage();
-
-protected:
-
-       //{{AFX_DATA(CThirdPage)
-       enum { IDD = IDR_APPLET_PAGE3 };
-       //}}AFX_DATA
-
-       //{{AFX_VIRTUAL(CThirdPage)
-       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
-       //}}AFX_VIRTUAL
-
-       DECLARE_DYNCREATE(CThirdPage)
-
-       //{{AFX_MSG(CThirdPage)
-       //}}AFX_MSG
-       DECLARE_MESSAGE_MAP()
-       
-private:
-       
-       typedef std::list<CString> StringList;
-
-       afx_msg BOOL
-       OnSetActive();
-       
-       afx_msg void
-       OnOK();
-       
-       void
-       SetModified( BOOL bChanged = TRUE );
-       
-       void
-       Commit();
-
-       BOOL                    m_modified;
-
-public:
-private:
-
-       static int CALLBACK 
-
-       SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
-
-
-
-       CListCtrl       m_browseListCtrl;
-
-       bool            m_initialized;
-
-       bool            m_firstTime;
-
-
-
-public:
-
-
-
-       afx_msg void OnBnClickedAddBrowseDomain();
-
-       afx_msg void OnBnClickedRemoveBrowseDomain();
-
-       afx_msg void OnLvnItemchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult);
-
-       CButton m_removeButton;
-
-};
-
-
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CAddBrowseDomain
-//---------------------------------------------------------------------------------------------------------------------------
-
-
-class CAddBrowseDomain : public CDialog
-
-{
-
-       DECLARE_DYNAMIC(CAddBrowseDomain)
-
-
-
-public:
-
-       CAddBrowseDomain(CWnd* pParent = NULL);   // standard constructor
-
-       virtual ~CAddBrowseDomain();
-
-
-
-// Dialog Data
-
-       enum { IDD = IDR_ADD_BROWSE_DOMAIN };
-
-
-
-protected:
-
-       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
-
-       virtual BOOL OnInitDialog();
-
-       virtual void OnOK();
-
-       DECLARE_MESSAGE_MAP()
-
-public:
-
-       CComboBox       m_comboBox;
-
-       CString         m_text;
-
-};
-
diff --git a/mDNSWindows/ControlPanel/res/EnergySaver.ico b/mDNSWindows/ControlPanel/res/EnergySaver.ico
new file mode 100755 (executable)
index 0000000..c2b935b
Binary files /dev/null and b/mDNSWindows/ControlPanel/res/EnergySaver.ico differ
index 021f1340bb67605958a2c039a35b8d473e17420a..7ef6ebba8736befa713155fd78f42635d7621b5f 100755 (executable)
Binary files a/mDNSWindows/ControlPanel/res/controlpanel.ico and b/mDNSWindows/ControlPanel/res/controlpanel.ico differ
index e82d604477d6b15ed4009bd8aca9c38ac23602a3..fec673fa4cf13a63642a4b35528c76a2e4a3afe5 100644 (file)
@@ -9,37 +9,48 @@
 #define IDR_SECRET                      133
 #define IDR_APPLET_PAGE3                134
 #define IDR_APPLET_PAGE4                135
+#define IDR_APPLET_PAGE5                136
 #define IDI_FAILURE                     140
 #define IDI_SUCCESS                     141
-#define IDD_ADD_BROWSE_DOMAIN           142
-#define IDR_ADD_BROWSE_DOMAIN           142
-#define IDC_EDIT1                       1000
-#define IDC_BUTTON1                     1001
-#define IDC_COMBO1                      1002
-#define IDC_CHECK1                      1003
-#define IDC_COMBO2                      1004
-#define IDC_EDIT2                       1005
-#define IDC_SECRET                      1005
-#define IDC_COMBO3                      1007
-#define IDC_FAILURE                     1008
-#define IDC_SUCCESS                     1009
-#define IDC_SECRET_NAME                 1010
-#define IDC_NAME                        1010
-#define IDC_KEY                         1010
-#define IDC_LIST1                       1011
-#define IDC_BROWSE_LIST                 1011
-#define IDC_BUTTON2                     1012
-#define IDC_REMOVE_BROWSE_DOMAIN        1012
-#define IDC_ADD_BROWSE_DOMAIN           1013
-#define IDC_POWER_MANAGEMENT            1014
+#define IDI_ENERGY_SAVER                               142
+#define IDR_ADD_BROWSE_DOMAIN           143
+#define IDR_POWER_MANAGEMENT_WARNING   144
+#define IDS_REINSTALL                                  145
+#define IDS_REINSTALL_CAPTION                  146
+#define IDS_APPLET_NAME                                        147
+#define IDS_APPLET_TOOLTIP                             148
+#define IDC_HOSTNAME                    1000
+#define IDC_USERNAME                                   1001
+#define IDC_PASSWORD                                   1002
+#define IDC_ADVERTISE_SERVICES                 1003
+#define IDC_BUTTON1                     1004
+#define IDC_COMBO1                      1005
+#define IDC_CHECK1                      1006
+#define IDC_COMBO2                      1007
+#define IDC_EDIT2                       1008
+#define IDC_SECRET                      1009
+#define IDC_COMBO3                      1010
+#define IDC_FAILURE                     1011
+#define IDC_SUCCESS                     1012
+#define IDC_SECRET_NAME                 1013
+#define IDC_NAME                        1014
+#define IDC_KEY                         1015
+#define IDC_LIST1                       1016
+#define IDC_BROWSE_LIST                 1017
+#define IDC_BUTTON2                     1018
+#define IDC_REMOVE_BROWSE_DOMAIN        1019
+#define IDC_ADD_BROWSE_DOMAIN           1020
+#define IDC_POWER_MANAGEMENT            1021
+#define IDC_ADVERTISE_SMB                  1022
+#define IDC_ENERGY_SAVER                               1023
 
 // Next default values for new objects
 // 
 #ifdef APSTUDIO_INVOKED
 #ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        143
+#define _APS_NEXT_RESOURCE_VALUE        149
 #define _APS_NEXT_COMMAND_VALUE         32771
-#define _APS_NEXT_CONTROL_VALUE         1015
+#define _APS_NEXT_CONTROL_VALUE         1024
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif
index 4bab622206c2b3ccb2aea0c6b846f465cc580b7c..e05ec3d102540f453e9220be593ddbbc1995fd52 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: stdafx.cpp,v $
-Revision 1.3  2006/08/14 23:25:29  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2005/03/03 19:55:22  shersche
-<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-
-
-*/
+ */
 
 #include "stdafx.h"
 
index 1a04b6c72a058c5bafaeb397b1d475e6538d63cc..246752e31c08ac4a3793895fe12c0eb8bde993d6 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: stdafx.h,v $
-Revision 1.4  2006/08/14 23:25:29  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2005/10/19 19:50:35  herscher
-Workaround a bug in the latest Microsoft Platform SDK when compiling C++ files that include (directly or indirectly) <WspiApi.h>
-
-Revision 1.2  2005/03/03 19:55:21  shersche
-<rdar://problem/4034481> ControlPanel source code isn't saving CVS log info
-
-
-*/
+ */
 
 #pragma once
 
index d99c8ab72246f81d20f03601100bc3ca9c5f970c..40f0b5db6f471b93693e22546610c4527012b405 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: AssemblyInfo.cpp,v $
-Revision 1.6  2009/03/30 20:16:27  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.5  2006/08/14 23:25:43  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.4  2004/07/26 21:03:00  shersche
-enable strong naming for dnssd.NET assembly
-
-Revision 1.3  2004/07/14 19:54:57  shersche
-use version file to get version numbers
-
-Revision 1.2  2004/07/14 15:42:47  shersche
-remove entries for strong authentication
-
-Revision 1.1  2004/06/26 04:01:22  shersche
-Initial revision
-
-
  */
     
 #include "stdafx.h"
index 1886c4475f12eb05ff60ac6aa627502cb14c5293..0249c05c66e7224a2787d6c220ebafb68d9b3eee 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: PString.h,v $
-Revision 1.3  2006/08/14 23:25:43  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/19 16:08:56  shersche
-fix problems in UTF8/Unicode string translations
-
-Revision 1.1  2004/06/26 04:01:22  shersche
-Initial revision
-
-
  */
     
 #pragma once
index 54ff68e5b429947c59a6039730c89b2c88d34606..ef03e217879d60582c6c1e804ffeefd61fe4cafc 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: Stdafx.cpp,v $
-Revision 1.3  2006/08/14 23:25:43  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2005/02/05 02:37:01  cheshire
-Convert newlines to Unix-style (ASCII 10)
-
-Revision 1.1  2004/06/26 04:01:22  shersche
-Initial revision
-
  */
     
 // stdafx.cpp : source file that includes just the standard includes
index ff4647d739041dcc8ecfe9f369c3fc0c6912b6c5..d2e5c1a8f2927a272c1f611b14ba160f4798d158 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: Stdafx.h,v $
-Revision 1.6  2009/03/30 20:17:57  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.5  2006/08/14 23:25:43  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.4  2005/10/19 19:50:35  herscher
-Workaround a bug in the latest Microsoft Platform SDK when compiling C++ files that include (directly or indirectly) <WspiApi.h>
-
-Revision 1.3  2005/02/05 02:40:59  cheshire
-Convert newlines to Unix-style (ASCII 10)
-
-Revision 1.2  2005/02/05 02:37:01  cheshire
-Convert newlines to Unix-style (ASCII 10)
-
-Revision 1.1  2004/06/26 04:01:22  shersche
-Initial revision
-
  */
     
 // stdafx.h : include file for standard system include files,
index b30699e8b22b1ebb4eafe72c2e5e8f153323c394..3e22146ee84225e3c78b186657327974112233a3 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: dnssd_NET.cpp,v $
-Revision 1.11  2009/03/30 20:19:05  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.10  2006/08/14 23:25:43  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.9  2004/09/16 18:17:13  shersche
-Use background threads, cleanup to parameter names.
-Submitted by: prepin@gmail.com
-
-Revision 1.8  2004/09/13 19:35:58  shersche
-<rdar://problem/3798941> Add Apple.DNSSD namespace to MC++ wrapper class
-<rdar://problem/3798950> Change all instances of unsigned short to int
-Bug #: 3798941, 3798950
-
-Revision 1.7  2004/09/11 00:36:40  shersche
-<rdar://problem/3786226> Modified .NET shim code to use host byte order for ports in APIs and callbacks
-Bug #: 3786226
-
-Revision 1.6  2004/09/02 21:20:56  cheshire
-<rdar://problem/3774871> DLL.NET crashes on null record
-
-Revision 1.5  2004/07/27 07:12:56  shersche
-make TextRecord an instantiable class object
-
-Revision 1.4  2004/07/26 06:19:05  shersche
-Treat byte arrays of zero-length as null arrays
-
-Revision 1.3  2004/07/19 16:08:56  shersche
-fix problems in UTF8/Unicode string translations
-
-Revision 1.2  2004/07/19 07:48:34  shersche
-fix bug in DNSService.Register when passing in NULL text record, add TextRecord APIs
-
-Revision 1.1  2004/06/26 04:01:22  shersche
-Initial revision
-
-
  */
     
 // This is the main DLL file.
index 999e6898af3b620b0a18a55baee92498f19e5e59..3e0196d29c11c24dd90351808a39e254777a2cba 100755 (executable)
  * 
  * <http://lists.apple.com/bonjour-dev/>
  * 
-
-    Change History (most recent first):
-
-$Log: dnssd_NET.h,v $
-Revision 1.9  2006/08/14 23:25:43  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.8  2005/02/10 22:35:33  cheshire
-<rdar://problem/3727944> Update name
-
-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
-
-Revision 1.5  2004/09/16 18:16:27  shersche
-Cleanup to parameter names
-Submitted by: prepin@gmail.com
-
-Revision 1.4  2004/09/13 19:35:57  shersche
-<rdar://problem/3798941> Add Apple.DNSSD namespace to MC++ wrapper class
-<rdar://problem/3798950> Change all instances of unsigned short to int
-Bug #: 3798941, 3798950
-
-Revision 1.3  2004/07/27 07:12:10  shersche
-make TextRecord an instantiable class object
-
-Revision 1.2  2004/07/19 07:48:34  shersche
-fix bug in DNSService.Register when passing in NULL text record, add TextRecord APIs
-
-Revision 1.1  2004/06/26 04:01:22  shersche
-Initial revision
-
-
  */
     
 #pragma once
index 0e3ea786a4cfcb353261343c1dc019a8bb232f77..79f3bb78e2114fc6a17e6f97fbf618fad070196a 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: dllmain.c,v $
-Revision 1.4  2006/08/14 23:25:41  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2005/07/07 19:18:29  shersche
-Fix error in previous checkin, change SystemServiceIsDisabled() to IsSystemServiceDisabled()
-
-Revision 1.2  2005/06/30 17:55:35  shersche
-<rdar://problem/4096913> Implement ISSystemServiceDisabled().  This is used to determine how long we should wait to connect to the system service.
-
-Revision 1.1  2004/06/18 03:55:11  rpantos
-Move DLL up to main level; additional integration from Scott.
-
-Revision 1.1  2004/02/21 04:16:50  bradley
-DLL wrapper for DNS-SD API.
-
-*/
+ */
 
 #include <windows.h>
 #include <DebugServices.h>
index 008ad970cc90624917e434e57dcdec858029b6e5..160510b4a0866dc8a070a248ad367cce80cd62fa 100644 (file)
 ; See the License for the specific language governing permissions and
 ; limitations under the License.
 ;
-;      Change History (most recent first):
-;    
-; $Log: dnssd.def,v $
-; Revision 1.5  2009/03/30 20:14:27  herscher
-; <rdar://problem/5925472> Current Bonjour code does not compile on Windows
-;
-; Revision 1.4  2006/09/27 00:46:18  herscher
-; <rdar://problem/4249761> API: Need DNSServiceGetAddrInfo()
-;
-; Revision 1.3  2006/08/14 23:25:41  cheshire
-; Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-;
-; Revision 1.2  2004/07/19 07:43:59  shersche
-; export TXTRecord APIs
-;
-; Revision 1.1  2004/06/18 03:55:11  rpantos
-; Move DLL up to main level; additional integration from Scott.
-;
-; Revision 1.2  2004/03/19 10:07:14  bradley
-; Export all DNS-SD API symbols from the DLL so they can be used by clients.
-;
-; Revision 1.1  2004/02/21 04:16:50  bradley
-; DLL wrapper for DNS-SD API.
-;
-;
-;
 
 LIBRARY                dnssd
 
index 22a6e3d9aac87007421382e0163cb234bb822916..1bfb5ccc77718adb65ee0cf100556b6f0d64e844 100644 (file)
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;             mkdir &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot; mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\include&quot;                      mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\include&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                            &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(OutDir)\dnssd.lib&quot;                                                                    &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\..\mDNSShared\dns_sd.h&quot;                                 &quot;$(DSTROOT)\Program Files\Bonjour SDK\include&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;             mkdir &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\include&quot;                      mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\include&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                            &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\..\mDNSShared\dns_sd.h&quot;                                 &quot;$(DSTROOT)\Program Files\Bonjour SDK\include&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
                <Configuration\r
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;             mkdir &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot; mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\include&quot;                      mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\include&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                            &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(OutDir)\dnssd.lib&quot;                                                                    &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;             mkdir &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\include&quot;                      mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\include&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                            &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
        </Configurations>\r
index b693b27e70a725fa0673215d787506d74e04a6b9..8029219ed524ac7b613f34f460b5a027f6f40055 100755 (executable)
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot; mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot;&#x0D;&#x0A;echo F | xcopy /Y &quot;$(OutDir)\dnssdStatic.lib&quot;                                                        &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)\dnssd.lib&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
                <Configuration\r
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot; mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot;&#x0D;&#x0A;echo F | xcopy /I/Y &quot;$(OutDir)\dnssdStatic.lib&quot;                                                     &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)\dnssd.lib&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
        </Configurations>\r
index 7cc6c63714ab9892534c6d0d10a954d31816c033..77883ccd8248f27f00e7856ff98c0cc757adf12e 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
+
+
+
+
+
+#include "stdafx.h"
+
+#include "resource.h"
+
+#include "DLLX.h"
+
+#include "dlldatax.h"
+
+#include <DebugServices.h>
+
+
+
+
+
+class CDLLComponentModule : public CAtlDllModuleT< CDLLComponentModule >
+
+{
+
+public :
+
+       DECLARE_LIBID(LIBID_Bonjour)
+
+       DECLARE_REGISTRY_APPID_RESOURCEID(IDR_DLLX, "{56608F9C-223B-4CB6-813D-85EDCCADFB4B}")
+
+};
+
+
+
+CDLLComponentModule _AtlModule;
+
+
+
+
+
+#ifdef _MANAGED
+
+#pragma managed(push, off)
+
+#endif
+
+
+
+// DLL Entry Point
+
+extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
+
+{
 
-    Change History (most recent first):
-    
-$Log: DLLX.cpp,v $
-Revision 1.1  2009/05/26 04:43:54  herscher
-<rdar://problem/3948252> COM component that can be used with any .NET language and VB.
-\r
-\r
-*/\r
-\r
-\r
-#include "stdafx.h"\r
-#include "resource.h"\r
-#include "DLLX.h"\r
-#include "dlldatax.h"\r
-#include <DebugServices.h>\r
-\r
-\r
-class CDLLComponentModule : public CAtlDllModuleT< CDLLComponentModule >\r
-{\r
-public :\r
-       DECLARE_LIBID(LIBID_Bonjour)\r
-       DECLARE_REGISTRY_APPID_RESOURCEID(IDR_DLLX, "{56608F9C-223B-4CB6-813D-85EDCCADFB4B}")\r
-};\r
-\r
-CDLLComponentModule _AtlModule;\r
-\r
-\r
-#ifdef _MANAGED\r
-#pragma managed(push, off)\r
-#endif\r
-\r
-// DLL Entry Point\r
-extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)\r
-{\r
        debug_initialize( kDebugOutputTypeWindowsDebugger );
-       debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );\r
-\r
-#ifdef _MERGE_PROXYSTUB\r
-    if (!PrxDllMain(hInstance, dwReason, lpReserved))\r
-        return FALSE;\r
-#endif\r
-       hInstance;\r
-    return _AtlModule.DllMain(dwReason, lpReserved); \r
-}\r
-\r
-#ifdef _MANAGED\r
-#pragma managed(pop)\r
-#endif\r
-\r
-\r
-\r
-\r
-// Used to determine whether the DLL can be unloaded by OLE\r
-STDAPI DllCanUnloadNow(void)\r
-{\r
-#ifdef _MERGE_PROXYSTUB\r
-    HRESULT hr = PrxDllCanUnloadNow();\r
-    if (hr != S_OK)\r
-        return hr;\r
-#endif\r
-    return _AtlModule.DllCanUnloadNow();\r
-}\r
-\r
-\r
-// Returns a class factory to create an object of the requested type\r
-STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)\r
-{\r
-#ifdef _MERGE_PROXYSTUB\r
-    if (PrxDllGetClassObject(rclsid, riid, ppv) == S_OK)\r
-        return S_OK;\r
-#endif\r
-    return _AtlModule.DllGetClassObject(rclsid, riid, ppv);\r
-}\r
-\r
-\r
-// DllRegisterServer - Adds entries to the system registry\r
-STDAPI DllRegisterServer(void)\r
-{\r
-    // registers object, typelib and all interfaces in typelib\r
-    HRESULT hr = _AtlModule.DllRegisterServer();\r
-#ifdef _MERGE_PROXYSTUB\r
-    if (FAILED(hr))\r
-        return hr;\r
-    hr = PrxDllRegisterServer();\r
-#endif\r
-       return hr;\r
-}\r
-\r
-\r
-// DllUnregisterServer - Removes entries from the system registry\r
-STDAPI DllUnregisterServer(void)\r
-{\r
-       HRESULT hr = _AtlModule.DllUnregisterServer();\r
-#ifdef _MERGE_PROXYSTUB\r
-    if (FAILED(hr))\r
-        return hr;\r
-    hr = PrxDllRegisterServer();\r
-    if (FAILED(hr))\r
-        return hr;\r
-    hr = PrxDllUnregisterServer();\r
-#endif\r
-       return hr;\r
-}\r
-\r
+       debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
+
+
+
+#ifdef _MERGE_PROXYSTUB
+
+    if (!PrxDllMain(hInstance, dwReason, lpReserved))
+
+        return FALSE;
+
+#endif
+
+       hInstance;
+
+    return _AtlModule.DllMain(dwReason, lpReserved); 
+
+}
+
+
+
+#ifdef _MANAGED
+
+#pragma managed(pop)
+
+#endif
+
+
+
+
+
+
+
+
+
+// Used to determine whether the DLL can be unloaded by OLE
+
+STDAPI DllCanUnloadNow(void)
+
+{
+
+#ifdef _MERGE_PROXYSTUB
+
+    HRESULT hr = PrxDllCanUnloadNow();
+
+    if (hr != S_OK)
+
+        return hr;
+
+#endif
+
+    return _AtlModule.DllCanUnloadNow();
+
+}
+
+
+
+
+
+// Returns a class factory to create an object of the requested type
+
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
+
+{
+
+#ifdef _MERGE_PROXYSTUB
+
+    if (PrxDllGetClassObject(rclsid, riid, ppv) == S_OK)
+
+        return S_OK;
+
+#endif
+
+    return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
+
+}
+
+
+
+
+
+// DllRegisterServer - Adds entries to the system registry
+
+STDAPI DllRegisterServer(void)
+
+{
+
+    // registers object, typelib and all interfaces in typelib
+
+    HRESULT hr = _AtlModule.DllRegisterServer();
+
+#ifdef _MERGE_PROXYSTUB
+
+    if (FAILED(hr))
+
+        return hr;
+
+    hr = PrxDllRegisterServer();
+
+#endif
+
+       return hr;
+
+}
+
+
+
+
+
+// DllUnregisterServer - Removes entries from the system registry
+
+STDAPI DllUnregisterServer(void)
+
+{
+
+       HRESULT hr = _AtlModule.DllUnregisterServer();
+
+#ifdef _MERGE_PROXYSTUB
+
+    if (FAILED(hr))
+
+        return hr;
+
+    hr = PrxDllRegisterServer();
+
+    if (FAILED(hr))
+
+        return hr;
+
+    hr = PrxDllUnregisterServer();
+
+#endif
+
+       return hr;
+
+}
+
+
+
index 3029b69d2ec23c10caa8c0452742989abb746224..698b1722e4516906f07d8a2630639c0cf272b511 100755 (executable)
 ; See the License for the specific language governing permissions and
 ; limitations under the License.
 ;
-;   Change History (most recent first):
-;   
-; $Log: DLLX.def,v $
-; Revision 1.1  2009/05/26 04:43:54  herscher
-; <rdar://problem/3948252> COM component that can be used with any .NET language and VB.
-;\r
-;\r
-;\r
-\r
-\r
-LIBRARY      "dnssdX.DLL"\r
-\r
-EXPORTS\r
-       DllCanUnloadNow         PRIVATE\r
-       DllGetClassObject       PRIVATE\r
-       DllRegisterServer       PRIVATE\r
-       DllUnregisterServer     PRIVATE\r
+
+
+
+
+
+LIBRARY      "dnssdX.DLL"
+
+
+
+EXPORTS
+
+       DllCanUnloadNow         PRIVATE
+
+       DllGetClassObject       PRIVATE
+
+       DllRegisterServer       PRIVATE
+
+       DllUnregisterServer     PRIVATE
+
index 05725e8565cb80d513d53557363b04bf1ac3519f..475558e3ccf0a8ab483933637a8a9a526c7ff36f 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
+
+
+
+// This file will be processed by the MIDL tool to
+
+// produce the type library (DLLComponent.tlb) and marshalling code.
+
+
+
+typedef [ uuid(4085DD59-D0E1-4efe-B6EE-DDBF7631B9C0) ]
+
+enum DNSSDFlags
+
+{
+
+       kDNSSDFlagsMoreComing                   = 0x0001,
+
+       kDNSSDFlagsDefault                              = 0x0004,
+
+       kDNSSDFlagsNoAutoRename                 = 0x0008,
+
+       kDNSSDFlagsShared                               = 0x0010,
+
+       kDNSSDFlagsUnique                               = 0x0020,
+
+       kDNSSDFlagsBrowseDomains                = 0x0040,
+
+       kDNSSDFlagsRegistrationDomains  = 0x0080,
+
+       kDNSSDFlagsLongLivedQuery               = 0x0100,
+
+       kDNSSDFlagsAllowRemoteQuery             = 0x0200,
+
+       kDNSSDFlagsForceMulticast               = 0x0400,
+
+       kDNSSDFlagsForce                                = 0x0800,
+
+       kDNSSDFlagsReturnIntermediates  = 0x1000,
+
+       kDNSSDFlagsNonBrowsable                 = 0x2000
+
+} DNSSDFlags;
+
+
+
+
+
+typedef [ uuid(30CDF335-CA52-4b17-AFF2-E83C64C450D4) ]
+
+enum DNSSDAddressFamily
+
+{
+
+       kDNSSDAddressFamily_IPv4 = 0x1,
+
+       kDNSSDAddressFamily_IPv6 = 0x2
+
+} DNSSDAddressFamily;
+
+
+
+
+
+typedef [ uuid(98FB4702-7374-4b16-A8DB-AD35BFB8364D) ]
+
+enum DNSSDProtocol
+
+{
+
+       kDNSSDProtocol_UDP      = 0x10,
+
+       kDNSSDProtocol_TCP      = 0x20
+
+} DNSSDProtocol;
+
+
+
+
+
+typedef [ uuid(72BF3EC3-19BC-47e5-8D95-3B73FF37D893) ]
+
+enum DNSSDRRClass
+
+{
+
+       kDNSSDClass_IN = 1
+
+} DNSSDRRClass;
+
+
+
+
+
+typedef [ uuid(08E362DF-5468-4c9a-AC66-FD4747B917BD) ]
+
+enum DNSSDRRType
+
+{
 
-    Change History (most recent first):
-    
-$Log: DLLX.idl,v $
-Revision 1.1  2009/05/26 04:43:54  herscher
-<rdar://problem/3948252> COM component that can be used with any .NET language and VB.
-\r
-\r
-*/\r
-\r
-// This file will be processed by the MIDL tool to\r
-// produce the type library (DLLComponent.tlb) and marshalling code.\r
-\r
-typedef [ uuid(4085DD59-D0E1-4efe-B6EE-DDBF7631B9C0) ]\r
-enum DNSSDFlags\r
-{\r
-       kDNSSDFlagsMoreComing                   = 0x0001,\r
-       kDNSSDFlagsDefault                              = 0x0004,\r
-       kDNSSDFlagsNoAutoRename                 = 0x0008,\r
-       kDNSSDFlagsShared                               = 0x0010,\r
-       kDNSSDFlagsUnique                               = 0x0020,\r
-       kDNSSDFlagsBrowseDomains                = 0x0040,\r
-       kDNSSDFlagsRegistrationDomains  = 0x0080,\r
-       kDNSSDFlagsLongLivedQuery               = 0x0100,\r
-       kDNSSDFlagsAllowRemoteQuery             = 0x0200,\r
-       kDNSSDFlagsForceMulticast               = 0x0400,\r
-       kDNSSDFlagsForce                                = 0x0800,\r
-       kDNSSDFlagsReturnIntermediates  = 0x1000,\r
-       kDNSSDFlagsNonBrowsable                 = 0x2000\r
-} DNSSDFlags;\r
-\r
-\r
-typedef [ uuid(30CDF335-CA52-4b17-AFF2-E83C64C450D4) ]\r
-enum DNSSDAddressFamily\r
-{\r
-       kDNSSDAddressFamily_IPv4 = 0x1,\r
-       kDNSSDAddressFamily_IPv6 = 0x2\r
-} DNSSDAddressFamily;\r
-\r
-\r
-typedef [ uuid(98FB4702-7374-4b16-A8DB-AD35BFB8364D) ]\r
-enum DNSSDProtocol\r
-{\r
-       kDNSSDProtocol_UDP      = 0x10,\r
-       kDNSSDProtocol_TCP      = 0x20\r
-} DNSSDProtocol;\r
-\r
-\r
-typedef [ uuid(72BF3EC3-19BC-47e5-8D95-3B73FF37D893) ]\r
-enum DNSSDRRClass\r
-{\r
-       kDNSSDClass_IN = 1\r
-} DNSSDRRClass;\r
-\r
-\r
-typedef [ uuid(08E362DF-5468-4c9a-AC66-FD4747B917BD) ]\r
-enum DNSSDRRType\r
-{\r
        kDNSSDType_A         = 1,
     kDNSSDType_NS        = 2,
     kDNSSDType_MD        = 3,
@@ -134,11 +176,16 @@ enum DNSSDRRType
     kDNSSDType_AXFR      = 252,
     kDNSSDType_MAILB     = 253,
     kDNSSDType_MAILA     = 254,
-    kDNSSDType_ANY       = 255\r
-} DNSSDRRType;\r
-\r
-\r
-typedef [ uuid(3B0059E7-5297-4301-9AAB-1522F31EC8A7) ]\r
+    kDNSSDType_ANY       = 255
+
+} DNSSDRRType;
+
+
+
+
+
+typedef [ uuid(3B0059E7-5297-4301-9AAB-1522F31EC8A7) ]
+
 enum DNSSDError
 {
        kDNSSDError_NoError                   = 0,
@@ -172,138 +219,273 @@ enum DNSSDError
     kDNSSDError_NATPortMappingDisabled    = -65565,  /* NAT supports NAT-PMP or UPnP but it's disabled by the administrator */
     kDNSSDError_NoRouter                  = -65566,  /* No router currently configured (probably no network connectivity) */
     kDNSSDError_PollingMode               = -65567
-} DNSSDError;\r
-\r
-import "oaidl.idl";\r
-import "ocidl.idl";\r
-\r
-\r
-[\r
-       object,\r
-       uuid(8FA0889C-5973-4FC9-970B-EC15C925D0CE),\r
-       dual,\r
-       nonextensible,\r
-       helpstring("ITXTRecord Interface"),\r
-       pointer_default(unique)\r
-]\r
-interface ITXTRecord : IDispatch{\r
-       [id(1), helpstring("method SetValue")] HRESULT SetValue([in] BSTR key, [in] VARIANT value);\r
-       [id(2), helpstring("method RemoveValue")] HRESULT RemoveValue([in] BSTR key);\r
-       [id(3), helpstring("method ContainsKey")] HRESULT ContainsKey([in] BSTR key, [out,retval] VARIANT_BOOL* retval);\r
-       [id(4), helpstring("method GetValueForKey")] HRESULT GetValueForKey([in] BSTR key, [out,retval] VARIANT* value);\r
-       [id(5), helpstring("method GetCount")] HRESULT GetCount([out,retval] ULONG* count);\r
-       [id(6), helpstring("method GetKeyAtIndex")] HRESULT GetKeyAtIndex([in] ULONG index, [out,retval] BSTR* retval);\r
-       [id(7), helpstring("method GetValueAtIndex")] HRESULT GetValueAtIndex([in] ULONG index, [out,retval] VARIANT* retval);\r
-};\r
-[\r
-       object,\r
-       uuid(9CE603A0-3365-4DA0-86D1-3F780ECBA110),\r
-       dual,\r
-       nonextensible,\r
-       helpstring("IDNSSDRecord Interface"),\r
-       pointer_default(unique)\r
-]\r
-interface IDNSSDRecord : IDispatch{\r
-       [id(1), helpstring("method Update")] HRESULT Update([in] DNSSDFlags flags, [in] VARIANT rdata, [in] ULONG ttl);\r
-       [id(2), helpstring("method Remove")] HRESULT Remove([in] DNSSDFlags flags);\r
-};\r
-[\r
-       object,\r
-       uuid(7FD72324-63E1-45AD-B337-4D525BD98DAD),\r
-       dual,\r
-       nonextensible,\r
-       helpstring("IDNSSDEventManager Interface"),\r
-       pointer_default(unique)\r
-]\r
-interface IDNSSDEventManager : IDispatch{\r
-};\r
-[\r
-       object,\r
-       uuid(29DE265F-8402-474F-833A-D4653B23458F),\r
-       dual,\r
-       nonextensible,\r
-       helpstring("IDNSSDService Interface"),\r
-       pointer_default(unique)\r
-]\r
-interface IDNSSDService : IDispatch{\r
-       [id(1), helpstring("method EnumerateDomains")] HRESULT EnumerateDomains([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);\r
-       [id(2), helpstring("method Browse"), local] HRESULT Browse([in] DNSSDFlags flags, [in] ULONG interfaceIndex, [in] BSTR regtype, [in] BSTR domain, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** sdref);\r
-       [id(3), helpstring("method Resolve")] HRESULT Resolve([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR serviceName, [in] BSTR regType, [in] BSTR domain, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);\r
-       [id(4), helpstring("method Register")] HRESULT Register([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR name, [in] BSTR regType, [in] BSTR domain, [in] BSTR host, [in] USHORT port, [in] ITXTRecord* record, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);\r
-       [id(5), helpstring("method QueryRecord")] HRESULT QueryRecord([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullname, [in] DNSSDRRType rrtype, [in] DNSSDRRClass rrclass, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);\r
-       [id(6), helpstring("method RegisterRecord")] HRESULT RegisterRecord([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullname, [in] DNSSDRRType rrtype, [in] DNSSDRRClass rrclass, [in] VARIANT rdata, [in] ULONG ttl, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDRecord** record);\r
-       [id(7), helpstring("method AddRecord")] HRESULT AddRecord([in] DNSSDFlags flags, [in] DNSSDRRType rrtype, [in] VARIANT rdata, [in] ULONG ttl, [out,retval] IDNSSDRecord** record);\r
-       [id(8), helpstring("method ReconfirmRecord")] HRESULT ReconfirmRecord([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullname, [in] DNSSDRRType rrtype, [in] DNSSDRRClass rrclass, [in] VARIANT rdata);\r
-       [id(9), helpstring("method GetProperty")] HRESULT GetProperty([in] BSTR prop, [in,out] VARIANT * value );       \r
-       [id(10), helpstring("method GetAddrInfo")] HRESULT GetAddrInfo([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] DNSSDAddressFamily addressFamily, [in] BSTR hostname, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);\r
-       [id(11), helpstring("method NATPortMappingCreate")] HRESULT NATPortMappingCreate([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] DNSSDAddressFamily addressFamily, [in] DNSSDProtocol protocol, [in] USHORT internalPort, [in] USHORT externalPort, [in] ULONG ttl, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);\r
-       [id(12), helpstring("method Stop"), local] HRESULT Stop(void);\r
-};\r
-[\r
-       uuid(18FBED6D-F2B7-4EC8-A4A4-46282E635308),\r
-       version(1.0),\r
-       helpstring("Apple Bonjour Library 1.0")\r
-]\r
-library Bonjour\r
-{\r
-       importlib("stdole2.tlb");\r
-       [\r
-               uuid(21AE8D7F-D5FE-45cf-B632-CFA2C2C6B498),\r
-               helpstring("_IDNSSDEvents Interface")\r
-       ]\r
-       dispinterface _IDNSSDEvents\r
-       {\r
-               properties:\r
-               methods:\r
-               [id(1), helpstring("method DomainFound")] void DomainFound([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR domain);\r
-               [id(2), helpstring("method DomainLost")] void DomainLost([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR domain);\r
-               [id(3), helpstring("method ServiceFound")] void ServiceFound([in] IDNSSDService* browser, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR serviceName, [in] BSTR regType, [in] BSTR domain);\r
-               [id(4), helpstring("method ServiceLost")] void ServiceLost([in] IDNSSDService* browser, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR serviceName, [in] BSTR regType, [in] BSTR domain);\r
-               [id(5), helpstring("method ServiceResolved")] void ServiceResolved([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullName, [in] BSTR hostName, [in] USHORT port, [in] ITXTRecord* record);\r
-               [id(6), helpstring("method ServiceRegistered")] void ServiceRegistered([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] BSTR name, [in] BSTR regType, [in] BSTR domain);\r
-               [id(7), helpstring("method QueryRecordAnswered")] void QueryRecordAnswered([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullName, [in] DNSSDRRType rrtype, [in] DNSSDRRClass rrclass, [in] VARIANT rdata, [in] ULONG ttl);\r
-               [id(8), helpstring("method RecordRegistered")] void RecordRegistered([in] IDNSSDRecord* record, [in] DNSSDFlags flags);\r
-               [id(9), helpstring("method AddressFound")] void AddressFound([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR hostname, [in] DNSSDAddressFamily addressFamily, [in] BSTR address, [in] ULONG ttl);\r
-               [id(10), helpstring("method MappingCreated")] void MappingCreated([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] ULONG externalAddress, [in] DNSSDAddressFamily addressFamily, [in] DNSSDProtocol protocol, [in] USHORT internalPort, [in] USHORT externalPort, [in] ULONG ttl);\r
-               [id(11), helpstring("method OperationFailed")] void OperationFailed([in] IDNSSDService* service, [in] DNSSDError error);\r
-       };\r
-       [\r
-               uuid(24CD4DE9-FF84-4701-9DC1-9B69E0D1090A),\r
-               helpstring("DNSSDService Class")\r
-       ]\r
-       coclass DNSSDService\r
-       {\r
-               [default] interface IDNSSDService;\r
-       };\r
-       [\r
-               uuid(AFEE063C-05BA-4248-A26E-168477F49734),\r
-               helpstring("TXTRecord Class")\r
-       ]\r
-       coclass TXTRecord\r
-       {\r
-               [default] interface ITXTRecord;\r
-       };\r
-       [\r
-               uuid(5E93C5A9-7516-4259-A67B-41A656F6E01C),\r
-               helpstring("DNSSDRecord Class")\r
-       ]\r
-       coclass DNSSDRecord\r
-       {\r
-               [default] interface IDNSSDRecord;\r
-       };\r
-       [\r
-               uuid(BEEB932A-8D4A-4619-AEFE-A836F988B221),\r
-               helpstring("DNSSDEventManager Class")\r
-       ]\r
-       coclass DNSSDEventManager\r
-       {\r
-               [default] interface IDNSSDEventManager;\r
-               [default, source] dispinterface _IDNSSDEvents;\r
-       };\r
-       enum DNSSDFlags;\r
-       enum DNSSDAddressFamily;\r
-       enum DNSSDProtocol;\r
-       enum DNSSDRRClass;\r
-       enum DNSSDRRType;\r
-       enum DNSSDError;\r
-};\r
+} DNSSDError;
+
+
+
+import "oaidl.idl";
+
+import "ocidl.idl";
+
+
+
+
+
+[
+
+       object,
+
+       uuid(8FA0889C-5973-4FC9-970B-EC15C925D0CE),
+
+       dual,
+
+       nonextensible,
+
+       helpstring("ITXTRecord Interface"),
+
+       pointer_default(unique)
+
+]
+
+interface ITXTRecord : IDispatch{
+
+       [id(1), helpstring("method SetValue")] HRESULT SetValue([in] BSTR key, [in] VARIANT value);
+
+       [id(2), helpstring("method RemoveValue")] HRESULT RemoveValue([in] BSTR key);
+
+       [id(3), helpstring("method ContainsKey")] HRESULT ContainsKey([in] BSTR key, [out,retval] VARIANT_BOOL* retval);
+
+       [id(4), helpstring("method GetValueForKey")] HRESULT GetValueForKey([in] BSTR key, [out,retval] VARIANT* value);
+
+       [id(5), helpstring("method GetCount")] HRESULT GetCount([out,retval] ULONG* count);
+
+       [id(6), helpstring("method GetKeyAtIndex")] HRESULT GetKeyAtIndex([in] ULONG index, [out,retval] BSTR* retval);
+
+       [id(7), helpstring("method GetValueAtIndex")] HRESULT GetValueAtIndex([in] ULONG index, [out,retval] VARIANT* retval);
+
+};
+
+[
+
+       object,
+
+       uuid(9CE603A0-3365-4DA0-86D1-3F780ECBA110),
+
+       dual,
+
+       nonextensible,
+
+       helpstring("IDNSSDRecord Interface"),
+
+       pointer_default(unique)
+
+]
+
+interface IDNSSDRecord : IDispatch{
+
+       [id(1), helpstring("method Update")] HRESULT Update([in] DNSSDFlags flags, [in] VARIANT rdata, [in] ULONG ttl);
+
+       [id(2), helpstring("method Remove")] HRESULT Remove([in] DNSSDFlags flags);
+
+};
+
+[
+
+       object,
+
+       uuid(7FD72324-63E1-45AD-B337-4D525BD98DAD),
+
+       dual,
+
+       nonextensible,
+
+       helpstring("IDNSSDEventManager Interface"),
+
+       pointer_default(unique)
+
+]
+
+interface IDNSSDEventManager : IDispatch{
+
+};
+
+[
+
+       object,
+
+       uuid(29DE265F-8402-474F-833A-D4653B23458F),
+
+       dual,
+
+       nonextensible,
+
+       helpstring("IDNSSDService Interface"),
+
+       pointer_default(unique)
+
+]
+
+interface IDNSSDService : IDispatch{
+
+       [id(1), helpstring("method EnumerateDomains")] HRESULT EnumerateDomains([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);
+
+       [id(2), helpstring("method Browse"), local] HRESULT Browse([in] DNSSDFlags flags, [in] ULONG interfaceIndex, [in] BSTR regtype, [in] BSTR domain, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** sdref);
+
+       [id(3), helpstring("method Resolve")] HRESULT Resolve([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR serviceName, [in] BSTR regType, [in] BSTR domain, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);
+
+       [id(4), helpstring("method Register")] HRESULT Register([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR name, [in] BSTR regType, [in] BSTR domain, [in] BSTR host, [in] USHORT port, [in] ITXTRecord* record, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);
+
+       [id(5), helpstring("method QueryRecord")] HRESULT QueryRecord([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullname, [in] DNSSDRRType rrtype, [in] DNSSDRRClass rrclass, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);
+
+       [id(6), helpstring("method RegisterRecord")] HRESULT RegisterRecord([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullname, [in] DNSSDRRType rrtype, [in] DNSSDRRClass rrclass, [in] VARIANT rdata, [in] ULONG ttl, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDRecord** record);
+
+       [id(7), helpstring("method AddRecord")] HRESULT AddRecord([in] DNSSDFlags flags, [in] DNSSDRRType rrtype, [in] VARIANT rdata, [in] ULONG ttl, [out,retval] IDNSSDRecord** record);
+
+       [id(8), helpstring("method ReconfirmRecord")] HRESULT ReconfirmRecord([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullname, [in] DNSSDRRType rrtype, [in] DNSSDRRClass rrclass, [in] VARIANT rdata);
+
+       [id(9), helpstring("method GetProperty")] HRESULT GetProperty([in] BSTR prop, [in,out] VARIANT * value );       
+
+       [id(10), helpstring("method GetAddrInfo")] HRESULT GetAddrInfo([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] DNSSDAddressFamily addressFamily, [in] BSTR hostname, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);
+
+       [id(11), helpstring("method NATPortMappingCreate")] HRESULT NATPortMappingCreate([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] DNSSDAddressFamily addressFamily, [in] DNSSDProtocol protocol, [in] USHORT internalPort, [in] USHORT externalPort, [in] ULONG ttl, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);
+
+       [id(12), helpstring("method Stop"), local] HRESULT Stop(void);
+
+};
+
+[
+
+       uuid(18FBED6D-F2B7-4EC8-A4A4-46282E635308),
+
+       version(1.0),
+
+       helpstring("Apple Bonjour Library 1.0")
+
+]
+
+library Bonjour
+
+{
+
+       importlib("stdole2.tlb");
+
+       [
+
+               uuid(21AE8D7F-D5FE-45cf-B632-CFA2C2C6B498),
+
+               helpstring("_IDNSSDEvents Interface")
+
+       ]
+
+       dispinterface _IDNSSDEvents
+
+       {
+
+               properties:
+
+               methods:
+
+               [id(1), helpstring("method DomainFound")] void DomainFound([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR domain);
+
+               [id(2), helpstring("method DomainLost")] void DomainLost([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR domain);
+
+               [id(3), helpstring("method ServiceFound")] void ServiceFound([in] IDNSSDService* browser, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR serviceName, [in] BSTR regType, [in] BSTR domain);
+
+               [id(4), helpstring("method ServiceLost")] void ServiceLost([in] IDNSSDService* browser, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR serviceName, [in] BSTR regType, [in] BSTR domain);
+
+               [id(5), helpstring("method ServiceResolved")] void ServiceResolved([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullName, [in] BSTR hostName, [in] USHORT port, [in] ITXTRecord* record);
+
+               [id(6), helpstring("method ServiceRegistered")] void ServiceRegistered([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] BSTR name, [in] BSTR regType, [in] BSTR domain);
+
+               [id(7), helpstring("method QueryRecordAnswered")] void QueryRecordAnswered([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullName, [in] DNSSDRRType rrtype, [in] DNSSDRRClass rrclass, [in] VARIANT rdata, [in] ULONG ttl);
+
+               [id(8), helpstring("method RecordRegistered")] void RecordRegistered([in] IDNSSDRecord* record, [in] DNSSDFlags flags);
+
+               [id(9), helpstring("method AddressFound")] void AddressFound([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR hostname, [in] DNSSDAddressFamily addressFamily, [in] BSTR address, [in] ULONG ttl);
+
+               [id(10), helpstring("method MappingCreated")] void MappingCreated([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] ULONG externalAddress, [in] DNSSDAddressFamily addressFamily, [in] DNSSDProtocol protocol, [in] USHORT internalPort, [in] USHORT externalPort, [in] ULONG ttl);
+
+               [id(11), helpstring("method OperationFailed")] void OperationFailed([in] IDNSSDService* service, [in] DNSSDError error);
+
+       };
+
+       [
+
+               uuid(24CD4DE9-FF84-4701-9DC1-9B69E0D1090A),
+
+               helpstring("DNSSDService Class")
+
+       ]
+
+       coclass DNSSDService
+
+       {
+
+               [default] interface IDNSSDService;
+
+       };
+
+       [
+
+               uuid(AFEE063C-05BA-4248-A26E-168477F49734),
+
+               helpstring("TXTRecord Class")
+
+       ]
+
+       coclass TXTRecord
+
+       {
+
+               [default] interface ITXTRecord;
+
+       };
+
+       [
+
+               uuid(5E93C5A9-7516-4259-A67B-41A656F6E01C),
+
+               helpstring("DNSSDRecord Class")
+
+       ]
+
+       coclass DNSSDRecord
+
+       {
+
+               [default] interface IDNSSDRecord;
+
+       };
+
+       [
+
+               uuid(BEEB932A-8D4A-4619-AEFE-A836F988B221),
+
+               helpstring("DNSSDEventManager Class")
+
+       ]
+
+       coclass DNSSDEventManager
+
+       {
+
+               [default] interface IDNSSDEventManager;
+
+               [default, source] dispinterface _IDNSSDEvents;
+
+       };
+
+       enum DNSSDFlags;
+
+       enum DNSSDAddressFamily;
+
+       enum DNSSDProtocol;
+
+       enum DNSSDRRClass;
+
+       enum DNSSDRRType;
+
+       enum DNSSDError;
+
+};
+
index af3248cedefa6a5623883faab327311449eb3339..310ced0e7956d4a2c6919cd6bd397bfc8bc97e60 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
+
+
+
+#include "stdafx.h"
+
+#include "DNSSDEventManager.h"
+
+
+
+
+
+// CDNSSDEventManager
+
+
 
-    Change History (most recent first):
-    
-$Log: DNSSDEventManager.cpp,v $
-Revision 1.1  2009/05/26 04:43:54  herscher
-<rdar://problem/3948252> COM component that can be used with any .NET language and VB.
-\r
-\r
-*/\r
-\r
-#include "stdafx.h"\r
-#include "DNSSDEventManager.h"\r
-\r
-\r
-// CDNSSDEventManager\r
-\r
index 3e43b2e822bdfa15439fe897d650e37774a49ca4..70aedfc92f016bae3ed7acd5675110dceca1b46d 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
+
+
+
+#pragma once
+
+#include "resource.h"       // main symbols
+
+
+
+#include "DLLX.h"
+
+#include "_IDNSSDEvents_CP.H"
+
+
+
+
+
+#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
+
+#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
+
+#endif
+
+
+
+
+
+
+
+// CDNSSDEventManager
+
+
+
+class ATL_NO_VTABLE CDNSSDEventManager :
+
+       public CComObjectRootEx<CComSingleThreadModel>,
+
+       public CComCoClass<CDNSSDEventManager, &CLSID_DNSSDEventManager>,
+
+       public IConnectionPointContainerImpl<CDNSSDEventManager>,
+
+       public CProxy_IDNSSDEvents<CDNSSDEventManager>,
+
+       public IDispatchImpl<IDNSSDEventManager, &IID_IDNSSDEventManager, &LIBID_Bonjour, /*wMajor =*/ 1, /*wMinor =*/ 0>
+
+{
+
+public:
+
+       CDNSSDEventManager()
+
+       {
+
+       }
+
+
+
+DECLARE_REGISTRY_RESOURCEID(IDR_DNSSDEVENTMANAGER)
+
+
+
+
+
+BEGIN_COM_MAP(CDNSSDEventManager)
+
+       COM_INTERFACE_ENTRY(IDNSSDEventManager)
+
+       COM_INTERFACE_ENTRY(IDispatch)
+
+       COM_INTERFACE_ENTRY(IConnectionPointContainer)
+
+END_COM_MAP()
+
+
+
+BEGIN_CONNECTION_POINT_MAP(CDNSSDEventManager)
+
+       CONNECTION_POINT_ENTRY(__uuidof(_IDNSSDEvents))
+
+END_CONNECTION_POINT_MAP()
+
+
+
+
+
+       DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+
+
+       HRESULT FinalConstruct()
+
+       {
+
+               return S_OK;
+
+       }
+
+
+
+       void FinalRelease()
+
+       {
+
+       }
+
+
+
+public:
+
+
+
+};
+
+
+
+OBJECT_ENTRY_AUTO(__uuidof(DNSSDEventManager), CDNSSDEventManager)
 
-    Change History (most recent first):
-    
-$Log: DNSSDEventManager.h,v $
-Revision 1.1  2009/05/26 04:43:54  herscher
-<rdar://problem/3948252> COM component that can be used with any .NET language and VB.
-\r
-\r
-*/\r
-\r
-#pragma once\r
-#include "resource.h"       // main symbols\r
-\r
-#include "DLLX.h"\r
-#include "_IDNSSDEvents_CP.H"\r
-\r
-\r
-#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)\r
-#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."\r
-#endif\r
-\r
-\r
-\r
-// CDNSSDEventManager\r
-\r
-class ATL_NO_VTABLE CDNSSDEventManager :\r
-       public CComObjectRootEx<CComSingleThreadModel>,\r
-       public CComCoClass<CDNSSDEventManager, &CLSID_DNSSDEventManager>,\r
-       public IConnectionPointContainerImpl<CDNSSDEventManager>,\r
-       public CProxy_IDNSSDEvents<CDNSSDEventManager>,\r
-       public IDispatchImpl<IDNSSDEventManager, &IID_IDNSSDEventManager, &LIBID_Bonjour, /*wMajor =*/ 1, /*wMinor =*/ 0>\r
-{\r
-public:\r
-       CDNSSDEventManager()\r
-       {\r
-       }\r
-\r
-DECLARE_REGISTRY_RESOURCEID(IDR_DNSSDEVENTMANAGER)\r
-\r
-\r
-BEGIN_COM_MAP(CDNSSDEventManager)\r
-       COM_INTERFACE_ENTRY(IDNSSDEventManager)\r
-       COM_INTERFACE_ENTRY(IDispatch)\r
-       COM_INTERFACE_ENTRY(IConnectionPointContainer)\r
-END_COM_MAP()\r
-\r
-BEGIN_CONNECTION_POINT_MAP(CDNSSDEventManager)\r
-       CONNECTION_POINT_ENTRY(__uuidof(_IDNSSDEvents))\r
-END_CONNECTION_POINT_MAP()\r
-\r
-\r
-       DECLARE_PROTECT_FINAL_CONSTRUCT()\r
-\r
-       HRESULT FinalConstruct()\r
-       {\r
-               return S_OK;\r
-       }\r
-\r
-       void FinalRelease()\r
-       {\r
-       }\r
-\r
-public:\r
-\r
-};\r
-\r
-OBJECT_ENTRY_AUTO(__uuidof(DNSSDEventManager), CDNSSDEventManager)\r
index 37955afd77268099124b5979aea3d28d3efba4ff..a27272077255b19517bf929a4ba0205926dce6e0 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
+
+
+
+#include "stdafx.h"
+
+#include "DNSSDRecord.h"
+
+#include "StringServices.h"
+
+#include <DebugServices.h>
+
+
+
+
+
+// CDNSSDRecord
+
+
+
+STDMETHODIMP CDNSSDRecord::Update(DNSSDFlags flags, VARIANT rdata, ULONG ttl)
+
+{
+
+       std::vector< BYTE >     byteArray;
+
+       const void              *       byteArrayPtr    = NULL;
+
+       DNSServiceErrorType     err                             = 0;
+
+       HRESULT                         hr                              = 0;
+
+       BOOL                            ok;
+
+
+
+       // Convert the VARIANT
+
+       ok = VariantToByteArray( &rdata, byteArray );
+
+       require_action( ok, exit, err = kDNSServiceErr_Unknown );
+
+
+
+       err = DNSServiceUpdateRecord( m_serviceObject->GetSubordRef(), m_rref, flags, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL, ttl );
+
+       require_noerr( err, exit );
+
+
+
+exit:
+
+
+
+       return err;
+
+}
+
+
+
+
+
+STDMETHODIMP CDNSSDRecord::Remove(DNSSDFlags flags)
+
+{
+
+       DNSServiceErrorType     err = 0;
+
+
+
+       err = DNSServiceRemoveRecord( m_serviceObject->GetSubordRef(), m_rref, flags );
+
+       require_noerr( err, exit );
+
+
+
+exit:
+
+
+
+       return err;
+
+}
+
+
 
-    Change History (most recent first):
-    
-$Log: DNSSDRecord.cpp,v $
-Revision 1.1  2009/05/26 04:43:54  herscher
-<rdar://problem/3948252> COM component that can be used with any .NET language and VB.
-\r
-\r
-*/\r
-\r
-#include "stdafx.h"\r
-#include "DNSSDRecord.h"\r
-#include "StringServices.h"\r
-#include <DebugServices.h>\r
-\r
-\r
-// CDNSSDRecord\r
-\r
-STDMETHODIMP CDNSSDRecord::Update(DNSSDFlags flags, VARIANT rdata, ULONG ttl)\r
-{\r
-       std::vector< BYTE >     byteArray;\r
-       const void              *       byteArrayPtr    = NULL;\r
-       DNSServiceErrorType     err                             = 0;\r
-       HRESULT                         hr                              = 0;\r
-       BOOL                            ok;\r
-\r
-       // Convert the VARIANT\r
-       ok = VariantToByteArray( &rdata, byteArray );\r
-       require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
-\r
-       err = DNSServiceUpdateRecord( m_serviceObject->GetSubordRef(), m_rref, flags, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL, ttl );\r
-       require_noerr( err, exit );\r
-\r
-exit:\r
-\r
-       return err;\r
-}\r
-\r
-\r
-STDMETHODIMP CDNSSDRecord::Remove(DNSSDFlags flags)\r
-{\r
-       DNSServiceErrorType     err = 0;\r
-\r
-       err = DNSServiceRemoveRecord( m_serviceObject->GetSubordRef(), m_rref, flags );\r
-       require_noerr( err, exit );\r
-\r
-exit:\r
-\r
-       return err;\r
-}\r
-\r
index fcf5c74244c71e42f398b46d7535e9feb8a98f0f..bdedda50335546da19e6b5f748fb14e6664b1bb8 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
+
+
+
+#pragma once
+
+#include "resource.h"       // main symbols
+
+
+
+#include "DLLX.h"
+
+#include "DNSSDService.h"
+
+#include <dns_sd.h>
+
+
+
+
+
+#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
+
+#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
+
+#endif
+
+
+
+
+
+
+
+// CDNSSDRecord
+
+
+
+class ATL_NO_VTABLE CDNSSDRecord :
+
+       public CComObjectRootEx<CComSingleThreadModel>,
+
+       public CComCoClass<CDNSSDRecord, &CLSID_DNSSDRecord>,
+
+       public IDispatchImpl<IDNSSDRecord, &IID_IDNSSDRecord, &LIBID_Bonjour, /*wMajor =*/ 1, /*wMinor =*/ 0>
+
+{
+
+public:
+
+       CDNSSDRecord()
+
+       {
+
+       }
+
+
+
+DECLARE_REGISTRY_RESOURCEID(IDR_DNSSDRECORD)
+
+
+
+
+
+BEGIN_COM_MAP(CDNSSDRecord)
+
+       COM_INTERFACE_ENTRY(IDNSSDRecord)
+
+       COM_INTERFACE_ENTRY(IDispatch)
+
+END_COM_MAP()
+
+
+
+
+
+
+
+       DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+
+
+       HRESULT FinalConstruct()
+
+       {
+
+               return S_OK;
+
+       }
+
+
+
+       void FinalRelease()
+
+       {
+
+       }
+
+
+
+       inline CDNSSDService*
+
+       GetServiceObject()
+
+       {
+
+               return m_serviceObject;
+
+       }
+
+
+
+       inline void
+
+       SetServiceObject( CDNSSDService * serviceObject )
+
+       {
+
+               m_serviceObject = serviceObject;
+
+       }
+
+
+
+       inline DNSRecordRef
+
+       GetRecordRef()
+
+       {
+
+               return m_rref;
+
+       }
+
+
+
+       inline void
+
+       SetRecordRef( DNSRecordRef rref )
+
+       {
+
+               m_rref = rref;
+
+       }
+
+
+
+public:
+
+
+
+       STDMETHOD(Update)(DNSSDFlags flags, VARIANT rdata, ULONG ttl);
+
+       STDMETHOD(Remove)(DNSSDFlags flags);
+
+
+
+private:
+
+
+
+       CDNSSDService * m_serviceObject;
+
+       DNSRecordRef    m_rref;
+
+};
+
+
+
+OBJECT_ENTRY_AUTO(__uuidof(DNSSDRecord), CDNSSDRecord)
 
-    Change History (most recent first):
-    
-$Log: DNSSDRecord.h,v $
-Revision 1.1  2009/05/26 04:43:54  herscher
-<rdar://problem/3948252> COM component that can be used with any .NET language and VB.
-\r
-\r
-*/\r
-\r
-#pragma once\r
-#include "resource.h"       // main symbols\r
-\r
-#include "DLLX.h"\r
-#include "DNSSDService.h"\r
-#include <dns_sd.h>\r
-\r
-\r
-#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)\r
-#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."\r
-#endif\r
-\r
-\r
-\r
-// CDNSSDRecord\r
-\r
-class ATL_NO_VTABLE CDNSSDRecord :\r
-       public CComObjectRootEx<CComSingleThreadModel>,\r
-       public CComCoClass<CDNSSDRecord, &CLSID_DNSSDRecord>,\r
-       public IDispatchImpl<IDNSSDRecord, &IID_IDNSSDRecord, &LIBID_Bonjour, /*wMajor =*/ 1, /*wMinor =*/ 0>\r
-{\r
-public:\r
-       CDNSSDRecord()\r
-       {\r
-       }\r
-\r
-DECLARE_REGISTRY_RESOURCEID(IDR_DNSSDRECORD)\r
-\r
-\r
-BEGIN_COM_MAP(CDNSSDRecord)\r
-       COM_INTERFACE_ENTRY(IDNSSDRecord)\r
-       COM_INTERFACE_ENTRY(IDispatch)\r
-END_COM_MAP()\r
-\r
-\r
-\r
-       DECLARE_PROTECT_FINAL_CONSTRUCT()\r
-\r
-       HRESULT FinalConstruct()\r
-       {\r
-               return S_OK;\r
-       }\r
-\r
-       void FinalRelease()\r
-       {\r
-       }\r
-\r
-       inline CDNSSDService*\r
-       GetServiceObject()\r
-       {\r
-               return m_serviceObject;\r
-       }\r
-\r
-       inline void\r
-       SetServiceObject( CDNSSDService * serviceObject )\r
-       {\r
-               m_serviceObject = serviceObject;\r
-       }\r
-\r
-       inline DNSRecordRef\r
-       GetRecordRef()\r
-       {\r
-               return m_rref;\r
-       }\r
-\r
-       inline void\r
-       SetRecordRef( DNSRecordRef rref )\r
-       {\r
-               m_rref = rref;\r
-       }\r
-\r
-public:\r
-\r
-       STDMETHOD(Update)(DNSSDFlags flags, VARIANT rdata, ULONG ttl);\r
-       STDMETHOD(Remove)(DNSSDFlags flags);\r
-\r
-private:\r
-\r
-       CDNSSDService * m_serviceObject;\r
-       DNSRecordRef    m_rref;\r
-};\r
-\r
-OBJECT_ENTRY_AUTO(__uuidof(DNSSDRecord), CDNSSDRecord)\r
index 219c6100cef2cc8a3a04a87e1644ad8ad3b56a5f..b8ce49bea83c648e475e6d5befd5a2f17431d6a1 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
+
+
+
+#pragma warning(disable:4995)
+
+
+
+#include "stdafx.h"
+
+#include <strsafe.h>
+
+#include "DNSSDService.h"
+
+#include "DNSSDEventManager.h"
+
+#include "DNSSDRecord.h"
+
+#include "TXTRecord.h"
+
+#include "StringServices.h"
+
+#include <DebugServices.h>
+
+
+
+
+
+#define WM_SOCKET (WM_APP + 100)
+
+
+
+
+
+// CDNSSDService
+
+
+
+BOOL                                           CDNSSDService::m_registeredWindowClass  = FALSE;
+
+HWND                                           CDNSSDService::m_hiddenWindow                   = NULL;
+
+CDNSSDService::SocketMap       CDNSSDService::m_socketMap;
+
+
+
+
+
+HRESULT CDNSSDService::FinalConstruct()
+
+{
+
+       DNSServiceErrorType     err     = 0;
+
+       HRESULT                         hr      = S_OK;
+
+
+
+       m_isPrimary = TRUE;
+
+       err = DNSServiceCreateConnection( &m_primary );
+
+       require_action( !err, exit, hr = E_FAIL );
+
+
+
+       if ( !m_hiddenWindow )
+
+       {
+
+               TCHAR windowClassName[ 256 ];
+
+
+
+               StringCchPrintf( windowClassName, sizeof( windowClassName ) / sizeof( TCHAR ), TEXT( "Bonjour Hidden Window %d" ), GetProcessId( NULL ) );
+
+
+
+               if ( !m_registeredWindowClass )
+
+               {
+
+                       WNDCLASS        wc;
+
+                       ATOM            atom;
+
+
+
+                       wc.style                        = 0;
+
+                       wc.lpfnWndProc          = WndProc;
+
+                       wc.cbClsExtra           = 0;
+
+                       wc.cbWndExtra           = 0;
+
+                       wc.hInstance            = NULL;
+
+                       wc.hIcon                        = NULL;
+
+                       wc.hCursor                      = NULL;
+
+                       wc.hbrBackground        = NULL;
+
+                       wc.lpszMenuName         = NULL;
+
+                       wc.lpszClassName        = windowClassName;
+
+
+
+                       atom = RegisterClass(&wc);
+
+                       require_action( atom != NULL, exit, hr = E_FAIL );
+
+
+
+                       m_registeredWindowClass = TRUE;
+
+               }
+
+
+
+               m_hiddenWindow = CreateWindow( windowClassName, windowClassName, WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL, GetModuleHandle( NULL ), NULL );
+
+               require_action( m_hiddenWindow != NULL, exit, hr = E_FAIL );
+
+       }
+
+
+
+       err = WSAAsyncSelect( DNSServiceRefSockFD( m_primary ), m_hiddenWindow, WM_SOCKET, FD_READ );
+
+       require_action( !err, exit, hr = E_FAIL );
+
+
+
+       m_socketMap[ DNSServiceRefSockFD( m_primary ) ] = this;
+
+
+
+exit:
+
+
+
+       return hr;
+
+}
+
+
+
+
+
+void CDNSSDService::FinalRelease()
+
+{
+
+       dlog( kDebugLevelTrace, "FinalRelease()\n" ); 
+
+       Stop();
+
+}
+
+
+
+
+
+STDMETHODIMP CDNSSDService::EnumerateDomains(DNSSDFlags flags, ULONG ifIndex, IDNSSDEventManager *eventManager, IDNSSDService **service)
+
+{
+
+       CComObject<CDNSSDService>       *       object  = NULL;
+
+       DNSServiceRef                                   subord  = NULL;
+
+       DNSServiceErrorType                             err             = 0;
+
+       HRESULT                                                 hr              = 0;
+
+
+
+       check( m_primary );
+
+
+
+       // Initialize
+
+       *service = NULL;
+
+
+
+       try
+
+       {
+
+               object = new CComObject<CDNSSDService>();
+
+       }
+
+       catch ( ... )
+
+       {
+
+               object = NULL;
+
+       }
+
+
+
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
+
+       object->AddRef();
+
+
+
+       subord = m_primary;
+
+       err = DNSServiceEnumerateDomains( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, ( DNSServiceDomainEnumReply ) &DomainEnumReply, object );
+
+       require_noerr( err, exit );
+
+
+
+       object->SetPrimaryRef( m_primary );
+
+       object->SetSubordRef( subord );
+
+       object->SetEventManager( eventManager );
+
+
+
+       *service = object;
+
+
+
+exit:
+
+
+
+       if ( err && object )
+
+       {
+
+               object->Release();
+
+       }
+
+
+
+       return err;
+
+}
+
+
+
+
+
+STDMETHODIMP CDNSSDService::Browse(DNSSDFlags flags, ULONG ifIndex, BSTR regtype, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** service )
+
+{
+
+       CComObject<CDNSSDService>       *       object          = NULL;
+
+       std::string                                             regtypeUTF8;
+
+       std::string                                             domainUTF8;
+
+       DNSServiceRef                                   subord          = NULL;
+
+       DNSServiceErrorType                             err                     = 0;
+
+       HRESULT                                                 hr                      = 0;
+
+       BOOL                                                    ok;
+
+
+
+       check( m_primary );
+
+
+
+       // Initialize
+
+       *service = NULL;
+
+
+
+       // Convert BSTR params to utf8
+
+       ok = BSTRToUTF8( regtype, regtypeUTF8 );
+
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+
+       ok = BSTRToUTF8( domain, domainUTF8 );
+
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+
+
+
+       try
+
+       {
+
+               object = new CComObject<CDNSSDService>();
+
+       }
+
+       catch ( ... )
+
+       {
+
+               object = NULL;
+
+       }
+
+
+
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
+
+       object->AddRef();
+
+
+
+       subord = m_primary;
+
+       err = DNSServiceBrowse( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, regtypeUTF8.c_str(), ( domainUTF8.size() > 0 ) ? domainUTF8.c_str() : NULL, ( DNSServiceBrowseReply ) &BrowseReply, object );
+
+       require_noerr( err, exit );
+
+
+
+       object->SetPrimaryRef( m_primary );
+
+       object->SetSubordRef( subord );
+
+       object->SetEventManager( eventManager );
+
+
+
+       *service = object;
+
+
+
+exit:
+
+
+
+       if ( err && object )
+
+       {
+
+               object->Release();
+
+       }
+
+
+
+       return err;
+
+}
+
+
+
+
+
+STDMETHODIMP CDNSSDService::Resolve(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** service)
+
+{
+
+       CComObject<CDNSSDService>       *       object                  = NULL;
+
+       std::string                                             serviceNameUTF8;
+
+       std::string                                             regTypeUTF8;
+
+       std::string                                             domainUTF8;
+
+       DNSServiceRef                                   subord                  = NULL;
+
+       DNSServiceErrorType                             err                             = 0;
+
+       HRESULT                                                 hr                              = 0;
+
+       BOOL                                                    ok;
+
+
+
+       check( m_primary );
+
+
+
+       // Initialize
+
+       *service = NULL;
+
+
+
+       // Convert BSTR params to utf8
+
+       ok = BSTRToUTF8( serviceName, serviceNameUTF8 );
+
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+
+       ok = BSTRToUTF8( regType, regTypeUTF8 );
+
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+
+       ok = BSTRToUTF8( domain, domainUTF8 );
+
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+
+
+
+       try
+
+       {
+
+               object = new CComObject<CDNSSDService>();
+
+       }
+
+       catch ( ... )
+
+       {
+
+               object = NULL;
+
+       }
+
+
+
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
+
+       object->AddRef();
+
+
+
+       subord = m_primary;
+
+       err = DNSServiceResolve( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), domainUTF8.c_str(), ( DNSServiceResolveReply ) &ResolveReply, object );
+
+       require_noerr( err, exit );
+
+
+
+       object->SetPrimaryRef( m_primary );
+
+       object->SetSubordRef( subord );
+
+       object->SetEventManager( eventManager );
+
+
+
+       *service = object;
+
+
+
+exit:
+
+
+
+       if ( err && object )
+
+       {
+
+               object->Release();
+
+       }
+
+
+
+       return err;
+
+}
+
+
+
+
+
+STDMETHODIMP CDNSSDService::Register(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, BSTR host, USHORT port, ITXTRecord *record, IDNSSDEventManager *eventManager, IDNSSDService **service)
+
+{
+
+       CComObject<CDNSSDService>       *       object                  = NULL;
+
+       std::string                                             serviceNameUTF8;
+
+       std::string                                             regTypeUTF8;
+
+       std::string                                             domainUTF8;
+
+       std::string                                             hostUTF8;
+
+       const void                                      *       txtRecord               = NULL;
+
+       uint16_t                                                txtLen                  = 0;
+
+       DNSServiceRef                                   subord                  = NULL;
+
+       DNSServiceErrorType                             err                             = 0;
+
+       HRESULT                                                 hr                              = 0;
+
+       BOOL                                                    ok;
+
+
+
+       check( m_primary );
+
+
+
+       // Initialize
+
+       *service = NULL;
+
+
+
+       // Convert BSTR params to utf8
+
+       ok = BSTRToUTF8( serviceName, serviceNameUTF8 );
+
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+
+       ok = BSTRToUTF8( regType, regTypeUTF8 );
+
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+
+       ok = BSTRToUTF8( domain, domainUTF8 );
+
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+
+       ok = BSTRToUTF8( host, hostUTF8 );
+
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+
+
+
+       try
+
+       {
+
+               object = new CComObject<CDNSSDService>();
+
+       }
+
+       catch ( ... )
+
+       {
+
+               object = NULL;
+
+       }
+
+
+
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
+
+       object->AddRef();
+
+
+
+       if ( record )
+
+       {
+
+               CComObject< CTXTRecord > * realTXTRecord;
+
+
+
+               realTXTRecord = ( CComObject< CTXTRecord >* ) record;
+
+
+
+               txtRecord       = realTXTRecord->GetBytes();
+
+               txtLen          = realTXTRecord->GetLen();
+
+       }
+
+
+
+       subord = m_primary;
+
+       err = DNSServiceRegister( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), ( domainUTF8.size() > 0 ) ? domainUTF8.c_str() : NULL, hostUTF8.c_str(), htons( port ), txtLen, txtRecord, ( DNSServiceRegisterReply ) &RegisterReply, object );
+
+       require_noerr( err, exit );
+
+
+
+       object->SetPrimaryRef( m_primary );
+
+       object->SetSubordRef( subord );
+
+       object->SetEventManager( eventManager );
+
+
+
+       *service = object;
+
+
+
+exit:
+
+
+
+       if ( err && object )
+
+       {
+
+               object->Release();
+
+       }
+
+
+
+       return err;
+
+}
+
+
+
+
+
+STDMETHODIMP CDNSSDService::QueryRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, IDNSSDEventManager *eventManager, IDNSSDService **service)
+
+{
+
+       CComObject<CDNSSDService>       *       object                  = NULL;
+
+       DNSServiceRef                                   subord                  = NULL;
+
+       std::string                                             fullNameUTF8;
+
+       DNSServiceErrorType                             err                             = 0;
+
+       HRESULT                                                 hr                              = 0;
+
+       BOOL                                                    ok;
+
+
+
+       check( m_primary );
+
+
+
+       // Initialize
+
+       *service = NULL;
+
+
+
+       // Convert BSTR params to utf8
+
+       ok = BSTRToUTF8( fullname, fullNameUTF8 );
+
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+
+
+
+       try
+
+       {
+
+               object = new CComObject<CDNSSDService>();
+
+       }
+
+       catch ( ... )
+
+       {
+
+               object = NULL;
+
+       }
+
+
+
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
+
+       object->AddRef();
+
+
+
+       subord = m_primary;
+
+       err = DNSServiceQueryRecord( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, fullNameUTF8.c_str(), ( uint16_t ) rrtype, ( uint16_t ) rrclass, ( DNSServiceQueryRecordReply ) &QueryRecordReply, object );
+
+       require_noerr( err, exit );
+
+
+
+       object->SetPrimaryRef( m_primary );
+
+       object->SetSubordRef( subord );
+
+       object->SetEventManager( eventManager );
+
+
+
+       *service = object;
+
+
+
+exit:
+
+
+
+       if ( err && object )
+
+       {
+
+               object->Release();
+
+       }
+
+
+
+       return err;
+
+}
+
+
+
+
+
+STDMETHODIMP CDNSSDService::RegisterRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullName, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata, ULONG ttl, IDNSSDEventManager* eventManager, IDNSSDRecord** record)
+
+{
+
+       CComObject<CDNSSDRecord>        *       object                  = NULL;
+
+       DNSRecordRef                                    rref                    = NULL;
+
+       std::string                                             fullNameUTF8;
+
+       std::vector< BYTE >                             byteArray;
+
+       const void                                      *       byteArrayPtr    = NULL;
+
+       DNSServiceErrorType                             err                             = 0;
+
+       HRESULT                                                 hr                              = 0;
+
+       BOOL                                                    ok;
+
+
+
+       check( m_primary );
+
+
+
+       // Initialize
+
+       *object = NULL;
+
+
+
+       // Convert BSTR params to utf8
+
+       ok = BSTRToUTF8( fullName, fullNameUTF8 );
+
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+
+
+
+       // Convert the VARIANT
+
+       ok = VariantToByteArray( &rdata, byteArray );
+
+       require_action( ok, exit, err = kDNSServiceErr_Unknown );
+
+
+
+       try
+
+       {
+
+               object = new CComObject<CDNSSDRecord>();
+
+       }
+
+       catch ( ... )
+
+       {
+
+               object = NULL;
+
+       }
+
+
+
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
+
+       object->AddRef();
+
+
+
+       err = DNSServiceRegisterRecord( m_primary, &rref, flags, ifIndex, fullNameUTF8.c_str(), rrtype, rrclass, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL, ttl, &RegisterRecordReply, object );
+
+       require_noerr( err, exit );
+
+
+
+       object->SetServiceObject( this );
+
+       object->SetRecordRef( rref );
+
+       this->SetEventManager( eventManager );
+
+
+
+       *record = object;
+
+
+
+exit:
+
+
+
+       if ( err && object )
+
+       {
+
+               object->Release();
+
+       }
+
+
+
+       return err;
+
+}
+
+
+
+
+
+STDMETHODIMP CDNSSDService::AddRecord(DNSSDFlags flags, DNSSDRRType rrtype, VARIANT rdata, ULONG ttl, IDNSSDRecord ** record)
+
+{
+
+       CComObject<CDNSSDRecord>        *       object                  = NULL;
+
+       DNSRecordRef                                    rref                    = NULL;
+
+       std::vector< BYTE >                             byteArray;
+
+       const void                                      *       byteArrayPtr    = NULL;
+
+       DNSServiceErrorType                             err                             = 0;
+
+       HRESULT                                                 hr                              = 0;
+
+       BOOL                                                    ok;
+
+
+
+       check( m_primary );
+
+
+
+       // Initialize
+
+       *object = NULL;
+
+
+
+       // Convert the VARIANT
+
+       ok = VariantToByteArray( &rdata, byteArray );
+
+       require_action( ok, exit, err = kDNSServiceErr_Unknown );
+
+
+
+       try
+
+       {
+
+               object = new CComObject<CDNSSDRecord>();
+
+       }
+
+       catch ( ... )
+
+       {
+
+               object = NULL;
+
+       }
+
+
+
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
+
+       object->AddRef();
+
+
+
+       err = DNSServiceAddRecord( m_primary, &rref, flags, rrtype, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL, ttl );
+
+       require_noerr( err, exit );
+
+
+
+       object->SetServiceObject( this );
+
+       object->SetRecordRef( rref );
+
+
+
+       *record = object;
+
+
+
+exit:
+
+
+
+       if ( err && object )
+
+       {
+
+               object->Release();
+
+       }
+
+
+
+       return err;
+
+}
+
+
+
+STDMETHODIMP CDNSSDService::ReconfirmRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullName, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata)
+
+{
+
+       std::string                                             fullNameUTF8;
+
+       std::vector< BYTE >                             byteArray;
+
+       const void                                      *       byteArrayPtr    = NULL;
+
+       DNSServiceErrorType                             err                             = 0;
+
+       HRESULT                                                 hr                              = 0;
+
+       BOOL                                                    ok;
+
+
+
+       // Convert BSTR params to utf8
+
+       ok = BSTRToUTF8( fullName, fullNameUTF8 );
+
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+
+
+
+       // Convert the VARIANT
+
+       ok = VariantToByteArray( &rdata, byteArray );
+
+       require_action( ok, exit, err = kDNSServiceErr_Unknown );
+
+
+
+       err = DNSServiceReconfirmRecord( flags, ifIndex, fullNameUTF8.c_str(), rrtype, rrclass, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL );
+
+       require_noerr( err, exit );
+
+
+
+exit:
+
+
+
+       return err;
+
+}
+
+
+
+
+
+STDMETHODIMP CDNSSDService::GetProperty(BSTR prop, VARIANT * value )
+
+{
+
+       std::string                     propUTF8;
+
+       std::vector< BYTE >     byteArray;
+
+       SAFEARRAY               *       psa                     = NULL;
+
+       BYTE                    *       pData           = NULL;
+
+       uint32_t                        elems           = 0;
+
+       DNSServiceErrorType     err                     = 0;
+
+       BOOL                            ok = TRUE;
+
+
+
+       // Convert BSTR params to utf8
+
+       ok = BSTRToUTF8( prop, propUTF8 );
+
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+
+
+
+       // Setup the byte array
+
+       require_action( V_VT( value ) == ( VT_ARRAY|VT_UI1 ), exit, err = kDNSServiceErr_Unknown );
+
+       psa = V_ARRAY( value );
+
+       require_action( psa, exit, err = kDNSServiceErr_Unknown );
+
+       require_action( SafeArrayGetDim( psa ) == 1, exit, err = kDNSServiceErr_Unknown );
+
+       byteArray.reserve( psa->rgsabound[0].cElements );
+
+       byteArray.assign( byteArray.capacity(), 0 );
+
+       elems = ( uint32_t ) byteArray.capacity();
+
+
+
+       // Call the function and package the return value in the Variant
+
+       err = DNSServiceGetProperty( propUTF8.c_str(), &byteArray[ 0 ], &elems );
+
+       require_noerr( err, exit );
+
+       ok = ByteArrayToVariant( &byteArray[ 0 ], elems, value );
+
+       require_action( ok, exit, err = kDNSSDError_Unknown );
+
+
+
+exit:
+
+
+
+       if ( psa )
+
+       {
+
+               SafeArrayUnaccessData( psa );
+
+               psa = NULL;
+
+       }
+
+
+
+       return err;
+
+}
+
+
+
+STDMETHODIMP CDNSSDService::GetAddrInfo(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, BSTR hostName, IDNSSDEventManager *eventManager, IDNSSDService **service)
+
+{
+
+       CComObject<CDNSSDService>       *       object                  = NULL;
+
+       DNSServiceRef                                   subord                  = NULL;
+
+       std::string                                             hostNameUTF8;
+
+       DNSServiceErrorType                             err                             = 0;
+
+       HRESULT                                                 hr                              = 0;
+
+       BOOL                                                    ok;
+
+
+
+       check( m_primary );
+
+
+
+       // Initialize
+
+       *service = NULL;
+
+
+
+       // Convert BSTR params to utf8
+
+       ok = BSTRToUTF8( hostName, hostNameUTF8 );
+
+       require_action( ok, exit, err = kDNSServiceErr_BadParam );
+
+
+
+       try
+
+       {
+
+               object = new CComObject<CDNSSDService>();
+
+       }
+
+       catch ( ... )
+
+       {
+
+               object = NULL;
+
+       }
+
+
+
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
+
+       object->AddRef();
+
+
+
+       subord = m_primary;
+
+       err = DNSServiceGetAddrInfo( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, addressFamily, hostNameUTF8.c_str(), ( DNSServiceGetAddrInfoReply ) &GetAddrInfoReply, object );
+
+       require_noerr( err, exit );
+
+
+
+       object->SetPrimaryRef( m_primary );
+
+       object->SetSubordRef( subord );
+
+       object->SetEventManager( eventManager );
+
+
+
+       *service = object;
+
+
+
+exit:
+
+
+
+       if ( err && object )
+
+       {
+
+               object->Release();
+
+       }
+
+
+
+       return err;
+
+}
+
+
+
+
+
+STDMETHODIMP CDNSSDService::NATPortMappingCreate(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, DNSSDProtocol protocol, USHORT internalPort, USHORT externalPort, ULONG ttl, IDNSSDEventManager *eventManager, IDNSSDService **service)
+
+{
+
+       CComObject<CDNSSDService>       *       object                  = NULL;
+
+       DNSServiceRef                                   subord                  = NULL;
+
+       DNSServiceProtocol                              prot                    = 0;
+
+       DNSServiceErrorType                             err                             = 0;
+
+       HRESULT                                                 hr                              = 0;
+
+
+
+       check( m_primary );
+
+
+
+       // Initialize
+
+       *service = NULL;
+
+
+
+       try
+
+       {
+
+               object = new CComObject<CDNSSDService>();
+
+       }
+
+       catch ( ... )
+
+       {
+
+               object = NULL;
+
+       }
+
+
+
+       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
+
+       object->AddRef();
+
+
+
+       prot = ( addressFamily | protocol );
+
+
+
+       subord = m_primary;
+
+       err = DNSServiceNATPortMappingCreate( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, prot, htons( internalPort ), htons( externalPort ), ttl, ( DNSServiceNATPortMappingReply ) &NATPortMappingReply, object );
+
+       require_noerr( err, exit );
+
+
+
+       object->SetPrimaryRef( m_primary );
+
+       object->SetSubordRef( subord );
+
+       object->SetEventManager( eventManager );
+
+
+
+       *service = object;
+
+
+
+exit:
+
+
+
+       if ( err && object )
+
+       {
+
+               object->Release();
+
+       }
+
+
+
+       return err;
+
+}
+
+
+
+
+
+STDMETHODIMP CDNSSDService::Stop(void)
+
+{
+
+       if ( !m_stopped )
+
+       {
+
+               m_stopped = TRUE;
+
+
+
+               dlog( kDebugLevelTrace, "Stop()\n" );
+
+
+
+               if ( m_isPrimary && m_primary )
+
+               {
+
+                       SocketMap::iterator it;
+
+
+
+                       if ( m_hiddenWindow )
+
+                       {
+
+                               WSAAsyncSelect( DNSServiceRefSockFD( m_primary ), m_hiddenWindow, 0, 0 );
+
+                       }
+
+
+
+                       it = m_socketMap.find( DNSServiceRefSockFD( m_primary ) );
+
+
+
+                       if ( it != m_socketMap.end() )
+
+                       {
+
+                               m_socketMap.erase( it );
+
+                       }
+
+
+
+                       DNSServiceRefDeallocate( m_primary );
+
+                       m_primary = NULL;
+
+               }
+
+               else if ( m_subord )
+
+               {
+
+                       DNSServiceRefDeallocate( m_subord );
+
+                       m_subord = NULL;
+
+               }
+
+
+
+               if ( m_eventManager != NULL )
+
+               {
+
+                       m_eventManager->Release();
+
+                       m_eventManager = NULL;
+
+               }
+
+       }
+
+
+
+       return S_OK;
+
+}
+
+
+
+
 
-    Change History (most recent first):
-    
-$Log: DNSSDService.cpp,v $
-Revision 1.1  2009/05/26 04:43:54  herscher
-<rdar://problem/3948252> COM component that can be used with any .NET language and VB.
-\r
-\r
-*/\r
-\r
-#pragma warning(disable:4995)\r
-\r
-#include "stdafx.h"\r
-#include <strsafe.h>\r
-#include "DNSSDService.h"\r
-#include "DNSSDEventManager.h"\r
-#include "DNSSDRecord.h"\r
-#include "TXTRecord.h"\r
-#include "StringServices.h"\r
-#include <DebugServices.h>\r
-\r
-\r
-#define WM_SOCKET (WM_APP + 100)\r
-\r
-\r
-// CDNSSDService\r
-\r
-BOOL                                           CDNSSDService::m_registeredWindowClass  = FALSE;\r
-HWND                                           CDNSSDService::m_hiddenWindow                   = NULL;\r
-CDNSSDService::SocketMap       CDNSSDService::m_socketMap;\r
-\r
-\r
-HRESULT CDNSSDService::FinalConstruct()\r
-{\r
-       DNSServiceErrorType     err     = 0;\r
-       HRESULT                         hr      = S_OK;\r
-\r
-       m_isPrimary = TRUE;\r
-       err = DNSServiceCreateConnection( &m_primary );\r
-       require_action( !err, exit, hr = E_FAIL );\r
-\r
-       if ( !m_hiddenWindow )\r
-       {\r
-               TCHAR windowClassName[ 256 ];\r
-\r
-               StringCchPrintf( windowClassName, sizeof( windowClassName ) / sizeof( TCHAR ), TEXT( "Bonjour Hidden Window %d" ), GetProcessId( NULL ) );\r
-\r
-               if ( !m_registeredWindowClass )\r
-               {\r
-                       WNDCLASS        wc;\r
-                       ATOM            atom;\r
-\r
-                       wc.style                        = 0;\r
-                       wc.lpfnWndProc          = WndProc;\r
-                       wc.cbClsExtra           = 0;\r
-                       wc.cbWndExtra           = 0;\r
-                       wc.hInstance            = NULL;\r
-                       wc.hIcon                        = NULL;\r
-                       wc.hCursor                      = NULL;\r
-                       wc.hbrBackground        = NULL;\r
-                       wc.lpszMenuName         = NULL;\r
-                       wc.lpszClassName        = windowClassName;\r
-\r
-                       atom = RegisterClass(&wc);\r
-                       require_action( atom != NULL, exit, hr = E_FAIL );\r
-\r
-                       m_registeredWindowClass = TRUE;\r
-               }\r
-\r
-               m_hiddenWindow = CreateWindow( windowClassName, windowClassName, WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL, GetModuleHandle( NULL ), NULL );\r
-               require_action( m_hiddenWindow != NULL, exit, hr = E_FAIL );\r
-       }\r
-\r
-       err = WSAAsyncSelect( DNSServiceRefSockFD( m_primary ), m_hiddenWindow, WM_SOCKET, FD_READ );\r
-       require_action( !err, exit, hr = E_FAIL );\r
-\r
-       m_socketMap[ DNSServiceRefSockFD( m_primary ) ] = this;\r
-\r
-exit:\r
-\r
-       return hr;\r
-}\r
-\r
-\r
-void CDNSSDService::FinalRelease()\r
-{\r
-       dlog( kDebugLevelTrace, "FinalRelease()\n" ); \r
-       Stop();\r
-}\r
-\r
-\r
-STDMETHODIMP CDNSSDService::EnumerateDomains(DNSSDFlags flags, ULONG ifIndex, IDNSSDEventManager *eventManager, IDNSSDService **service)\r
-{\r
-       CComObject<CDNSSDService>       *       object  = NULL;\r
-       DNSServiceRef                                   subord  = NULL;\r
-       DNSServiceErrorType                             err             = 0;\r
-       HRESULT                                                 hr              = 0;\r
-\r
-       check( m_primary );\r
-\r
-       // Initialize\r
-       *service = NULL;\r
-\r
-       try\r
-       {\r
-               object = new CComObject<CDNSSDService>();\r
-       }\r
-       catch ( ... )\r
-       {\r
-               object = NULL;\r
-       }\r
-\r
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
-       object->AddRef();\r
-\r
-       subord = m_primary;\r
-       err = DNSServiceEnumerateDomains( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, ( DNSServiceDomainEnumReply ) &DomainEnumReply, object );\r
-       require_noerr( err, exit );\r
-\r
-       object->SetPrimaryRef( m_primary );\r
-       object->SetSubordRef( subord );\r
-       object->SetEventManager( eventManager );\r
-\r
-       *service = object;\r
-\r
-exit:\r
-\r
-       if ( err && object )\r
-       {\r
-               object->Release();\r
-       }\r
-\r
-       return err;\r
-}\r
-\r
-\r
-STDMETHODIMP CDNSSDService::Browse(DNSSDFlags flags, ULONG ifIndex, BSTR regtype, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** service )\r
-{\r
-       CComObject<CDNSSDService>       *       object          = NULL;\r
-       std::string                                             regtypeUTF8;\r
-       std::string                                             domainUTF8;\r
-       DNSServiceRef                                   subord          = NULL;\r
-       DNSServiceErrorType                             err                     = 0;\r
-       HRESULT                                                 hr                      = 0;\r
-       BOOL                                                    ok;\r
-\r
-       check( m_primary );\r
-\r
-       // Initialize\r
-       *service = NULL;\r
-\r
-       // Convert BSTR params to utf8\r
-       ok = BSTRToUTF8( regtype, regtypeUTF8 );\r
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
-       ok = BSTRToUTF8( domain, domainUTF8 );\r
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
-\r
-       try\r
-       {\r
-               object = new CComObject<CDNSSDService>();\r
-       }\r
-       catch ( ... )\r
-       {\r
-               object = NULL;\r
-       }\r
-\r
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
-       object->AddRef();\r
-\r
-       subord = m_primary;\r
-       err = DNSServiceBrowse( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, regtypeUTF8.c_str(), ( domainUTF8.size() > 0 ) ? domainUTF8.c_str() : NULL, ( DNSServiceBrowseReply ) &BrowseReply, object );\r
-       require_noerr( err, exit );\r
-\r
-       object->SetPrimaryRef( m_primary );\r
-       object->SetSubordRef( subord );\r
-       object->SetEventManager( eventManager );\r
-\r
-       *service = object;\r
-\r
-exit:\r
-\r
-       if ( err && object )\r
-       {\r
-               object->Release();\r
-       }\r
-\r
-       return err;\r
-}\r
-\r
-\r
-STDMETHODIMP CDNSSDService::Resolve(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** service)\r
-{\r
-       CComObject<CDNSSDService>       *       object                  = NULL;\r
-       std::string                                             serviceNameUTF8;\r
-       std::string                                             regTypeUTF8;\r
-       std::string                                             domainUTF8;\r
-       DNSServiceRef                                   subord                  = NULL;\r
-       DNSServiceErrorType                             err                             = 0;\r
-       HRESULT                                                 hr                              = 0;\r
-       BOOL                                                    ok;\r
-\r
-       check( m_primary );\r
-\r
-       // Initialize\r
-       *service = NULL;\r
-\r
-       // Convert BSTR params to utf8\r
-       ok = BSTRToUTF8( serviceName, serviceNameUTF8 );\r
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
-       ok = BSTRToUTF8( regType, regTypeUTF8 );\r
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
-       ok = BSTRToUTF8( domain, domainUTF8 );\r
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
-\r
-       try\r
-       {\r
-               object = new CComObject<CDNSSDService>();\r
-       }\r
-       catch ( ... )\r
-       {\r
-               object = NULL;\r
-       }\r
-\r
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
-       object->AddRef();\r
-\r
-       subord = m_primary;\r
-       err = DNSServiceResolve( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), domainUTF8.c_str(), ( DNSServiceResolveReply ) &ResolveReply, object );\r
-       require_noerr( err, exit );\r
-\r
-       object->SetPrimaryRef( m_primary );\r
-       object->SetSubordRef( subord );\r
-       object->SetEventManager( eventManager );\r
-\r
-       *service = object;\r
-\r
-exit:\r
-\r
-       if ( err && object )\r
-       {\r
-               object->Release();\r
-       }\r
-\r
-       return err;\r
-}\r
-\r
-\r
-STDMETHODIMP CDNSSDService::Register(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, BSTR host, USHORT port, ITXTRecord *record, IDNSSDEventManager *eventManager, IDNSSDService **service)\r
-{\r
-       CComObject<CDNSSDService>       *       object                  = NULL;\r
-       std::string                                             serviceNameUTF8;\r
-       std::string                                             regTypeUTF8;\r
-       std::string                                             domainUTF8;\r
-       std::string                                             hostUTF8;\r
-       const void                                      *       txtRecord               = NULL;\r
-       uint16_t                                                txtLen                  = 0;\r
-       DNSServiceRef                                   subord                  = NULL;\r
-       DNSServiceErrorType                             err                             = 0;\r
-       HRESULT                                                 hr                              = 0;\r
-       BOOL                                                    ok;\r
-\r
-       check( m_primary );\r
-\r
-       // Initialize\r
-       *service = NULL;\r
-\r
-       // Convert BSTR params to utf8\r
-       ok = BSTRToUTF8( serviceName, serviceNameUTF8 );\r
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
-       ok = BSTRToUTF8( regType, regTypeUTF8 );\r
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
-       ok = BSTRToUTF8( domain, domainUTF8 );\r
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
-       ok = BSTRToUTF8( host, hostUTF8 );\r
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
-\r
-       try\r
-       {\r
-               object = new CComObject<CDNSSDService>();\r
-       }\r
-       catch ( ... )\r
-       {\r
-               object = NULL;\r
-       }\r
-\r
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
-       object->AddRef();\r
-\r
-       if ( record )\r
-       {\r
-               CComObject< CTXTRecord > * realTXTRecord;\r
-\r
-               realTXTRecord = ( CComObject< CTXTRecord >* ) record;\r
-\r
-               txtRecord       = realTXTRecord->GetBytes();\r
-               txtLen          = realTXTRecord->GetLen();\r
-       }\r
-\r
-       subord = m_primary;\r
-       err = DNSServiceRegister( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), ( domainUTF8.size() > 0 ) ? domainUTF8.c_str() : NULL, hostUTF8.c_str(), htons( port ), txtLen, txtRecord, ( DNSServiceRegisterReply ) &RegisterReply, object );\r
-       require_noerr( err, exit );\r
-\r
-       object->SetPrimaryRef( m_primary );\r
-       object->SetSubordRef( subord );\r
-       object->SetEventManager( eventManager );\r
-\r
-       *service = object;\r
-\r
-exit:\r
-\r
-       if ( err && object )\r
-       {\r
-               object->Release();\r
-       }\r
-\r
-       return err;\r
-}\r
-\r
-\r
-STDMETHODIMP CDNSSDService::QueryRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, IDNSSDEventManager *eventManager, IDNSSDService **service)\r
-{\r
-       CComObject<CDNSSDService>       *       object                  = NULL;\r
-       DNSServiceRef                                   subord                  = NULL;\r
-       std::string                                             fullNameUTF8;\r
-       DNSServiceErrorType                             err                             = 0;\r
-       HRESULT                                                 hr                              = 0;\r
-       BOOL                                                    ok;\r
-\r
-       check( m_primary );\r
-\r
-       // Initialize\r
-       *service = NULL;\r
-\r
-       // Convert BSTR params to utf8\r
-       ok = BSTRToUTF8( fullname, fullNameUTF8 );\r
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
-\r
-       try\r
-       {\r
-               object = new CComObject<CDNSSDService>();\r
-       }\r
-       catch ( ... )\r
-       {\r
-               object = NULL;\r
-       }\r
-\r
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
-       object->AddRef();\r
-\r
-       subord = m_primary;\r
-       err = DNSServiceQueryRecord( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, fullNameUTF8.c_str(), ( uint16_t ) rrtype, ( uint16_t ) rrclass, ( DNSServiceQueryRecordReply ) &QueryRecordReply, object );\r
-       require_noerr( err, exit );\r
-\r
-       object->SetPrimaryRef( m_primary );\r
-       object->SetSubordRef( subord );\r
-       object->SetEventManager( eventManager );\r
-\r
-       *service = object;\r
-\r
-exit:\r
-\r
-       if ( err && object )\r
-       {\r
-               object->Release();\r
-       }\r
-\r
-       return err;\r
-}\r
-\r
-\r
-STDMETHODIMP CDNSSDService::RegisterRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullName, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata, ULONG ttl, IDNSSDEventManager* eventManager, IDNSSDRecord** record)\r
-{\r
-       CComObject<CDNSSDRecord>        *       object                  = NULL;\r
-       DNSRecordRef                                    rref                    = NULL;\r
-       std::string                                             fullNameUTF8;\r
-       std::vector< BYTE >                             byteArray;\r
-       const void                                      *       byteArrayPtr    = NULL;\r
-       DNSServiceErrorType                             err                             = 0;\r
-       HRESULT                                                 hr                              = 0;\r
-       BOOL                                                    ok;\r
-\r
-       check( m_primary );\r
-\r
-       // Initialize\r
-       *object = NULL;\r
-\r
-       // Convert BSTR params to utf8\r
-       ok = BSTRToUTF8( fullName, fullNameUTF8 );\r
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
-\r
-       // Convert the VARIANT\r
-       ok = VariantToByteArray( &rdata, byteArray );\r
-       require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
-\r
-       try\r
-       {\r
-               object = new CComObject<CDNSSDRecord>();\r
-       }\r
-       catch ( ... )\r
-       {\r
-               object = NULL;\r
-       }\r
-\r
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
-       object->AddRef();\r
-\r
-       err = DNSServiceRegisterRecord( m_primary, &rref, flags, ifIndex, fullNameUTF8.c_str(), rrtype, rrclass, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL, ttl, &RegisterRecordReply, object );\r
-       require_noerr( err, exit );\r
-\r
-       object->SetServiceObject( this );\r
-       object->SetRecordRef( rref );\r
-       this->SetEventManager( eventManager );\r
-\r
-       *record = object;\r
-\r
-exit:\r
-\r
-       if ( err && object )\r
-       {\r
-               object->Release();\r
-       }\r
-\r
-       return err;\r
-}\r
-\r
-\r
-STDMETHODIMP CDNSSDService::AddRecord(DNSSDFlags flags, DNSSDRRType rrtype, VARIANT rdata, ULONG ttl, IDNSSDRecord ** record)\r
-{\r
-       CComObject<CDNSSDRecord>        *       object                  = NULL;\r
-       DNSRecordRef                                    rref                    = NULL;\r
-       std::vector< BYTE >                             byteArray;\r
-       const void                                      *       byteArrayPtr    = NULL;\r
-       DNSServiceErrorType                             err                             = 0;\r
-       HRESULT                                                 hr                              = 0;\r
-       BOOL                                                    ok;\r
-\r
-       check( m_primary );\r
-\r
-       // Initialize\r
-       *object = NULL;\r
-\r
-       // Convert the VARIANT\r
-       ok = VariantToByteArray( &rdata, byteArray );\r
-       require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
-\r
-       try\r
-       {\r
-               object = new CComObject<CDNSSDRecord>();\r
-       }\r
-       catch ( ... )\r
-       {\r
-               object = NULL;\r
-       }\r
-\r
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
-       object->AddRef();\r
-\r
-       err = DNSServiceAddRecord( m_primary, &rref, flags, rrtype, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL, ttl );\r
-       require_noerr( err, exit );\r
-\r
-       object->SetServiceObject( this );\r
-       object->SetRecordRef( rref );\r
-\r
-       *record = object;\r
-\r
-exit:\r
-\r
-       if ( err && object )\r
-       {\r
-               object->Release();\r
-       }\r
-\r
-       return err;\r
-}\r
-\r
-STDMETHODIMP CDNSSDService::ReconfirmRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullName, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata)\r
-{\r
-       std::string                                             fullNameUTF8;\r
-       std::vector< BYTE >                             byteArray;\r
-       const void                                      *       byteArrayPtr    = NULL;\r
-       DNSServiceErrorType                             err                             = 0;\r
-       HRESULT                                                 hr                              = 0;\r
-       BOOL                                                    ok;\r
-\r
-       // Convert BSTR params to utf8\r
-       ok = BSTRToUTF8( fullName, fullNameUTF8 );\r
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
-\r
-       // Convert the VARIANT\r
-       ok = VariantToByteArray( &rdata, byteArray );\r
-       require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
-\r
-       err = DNSServiceReconfirmRecord( flags, ifIndex, fullNameUTF8.c_str(), rrtype, rrclass, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL );\r
-       require_noerr( err, exit );\r
-\r
-exit:\r
-\r
-       return err;\r
-}\r
-\r
-\r
-STDMETHODIMP CDNSSDService::GetProperty(BSTR prop, VARIANT * value )\r
-{\r
-       std::string                     propUTF8;\r
-       std::vector< BYTE >     byteArray;\r
-       SAFEARRAY               *       psa                     = NULL;\r
-       BYTE                    *       pData           = NULL;\r
-       uint32_t                        elems           = 0;\r
-       DNSServiceErrorType     err                     = 0;\r
-       BOOL                            ok = TRUE;\r
-\r
-       // Convert BSTR params to utf8\r
-       ok = BSTRToUTF8( prop, propUTF8 );\r
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
-\r
-       // Setup the byte array\r
-       require_action( V_VT( value ) == ( VT_ARRAY|VT_UI1 ), exit, err = kDNSServiceErr_Unknown );\r
-       psa = V_ARRAY( value );\r
-       require_action( psa, exit, err = kDNSServiceErr_Unknown );\r
-       require_action( SafeArrayGetDim( psa ) == 1, exit, err = kDNSServiceErr_Unknown );\r
-       byteArray.reserve( psa->rgsabound[0].cElements );\r
-       byteArray.assign( byteArray.capacity(), 0 );\r
-       elems = ( uint32_t ) byteArray.capacity();\r
-\r
-       // Call the function and package the return value in the Variant\r
-       err = DNSServiceGetProperty( propUTF8.c_str(), &byteArray[ 0 ], &elems );\r
-       require_noerr( err, exit );\r
-       ok = ByteArrayToVariant( &byteArray[ 0 ], elems, value );\r
-       require_action( ok, exit, err = kDNSSDError_Unknown );\r
-\r
-exit:\r
-\r
-       if ( psa )\r
-       {\r
-               SafeArrayUnaccessData( psa );\r
-               psa = NULL;\r
-       }\r
-\r
-       return err;\r
-}\r
-\r
-STDMETHODIMP CDNSSDService::GetAddrInfo(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, BSTR hostName, IDNSSDEventManager *eventManager, IDNSSDService **service)\r
-{\r
-       CComObject<CDNSSDService>       *       object                  = NULL;\r
-       DNSServiceRef                                   subord                  = NULL;\r
-       std::string                                             hostNameUTF8;\r
-       DNSServiceErrorType                             err                             = 0;\r
-       HRESULT                                                 hr                              = 0;\r
-       BOOL                                                    ok;\r
-\r
-       check( m_primary );\r
-\r
-       // Initialize\r
-       *service = NULL;\r
-\r
-       // Convert BSTR params to utf8\r
-       ok = BSTRToUTF8( hostName, hostNameUTF8 );\r
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );\r
-\r
-       try\r
-       {\r
-               object = new CComObject<CDNSSDService>();\r
-       }\r
-       catch ( ... )\r
-       {\r
-               object = NULL;\r
-       }\r
-\r
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
-       object->AddRef();\r
-\r
-       subord = m_primary;\r
-       err = DNSServiceGetAddrInfo( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, addressFamily, hostNameUTF8.c_str(), ( DNSServiceGetAddrInfoReply ) &GetAddrInfoReply, object );\r
-       require_noerr( err, exit );\r
-\r
-       object->SetPrimaryRef( m_primary );\r
-       object->SetSubordRef( subord );\r
-       object->SetEventManager( eventManager );\r
-\r
-       *service = object;\r
-\r
-exit:\r
-\r
-       if ( err && object )\r
-       {\r
-               object->Release();\r
-       }\r
-\r
-       return err;\r
-}\r
-\r
-\r
-STDMETHODIMP CDNSSDService::NATPortMappingCreate(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, DNSSDProtocol protocol, USHORT internalPort, USHORT externalPort, ULONG ttl, IDNSSDEventManager *eventManager, IDNSSDService **service)\r
-{\r
-       CComObject<CDNSSDService>       *       object                  = NULL;\r
-       DNSServiceRef                                   subord                  = NULL;\r
-       DNSServiceProtocol                              prot                    = 0;\r
-       DNSServiceErrorType                             err                             = 0;\r
-       HRESULT                                                 hr                              = 0;\r
-\r
-       check( m_primary );\r
-\r
-       // Initialize\r
-       *service = NULL;\r
-\r
-       try\r
-       {\r
-               object = new CComObject<CDNSSDService>();\r
-       }\r
-       catch ( ... )\r
-       {\r
-               object = NULL;\r
-       }\r
-\r
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );\r
-       object->AddRef();\r
-\r
-       prot = ( addressFamily | protocol );\r
-\r
-       subord = m_primary;\r
-       err = DNSServiceNATPortMappingCreate( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, prot, htons( internalPort ), htons( externalPort ), ttl, ( DNSServiceNATPortMappingReply ) &NATPortMappingReply, object );\r
-       require_noerr( err, exit );\r
-\r
-       object->SetPrimaryRef( m_primary );\r
-       object->SetSubordRef( subord );\r
-       object->SetEventManager( eventManager );\r
-\r
-       *service = object;\r
-\r
-exit:\r
-\r
-       if ( err && object )\r
-       {\r
-               object->Release();\r
-       }\r
-\r
-       return err;\r
-}\r
-\r
-\r
-STDMETHODIMP CDNSSDService::Stop(void)\r
-{\r
-       if ( !m_stopped )\r
-       {\r
-               m_stopped = TRUE;\r
-\r
-               dlog( kDebugLevelTrace, "Stop()\n" );\r
-\r
-               if ( m_isPrimary && m_primary )\r
-               {\r
-                       SocketMap::iterator it;\r
-\r
-                       if ( m_hiddenWindow )\r
-                       {\r
-                               WSAAsyncSelect( DNSServiceRefSockFD( m_primary ), m_hiddenWindow, 0, 0 );\r
-                       }\r
-\r
-                       it = m_socketMap.find( DNSServiceRefSockFD( m_primary ) );\r
-\r
-                       if ( it != m_socketMap.end() )\r
-                       {\r
-                               m_socketMap.erase( it );\r
-                       }\r
-\r
-                       DNSServiceRefDeallocate( m_primary );\r
-                       m_primary = NULL;\r
-               }\r
-               else if ( m_subord )\r
-               {\r
-                       DNSServiceRefDeallocate( m_subord );\r
-                       m_subord = NULL;\r
-               }\r
-\r
-               if ( m_eventManager != NULL )\r
-               {\r
-                       m_eventManager->Release();\r
-                       m_eventManager = NULL;\r
-               }\r
-       }\r
-\r
-       return S_OK;\r
-}\r
-\r
-\r
 void DNSSD_API
 CDNSSDService::DomainEnumReply
     (
@@ -706,39 +1374,72 @@ CDNSSDService::DomainEnumReply
     DNSServiceErrorType                 errorCode,
     const char                          *replyDomainUTF8,
     void                                *context
-    )\r
-{\r
-       CComObject<CDNSSDService>       * service               = NULL;\r
-       CDNSSDEventManager                      * eventManager  = NULL;\r
-       int err = 0;\r
-       \r
-       service = ( CComObject< CDNSSDService>* ) context;\r
-       require_action( service, exit, err = kDNSServiceErr_Unknown );\r
-\r
-       if ( service->ShouldHandleReply( errorCode, eventManager ) )\r
-       {\r
-               CComBSTR replyDomain;\r
-               BOOL ok;\r
-               \r
-               ok = UTF8ToBSTR( replyDomainUTF8, replyDomain );\r
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
-\r
-               if ( flags & kDNSServiceFlagsAdd )\r
-               {\r
-                       eventManager->Fire_DomainFound( service, ( DNSSDFlags ) flags, ifIndex, replyDomain );\r
-               }\r
-               else\r
-               {\r
-                       eventManager->Fire_DomainLost( service, ( DNSSDFlags ) flags, ifIndex, replyDomain );\r
-               }\r
-       }\r
-\r
-exit:\r
-\r
-       return;\r
-}\r
-\r
-\r
+    )
+
+{
+
+       CComObject<CDNSSDService>       * service               = NULL;
+
+       CDNSSDEventManager                      * eventManager  = NULL;
+
+       int err = 0;
+
+       
+
+       service = ( CComObject< CDNSSDService>* ) context;
+
+       require_action( service, exit, err = kDNSServiceErr_Unknown );
+
+
+
+       if ( service->ShouldHandleReply( errorCode, eventManager ) )
+
+       {
+
+               CComBSTR replyDomain;
+
+               BOOL ok;
+
+               
+
+               ok = UTF8ToBSTR( replyDomainUTF8, replyDomain );
+
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );
+
+
+
+               if ( flags & kDNSServiceFlagsAdd )
+
+               {
+
+                       eventManager->Fire_DomainFound( service, ( DNSSDFlags ) flags, ifIndex, replyDomain );
+
+               }
+
+               else
+
+               {
+
+                       eventManager->Fire_DomainLost( service, ( DNSSDFlags ) flags, ifIndex, replyDomain );
+
+               }
+
+       }
+
+
+
+exit:
+
+
+
+       return;
+
+}
+
+
+
+
+
 void DNSSD_API
 CDNSSDService::BrowseReply
                (
@@ -750,43 +1451,80 @@ CDNSSDService::BrowseReply
                const char                          *regTypeUTF8,
                const char                          *replyDomainUTF8,
                void                                *context
-               )\r
-{\r
-       CComObject<CDNSSDService>       * service               = NULL;\r
-       CDNSSDEventManager                      * eventManager  = NULL;\r
-       int err = 0;\r
-       \r
-       service = ( CComObject< CDNSSDService>* ) context;\r
-       require_action( service, exit, err = kDNSServiceErr_Unknown );\r
-\r
-       if ( service->ShouldHandleReply( errorCode, eventManager ) )\r
-       {\r
-               CComBSTR        serviceName;\r
-               CComBSTR        regType;\r
-               CComBSTR        replyDomain;\r
-       \r
-               UTF8ToBSTR( serviceNameUTF8, serviceName );\r
-               UTF8ToBSTR( regTypeUTF8, regType );\r
-               UTF8ToBSTR( replyDomainUTF8, replyDomain );\r
-\r
-               if ( flags & kDNSServiceFlagsAdd )\r
-               {\r
-                       eventManager->Fire_ServiceFound( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain );\r
-               }\r
-               else\r
-               {\r
-                       eventManager->Fire_ServiceLost( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain );\r
-               }\r
-       }\r
-\r
-exit:\r
-\r
-       return;\r
-}\r
-\r
-\r
-void DNSSD_API\r
-CDNSSDService::ResolveReply\r
+               )
+
+{
+
+       CComObject<CDNSSDService>       * service               = NULL;
+
+       CDNSSDEventManager                      * eventManager  = NULL;
+
+       int err = 0;
+
+       
+
+       service = ( CComObject< CDNSSDService>* ) context;
+
+       require_action( service, exit, err = kDNSServiceErr_Unknown );
+
+
+
+       if ( service->ShouldHandleReply( errorCode, eventManager ) )
+
+       {
+
+               CComBSTR        serviceName;
+
+               CComBSTR        regType;
+
+               CComBSTR        replyDomain;
+
+       
+
+               UTF8ToBSTR( serviceNameUTF8, serviceName );
+
+               UTF8ToBSTR( regTypeUTF8, regType );
+
+               UTF8ToBSTR( replyDomainUTF8, replyDomain );
+
+
+
+               if ( flags & kDNSServiceFlagsAdd )
+
+               {
+
+                       eventManager->Fire_ServiceFound( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain );
+
+               }
+
+               else
+
+               {
+
+                       eventManager->Fire_ServiceLost( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain );
+
+               }
+
+       }
+
+
+
+exit:
+
+
+
+       return;
+
+}
+
+
+
+
+
+void DNSSD_API
+
+CDNSSDService::ResolveReply
+
                (
                DNSServiceRef                       sdRef,
                DNSServiceFlags                     flags,
@@ -797,56 +1535,106 @@ CDNSSDService::ResolveReply
                uint16_t                            port,
                uint16_t                            txtLen,
                const unsigned char                 *txtRecord,
-               void                                *context\r
-               )\r
-{\r
-       CComObject<CDNSSDService>       * service               = NULL;\r
-       CDNSSDEventManager                      * eventManager  = NULL;\r
-       int err = 0;\r
-       \r
-       service = ( CComObject< CDNSSDService>* ) context;\r
-       require_action( service, exit, err = kDNSServiceErr_Unknown );\r
-\r
-       if ( service->ShouldHandleReply( errorCode, eventManager ) )\r
-       {\r
-               CComBSTR                                        fullName;\r
-               CComBSTR                                        hostName;\r
-               CComBSTR                                        regType;\r
-               CComBSTR                                        replyDomain;\r
-               CComObject< CTXTRecord >*       record;\r
-               BOOL                                            ok;\r
-\r
-               ok = UTF8ToBSTR( fullNameUTF8, fullName );\r
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
-               ok = UTF8ToBSTR( hostNameUTF8, hostName );\r
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
-\r
-               try\r
-               {\r
-                       record = new CComObject<CTXTRecord>();\r
-               }\r
-               catch ( ... )\r
-               {\r
-                       record = NULL;\r
-               }\r
-\r
-               require_action( record, exit, err = kDNSServiceErr_NoMemory );\r
-               record->AddRef();\r
-\r
-               if ( txtLen > 0 )\r
-               {\r
-                       record->SetBytes( txtRecord, txtLen );\r
-               }\r
-\r
-               eventManager->Fire_ServiceResolved( service, ( DNSSDFlags ) flags, ifIndex, fullName, hostName, ntohs( port ), record );\r
-       }\r
-\r
-exit:\r
-\r
-       return;\r
-}\r
-\r
-\r
+               void                                *context
+
+               )
+
+{
+
+       CComObject<CDNSSDService>       * service               = NULL;
+
+       CDNSSDEventManager                      * eventManager  = NULL;
+
+       int err = 0;
+
+       
+
+       service = ( CComObject< CDNSSDService>* ) context;
+
+       require_action( service, exit, err = kDNSServiceErr_Unknown );
+
+
+
+       if ( service->ShouldHandleReply( errorCode, eventManager ) )
+
+       {
+
+               CComBSTR                                        fullName;
+
+               CComBSTR                                        hostName;
+
+               CComBSTR                                        regType;
+
+               CComBSTR                                        replyDomain;
+
+               CComObject< CTXTRecord >*       record;
+
+               BOOL                                            ok;
+
+
+
+               ok = UTF8ToBSTR( fullNameUTF8, fullName );
+
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );
+
+               ok = UTF8ToBSTR( hostNameUTF8, hostName );
+
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );
+
+
+
+               try
+
+               {
+
+                       record = new CComObject<CTXTRecord>();
+
+               }
+
+               catch ( ... )
+
+               {
+
+                       record = NULL;
+
+               }
+
+
+
+               require_action( record, exit, err = kDNSServiceErr_NoMemory );
+
+               record->AddRef();
+
+
+
+               if ( txtLen > 0 )
+
+               {
+
+                       record->SetBytes( txtRecord, txtLen );
+
+               }
+
+
+
+               eventManager->Fire_ServiceResolved( service, ( DNSSDFlags ) flags, ifIndex, fullName, hostName, ntohs( port ), record );
+
+       }
+
+
+
+exit:
+
+
+
+       return;
+
+}
+
+
+
+
+
 void DNSSD_API
 CDNSSDService::RegisterReply
                (
@@ -857,38 +1645,70 @@ CDNSSDService::RegisterReply
                const char                          *regTypeUTF8,
                const char                          *domainUTF8,
                void                                *context
-               )\r
-{\r
-       CComObject<CDNSSDService>       * service               = NULL;\r
-       CDNSSDEventManager                      * eventManager  = NULL;\r
-       int err = 0;\r
-       \r
-       service = ( CComObject< CDNSSDService>* ) context;\r
-       require_action( service, exit, err = kDNSServiceErr_Unknown );\r
-\r
-       if ( service->ShouldHandleReply( errorCode, eventManager ) )\r
-       {\r
-               CComBSTR                                        serviceName;\r
-               CComBSTR                                        regType;\r
-               CComBSTR                                        domain;\r
-               BOOL                                            ok;\r
-\r
-               ok = UTF8ToBSTR( serviceNameUTF8, serviceName );\r
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
-               ok = UTF8ToBSTR( regTypeUTF8, regType );\r
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
-               ok = UTF8ToBSTR( domainUTF8, domain );\r
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
-\r
-               eventManager->Fire_ServiceRegistered( service, ( DNSSDFlags ) flags, serviceName, regType, domain );\r
-       }\r
-\r
-exit:\r
-\r
-       return;\r
-}\r
-\r
-\r
+               )
+
+{
+
+       CComObject<CDNSSDService>       * service               = NULL;
+
+       CDNSSDEventManager                      * eventManager  = NULL;
+
+       int err = 0;
+
+       
+
+       service = ( CComObject< CDNSSDService>* ) context;
+
+       require_action( service, exit, err = kDNSServiceErr_Unknown );
+
+
+
+       if ( service->ShouldHandleReply( errorCode, eventManager ) )
+
+       {
+
+               CComBSTR                                        serviceName;
+
+               CComBSTR                                        regType;
+
+               CComBSTR                                        domain;
+
+               BOOL                                            ok;
+
+
+
+               ok = UTF8ToBSTR( serviceNameUTF8, serviceName );
+
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );
+
+               ok = UTF8ToBSTR( regTypeUTF8, regType );
+
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );
+
+               ok = UTF8ToBSTR( domainUTF8, domain );
+
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );
+
+
+
+               eventManager->Fire_ServiceRegistered( service, ( DNSSDFlags ) flags, serviceName, regType, domain );
+
+       }
+
+
+
+exit:
+
+
+
+       return;
+
+}
+
+
+
+
+
 void DNSSD_API
 CDNSSDService::QueryRecordReply
                (
@@ -903,35 +1723,64 @@ CDNSSDService::QueryRecordReply
                const void                          *rdata,
                uint32_t                            ttl,
                void                                *context
-               )\r
-{\r
-       CComObject<CDNSSDService>       * service               = NULL;\r
-       CDNSSDEventManager                      * eventManager  = NULL;\r
-       int err = 0;\r
-       \r
-       service = ( CComObject< CDNSSDService>* ) context;\r
-       require_action( service, exit, err = kDNSServiceErr_Unknown );\r
-\r
-       if ( service->ShouldHandleReply( errorCode, eventManager ) )\r
-       {\r
-               CComBSTR        fullName;\r
-               VARIANT         var;\r
-               BOOL            ok;\r
-\r
-               ok = UTF8ToBSTR( fullNameUTF8, fullName );\r
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
-               ok = ByteArrayToVariant( rdata, rdlen, &var );\r
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
-\r
-               eventManager->Fire_QueryRecordAnswered( service, ( DNSSDFlags ) flags, ifIndex, fullName, ( DNSSDRRType ) rrtype, ( DNSSDRRClass ) rrclass, var, ttl );\r
-       }\r
-\r
-exit:\r
-\r
-       return;\r
-}\r
-\r
-\r
+               )
+
+{
+
+       CComObject<CDNSSDService>       * service               = NULL;
+
+       CDNSSDEventManager                      * eventManager  = NULL;
+
+       int err = 0;
+
+       
+
+       service = ( CComObject< CDNSSDService>* ) context;
+
+       require_action( service, exit, err = kDNSServiceErr_Unknown );
+
+
+
+       if ( service->ShouldHandleReply( errorCode, eventManager ) )
+
+       {
+
+               CComBSTR        fullName;
+
+               VARIANT         var;
+
+               BOOL            ok;
+
+
+
+               ok = UTF8ToBSTR( fullNameUTF8, fullName );
+
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );
+
+               ok = ByteArrayToVariant( rdata, rdlen, &var );
+
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );
+
+
+
+               eventManager->Fire_QueryRecordAnswered( service, ( DNSSDFlags ) flags, ifIndex, fullName, ( DNSSDRRType ) rrtype, ( DNSSDRRClass ) rrclass, var, ttl );
+
+       }
+
+
+
+exit:
+
+
+
+       return;
+
+}
+
+
+
+
+
 void DNSSD_API
 CDNSSDService::GetAddrInfoReply
                (
@@ -943,59 +1792,112 @@ CDNSSDService::GetAddrInfoReply
                const struct sockaddr            *rawAddress,
                uint32_t                         ttl,
                void                             *context
-               )\r
-{\r
-       CComObject<CDNSSDService>       * service               = NULL;\r
-       CDNSSDEventManager                      * eventManager  = NULL;\r
-       int err = 0;\r
-       \r
-       service = ( CComObject< CDNSSDService>* ) context;\r
-       require_action( service, exit, err = kDNSServiceErr_Unknown );\r
-\r
-       if ( service->ShouldHandleReply( errorCode, eventManager ) )\r
-       {\r
-               CComBSTR                        hostName;\r
-               DWORD                           sockaddrLen;\r
-               DNSSDAddressFamily      addressFamily;\r
-               char                            addressUTF8[INET6_ADDRSTRLEN];\r
-               DWORD                           addressLen = sizeof( addressUTF8 );\r
-               CComBSTR                        address;\r
-               BOOL                            ok;\r
-\r
-               ok = UTF8ToBSTR( hostNameUTF8, hostName );\r
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
-\r
-               switch ( rawAddress->sa_family )\r
-               {\r
-                       case AF_INET:\r
-                       {\r
-                               addressFamily   = kDNSSDAddressFamily_IPv4;\r
-                               sockaddrLen             = sizeof( sockaddr_in );\r
-                       }\r
-                       break;\r
-\r
-                       case AF_INET6:\r
-                       {\r
-                               addressFamily   = kDNSSDAddressFamily_IPv6;\r
-                               sockaddrLen             = sizeof( sockaddr_in6 );\r
-                       }\r
-                       break;\r
-               }\r
-\r
-               err = WSAAddressToStringA( ( LPSOCKADDR ) rawAddress, sockaddrLen, NULL, addressUTF8, &addressLen );\r
-               require_noerr( err, exit );\r
-               ok = UTF8ToBSTR( addressUTF8, address );\r
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );\r
-\r
-               eventManager->Fire_AddressFound( service, ( DNSSDFlags ) flags, ifIndex, hostName, addressFamily, address, ttl );\r
-       }\r
-\r
-exit:\r
-\r
-       return;\r
-}\r
-\r
-\r
+               )
+
+{
+
+       CComObject<CDNSSDService>       * service               = NULL;
+
+       CDNSSDEventManager                      * eventManager  = NULL;
+
+       int err = 0;
+
+       
+
+       service = ( CComObject< CDNSSDService>* ) context;
+
+       require_action( service, exit, err = kDNSServiceErr_Unknown );
+
+
+
+       if ( service->ShouldHandleReply( errorCode, eventManager ) )
+
+       {
+
+               CComBSTR                        hostName;
+
+               DWORD                           sockaddrLen;
+
+               DNSSDAddressFamily      addressFamily;
+
+               char                            addressUTF8[INET6_ADDRSTRLEN];
+
+               DWORD                           addressLen = sizeof( addressUTF8 );
+
+               CComBSTR                        address;
+
+               BOOL                            ok;
+
+
+
+               ok = UTF8ToBSTR( hostNameUTF8, hostName );
+
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );
+
+
+
+               switch ( rawAddress->sa_family )
+
+               {
+
+                       case AF_INET:
+
+                       {
+
+                               addressFamily   = kDNSSDAddressFamily_IPv4;
+
+                               sockaddrLen             = sizeof( sockaddr_in );
+
+                       }
+
+                       break;
+
+
+
+                       case AF_INET6:
+
+                       {
+
+                               addressFamily   = kDNSSDAddressFamily_IPv6;
+
+                               sockaddrLen             = sizeof( sockaddr_in6 );
+
+                       }
+
+                       break;
+
+               }
+
+
+
+               err = WSAAddressToStringA( ( LPSOCKADDR ) rawAddress, sockaddrLen, NULL, addressUTF8, &addressLen );
+
+               require_noerr( err, exit );
+
+               ok = UTF8ToBSTR( addressUTF8, address );
+
+               require_action( ok, exit, err = kDNSServiceErr_Unknown );
+
+
+
+               eventManager->Fire_AddressFound( service, ( DNSSDFlags ) flags, ifIndex, hostName, addressFamily, address, ttl );
+
+       }
+
+
+
+exit:
+
+
+
+       return;
+
+}
+
+
+
+
+
 void DNSSD_API
 CDNSSDService::NATPortMappingReply
     (
@@ -1009,26 +1911,46 @@ CDNSSDService::NATPortMappingReply
     uint16_t                         externalPort,      /* may be different than the requested port     */
     uint32_t                         ttl,               /* may be different than the requested ttl      */
     void                             *context
-    )\r
-{\r
-       CComObject<CDNSSDService>       * service               = NULL;\r
-       CDNSSDEventManager                      * eventManager  = NULL;\r
-       int err = 0;\r
-       \r
-       service = ( CComObject< CDNSSDService>* ) context;\r
-       require_action( service, exit, err = kDNSServiceErr_Unknown );\r
-\r
-       if ( service->ShouldHandleReply( errorCode, eventManager ) )\r
-       {\r
-               eventManager->Fire_MappingCreated( service, ( DNSSDFlags ) flags, ifIndex, externalAddress, ( DNSSDAddressFamily ) ( protocol & 0x8 ), ( DNSSDProtocol ) ( protocol & 0x80 ), ntohs( internalPort ), ntohs( externalPort ), ttl  );\r
-       }\r
-\r
-exit:\r
-\r
-       return;\r
-}\r
-\r
-\r
+    )
+
+{
+
+       CComObject<CDNSSDService>       * service               = NULL;
+
+       CDNSSDEventManager                      * eventManager  = NULL;
+
+       int err = 0;
+
+       
+
+       service = ( CComObject< CDNSSDService>* ) context;
+
+       require_action( service, exit, err = kDNSServiceErr_Unknown );
+
+
+
+       if ( service->ShouldHandleReply( errorCode, eventManager ) )
+
+       {
+
+               eventManager->Fire_MappingCreated( service, ( DNSSDFlags ) flags, ifIndex, externalAddress, ( DNSSDAddressFamily ) ( protocol & 0x8 ), ( DNSSDProtocol ) ( protocol & 0x80 ), ntohs( internalPort ), ntohs( externalPort ), ttl  );
+
+       }
+
+
+
+exit:
+
+
+
+       return;
+
+}
+
+
+
+
+
 void DNSSD_API
 CDNSSDService::RegisterRecordReply
                (
@@ -1037,70 +1959,137 @@ CDNSSDService::RegisterRecordReply
                DNSServiceFlags         flags,
                DNSServiceErrorType     errorCode,
                void                            *context
-               )\r
-{\r
-       CComObject<CDNSSDRecord>        * record                = NULL;\r
-       CDNSSDService                           * service               = NULL;\r
-       CDNSSDEventManager                      * eventManager  = NULL;\r
-       int err = 0;\r
-       \r
-       record = ( CComObject< CDNSSDRecord >* ) context;\r
-       require_action( record, exit, err = kDNSServiceErr_Unknown );\r
-       service = record->GetServiceObject();\r
-       require_action( service, exit, err = kDNSServiceErr_Unknown );\r
-\r
-       if ( service->ShouldHandleReply( errorCode, eventManager ) )\r
-       {\r
-               eventManager->Fire_RecordRegistered( record, ( DNSSDFlags ) flags );\r
-       }\r
-\r
-exit:\r
-\r
-       return;\r
-}\r
-\r
-\r
-BOOL\r
-CDNSSDService::ShouldHandleReply( DNSServiceErrorType errorCode, CDNSSDEventManager *& eventManager )\r
-{\r
-       BOOL ok = FALSE;\r
-\r
-       if ( !this->Stopped() )\r
-       {\r
-               eventManager = this->GetEventManager();\r
-               require_action( eventManager, exit, ok = FALSE );\r
-\r
-               if ( !errorCode )\r
-               {\r
-                       ok = TRUE;\r
-               }\r
-               else\r
-               {\r
-                       eventManager->Fire_OperationFailed( this, ( DNSSDError ) errorCode );\r
-               }\r
-       }\r
-\r
-exit:\r
-\r
-       return ok;\r
-}\r
-\r
-\r
-LRESULT CALLBACK\r
-CDNSSDService::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )\r
-{\r
-       if ( msg == WM_SOCKET )\r
-       {\r
-               SocketMap::iterator it;\r
-                       \r
-               it = m_socketMap.find( ( SOCKET ) wParam );\r
-               check( it != m_socketMap.end() );\r
-\r
-               if ( it != m_socketMap.end() )\r
-               {\r
-                       DNSServiceProcessResult( it->second->m_primary );\r
-               }\r
-       }\r
-\r
-       return DefWindowProc(hWnd, msg, wParam, lParam);;\r
-}\r
+               )
+
+{
+
+       CComObject<CDNSSDRecord>        * record                = NULL;
+
+       CDNSSDService                           * service               = NULL;
+
+       CDNSSDEventManager                      * eventManager  = NULL;
+
+       int err = 0;
+
+       
+
+       record = ( CComObject< CDNSSDRecord >* ) context;
+
+       require_action( record, exit, err = kDNSServiceErr_Unknown );
+
+       service = record->GetServiceObject();
+
+       require_action( service, exit, err = kDNSServiceErr_Unknown );
+
+
+
+       if ( service->ShouldHandleReply( errorCode, eventManager ) )
+
+       {
+
+               eventManager->Fire_RecordRegistered( record, ( DNSSDFlags ) flags );
+
+       }
+
+
+
+exit:
+
+
+
+       return;
+
+}
+
+
+
+
+
+BOOL
+
+CDNSSDService::ShouldHandleReply( DNSServiceErrorType errorCode, CDNSSDEventManager *& eventManager )
+
+{
+
+       BOOL ok = FALSE;
+
+
+
+       if ( !this->Stopped() )
+
+       {
+
+               eventManager = this->GetEventManager();
+
+               require_action( eventManager, exit, ok = FALSE );
+
+
+
+               if ( !errorCode )
+
+               {
+
+                       ok = TRUE;
+
+               }
+
+               else
+
+               {
+
+                       eventManager->Fire_OperationFailed( this, ( DNSSDError ) errorCode );
+
+               }
+
+       }
+
+
+
+exit:
+
+
+
+       return ok;
+
+}
+
+
+
+
+
+LRESULT CALLBACK
+
+CDNSSDService::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
+
+{
+
+       if ( msg == WM_SOCKET )
+
+       {
+
+               SocketMap::iterator it;
+
+                       
+
+               it = m_socketMap.find( ( SOCKET ) wParam );
+
+               check( it != m_socketMap.end() );
+
+
+
+               if ( it != m_socketMap.end() )
+
+               {
+
+                       DNSServiceProcessResult( it->second->m_primary );
+
+               }
+
+       }
+
+
+
+       return DefWindowProc(hWnd, msg, wParam, lParam);;
+
+}
+
index 1618a009fabe80f330ad1f07064ed0b80038e062..5eb8dcbd5dd2c8d7766ad250081d3d9aa066ed77 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
+
+
+
+#pragma once
+
+#include "resource.h"       // main symbols
+
+
+
+#include "DLLX.h"
+
+#include "DNSSDEventManager.h"
+
+#include <CommonServices.h>
+
+#include <DebugServices.h>
+
+#include <dns_sd.h>
+
+#include <map>
+
+
+
+
+
+#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
+
+#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
+
+#endif
+
+
+
+
+
+
+
+// CDNSSDService
+
+
+
+class ATL_NO_VTABLE CDNSSDService :
+
+       public CComObjectRootEx<CComSingleThreadModel>,
+
+       public CComCoClass<CDNSSDService, &CLSID_DNSSDService>,
+
+       public IDispatchImpl<IDNSSDService, &IID_IDNSSDService, &LIBID_Bonjour, /*wMajor =*/ 1, /*wMinor =*/ 0>
+
+{
+
+public:
+
+
+
+       typedef CComObjectRootEx<CComSingleThreadModel> Super;
+
+
+
+       CDNSSDService()
+
+       :
+
+               m_isPrimary( FALSE ),
+
+               m_eventManager( NULL ),
+
+               m_stopped( FALSE ),
+
+               m_primary( NULL ),
+
+               m_subord( NULL )
+
+       {
+
+       }
+
+
+
+DECLARE_REGISTRY_RESOURCEID(IDR_DNSSDSERVICE)
+
+
+
+
+
+BEGIN_COM_MAP(CDNSSDService)
+
+       COM_INTERFACE_ENTRY(IDNSSDService)
+
+       COM_INTERFACE_ENTRY(IDispatch)
+
+END_COM_MAP()
+
+
+
+       DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+
+
+       HRESULT
+
+       FinalConstruct();
+
+
+
+       void 
+
+       FinalRelease();
+
+
+
+public:
+
+
+
+       inline DNSServiceRef
+
+       GetPrimaryRef()
+
+       {
+
+               return m_primary;
+
+       }
+
+
+
+       inline void
+
+       SetPrimaryRef( DNSServiceRef primary )
+
+       {
+
+               m_primary = primary;
+
+       }
+
+
+
+       inline DNSServiceRef
+
+       GetSubordRef()
+
+       {
+
+               return m_subord;
+
+       }
+
+
+
+       inline void
+
+       SetSubordRef( DNSServiceRef subord )
+
+       {
+
+               m_subord = subord;
+
+       }
+
+
+
+       inline CDNSSDEventManager*
+
+       GetEventManager()
+
+       {
+
+               return m_eventManager;
+
+       }
+
+
+
+       inline void
+
+       SetEventManager( IDNSSDEventManager * eventManager )
+
+       {
+
+               if ( m_eventManager )
+
+               {
+
+                       m_eventManager->Release();
+
+                       m_eventManager = NULL;
+
+               }
+
+
+
+               if ( eventManager )
+
+               {
+
+                       m_eventManager = dynamic_cast< CDNSSDEventManager* >( eventManager );
+
+                       check( m_eventManager );
+
+                       m_eventManager->AddRef();
+
+               }
+
+       }
+
+
+
+       inline BOOL
+
+       Stopped()
+
+       {
+
+               return m_stopped;
+
+       }
+
+
+
+private:
+
+
 
-    Change History (most recent first):
-    
-$Log: DNSSDService.h,v $
-Revision 1.1  2009/05/26 04:43:54  herscher
-<rdar://problem/3948252> COM component that can be used with any .NET language and VB.
-\r
-\r
-*/\r
-\r
-#pragma once\r
-#include "resource.h"       // main symbols\r
-\r
-#include "DLLX.h"\r
-#include "DNSSDEventManager.h"\r
-#include <CommonServices.h>\r
-#include <DebugServices.h>\r
-#include <dns_sd.h>\r
-#include <map>\r
-\r
-\r
-#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)\r
-#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."\r
-#endif\r
-\r
-\r
-\r
-// CDNSSDService\r
-\r
-class ATL_NO_VTABLE CDNSSDService :\r
-       public CComObjectRootEx<CComSingleThreadModel>,\r
-       public CComCoClass<CDNSSDService, &CLSID_DNSSDService>,\r
-       public IDispatchImpl<IDNSSDService, &IID_IDNSSDService, &LIBID_Bonjour, /*wMajor =*/ 1, /*wMinor =*/ 0>\r
-{\r
-public:\r
-\r
-       typedef CComObjectRootEx<CComSingleThreadModel> Super;\r
-\r
-       CDNSSDService()\r
-       :\r
-               m_isPrimary( FALSE ),\r
-               m_eventManager( NULL ),\r
-               m_stopped( FALSE ),\r
-               m_primary( NULL ),\r
-               m_subord( NULL )\r
-       {\r
-       }\r
-\r
-DECLARE_REGISTRY_RESOURCEID(IDR_DNSSDSERVICE)\r
-\r
-\r
-BEGIN_COM_MAP(CDNSSDService)\r
-       COM_INTERFACE_ENTRY(IDNSSDService)\r
-       COM_INTERFACE_ENTRY(IDispatch)\r
-END_COM_MAP()\r
-\r
-       DECLARE_PROTECT_FINAL_CONSTRUCT()\r
-\r
-       HRESULT\r
-       FinalConstruct();\r
-\r
-       void \r
-       FinalRelease();\r
-\r
-public:\r
-\r
-       inline DNSServiceRef\r
-       GetPrimaryRef()\r
-       {\r
-               return m_primary;\r
-       }\r
-\r
-       inline void\r
-       SetPrimaryRef( DNSServiceRef primary )\r
-       {\r
-               m_primary = primary;\r
-       }\r
-\r
-       inline DNSServiceRef\r
-       GetSubordRef()\r
-       {\r
-               return m_subord;\r
-       }\r
-\r
-       inline void\r
-       SetSubordRef( DNSServiceRef subord )\r
-       {\r
-               m_subord = subord;\r
-       }\r
-\r
-       inline CDNSSDEventManager*\r
-       GetEventManager()\r
-       {\r
-               return m_eventManager;\r
-       }\r
-\r
-       inline void\r
-       SetEventManager( IDNSSDEventManager * eventManager )\r
-       {\r
-               if ( m_eventManager )\r
-               {\r
-                       m_eventManager->Release();\r
-                       m_eventManager = NULL;\r
-               }\r
-\r
-               if ( eventManager )\r
-               {\r
-                       m_eventManager = dynamic_cast< CDNSSDEventManager* >( eventManager );\r
-                       check( m_eventManager );\r
-                       m_eventManager->AddRef();\r
-               }\r
-       }\r
-\r
-       inline BOOL\r
-       Stopped()\r
-       {\r
-               return m_stopped;\r
-       }\r
-\r
-private:\r
-\r
        static void DNSSD_API
        DomainEnumReply
                (
@@ -143,8 +248,10 @@ private:
                DNSServiceErrorType                 errorCode,
                const char                          *replyDomain,
                void                                *context
-               );\r
-\r
+               );
+
+
+
        static void DNSSD_API
        BrowseReply
                (
@@ -156,10 +263,14 @@ private:
                const char                          *regtype,
                const char                          *replyDomain,
                void                                *context
-               );\r
-\r
-       static void DNSSD_API\r
-       ResolveReply\r
+               );
+
+
+
+       static void DNSSD_API
+
+       ResolveReply
+
                (
                DNSServiceRef                       sdRef,
                DNSServiceFlags                     flags,
@@ -170,9 +281,12 @@ private:
                uint16_t                            port,
                uint16_t                            txtLen,
                const unsigned char                 *txtRecord,
-               void                                *context\r
-               );\r
-\r
+               void                                *context
+
+               );
+
+
+
        static void DNSSD_API
        RegisterReply
                (
@@ -183,8 +297,10 @@ private:
                const char                          *regtype,
                const char                          *domain,
                void                                *context
-               );\r
-\r
+               );
+
+
+
        static void DNSSD_API
        QueryRecordReply
                (
@@ -199,8 +315,10 @@ private:
                const void                          *rdata,
                uint32_t                            ttl,
                void                                *context
-               );\r
-\r
+               );
+
+
+
        static void DNSSD_API
     GetAddrInfoReply
                (
@@ -212,8 +330,10 @@ private:
                const struct sockaddr            *address,
                uint32_t                         ttl,
                void                             *context
-               );\r
-\r
+               );
+
+
+
        static void DNSSD_API
        NATPortMappingReply
                (
@@ -227,8 +347,10 @@ private:
                uint16_t                         externalPort,      /* may be different than the requested port     */
                uint32_t                         ttl,               /* may be different than the requested ttl      */
                void                             *context
-               );\r
-\r
+               );
+
+
+
        static void DNSSD_API
        RegisterRecordReply
                (
@@ -237,37 +359,71 @@ private:
                DNSServiceFlags                     flags,
                DNSServiceErrorType                 errorCode,
                void                                *context
-               );\r
-\r
-       inline BOOL\r
-       ShouldHandleReply( DNSServiceErrorType errorCode, CDNSSDEventManager *& eventManager );\r
-       \r
-       static LRESULT CALLBACK\r
-       WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );\r
-\r
-       typedef std::map< SOCKET, CDNSSDService* > SocketMap;\r
-\r
-       static BOOL                             m_registeredWindowClass;\r
-       static HWND                             m_hiddenWindow;\r
-       static SocketMap                m_socketMap;\r
-       CDNSSDEventManager      *       m_eventManager;\r
-       BOOL                                    m_stopped;\r
-       BOOL                                    m_isPrimary;\r
-       DNSServiceRef                   m_primary;\r
-       DNSServiceRef                   m_subord;\r
-public:\r
-       STDMETHOD(EnumerateDomains)(DNSSDFlags flags, ULONG ifIndex, IDNSSDEventManager *eventManager, IDNSSDService **service);  \r
-       STDMETHOD(Browse)(DNSSDFlags flags, ULONG interfaceIndex, BSTR regtype, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** sdref);\r
-       STDMETHOD(Resolve)(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** service);\r
-       STDMETHOD(Register)(DNSSDFlags flags, ULONG ifIndex, BSTR name, BSTR regType, BSTR domain, BSTR host, USHORT port, ITXTRecord *record, IDNSSDEventManager *eventManager, IDNSSDService **service);\r
-       STDMETHOD(QueryRecord)(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, IDNSSDEventManager *eventManager, IDNSSDService **service);      \r
-       STDMETHOD(RegisterRecord)(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata, ULONG ttl, IDNSSDEventManager* eventManager, IDNSSDRecord** record);\r
-       STDMETHOD(AddRecord)(DNSSDFlags flags, DNSSDRRType rrtype, VARIANT rdata, ULONG ttl, IDNSSDRecord ** record);\r
-       STDMETHOD(ReconfirmRecord)(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata);\r
-       STDMETHOD(GetProperty)(BSTR prop, VARIANT * value);\r
-       STDMETHOD(GetAddrInfo)(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, BSTR hostname, IDNSSDEventManager *eventManager, IDNSSDService **service);      \r
-       STDMETHOD(NATPortMappingCreate)(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, DNSSDProtocol protocol, USHORT internalPort, USHORT externalPort, ULONG ttl, IDNSSDEventManager *eventManager, IDNSSDService **service);\r
-       STDMETHOD(Stop)(void);\r
-};\r
-\r
-OBJECT_ENTRY_AUTO(__uuidof(DNSSDService), CDNSSDService)\r
+               );
+
+
+
+       inline BOOL
+
+       ShouldHandleReply( DNSServiceErrorType errorCode, CDNSSDEventManager *& eventManager );
+
+       
+
+       static LRESULT CALLBACK
+
+       WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
+
+
+
+       typedef std::map< SOCKET, CDNSSDService* > SocketMap;
+
+
+
+       static BOOL                             m_registeredWindowClass;
+
+       static HWND                             m_hiddenWindow;
+
+       static SocketMap                m_socketMap;
+
+       CDNSSDEventManager      *       m_eventManager;
+
+       BOOL                                    m_stopped;
+
+       BOOL                                    m_isPrimary;
+
+       DNSServiceRef                   m_primary;
+
+       DNSServiceRef                   m_subord;
+
+public:
+
+       STDMETHOD(EnumerateDomains)(DNSSDFlags flags, ULONG ifIndex, IDNSSDEventManager *eventManager, IDNSSDService **service);  
+
+       STDMETHOD(Browse)(DNSSDFlags flags, ULONG interfaceIndex, BSTR regtype, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** sdref);
+
+       STDMETHOD(Resolve)(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** service);
+
+       STDMETHOD(Register)(DNSSDFlags flags, ULONG ifIndex, BSTR name, BSTR regType, BSTR domain, BSTR host, USHORT port, ITXTRecord *record, IDNSSDEventManager *eventManager, IDNSSDService **service);
+
+       STDMETHOD(QueryRecord)(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, IDNSSDEventManager *eventManager, IDNSSDService **service);      
+
+       STDMETHOD(RegisterRecord)(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata, ULONG ttl, IDNSSDEventManager* eventManager, IDNSSDRecord** record);
+
+       STDMETHOD(AddRecord)(DNSSDFlags flags, DNSSDRRType rrtype, VARIANT rdata, ULONG ttl, IDNSSDRecord ** record);
+
+       STDMETHOD(ReconfirmRecord)(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata);
+
+       STDMETHOD(GetProperty)(BSTR prop, VARIANT * value);
+
+       STDMETHOD(GetAddrInfo)(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, BSTR hostname, IDNSSDEventManager *eventManager, IDNSSDService **service);      
+
+       STDMETHOD(NATPortMappingCreate)(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, DNSSDProtocol protocol, USHORT internalPort, USHORT externalPort, ULONG ttl, IDNSSDEventManager *eventManager, IDNSSDService **service);
+
+       STDMETHOD(Stop)(void);
+
+};
+
+
+
+OBJECT_ENTRY_AUTO(__uuidof(DNSSDService), CDNSSDService)
+
index a9c1d8a01bf47720083659f1f4fd7224e4657236..f00750d0128ebd85a77d16e26ed37b278d46bdaf 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
+
+
+
+#include "StringServices.h"
+
+#include <DebugServices.h>
+
+
+
+
+
+extern BOOL
+
+BSTRToUTF8
+
+       (
+
+       BSTR                    inString,
+
+       std::string     &       outString
+
+       )
+
+{
+
+       USES_CONVERSION;
+
+       
+
+       char    *       utf8String      = NULL;
+
+       OSStatus    err                 = kNoErr;
+
+
 
-    Change History (most recent first):
-    
-$Log: StringServices.cpp,v $
-Revision 1.2  2009/06/02 18:43:57  herscher
-<rdar://problem/3948252> Allow component consumers to pass in null strings
-
-Revision 1.1  2009/05/26 04:43:54  herscher
-<rdar://problem/3948252> COM component that can be used with any .NET language and VB.
-\r
-\r
-*/\r
-\r
-#include "StringServices.h"\r
-#include <DebugServices.h>\r
-\r
-\r
-extern BOOL\r
-BSTRToUTF8\r
-       (\r
-       BSTR                    inString,\r
-       std::string     &       outString\r
-       )\r
-{\r
-       USES_CONVERSION;\r
-       \r
-       char    *       utf8String      = NULL;\r
-       OSStatus    err                 = kNoErr;\r
-\r
        outString = "";
 
-       if ( inString )\r
+       if ( inString )
+
        {
                TCHAR   *       utf16String     = NULL;
                size_t      size                = 0;
-\r
-               utf16String = OLE2T( inString );\r
-               require_action( utf16String != NULL, exit, err = kUnknownErr );\r
-\r
-               if ( wcslen( utf16String ) > 0 )\r
-               {\r
-                       size = (size_t) WideCharToMultiByte( CP_UTF8, 0, utf16String, ( int ) wcslen( utf16String ), NULL, 0, NULL, NULL );\r
-                       err = translate_errno( size != 0, GetLastError(), kUnknownErr );\r
-                       require_noerr( err, exit );\r
-\r
-                       try\r
-                       {\r
-                               utf8String = new char[ size + 1 ];\r
-                       }\r
-                       catch ( ... )\r
-                       {\r
-                               utf8String = NULL;\r
-                       }\r
-\r
-                       require_action( utf8String != NULL, exit, err = kNoMemoryErr );\r
-                       size = (size_t) WideCharToMultiByte( CP_UTF8, 0, utf16String, ( int ) wcslen( utf16String ), utf8String, (int) size, NULL, NULL);\r
-                       err = translate_errno( size != 0, GetLastError(), kUnknownErr );\r
-                       require_noerr( err, exit );\r
-\r
-                       // have to add the trailing 0 because WideCharToMultiByte doesn't do it,\r
-                       // although it does return the correct size\r
-\r
-                       utf8String[size] = '\0';\r
-                       outString = utf8String;\r
+
+
+               utf16String = OLE2T( inString );
+
+               require_action( utf16String != NULL, exit, err = kUnknownErr );
+
+
+
+               if ( wcslen( utf16String ) > 0 )
+
+               {
+
+                       size = (size_t) WideCharToMultiByte( CP_UTF8, 0, utf16String, ( int ) wcslen( utf16String ), NULL, 0, NULL, NULL );
+
+                       err = translate_errno( size != 0, GetLastError(), kUnknownErr );
+
+                       require_noerr( err, exit );
+
+
+
+                       try
+
+                       {
+
+                               utf8String = new char[ size + 1 ];
+
+                       }
+
+                       catch ( ... )
+
+                       {
+
+                               utf8String = NULL;
+
+                       }
+
+
+
+                       require_action( utf8String != NULL, exit, err = kNoMemoryErr );
+
+                       size = (size_t) WideCharToMultiByte( CP_UTF8, 0, utf16String, ( int ) wcslen( utf16String ), utf8String, (int) 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
+
+
+
+                       utf8String[size] = '\0';
+
+                       outString = utf8String;
+
                }
-       }\r
-\r
-exit:\r
-\r
-       if ( utf8String != NULL )\r
-       {\r
-               delete [] utf8String;\r
-       }\r
-\r
-       return ( !err ) ? TRUE : FALSE;\r
-}\r
-\r
-\r
-extern BOOL\r
-UTF8ToBSTR\r
-       (\r
-       const char      *       inString,\r
-       CComBSTR        &       outString\r
-       )\r
-{\r
-       wchar_t *       unicode = NULL;\r
-       OSStatus        err             = 0;\r
-\r
-       if ( inString )\r
+       }
+
+
+
+exit:
+
+
+
+       if ( utf8String != NULL )
+
+       {
+
+               delete [] utf8String;
+
+       }
+
+
+
+       return ( !err ) ? TRUE : FALSE;
+
+}
+
+
+
+
+
+extern BOOL
+
+UTF8ToBSTR
+
+       (
+
+       const char      *       inString,
+
+       CComBSTR        &       outString
+
+       )
+
+{
+
+       wchar_t *       unicode = NULL;
+
+       OSStatus        err             = 0;
+
+
+
+       if ( inString )
+
        {
                int n;
 
-               n = MultiByteToWideChar( CP_UTF8, 0, inString, -1, NULL, 0 );\r
-           \r
-               if ( n > 0 )\r
-               {\r
-                       try\r
-                       {\r
-                               unicode = new wchar_t[ n ];\r
-                       }\r
-                       catch ( ... )\r
-                       {\r
-                               unicode = NULL;\r
-                       }\r
-\r
-                       require_action( unicode, exit, err = ERROR_INSUFFICIENT_BUFFER );\r
-\r
-                       n = MultiByteToWideChar( CP_UTF8, 0, inString, -1, unicode, n );\r
-               }\r
-\r
-               outString = unicode;\r
+               n = MultiByteToWideChar( CP_UTF8, 0, inString, -1, NULL, 0 );
+
+           
+
+               if ( n > 0 )
+
+               {
+
+                       try
+
+                       {
+
+                               unicode = new wchar_t[ n ];
+
+                       }
+
+                       catch ( ... )
+
+                       {
+
+                               unicode = NULL;
+
+                       }
+
+
+
+                       require_action( unicode, exit, err = ERROR_INSUFFICIENT_BUFFER );
+
+
+
+                       n = MultiByteToWideChar( CP_UTF8, 0, inString, -1, unicode, n );
+
+               }
+
+
+
+               outString = unicode;
+
+       }
+
+
+exit:
+
+
+
+    if ( unicode != NULL )
+
+    {
+
+        delete [] unicode;
+
        }
-\r
-exit:\r
-\r
-    if ( unicode != NULL )\r
-    {\r
-        delete [] unicode;\r
-       }\r
-\r
-       return ( !err ) ? TRUE : FALSE;\r
-}\r
-\r
-\r
-BOOL\r
-ByteArrayToVariant\r
-       (\r
-       const void      *       inArray,\r
-       size_t                  inArrayLen,\r
-       VARIANT         *       outVariant\r
-       )\r
-{\r
-       LPBYTE                  buf     = NULL;\r
-       HRESULT                 hr      = 0;\r
-       BOOL                    ok      = TRUE;\r
-\r
-       VariantClear( outVariant );\r
-       outVariant->vt          = VT_ARRAY|VT_UI1;\r
-       outVariant->parray      = SafeArrayCreateVector( VT_UI1, 0, ( ULONG ) inArrayLen );\r
-       require_action( outVariant->parray, exit, ok = FALSE );\r
-       hr = SafeArrayAccessData( outVariant->parray, (LPVOID *)&buf );\r
-       require_action( hr == S_OK, exit, ok = FALSE );\r
-       memcpy( buf, inArray, inArrayLen );\r
-       hr = SafeArrayUnaccessData( outVariant->parray );\r
-       require_action( hr == S_OK, exit, ok = FALSE );\r
-\r
-exit:\r
-\r
-       return ok;\r
-}\r
-\r
-\r
-extern BOOL\r
-VariantToByteArray\r
-       (\r
-       VARIANT                         *       inVariant,\r
-       std::vector< BYTE >     &       outArray\r
-       )\r
-{\r
-       SAFEARRAY       *       psa                     = NULL;\r
-       BYTE            *       pData           = NULL;\r
-       ULONG                   cElements       = 0;\r
-       HRESULT                 hr;\r
-       BOOL                    ok = TRUE;\r
-\r
-       require_action( V_VT( inVariant ) == ( VT_ARRAY|VT_UI1 ), exit, ok = FALSE );\r
-       psa = V_ARRAY( inVariant );\r
-       require_action( psa, exit, ok = FALSE );\r
-       require_action( SafeArrayGetDim( psa ) == 1, exit, ok = FALSE );\r
-       hr = SafeArrayAccessData( psa, ( LPVOID* )&pData );\r
-       require_action( hr == S_OK, exit, ok = FALSE );\r
-       cElements = psa->rgsabound[0].cElements;\r
-       outArray.reserve( cElements );\r
-       outArray.assign( cElements, 0 );\r
-       memcpy( &outArray[ 0 ], pData, cElements );\r
-       SafeArrayUnaccessData( psa );\r
-\r
-exit:\r
-\r
-       return ok;\r
+
+
+
+       return ( !err ) ? TRUE : FALSE;
+
+}
+
+
+
+
+
+BOOL
+
+ByteArrayToVariant
+
+       (
+
+       const void      *       inArray,
+
+       size_t                  inArrayLen,
+
+       VARIANT         *       outVariant
+
+       )
+
+{
+
+       LPBYTE                  buf     = NULL;
+
+       HRESULT                 hr      = 0;
+
+       BOOL                    ok      = TRUE;
+
+
+
+       VariantClear( outVariant );
+
+       outVariant->vt          = VT_ARRAY|VT_UI1;
+
+       outVariant->parray      = SafeArrayCreateVector( VT_UI1, 0, ( ULONG ) inArrayLen );
+
+       require_action( outVariant->parray, exit, ok = FALSE );
+
+       hr = SafeArrayAccessData( outVariant->parray, (LPVOID *)&buf );
+
+       require_action( hr == S_OK, exit, ok = FALSE );
+
+       memcpy( buf, inArray, inArrayLen );
+
+       hr = SafeArrayUnaccessData( outVariant->parray );
+
+       require_action( hr == S_OK, exit, ok = FALSE );
+
+
+
+exit:
+
+
+
+       return ok;
+
+}
+
+
+
+
+
+extern BOOL
+
+VariantToByteArray
+
+       (
+
+       VARIANT                         *       inVariant,
+
+       std::vector< BYTE >     &       outArray
+
+       )
+
+{
+
+       SAFEARRAY       *       psa                     = NULL;
+
+       BYTE            *       pData           = NULL;
+
+       ULONG                   cElements       = 0;
+
+       HRESULT                 hr;
+
+       BOOL                    ok = TRUE;
+
+
+
+       require_action( V_VT( inVariant ) == ( VT_ARRAY|VT_UI1 ), exit, ok = FALSE );
+
+       psa = V_ARRAY( inVariant );
+
+       require_action( psa, exit, ok = FALSE );
+
+       require_action( SafeArrayGetDim( psa ) == 1, exit, ok = FALSE );
+
+       hr = SafeArrayAccessData( psa, ( LPVOID* )&pData );
+
+       require_action( hr == S_OK, exit, ok = FALSE );
+
+       cElements = psa->rgsabound[0].cElements;
+
+       outArray.reserve( cElements );
+
+       outArray.assign( cElements, 0 );
+
+       memcpy( &outArray[ 0 ], pData, cElements );
+
+       SafeArrayUnaccessData( psa );
+
+
+
+exit:
+
+
+
+       return ok;
+
 }
\ No newline at end of file
index ff6d59bf96a816fd02ea3ecc896c855381e52152..12aa99686a07a0c46b6dba54b9c816905f7c18dd 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
+
+
+
+#ifndef _StringServices_h
+
+#define _StringServices_h
+
+
+
+#include <atlbase.h>
+
+#include <vector>
+
+#include <string>
+
+
+
+
+
+extern BOOL
+
+BSTRToUTF8
+
+       (
+
+       BSTR                    inString,
+
+       std::string     &       outString
+
+       );
+
+
+
+
+
+extern BOOL
+
+UTF8ToBSTR
+
+       (
+
+       const char      *       inString,
+
+       CComBSTR        &       outString
+
+       );
+
+
+
+
+
+extern BOOL
+
+ByteArrayToVariant
+
+       (
+
+       const void      *       inArray,
+
+       size_t                  inArrayLen,
+
+       VARIANT         *       outVariant
+
+       );
+
+
+
+
+
+extern BOOL
+
+VariantToByteArray
+
+       (
+
+       VARIANT                         *       inVariant,
+
+       std::vector< BYTE >     &       outArray
+
+       );
+
+
+
+
 
-    Change History (most recent first):
-    
-$Log: StringServices.h,v $
-Revision 1.1  2009/05/26 04:43:54  herscher
-<rdar://problem/3948252> COM component that can be used with any .NET language and VB.
-\r
-\r
-*/\r
-\r
-#ifndef _StringServices_h\r
-#define _StringServices_h\r
-\r
-#include <atlbase.h>\r
-#include <vector>\r
-#include <string>\r
-\r
-\r
-extern BOOL\r
-BSTRToUTF8\r
-       (\r
-       BSTR                    inString,\r
-       std::string     &       outString\r
-       );\r
-\r
-\r
-extern BOOL\r
-UTF8ToBSTR\r
-       (\r
-       const char      *       inString,\r
-       CComBSTR        &       outString\r
-       );\r
-\r
-\r
-extern BOOL\r
-ByteArrayToVariant\r
-       (\r
-       const void      *       inArray,\r
-       size_t                  inArrayLen,\r
-       VARIANT         *       outVariant\r
-       );\r
-\r
-\r
-extern BOOL\r
-VariantToByteArray\r
-       (\r
-       VARIANT                         *       inVariant,\r
-       std::vector< BYTE >     &       outArray\r
-       );\r
-\r
-\r
 #endif
\ No newline at end of file
index 5921654a2b17a42a18badb5d01c3dfb2db9b9a1e..e5345f8d245e45b93c6b6837f89b01bc5510932b 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
+
+
+
+#include "stdafx.h"
+
+#include "TXTRecord.h"
+
+#include "StringServices.h"
+
+#include <DebugServices.h>
+
+
+
+
+
+// CTXTRecord
+
+
+
+
+
+STDMETHODIMP CTXTRecord::SetValue(BSTR key, VARIANT value)
+
+{
+
+       std::string                     keyUTF8;
+
+       ByteArray                       valueArray;
+
+       BOOL                            ok;
+
+       DNSServiceErrorType     err;
+
+       HRESULT                         hr = S_OK;
+
+
+
+       if ( !m_allocated )
+
+       {
+
+               TXTRecordCreate( &m_tref, 0, NULL );
+
+               m_allocated = TRUE;
+
+       }
+
+
+
+       ok = BSTRToUTF8( key, keyUTF8 );
+
+       require_action( ok, exit, hr = S_FALSE );
+
+
+
+       ok = VariantToByteArray( &value, valueArray );
+
+       require_action( ok, exit, hr = S_FALSE );
+
+
+
+       err = TXTRecordSetValue( &m_tref, keyUTF8.c_str(), ( uint8_t ) valueArray.size(), &valueArray[ 0 ] );
+
+       require_action( !err, exit, hr = S_FALSE );
+
+
+
+exit:
+
+
+
+       return hr;
+
+}
+
+
+
+STDMETHODIMP CTXTRecord::RemoveValue(BSTR key)
+
+{
+
+       HRESULT hr = S_OK;
+
+
+
+       if ( m_allocated )
+
+       {
+
+               std::string                     keyUTF8;
+
+               BOOL                            ok;
+
+               DNSServiceErrorType     err;
+
+
+
+               ok = BSTRToUTF8( key, keyUTF8 );
+
+               require_action( ok, exit, hr = S_FALSE );
+
+
+
+               err = TXTRecordRemoveValue( &m_tref, keyUTF8.c_str() );
+
+               require_action( !err, exit, hr = S_FALSE );
+
+       }
+
+
+
+exit:
+
+
+
+       return hr;
+
+}
+
+
+
+STDMETHODIMP CTXTRecord::ContainsKey(BSTR key, VARIANT_BOOL* retval)
+
+{
+
+       std::string keyUTF8;
+
+       int                     ret     = 0;
+
+       HRESULT         err     = S_OK;
+
+
+
+       if ( m_byteArray.size() > 0 )
+
+       {
+
+               BOOL ok;
+
+
+
+               ok = BSTRToUTF8( key, keyUTF8 );
+
+               require_action( ok, exit, err = S_FALSE );
+
+
+
+               ret = TXTRecordContainsKey( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ], keyUTF8.c_str() );
+
+       }
+
+
+
+       *retval = ( ret ) ? VARIANT_TRUE : VARIANT_FALSE;
+
+
+
+exit:
+
+
+
+       return err;
+
+}
+
+
+
+STDMETHODIMP CTXTRecord::GetValueForKey(BSTR key, VARIANT* value)
+
+{
+
+       std::string             keyUTF8;
+
+       const void      *       rawValue;
+
+       uint8_t                 rawValueLen;
+
+       BOOL                    ok      = TRUE;
+
+       HRESULT                 hr      = S_OK;
+
+
+
+       VariantClear( value );
+
+
+
+       if ( m_byteArray.size() > 0 )
+
+       {
+
+               ok = BSTRToUTF8( key, keyUTF8 );
+
+               require_action( ok, exit, hr = S_FALSE );
+
+
+
+               rawValue = TXTRecordGetValuePtr( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ], keyUTF8.c_str(), &rawValueLen );
+
+
+
+               if ( rawValue )
+
+               {
+
+                       ok = ByteArrayToVariant( rawValue, rawValueLen, value );
+
+                       require_action( ok, exit, hr = S_FALSE );
+
+               }
+
+       }
+
+
+
+exit:
+
+
+
+       return hr;
+
+}
+
+
+
+STDMETHODIMP CTXTRecord::GetCount(ULONG* count)
+
+{
+
+       *count = 0;
+
+
+
+       if ( m_byteArray.size() > 0 )
+
+       {
+
+               *count = TXTRecordGetCount( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ] );
+
+       }
+
+
+
+       return S_OK;
+
+}
+
+
+
+STDMETHODIMP CTXTRecord::GetKeyAtIndex(ULONG index, BSTR* retval)
+
+{
+
+       char                            keyBuf[ 64 ];
+
+       uint8_t                         rawValueLen;
+
+       const void              *       rawValue;
+
+       CComBSTR                        temp;
+
+       DNSServiceErrorType     err;
+
+       BOOL                            ok;
+
+       HRESULT                         hr = S_OK;
+
+
+
+       err = TXTRecordGetItemAtIndex( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ], ( uint16_t ) index, sizeof( keyBuf ), keyBuf, &rawValueLen, &rawValue );
+
+       require_action( !err, exit, hr = S_FALSE );
+
+
+
+       ok = UTF8ToBSTR( keyBuf, temp );
+
+       require_action( ok, exit, hr = S_FALSE );
+
+
+
+       *retval = temp;
+
+
+
+exit:
+
+
+
+       return hr;
+
+}
+
+
+
+STDMETHODIMP CTXTRecord::GetValueAtIndex(ULONG index, VARIANT* retval)
+
+{
+
+       char                            keyBuf[ 64 ];
+
+       uint8_t                         rawValueLen;
+
+       const void              *       rawValue;
+
+       CComBSTR                        temp;
+
+       DNSServiceErrorType     err;
+
+       BOOL                            ok;
+
+       HRESULT                         hr = S_OK;
+
+
+
+       err = TXTRecordGetItemAtIndex( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ], ( uint16_t ) index, sizeof( keyBuf ), keyBuf, &rawValueLen, &rawValue );
+
+       require_action( !err, exit, hr = S_FALSE );
+
+
+
+       ok = ByteArrayToVariant( rawValue, rawValueLen, retval );
+
+       require_action( ok, exit, hr = S_FALSE );
+
+
+
+exit:
+
+
+
+       return hr;
+
+}
+
+
+
+
+
+void
+
+CTXTRecord::SetBytes
+
+       (
+
+       const unsigned char     *       bytes,
+
+       uint16_t                                len
+
+       )
+
+{
+
+       check ( bytes != NULL );
+
+       check( len );
+
+
+
+       m_byteArray.reserve( len );
+
+       m_byteArray.assign( bytes, bytes + len );
+
+}
 
-    Change History (most recent first):
-    
-$Log: TXTRecord.cpp,v $
-Revision 1.1  2009/05/26 04:43:54  herscher
-<rdar://problem/3948252> COM component that can be used with any .NET language and VB.
-\r
-\r
-*/\r
-\r
-#include "stdafx.h"\r
-#include "TXTRecord.h"\r
-#include "StringServices.h"\r
-#include <DebugServices.h>\r
-\r
-\r
-// CTXTRecord\r
-\r
-\r
-STDMETHODIMP CTXTRecord::SetValue(BSTR key, VARIANT value)\r
-{\r
-       std::string                     keyUTF8;\r
-       ByteArray                       valueArray;\r
-       BOOL                            ok;\r
-       DNSServiceErrorType     err;\r
-       HRESULT                         hr = S_OK;\r
-\r
-       if ( !m_allocated )\r
-       {\r
-               TXTRecordCreate( &m_tref, 0, NULL );\r
-               m_allocated = TRUE;\r
-       }\r
-\r
-       ok = BSTRToUTF8( key, keyUTF8 );\r
-       require_action( ok, exit, hr = S_FALSE );\r
-\r
-       ok = VariantToByteArray( &value, valueArray );\r
-       require_action( ok, exit, hr = S_FALSE );\r
-\r
-       err = TXTRecordSetValue( &m_tref, keyUTF8.c_str(), ( uint8_t ) valueArray.size(), &valueArray[ 0 ] );\r
-       require_action( !err, exit, hr = S_FALSE );\r
-\r
-exit:\r
-\r
-       return hr;\r
-}\r
-\r
-STDMETHODIMP CTXTRecord::RemoveValue(BSTR key)\r
-{\r
-       HRESULT hr = S_OK;\r
-\r
-       if ( m_allocated )\r
-       {\r
-               std::string                     keyUTF8;\r
-               BOOL                            ok;\r
-               DNSServiceErrorType     err;\r
-\r
-               ok = BSTRToUTF8( key, keyUTF8 );\r
-               require_action( ok, exit, hr = S_FALSE );\r
-\r
-               err = TXTRecordRemoveValue( &m_tref, keyUTF8.c_str() );\r
-               require_action( !err, exit, hr = S_FALSE );\r
-       }\r
-\r
-exit:\r
-\r
-       return hr;\r
-}\r
-\r
-STDMETHODIMP CTXTRecord::ContainsKey(BSTR key, VARIANT_BOOL* retval)\r
-{\r
-       std::string keyUTF8;\r
-       int                     ret     = 0;\r
-       HRESULT         err     = S_OK;\r
-\r
-       if ( m_byteArray.size() > 0 )\r
-       {\r
-               BOOL ok;\r
-\r
-               ok = BSTRToUTF8( key, keyUTF8 );\r
-               require_action( ok, exit, err = S_FALSE );\r
-\r
-               ret = TXTRecordContainsKey( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ], keyUTF8.c_str() );\r
-       }\r
-\r
-       *retval = ( ret ) ? VARIANT_TRUE : VARIANT_FALSE;\r
-\r
-exit:\r
-\r
-       return err;\r
-}\r
-\r
-STDMETHODIMP CTXTRecord::GetValueForKey(BSTR key, VARIANT* value)\r
-{\r
-       std::string             keyUTF8;\r
-       const void      *       rawValue;\r
-       uint8_t                 rawValueLen;\r
-       BOOL                    ok      = TRUE;\r
-       HRESULT                 hr      = S_OK;\r
-\r
-       VariantClear( value );\r
-\r
-       if ( m_byteArray.size() > 0 )\r
-       {\r
-               ok = BSTRToUTF8( key, keyUTF8 );\r
-               require_action( ok, exit, hr = S_FALSE );\r
-\r
-               rawValue = TXTRecordGetValuePtr( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ], keyUTF8.c_str(), &rawValueLen );\r
-\r
-               if ( rawValue )\r
-               {\r
-                       ok = ByteArrayToVariant( rawValue, rawValueLen, value );\r
-                       require_action( ok, exit, hr = S_FALSE );\r
-               }\r
-       }\r
-\r
-exit:\r
-\r
-       return hr;\r
-}\r
-\r
-STDMETHODIMP CTXTRecord::GetCount(ULONG* count)\r
-{\r
-       *count = 0;\r
-\r
-       if ( m_byteArray.size() > 0 )\r
-       {\r
-               *count = TXTRecordGetCount( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ] );\r
-       }\r
-\r
-       return S_OK;\r
-}\r
-\r
-STDMETHODIMP CTXTRecord::GetKeyAtIndex(ULONG index, BSTR* retval)\r
-{\r
-       char                            keyBuf[ 64 ];\r
-       uint8_t                         rawValueLen;\r
-       const void              *       rawValue;\r
-       CComBSTR                        temp;\r
-       DNSServiceErrorType     err;\r
-       BOOL                            ok;\r
-       HRESULT                         hr = S_OK;\r
-\r
-       err = TXTRecordGetItemAtIndex( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ], ( uint16_t ) index, sizeof( keyBuf ), keyBuf, &rawValueLen, &rawValue );\r
-       require_action( !err, exit, hr = S_FALSE );\r
-\r
-       ok = UTF8ToBSTR( keyBuf, temp );\r
-       require_action( ok, exit, hr = S_FALSE );\r
-\r
-       *retval = temp;\r
-\r
-exit:\r
-\r
-       return hr;\r
-}\r
-\r
-STDMETHODIMP CTXTRecord::GetValueAtIndex(ULONG index, VARIANT* retval)\r
-{\r
-       char                            keyBuf[ 64 ];\r
-       uint8_t                         rawValueLen;\r
-       const void              *       rawValue;\r
-       CComBSTR                        temp;\r
-       DNSServiceErrorType     err;\r
-       BOOL                            ok;\r
-       HRESULT                         hr = S_OK;\r
-\r
-       err = TXTRecordGetItemAtIndex( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ], ( uint16_t ) index, sizeof( keyBuf ), keyBuf, &rawValueLen, &rawValue );\r
-       require_action( !err, exit, hr = S_FALSE );\r
-\r
-       ok = ByteArrayToVariant( rawValue, rawValueLen, retval );\r
-       require_action( ok, exit, hr = S_FALSE );\r
-\r
-exit:\r
-\r
-       return hr;\r
-}\r
-\r
-\r
-void\r
-CTXTRecord::SetBytes\r
-       (\r
-       const unsigned char     *       bytes,\r
-       uint16_t                                len\r
-       )\r
-{\r
-       check ( bytes != NULL );\r
-       check( len );\r
-\r
-       m_byteArray.reserve( len );\r
-       m_byteArray.assign( bytes, bytes + len );\r
-}\r
index f74f8a01583eca7f1c5c4301eea39f0b5b8322d1..67f3bdc3b117c3683dce95411f2beef4e64c145e 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
+
+
+
+#pragma once
+
+#include "resource.h"       // main symbols
+
+#include "DLLX.h"
+
+#include <vector>
+
+#include <dns_sd.h>
+
+
+
+
+
+#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
+
+#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
+
+#endif
+
+
+
+
+
+
+
+// CTXTRecord
+
+
+
+class ATL_NO_VTABLE CTXTRecord :
+
+       public CComObjectRootEx<CComSingleThreadModel>,
+
+       public CComCoClass<CTXTRecord, &CLSID_TXTRecord>,
+
+       public IDispatchImpl<ITXTRecord, &IID_ITXTRecord, &LIBID_Bonjour, /*wMajor =*/ 1, /*wMinor =*/ 0>
+
+{
+
+public:
+
+       CTXTRecord()
+
+       :
+
+               m_allocated( FALSE )
+
+       {
+
+       }
+
+
+
+DECLARE_REGISTRY_RESOURCEID(IDR_TXTRECORD)
+
+
+
+
+
+BEGIN_COM_MAP(CTXTRecord)
+
+       COM_INTERFACE_ENTRY(ITXTRecord)
+
+       COM_INTERFACE_ENTRY(IDispatch)
+
+END_COM_MAP()
+
+
+
+
+
+
+
+       DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+
+
+       HRESULT FinalConstruct()
+
+       {
+
+               return S_OK;
+
+       }
+
+
+
+       void FinalRelease()
+
+       {
+
+               if ( m_allocated )
+
+               {
+
+                       TXTRecordDeallocate( &m_tref );
+
+               }
+
+       }
+
+
+
+public:
+
+
+
+       STDMETHOD(SetValue)(BSTR key, VARIANT value);
+
+       STDMETHOD(RemoveValue)(BSTR key);
+
+       STDMETHOD(ContainsKey)(BSTR key, VARIANT_BOOL* retval);
+
+       STDMETHOD(GetValueForKey)(BSTR key, VARIANT* value);
+
+       STDMETHOD(GetCount)(ULONG* count);
+
+       STDMETHOD(GetKeyAtIndex)(ULONG index, BSTR* retval);
+
+       STDMETHOD(GetValueAtIndex)(ULONG index, VARIANT* retval);
+
+
+
+private:
+
+
+
+       typedef std::vector< BYTE > ByteArray;
+
+       ByteArray               m_byteArray;
+
+       BOOL                    m_allocated;
+
+       TXTRecordRef    m_tref;
+
+
+
+public:
+
+
+
+       uint16_t
+
+       GetLen()
+
+       {
+
+               return TXTRecordGetLength( &m_tref );
+
+       }
+
+
+
+       const void*
+
+       GetBytes()
+
+       {
+
+               return TXTRecordGetBytesPtr( &m_tref );
+
+       }
+
+
+
+       void
+
+       SetBytes
+
+               (
+
+               const unsigned char     *       bytes,
+
+               uint16_t                                len
+
+               );
+
+};
+
+
+
+OBJECT_ENTRY_AUTO(__uuidof(TXTRecord), CTXTRecord)
 
-    Change History (most recent first):
-    
-$Log: TXTRecord.h,v $
-Revision 1.1  2009/05/26 04:43:54  herscher
-<rdar://problem/3948252> COM component that can be used with any .NET language and VB.
-\r
-\r
-*/\r
-\r
-#pragma once\r
-#include "resource.h"       // main symbols\r
-#include "DLLX.h"\r
-#include <vector>\r
-#include <dns_sd.h>\r
-\r
-\r
-#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)\r
-#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."\r
-#endif\r
-\r
-\r
-\r
-// CTXTRecord\r
-\r
-class ATL_NO_VTABLE CTXTRecord :\r
-       public CComObjectRootEx<CComSingleThreadModel>,\r
-       public CComCoClass<CTXTRecord, &CLSID_TXTRecord>,\r
-       public IDispatchImpl<ITXTRecord, &IID_ITXTRecord, &LIBID_Bonjour, /*wMajor =*/ 1, /*wMinor =*/ 0>\r
-{\r
-public:\r
-       CTXTRecord()\r
-       :\r
-               m_allocated( FALSE )\r
-       {\r
-       }\r
-\r
-DECLARE_REGISTRY_RESOURCEID(IDR_TXTRECORD)\r
-\r
-\r
-BEGIN_COM_MAP(CTXTRecord)\r
-       COM_INTERFACE_ENTRY(ITXTRecord)\r
-       COM_INTERFACE_ENTRY(IDispatch)\r
-END_COM_MAP()\r
-\r
-\r
-\r
-       DECLARE_PROTECT_FINAL_CONSTRUCT()\r
-\r
-       HRESULT FinalConstruct()\r
-       {\r
-               return S_OK;\r
-       }\r
-\r
-       void FinalRelease()\r
-       {\r
-               if ( m_allocated )\r
-               {\r
-                       TXTRecordDeallocate( &m_tref );\r
-               }\r
-       }\r
-\r
-public:\r
-\r
-       STDMETHOD(SetValue)(BSTR key, VARIANT value);\r
-       STDMETHOD(RemoveValue)(BSTR key);\r
-       STDMETHOD(ContainsKey)(BSTR key, VARIANT_BOOL* retval);\r
-       STDMETHOD(GetValueForKey)(BSTR key, VARIANT* value);\r
-       STDMETHOD(GetCount)(ULONG* count);\r
-       STDMETHOD(GetKeyAtIndex)(ULONG index, BSTR* retval);\r
-       STDMETHOD(GetValueAtIndex)(ULONG index, VARIANT* retval);\r
-\r
-private:\r
-\r
-       typedef std::vector< BYTE > ByteArray;\r
-       ByteArray               m_byteArray;\r
-       BOOL                    m_allocated;\r
-       TXTRecordRef    m_tref;\r
-\r
-public:\r
-\r
-       uint16_t\r
-       GetLen()\r
-       {\r
-               return TXTRecordGetLength( &m_tref );\r
-       }\r
-\r
-       const void*\r
-       GetBytes()\r
-       {\r
-               return TXTRecordGetBytesPtr( &m_tref );\r
-       }\r
-\r
-       void\r
-       SetBytes\r
-               (\r
-               const unsigned char     *       bytes,\r
-               uint16_t                                len\r
-               );\r
-};\r
-\r
-OBJECT_ENTRY_AUTO(__uuidof(TXTRecord), CTXTRecord)\r
index d2508e8b3647e8f7a6206ad228e5b413e490320f..a58153258a7357b9fb43d7f2eae565eac5310d84 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
+
+
+
+#ifdef _MERGE_PROXYSTUB // merge proxy stub DLL
+
+
+
+#define REGISTER_PROXY_DLL //DllRegisterServer, etc.
+
+
+
+#define _WIN32_WINNT 0x0500    //for WinNT 4.0 or Win95 with DCOM
+
+#define USE_STUBLESS_PROXY     //defined only with MIDL switch /Oicf
+
+
+
+#pragma comment(lib, "rpcns4.lib")
+
+#pragma comment(lib, "rpcrt4.lib")
+
+
+
+#define ENTRY_PREFIX   Prx
+
+
+
+#include "dlldata.c"
+
+#include "DLLX_p.c"
+
+
+
+#endif //_MERGE_PROXYSTUB
 
-    Change History (most recent first):
-    
-$Log: dlldatax.c,v $
-Revision 1.1  2009/05/26 04:43:54  herscher
-<rdar://problem/3948252> COM component that can be used with any .NET language and VB.
-\r
-\r
-*/\r
-\r
-#ifdef _MERGE_PROXYSTUB // merge proxy stub DLL\r
-\r
-#define REGISTER_PROXY_DLL //DllRegisterServer, etc.\r
-\r
-#define _WIN32_WINNT 0x0500    //for WinNT 4.0 or Win95 with DCOM\r
-#define USE_STUBLESS_PROXY     //defined only with MIDL switch /Oicf\r
-\r
-#pragma comment(lib, "rpcns4.lib")\r
-#pragma comment(lib, "rpcrt4.lib")\r
-\r
-#define ENTRY_PREFIX   Prx\r
-\r
-#include "dlldata.c"\r
-#include "DLLX_p.c"\r
-\r
-#endif //_MERGE_PROXYSTUB\r
index 093d8f1f8706e87e53a783e5f3bdc020144799b9..f8816a39da5cae0410c57ace3e66be7ae2156542 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
+
+
+
+#pragma once
+
+
+
+#ifdef _MERGE_PROXYSTUB
+
+
+
+extern "C" 
+
+{
+
+BOOL WINAPI PrxDllMain(HINSTANCE hInstance, DWORD dwReason, 
+
+       LPVOID lpReserved);
+
+STDAPI PrxDllCanUnloadNow(void);
+
+STDAPI PrxDllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
+
+STDAPI PrxDllRegisterServer(void);
+
+STDAPI PrxDllUnregisterServer(void);
+
+}
+
+
+
+#endif
 
-    Change History (most recent first):
-    
-$Log: dlldatax.h,v $
-Revision 1.1  2009/05/26 04:43:54  herscher
-<rdar://problem/3948252> COM component that can be used with any .NET language and VB.
-\r
-\r
-*/\r
-\r
-#pragma once\r
-\r
-#ifdef _MERGE_PROXYSTUB\r
-\r
-extern "C" \r
-{\r
-BOOL WINAPI PrxDllMain(HINSTANCE hInstance, DWORD dwReason, \r
-       LPVOID lpReserved);\r
-STDAPI PrxDllCanUnloadNow(void);\r
-STDAPI PrxDllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv);\r
-STDAPI PrxDllRegisterServer(void);\r
-STDAPI PrxDllUnregisterServer(void);\r
-}\r
-\r
-#endif\r
index fdde090a11e4eb0531b7e6a93f9c8c88f4571829..66fb37b9254d6f2672ddd872a5f605da4a2a423e 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
+
+
+
+#pragma once
+
+
+
+#ifndef STRICT
+
+#define STRICT
+
+#endif
+
+
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+
+#ifndef WINVER                         // Allow use of features specific to Windows XP or later.
+
+#define WINVER 0x0501          // Change this to the appropriate value to target other versions of Windows.
+
+#endif
+
+
+
+#ifndef _WIN32_WINNT           // Allow use of features specific to Windows XP or later.                   
+
+#define _WIN32_WINNT 0x0501    // Change this to the appropriate value to target other versions of Windows.
+
+#endif                                         
+
+
+
+#ifndef _WIN32_WINDOWS         // Allow use of features specific to Windows 98 or later.
+
+#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
+
+#endif
+
+
+
+#ifndef _WIN32_IE                      // Allow use of features specific to IE 6.0 or later.
+
+#define _WIN32_IE 0x0600       // Change this to the appropriate value to target other versions of IE.
+
+#endif
+
+
+
+#define _ATL_APARTMENT_THREADED
+
+#define _ATL_NO_AUTOMATIC_NAMESPACE
+
+
+
+#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS     // some CString constructors will be explicit
+
+
+
+
+
+#include "resource.h"
+
+#include <atlbase.h>
+
+#include <atlcom.h>
+
+
 
-    Change History (most recent first):
-    
-$Log: stdafx.h,v $
-Revision 1.1  2009/05/26 04:43:54  herscher
-<rdar://problem/3948252> COM component that can be used with any .NET language and VB.
-\r
-\r
-*/\r
-\r
-#pragma once\r
-\r
-#ifndef STRICT\r
-#define STRICT\r
-#endif\r
-\r
-// Modify the following defines if you have to target a platform prior to the ones specified below.\r
-// Refer to MSDN for the latest info on corresponding values for different platforms.\r
-#ifndef WINVER                         // Allow use of features specific to Windows XP or later.\r
-#define WINVER 0x0501          // Change this to the appropriate value to target other versions of Windows.\r
-#endif\r
-\r
-#ifndef _WIN32_WINNT           // Allow use of features specific to Windows XP or later.                   \r
-#define _WIN32_WINNT 0x0501    // Change this to the appropriate value to target other versions of Windows.\r
-#endif                                         \r
-\r
-#ifndef _WIN32_WINDOWS         // Allow use of features specific to Windows 98 or later.\r
-#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.\r
-#endif\r
-\r
-#ifndef _WIN32_IE                      // Allow use of features specific to IE 6.0 or later.\r
-#define _WIN32_IE 0x0600       // Change this to the appropriate value to target other versions of IE.\r
-#endif\r
-\r
-#define _ATL_APARTMENT_THREADED\r
-#define _ATL_NO_AUTOMATIC_NAMESPACE\r
-\r
-#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS     // some CString constructors will be explicit\r
-\r
-\r
-#include "resource.h"\r
-#include <atlbase.h>\r
-#include <atlcom.h>\r
-\r
 using namespace ATL;
\ No newline at end of file
index 82e9c9e20a57199ee6a6a7cdc48b62f1bc83774d..ec5e69fa4a4f34e4dd87aff2cddc66095a332863 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: Application.rc2,v $
-Revision 1.3  2006/08/14 23:25:48  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:26  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:04:35  rpantos
-Move up one level
-
-Revision 1.2  2004/01/30 02:56:33  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.1  2003/08/21 02:06:46  bradley
-Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
-
-Revision 1.2  2003/08/20 07:06:34  bradley
-Update to APSL 2.0. Updated change history to match other mDNSResponder files.
-
-Revision 1.1  2002/09/20 06:12:48  bradley
-DNSServiceBrowser for Windows
-
-*/
+ */
 
 #ifdef APSTUDIO_INVOKED
        #error this file is not editable by Microsoft Visual C++
index 4a49fdfeedd71ba33cc13b45fbb6a1886dca60a9..8dd6b091e99cadeca39a54b8ed9615221e1d5692 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: AboutDialog.cpp,v $
-Revision 1.4  2008/10/23 22:33:26  cheshire
-Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
-
-Revision 1.3  2006/08/14 23:25:49  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:26  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:04:36  rpantos
-Move up one level
-
-Revision 1.2  2004/01/30 02:56:32  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.1  2003/08/21 02:06:47  bradley
-Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
-
-Revision 1.4  2003/08/12 19:56:28  cheshire
-Update to APSL 2.0
-
-Revision 1.3  2003/07/02 21:20:06  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.2  2002/09/21 20:44:55  zarzycki
-Added APSL info
-
-Revision 1.1  2002/09/20 06:12:49  bradley
-DNSServiceBrowser for Windows
-
-*/
+ */
 
 #include       <stdlib.h>
 
index e4869ca02588044e6e9c9e75b8b48f7b52491755..cdd257cf49b3fc1204ca363adab33d7e2ba2c325 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: AboutDialog.h,v $
-Revision 1.4  2008/10/23 22:33:26  cheshire
-Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
-
-Revision 1.3  2006/08/14 23:25:49  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:26  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:04:36  rpantos
-Move up one level
-
-Revision 1.2  2004/01/30 02:56:32  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.1  2003/08/21 02:06:47  bradley
-Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
-
-Revision 1.4  2003/08/12 19:56:28  cheshire
-Update to APSL 2.0
-
-Revision 1.3  2003/07/02 21:20:06  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.2  2002/09/21 20:44:55  zarzycki
-Added APSL info
-
-Revision 1.1  2002/09/20 06:12:50  bradley
-DNSServiceBrowser for Windows
-
-*/
+ */
 
 #if !defined(AFX_ABOUTDIALOG_H__4B8A04B2_9735_4F4A_AFCA_15F85FB3D763__INCLUDED_)
 #define AFX_ABOUTDIALOG_H__4B8A04B2_9735_4F4A_AFCA_15F85FB3D763__INCLUDED_
index b3a377e404a35c78b0e1383d282b3e02915b62ff..f7f4b0352f4b20b80076a55ff8b78d1b9adad285 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: Application.cpp,v $
-Revision 1.3  2006/08/14 23:25:49  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:26  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:04:36  rpantos
-Move up one level
-
-Revision 1.2  2004/01/30 02:56:32  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.1  2003/08/21 02:06:47  bradley
-Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
-
-Revision 1.5  2003/08/12 19:56:28  cheshire
-Update to APSL 2.0
-
-Revision 1.4  2003/07/02 21:20:06  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.3  2002/09/21 20:44:55  zarzycki
-Added APSL info
-
-Revision 1.2  2002/09/20 08:37:34  bradley
-Increased the DNS record cache from the default of 64 to 512 entries for larger networks.
-
-Revision 1.1  2002/09/20 06:12:51  bradley
-DNSServiceBrowser for Windows
-
-*/
+ */
 
 #include       <assert.h>
 
index b21deda5ff8ccf34a744946d246e591eb9d3b94b..8368a49fe50e39995ceb4c60b50a675b7c5e0c95 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: Application.h,v $
-Revision 1.3  2006/08/14 23:25:49  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:26  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:04:36  rpantos
-Move up one level
-
-Revision 1.2  2004/01/30 02:56:32  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.1  2003/08/21 02:06:47  bradley
-Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
-
-Revision 1.4  2003/08/12 19:56:28  cheshire
-Update to APSL 2.0
-
-Revision 1.3  2003/07/02 21:20:06  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.2  2002/09/21 20:44:55  zarzycki
-Added APSL info
-
-Revision 1.1  2002/09/20 06:12:51  bradley
-DNSServiceBrowser for Windows
-
-*/
+ */
 
 #if !defined(AFX_ADMIN_H__8663733F_6A15_439F_B568_F5A0125CD572__INCLUDED_)
 #define AFX_ADMIN_H__8663733F_6A15_439F_B568_F5A0125CD572__INCLUDED_
index 486d46bf79ac7ea5c3bcd6ea1460910d35231220..9e4db65b260d6508746652efca5f2da462238af6 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: ChooserDialog.cpp,v $
-Revision 1.5  2008/10/23 22:33:26  cheshire
-Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
-
-Revision 1.4  2006/08/14 23:25:49  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2005/02/10 22:35:35  cheshire
-<rdar://problem/3727944> Update name
-
-Revision 1.2  2004/07/13 21:24:26  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:04:36  rpantos
-Move up one level
-
-Revision 1.10  2004/04/23 01:19:41  bradley
-Changed TXT record new line delimiter from \n to \r\n so it works now that it is an edit text.
-
-Revision 1.9  2004/03/07 05:51:04  bradley
-Updated service type list table to include all service types from dns-sd.org as of 2004-03-06.
-Added separate Service Type and Service Description columns so both are show in the window.
-
-Revision 1.8  2004/01/30 02:56:32  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.7  2003/12/25 03:42:04  bradley
-Added login dialog to get username/password when going to FTP sites. Added more services.
-
-Revision 1.6  2003/10/31 12:18:30  bradley
-Added display of the resolved host name. Show separate TXT record entries on separate lines.
-
-Revision 1.5  2003/10/16 09:21:56  bradley
-Ignore non-IPv4 resolves until mDNS on Windows supports IPv6.
-
-Revision 1.4  2003/10/10 03:41:29  bradley
-Changed HTTP double-click handling to work with or without the path= prefix in the TXT record.
-
-Revision 1.3  2003/10/09 19:50:40  bradley
-Sort service type list by description.
-
-Revision 1.2  2003/10/09 19:41:29  bradley
-Changed quit handling to go through normal close path so dialog is freed on quit. Integrated changes
-from Andrew van der Stock for the addition of an _rfb._tcp service type for a VNC Remote Framebuffer
-Server for KDE support. Widened service type list to handle larger service type descriptions.
-
-Revision 1.1  2003/08/21 02:06:47  bradley
-Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
-
-Revision 1.7  2003/08/20 06:45:56  bradley
-Updated for IP address changes in DNSServices. Added support for browsing for Xserve RAID.
-
-Revision 1.6  2003/08/12 19:56:28  cheshire
-Update to APSL 2.0
-
-Revision 1.5  2003/07/13 01:03:55  cheshire
-Diffs provided by Bob Bradley to provide provide proper display of Unicode names
-
-Revision 1.4  2003/07/02 21:20:06  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.3  2002/09/21 20:44:55  zarzycki
-Added APSL info
-
-Revision 1.2  2002/09/20 08:39:21  bradley
-Make sure each resolved item matches the selected service type to handle resolved that may have
-been queued up on the Windows Message Loop. Reduce column to fit when scrollbar is present.
-
-Revision 1.1  2002/09/20 06:12:52  bradley
-DNSServiceBrowser for Windows
-
-*/
+ */
 
 #include       <assert.h>
 #include       <stdio.h>
index 833661009ccefccb808e3af3e270005848670493..41fd82752c631612c5a9f0104fd244cb16cff426 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: ChooserDialog.h,v $
-Revision 1.3  2006/08/14 23:25:49  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:26  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:04:36  rpantos
-Move up one level
-
-Revision 1.3  2004/01/30 02:56:32  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.2  2003/10/31 12:18:30  bradley
-Added display of the resolved host name. Show separate TXT record entries on separate lines.
-
-Revision 1.1  2003/08/21 02:06:47  bradley
-Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
-
-Revision 1.4  2003/08/12 19:56:28  cheshire
-Update to APSL 2.0
-
-Revision 1.3  2003/07/02 21:20:06  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.2  2002/09/21 20:44:55  zarzycki
-Added APSL info
-
-Revision 1.1  2002/09/20 06:12:52  bradley
-DNSServiceBrowser for Windows
-
-*/
+ */
 
 #if !defined(AFX_CHOOSERDIALOG_H__AC258704_B307_4901_9F98_A0AC022FD8AC__INCLUDED_)
 #define AFX_CHOOSERDIALOG_H__AC258704_B307_4901_9F98_A0AC022FD8AC__INCLUDED_
index b4209d08614cf0e00221f1193c2dce499dfea7fa..b9a9ec9343d5d84ffde34d3d444ea44db9162b24 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: LoginDialog.cpp,v $
-Revision 1.2  2006/08/14 23:25:49  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.1  2004/06/18 04:04:36  rpantos
-Move up one level
-
-Revision 1.2  2004/01/30 02:56:32  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.1  2003/12/25 03:47:28  bradley
-Login dialog to get the username/password from the user.
-
-*/
+ */
 
 #include       <assert.h>
 #include       <stdlib.h>
index 4149fc8bfd8fee9455f542f7dba14388b94c487f..e53beb6bbfd1ec470953d018b6081ed09f9585d6 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: LoginDialog.h,v $
-Revision 1.2  2006/08/14 23:25:49  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.1  2004/06/18 04:04:36  rpantos
-Move up one level
-
-Revision 1.2  2004/01/30 02:56:32  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.1  2003/12/25 03:47:28  bradley
-Login dialog to get the username/password from the user.
-
-*/
+ */
 
 #ifndef        __LOGIN_DIALOG__
 #define        __LOGIN_DIALOG__
index 7c4030536c6870715daba62f78990fe7b7bb117c..ae2ca2ecf9c0bfaaee737d19393ae3c3ddc96f71 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: StdAfx.cpp,v $
-Revision 1.3  2006/08/14 23:25:49  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:26  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:04:36  rpantos
-Move up one level
-
-Revision 1.2  2004/01/30 02:56:32  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.1  2003/08/21 02:06:47  bradley
-Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
-
-Revision 1.4  2003/08/12 19:56:28  cheshire
-Update to APSL 2.0
-
-Revision 1.3  2003/07/02 21:20:06  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.2  2002/09/21 20:44:55  zarzycki
-Added APSL info
-
-Revision 1.1  2002/09/20 06:12:53  bradley
-DNSServiceBrowser for Windows
-
-*/
+ */
 
 #include       "stdafx.h"
index 958c12e53fa97438c2dda293c5d285155cb6416a..c62bd3ee98dbd51a6db6efe946612fa954ee430e 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: StdAfx.h,v $
-Revision 1.3  2006/08/14 23:25:49  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:26  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:04:36  rpantos
-Move up one level
-
-Revision 1.3  2004/01/30 02:56:32  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.2  2003/10/09 02:31:55  bradley
-Define WINVER if not already defined to avoid warning with Visual Studio .NET 2003.
-
-Revision 1.1  2003/08/21 02:06:47  bradley
-Moved DNSServiceBrowser for non-Windows CE into Windows sub-folder.
-
-Revision 1.4  2003/08/12 19:56:28  cheshire
-Update to APSL 2.0
-
-Revision 1.3  2003/07/02 21:20:06  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
-
-Revision 1.2  2002/09/21 20:44:56  zarzycki
-Added APSL info
-
-Revision 1.1  2002/09/20 06:12:53  bradley
-DNSServiceBrowser for Windows
-
-*/
+ */
 
 #if !defined(AFX_STDAFX_H__424305D2_0A97_4AA0_B9B1_A7D90D18EBA0__INCLUDED_)
 #define AFX_STDAFX_H__424305D2_0A97_4AA0_B9B1_A7D90D18EBA0__INCLUDED_
index 257197622e3b569014385d275e85da3332a84dd9..931cd950a5b6d99d4ce0c1faa96e3ec985ff64b8 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: Application.cpp,v $
-Revision 1.3  2006/08/14 23:25:55  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:27  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:04:37  rpantos
-Move up one level
-
-Revision 1.2  2004/01/30 02:56:33  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.1  2003/08/21 02:16:10  bradley
-DNSServiceBrowser for HTTP services for Windows CE/PocketPC.
-
-*/
+ */
 
 #include       "stdafx.h"
 
index 76e80983ed3a536a01fbba68594848885380745a..cfd5429214a8587b85007a6d4e1d91293747f334 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: Application.h,v $
-Revision 1.3  2006/08/14 23:25:55  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:27  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:04:37  rpantos
-Move up one level
-
-Revision 1.2  2004/01/30 02:56:33  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.1  2003/08/21 02:16:10  bradley
-DNSServiceBrowser for HTTP services for Windows CE/PocketPC.
-
-*/
+ */
 
 #if !defined(AFX_APPLICATION_H__E2E51302_D643_458E_A7A5_5157233D1E5C__INCLUDED_)
 #define AFX_APPLICATION_H__E2E51302_D643_458E_A7A5_5157233D1E5C__INCLUDED_
index 5472b47d51c4dd6cb908820d29dc680cd2e70ff2..92cdeb307c2338ea645847518951f5f8d5b902a5 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: BrowserDialog.cpp,v $
-Revision 1.4  2008/10/23 22:33:26  cheshire
-Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
-
-Revision 1.3  2006/08/14 23:25:55  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:27  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:04:37  rpantos
-Move up one level
-
-Revision 1.5  2004/01/30 02:56:33  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.4  2003/10/16 09:21:56  bradley
-Ignore non-IPv4 resolves until mDNS on Windows supports IPv6.
-
-Revision 1.3  2003/10/14 03:28:50  bradley
-Insert services in sorted order to make them easier to find. Defer service adds/removes to the main
-thread to avoid potential problems with multi-threaded MFC message map access. Added some asserts.
-
-Revision 1.2  2003/10/10 03:43:34  bradley
-Added support for launching a web browser to go to the browsed web site on a single-tap.
-
-Revision 1.1  2003/08/21 02:16:10  bradley
-DNSServiceBrowser for HTTP services for Windows CE/PocketPC.
-
-*/
+ */
 
 #include       "stdafx.h"
 
index 206ca91f315e2a2e2a33a41707c494850a3bdfb2..a27df91e4e8c7f368a86aafc459de622cb915e9a 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: BrowserDialog.h,v $
-Revision 1.3  2006/08/14 23:25:55  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:27  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:04:37  rpantos
-Move up one level
-
-Revision 1.4  2004/01/30 02:56:33  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.3  2003/10/14 03:28:50  bradley
-Insert services in sorted order to make them easier to find. Defer service adds/removes to the main
-thread to avoid potential problems with multi-threaded MFC message map access. Added some asserts.
-
-Revision 1.2  2003/10/10 03:43:34  bradley
-Added support for launching a web browser to go to the browsed web site on a single-tap.
-
-Revision 1.1  2003/08/21 02:16:10  bradley
-DNSServiceBrowser for HTTP services for Windows CE/PocketPC.
-
-*/
+ */
 
 #if !defined(AFX_BROWSERDIALOG_H__DECC5C82_C1C6_4630_B8D5_E1DDE570A061__INCLUDED_)
 #define AFX_BROWSERDIALOG_H__DECC5C82_C1C6_4630_B8D5_E1DDE570A061__INCLUDED_
index dbbcc18800968f9022982a35d3e4ef3df99858b6..ae2ca2ecf9c0bfaaee737d19393ae3c3ddc96f71 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: StdAfx.cpp,v $
-Revision 1.3  2006/08/14 23:25:55  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:27  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:04:37  rpantos
-Move up one level
-
-Revision 1.2  2004/01/30 02:56:33  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.1  2003/08/21 02:16:10  bradley
-DNSServiceBrowser for HTTP services for Windows CE/PocketPC.
-
-*/
+ */
 
 #include       "stdafx.h"
index 4cdcef7bbbe769ca7d3f50dfd20d986a35a89c1c..4b14a0b7cf1b55e3a125bac7fd03b737a55e2df6 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: StdAfx.h,v $
-Revision 1.3  2006/08/14 23:25:55  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2004/07/13 21:24:27  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.1  2004/06/18 04:04:37  rpantos
-Move up one level
-
-Revision 1.2  2004/01/30 02:56:33  bradley
-Updated to support full Unicode display. Added support for all services on www.dns-sd.org.
-
-Revision 1.1  2003/08/21 02:16:10  bradley
-DNSServiceBrowser for HTTP services for Windows CE/PocketPC.
-
-*/
+ */
 
 #if !defined(AFX_STDAFX_H__7F91E52B_CF39_429D_837D_599CE0B2B3D6__INCLUDED_)
 #define AFX_STDAFX_H__7F91E52B_CF39_429D_837D_599CE0B2B3D6__INCLUDED_
index 593175dc186570a9452cabb3b96298f78f47436a..1707ac59e4be66108f3e1c138eaf518af39151a3 100755 (executable)
                        />\r
                </Configuration>\r
                <Configuration\r
-                       Name="Release|Win32"\r
-                       OutputDirectory="Release"\r
-                       IntermediateDirectory="Release"\r
+                       Name="Debug|x64"\r
+                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
                        ConfigurationType="0"\r
                        InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
                        >\r
                        <Tool\r
                                Name="VCNMakeTool"\r
-                               BuildCommandLine="nmake /f makefile"\r
-                               ReBuildCommandLine="nmake /f makefile"\r
-                               CleanCommandLine="nmake /f makefile clean"\r
+                               BuildCommandLine="nmake /f makefile64 DEBUG=1"\r
+                               ReBuildCommandLine="nmake /f makefile64 DEBUG=1"\r
+                               CleanCommandLine="nmake /f makefile64 DEBUG=1 clean"\r
                                Output=""\r
                                PreprocessorDefinitions=""\r
                                IncludeSearchPath=""\r
                        />\r
                </Configuration>\r
                <Configuration\r
-                       Name="Debug|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
                        ConfigurationType="0"\r
                        InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
                        >\r
                        <Tool\r
                                Name="VCNMakeTool"\r
-                               BuildCommandLine="nmake /f makefile DEBUG=1"\r
-                               ReBuildCommandLine="nmake /f makefile DEBUG=1"\r
-                               CleanCommandLine="nmake /f makefile DEBUG=1 clean"\r
+                               BuildCommandLine="nmake /f makefile"\r
+                               ReBuildCommandLine="nmake /f makefile"\r
+                               CleanCommandLine="nmake /f makefile clean"\r
                                Output=""\r
                                PreprocessorDefinitions=""\r
                                IncludeSearchPath=""\r
@@ -89,9 +89,9 @@
                        >\r
                        <Tool\r
                                Name="VCNMakeTool"\r
-                               BuildCommandLine="nmake /f makefile"\r
-                               ReBuildCommandLine="nmake /f makefile"\r
-                               CleanCommandLine="nmake /f makefile clean"\r
+                               BuildCommandLine="nmake /f makefile64"\r
+                               ReBuildCommandLine="nmake /f makefile64"\r
+                               CleanCommandLine="nmake /f makefile64 clean"\r
                                Output=""\r
                                PreprocessorDefinitions=""\r
                                IncludeSearchPath=""\r
index cb2d864373373865c3887d9edfbd9f1bff0b5700..79fdf140c7fd066f275f3772d4863e50eac1e042 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: jdns_sd.rc,v $
-Revision 1.5  2007/04/27 20:34:31  herscher
-<rdar://problem/5159673> mDNS: Company name needs to be changed to Apple Inc.
-
-Revision 1.4  2006/08/14 23:26:04  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2004/10/19 03:41:42  shersche
-<rdar://problem/3843396> Include "afxres.h" to resource script so it gets compiled correctly
-Bug #: 3843396
-
-Revision 1.2  2004/06/26 21:27:38  rpantos
-Update to use WinVersRes.h
-
-Revision 1.1  2004/06/26 20:06:51  rpantos
-Update to use WinVersRes.h
-
-
-*/
+ */
 
 #ifndef JDNS_SD_RC
 #define JDNS_SD_RC
index 768b51f9102fe5c41ac0e2d40f9b560b391dedfe..2e4b6bd0ce3dd4df4bcda30345f665dad5adc258 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# $Log: makefile,v $
-# Revision 1.10  2009/03/30 20:22:43  herscher
-# <rdar://problem/5925472> Current Bonjour code does not compile on Windows
-# Update LIBDIR to work with new build directory structure
-# Create postbuild rules for new buildtrain
-#
-# Revision 1.9  2006/08/14 23:26:04  cheshire
-# Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-#
-# Revision 1.8  2006/07/05 20:57:22  cheshire
-# <rdar://problem/3839132> Java needs to implement DNSServiceRegisterRecord equivalent
-#
-# Revision 1.7  2005/10/19 17:19:56  herscher
-# Change JDK to use JAVA_HOME environment variable
-#
-# Revision 1.6  2005/02/10 22:35:36  cheshire
-# <rdar://problem/3727944> Update name
-#
-# Revision 1.5  2005/02/08 23:47:51  shersche
-# Build into proper directories for installer
-#
-# 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
-#
-# Revision 1.2  2004/06/26 20:07:06  rpantos
-# Update to use WinVersRes.h
-#
-# Revision 1.1  2004/06/18 04:12:05  rpantos
-# Move up one level. Integration changes for Scott.
-#
-# Revision 1.2  2004/05/01 00:31:41  rpantos
-# Change line endings for CVS.
-#
-# Revision 1.1  2004/04/30 16:32:34  rpantos
-# First checked in.
-#
 # This Makefile builds a .jar file and accompanying JNI support library
 # containing the DNSSD implementation for Java and support classes.
 #
@@ -163,7 +124,7 @@ $(BUILDDIR)\dns_sd.jar: $(JARCONTENTS)
 
 $(BUILDDIR)\jdns_sd.dll: $(JAVASRC)\JNISupport.c $(OBJDIR)\DNSSD.java.h $(OBJDIR)\jdns_sd.RES
        $(CC) -Fe$@ $(JAVASRC)\JNISupport.c $(CFLAGS) -I$(OBJDIR) \
-       $(LIBDIR)\DNSSD.lib $(JDK)\lib\jvm.lib ws2_32.lib iphlpapi.lib $(OBJDIR)\jdns_sd.RES
+       $(LIBDIR)\DNSSD.lib $(JDK)\lib\jvm.lib ws2_32.lib iphlpapi.lib $(OBJDIR)\jdns_sd.RES /link /NXCOMPAT /DYNAMICBASE /SAFESEH
 
 .SUFFIXES : .java
 {$(JAVASRC)}.java{$(OBJDIR)\com\apple\dnssd}.class:    
diff --git a/mDNSWindows/Java/makefile64 b/mDNSWindows/Java/makefile64
new file mode 100644 (file)
index 0000000..fb0ff9c
--- /dev/null
@@ -0,0 +1,143 @@
+# -*- tab-width: 4 -*-
+#
+# Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#     http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This Makefile builds a .jar file and accompanying JNI support library
+# containing the DNSSD implementation for Java and support classes.
+#
+# Prior to building Java support, you must build DNSSD.dll.
+#
+# nmake with no arguments builds all production targets.
+# 'nmake DEBUG=1' to build debugging targets.
+# 'nmake clean' or 'nmake clean DEBUG=1' to delete prod/debug objects & targets
+#
+# To run nmake, you may need to set up your PATH correctly, using a script 
+# such as: "\Program Files\Microsoft Visual Studio .NET\Vc7\bin\vcvars32.bat"
+# 
+# The default location of the JDK is \javasdk. You can override this on the
+# command line (e.g. 'nmake JDK=\j2dk1.4.2_03').
+
+############################################################################
+
+COREDIR = ..\..\mDNSCore
+SHAREDDIR = ..\..\mDNSShared
+
+JDK = $(JAVA_HOME)
+
+CC = cl
+RC = rc
+LD = ld
+CP = copy
+RM = del /Q
+RMDIR = rmdir /S /Q
+JAVAC = $(JDK)\bin\javac
+JAVAH = $(JDK)\bin\javah
+JAR = $(JDK)\bin\jar
+CFLAGS_COMMON = -LD -DAUTO_CALLBACKS=0 -I. -I..\.. \
+       -I$(COREDIR) -I$(SHAREDDIR) -I$(JDK)\include -I$(JDK)\include\win32
+
+# Set up diverging paths for debug vs. prod builds
+DEBUG=0
+!if $(DEBUG) == 1
+CFLAGS_DEBUG = -Zi -DMDNS_DEBUGMSGS=2 
+OBJDIR = objects\debug\x64
+BUILDDIR = build\debug\x64
+INSTALLDIR = root\"Program Files"\Bonjour
+LIBDIR = ..\DLL\x64\Debug
+!else
+CFLAGS_DEBUG = -Os -DMDNS_DEBUGMSGS=0 
+OBJDIR = objects\prod\x64
+BUILDDIR = build\prod\x64
+INSTALLDIR = root\"Program Files"\Bonjour
+LIBDIR = ..\DLL\x64\Release
+!endif
+
+CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_DEBUG)
+JAVACFLAGS = $(CFLAGS) $(JAVACFLAGS_OS)
+
+#############################################################################
+
+all: setup Java postbuild
+
+# 'setup' sets up the build directory structure the way we want
+setup:
+       @if not exist objects           mkdir objects
+       @if not exist build                     mkdir build
+       @if not exist $(OBJDIR)         mkdir $(OBJDIR)
+       @if not exist $(BUILDDIR)       mkdir $(BUILDDIR)
+
+postbuild:
+       @if not "%RC_XBS%"=="YES" GOTO CONT
+       @if not exist "$(DSTROOT)\WINDOWS\system32\x64" mkdir "$(DSTROOT)\WINDOWS\system32\x64"
+       @if not exist "$(DSTROOT)\Program Files\Bonjour\x64"    mkdir "$(DSTROOT)\Program Files\Bonjour\x64"
+       @copy $(BUILDDIR)\jdns_sd.dll "$(DSTROOT)\WINDOWS\system32\x64"
+       @copy $(BUILDDIR)\dns_sd.jar  "$(DSTROOT)\Program Files\Bonjour\x64"
+       @:CONT
+       @if not exist root                                      mkdir root
+       @if not exist root\"Program Files"      mkdir root\"Program Files"
+       @if not exist $(INSTALLDIR)                     mkdir $(INSTALLDIR)
+       copy $(BUILDDIR)\dns_sd.jar $(INSTALLDIR)
+       copy $(BUILDDIR)\jdns_sd.dll $(INSTALLDIR)
+
+# clean removes targets and objects
+clean:
+       @if exist $(OBJDIR)             $(RMDIR) $(OBJDIR)
+       @if exist $(BUILDDIR)   $(RMDIR) $(BUILDDIR)
+
+#############################################################################
+
+# The following targets build Java wrappers for the dns-sd.h API.
+
+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\DNSSDException.class \
+                               $(OBJDIR)\com\apple\dnssd\DNSRecord.class \
+                               $(OBJDIR)\com\apple\dnssd\TXTRecord.class \
+                               $(OBJDIR)\com\apple\dnssd\DNSSDRegistration.class \
+                               $(OBJDIR)\com\apple\dnssd\DNSSDRecordRegistrar.class \
+                               $(OBJDIR)\com\apple\dnssd\BaseListener.class \
+                               $(OBJDIR)\com\apple\dnssd\BrowseListener.class \
+                               $(OBJDIR)\com\apple\dnssd\ResolveListener.class \
+                               $(OBJDIR)\com\apple\dnssd\RegisterListener.class \
+                               $(OBJDIR)\com\apple\dnssd\RegisterRecordListener.class \
+                               $(OBJDIR)\com\apple\dnssd\QueryListener.class \
+                               $(OBJDIR)\com\apple\dnssd\DomainListener.class \
+                               $(OBJDIR)\com\apple\dnssd\DNSSD.class
+
+$(BUILDDIR)\dns_sd.jar: $(JARCONTENTS)
+       $(JAR) -cf $@ -C $(OBJDIR) com
+
+$(BUILDDIR)\jdns_sd.dll: $(JAVASRC)\JNISupport.c $(OBJDIR)\DNSSD.java.h $(OBJDIR)\jdns_sd.RES
+       $(CC) -Fe$@ $(JAVASRC)\JNISupport.c $(CFLAGS) -I$(OBJDIR) \
+       $(LIBDIR)\DNSSD.lib $(JDK)\lib\jvm.lib ws2_32.lib iphlpapi.lib $(OBJDIR)\jdns_sd.RES /link /NXCOMPAT /DYNAMICBASE
+
+.SUFFIXES : .java
+{$(JAVASRC)}.java{$(OBJDIR)\com\apple\dnssd}.class:    
+       $(JAVAC) -d $(OBJDIR) -classpath $(OBJDIR) $<
+
+$(OBJDIR)\DNSSD.java.h: $(OBJDIR)\com\apple\dnssd\DNSSD.class
+       $(JAVAH) -classpath $(OBJDIR) -o $@ \
+               com.apple.dnssd.AppleBrowser \
+               com.apple.dnssd.AppleResolver \
+               com.apple.dnssd.AppleRegistration \
+               com.apple.dnssd.AppleQuery \
+               com.apple.dnssd.AppleService 
+
+$(OBJDIR)\jdns_sd.RES: jdns_sd.rc
+       $(RC) /fo $@ $?
+
index 63a7df1d795dd91ca9b634aa227519fae73ae6cb..f3052d16e0f8c948717f14eabf7db0f60f570f63 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-       
-$Log: NSPTool.c,v $
-Revision 1.4  2006/08/14 23:26:06  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2004/08/26 04:46:49  shersche
-Add -q switch for silent operation
-
-Revision 1.2  2004/06/23 16:39:14  shersche
-Fix extraneous warnings regarding implict casts
-
-Submitted by: Scott Herscher (sherscher@apple.com)
-
-Revision 1.1  2004/06/18 04:14:26  rpantos
-Move up one level.
-
-Revision 1.1  2004/01/30 03:02:58  bradley
-NameSpace Provider Tool for installing, removing, list, etc. NameSpace Providers.
-
-*/
+ */
 
 #include       <stdio.h>
 #include       <stdlib.h>
index 4ae504fda5e0dd91468a39cf0036d807228b236f..3aa1cee7d410467def537e1f18d0b6e6b40ddde2 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: Prefix.h,v $
-Revision 1.2  2006/08/14 23:26:06  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.1  2004/06/18 04:14:26  rpantos
-Move up one level.
-
-Revision 1.1  2004/01/30 03:02:58  bradley
-NameSpace Provider Tool for installing, removing, list, etc. NameSpace Providers.
-                                       
-*/
+ */
 
 #ifndef __PREFIX__
 #define __PREFIX__
index ec69f950297792156b1529820a8bd3e498f8c28b..506c82b5eb0364f14c878888cf4251b533ce44c2 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: PosixCompat.c,v $
-Revision 1.1  2009/07/09 21:40:32  herscher
-<rdar://problem/3775717> SDK: Port mDNSNetMonitor to Windows. Add a small Posix compatibility layer to the mDNSWindows platform layer. This makes it possible to centralize the implementations to functions such as if_indextoname() and inet_pton() that are made in several projects in B4W.
-
-
-*/
+ */
 
 #include "PosixCompat.h"
 #include <DebugServices.h>
@@ -101,34 +93,29 @@ inet_pton( int family, const char * addr, void * dst )
        }
     else return 0;
 }
-
+\r
 
 int
 gettimeofday( struct timeval * tv, struct timezone * tz )
-{
-#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
-#      define DELTA_EPOCH_IN_MICROSECS  11644473600000000Ui64
-#else
-#      define DELTA_EPOCH_IN_MICROSECS  11644473600000000ULL
-#endif
-       FILETIME ft;
-       unsigned __int64 tmpres = 0;
-       if ( tv != NULL )
-       {
-               GetSystemTimeAsFileTime(&ft);
-               tmpres |= ft.dwHighDateTime;
-               tmpres <<= 32;
-               tmpres |= ft.dwLowDateTime;
-               tmpres -= DELTA_EPOCH_IN_MICROSECS; 
-               tmpres /= 10;  /*convert into microseconds*/
-               tv->tv_sec = (long)(tmpres / 1000000UL);
-               tv->tv_usec = (long)(tmpres % 1000000UL);
-       }
+{\r
+#define EPOCHFILETIME (116444736000000000i64)\r
+\r
+       if ( tv != NULL )\r
+       {\r
+               FILETIME        ft;\r
+               LARGE_INTEGER   li;\r
+               __int64         t;\r
+\r
+               GetSystemTimeAsFileTime(&ft);\r
+               li.LowPart  = ft.dwLowDateTime;\r
+               li.HighPart = ft.dwHighDateTime;\r
+               t  = li.QuadPart;       /* In 100-nanosecond intervals */\r
+               t -= EPOCHFILETIME;     /* Offset to the Epoch time */\r
+               t /= 10;                        /* In microseconds */\r
+               tv->tv_sec  = ( long )( t / 1000000 );\r
+               tv->tv_usec = ( long )( t % 1000000 );\r
+       }\r
+\r
        return 0;
 }
 
@@ -136,6 +123,6 @@ gettimeofday( struct timeval * tv, struct timezone * tz )
 extern struct tm*
 localtime_r( const time_t * clock, struct tm * result )
 {
-       result = localtime( clock );
+       localtime_s( result, clock );
        return result;
 }
index c7de0ea4de813745bd7a4327c1fbc0626452b684..9f9d0059a3b979b3a7db94faf9b1d1924f1f16cc 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: PosixCompat.h,v $
-Revision 1.1  2009/07/09 21:40:32  herscher
-<rdar://problem/3775717> SDK: Port mDNSNetMonitor to Windows. Add a small Posix compatibility layer to the mDNSWindows platform layer. This makes it possible to centralize the implementations to functions such as if_indextoname() and inet_pton() that are made in several projects in B4W.
-
-
-*/
+ */
 
 #pragma once
 
index 47b910dcae5eabfd7fa9a7f2b43f9473e2f69bf4..bc885d61e592a666eb6209446b5acaf1024139af 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: RegNames.h,v $
-Revision 1.5  2009/03/30 21:47:35  herscher
-Fix file corruption during previous checkin
-
-Revision 1.3  2006/08/14 23:25:20  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2005/10/05 18:05:28  herscher
-<rdar://problem/4192011> Save Wide-Area preferences in a different spot in the registry so they don't get removed when doing an update install.
-
-Revision 1.1  2005/03/03 02:31:37  shersche
-Consolidates all registry key names and can safely be included in any component that needs it
-
-
-*/
+ */
 
 //----------------------------------------------------------------------------------------
 //     Registry Constants
@@ -52,6 +35,7 @@ Consolidates all registry key names and can safely be included in any component
 #      define kServiceManageLLRouting                          L"ManageLLRouting"
 #      define kServiceCacheEntryCount                          L"CacheEntryCount"
 #      define kServiceManageFirewall                           L"ManageFirewall"
+#      define kServiceAdvertisedServices                       L"Services"
 
 # else
 
index 279765539744f6b3b82b368033a120f907786ff4..5abd28b39f1fe050636c99fd1175789dd0107635 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: Secret.c,v $
-Revision 1.3  2009/07/17 19:50:25  herscher
-<rdar://problem/5265747> ControlPanel doesn't display key and password in dialog box
-
-Revision 1.2  2009/06/25 21:11:52  herscher
-Fix compilation error when building Control Panel.
-
-Revision 1.1  2009/06/22 23:25:04  herscher
-<rdar://problem/5265747> ControlPanel doesn't display key and password in dialog box. Refactor Lsa calls into Secret.h and Secret.c, which is used by both the ControlPanel and mDNSResponder system service.
-
-
-*/
+ */
 
 #include "Secret.h"
 #include <stdarg.h>
index a117f090e58488af34ba872b1e19e850e3a68ccf..79643d6242f4c5ca011cc5bcc04f6fc98d1178c4 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: Secret.h,v $
-Revision 1.2  2009/06/25 21:11:52  herscher
-Fix compilation error when building Control Panel.
-
-Revision 1.1  2009/06/22 23:25:04  herscher
-<rdar://problem/5265747> ControlPanel doesn't display key and password in dialog box. Refactor Lsa calls into Secret.h and Secret.c, which is used by both the ControlPanel and mDNSResponder system service.
-
-
-*/
+ */
 
 #ifndef _Secret_h
 #define _Secret_h
diff --git a/mDNSWindows/SystemService/EventLog.mc b/mDNSWindows/SystemService/EventLog.mc
new file mode 100644 (file)
index 0000000..248e6c1
--- /dev/null
@@ -0,0 +1,11 @@
+MessageIdTypedef=WORD
+LanguageNames=(English=0x409:MSG00409)
+
+MessageId=100
+SymbolicName=MDNSRESPONDER_LOG
+Severity=Success
+Facility=Application
+Language=English
+%1
+.
+
index 4f1ad49426892dc6c7d7e554bea62526c167631a..c7c96d09f8c2557f035ce2066c9a37d6d616cfb7 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: Firewall.cpp,v $
-Revision 1.6  2009/04/24 04:55:26  herscher
-<rdar://problem/3496833> Advertise SMB file sharing via Bonjour
-
-Revision 1.5  2009/03/30 20:39:29  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/5712486> Put in extra defensive checks to prevent NULL pointer dereferencing crash
-<rdar://problem/5187308> Move build train to Visual Studio 2005
-
-Revision 1.4  2006/08/14 23:26:07  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.3  2005/09/29 06:33:54  herscher
-<rdar://problem/4278931> Fix compilation error when using latest Microsoft Platform SDK.
-
-Revision 1.2  2004/09/15 09:39:53  shersche
-Retry the method INetFwPolicy::get_CurrentProfile on error
-
-Revision 1.1  2004/09/13 07:32:31  shersche
-Wrapper for Windows Firewall API code
-
-
-*/
+ */
 
 // <rdar://problem/4278931> Doesn't compile correctly with latest Platform SDK
 
@@ -299,57 +274,108 @@ exit:
     }
 
     return err;
-}\r
-\r
-\r
-static OSStatus\r
-mDNSFirewallIsFileAndPrintSharingEnabled\r
-       (\r
-       IN INetFwProfile        * fwProfile,\r
-       OUT BOOL                        * fwServiceEnabled\r
-       )\r
-{\r
-    VARIANT_BOOL fwEnabled;\r
-    INetFwService* fwService = NULL;\r
-    INetFwServices* fwServices = NULL;\r
-       OSStatus err = S_OK;\r
-\r
-    _ASSERT(fwProfile != NULL);\r
-    _ASSERT(fwServiceEnabled != NULL);\r
-\r
-    *fwServiceEnabled = FALSE;\r
-\r
-    // Retrieve the globally open ports collection.\r
-    err = fwProfile->get_Services(&fwServices);\r
-       require( SUCCEEDED( err ), exit );\r
-\r
-    // Attempt to retrieve the globally open port.\r
-    err = fwServices->Item(NET_FW_SERVICE_FILE_AND_PRINT, &fwService);\r
-       require( SUCCEEDED( err ), exit );\r
-       \r
-       // Find out if the globally open port is enabled.\r
-    err = fwService->get_Enabled(&fwEnabled);\r
-       require( SUCCEEDED( err ), exit );\r
-       if (fwEnabled != VARIANT_FALSE)\r
-       {\r
-               *fwServiceEnabled = TRUE;\r
-       }\r
-\r
-exit:\r
-\r
-    // Release the globally open port.\r
-    if (fwService != NULL)\r
-    {\r
-        fwService->Release();\r
-    }\r
-\r
-    // Release the globally open ports collection.\r
-    if (fwServices != NULL)\r
-    {\r
-        fwServices->Release();\r
-    }\r
-\r
-    return err;\r
+}
+
+
+
+
+
+static OSStatus
+
+mDNSFirewallIsFileAndPrintSharingEnabled
+
+       (
+
+       IN INetFwProfile        * fwProfile,
+
+       OUT BOOL                        * fwServiceEnabled
+
+       )
+
+{
+
+    VARIANT_BOOL fwEnabled;
+
+    INetFwService* fwService = NULL;
+
+    INetFwServices* fwServices = NULL;
+
+       OSStatus err = S_OK;
+
+
+
+    _ASSERT(fwProfile != NULL);
+
+    _ASSERT(fwServiceEnabled != NULL);
+
+
+
+    *fwServiceEnabled = FALSE;
+
+
+
+    // Retrieve the globally open ports collection.
+
+    err = fwProfile->get_Services(&fwServices);
+
+       require( SUCCEEDED( err ), exit );
+
+
+
+    // Attempt to retrieve the globally open port.
+
+    err = fwServices->Item(NET_FW_SERVICE_FILE_AND_PRINT, &fwService);
+
+       require( SUCCEEDED( err ), exit );
+
+       
+
+       // Find out if the globally open port is enabled.
+
+    err = fwService->get_Enabled(&fwEnabled);
+
+       require( SUCCEEDED( err ), exit );
+
+       if (fwEnabled != VARIANT_FALSE)
+
+       {
+
+               *fwServiceEnabled = TRUE;
+
+       }
+
+
+
+exit:
+
+
+
+    // Release the globally open port.
+
+    if (fwService != NULL)
+
+    {
+
+        fwService->Release();
+
+    }
+
+
+
+    // Release the globally open ports collection.
+
+    if (fwServices != NULL)
+
+    {
+
+        fwServices->Release();
+
+    }
+
+
+
+    return err;
+
 }
 
 
@@ -408,7 +434,7 @@ exit:
 
 
 BOOL
-mDNSIsFileAndPrintSharingEnabled()
+mDNSIsFileAndPrintSharingEnabled( BOOL * retry )
 {
        INetFwProfile   *       fwProfile                                       = NULL;
        HRESULT                         comInit                                         = E_FAIL;
@@ -417,6 +443,7 @@ mDNSIsFileAndPrintSharingEnabled()
 
        // Initialize COM.
 
+       *retry = FALSE;
        comInit = CoInitializeEx( 0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE );
 
        // Ignore this case. RPC_E_CHANGED_MODE means that COM has already been
@@ -424,6 +451,7 @@ mDNSIsFileAndPrintSharingEnabled()
 
        if (comInit != RPC_E_CHANGED_MODE)
        {
+               *retry = TRUE;
                err = comInit;
                require(SUCCEEDED(err), exit);
        }
index 155ac9af594ab9bcdc51f7c634b8cca84318ffc7..3d7d532d1721008941959681fdaaacef84eace58 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: Firewall.h,v $
-Revision 1.3  2009/04/24 04:55:26  herscher
-<rdar://problem/3496833> Advertise SMB file sharing via Bonjour
-
-Revision 1.2  2006/08/14 23:26:07  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.1  2004/09/13 07:32:31  shersche
-Wrapper for Windows Firewall API code
-
-
-
-
-*/
+ */
 
 
 
@@ -75,7 +59,7 @@ mDNSAddToFirewall
 
 
 BOOL
-mDNSIsFileAndPrintSharingEnabled();
+mDNSIsFileAndPrintSharingEnabled( BOOL * retry );
 
 
 
index a64b0e419a3bd5de647e207b85a85390c6f8ffd0..61381d082dcf2de71ec35f23f5d59b4f359de7b9 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: Prefix.h,v $
-Revision 1.2  2006/08/14 23:26:07  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.1  2004/06/18 04:16:41  rpantos
-Move up one level.
-
-Revision 1.2  2004/04/30 02:40:23  bradley
-Define DNS_SD_CLIENT_ENABLED=0 so DNSSD.c can be included without linking the client IPC code.
-
-Revision 1.1  2004/01/30 02:58:39  bradley
-mDNSResponder Windows Service. Provides global Bonjour support with an IPC interface.
-
-*/
+ */
 
 #ifndef __PREFIX__
 #define __PREFIX__
index 2fb67bc70672b0cc4f83433f2671684e362e6144..2ef5d212beb4b9d0d8dba28d5bd832f2cf445623 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: Service.c,v $
-Revision 1.49  2009/07/17 19:59:46  herscher
-<rdar://problem/7062660> Update the womp settings for each network adapter immediately preceding the call to mDNSCoreMachineSleep().
-
-Revision 1.48  2009/07/09 21:34:14  herscher
-<rdar://problem/3775717> SDK: Port mDNSNetMonitor to Windows. Refactor the system service slightly by removing the main() function from Service.c so that mDNSNetMonitor can link to functions defined in Service.c
-
-Revision 1.47  2009/07/07 21:35:06  herscher
-<rdar://problem/6713286> windows platform changes to support use as sleep proxy client
-
-Revision 1.46  2009/06/05 18:28:24  herscher
-<rdar://problem/6125087> mDNSResponder should be able to identify VPN adapters generically
-<rdar://problem/6885843> WIN7: Bonjour removes the default gateway entry and thereby breaks network connectivity
-
-Revision 1.45  2009/04/30 20:07:51  mcguire
-<rdar://problem/6822674> Support multiple UDSs from launchd
-
-Revision 1.44  2009/03/30 20:41:36  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/6330821> Bonjour for Windows incompatible w/Juniper Network Connect. Do a substring search for "Juniper" in the description field
- of the network adapter.
-<rdar://problem/6122028> Bonjour for Windows incompatible w/Cisco AnyConnect VPN Client
-<rdar://problem/5652098> Bonjour for Windows incompatible w/Juniper Network Connect. Update the adapter name per info received from Juniper
-<rdar://problem/5781566> Core: Default Gateway set to 0.0.0.0 on Vista causes ARP flood
-<rdar://problem/5991983> Change the registry values from Apple Computer, Inc. to Apple Inc.
-<rdar://problem/5301328> wchar/sizeof mismatch in CheckFirewall()
-
-Revision 1.43  2009/01/13 05:31:35  mkrochma
-<rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
-
-Revision 1.42  2007/02/14 01:58:19  cheshire
-<rdar://problem/4995831> Don't delete Unix Domain Socket on exit if we didn't create it on startup
-
-Revision 1.41  2007/02/06 19:06:49  cheshire
-<rdar://problem/3956518> Need to go native with launchd
-
-Revision 1.40  2007/01/05 05:46:08  cheshire
-Add mDNS *const m parameter to udsserver_handle_configchange()
-
-Revision 1.39  2006/08/14 23:26:07  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.38  2005/10/05 20:55:15  herscher
-<rdar://problem/4096464> Don't call SetLLRoute on loopback interface
-
-Revision 1.37  2005/10/05 18:05:28  herscher
-<rdar://problem/4192011> Save Wide-Area preferences in a different spot in the registry so they don't get removed when doing an update install.
-
-Revision 1.36  2005/09/11 22:12:42  herscher
-<rdar://problem/4247793> Remove dependency on WMI.  Ensure that the Windows firewall is turned on before trying to configure it.
-
-Revision 1.35  2005/06/30 18:29:49  shersche
-<rdar://problem/4090059> Don't overwrite the localized service description text
-
-Revision 1.34  2005/04/22 07:34:23  shersche
-Check an interface's address and make sure it's valid before using it to set link-local routes.
-
-Revision 1.33  2005/04/13 17:48:23  shersche
-<rdar://problem/4079667> Make sure there is only one default route for link-local addresses.
-
-Revision 1.32  2005/04/06 01:32:05  shersche
-Remove default route for link-local addressing when another interface comes up with a routable IPv4 address
-
-Revision 1.31  2005/04/06 01:00:11  shersche
-<rdar://problem/4080127> GetFullPathName() should be passed the number of TCHARs in the path buffer, not the size in bytes of the path buffer.
-
-Revision 1.30  2005/04/06 00:52:43  shersche
-<rdar://problem/4079667> Only add default route if there are no other routable IPv4 addresses on any of the other interfaces. More work needs to be done to correctly configure the routing table when multiple interfaces are extant and none of them have routable IPv4 addresses.
-
-Revision 1.29  2005/03/06 05:21:56  shersche
-<rdar://problem/4037635> Fix corrupt UTF-8 name when non-ASCII system name used, enabled unicode support
-
-Revision 1.28  2005/03/03 02:27:24  shersche
-Include the RegNames.h header file for names of registry keys
-
-Revision 1.27  2005/03/02 20:12:59  shersche
-Update name
-
-Revision 1.26  2005/02/15 08:00:27  shersche
-<rdar://problem/4007151> Update name
-
-Revision 1.25  2005/02/10 22:35:36  cheshire
-<rdar://problem/3727944> Update name
-
-Revision 1.24  2005/01/27 20:02:43  cheshire
-udsSupportRemoveFDFromEventLoop() needs to close the SocketRef as well
-
-Revision 1.23  2005/01/25 08:14:15  shersche
-Change CacheRecord to CacheEntity
-
-Revision 1.22  2004/12/10 13:18:40  cheshire
-Create no-op function RecordUpdatedNiceLabel(), required by uds_daemon.c
-
-Revision 1.21  2004/11/10 04:03:41  shersche
-Remove SharedAccess dependency.  This causes problems on XP SP1, and isn't necessary for XP SP2 because we already are dependent on WMI, which itself is dependent on SharedAccess.
-
-Revision 1.20  2004/10/14 21:44:05  shersche
-<rdar://problem/3838237> Fix a race condition between the socket thread and the main processing thread that resulted in the socket thread accessing a previously deleted Win32EventSource object.
-Bug #: 3838237
-
-Revision 1.19  2004/10/12 17:59:55  shersche
-<rdar://problem/3718122> Disable routing table modifications when Nortel VPN adapter is active
-Bug #: 3718122
-
-Revision 1.18  2004/10/11 21:57:50  shersche
-<rdar://problem/3832450> The SharedAccess service dependency causes a circular dependency on Windows Server 2003.  Only add the SharedAccess service dependency if running on XP.  All other platforms do not manipulate the firewall and thus are not dependent on it.
-Bug #: 3832450
-
-Revision 1.17  2004/09/17 01:08:58  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.16  2004/09/16 18:49:34  shersche
-Remove the XP SP2 check before attempting to manage the firewall. There is a race condition in the SP2 updater such that upon first reboot after the upgrade, mDNSResponder might not know that it is running under SP2 yet.  This necessitates a second reboot before the firewall is managed.  Removing the check will cause mDNSResponder to try and manage the firewall everytime it boots up, if and only if it hasn't managed the firewall a previous time.
-
-Revision 1.15  2004/09/15 17:13:33  shersche
-Change Firewall name
-
-Revision 1.14  2004/09/15 09:37:25  shersche
-Add SharedAccess to dependency list, call CheckFirewall after sending status back to SCM
-
-Revision 1.13  2004/09/13 07:35:10  shersche
-<rdar://problem/3762235> Add mDNSResponder to Windows Firewall application list if SP2 is detected and app hasn't been added before
-Bug #: 3762235
-
-Revision 1.12  2004/09/11 21:18:32  shersche
-<rdar://problem/3779502> Add route to ARP everything when a 169.254.x.x address is selected
-Bug #: 3779502
-
-Revision 1.11  2004/09/11 05:39:19  shersche
-<rdar://problem/3780203> Detect power managment state changes, calling mDNSCoreMachineSleep(m, true) on sleep, and mDNSCoreMachineSleep(m, false) on resume
-Bug #: 3780203
-
-Revision 1.10  2004/08/16 21:45:24  shersche
-Use the full pathname of executable when calling CreateService()
-Submitted by: prepin@zetron.com
-
-Revision 1.9  2004/08/11 01:59:41  cheshire
-Remove "mDNS *globalInstance" parameter from udsserver_init()
-
-Revision 1.8  2004/08/05 05:40:05  shersche
-<rdar://problem/3751566> Only invoke SetConsoleCtrlHandler when running directly from command line.
-<rdar://problem/3751481> Invoke udsserver_handle_configchange() when the computer description changes
-Bug #: 3751481, 3751566
-
-Revision 1.7  2004/07/26 05:35:07  shersche
-ignore non-enet interfaces when setting up link-local routing
-
-Revision 1.6  2004/07/20 06:48:26  shersche
-<rdar://problem/3718122> Allow registry entries to dictate whether to manage link local routing
-Bug #: 3718122
-
-Revision 1.5  2004/07/09 19:08:07  shersche
-<rdar://problem/3713762> ServiceSetupEventLogging() errors are handled gracefully
-Bug #: 3713762
-
-Revision 1.4  2004/06/24 20:58:15  shersche
-Fix compiler error in Release build
-Submitted by: herscher
-
-Revision 1.3  2004/06/24 15:28:53  shersche
-Automatically setup routes to link-local addresses upon interface list change events.
-Submitted by: herscher
-
-Revision 1.2  2004/06/23 16:56:00  shersche
-<rdar://problem/3697326> locked call to udsserver_idle().
-Bug #: 3697326
-Submitted by: herscher
-
-Revision 1.1  2004/06/18 04:16:41  rpantos
-Move up one level.
-
-Revision 1.1  2004/01/30 02:58:39  bradley
-mDNSResponder Windows Service. Provides global Bonjour support with an IPC interface.
-
-*/
+ */
 
 #include       <stdio.h>
 #include       <stdlib.h>
+#include       <crtdbg.h>
 #include       <stdarg.h>
 #include       <stddef.h>
 
@@ -208,10 +29,12 @@ mDNSResponder Windows Service. Provides global Bonjour support with an IPC inter
 #include       "uds_daemon.h"
 #include       "GenLinkedList.h"
 #include       "Service.h"
+#include       "EventLog.h"
 
 #include       "Resource.h"
 
 #include       "mDNSEmbeddedAPI.h"
+#include       "uDNS.h"
 #include       "mDNSWin32.h"
 
 #include       "Firewall.h"
@@ -240,7 +63,7 @@ mDNSResponder Windows Service. Provides global Bonjour support with an IPC inter
 //     Constants
 //===========================================================================================================================
 
-#define        DEBUG_NAME                                                      "[Server] "
+#define        DEBUG_NAME                                                      "[mDNSWin32] "
 #define kServiceFirewallName                           L"Bonjour"
 #define        kServiceDependencies                            TEXT("Tcpip\0\0")
 #define        kDNSServiceCacheEntryCountDefault       512
@@ -248,6 +71,8 @@ mDNSResponder Windows Service. Provides global Bonjour support with an IPC inter
 #define kDefValueSize                                          MAX_PATH + 1
 #define kZeroIndex                                                     0
 #define kDefaultRouteMetric                                    399
+#define kSecondsTo100NSUnits                           ( 10 * 1000 * 1000 )
+#define kSPSMaintenanceWakePeriod                      -30
 
 #define RR_CACHE_SIZE 500
 static CacheEntity gRRCache[RR_CACHE_SIZE];
@@ -258,39 +83,31 @@ static CacheEntity gRRCache[RR_CACHE_SIZE];
 //===========================================================================================================================
 //     Structures
 //===========================================================================================================================
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        EventSourceFlags
-
-       @abstract       Session flags.
-       
-       @constant       EventSourceFlagsNone                    No flags.
-       @constant       EventSourceFlagsThreadDone              Thread is no longer active.
-       @constant       EventSourceFlagsNoClose                 Do not close the session when the thread exits.
-       @constant       EventSourceFinalized                    Finalize has been called for this session
-*/
-
-typedef uint32_t               EventSourceFlags;
-
-#define        EventSourceFlagsNone                    0
-#define        EventSourceFlagsThreadDone              ( 1 << 2 )
-#define        EventSourceFlagsNoClose                 ( 1 << 3 )
-#define EventSourceFinalized                   ( 1 << 4 )
 
-
-typedef struct Win32EventSource
+typedef struct EventSource
 {
-       EventSourceFlags                        flags;
-       HANDLE                                          threadHandle;
-       unsigned                                        threadID;
-       HANDLE                                          socketEvent;
-       HANDLE                                          closeEvent;
-       udsEventCallback                        callback;
-       void                                    *       context;
-       DWORD                                           waitCount;
-       HANDLE                                          waitList[2];
-       SOCKET                                          sock;
-       struct Win32EventSource *       next;
-} Win32EventSource;
+       HANDLE                                                  event;
+       void                                            *       context;
+       RegisterWaitableEventHandler    handler;
+       struct EventSource                      *       next;
+} EventSource;
+
+static BOOL                                                                                    gEventSourceListChanged = FALSE;
+static EventSource                                                             *       gEventSourceList = NULL;
+static EventSource                                                             *       gCurrentSource = NULL;
+static int                                                                                     gEventSources = 0;
+
+#define        kWaitListStopEvent                                                      ( WAIT_OBJECT_0 + 0 )
+#define        kWaitListInterfaceListChangedEvent                      ( WAIT_OBJECT_0 + 1 )
+#define kWaitListComputerDescriptionEvent                      ( WAIT_OBJECT_0 + 2 )
+#define kWaitListTCPIPEvent                                                    ( WAIT_OBJECT_0 + 3 )
+#define kWaitListDynDNSEvent                                           ( WAIT_OBJECT_0 + 4 )
+#define kWaitListFileShareEvent                                                ( WAIT_OBJECT_0 + 5 )
+#define kWaitListFirewallEvent                                         ( WAIT_OBJECT_0 + 6 )
+#define kWaitListAdvertisedServicesEvent                       ( WAIT_OBJECT_0 + 7 )
+#define kWaitListSPSWakeupEvent                                                ( WAIT_OBJECT_0 + 8 )
+#define kWaitListSPSSleepEvent                                         ( WAIT_OBJECT_0 + 9 )
+#define        kWaitListFixedItemCount                                         10
 
 
 #if 0
@@ -321,12 +138,16 @@ static OSStatus           ServiceSpecificInitialize( int argc, LPTSTR  argv[] );
 static OSStatus                ServiceSpecificRun( int argc, LPTSTR argv[] );
 static OSStatus                ServiceSpecificStop( void );
 static void                    ServiceSpecificFinalize( int argc, LPTSTR argv[] );
-static mStatus         EventSourceFinalize(Win32EventSource * source);
-static void                    EventSourceLock();
-static void                    EventSourceUnlock();
-static mDNSs32         udsIdle(mDNS * const inMDNS, mDNSs32 interval);
+static mStatus         SetupNotifications();
+static mStatus         TearDownNotifications();
+static mStatus         RegisterWaitableEvent( mDNS * const inMDNS, HANDLE event, void * context, RegisterWaitableEventHandler handler );
+static void                    UnregisterWaitableEvent( mDNS * const inMDNS, HANDLE event );
+static mStatus         SetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount );
+static void                    UDSCanAccept( mDNS * const inMDNS, HANDLE event, void * context );
+static void                    UDSCanRead( TCPSocket * sock );
+static void                    HandlePowerSuspend( void * v );
+static void                    HandlePowerResumeSuspend( void * v );
 static void                    CoreCallback(mDNS * const inMDNS, mStatus result);
-static void                    HostDescriptionChanged(mDNS * const inMDNS);
 static mDNSu8          SystemWakeForNetworkAccess( LARGE_INTEGER * timeout );
 static OSStatus                GetRouteDestination(DWORD * ifIndex, DWORD * address);
 static OSStatus                SetLLRoute( mDNS * const inMDNS );
@@ -367,6 +188,20 @@ DEBUG_LOCAL SERVICE_TABLE_ENTRY                    gServiceDispatchTable[] =
        { kServiceName, ServiceMain }, 
        { NULL,                 NULL }
 };
+DEBUG_LOCAL SOCKET                                             gInterfaceListChangedSocket     = INVALID_SOCKET;
+DEBUG_LOCAL HANDLE                                             gInterfaceListChangedEvent      = NULL;
+DEBUG_LOCAL HKEY                                               gDescKey                                        = NULL;
+DEBUG_LOCAL HANDLE                                             gDescChangedEvent                       = NULL; // Computer description changed event
+DEBUG_LOCAL HKEY                                               gTcpipKey                                       = NULL;
+DEBUG_LOCAL HANDLE                                             gTcpipChangedEvent                      = NULL; // TCP/IP config changed
+DEBUG_LOCAL HKEY                                               gDdnsKey                                        = NULL;
+DEBUG_LOCAL HANDLE                                             gDdnsChangedEvent                       = NULL; // DynDNS config changed
+DEBUG_LOCAL HKEY                                               gFileSharingKey                         = NULL;
+DEBUG_LOCAL HANDLE                                             gFileSharingChangedEvent        = NULL; // File Sharing changed
+DEBUG_LOCAL HKEY                                               gFirewallKey                            = NULL;
+DEBUG_LOCAL HANDLE                                             gFirewallChangedEvent           = NULL; // Firewall changed
+DEBUG_LOCAL HKEY                                               gAdvertisedServicesKey          = NULL;
+DEBUG_LOCAL HANDLE                                             gAdvertisedServicesChangedEvent = NULL; // Advertised services changed
 DEBUG_LOCAL SERVICE_STATUS                             gServiceStatus;
 DEBUG_LOCAL SERVICE_STATUS_HANDLE              gServiceStatusHandle    = NULL;
 DEBUG_LOCAL HANDLE                                             gServiceEventSource             = NULL;
@@ -378,8 +213,9 @@ DEBUG_LOCAL HANDLE                                  *       gWaitList                               = NULL;
 DEBUG_LOCAL HANDLE                                             gStopEvent                              = NULL;
 DEBUG_LOCAL HANDLE                                             gSPSWakeupEvent                 = NULL;
 DEBUG_LOCAL HANDLE                                             gSPSSleepEvent                  = NULL;
-DEBUG_LOCAL CRITICAL_SECTION                   gEventSourceLock;
-DEBUG_LOCAL GenLinkedList                              gEventSources;
+DEBUG_LOCAL HANDLE                                             gUDSEvent                               = NULL;
+DEBUG_LOCAL SocketRef                                  gUDSSocket                              = 0;
+DEBUG_LOCAL udsEventCallback                   gUDSCallback                    = NULL;
 DEBUG_LOCAL BOOL                                               gRetryFirewall                  = FALSE;
 DEBUG_LOCAL DWORD                                              gOSMajorVersion;
 DEBUG_LOCAL DWORD                                              gOSMinorVersion;
@@ -404,7 +240,7 @@ int Main( int argc, LPTSTR argv[] )
        int                             i;
 
        HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 );
-       
+
        debug_initialize( kDebugOutputTypeMetaConsole );
        debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
 
@@ -488,6 +324,7 @@ int Main( int argc, LPTSTR argv[] )
        
 exit:
        dlog( kDebugLevelTrace, DEBUG_NAME "exited (%d %m)\n", err, err );
+       _CrtDumpMemoryLeaks();
        return( (int) err );
 }
 
@@ -591,7 +428,7 @@ static OSStatus     InstallService( LPCTSTR inName, LPCTSTR inDisplayName, LPCTSTR i
        err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
        require_noerr( err, exit );
        
-       ReportStatus( EVENTLOG_SUCCESS, "installed service \"%s\"/\"%s\" at \"%s\"\n", inName, inDisplayName, inPath );
+       ReportStatus( EVENTLOG_SUCCESS, "installed service\n" );
        err = kNoErr;
        
 exit:
@@ -647,7 +484,7 @@ static OSStatus     RemoveService( LPCTSTR inName )
        err = translate_errno( ok, (OSStatus) GetLastError(), kDeletedErr );
        require_noerr( err, exit );
                
-       ReportStatus( EVENTLOG_SUCCESS, "Removed service \"%s\"\n", inName );
+       ReportStatus( EVENTLOG_SUCCESS, "Removed service\n" );
        err = ERROR_SUCCESS;
        
 exit:
@@ -973,7 +810,7 @@ static void ReportStatus( int inType, const char *inFormat, ... )
                        
                        vsprintf( s, inFormat, args );
                        array[ 0 ] = s;
-                       ok = ReportEventA( gServiceEventSource, (WORD) inType, 0, 0x20000001L, NULL, 1, 0, array, NULL );
+                       ok = ReportEventA( gServiceEventSource, (WORD) inType, 0, MDNSRESPONDER_LOG, NULL, 1, 0, array, NULL );
                        check_translated_errno( ok, GetLastError(), kUnknownErr );
                }
                else
@@ -1011,7 +848,7 @@ int        RunDirect( int argc, LPTSTR argv[] )
        
        // Run the service. This does not return until the service quits or is stopped.
        
-       ReportStatus( EVENTLOG_SUCCESS, "Running \"%s\" service directly\n", kServiceName );
+       ReportStatus( EVENTLOG_INFORMATION_TYPE, "Running service directly\n" );
        
        err = ServiceSpecificRun( argc, argv );
        require_noerr( err, exit );
@@ -1049,7 +886,7 @@ static void WINAPI ServiceMain( DWORD argc, LPTSTR argv[] )
        
        gServiceStatus.dwServiceType                            = SERVICE_WIN32_SHARE_PROCESS;
        gServiceStatus.dwCurrentState                           = 0;
-       gServiceStatus.dwControlsAccepted                       = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_POWEREVENT;
+       gServiceStatus.dwControlsAccepted                       = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN|SERVICE_ACCEPT_POWEREVENT;
        gServiceStatus.dwWin32ExitCode                          = NO_ERROR;
        gServiceStatus.dwServiceSpecificExitCode        = NO_ERROR;
        gServiceStatus.dwCheckPoint                             = 0;
@@ -1148,6 +985,55 @@ exit:
        return( err );
 }
 
+//===========================================================================================================================
+//     HandlePowerSuspend
+//===========================================================================================================================
+
+static void HandlePowerSuspend( void * v )
+{
+       LARGE_INTEGER   timeout;
+       BOOL                    ok;
+
+       ( void ) v;
+
+       dlog( kDebugLevelInfo, DEBUG_NAME "HandlePowerSuspend\n" );
+
+       gMDNSRecord.SystemWakeOnLANEnabled = SystemWakeForNetworkAccess( &timeout );
+                               
+       if ( gMDNSRecord.SystemWakeOnLANEnabled )
+       {
+               ok = SetWaitableTimer( gSPSWakeupEvent, &timeout, 0, NULL, NULL, TRUE );
+               check( ok );
+       }
+
+       mDNSCoreMachineSleep(&gMDNSRecord, TRUE);
+}
+
+
+//===========================================================================================================================
+//     HandlePowerResumeSuspend
+//===========================================================================================================================
+
+static void HandlePowerResumeSuspend( void * v )
+{
+       ( void ) v;
+
+       dlog( kDebugLevelInfo, DEBUG_NAME "HandlePowerResumeSuspend\n" );
+
+       if ( gSPSWakeupEvent )
+       {
+               CancelWaitableTimer( gSPSWakeupEvent );
+       }
+
+       if ( gSPSSleepEvent )
+       {
+               CancelWaitableTimer( gSPSSleepEvent );
+       }
+
+       mDNSCoreMachineSleep(&gMDNSRecord, FALSE);
+}
+
+
 //===========================================================================================================================
 //     ServiceControlHandler
 //===========================================================================================================================
@@ -1164,7 +1050,8 @@ static DWORD WINAPI       ServiceControlHandler( DWORD inControl, DWORD inEventType, L
        switch( inControl )
        {
                case SERVICE_CONTROL_STOP:
-                       dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: SERVICE_CONTROL_STOP\n" );
+               case SERVICE_CONTROL_SHUTDOWN:
+                       dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: SERVICE_CONTROL_STOP|SERVICE_CONTROL_SHUTDOWN\n" );
                        
                        ServiceStop();
                        setStatus = FALSE;
@@ -1174,43 +1061,15 @@ static DWORD WINAPI     ServiceControlHandler( DWORD inControl, DWORD inEventType, L
 
                        if (inEventType == PBT_APMSUSPEND)
                        {
-                               LARGE_INTEGER timeout;
-
                                dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: PBT_APMSUSPEND\n" );
 
-                               mDNSPlatformLock( &gMDNSRecord );
-                               
-                               gMDNSRecord.SystemWakeOnLANEnabled = SystemWakeForNetworkAccess( &timeout );
-                               
-                               if ( gMDNSRecord.SystemWakeOnLANEnabled )
-                               {
-                                       ok = SetWaitableTimer( gSPSWakeupEvent, &timeout, 0, NULL, NULL, TRUE );
-                                       check( ok );
-                               }
-
-                               mDNSPlatformUnlock( &gMDNSRecord );
-
-                               mDNSCoreMachineSleep(&gMDNSRecord, TRUE);
+                               QueueUserAPC( ( PAPCFUNC ) HandlePowerSuspend, gMDNSRecord.p->mainThread, ( ULONG_PTR ) NULL );
                        }
                        else if (inEventType == PBT_APMRESUMESUSPEND)
                        {
                                dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: PBT_APMRESUMESUSPEND\n" );
 
-                               mDNSPlatformLock( &gMDNSRecord );
-
-                               if ( gSPSWakeupEvent )
-                               {
-                                       CancelWaitableTimer( gSPSWakeupEvent );
-                               }
-
-                               if ( gSPSSleepEvent )
-                               {
-                                       CancelWaitableTimer( gSPSSleepEvent );
-                               }
-
-                               mDNSPlatformUnlock( &gMDNSRecord );
-
-                               mDNSCoreMachineSleep(&gMDNSRecord, FALSE);
+                               QueueUserAPC( ( PAPCFUNC ) HandlePowerResumeSuspend, gMDNSRecord.p->mainThread, ( ULONG_PTR ) NULL );
                        }
                
                        break;
@@ -1270,9 +1129,9 @@ static OSStatus   ServiceRun( int argc, LPTSTR argv[] )
        
        // Run the service-specific stuff. This does not return until the service quits or is stopped.
        
-       ReportStatus( EVENTLOG_INFORMATION_TYPE, "mDNSResponder started\n" );
+       ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service started\n" );
        err = ServiceSpecificRun( argc, argv );
-       ReportStatus( EVENTLOG_INFORMATION_TYPE, "mDNSResponder stopped (%d)\n", err );
+       ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service stopped (%d)\n", err );
        require_noerr( err, exit );
        
        // Service stopped. Clean up and we're done.
@@ -1328,26 +1187,15 @@ static OSStatus ServiceSpecificInitialize( int argc, LPTSTR argv[] )
        mDNSPlatformMemZero( &gMDNSRecord, sizeof gMDNSRecord);
        mDNSPlatformMemZero( &gPlatformStorage, sizeof gPlatformStorage);
 
-       gPlatformStorage.idleThreadCallback = udsIdle;
-       gPlatformStorage.hostDescriptionChangedCallback = HostDescriptionChanged;
-
-       InitializeCriticalSection(&gEventSourceLock);
-       
-       gStopEvent      =       CreateEvent(NULL, FALSE, FALSE, NULL);
-       err = translate_errno( gStopEvent, errno_compat(), kNoResourcesErr );
-       require_noerr( err, exit );
-
-       gSPSWakeupEvent = CreateWaitableTimer( NULL, FALSE, NULL );
-       err = translate_errno( gSPSWakeupEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-       gSPSSleepEvent = CreateWaitableTimer( NULL, FALSE, NULL );
-       err = translate_errno( gSPSSleepEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
+       gPlatformStorage.registerWaitableEventFunc = RegisterWaitableEvent;
+       gPlatformStorage.unregisterWaitableEventFunc = UnregisterWaitableEvent;
 
        err = mDNS_Init( &gMDNSRecord, &gPlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, CoreCallback, mDNS_Init_NoInitCallbackContext); 
        require_noerr( err, exit);
 
+       err = SetupNotifications();
+       check_noerr( err );
+
        err = udsserver_init(mDNSNULL, 0);
        require_noerr( err, exit);
 
@@ -1377,67 +1225,330 @@ exit:
 
 static OSStatus        ServiceSpecificRun( int argc, LPTSTR argv[] )
 {
-       DWORD   timeout;
-       DWORD result;
+       HANDLE  *       waitList;
+       int                     waitListCount;
+       DWORD           timeout;
+       DWORD           result;
+       BOOL            done;
+       mStatus         err;
        
        DEBUG_UNUSED( argc );
        DEBUG_UNUSED( argv );
 
-       // Main event loop. Process connection requests and state changes (i.e. quit).
-
        timeout = ( gRetryFirewall ) ? kRetryFirewallPeriod : INFINITE;
 
-       for ( ;; )
+       err = SetupInterfaceList( &gMDNSRecord );
+       check( !err );
+
+       err = uDNS_SetupDNSConfig( &gMDNSRecord );
+       check( !err );
+
+       done = FALSE;
+
+       // Main event loop.
+
+       while( !done )
        {
-               HANDLE  waitList[ 3 ];
+               waitList                = NULL;
+               waitListCount   = 0;
 
-               waitList[ 0 ] = gStopEvent;
-               waitList[ 1 ] = gSPSWakeupEvent;
-               waitList[ 2 ] = gSPSSleepEvent;
+               err = SetupWaitList( &gMDNSRecord, &waitList, &waitListCount );
+               require_noerr( err, exit );
 
-               result = WaitForMultipleObjects( 3, waitList, FALSE, timeout );
+               gEventSourceListChanged = FALSE;
 
-               if ( result == WAIT_OBJECT_0 )
+               while ( !gEventSourceListChanged )
                {
-                       break;
-               }
-               else if ( result == WAIT_OBJECT_0 + 1 )
-               {
-                       __int64                 temp;
-                       LARGE_INTEGER   timeout;
+                       static mDNSs32 RepeatedBusy = 0;        
+                       mDNSs32 nextTimerEvent;
 
-                       dlog( kDebugLevelInfo, DEBUG_NAME "setting suspend event\n" );
+                       // Give the mDNS core a chance to do its work and determine next event time.
 
-                       // Stay awake for 60 seconds
+                       nextTimerEvent = udsserver_idle( mDNS_Execute( &gMDNSRecord ) - mDNS_TimeNow( &gMDNSRecord ) );
 
-                       temp                            = -60 * 10000000;
-                       timeout.LowPart         = (DWORD) ( temp & 0xFFFFFFFF );
-                       timeout.HighPart        = (LONG)  ( temp >> 32 );
+                       if      ( nextTimerEvent < 0)                                   nextTimerEvent = 0;
+                       else if ( nextTimerEvent > (0x7FFFFFFF / 1000)) nextTimerEvent = 0x7FFFFFFF / mDNSPlatformOneSecond;
+                       else                                                                                    nextTimerEvent = ( nextTimerEvent * 1000) / mDNSPlatformOneSecond;
 
-                       SetWaitableTimer( gSPSSleepEvent, &timeout, 0, NULL, NULL, TRUE );
-               }
-               else if ( result == WAIT_OBJECT_0 + 2 )
-               {
-                       dlog( kDebugLevelInfo, DEBUG_NAME "suspending machine\n" );
-                       SetSuspendState( FALSE, FALSE, FALSE );
-               }
-               else if ( result == WAIT_TIMEOUT )
-               {
-                       OSStatus err;
+                       // Debugging sanity check, to guard against CPU spins
+                       
+                       if ( nextTimerEvent > 0 )
+                       {
+                               RepeatedBusy = 0;
+                       }
+                       else
+                       {
+                               nextTimerEvent = 1;
 
-                       err = CheckFirewall();
-                       check_noerr( err );
+                               if ( ++RepeatedBusy >= mDNSPlatformOneSecond )
+                               {
+                                       ShowTaskSchedulingError( &gMDNSRecord );
+                                       RepeatedBusy = 0;
+                               }
+                       }
+
+                       if ( gMDNSRecord.ShutdownTime )
+                       {
+                               mDNSs32 now = mDNS_TimeNow( &gMDNSRecord );
+
+                               if ( mDNS_ExitNow( &gMDNSRecord, now ) )
+                               {
+                                       mDNS_FinalExit( &gMDNSRecord );
+                                       done = TRUE;
+                                       break;
+                               }
+
+                               if ( nextTimerEvent - gMDNSRecord.ShutdownTime >= 0 )
+                               {
+                                       nextTimerEvent = gMDNSRecord.ShutdownTime;
+                               }
+                       }
+
+                       // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
+
+                       SetSocketEventsEnabled( &gMDNSRecord, TRUE );
+                       result = WaitForMultipleObjectsEx( ( DWORD ) waitListCount, waitList, FALSE, (DWORD) nextTimerEvent, TRUE );
+                       SetSocketEventsEnabled( &gMDNSRecord, FALSE );
+                       check( result != WAIT_FAILED );
+
+                       if ( result != WAIT_FAILED )
+                       {
+                               if ( result == WAIT_TIMEOUT )
+                               {
+                                       // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
+                                       
+                                       dlog( kDebugLevelChatty - 1, DEBUG_NAME "timeout\n" );
+                                       continue;
+                               }
+                               else if ( result == WAIT_IO_COMPLETION )
+                               {
+                                       dlog( kDebugLevelChatty - 1, DEBUG_NAME "i/o completion\n" );
+                                       continue;
+                               }
+                               else if ( result == kWaitListStopEvent )
+                               {
+                                       // Stop event. Set the done flag and break to exit.
+                                       
+                                       dlog( kDebugLevelVerbose, DEBUG_NAME "stopping...\n" );
+                                       udsserver_exit();
+                                       mDNS_StartExit( &gMDNSRecord );
+                                       break;
+                               }
+                               else if( result == kWaitListInterfaceListChangedEvent )
+                               {
+                                       int             inBuffer;
+                                       int             outBuffer;
+                                       DWORD   outSize;
+
+                                       // It would be nice to come up with a more elegant solution to this, but it seems that
+                                       // GetAdaptersAddresses doesn't always stay in sync after network changed events.  So as
+                                       // as a simple workaround, we'll pause for a couple of seconds before processing the change.
+
+                                       // We arrived at 2 secs by trial and error. We could reproduce the problem after sleeping
+                                       // for 500 msec and 750 msec, but couldn't after sleeping for 1 sec.  We added another
+                                       // second on top of that to account for machine load or some other exigency.
+
+                                       Sleep( 2000 );
+
+                                       // Interface list changed event. Break out of the inner loop to re-setup the wait list.
+                                       
+                                       InterfaceListDidChange( &gMDNSRecord );
+
+                                       // reset the event handler
+                                       inBuffer        = 0;
+                                       outBuffer       = 0;
+                                       err = WSAIoctl( gInterfaceListChangedSocket, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
+                                       if( err < 0 )
+                                       {
+                                               check( errno_compat() == WSAEWOULDBLOCK );
+                                       }
+                               }
+                               else if ( result == kWaitListComputerDescriptionEvent )
+                               {
+                                       // The computer description might have changed
+                                       
+                                       ComputerDescriptionDidChange( &gMDNSRecord );
+                                       udsserver_handle_configchange( &gMDNSRecord );
+
+                                       // and reset the event handler
+                                       if ( ( gDescKey != NULL ) && ( gDescChangedEvent != NULL ) )
+                                       {
+                                               err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
+                                               check_noerr( err );
+                                       }
+                               }
+                               else if ( result == kWaitListTCPIPEvent )
+                               {       
+                                       // The TCP/IP might have changed
+
+                                       TCPIPConfigDidChange( &gMDNSRecord );
+                                       udsserver_handle_configchange( &gMDNSRecord );
+
+                                       // and reset the event handler
+
+                                       if ( ( gTcpipKey != NULL ) && ( gTcpipChangedEvent ) )
+                                       {
+                                               err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE );
+                                               check_noerr( err );
+                                       }
+                               }
+                               else if ( result == kWaitListDynDNSEvent )
+                               {
+                                       // The DynDNS config might have changed
+
+                                       DynDNSConfigDidChange( &gMDNSRecord );
+                                       udsserver_handle_configchange( &gMDNSRecord );
+
+                                       // and reset the event handler
+
+                                       if ((gDdnsKey != NULL) && (gDdnsChangedEvent))
+                                       {
+                                               err = RegNotifyChangeKeyValue(gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
+                                               check_noerr( err );
+                                       }
+                               }
+                               else if ( result == kWaitListFileShareEvent )
+                               {
+                                       // File sharing changed
+
+                                       FileSharingDidChange( &gMDNSRecord );
+
+                                       // and reset the event handler
+
+                                       if ((gFileSharingKey != NULL) && (gFileSharingChangedEvent))
+                                       {
+                                               err = RegNotifyChangeKeyValue(gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
+                                               check_noerr( err );
+                                       }
+                               }
+                               else if ( result == kWaitListFirewallEvent )
+                               {
+                                       // Firewall configuration changed
+
+                                       FirewallDidChange( &gMDNSRecord );
+
+                                       // and reset the event handler
+
+                                       if ((gFirewallKey != NULL) && (gFirewallChangedEvent))
+                                       {
+                                               err = RegNotifyChangeKeyValue(gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
+                                               check_noerr( err );
+                                       }
+                               }
+                               else if ( result == kWaitListAdvertisedServicesEvent )
+                               {
+                                       // Ultimately we'll want to manage multiple services, but right now the only service
+                                       // we'll be managing is SMB.
+
+                                       FileSharingDidChange( &gMDNSRecord );
+
+                                       // and reset the event handler
+
+                                       if ( ( gAdvertisedServicesKey != NULL ) && ( gAdvertisedServicesChangedEvent ) )
+                                       {
+                                               err = RegNotifyChangeKeyValue(gAdvertisedServicesKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gAdvertisedServicesChangedEvent, TRUE);
+                                               check_noerr( err );
+                                       }
+                               }
+                               else if ( result == kWaitListSPSWakeupEvent )
+                               {
+                                       LARGE_INTEGER timeout;
 
-                       timeout = INFINITE;
+                                       ReportStatus( EVENTLOG_INFORMATION_TYPE, "Maintenance wake" );
+
+                                       timeout.QuadPart  = kSPSMaintenanceWakePeriod;
+                                       timeout.QuadPart *= kSecondsTo100NSUnits;
+
+                                       SetWaitableTimer( gSPSSleepEvent, &timeout, 0, NULL, NULL, TRUE );
+                               }
+                               else if ( result == kWaitListSPSSleepEvent )
+                               {
+                                       ReportStatus( EVENTLOG_INFORMATION_TYPE, "Returning to sleep after maintenance wake" );
+
+                                       // Calling SetSuspendState() doesn't invoke our sleep handlers, so we'll
+                                       // call HandlePowerSuspend() explicity.  This will reset the 
+                                       // maintenance wake timers.
+
+                                       HandlePowerSuspend( NULL );
+                                       SetSuspendState( FALSE, FALSE, FALSE );
+                               }
+                               else
+                               {
+                                       int waitItemIndex;
+
+                                       waitItemIndex = (int)( ( (int) result ) - WAIT_OBJECT_0 );
+                                       dlog( kDebugLevelChatty, DEBUG_NAME "waitable event on %d\n", waitItemIndex );
+                                       check( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) );
+
+                                       if ( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) )
+                                       {
+                                               HANDLE  signaledEvent;
+                                               int             n = 0;
+                                               
+                                               signaledEvent = waitList[ waitItemIndex ];
+
+                                               // If gCurrentSource is not NULL, then this routine has been called
+                                               // re-entrantly which should never happen.
+
+                                               check( !gCurrentSource );
+
+                                               for ( gCurrentSource = gEventSourceList; gCurrentSource; )
+                                               {
+                                                       EventSource * current = gCurrentSource;
+
+                                                       if ( gCurrentSource->event == signaledEvent )
+                                                       {
+                                                               gCurrentSource->handler( &gMDNSRecord, gCurrentSource->event, gCurrentSource->context );
+                                                               ++n;
+                                                               break;
+                                                       }
+
+                                                       // If the current node was removed as a result of calling
+                                                       // the handler, then gCurrentSource was already incremented to
+                                                       // the next node.  If it wasn't removed, then increment it
+                                                       // ourselves
+
+                                                       if ( gCurrentSource == current )
+                                                       {
+                                                               gCurrentSource = gCurrentSource->next;
+                                                       }
+                                               }
+
+                                               gCurrentSource = NULL;
+
+                                               check( n > 0 );
+                                       }
+                                       else
+                                       {
+                                               dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               Sleep( 3 * 1000 );
+                               
+                               err = SetupInterfaceList( &gMDNSRecord );
+                               check( !err );
+
+                               err = uDNS_SetupDNSConfig( &gMDNSRecord );
+                               check( !err );
+                               
+                               break;
+                       }
                }
-               else
+
+               if ( waitList )
                {
-                       // Unexpected wait result.
-                       dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
+                       free( waitList );
+                       waitList = NULL;
+                       waitListCount = 0;
                }
        }
 
-       return kNoErr;
+exit:
+
+       return( 0 );
 }
 
 //===========================================================================================================================
@@ -1468,42 +1579,15 @@ static void     ServiceSpecificFinalize( int argc, LPTSTR argv[] )
        //
        // clean up any open sessions
        //
-       while (gEventSources.Head)
+       while ( gEventSourceList )
        {
-               EventSourceFinalize((Win32EventSource*) gEventSources.Head);
+               UnregisterWaitableEvent( &gMDNSRecord, gEventSourceList->event );
        }
-       //
-       // give a chance for the udsserver code to clean up
-       //
-       udsserver_exit();
-
-       //
-       // and finally close down the mDNSCore
-       //
-       mDNS_Close(&gMDNSRecord);
 
        //
-       // clean up the event sources mutex...no one should be using it now
+       // clean up the notifications
        //
-       DeleteCriticalSection(&gEventSourceLock);
-
-       if ( gSPSWakeupEvent )
-       {
-               CloseHandle( gSPSWakeupEvent );
-               gSPSWakeupEvent = NULL;
-       }
-
-       if ( gSPSSleepEvent )
-       {
-               CloseHandle( gSPSSleepEvent );
-               gSPSSleepEvent = NULL;
-       }
-
-       if ( gStopEvent )
-       {
-               CloseHandle( gStopEvent );
-               gStopEvent = NULL;
-       }
+       TearDownNotifications();
 
        //
        // clean up loaded library
@@ -1519,415 +1603,573 @@ static void   ServiceSpecificFinalize( int argc, LPTSTR argv[] )
 }
 
 
-static void
-CoreCallback(mDNS * const inMDNS, mStatus status)
-{
-       if (status == mStatus_ConfigChanged)
-       {
-               SetLLRoute( inMDNS );
-       }
-}
-
+//===========================================================================================================================
+//     SetupNotifications
+//===========================================================================================================================
 
-static mDNSs32
-udsIdle(mDNS * const inMDNS, mDNSs32 interval)
+mDNSlocal mStatus      SetupNotifications()
 {
-       DEBUG_UNUSED( inMDNS );
+       mStatus                         err;
+       SocketRef                       sock;
+       unsigned long           param;
+       int                                     inBuffer;
+       int                                     outBuffer;
+       DWORD                           outSize;
+       
+       gStopEvent      =       CreateEvent(NULL, FALSE, FALSE, NULL);
+       err = translate_errno( gStopEvent, errno_compat(), kNoResourcesErr );
+       require_noerr( err, exit );
 
-       //
-       // rdar://problem/3697326
-       //
-       // udsserver_idle wasn't being locked.  This resulted
-       // in multiple threads contesting for the all_requests
-       // data structure in uds_daemon.c
-       //
-       mDNSPlatformLock(&gMDNSRecord);
+       // Register to listen for address list changes.
+       
+       gInterfaceListChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+       err = translate_errno( gInterfaceListChangedEvent, (mStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
 
-       interval = udsserver_idle(interval);
+       sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
+       err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
+       require_noerr( err, exit );
+       gInterfaceListChangedSocket = sock;
+       
+       // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event 
+       // when a change to the interface list is detected.
+       
+       param = 1;
+       err = ioctlsocket( sock, FIONBIO, &param );
+       err = translate_errno( err == 0, errno_compat(), kUnknownErr );
+       require_noerr( err, exit );
+       
+       inBuffer        = 0;
+       outBuffer       = 0;
+       err = WSAIoctl( sock, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
+       if( err < 0 )
+       {
+               check( errno_compat() == WSAEWOULDBLOCK );
+       }
+       
+       err = WSAEventSelect( sock, gInterfaceListChangedEvent, FD_ADDRESS_LIST_CHANGE );
+       err = translate_errno( err == 0, errno_compat(), kUnknownErr );
+       require_noerr( err, exit );
 
-       mDNSPlatformUnlock(&gMDNSRecord);
+       gDescChangedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+       err = translate_errno( gDescChangedEvent, (mStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
 
-       return interval;
-}
+       err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters"), 0, KEY_READ, &gDescKey);
+       check_translated_errno( err == 0, errno_compat(), kNameErr );
 
+       if ( gDescKey != NULL )
+       {
+               err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
+               require_noerr( err, exit );
+       }
 
-static void
-HostDescriptionChanged(mDNS * const inMDNS)
-{
-       DEBUG_UNUSED( inMDNS );
+       // This will catch all changes to tcp/ip networking, including changes to the domain search list
 
-       udsserver_handle_configchange(inMDNS);
-}
+       gTcpipChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+       err = translate_errno( gTcpipChangedEvent, (mStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
 
+       err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &gTcpipKey );
+       require_noerr( err, exit );
 
-mDNSlocal unsigned WINAPI
-udsSocketThread(LPVOID inParam)
-{
-       Win32EventSource        *       source          =       (Win32EventSource*) inParam;
-       DWORD                                   threadID        =       GetCurrentThreadId();
-       DWORD                                   waitCount;
-       HANDLE                                  waitList[2];
-       bool                                    safeToClose;
-       bool                                    done;
-       bool                                    locked          = false;
-       mStatus                                 err                     = 0;
+       err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE);
+       require_noerr( err, exit );
 
-       waitCount       = source->waitCount;
-       waitList[0] = source->waitList[0];
-       waitList[1] = source->waitList[1];
-       done            = (bool) (source->flags & EventSourceFinalized);
+       // This will catch all changes to ddns configuration
 
-       while (!done)
-       {
-               DWORD result;
+       gDdnsChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+       err = translate_errno( gDdnsChangedEvent, (mStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
 
-               result = WaitForMultipleObjects(waitCount, waitList, FALSE, INFINITE);
-               
-               mDNSPlatformLock(&gMDNSRecord);
-               locked = true;
+       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup"), &gDdnsKey );
+       require_noerr( err, exit );
 
-               // <rdar://problem/3838237>
-               //
-               // Look up the source by the thread id.  This will ensure that the 
-               // source is still extant.  It could already have been deleted
-               // by the processing thread.
-               //
+       err = RegNotifyChangeKeyValue( gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
+       require_noerr( err, exit );
 
-               EventSourceLock();
+       // This will catch all changes to file sharing
 
-               for (source = gEventSources.Head; source; source = source->next)
-               {
-                       if (source->threadID == threadID)
-                       {
-                               break;
-                       }
-               }
+       gFileSharingChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+       err = translate_errno( gFileSharingChangedEvent, (mStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
 
-               EventSourceUnlock();
-               
-               if (source == NULL)
-               {
-                       goto exit;
-               }
+       err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\Shares"), &gFileSharingKey );
+       
+       // Just to make sure that initialization doesn't fail on some old OS
+       // that doesn't have this key, we'll only add the notification if
+       // the key exists.
 
-               //
-               // socket event
-               //
-               if (result == WAIT_OBJECT_0)
-               {
-                       source->callback( (int) source->sock, 0, source->context);
-               }
-               //
-               // close event
-               //
-               else if (result == WAIT_OBJECT_0 + 1)
-               {
-                       //
-                       // this is a bit of a hack.  we want to clean up the internal data structures
-                       // so we'll go in here and it will clean up for us
-                       //
-                       shutdown(source->sock, 2);
-                       source->callback( (int) source->sock, 0, source->context);
+       if ( !err )
+       {
+               err = RegNotifyChangeKeyValue( gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
+               require_noerr( err, exit );
+       }
+       else
+       {
+               err = mStatus_NoError;
+       }
 
-                       break;
-               }
-               else
-               {
-                       // Unexpected wait result.
-                       dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
-                       goto exit;
-               }
+       // This will catch changes to the Windows firewall
 
-               done   = (bool) (source->flags & EventSourceFinalized);
-               
-               mDNSPlatformUnlock(&gMDNSRecord);
-               locked = false;
-       }
+       gFirewallChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+       err = translate_errno( gFirewallChangedEvent, (mStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
 
-       EventSourceLock();
-       source->flags |= EventSourceFlagsThreadDone;
-       safeToClose = !( source->flags & EventSourceFlagsNoClose );
-       EventSourceUnlock();
+       // Just to make sure that initialization doesn't fail on some old OS
+       // that doesn't have this key, we'll only add the notification if
+       // the key exists.
 
-       if( safeToClose )
+       err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\FirewallRules"), &gFirewallKey );
+       
+       if ( !err )
        {
-               EventSourceFinalize( source );
+               err = RegNotifyChangeKeyValue( gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
+               require_noerr( err, exit );
        }
-
-exit:
-
-       if ( locked )
+       else
        {
-               mDNSPlatformUnlock(&gMDNSRecord);
+               err = mStatus_NoError;
        }
 
-       _endthreadex_compat( (unsigned) err );
-       return( (unsigned) err );       
-}
-
+       // This will catch all changes to advertised services configuration
 
-mStatus
-udsSupportAddFDToEventLoop( SocketRef fd, udsEventCallback callback, void *context)
-{
-       Win32EventSource *  newSource;
-       DWORD                           result;
-       mStatus                         err;
+       gAdvertisedServicesChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+       err = translate_errno( gAdvertisedServicesChangedEvent, (mStatus) GetLastError(), kUnknownErr );
+       require_noerr( err, exit );
 
-       newSource = malloc(sizeof(Win32EventSource));
-       require_action( newSource, exit, err = mStatus_NoMemoryErr );
-       mDNSPlatformMemZero(newSource, sizeof(Win32EventSource));
+       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\Services"), &gAdvertisedServicesKey );
+       require_noerr( err, exit );
 
-       newSource->flags        = 0;
-       newSource->sock         = (SOCKET) fd;
-       newSource->callback     = callback;
-       newSource->context      = context;
+       err = RegNotifyChangeKeyValue( gAdvertisedServicesKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gAdvertisedServicesChangedEvent, TRUE);
+       require_noerr( err, exit );
 
-       newSource->socketEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-       err = translate_errno( newSource->socketEvent, (mStatus) GetLastError(), kUnknownErr );
+       gSPSWakeupEvent = CreateWaitableTimer( NULL, FALSE, NULL );
+       err = translate_errno( gSPSWakeupEvent, (mStatus) GetLastError(), kUnknownErr );
        require_noerr( err, exit );
 
-       newSource->closeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-       err = translate_errno( newSource->closeEvent, (mStatus) GetLastError(), kUnknownErr );
+       gSPSSleepEvent = CreateWaitableTimer( NULL, FALSE, NULL );
+       err = translate_errno( gSPSSleepEvent, (mStatus) GetLastError(), kUnknownErr );
        require_noerr( err, exit );
 
-       err = WSAEventSelect(newSource->sock, newSource->socketEvent, FD_ACCEPT|FD_READ|FD_CLOSE);
-       err = translate_errno( err == 0, errno_compat(), kNoResourcesErr );
+       gUDSEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+       err = translate_errno( gUDSEvent, ( mStatus ) GetLastError(), kUnknownErr );
        require_noerr( err, exit );
 
-       newSource->waitCount = 0;
-       newSource->waitList[ newSource->waitCount++ ] = newSource->socketEvent;
-       newSource->waitList[ newSource->waitCount++ ] = newSource->closeEvent;
+exit:
+       if( err )
+       {
+               TearDownNotifications();
+       }
+       return( err );
+}
 
-       //
-       // lock the list
-       //
-       EventSourceLock();
-       
-       // add the event source to the end of the list, while checking
-       // to see if the list needs to be initialized
-       //
-       if ( gEventSources.LinkOffset == 0)
+//===========================================================================================================================
+//     TearDownNotifications
+//===========================================================================================================================
+
+mDNSlocal mStatus      TearDownNotifications()
+{
+       if ( gStopEvent )
        {
-               InitLinkedList( &gEventSources, offsetof( Win32EventSource, next));
+               CloseHandle( gStopEvent );
+               gStopEvent = NULL;
        }
 
-       AddToTail( &gEventSources, newSource);
+       if( IsValidSocket( gInterfaceListChangedSocket ) )
+       {
+               close_compat( gInterfaceListChangedSocket );
+               gInterfaceListChangedSocket = kInvalidSocketRef;
+       }
 
-       //
-       // no longer using the list
-       //
-       EventSourceUnlock();
+       if( gInterfaceListChangedEvent )
+       {
+               CloseHandle( gInterfaceListChangedEvent );
+               gInterfaceListChangedEvent = 0;
+       }
 
-       // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time 
-       // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
-       // Create the thread suspended then resume it so the thread handle and ID are valid before the thread starts running.
-       newSource->threadHandle = (HANDLE) _beginthreadex_compat( NULL, 0, udsSocketThread, newSource, CREATE_SUSPENDED, &newSource->threadID );
-       err = translate_errno( newSource->threadHandle, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
+       if ( gDescChangedEvent != NULL )
+       {
+               CloseHandle( gDescChangedEvent );
+               gDescChangedEvent = NULL;
+       }
 
-       result = ResumeThread( newSource->threadHandle );
-       err = translate_errno( result != (DWORD) -1, errno_compat(), kNoResourcesErr );
-       require_noerr( err, exit );
+       if ( gDescKey != NULL )
+       {
+               RegCloseKey( gDescKey );
+               gDescKey = NULL;
+       }
 
-exit:
+       if ( gTcpipChangedEvent != NULL )
+       {
+               CloseHandle( gTcpipChangedEvent );
+               gTcpipChangedEvent = NULL;
+       }
 
-       if (err && newSource)
+       if ( gDdnsChangedEvent != NULL )
        {
-               EventSourceFinalize(newSource);
+               CloseHandle( gDdnsChangedEvent );
+               gDdnsChangedEvent = NULL;
        }
 
-       return err;
-}
+       if ( gDdnsKey != NULL )
+       {
+               RegCloseKey( gDdnsKey );
+               gDdnsKey = NULL;
+       }
 
+       if ( gFileSharingChangedEvent != NULL )
+       {
+               CloseHandle( gFileSharingChangedEvent );
+               gFileSharingChangedEvent = NULL;
+       }
 
-mStatus
-udsSupportRemoveFDFromEventLoop( SocketRef fd)         // Note: This also CLOSES the socket
-{
-       Win32EventSource        *       source;
-       mStatus                                 err = mStatus_NoError;
-       
-       //
-       // find the event source
-       //
-       EventSourceLock();
+       if ( gFileSharingKey != NULL )
+       {
+               RegCloseKey( gFileSharingKey );
+               gFileSharingKey = NULL;
+       }
 
-       for (source = gEventSources.Head; source; source = source->next)
+       if ( gFirewallChangedEvent != NULL )
        {
-               if (source->sock == (SOCKET) fd)
-               {
-                       break;
-               }
+               CloseHandle( gFirewallChangedEvent );
+               gFirewallChangedEvent = NULL;
        }
 
-       //
-       // if we found him, finalize him
-       //
-       if (source != NULL)
+       if ( gFirewallKey != NULL )
        {
-               EventSourceFinalize(source);
+               RegCloseKey( gFirewallKey );
+               gFirewallKey = NULL;
        }
 
-       //
-       // done with the list
-       //
-       EventSourceUnlock();
-       
-       closesocket(fd);
+       if ( gAdvertisedServicesChangedEvent != NULL )
+       {
+               CloseHandle( gAdvertisedServicesChangedEvent );
+               gAdvertisedServicesChangedEvent = NULL;
+       }
 
-       return err;
-}
+       if ( gAdvertisedServicesKey != NULL )
+       {
+               RegCloseKey( gAdvertisedServicesKey );
+               gAdvertisedServicesKey = NULL;
+       }
 
+       if ( gSPSWakeupEvent )
+       {
+               CloseHandle( gSPSWakeupEvent );
+               gSPSWakeupEvent = NULL;
+       }
 
-mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
+       if ( gSPSSleepEvent )
        {
-       (void)m;
-       (void)delay;
-       // No-op, for now
+               CloseHandle( gSPSSleepEvent );
+               gSPSSleepEvent = NULL;
        }
 
+       return( mStatus_NoError );
+}
+
+
+//===========================================================================================================================
+//     RegisterWaitableEvent
+//===========================================================================================================================
 
-static mStatus
-EventSourceFinalize(Win32EventSource * source)
+static mStatus RegisterWaitableEvent( mDNS * const inMDNS, HANDLE event, void * context, RegisterWaitableEventHandler handler )
 {
-       OSStatus                                err;
-       bool                                    locked;
-       Win32EventSource        *       inserted;
-       bool                            sameThread;
-       bool                            deferClose;
-       BOOL                            ok;
-       DWORD                           threadID;
-       DWORD                           result;
-       
-       check( source );
-       
-       // Find the session in the list.
-       
-       EventSourceLock();
-       locked = true;
-       
-       for( inserted = (Win32EventSource*) gEventSources.Head; inserted; inserted = inserted->next )
+       EventSource * source;
+       mStatus err = mStatus_NoError;
+
+       ( void ) inMDNS;
+       check( event );
+       check( handler );
+
+       source = ( EventSource* ) malloc( sizeof( EventSource ) );
+       require_action( source, exit, err = mStatus_NoMemoryErr );
+       mDNSPlatformMemZero( source, sizeof( EventSource ) );
+       source->event = event;
+       source->context = context;
+       source->handler = handler;
+
+       source->next                    = gEventSourceList;
+       gEventSourceList                = source;
+       gEventSourceListChanged = TRUE;
+       gEventSources++;
+
+exit:
+
+       return err;
+}
+
+
+//===========================================================================================================================
+//     UnregisterWaitableEvent
+//===========================================================================================================================
+
+static void UnregisterWaitableEvent( mDNS * const inMDNS, HANDLE event )
+{
+       EventSource     *       current = gEventSourceList;
+       EventSource     *       last    = NULL;
+
+       ( void ) inMDNS;
+       check( event );
+
+       while ( current )
        {
-               if( inserted == source )
+               if ( current->event == event )
                {
+                       if ( last == NULL )
+                       {
+                               gEventSourceList = current->next;
+                       }
+                       else
+                       {
+                               last->next = current->next;
+                       }
+
+                       gEventSourceListChanged = TRUE;
+
+                       // Protect against removing the node that we happen
+                       // to be looking at as we iterate through the event
+                       // source list in ServiceSpecificRun()
+
+                       if ( current == gCurrentSource )
+                       {
+                               gCurrentSource = current->next;
+                       }
+
+                       gEventSources--;
+                       free( current );
+
                        break;
                }
+
+               last    = current;
+               current = current->next;
        }
-       require_action( inserted, exit, err = kNotFoundErr );
+}
 
-       //
-       // note that we've had finalize called
-       //
-       source->flags |= EventSourceFinalized;
+
+//===========================================================================================================================
+//     SetupWaitList
+//===========================================================================================================================
+
+mDNSlocal mStatus SetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount )
+{
+       int                             waitListCount;
+       HANDLE          *       waitList;
+       HANDLE          *       waitItemPtr;
+       EventSource     *       source;
+       mStatus                 err;
        
-       // If we're being called from the same thread as the session (e.g. message callback is closing the session) then 
-       // we must defer the close until the thread is done because the thread is still using the session object.
+       dlog( kDebugLevelTrace, DEBUG_NAME "setting up wait list\n" );
        
-       deferClose      = false;
-       threadID        = GetCurrentThreadId();
-       sameThread      = source->threadHandle && ( threadID == source->threadID );
-       if( sameThread && !( source->flags & EventSourceFlagsThreadDone ) )
-       {
-               source->flags &= ~EventSourceFlagsNoClose;
-               deferClose = true;
-       }
+       ( void ) inMDNS;
+       check( inMDNS->p );
+       check( outWaitList );
+       check( outWaitListCount );
        
-       // If the thread we're not being called from the session thread, but the thread has already marked itself as
-       // as done (e.g. session closed from something like a peer disconnect and at the same time the client also 
-       // tried to close) then we only want to continue with the close if the thread is not going to close itself.
+       // Allocate an array to hold all the objects to wait on.
        
-       if( !sameThread && ( source->flags & EventSourceFlagsThreadDone ) && !( source->flags & EventSourceFlagsNoClose ) )
-       {
-               deferClose = true;
-       }
+       waitListCount = kWaitListFixedItemCount + gEventSources;
+       waitList = ( HANDLE* ) malloc( waitListCount * sizeof( *waitList ) );
+       require_action( waitList, exit, err = mStatus_NoMemoryErr );
+       waitItemPtr = waitList;
        
-       // Signal a close so the thread exits.
+       // Add the fixed wait items to the beginning of the list.
        
-       if( source->closeEvent )
-       {
-               ok = SetEvent( source->closeEvent );
-               check_translated_errno( ok, errno_compat(), kUnknownErr );
-       }       
-       if( deferClose )
+       *waitItemPtr++  =       gStopEvent;
+       *waitItemPtr++  =       gInterfaceListChangedEvent;
+       *waitItemPtr++  =       gDescChangedEvent;
+       *waitItemPtr++  =       gTcpipChangedEvent;
+       *waitItemPtr++  =       gDdnsChangedEvent;
+       *waitItemPtr++  =       gFileSharingChangedEvent;
+       *waitItemPtr++  =       gFirewallChangedEvent;
+       *waitItemPtr++  =       gAdvertisedServicesChangedEvent;
+       *waitItemPtr++  =       gSPSWakeupEvent;
+       *waitItemPtr++  =       gSPSSleepEvent;
+
+       for ( source = gEventSourceList; source; source = source->next )
        {
-               err = kNoErr;
-               goto exit;
+               *waitItemPtr++ = source->event;
        }
+
+       check( ( int )( waitItemPtr - waitList ) == waitListCount );
        
-       source->flags |= EventSourceFlagsNoClose;
-       
-       // Remove the session from the list.
-       RemoveFromList(&gEventSources, source);
-       
-       EventSourceUnlock();
-       locked = false;
-       
-       // Wait for the thread to exit. Give up after 3 seconds to handle a hung thread.
+       *outWaitList            = waitList;
+       *outWaitListCount       = waitListCount;
+       waitList                        = NULL;
+       err                                     = mStatus_NoError;
        
-       if( source->threadHandle && ( threadID != source->threadID ) )
+exit:
+
+       if( waitList )
        {
-               result = WaitForSingleObject( source->threadHandle, 3 * 1000 );
-               check_translated_errno( result == WAIT_OBJECT_0, (OSStatus) GetLastError(), result );
+               free( waitList );
        }
-       
-       // Release the thread.
-       
-       if( source->threadHandle )
+
+       dlog( kDebugLevelTrace, DEBUG_NAME "setting up wait list done (err=%d %m)\n", err, err );
+       return( err );
+}
+
+
+//===========================================================================================================================
+//     CoreCallback
+//===========================================================================================================================
+
+static void
+CoreCallback(mDNS * const inMDNS, mStatus status)
+{
+       if (status == mStatus_ConfigChanged)
        {
-               ok = CloseHandle( source->threadHandle );
-               check_translated_errno( ok, errno_compat(), kUnknownErr );
-               source->threadHandle = NULL;
+               SetLLRoute( inMDNS );
        }
+}
+
+
+//===========================================================================================================================
+//     UDSCanAccept
+//===========================================================================================================================
+
+mDNSlocal void UDSCanAccept( mDNS * const inMDNS, HANDLE event, void * context )
+{
+       ( void ) inMDNS;
+       ( void ) event;
        
-       // Release the socket event.
-       
-       if( source->socketEvent )
+       if ( gUDSCallback )
        {
-               ok = CloseHandle( source->socketEvent );
-               check_translated_errno( ok, errno_compat(), kUnknownErr );
-               source->socketEvent = NULL;
+               gUDSCallback( ( int ) gUDSSocket, 0, context );
        }
-       
-       // Release the close event.
-       
-       if( source->closeEvent )
+}
+
+
+//===========================================================================================================================
+//     UDSCanRead
+//===========================================================================================================================
+
+mDNSlocal void UDSCanRead( TCPSocket * sock )
+{
+       udsEventCallback callback = ( udsEventCallback ) sock->userCallback;
+
+       if ( callback )
        {
-               ok = CloseHandle( source->closeEvent );
-               check_translated_errno( ok, errno_compat(), kUnknownErr );
-               source->closeEvent = NULL;
+               callback( (int) sock->fd, 0, sock->userContext );
        }
-       
-       // Release the memory used by the object.
-       free ( source );
+}
 
-       err = kNoErr;
-       
-       dlog( kDebugLevelNotice, DEBUG_NAME "session closed\n" );
-       
-exit:
 
-       if( locked )
+//===========================================================================================================================
+//     udsSupportAddFDToEventLoop
+//===========================================================================================================================
+
+mStatus
+udsSupportAddFDToEventLoop( SocketRef fd, udsEventCallback callback, void *context, void **platform_data)
+{
+       mStatus err = mStatus_NoError;
+
+       // We are using some knowledge of what is being passed to us here.  If the fd is a listen socket,
+       // then the "callback" parameter is NULL.  If it is an actual read/write socket, then the "callback"
+       // parameter is not null. This is important because we use waitable events for the listen socket
+       // and alertable I/O for the read/write sockets.
+
+       if ( context )
        {
-               EventSourceUnlock();
+               TCPSocket * sock;
+
+               sock = malloc( sizeof( TCPSocket ) );
+               require_action( sock, exit, err = mStatus_NoMemoryErr );
+               mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
+
+               sock->fd                                = (SOCKET) fd;
+               sock->readEventHandler  = UDSCanRead;
+               sock->userCallback              = callback;
+               sock->userContext               = context;
+               sock->m                                 = &gMDNSRecord;
+
+               err = TCPAddSocket( sock->m, sock );
+               require_noerr( err, exit );
+
+               *platform_data = sock;
+       }
+       else
+       {
+               gUDSSocket              = fd;
+               gUDSCallback    = callback;
+               gUDSEvent               = CreateEvent( NULL, FALSE, FALSE, NULL );
+               err = translate_errno( gUDSEvent, (mStatus) GetLastError(), kUnknownErr );
+               require_noerr( err, exit ); 
+               err = WSAEventSelect( fd, gUDSEvent, FD_ACCEPT | FD_CLOSE );
+               err = translate_errno( err == 0, WSAGetLastError(), kNoResourcesErr );
+               require_noerr( err, exit );
+               err = RegisterWaitableEvent( &gMDNSRecord, gUDSEvent, context, UDSCanAccept );
+               require_noerr( err, exit );
        }
 
-       return( err );
+exit:
+
+       return err;
 }
 
 
-static void
-EventSourceLock()
+int
+udsSupportReadFD( SocketRef fd, char *buf, int len, int flags, void *platform_data )
 {
-       EnterCriticalSection(&gEventSourceLock);
+       TCPSocket       *       sock;
+       mDNSBool                closed;
+       int                             ret;
+
+       ( void ) flags;
+
+       sock = ( TCPSocket* ) platform_data;
+       require_action( sock, exit, ret = -1 );
+       require_action( sock->fd == fd, exit, ret = -1 );
+
+       ret = mDNSPlatformReadTCP( sock, buf, len, &closed );
+
+       if ( closed )
+       {
+               ret = 0;
+       }
+
+exit:
+
+       return ret;
 }
 
 
-static void
-EventSourceUnlock()
+mStatus
+udsSupportRemoveFDFromEventLoop( SocketRef fd, void *platform_data)            // Note: This also CLOSES the socket
 {
-       LeaveCriticalSection(&gEventSourceLock);
+       mStatus err = kNoErr;
+
+       if ( platform_data != NULL )
+       {
+               TCPSocket * sock;
+
+               dlog( kDebugLevelInfo, DEBUG_NAME "session closed\n" );
+               sock = ( TCPSocket* ) platform_data;
+               check( sock->fd == fd );
+               mDNSPlatformTCPCloseConnection( sock );
+       }
+       else if ( gUDSEvent != NULL )
+       {
+               UnregisterWaitableEvent( &gMDNSRecord, gUDSEvent );
+               WSAEventSelect( fd, gUDSEvent, 0 );
+               CloseHandle( gUDSEvent );
+               gUDSEvent = NULL;
+       }
+
+       return err;
 }
 
 
+mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
+       {
+       (void)m;
+       (void)delay;
+       // No-op, for now
+       }
+
+
 //===========================================================================================================================
 //     SystemWakeForNetworkAccess
 //===========================================================================================================================
@@ -1942,8 +2184,7 @@ SystemWakeForNetworkAccess( LARGE_INTEGER * timeout )
        SYSTEM_POWER_STATUS             powerStatus;
        time_t                                  startTime;
        time_t                                  nextWakeupTime;
-       time_t                                  delta;
-       __int64                                 delta64;
+       int                                             delta;
        DWORD                                   err;
 
        dlog( kDebugLevelInfo, DEBUG_NAME "SystemWakeForNetworkAccess\n" );
@@ -1970,13 +2211,20 @@ SystemWakeForNetworkAccess( LARGE_INTEGER * timeout )
 
        // Now make sure we have a network interface that does wake-on-lan
 
-       UpdateWOMPConfig( &gMDNSRecord );
-       require_action( gMDNSRecord.p->womp, exit, ok = FALSE );
+       ok = ( mDNSu8 ) IsWOMPEnabled( &gMDNSRecord );
+       require_action( ok, exit, ok = FALSE );
+
+       // Now make sure we have advertised services. Doesn't make sense to
+       // enable sleep proxy if we have no multicast services that could
+       // potentially wake us up.
+
+       ok = ( mDNSu8 ) mDNSCoreHaveAdvertisedMulticastServices( &gMDNSRecord );
+       require_action( ok, exit, ok = FALSE );
 
        // Calculate next wake up time
 
-       startTime               = time( NULL );
-       nextWakeupTime  = startTime + ( 120 * 60 );
+       startTime               = time( NULL );                                 // Seconds since midnight January 1, 1970
+       nextWakeupTime  = startTime + ( 120 * 60 );             // 2 hours later
        
        if ( gMDNSRecord.p->nextDHCPLeaseExpires < nextWakeupTime )
        {
@@ -1985,12 +2233,13 @@ SystemWakeForNetworkAccess( LARGE_INTEGER * timeout )
 
        // Finally calculate the next relative wakeup time
 
-       delta = ( time_t ) ( ( ( double )( nextWakeupTime - startTime ) ) * 0.9 );
-       delta64 = -delta * 10000000;
-       timeout->LowPart  = (DWORD) ( delta64 & 0xFFFFFFFF );
-       timeout->HighPart = (LONG)  ( delta64 >> 32 );
+       delta = ( int )( ( ( double )( nextWakeupTime - startTime ) ) * 0.9 );
+       ReportStatus( EVENTLOG_INFORMATION_TYPE, "enabling sleep proxy client with next maintenance wake in %d seconds", delta );
+
+       // Convert seconds to 100 nanosecond units expected by SetWaitableTimer
 
-       dlog( kDebugLevelInfo, DEBUG_NAME "enabling sleep proxy client with next wakeup time %d seconds from now\n", delta );
+       timeout->QuadPart  = -delta;
+       timeout->QuadPart *= kSecondsTo100NSUnits;
 
        ok = TRUE;
 
index 438c1c4e62eed32431ee688f90f92c918254e1a3..0b806f002b6f24e7c728cecdd3fb85dbb4e4443a 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: Service.h,v $
-Revision 1.1  2009/07/09 21:34:15  herscher
-<rdar://problem/3775717> SDK: Port mDNSNetMonitor to Windows. Refactor the system service slightly by removing the main() function from Service.c so that mDNSNetMonitor can link to functions defined in Service.c
-
-
  */
 
 #ifndef        __MDNS_SERVICE_H__
index 41c42735a789533474d510c5ab356ab68501389c..60ad48472d22d497dcb54046886c16a9f629291c 100644 (file)
@@ -9,6 +9,7 @@
 //
 #include "winres.h"
 #include "WinVersRes.h"
+#include "EventLog.rc"
 /////////////////////////////////////////////////////////////////////////////
 #undef APSTUDIO_READONLY_SYMBOLS
 
index c30cca8d090b31d58f63a85b47a87baf18467904..7461028b1516bba6efbb05bed05612ad26a5cac3 100644 (file)
@@ -4,6 +4,7 @@
        Version="8.00"\r
        Name="mDNSResponder"\r
        ProjectGUID="{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}"\r
+       RootNamespace="mDNSResponder"\r
        Keyword="Win32Proj"\r
        >\r
        <Platforms>\r
                        <Tool\r
                                Name="VCLinkerTool"\r
                                AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
-                               AdditionalDependencies="ws2_32.lib iphlpapi.lib crypt32.lib netapi32.lib"\r
+                               AdditionalDependencies="ws2_32.lib iphlpapi.lib crypt32.lib netapi32.lib powrprof.lib"\r
                                OutputFile="$(OutDir)/mDNSResponder.exe"\r
                                LinkIncremental="2"\r
                                IgnoreAllDefaultLibraries="false"\r
                                WarningLevel="4"\r
                                Detect64BitPortabilityProblems="true"\r
                                DebugInformationFormat="3"\r
+                               CallingConvention="2"\r
                                DisableSpecificWarnings="4127;4201"\r
                        />\r
                        <Tool\r
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                  &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\AppleInternal&quot;                                                   mkdir &quot;$(DSTROOT)\AppleInternal&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\AppleInternal\bin&quot;                                            mkdir &quot;$(DSTROOT)\AppleInternal\bin&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                           &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetDir)$(TargetName).pdb&quot;                                          &quot;$(DSTROOT)\AppleInternal\bin&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
                <Configuration\r
                        />\r
                        <Tool\r
                                Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                  &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
+                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\AppleInternal&quot;                                                   mkdir &quot;$(DSTROOT)\AppleInternal&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\AppleInternal\bin&quot;                                            mkdir &quot;$(DSTROOT)\AppleInternal\bin&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                           &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetDir)$(TargetName).pdb&quot;                                          &quot;$(DSTROOT)\AppleInternal\bin&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
                        />\r
                </Configuration>\r
        </Configurations>\r
                                RelativePath="..\..\mDNSShared\dnssd_ipc.c"\r
                                >\r
                        </File>\r
+                       <File\r
+                               RelativePath=".\EventLog.mc"\r
+                               >\r
+                               <FileConfiguration\r
+                                       Name="Debug|Win32"\r
+                                       >\r
+                                       <Tool\r
+                                               Name="VCCustomBuildTool"\r
+                                               Description="Compiling Message Resource"\r
+                                               CommandLine="mc.exe EventLog.mc"\r
+                                               Outputs="EventLog.rc EventLog.h"\r
+                                       />\r
+                               </FileConfiguration>\r
+                               <FileConfiguration\r
+                                       Name="Debug|x64"\r
+                                       >\r
+                                       <Tool\r
+                                               Name="VCCustomBuildTool"\r
+                                               Description="Compiling Message Resource"\r
+                                               CommandLine="mc.exe EventLog.mc"\r
+                                               Outputs="EventLog.rc EventLog.h"\r
+                                       />\r
+                               </FileConfiguration>\r
+                               <FileConfiguration\r
+                                       Name="Release|Win32"\r
+                                       >\r
+                                       <Tool\r
+                                               Name="VCCustomBuildTool"\r
+                                               Description="Compiling Message Resource"\r
+                                               CommandLine="mc.exe EventLog.mc"\r
+                                               Outputs="EventLog.rc EventLog.h"\r
+                                       />\r
+                               </FileConfiguration>\r
+                               <FileConfiguration\r
+                                       Name="Release|x64"\r
+                                       >\r
+                                       <Tool\r
+                                               Name="VCCustomBuildTool"\r
+                                               Description="Compiling Message Resource"\r
+                                               CommandLine="mc.exe EventLog.mc"\r
+                                               Outputs="EventLog.rc EventLog.h"\r
+                                       />\r
+                               </FileConfiguration>\r
+                       </File>\r
                        <File\r
                                RelativePath="Firewall.cpp"\r
                                >\r
index 40c53b8acd08fb3734abbe1f751da68976835942..33cce9eae4968bd87610c6b4adcf75eb6db4a973 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: main.c,v $
-Revision 1.1  2009/07/09 21:34:15  herscher
-<rdar://problem/3775717> SDK: Port mDNSNetMonitor to Windows. Refactor the system service slightly by removing the main() function from Service.c so that mDNSNetMonitor can link to functions defined in Service.c
-
-
  */
 
 #include "Service.h"
index c0f4d01c4fdc0d600169f7ed280287f8a9063c5d..3df7c141ccadbabc2666f458d5356ca196811f81 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: VPCDetect.cpp,v $
-Revision 1.3  2006/08/14 23:25:20  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2006/02/26 19:31:05  herscher
-<rdar://problem/4455038> Bonjour For Windows takes 90 seconds to start. This was caused by a bad interaction between the VirtualPC check, and the removal of the WMI dependency.  The problem was fixed by: 1) checking to see if WMI is running before trying to talk to it.  2) Retrying the VirtualPC check every 10 seconds upon failure, stopping after 10 unsuccessful tries.
-
-Revision 1.1  2005/11/27 20:21:16  herscher
-<rdar://problem/4210580> Workaround Virtual PC bug that incorrectly modifies incoming mDNS packets
-
-*/
+ */
 
 #define _WIN32_DCOM
 #include "VPCDetect.h"
index 0b7ce19efb48c1ca8b0e268545aedac31d045fea..9f34beeec9e9bf80694d610310eeb26dc4956401 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: VPCDetect.h,v $
-Revision 1.3  2006/08/14 23:25:20  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.2  2006/02/26 19:31:05  herscher
-<rdar://problem/4455038> Bonjour For Windows takes 90 seconds to start. This was caused by a bad interaction between the VirtualPC check, and the removal of the WMI dependency.  The problem was fixed by: 1) checking to see if WMI is running before trying to talk to it.  2) Retrying the VirtualPC check every 10 seconds upon failure, stopping after 10 unsuccessful tries.
-
-Revision 1.1  2005/11/27 20:21:16  herscher
-<rdar://problem/4210580> Workaround Virtual PC bug that incorrectly modifies incoming mDNS packets
-
-*/
+ */
 
 #pragma once
 
index b3b5551a94e996fef6efdca691ccc09ccc7abff9..e47c46889ef0eba1afc49a632c002ceba2ccbf97 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: WinServices.cpp,v $
-Revision 1.3  2009/06/22 23:25:04  herscher
-<rdar://problem/5265747> ControlPanel doesn't display key and password in dialog box. Refactor Lsa calls into Secret.h and Secret.c, which is used by both the ControlPanel and mDNSResponder system service.
-
-Revision 1.2  2006/08/14 23:25:20  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.1  2004/06/18 05:23:33  rpantos
-First checked in
-
-
-*/
+ */
 
 #include "WinServices.h"
 #include <DebugServices.h>
index 8909cd1a4472d94572b64ffce11cbca8a504c687..f650d1d39e240514c41ffcae853d010a218dbb4f 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: WinServices.h,v $
-Revision 1.3  2009/06/22 23:25:05  herscher
-<rdar://problem/5265747> ControlPanel doesn't display key and password in dialog box. Refactor Lsa calls into Secret.h and Secret.c, which is used by both the ControlPanel and mDNSResponder system service.
-
-Revision 1.2  2006/08/14 23:25:21  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.1  2004/06/18 05:23:33  rpantos
-First checked in
-
-
-*/
+ */
 
 
 #pragma once
index a46a002be77a2c90143efee4f8c1ff67c81a5cce..c395aa443495344ff686d0388e8cc39f83230dc3 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
-$Log: WinVersRes.h,v $
-Revision 1.63  2009/07/21 05:10:55  herscher
-Bump version to 2.0.0.7
-
-Revision 1.62  2009/07/13 18:47:58  herscher
-Bump to version 2.0.0.6
-
-Revision 1.61  2009/06/30 17:37:32  herscher
-Bump to 2.0.0.5
-
-Revision 1.60  2009/06/15 18:03:41  herscher
-Bump to version 2.0.0.4
-
-Revision 1.59  2009/05/27 20:14:35  herscher
-Bump version to 2.0.0.3
-
-Revision 1.58  2009/05/26 21:13:35  herscher
-Bump to version 2.0.0.2
-
-Revision 1.57  2009/04/28 20:12:15  herscher
-Bump version to 2.0.0.1
-
-Revision 1.56  2009/04/02 22:04:43  herscher
-Bump to version 2.0.0.0
-
-Revision 1.55  2007/04/27 20:34:31  herscher
-<rdar://problem/5159673> mDNS: Company name needs to be changed to Apple Inc.
-
-Revision 1.54  2006/08/14 23:25:21  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.53  2006/02/28 20:07:53  herscher
-Bump to 1.0.3.1
-
-Revision 1.52  2006/01/09 20:45:29  cheshire
-Update copyright date to 2006
-
-Revision 1.51  2005/11/28 19:49:56  herscher
-Bump to 1.0.2.9
-
-Revision 1.50  2005/10/28 18:48:04  herscher
-Bump to version 1.0.2.8
-
-Revision 1.49  2005/10/25 05:24:27  herscher
-Bump to 1.0.2.7
-
-Revision 1.48  2005/10/18 06:17:05  herscher
-Bump to 1.0.2.6
-
-Revision 1.47  2005/10/05 22:16:57  herscher
-Bump version number to 1.0.2.5
-
-Revision 1.46  2005/09/29 06:43:07  herscher
-Bump to version 1.0.2.4
-
-Revision 1.45  2005/09/22 07:11:35  herscher
-Bump version to 1.0.2.3
-
-Revision 1.44  2005/09/13 01:07:40  herscher
-Bump to 1.0.2.2
-
-Revision 1.43  2005/09/12 06:13:32  herscher
-Bump version 1.0.2.1
-
-Revision 1.42  2005/07/22 19:41:44  ksekar
-Update version
-
-Revision 1.41  2005/07/15 15:22:20  shersche
-Bump to 1.0.1.1
-
-Revision 1.40  2005/07/11 20:42:03  shersche
-Bump version to 1.0.0.68
-
-Revision 1.39  2005/07/07 19:12:47  shersche
-Bump to 1.0.0.67
-
-Revision 1.38  2005/04/25 21:59:42  shersche
-Bump to 1.0.0.66
-
-Revision 1.37  2005/04/22 07:39:48  shersche
-Bump to 1.0.0.65
-
-Revision 1.36  2005/04/19 07:25:56  shersche
-Bump version to 1.0.0.64
-
-Revision 1.35  2005/04/13 17:48:58  shersche
-Bump to 1.0.0.63
-
-Revision 1.34  2005/04/06 01:00:55  shersche
-Bump to 1.0.0.62
-
-Revision 1.33  2005/03/30 07:37:41  shersche
-Bump to 1.0.0.61
-
-Revision 1.32  2005/03/23 00:39:46  shersche
-Bump to version 1.0.0.60
-
-Revision 1.31  2005/03/16 03:52:06  shersche
-Bump to 1.0.0.59
-
-Revision 1.30  2005/03/07 19:18:18  shersche
-<rdar://problem/4039831> Update Windows build to 1.0.0.58
-
-Revision 1.29  2005/03/02 20:11:45  shersche
-Update name
-
-Revision 1.28  2005/03/02 03:57:51  shersche
-Bump to 1.0.0.57
-
-Revision 1.27  2005/02/23 03:12:27  shersche
-Bump to 1.0.0.56
-
-Revision 1.26  2005/02/15 23:20:18  shersche
-Bump to 1.0.0.55 and update name
-
-Revision 1.25  2005/02/10 22:35:29  cheshire
-<rdar://problem/3727944> Update name
-
-Revision 1.24  2005/02/08 23:32:24  shersche
-Bump to 1.0.0.54
-
-Revision 1.23  2005/02/02 02:08:28  shersche
-Bump to version 1.0.0.53
-
-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
-
-Revision 1.16  2004/10/12 23:51:36  cheshire
-Bump version to 1.0.0.20
-
-Revision 1.15  2004/09/21 01:15:56  shersche
-bump version to 1.0.19
-
-Revision 1.14  2004/09/16 21:27:46  shersche
-Bump to version 18
-
-Revision 1.13  2004/09/13 21:28:41  shersche
-Bump version to 17
-
-Revision 1.12  2004/08/28 00:18:01  rpantos
-no message
-
-Revision 1.11  2004/08/26 17:37:15  shersche
-bump version to 1.0.0.14
-
-Revision 1.10  2004/08/05 18:00:04  rpantos
-bump to 1.0.0.13
-
-Revision 1.9  2004/07/27 07:31:46  shersche
-bump to 1.0.0.12
-
-Revision 1.8  2004/07/22 23:28:54  shersche
-bump to Version 1.0.0.11
-
-Revision 1.7  2004/07/20 23:36:24  shersche
-bump to version 1.0.0.10
-
-Revision 1.6  2004/07/14 19:53:26  shersche
-bump version to 1.0.0.9
-
-Revision 1.5  2004/07/13 22:20:02  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.4  2004/07/09 18:04:17  shersche
-bump version to 1.0.0.8
-
-Revision 1.3  2004/06/27 17:00:15  rpantos
-Cleanup.
-
-Revision 1.2  2004/06/26 22:24:08  rpantos
-Cleanup.
-
-Revision 1.1  2004/06/26 19:17:41  rpantos
-First checked in.
-
  */
 
 #ifndef WINRESVERS_H
@@ -217,12 +24,12 @@ First checked in.
 #define MASTER_COMPANY_NAME   "Apple Inc."
 
 // Define the product version for mDNSResponder on Windows
-#define MASTER_PROD_VERS               2,0,0,7
-#define MASTER_PROD_VERS_STR   "2,0,0,7"
-#define MASTER_PROD_VERS_STR2  "2.0.0.7"
-#define MASTER_PROD_VERS_STR3 "Explorer Plugin 2.0.0.7"
+#define MASTER_PROD_VERS               2,0,0,19
+#define MASTER_PROD_VERS_STR   "2,0,0,19"
+#define MASTER_PROD_VERS_STR2  "2.0.0.19"
+#define MASTER_PROD_VERS_STR3 "Explorer Plugin 2.0.0.19"
 
 // Define the legal copyright
-#define MASTER_LEGAL_COPYRIGHT "Copyright (C) 2003-2009 Apple Inc."
+#define MASTER_LEGAL_COPYRIGHT "Copyright (C) 2003-2010 Apple Inc."
 
 #endif // WINRESVERS_H
index 0edb6ff67251660e6ff85569a615f922eeeeea10..fe04f3120aa7d70cb3475d9305c20987470bb628 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-*/
+ */
 
 /* isocode.h                                                             */
 /* ----------------------------------------------------------------------*/
@@ -124,7 +121,7 @@ unsigned char ISOCODES[] = {
 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 ,
+4, 25, '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 ,
index 2f5d46cd62a870ffc270fbc00eb701b3f8966802..9744120395331fb18e1a52251a53b7c5401376ec 100755 (executable)
@@ -13,9 +13,6 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
  */
     
 /* loclibrary.c                                                          
index 9b081be4f44c7fc3e5b54dfe6494b1b6a5d7abd6..0a9b7ce614fb48da602ac90662a54a1320120f71 100755 (executable)
@@ -13,9 +13,6 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-
  */
     
 /* loclibrary.h                                                      
index 05b9a562d5d2ce2838fbd61fd696bc91c08be962..4add8451fc69bc9aa87f279250ba262a48ade239 100755 (executable)
  * See the License for the specific language governing permissions and
  * limitations under the License.
 
-    Change History (most recent first):
-    
-$Log: mDNSWin32.c,v $
-Revision 1.145  2009/07/20 04:07:41  herscher
-<rdar://problem/6145339> Bonjour does not list IPv6 loopback address when all network adapters are disabled
-
-Revision 1.144  2009/07/17 19:59:46  herscher
-<rdar://problem/7062660> Update the womp settings for each network adapter immediately preceding the call to mDNSCoreMachineSleep().
-
-Revision 1.143  2009/07/07 21:34:58  herscher
-<rdar://problem/6713286> windows platform changes to support use as sleep proxy client
-
-Revision 1.142  2009/06/25 21:11:02  herscher
-<rdar://problem/7003607> Platform layer doesn't correctly initialize the port field of TCP and UDP socket structures.
-
-Revision 1.141  2009/06/22 23:25:05  herscher
-<rdar://problem/5265747> ControlPanel doesn't display key and password in dialog box. Refactor Lsa calls into Secret.h and Secret.c, which is used by both the ControlPanel and mDNSResponder system service.
-
-Revision 1.140  2009/04/24 04:55:26  herscher
-<rdar://problem/3496833> Advertise SMB file sharing via Bonjour
-
-Revision 1.139  2009/04/01 20:06:31  herscher
-<rdar://problem/5629676> Corrupt computer name string used
-
-Revision 1.138  2009/04/01 19:31:54  herscher
-Remove extraneous printf
-
-Revision 1.137  2009/04/01 17:50:15  mcguire
-cleanup mDNSRandom
-
-Revision 1.136  2009/03/30 20:53:10  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8.
-<rdar://problem/6145992> Reduce sleep from 3 seconds to 2 seconds
-<rdar://problem/6145992> Bonjour Service sometimes only gets a IPv6 link-local address after a network changed event
-<rdar://problem/6145913> Bonjour For Windows doesn't show IPv4 loopback intermittently when no network interfaces are active
-<rdar://problem/6143633> Bonjour service does not publish ANY IPv6 address on Windows Vista
-<rdar://problem/6136296> Bonjour 105A6: mDNSResponder is crashing on startup
-<rdar://problem/6127927> B4Windows: uDNS: Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-<rdar://problem/5270738> Remove Virtual PC check from mDNSResponder code
-
-Revision 1.135  2009/01/13 05:31:35  mkrochma
-<rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
-
-Revision 1.134  2008/10/23 22:33:25  cheshire
-Changed "NOTE:" to "Note:" so that BBEdit 9 stops putting those comment lines into the funtion popup menu
-
-Revision 1.133  2008/10/22 17:19:57  cheshire
-Don't need to define BPF_fd any more (it's now per-interface, not global)
-
-Revision 1.132  2008/10/03 23:34:08  cheshire
-Added skeleton definition of mDNSPlatformSendRawPacket
-
-Revision 1.131  2008/10/03 18:25:18  cheshire
-Instead of calling "m->MainCallback" function pointer directly, call mDNSCore routine "mDNS_ConfigChanged(m);"
-
-Revision 1.130  2007/11/16 18:53:56  cheshire
-TCPSocketFlags needs to be first field of TCPSocket_struct
-
-Revision 1.129  2007/10/17 22:52:26  cheshire
-Get rid of unused mDNS_UpdateLLQs()
-
-Revision 1.128  2007/09/12 19:23:17  cheshire
-Get rid of unnecessary mDNSPlatformTCPIsConnected() routine
-
-Revision 1.127  2007/07/20 00:54:22  cheshire
-<rdar://problem/4641118> Need separate SCPreferences for per-user .Mac settings
-
-Revision 1.126  2007/07/11 02:56:20  cheshire
-<rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
-Remove unused mDNSPlatformDefaultRegDomainChanged
-
-Revision 1.125  2007/06/20 01:10:13  cheshire
-<rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
-
-Revision 1.124  2007/04/26 00:35:16  cheshire
-<rdar://problem/5140339> uDNS: Domain discovery not working over VPN
-Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
-inside the firewall may give answers where a public one gives none, and vice versa.)
-
-Revision 1.123  2007/04/18 21:00:40  cheshire
-Use mDNS_AddSearchDomain_CString() instead of MakeDomainNameFromDNSNameString ... mDNS_AddSearchDomain
-
-Revision 1.122  2007/04/17 19:21:29  cheshire
-<rdar://problem/5140339> Domain discovery not working over VPN
-
-Revision 1.121  2007/04/05 20:40:37  cheshire
-Remove unused mDNSPlatformTCPGetFlags()
-
-Revision 1.120  2007/03/28 20:59:27  cheshire
-<rdar://problem/4743285> Remove inappropriate use of IsPrivateV4Addr()
-
-Revision 1.119  2007/03/28 15:56:38  cheshire
-<rdar://problem/5085774> Add listing of NAT port mapping and GetAddrInfo requests in SIGINFO output
-
-Revision 1.118  2007/03/22 18:31:49  cheshire
-Put dst parameter first in mDNSPlatformStrCopy/mDNSPlatformMemCopy, like conventional Posix strcpy/memcpy
-
-Revision 1.117  2007/03/21 00:30:07  cheshire
-<rdar://problem/4789455> Multiple errors in DNameList-related code
-
-Revision 1.116  2007/03/20 17:07:16  cheshire
-Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
-
-Revision 1.115  2007/02/08 21:12:28  cheshire
-<rdar://problem/4386497> Stop reading /etc/mDNSResponder.conf on every sleep/wake
-
-Revision 1.114  2007/01/05 08:31:01  cheshire
-Trim excessive "$Log" checkin history from before 2006
-(checkin history still available via "cvs log ..." of course)
-
-Revision 1.113  2007/01/04 23:12:20  cheshire
-Remove unused mDNSPlatformDefaultBrowseDomainChanged
-
-Revision 1.112  2006/12/22 20:59:51  cheshire
-<rdar://problem/4742742> Read *all* DNS keys from keychain,
- not just key for the system-wide default registration domain
-
-Revision 1.111  2006/12/19 22:43:56  cheshire
-Fix compiler warnings
-
-Revision 1.110  2006/09/27 00:47:40  herscher
-Fix compile error caused by changes to the tcp callback api.
-
-Revision 1.109  2006/08/14 23:25:21  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.108  2006/07/06 00:06:21  cheshire
-<rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
-
-Revision 1.107  2006/03/19 02:00:13  cheshire
-<rdar://problem/4073825> Improve logic for delaying packets after repeated interface transitions
-
-Revision 1.106  2006/02/26 19:31:05  herscher
-<rdar://problem/4455038> Bonjour For Windows takes 90 seconds to start. This was caused by a bad interaction between the VirtualPC check, and the removal of the WMI dependency.  The problem was fixed by: 1) checking to see if WMI is running before trying to talk to it.  2) Retrying the VirtualPC check every 10 seconds upon failure, stopping after 10 unsuccessful tries.
-
        To Do:
        
        - Get unicode name of machine for nice name instead of just the host name.
@@ -163,6 +27,7 @@ Revision 1.106  2006/02/26 19:31:05  herscher
 #include       <stddef.h>
 #include       <stdio.h>
 #include       <stdlib.h>
+#include       <crtdbg.h>
 #include       <string.h>
 
 #include       "CommonServices.h"
@@ -173,16 +38,15 @@ Revision 1.106  2006/02/26 19:31:05  herscher
 #include       <dns_sd.h>
 
 #include       <Iphlpapi.h>
-#if( !TARGET_OS_WINDOWS_CE )
-       #include        <mswsock.h>
-       #include        <process.h>
-       #include        <ntsecapi.h>
-       #include        <lm.h>
-       #include        <winioctl.h>
-       #include        <ntddndis.h>        // This defines the IOCTL constants.
-#endif
+#include       <mswsock.h>
+#include       <process.h>
+#include       <ntsecapi.h>
+#include       <lm.h>
+#include       <winioctl.h>
+#include       <ntddndis.h>        // This defines the IOCTL constants.
 
 #include       "mDNSEmbeddedAPI.h"
+#include       "GenLinkedList.h"
 #include       "DNSCommon.h"
 #include       "mDNSWin32.h"
 
@@ -207,28 +71,15 @@ Revision 1.106  2006/02/26 19:31:05  herscher
 #define        kWinSockMajorMin                                                        2
 #define        kWinSockMinorMin                                                        2
 
-#define        kWaitListCancelEvent                                            ( WAIT_OBJECT_0 + 0 )
-#define        kWaitListInterfaceListChangedEvent                      ( WAIT_OBJECT_0 + 1 )
-#define        kWaitListWakeupEvent                                            ( WAIT_OBJECT_0 + 2 )
-#define kWaitListComputerDescriptionEvent                      ( WAIT_OBJECT_0 + 3 )
-#define kWaitListTCPIPEvent                                                    ( WAIT_OBJECT_0 + 4 )
-#define kWaitListDynDNSEvent                                           ( WAIT_OBJECT_0 + 5 )
-#define kWaitListFileShareEvent                                                ( WAIT_OBJECT_0 + 6 )
-#define kWaitListFirewallEvent                                         ( WAIT_OBJECT_0 + 7 )
-#define        kWaitListFixedItemCount                                         8 + MDNS_WINDOWS_ENABLE_IPV4 + MDNS_WINDOWS_ENABLE_IPV6
-
 #define kRegistryMaxKeyLength                                          255
 #define kRegistryMaxValueName                                          16383
 
-#if( !TARGET_OS_WINDOWS_CE )
-       static GUID                                                                             kWSARecvMsgGUID = WSAID_WSARECVMSG;
-#endif
+static GUID                                                                                    kWSARecvMsgGUID = WSAID_WSARECVMSG;
 
 #define kIPv6IfIndexBase                                                       (10000000L)
 #define SMBPortAsNumber                                                                445
 #define DEVICE_PREFIX                                                          "\\\\.\\"
 
-
 #if 0
 #pragma mark == Prototypes ==
 #endif
@@ -237,34 +88,15 @@ Revision 1.106  2006/02/26 19:31:05  herscher
 //     Prototypes
 //===========================================================================================================================
 
-mDNSlocal mStatus                      SetupSynchronizationObjects( mDNS * const inMDNS );
-mDNSlocal mStatus                      TearDownSynchronizationObjects( mDNS * const inMDNS );
 mDNSlocal mStatus                      SetupNiceName( mDNS * const inMDNS );
 mDNSlocal mStatus                      SetupHostName( mDNS * const inMDNS );
 mDNSlocal mStatus                      SetupName( mDNS * const inMDNS );
-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 void CALLBACK                FreeInterface( mDNSInterfaceData *inIFD );
 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 );
-
-mDNSlocal mStatus                      SetupThread( mDNS * const inMDNS );
-mDNSlocal mStatus                      TearDownThread( const mDNS * const inMDNS );
-mDNSlocal unsigned WINAPI      ProcessingThread( LPVOID inParam );
-mDNSlocal mStatus                      ProcessingThreadInitialize( mDNS * const inMDNS );
-mDNSlocal mStatus                      ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount );
-mDNSlocal void                         ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, UDPSocket * inUDPSocket, SocketRef inSock );
-mDNSlocal void                         ProcessingThreadInterfaceListChanged( mDNS *inMDNS );
-mDNSlocal void                         ProcessingThreadComputerDescriptionChanged( mDNS * inMDNS );
-mDNSlocal void                         ProcessingThreadTCPIPConfigChanged( mDNS * inMDNS );
-mDNSlocal void                         ProcessingThreadDynDNSConfigChanged( mDNS * inMDNS );
-mDNSlocal void                         ProcessingThreadFileShareChanged( mDNS * inMDNS );
-mDNSlocal void                         ProcessingThreadFirewallChanged( mDNS * inMDNS );
 mDNSlocal OSStatus                     GetWindowsVersionString( char *inBuffer, size_t inBufferSize );
-
 mDNSlocal int                          getifaddrs( struct ifaddrs **outAddrs );
 mDNSlocal void                         freeifaddrs( struct ifaddrs *inAddrs );
 
@@ -283,30 +115,6 @@ struct     mDNSPlatformInterfaceInfo
        mDNSAddr                        ip;
 };
 
-struct TCPSocket_struct
-{
-       TCPSocketFlags flags;           // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
-       SocketRef                               fd;
-       BOOL                                    connected;
-       TCPConnectionCallback   callback;
-       void                            *       context;
-       HANDLE                                  pendingEvent;
-       TCPSocket *                     next;
-};
-
-struct UDPSocket_struct
-{
-       mDNSIPPort                                      port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
-       SocketRef                                       sock;
-       HANDLE                                          readEvent;
-       mDNSAddr                                        dstAddr;
-       LPFN_WSARECVMSG                         recvMsgPtr;
-       struct UDPSocket_struct *       next;
-};
-
-
-
-
 
 mDNSexport mStatus     mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID );
 mDNSexport mStatus     mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo );
@@ -317,13 +125,8 @@ mDNSexport mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInter
        mDNSlocal int   getifaddrs_ipv6( struct ifaddrs **outAddrs );
 #endif
 
-#if( !TARGET_OS_WINDOWS_CE )
-       mDNSlocal int   getifaddrs_ipv4( struct ifaddrs **outAddrs );
-#endif
+mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs );
 
-#if( TARGET_OS_WINDOWS_CE )
-       mDNSlocal int   getifaddrs_ce( struct ifaddrs **outAddrs );
-#endif
 
 mDNSlocal DWORD                                GetPrimaryInterface();
 mDNSlocal mStatus                      AddressToIndexAndMask( struct sockaddr * address, uint32_t * index, struct sockaddr * mask );
@@ -335,8 +138,14 @@ mDNSlocal mStatus                  RegQueryString( HKEY key, LPCSTR param, LPSTR * string, DWOR
 mDNSlocal struct ifaddrs*      myGetIfAddrs(int refresh);
 mDNSlocal OSStatus                     TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize );
 mDNSlocal OSStatus                     WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize );
-mDNSlocal void                         FreeTCPSocket( TCPSocket *sock );
-mDNSlocal void                         FreeUDPSocket( UDPSocket * sock );
+mDNSlocal void                         TCPDidConnect( mDNS * const inMDNS, HANDLE event, void * context );
+mDNSlocal void                         TCPCanRead( TCPSocket * sock );
+mDNSlocal mStatus                      TCPBeginRecv( TCPSocket * sock );
+mDNSlocal void CALLBACK                TCPEndRecv( DWORD error, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags );
+mDNSlocal void CALLBACK                TCPFreeSocket( TCPSocket *sock );
+mDNSlocal OSStatus                     UDPBeginRecv( UDPSocket * socket );
+mDNSlocal void CALLBACK                UDPEndRecv( DWORD err, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags );
+mDNSlocal void CALLBACK                UDPFreeSocket( UDPSocket * sock );
 mDNSlocal mStatus           SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa);
 mDNSlocal void                         GetDDNSFQDN( domainname *const fqdn );
 #ifdef UNICODE
@@ -344,10 +153,16 @@ mDNSlocal void                            GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey );
 #else
 mDNSlocal void                         GetDDNSDomains( DNameListElem ** domains, LPCSTR lpSubKey );
 #endif
-mDNSlocal void                         SetDomainSecrets( mDNS * const m );
+mDNSlocal void                         SetDomainSecrets( mDNS * const inMDNS );
 mDNSlocal void                         SetDomainSecret( mDNS * const m, const domainname * inDomain );
-mDNSlocal void                         CheckFileShares( mDNS * const m );
-mDNSlocal mDNSu8                       IsWOMPEnabled( const char * adapterName );
+mDNSlocal VOID CALLBACK                CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue );
+mDNSlocal void                         CheckFileShares( mDNS * const inMDNS );
+mDNSlocal void                         SMBCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
+mDNSlocal mDNSu8                       IsWOMPEnabledForAdapter( const char * adapterName );
+mDNSlocal void                         FreeSocketEventsForSocket( mDNS * const inMDNS, void * sock );
+mDNSlocal void                         FreeSocketEvents( mDNS * const inMDNS );
+mDNSlocal void                         TCPSocketEventHandler( mDNS * const inMDNS, void * v );
+mDNSlocal void                         UDPSocketEventHandler( mDNS * const inMDNS, void * v );
 
 #ifdef __cplusplus
        }
@@ -363,11 +178,10 @@ mDNSlocal mDNSu8                  IsWOMPEnabled( const char * adapterName );
 
 mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
 mDNSs32                                                        mDNSPlatformOneSecond = 0;
-mDNSlocal TCPSocket *          gTCPConnectionList              = NULL;
-mDNSlocal int                                  gTCPConnections                 = 0;
-mDNSlocal UDPSocket *                          gUDPSocketList                  = NULL;
-mDNSlocal int                                          gUDPSockets                             = 0;
-mDNSlocal BOOL                                 gWaitListChanged                = FALSE;
+mDNSlocal UDPSocket            *               gUDPSocketList                  = NULL;
+mDNSlocal int                                  gUDPSockets                             = 0;
+mDNSlocal BOOL                                 gSocketEventsEnabled    = FALSE;
+mDNSlocal GenLinkedList                        gSocketEvents;
 
 #if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
 
@@ -413,6 +227,39 @@ static HINSTANCE                    g_hAAPI32                                      = NULL;
 static HCRYPTPROV                       g_hProvider                            = ( ULONG_PTR ) NULL;
 
 
+typedef DNSServiceErrorType ( DNSSD_API *DNSServiceRegisterFunc )
+    (
+    DNSServiceRef                       *sdRef,
+    DNSServiceFlags                     flags,
+    uint32_t                            interfaceIndex,
+    const char                          *name,         /* may be NULL */
+    const char                          *regtype,
+    const char                          *domain,       /* may be NULL */
+    const char                          *host,         /* may be NULL */
+    uint16_t                            port,
+    uint16_t                            txtLen,
+    const void                          *txtRecord,    /* may be NULL */
+    DNSServiceRegisterReply             callBack,      /* may be NULL */
+    void                                *context       /* may be NULL */
+    );
+
+
+typedef void ( DNSSD_API *DNSServiceRefDeallocateFunc )( DNSServiceRef sdRef );
+
+mDNSlocal HMODULE                                      gDNSSDLibrary                           = NULL;
+mDNSlocal DNSServiceRegisterFunc       gDNSServiceRegister                     = NULL;
+mDNSlocal DNSServiceRefDeallocateFunc gDNSServiceRefDeallocate = NULL;
+mDNSlocal HANDLE                                       gSMBThread                                      = NULL;
+mDNSlocal HANDLE                                       gSMBThreadRegisterEvent         = NULL;
+mDNSlocal HANDLE                                       gSMBThreadDeregisterEvent       = NULL;
+mDNSlocal HANDLE                                       gSMBThreadStopEvent                     = NULL;
+mDNSlocal HANDLE                                       gSMBThreadQuitEvent                     = NULL;
+
+#define        kSMBStopEvent                           ( WAIT_OBJECT_0 + 0 )
+#define        kSMBRegisterEvent                       ( WAIT_OBJECT_0 + 1 )
+#define kSMBDeregisterEvent                    ( WAIT_OBJECT_0 + 2 )
+
+
 #if 0
 #pragma mark -
 #pragma mark == Platform Support ==
@@ -431,6 +278,8 @@ mDNSexport mStatus  mDNSPlatformInit( mDNS * const inMDNS )
        struct sockaddr_in6 sa6;
        int                                     sa4len;
        int                                     sa6len;
+       DWORD                           size;
+       DWORD                           val;
        
        dlog( kDebugLevelTrace, DEBUG_NAME "platform init\n" );
        
@@ -439,8 +288,13 @@ mDNSexport mStatus mDNSPlatformInit( mDNS * const inMDNS )
        
        mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) );
        if( !inMDNS->p ) inMDNS->p                              = &gMDNSPlatformSupport;
-       inMDNS->p->interfaceListChangedSocket   = kInvalidSocketRef;
+       inMDNS->p->mainThread                                   = OpenThread( THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId() );
+       require_action( inMDNS->p->mainThread, exit, err = mStatus_UnknownErr );
+       inMDNS->p->checkFileSharesTimer = CreateWaitableTimer( NULL, FALSE, NULL );
+       require_action( inMDNS->p->checkFileSharesTimer, exit, err = mStatus_UnknownErr );
+       inMDNS->p->checkFileSharesTimeout               = 10;           // Retry time for CheckFileShares() in seconds
        mDNSPlatformOneSecond                                   = 1000;         // Use milliseconds as the quantum of time
+       InitLinkedList( &gSocketEvents, offsetof( SocketEvent, next));
        
        // Startup WinSock 2.2 or later.
        
@@ -452,64 +306,66 @@ mDNSexport mStatus        mDNSPlatformInit( mDNS * const inMDNS )
        
        inMDNS->CanReceiveUnicastOn5353 = CanReceiveUnicast();
        
-       // Setup the HINFO HW/SW strings.
-       
-#if ( MDNS_SET_HINFO_STRINGS )
-       err = GetWindowsVersionString( (char *) &inMDNS->HIHardware.c[ 1 ], sizeof( inMDNS->HIHardware.c ) - 2 );
-       check_noerr( err );
-       // Note that GetWindowsVersionString guarantees that the resulting string is always null-terminated,
-       // so the following strlen call is safe
-       inMDNS->HIHardware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HIHardware.c[ 1 ] );
+       // Setup the HINFO HW strings.
+       //<rdar://problem/7245119> device-info should have model=Windows
+
+       strcpy_s( ( char* ) &inMDNS->HIHardware.c[ 1 ], sizeof( inMDNS->HIHardware.c ) - 2, "Windows" );
+       inMDNS->HIHardware.c[ 0 ] = ( mDNSu8 ) mDNSPlatformStrLen( &inMDNS->HIHardware.c[ 1 ] );
        dlog( kDebugLevelInfo, DEBUG_NAME "HIHardware: %#s\n", inMDNS->HIHardware.c );
-       
+
+       // Setup the HINFO SW strings.
+#if ( MDNS_SET_HINFO_STRINGS )
        mDNS_snprintf( (char *) &inMDNS->HISoftware.c[ 1 ], sizeof( inMDNS->HISoftware.c ) - 2, 
                "mDNSResponder (%s %s)", __DATE__, __TIME__ );
        inMDNS->HISoftware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HISoftware.c[ 1 ] );
        dlog( kDebugLevelInfo, DEBUG_NAME "HISoftware: %#s\n", inMDNS->HISoftware.c );
 #endif
-       
+
+       // Set the thread global overlapped flag
+
+       val = 0;
+       err = setsockopt( INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, ( char* ) &val, sizeof( val ) );
+       err = translate_errno( err != SOCKET_ERROR, WSAGetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
        // Set up the IPv4 unicast socket
 
-       inMDNS->p->unicastSock4                         = INVALID_SOCKET;
-       inMDNS->p->unicastSock4ReadEvent        = NULL;
-       inMDNS->p->unicastSock4RecvMsgPtr       = NULL;
+       inMDNS->p->unicastSock4.fd                      = INVALID_SOCKET;
+       inMDNS->p->unicastSock4.recvMsgPtr      = NULL;
+       inMDNS->p->unicastSock4.ifd                     = NULL;
+       inMDNS->p->unicastSock4.next            = NULL;
+       inMDNS->p->unicastSock4.m                       = inMDNS;
 
 #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 );
+       err = SetupSocket( inMDNS, (const struct sockaddr*) &sa4, zeroIPPort, &inMDNS->p->unicastSock4.fd );
        check_noerr( err );
        sa4len = sizeof( sa4 );
-       err = getsockname( inMDNS->p->unicastSock4, (struct sockaddr*) &sa4, &sa4len );
-       require_noerr( err, exit );
-       inMDNS->UnicastPort4.NotAnInteger = sa4.sin_port;
-       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 );
+       err = getsockname( inMDNS->p->unicastSock4.fd, (struct sockaddr*) &sa4, &sa4len );
        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 );
+       inMDNS->p->unicastSock4.port.NotAnInteger = sa4.sin_port;
+       inMDNS->UnicastPort4 = inMDNS->p->unicastSock4.port;
+       err = WSAIoctl( inMDNS->p->unicastSock4.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock4.recvMsgPtr, sizeof( inMDNS->p->unicastSock4.recvMsgPtr ), &size, NULL, NULL );
                
-               if ( err )
-               {
-                       inMDNS->p->unicastSock4RecvMsgPtr = NULL;
-               }
+       if ( err )
+       {
+               inMDNS->p->unicastSock4.recvMsgPtr = NULL;
        }
-#endif
+
+       err = UDPBeginRecv( &inMDNS->p->unicastSock4 );
+       require_noerr( err, exit ); 
 
 #endif
 
        // Set up the IPv6 unicast socket
 
-       inMDNS->p->unicastSock6                         = INVALID_SOCKET;
-       inMDNS->p->unicastSock6ReadEvent        = NULL;
-       inMDNS->p->unicastSock6RecvMsgPtr       = NULL;
+       inMDNS->p->unicastSock6.fd                      = INVALID_SOCKET;
+       inMDNS->p->unicastSock6.recvMsgPtr      = NULL;
+       inMDNS->p->unicastSock6.ifd                     = NULL;
+       inMDNS->p->unicastSock6.next            = NULL;
+       inMDNS->p->unicastSock6.m                       = inMDNS;
 
 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
 
@@ -520,48 +376,32 @@ mDNSexport mStatus        mDNSPlatformInit( mDNS * const inMDNS )
        // 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 );
+       err = SetupSocket( inMDNS, (const struct sockaddr*) &sa6, zeroIPPort, &inMDNS->p->unicastSock6.fd );
        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 );
+       err = kNoErr;
        
        // 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 )
+       if ( inMDNS->p->unicastSock6.fd != INVALID_SOCKET )
        {
                sa6len = sizeof( sa6 );
-               err = getsockname( inMDNS->p->unicastSock6, (struct sockaddr*) &sa6, &sa6len );
-               require_noerr( err, exit );
-               inMDNS->UnicastPort6.NotAnInteger = sa6.sin6_port;
-
-               err = WSAEventSelect( inMDNS->p->unicastSock6, inMDNS->p->unicastSock6ReadEvent, FD_READ );
+               err = getsockname( inMDNS->p->unicastSock6.fd, (struct sockaddr*) &sa6, &sa6len );
                require_noerr( err, exit );
+               inMDNS->p->unicastSock6.port.NotAnInteger = sa6.sin6_port;
+               inMDNS->UnicastPort6 = inMDNS->p->unicastSock6.port;
 
-#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 );
+               err = WSAIoctl( inMDNS->p->unicastSock6.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock6.recvMsgPtr, sizeof( inMDNS->p->unicastSock6.recvMsgPtr ), &size, NULL, NULL );
                
-                       if ( err != 0 )
-                       {
-                               inMDNS->p->unicastSock6RecvMsgPtr = NULL;
-                       }
+               if ( err != 0 )
+               {
+                       inMDNS->p->unicastSock6.recvMsgPtr = NULL;
                }
-#endif
-       }
 
-#endif
+               err = UDPBeginRecv( &inMDNS->p->unicastSock6 );
+               require_noerr( err, exit );
+       } 
 
-       // Set up the mDNS thread.
-       
-       err = SetupSynchronizationObjects( inMDNS );
-       require_noerr( err, exit );
-       
-       err = SetupThread( inMDNS );
-       require_noerr( err, exit );
+#endif
 
        // Notify core of domain secret keys
 
@@ -571,16 +411,14 @@ mDNSexport mStatus        mDNSPlatformInit( mDNS * const inMDNS )
 
        mDNSCoreInitComplete( inMDNS, err );
 
-       // See if we need to advertise file sharing
-
-       inMDNS->p->smbRegistered = mDNSfalse;
-       CheckFileShares( inMDNS );
        
 exit:
-       if( err )
+
+       if ( err )
        {
                mDNSPlatformClose( inMDNS );
        }
+
        dlog( kDebugLevelTrace, DEBUG_NAME "platform init done (err=%d %m)\n", err, err );
        return( err );
 }
@@ -595,45 +433,75 @@ mDNSexport void   mDNSPlatformClose( mDNS * const inMDNS )
        
        dlog( kDebugLevelTrace, DEBUG_NAME "platform close\n" );
        check( inMDNS );
-       
-       // Tear everything down in reverse order to how it was set up.
+
+       if ( gSMBThread != NULL )
+       {
+               dlog( kDebugLevelTrace, DEBUG_NAME "tearing down smb registration thread\n" );
+               SetEvent( gSMBThreadStopEvent );
                
-       err = TearDownThread( inMDNS );
-       check_noerr( err );
+               if ( WaitForSingleObject( gSMBThreadQuitEvent, 5 * 1000 ) == WAIT_OBJECT_0 )
+               {
+                       if ( gSMBThreadQuitEvent )
+                       {
+                               CloseHandle( gSMBThreadQuitEvent );
+                               gSMBThreadQuitEvent = NULL;
+                       }
+
+                       if ( gSMBThreadStopEvent )
+                       {
+                               CloseHandle( gSMBThreadStopEvent );
+                               gSMBThreadStopEvent = NULL;
+                       }
+
+                       if ( gSMBThreadDeregisterEvent )
+                       {
+                               CloseHandle( gSMBThreadDeregisterEvent );
+                               gSMBThreadDeregisterEvent = NULL;
+                       }
+
+                       if ( gSMBThreadRegisterEvent )
+                       {
+                               CloseHandle( gSMBThreadRegisterEvent );
+                               gSMBThreadRegisterEvent = NULL;
+                       }
+
+                       if ( gDNSSDLibrary )
+                       {
+                               FreeLibrary( gDNSSDLibrary );
+                               gDNSSDLibrary = NULL;
+                       }       
+               }
+               else
+               {
+                       LogMsg( "Unable to stop SMBThread" );
+               }
+
+               inMDNS->p->smbFileSharing = mDNSfalse;
+               inMDNS->p->smbPrintSharing = mDNSfalse;
+       }
+
+       // Tear everything down in reverse order to how it was set up.
        
        err = TearDownInterfaceList( inMDNS );
        check_noerr( err );
        check( !inMDNS->p->inactiveInterfaceList );
-               
-       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 ) )
+       if ( inMDNS->p->unicastSock4.fd != INVALID_SOCKET )
        {
-               close_compat( inMDNS->p->unicastSock4 );
+               closesocket( inMDNS->p->unicastSock4.fd );
+               inMDNS->p->unicastSock4.fd = INVALID_SOCKET;
        }
 
 #endif
        
 #if ( MDNS_WINDOWS_ENABLE_IPV6 )
 
-       if ( inMDNS->p->unicastSock6ReadEvent )
-       {
-               CloseHandle( inMDNS->p->unicastSock6ReadEvent );
-               inMDNS->p->unicastSock6ReadEvent = 0;
-       }
-       
-       if ( IsValidSocket( inMDNS->p->unicastSock6 ) )
+       if ( inMDNS->p->unicastSock6.fd != INVALID_SOCKET )
        {
-               close_compat( inMDNS->p->unicastSock6 );
+               closesocket( inMDNS->p->unicastSock6.fd );
+               inMDNS->p->unicastSock6.fd = INVALID_SOCKET;
        }
 
 #endif
@@ -672,6 +540,12 @@ mDNSexport void    mDNSPlatformClose( mDNS * const inMDNS )
                g_hAAPI32                               = NULL;
        }
 
+       // Clear out the APC queue
+
+       SetSocketEventsEnabled( inMDNS, TRUE );
+       while ( SleepEx( 0, TRUE ) == WAIT_IO_COMPLETION );
+       SetSocketEventsEnabled( inMDNS, FALSE );
+
        WSACleanup();
        
        dlog( kDebugLevelTrace, DEBUG_NAME "platform close done\n" );
@@ -684,12 +558,7 @@ mDNSexport void    mDNSPlatformClose( mDNS * const inMDNS )
 
 mDNSexport void        mDNSPlatformLock( const mDNS * const inMDNS )
 {
-       check( inMDNS );
-       
-       if ( inMDNS->p->lockInitialized )
-       {
-               EnterCriticalSection( &inMDNS->p->lock );
-       }
+       ( void ) inMDNS;
 }
 
 //===========================================================================================================================
@@ -698,25 +567,7 @@ mDNSexport void    mDNSPlatformLock( const mDNS * const inMDNS )
 
 mDNSexport void        mDNSPlatformUnlock( const mDNS * const inMDNS )
 {
-       check( inMDNS );
-       check( inMDNS->p );
-
-       if ( inMDNS->p->lockInitialized )
-       {
-               check( inMDNS->p->threadID );
-       
-               // Signal a wakeup event if when called from a task other than the mDNS task since if we are called from mDNS task, 
-               // we'll loop back and call mDNS_Execute anyway. Signaling is needed to re-evaluate the wakeup via mDNS_Execute.
-       
-               if( GetCurrentThreadId() != inMDNS->p->threadID )
-               {
-                       BOOL            wasSet;
-               
-                       wasSet = SetEvent( inMDNS->p->wakeupEvent );
-                       check_translated_errno( wasSet, GetLastError(), kUnknownErr );
-               }
-               LeaveCriticalSection( &inMDNS->p->lock );
-       }
+       ( void ) inMDNS;
 }
 
 //===========================================================================================================================
@@ -994,6 +845,12 @@ mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS * con
        {
                id = mDNSInterface_LocalOnly;
        }
+       /* uncomment if Windows ever supports P2P
+       else if( inIndex == kDNSServiceInterfaceIndexP2P )
+       {
+               id = mDNSInterface_P2P;
+       }
+       */
        else if( inIndex != 0 )
        {
                mDNSInterfaceData *             ifd;
@@ -1024,6 +881,12 @@ mDNSexport mDNSu32        mDNSPlatformInterfaceIndexfromInterfaceID( mDNS * const inMDN
        {
                index = (mDNSu32) kDNSServiceInterfaceIndexLocalOnly;
        }
+       /* uncomment if Windows ever supports P2P
+       else if( inID == mDNSInterface_P2P )
+       {
+               index = (mDNSu32) kDNSServiceInterfaceIndexP2P;
+       }
+       */
        else if( inID )
        {
                mDNSInterfaceData *             ifd;
@@ -1056,6 +919,7 @@ mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID( mDNS * const inMDN
        return( index );
 }
 
+
 //===========================================================================================================================
 //     mDNSPlatformTCPSocket
 //===========================================================================================================================
@@ -1083,9 +947,9 @@ mDNSPlatformTCPSocket
        sock = (TCPSocket *) malloc( sizeof( TCPSocket ) );
        require_action( sock, exit, err = mStatus_NoMemoryErr );
        mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
-
        sock->fd                = INVALID_SOCKET;
        sock->flags             = flags;
+       sock->m                 = m;
 
        mDNSPlatformMemZero(&saddr, sizeof(saddr));
        saddr.sin_family                = AF_INET;
@@ -1125,7 +989,7 @@ exit:
 
        if ( err && sock )
        {
-               FreeTCPSocket( sock );
+               TCPFreeSocket( sock );
                sock = mDNSNULL;
        }
 
@@ -1139,19 +1003,21 @@ exit:
 mStatus
 mDNSPlatformTCPConnect
        (
-       TCPSocket *                     sock,
+       TCPSocket                       *       sock,
        const mDNSAddr          *       inDstIP, 
        mDNSOpaque16                    inDstPort, 
+       domainname          *   hostname,
        mDNSInterfaceID                 inInterfaceID,
        TCPConnectionCallback   inCallback, 
        void *                                  inContext
        )
 {
        struct sockaddr_in      saddr;
+       ( void ) hostname; 
        mStatus                         err             = mStatus_NoError;
 
        DEBUG_UNUSED( inInterfaceID );
-       
+
        if ( inDstIP->type != mDNSAddrType_IPv4 )
        {
                LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
@@ -1160,8 +1026,9 @@ mDNSPlatformTCPConnect
 
        // Setup connection data object
 
-       sock->callback = inCallback;
-       sock->context = inContext;
+       sock->readEventHandler  = TCPCanRead;
+       sock->userCallback              = inCallback;
+       sock->userContext               = inContext;
 
        mDNSPlatformMemZero(&saddr, sizeof(saddr));
        saddr.sin_family        = AF_INET;
@@ -1172,19 +1039,27 @@ mDNSPlatformTCPConnect
 
        err = connect( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
        require_action( !err || ( WSAGetLastError() == WSAEWOULDBLOCK ), exit, err = mStatus_ConnFailed );
-       sock->connected         = !err ? TRUE : FALSE;
-       sock->pendingEvent      = CreateEvent( NULL, FALSE, FALSE, NULL );
-       err = translate_errno( sock->pendingEvent, GetLastError(), mStatus_UnknownErr );
-       require_noerr( err, exit );
-       err = WSAEventSelect( sock->fd, sock->pendingEvent, FD_CONNECT|FD_READ|FD_CLOSE );
-       require_noerr( err, exit );
+       sock->connected = !err ? TRUE : FALSE;
 
-       // Bookkeeping
+       if ( sock->connected )
+       {
+               err = TCPAddSocket( sock->m, sock );
+               require_noerr( err, exit );
+       }
+       else
+       {
+               require_action( sock->m->p->registerWaitableEventFunc != NULL, exit, err = mStatus_ConnFailed );
 
-       sock->next                      = gTCPConnectionList;
-       gTCPConnectionList      = sock;
-       gTCPConnections++;
-       gWaitListChanged        = TRUE;
+               sock->connectEvent      = CreateEvent( NULL, FALSE, FALSE, NULL );
+               err = translate_errno( sock->connectEvent, GetLastError(), mStatus_UnknownErr );
+               require_noerr( err, exit );
+
+               err = WSAEventSelect( sock->fd, sock->connectEvent, FD_CONNECT );
+               require_noerr( err, exit );
+
+               err = sock->m->p->registerWaitableEventFunc( sock->m, sock->connectEvent, sock, TCPDidConnect );
+               require_noerr( err, exit );
+       }
 
 exit:
 
@@ -1234,33 +1109,22 @@ exit:
 
 mDNSexport void        mDNSPlatformTCPCloseConnection( TCPSocket *sock )
 {
-       TCPSocket *     inserted  = gTCPConnectionList;
-       TCPSocket *     last = NULL;
+       check( sock );
 
-       while ( inserted )
+       if ( sock->connectEvent && sock->m->p->unregisterWaitableEventFunc )
        {
-               if ( inserted == sock )
-               {
-                       if ( last == NULL )
-                       {
-                               gTCPConnectionList = inserted->next;
-                       }
-                       else
-                       {
-                               last->next = inserted->next;
-                       }
-
-                       gTCPConnections--;
-                       gWaitListChanged = TRUE;
+               sock->m->p->unregisterWaitableEventFunc( sock->m, sock->connectEvent );
+       }
 
-                       break;
-               }
+       if ( sock->fd != INVALID_SOCKET )
+       {
+               closesocket( sock->fd );
+               sock->fd = INVALID_SOCKET;
 
-               last            = inserted;
-               inserted        = inserted->next;
+               QueueUserAPC( ( PAPCFUNC ) TCPFreeSocket, sock->m->p->mainThread, ( ULONG_PTR ) sock );
        }
 
-       FreeTCPSocket( sock );
+       FreeSocketEventsForSocket( sock->m, sock );
 }
 
 //===========================================================================================================================
@@ -1269,29 +1133,66 @@ mDNSexport void mDNSPlatformTCPCloseConnection( TCPSocket *sock )
 
 mDNSexport long        mDNSPlatformReadTCP( TCPSocket *sock, void *inBuffer, unsigned long inBufferSize, mDNSBool * closed )
 {
-       int     nread;
+       unsigned long   bytesLeft;
+       int                             wsaError;
+       long                    ret;
 
-       nread = recv( sock->fd, inBuffer, inBufferSize, 0);
+       *closed = sock->closed;
+       wsaError = sock->lastError;
+       ret = -1;
 
-       if ( nread < 0 )
+       if ( *closed )
+       {
+               ret = 0;
+       }
+       else if ( sock->lastError == 0 )
        {
-               if ( WSAGetLastError() == WSAEWOULDBLOCK )
+               // First check to see if we have any data left in our buffer
+
+               bytesLeft = ( DWORD ) ( sock->eptr - sock->bptr );
+
+               if ( bytesLeft )
                {
-                       nread = 0;
+                       unsigned long bytesToCopy = ( bytesLeft < inBufferSize ) ? bytesLeft : inBufferSize;
+
+                       memcpy( inBuffer, sock->bptr, bytesToCopy );
+                       sock->bptr += bytesToCopy;
+
+                       ret = bytesToCopy;
+
+                       if ( bytesLeft == bytesToCopy )
+                       {
+                               sock->lastError = TCPBeginRecv( sock );
+                               
+                               // If we can't immediately queue up another read, abort the connection
+                               // now, even if we successfully wrote bytes to the buffer.
+                               // We don't expect this to happen unless something is seriously borked.
+                               // If we run into this in the real world, we should consider queuing up
+                               // a user APC function to defer an explicit callback to the read event handler
+                               // to inform the consumer of the problem.
+
+                               if ( sock->lastError )
+                               {
+                                       dlog( kDebugLevelError, DEBUG_NAME "TCPBeginRecv failed with error %d\n", sock->lastError );
+                                       wsaError = sock->lastError;
+                                       ret = -1;
+                               }
+                       }
                }
                else
                {
-                       nread = -1;
+                       wsaError = WSAEWOULDBLOCK;
                }
        }
-       else if ( !nread )
-       {
-               *closed = mDNStrue;
-       }
-               
-       return nread;
+
+       // Always set the last winsock error, so that we don't inadvertently use a previous one         
+       
+       WSASetLastError( wsaError );
+
+       return ret;
 }
 
+
 //===========================================================================================================================
 //     mDNSPlatformWriteTCP
 //===========================================================================================================================
@@ -1321,54 +1222,253 @@ exit:
 //===========================================================================================================================
 
 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock )
-    {
-    return ( int ) sock->fd;
-    }
+{
+       return ( int ) sock->fd;
+}
+
 
-       
 //===========================================================================================================================
-//     mDNSPlatformUDPSocket
+//     TCPAddConnection
 //===========================================================================================================================
 
-mDNSexport UDPSocket* mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
+mStatus TCPAddSocket( mDNS * const inMDNS, TCPSocket *sock )
 {
-       UDPSocket*      sock    = NULL;
-       mDNSIPPort      port    = requestedport;
-       mStatus         err             = mStatus_NoError;
-       unsigned        i;
+       mStatus err;
 
-       // Setup connection data object
+       ( void ) inMDNS;
 
-       sock = (struct UDPSocket_struct*) malloc( sizeof( struct UDPSocket_struct ) );
-       require_action( sock, exit, err = mStatus_NoMemoryErr );
-       memset( sock, 0, sizeof( struct UDPSocket_struct ) );
+       dlog( kDebugLevelChatty, DEBUG_NAME "adding TCPSocket 0x%x:%d\n", sock, sock->fd );
+       err = TCPBeginRecv( sock );
+       require_noerr( err, exit );
 
-       // Create the socket
+exit:
 
-       sock->recvMsgPtr        = m->p->unicastSock4RecvMsgPtr;
-       sock->dstAddr           = m->p->unicastSock4DestAddr;
-       sock->sock                      = INVALID_SOCKET;
+       return err;
+}
 
-       // Try at most 10000 times to get a unique random port
 
-       for (i=0; i<10000; i++)
+//===========================================================================================================================
+//     TCPDidConnect
+//===========================================================================================================================
+
+mDNSlocal void TCPDidConnect( mDNS * const inMDNS, HANDLE event, void * context )
+{
+       TCPSocket * sock = ( TCPSocket* ) context;
+       TCPConnectionCallback callback = NULL;
+       WSANETWORKEVENTS sockEvent;
+       int err = kNoErr;
+
+       if ( inMDNS->p->unregisterWaitableEventFunc )
        {
-               struct sockaddr_in saddr;
+               inMDNS->p->unregisterWaitableEventFunc( inMDNS, event );
+       }
 
-               saddr.sin_family                = AF_INET;
-               saddr.sin_addr.s_addr   = 0;
+       if ( sock )
+       {
+               callback = ( TCPConnectionCallback ) sock->userCallback;
+               err = WSAEnumNetworkEvents( sock->fd, sock->connectEvent, &sockEvent );
+               require_noerr( err, exit );
+               require_action( sockEvent.lNetworkEvents & FD_CONNECT, exit, err = mStatus_UnknownErr );
+               require_action( sockEvent.iErrorCode[ FD_CONNECT_BIT ] == 0, exit, err = sockEvent.iErrorCode[ FD_CONNECT_BIT ] );
 
-               // The kernel doesn't do cryptographically strong random port
-               // allocation, so we do it ourselves here
+               sock->connected = mDNStrue;
 
-        if (mDNSIPPortIsZero(requestedport))
+               if ( sock->fd != INVALID_SOCKET )
                {
-                       port = mDNSOpaque16fromIntVal( ( mDNSu16 ) ( 0xC000 + mDNSRandom(0x3FFF) ) );
+                       err = TCPAddSocket( sock->m, sock );
+                       require_noerr( err, exit );
                }
 
-               saddr.sin_port = port.NotAnInteger;
+               if ( callback )
+               {
+                       callback( sock, sock->userContext, TRUE, 0 );
+               }
+       }
+
+exit:
+
+       if ( err && callback )
+       {
+               callback( sock, sock->userContext, TRUE, err );
+       }
+}
+
+
+
+//===========================================================================================================================
+//     TCPCanRead
+//===========================================================================================================================
+
+mDNSlocal void TCPCanRead( TCPSocket * sock )
+{
+       TCPConnectionCallback callback = ( TCPConnectionCallback ) sock->userCallback;
+
+       if ( callback )
+       {
+               callback( sock, sock->userContext, mDNSfalse, sock->lastError );
+       }
+}
+
+
+//===========================================================================================================================
+//     TCPBeginRecv
+//===========================================================================================================================
+
+mDNSlocal mStatus TCPBeginRecv( TCPSocket * sock )
+{
+       DWORD   bytesReceived   = 0;
+       DWORD   flags                   = 0;
+       mStatus err;
+
+       ZeroMemory( &sock->overlapped, sizeof( sock->overlapped ) );
+       sock->overlapped.hEvent = sock;
+
+       sock->wbuf.buf = ( char* ) sock->buf;
+       sock->wbuf.len = sizeof( sock->buf );
+
+       err = WSARecv( sock->fd, &sock->wbuf, 1, &bytesReceived, &flags, &sock->overlapped, ( LPWSAOVERLAPPED_COMPLETION_ROUTINE ) TCPEndRecv );
+       err = translate_errno( ( err == 0 ) || ( WSAGetLastError() == WSA_IO_PENDING ), WSAGetLastError(), kUnknownErr );
+       require_noerr( err, exit );
+
+exit:
+
+       return err;
+}
+
+
+//===========================================================================================================================
+//     TCPEndRecv
+//===========================================================================================================================
+
+mDNSlocal void CALLBACK TCPEndRecv( DWORD error, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags )
+{
+       TCPSocket * sock;
+
+       ( void ) flags;
+
+       sock = ( overlapped != NULL ) ? overlapped->hEvent : NULL;
+
+       if ( sock && ( sock->fd != INVALID_SOCKET ) )
+       {
+               // <rdar://problem/7532492> mDNSResponder gets locking errors on Windows
+               //
+               // There seems to be a bug in WinSock with respect to Alertable I/O. According
+               // to MSDN <http://msdn.microsoft.com/en-us/library/aa363772(VS.85).aspx>, Alertable I/O
+               // callbacks will only be invoked during the following calls (when the caller sets
+               // the appropriate flag):
+               //
+               // - SleepEx
+               // - WaitForSingleObjectEx
+               // - WaitForMultipleObjectsEx
+               // - SignalObjectAndWait
+               // - MsgWaitForMultipleObjectsEx
+               //
+               // However, we have seen callbacks be invoked during calls to bind() (and maybe others).
+               // To workaround this, we set the gSocketEventsEnabled flag to be TRUE only when it's okay
+               // to directly call the readEventHandler.  Otherwise we queue the packet up and
+               // dispatch it later.
+
+               if ( gSocketEventsEnabled && !gSocketEvents.Head )
+               {
+                       sock->lastError = error;
+
+                       if ( !error )
+                       {
+                               if ( bytesTransferred )
+                               {
+                                       sock->bptr = sock->buf;
+                                       sock->eptr = sock->buf + bytesTransferred;
+                               }
+                               else
+                               {
+                                       sock->closed = TRUE;
+                               }
+                       }
+
+                       if ( sock->readEventHandler != NULL )
+                       {
+                               // Turn off socket events before calling the readEventHandler.
+                               // This will prevent reentrancy problems.
+                               //
+                               // Don't forget to reenable socket events afterwards.
+
+                               SetSocketEventsEnabled( sock->m, FALSE );
+                               sock->readEventHandler( sock );
+                               SetSocketEventsEnabled( sock->m, TRUE );
+                       }
+               }
+               else
+               {
+                       TCPSocketEvent * event;
+
+                       event = malloc( sizeof( TCPSocketEvent ) );
+                       require_action( event, exit, error = ( DWORD ) kNoMemoryErr );
+                       event->super.sock               = sock;
+                       event->super.handler    = &TCPSocketEventHandler;
+                       event->super.next               = NULL;
+                       event->error                    = error;
+                       event->bytesTransferred = bytesTransferred;
+
+                       if ( bytesTransferred )
+                       {
+                               memcpy( event->buf, sock->buf, bytesTransferred );  
+                       }
+
+                       AddToTail( &gSocketEvents, event );
+               }
+       }
+
+exit:
+
+       return;
+}
+
+       
+//===========================================================================================================================
+//     mDNSPlatformUDPSocket
+//===========================================================================================================================
+
+mDNSexport UDPSocket* mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
+{
+       UDPSocket*      sock    = NULL;
+       mDNSIPPort      port    = requestedport;
+       mStatus         err             = mStatus_NoError;
+       unsigned        i;
+
+       // Setup connection data object
+
+       sock = ( UDPSocket* ) malloc(sizeof( UDPSocket ) );
+       require_action( sock, exit, err = mStatus_NoMemoryErr );
+       memset( sock, 0, sizeof( UDPSocket ) );
+
+       // Create the socket
+
+       sock->fd                        = INVALID_SOCKET;
+       sock->recvMsgPtr        = m->p->unicastSock4.recvMsgPtr;
+       sock->addr                      = m->p->unicastSock4.addr;
+       sock->ifd                       = NULL;
+       sock->m                         = m;
 
-        err = SetupSocket(m, ( struct sockaddr* ) &saddr, port, &sock->sock );
+       // Try at most 10000 times to get a unique random port
+
+       for (i=0; i<10000; i++)
+       {
+               struct sockaddr_in saddr;
+
+               saddr.sin_family                = AF_INET;
+               saddr.sin_addr.s_addr   = 0;
+
+               // The kernel doesn't do cryptographically strong random port
+               // allocation, so we do it ourselves here
+
+        if (mDNSIPPortIsZero(requestedport))
+               {
+                       port = mDNSOpaque16fromIntVal( ( mDNSu16 ) ( 0xC000 + mDNSRandom(0x3FFF) ) );
+               }
+
+               saddr.sin_port = port.NotAnInteger;
+
+        err = SetupSocket(m, ( struct sockaddr* ) &saddr, port, &sock->fd );
         if (!err) break;
        }
 
@@ -1378,30 +1478,23 @@ mDNSexport UDPSocket* mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requ
 
        sock->port = port;
 
-       // Set it up with Windows Eventing
+       // Arm the completion routine
 
-       sock->readEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-       err = translate_errno( sock->readEvent, GetLastError(), mStatus_UnknownErr );
-       require_noerr( err, exit );
-       err = WSAEventSelect( sock->sock, sock->readEvent, FD_READ );
-       require_noerr( err, exit );
+       err = UDPBeginRecv( sock );
+       require_noerr( err, exit ); 
 
        // Bookkeeping
 
        sock->next                      = gUDPSocketList;
        gUDPSocketList          = sock;
        gUDPSockets++;
-       gWaitListChanged        = TRUE;
 
 exit:
 
-       if ( err )
+       if ( err && sock )
        {
-               if ( sock )
-               {
-                       FreeUDPSocket( sock );
-                       sock = NULL;
-               }
+               UDPFreeSocket( sock );
+               sock = NULL;
        }
 
        return sock;
@@ -1429,10 +1522,24 @@ mDNSexport void mDNSPlatformUDPClose( UDPSocket *sock )
                                last->next = sock->next;
                        }
 
-                       FreeUDPSocket( sock );
+                       // Alertable I/O is great, except not so much when it comes to closing
+                       // the socket.  Anything that has been previously queued for this socket
+                       // will stay in the queue after you close the socket.  This is problematic
+                       // for obvious reasons. So we'll attempt to workaround this by closing
+                       // the socket which will prevent any further queued packets and then not calling
+                       // UDPFreeSocket directly, but by queueing it using QueueUserAPC.  The queues
+                       // are FIFO, so that will execute *after* any other previous items in the queue
+                       //
+                       // UDPEndRecv will check if the socket is valid, and if not, it will ignore
+                       // the packet
+
+                       closesocket( sock->fd );
+                       sock->fd = INVALID_SOCKET;
+
+                       QueueUserAPC( ( PAPCFUNC ) UDPFreeSocket, sock->m->p->mainThread, ( ULONG_PTR ) sock );
+                       FreeSocketEventsForSocket( sock->m, sock );
 
                        gUDPSockets--;
-                       gWaitListChanged = TRUE;
 
                        break;
                }
@@ -1481,9 +1588,9 @@ mDNSexport 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;
+               sendingsocket           = ifd ? ifd->sock.fd : inMDNS->p->unicastSock4.fd;
 
-               if (inSrcSocket) { sendingsocket = inSrcSocket->sock; debugf("mDNSPlatformSendUDP using port %d, static port %d, sock %d", mDNSVal16(inSrcSocket->port), inMDNS->p->unicastSock4, sendingsocket); }
+               if (inSrcSocket) { sendingsocket = inSrcSocket->fd; debugf("mDNSPlatformSendUDP using port %d, static port %d, sock %d", mDNSVal16(inSrcSocket->port), inMDNS->p->unicastSock4.fd, sendingsocket); }
        }
        else if( inDstIP->type == mDNSAddrType_IPv6 )
        {
@@ -1495,7 +1602,7 @@ mDNSexport 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;
+               sendingsocket           = ifd ? ifd->sock.fd : inMDNS->p->unicastSock6.fd;
        }
        else
        {
@@ -1553,7 +1660,7 @@ mDNSexport void mDNSPlatformReceiveRawPacket(const void *const msg, const mDNSu8
        DEBUG_UNUSED( InterfaceID );
        }
 
-mDNSexport void mDNSPlatformSetLocalARP( const mDNSv4Addr * const tpa, const mDNSEthAddr * const tha, mDNSInterfaceID InterfaceID )
+mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
        {
        DEBUG_UNUSED( tpa );
        DEBUG_UNUSED( tha );
@@ -1562,14 +1669,32 @@ mDNSexport void mDNSPlatformSetLocalARP( const mDNSv4Addr * const tpa, const mDN
 
 mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg)
        {
-       fprintf( stderr, msg );
+       dlog( kDebugLevelInfo, "%s\n", msg );
        }
 
-mDNSexport void mDNSPlatformWriteLogMsg( const char * ident, const char * msg, int flags )
+mDNSexport void mDNSPlatformWriteLogMsg( const char * ident, const char * msg, mDNSLogLevel_t loglevel )
        {
+       extern mDNS mDNSStorage;
+       int type;
+       
        DEBUG_UNUSED( ident );
-       DEBUG_UNUSED( msg );
-       DEBUG_UNUSED( flags );
+
+       type = EVENTLOG_ERROR_TYPE;
+
+       switch (loglevel) 
+       {
+               case MDNS_LOG_MSG:       type = EVENTLOG_ERROR_TYPE;            break;
+               case MDNS_LOG_OPERATION: type = EVENTLOG_WARNING_TYPE;          break;
+               case MDNS_LOG_SPS:       type = EVENTLOG_INFORMATION_TYPE;  break;
+               case MDNS_LOG_INFO:      type = EVENTLOG_INFORMATION_TYPE;      break;
+               case MDNS_LOG_DEBUG:     type = EVENTLOG_INFORMATION_TYPE;      break;
+               default:
+                       fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel);
+                       fflush(stderr);
+                       }
+
+       mDNSStorage.p->reportStatusFunc( type, msg );
+       dlog( kDebugLevelInfo, "%s\n", msg );
        }
 
 mDNSexport void mDNSPlatformSourceAddrForDest( mDNSAddr * const src, const mDNSAddr * const dst )
@@ -1676,9 +1801,9 @@ exit:
 //===========================================================================================================================
 
 // This routine needs to be called whenever the system secrets database changes.
-// We call it from ProcessingThreadDynDNSConfigChanged and mDNSPlatformInit
+// We call it from DynDNSConfigDidChange and mDNSPlatformInit
 
-mDNSlocal void
+void
 SetDomainSecrets( mDNS * const m )
 {
        DomainAuthInfo *ptr;
@@ -2038,6 +2163,11 @@ mDNSPlatformGetPrimaryInterface( mDNS * const m, mDNSAddr * v4, mDNSAddr * v6, m
                {
                        // Found one that will work
 
+                       if ( pAdapter->AddressLength == sizeof( m->PrimaryMAC ) )
+                       {
+                               memcpy( &m->PrimaryMAC, pAdapter->Address, pAdapter->AddressLength );
+                       }
+
                        found = TRUE;
                        break;
                }
@@ -2061,7 +2191,6 @@ exit:
 //===========================================================================================================================
 //     debugf_
 //===========================================================================================================================
-
 #if( MDNS_DEBUGMSGS )
 mDNSexport void        debugf_( const char *inFormat, ... )
 {
@@ -2096,108 +2225,27 @@ mDNSexport void        verbosedebugf_( const char *inFormat, ... )
 }
 #endif
 
-//===========================================================================================================================
-//     LogMsg
-//===========================================================================================================================
-
-/*
-mDNSexport void        LogMsg( const char *inFormat, ... )
-{
-       char            buffer[ 512 ];
-    va_list            args;
-    mDNSu32            length;
-       
-       va_start( args, inFormat );
-       length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
-       va_end( args );
-       
-       dlog( kDebugLevelWarning, "%s\n", buffer );
-}
-*/
 
 #if 0
 #pragma mark -
 #pragma mark == Platform Internals  ==
 #endif
 
-//===========================================================================================================================
-//     SetupSynchronizationObjects
-//===========================================================================================================================
-
-mDNSlocal mStatus      SetupSynchronizationObjects( mDNS * const inMDNS )
-{
-       mStatus         err;
-               
-       InitializeCriticalSection( &inMDNS->p->lock );
-       inMDNS->p->lockInitialized = mDNStrue;
-       
-       inMDNS->p->cancelEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-       err = translate_errno( inMDNS->p->cancelEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       
-       inMDNS->p->quitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-       err = translate_errno( inMDNS->p->quitEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       
-       inMDNS->p->interfaceListChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-       err = translate_errno( inMDNS->p->interfaceListChangedEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       
-       inMDNS->p->wakeupEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-       err = translate_errno( inMDNS->p->wakeupEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       
-exit:
-       if( err )
-       {
-               TearDownSynchronizationObjects( inMDNS );
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     TearDownSynchronizationObjects
-//===========================================================================================================================
-
-mDNSlocal mStatus      TearDownSynchronizationObjects( mDNS * const inMDNS )
-{
-       if( inMDNS->p->quitEvent )
-       {
-               CloseHandle( inMDNS->p->quitEvent );
-               inMDNS->p->quitEvent = 0;
-       }
-       if( inMDNS->p->cancelEvent )
-       {
-               CloseHandle( inMDNS->p->cancelEvent );
-               inMDNS->p->cancelEvent = 0;
-       }
-       if( inMDNS->p->interfaceListChangedEvent )
-       {
-               CloseHandle( inMDNS->p->interfaceListChangedEvent );
-               inMDNS->p->interfaceListChangedEvent = 0;
-       }
-       if( inMDNS->p->wakeupEvent )
-       {
-               CloseHandle( inMDNS->p->wakeupEvent );
-               inMDNS->p->wakeupEvent = 0;
-       }
-       if( inMDNS->p->lockInitialized )
-       {
-               DeleteCriticalSection( &inMDNS->p->lock );
-               inMDNS->p->lockInitialized = mDNSfalse;
-       }
-       return( mStatus_NoError );
-}
-
 
 //===========================================================================================================================
 //     SetupNiceName
 //===========================================================================================================================
 
-mDNSlocal mStatus      SetupNiceName( mDNS * const inMDNS )
+mStatus        SetupNiceName( mDNS * const inMDNS )
 {
-       mStatus         err = 0;
+       HKEY            descKey = NULL;
        char            utf8[ 256 ];
+       LPCTSTR         s;
+       LPWSTR          joinName;
+       NETSETUP_JOIN_STATUS joinStatus;
+       mStatus         err = 0;
+       DWORD           namelen;
+       BOOL            ok;
        
        check( inMDNS );
        
@@ -2205,26 +2253,17 @@ mDNSlocal mStatus       SetupNiceName( mDNS * const inMDNS )
        utf8[0] = '\0';
 
        // First try and open the registry key that contains the computer description value
-       if (inMDNS->p->descKey == NULL)
-       {
-               LPCTSTR s = TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
-               err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s, 0, KEY_READ, &inMDNS->p->descKey);
-               check_translated_errno( err == 0, errno_compat(), kNameErr );
-
-               if (err)
-               {
-                       inMDNS->p->descKey = NULL;
-               }
-       }
+       s = TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
+       err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s, 0, KEY_READ, &descKey);
+       check_translated_errno( err == 0, errno_compat(), kNameErr );
 
-       // if we opened it...
-       if (inMDNS->p->descKey != NULL)
+       if ( !err )
        {
                TCHAR   desc[256];
                DWORD   descSize = sizeof( desc );
 
                // look for the computer description
-               err = RegQueryValueEx(inMDNS->p->descKey, TEXT("srvcomment"), 0, NULL, (LPBYTE) &desc, &descSize);
+               err = RegQueryValueEx( descKey, TEXT("srvcomment"), 0, NULL, (LPBYTE) &desc, &descSize);
                
                if ( !err )
                {
@@ -2241,10 +2280,10 @@ mDNSlocal mStatus       SetupNiceName( mDNS * const inMDNS )
        if ( err || ( utf8[ 0 ] == '\0' ) )
        {
                TCHAR hostname[256];
-               DWORD hostnameLen = sizeof( hostname ) / sizeof( TCHAR );
-               BOOL  ok;
+               
+               namelen = sizeof( hostname ) / sizeof( TCHAR );
 
-               ok = GetComputerNameExW( ComputerNamePhysicalDnsHostname, hostname, &hostnameLen );
+               ok = GetComputerNameExW( ComputerNamePhysicalDnsHostname, hostname, &namelen );
                err = translate_errno( ok, (mStatus) GetLastError(), kNameErr );
                check_noerr( err );
                
@@ -2273,6 +2312,36 @@ mDNSlocal mStatus        SetupNiceName( mDNS * const inMDNS )
        
        dlog( kDebugLevelInfo, DEBUG_NAME "nice name \"%.*s\"\n", inMDNS->nicelabel.c[ 0 ], &inMDNS->nicelabel.c[ 1 ] );
        
+       if ( descKey )
+       {
+               RegCloseKey( descKey );
+       }
+
+       ZeroMemory( inMDNS->p->nbname, sizeof( inMDNS->p->nbname ) );
+       ZeroMemory( inMDNS->p->nbdomain, sizeof( inMDNS->p->nbdomain ) );
+
+       namelen = sizeof( inMDNS->p->nbname );
+       ok = GetComputerNameExA( ComputerNamePhysicalNetBIOS, inMDNS->p->nbname, &namelen );
+       check( ok );
+       if ( ok ) dlog( kDebugLevelInfo, DEBUG_NAME "netbios name \"%s\"\n", inMDNS->p->nbname );
+
+       err = NetGetJoinInformation( NULL, &joinName, &joinStatus );
+       check ( err == NERR_Success );
+       if ( err == NERR_Success )
+       {
+               if ( ( joinStatus == NetSetupWorkgroupName ) || ( joinStatus == NetSetupDomainName ) )
+               {
+                       err = TCHARtoUTF8( joinName, inMDNS->p->nbdomain, sizeof( inMDNS->p->nbdomain ) );
+                       check( !err );
+                       if ( !err ) dlog( kDebugLevelInfo, DEBUG_NAME "netbios domain/workgroup \"%s\"\n", inMDNS->p->nbdomain );
+               }
+
+               NetApiBufferFree( joinName );
+               joinName = NULL;
+       }
+
+       err = 0;
+
        return( err );
 }
 
@@ -2354,7 +2423,7 @@ mDNSlocal mStatus SetupName( mDNS * const inMDNS )
 //     SetupInterfaceList
 //===========================================================================================================================
 
-mDNSlocal mStatus      SetupInterfaceList( mDNS * const inMDNS )
+mStatus        SetupInterfaceList( mDNS * const inMDNS )
 {
        mStatus                                         err;
        mDNSInterfaceData **            next;
@@ -2375,8 +2444,7 @@ mDNSlocal mStatus SetupInterfaceList( mDNS * const inMDNS )
        check( inMDNS->p );
        
        inMDNS->p->registeredLoopback4  = mDNSfalse;
-       inMDNS->p->nextDHCPLeaseExpires = 0xFFFFFFFF;
-       inMDNS->p->womp                                 = mDNSfalse;
+       inMDNS->p->nextDHCPLeaseExpires = 0x7FFFFFFF;
        addrs                                                   = NULL;
        foundv4                                                 = mDNSfalse;
        foundv6                                                 = mDNSfalse;
@@ -2391,12 +2459,7 @@ mDNSlocal mStatus        SetupInterfaceList( mDNS * const inMDNS )
        
        err = SetupName( inMDNS );
        check_noerr( err );
-       
-       // Set up the interface list change notification.
-       
-       err = SetupNotifications( inMDNS );
-       check_noerr( err );
-       
+
        // Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
        // can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
        
@@ -2453,7 +2516,7 @@ mDNSlocal mStatus SetupInterfaceList( mDNS * const inMDNS )
 
                if ( !foundUnicastSock4DestAddr )
                {
-                       inMDNS->p->unicastSock4DestAddr = ifd->interfaceInfo.ip;
+                       inMDNS->p->unicastSock4.addr = ifd->interfaceInfo.ip;
                        foundUnicastSock4DestAddr = TRUE;
                }
                        
@@ -2503,7 +2566,7 @@ mDNSlocal mStatus SetupInterfaceList( mDNS * const inMDNS )
 
                if ( !foundUnicastSock6DestAddr )
                {
-                       inMDNS->p->unicastSock6DestAddr = ifd->interfaceInfo.ip;
+                       inMDNS->p->unicastSock6.addr = ifd->interfaceInfo.ip;
                        foundUnicastSock6DestAddr = TRUE;
                }
 
@@ -2557,7 +2620,7 @@ mDNSlocal mStatus SetupInterfaceList( mDNS * const inMDNS )
 
                if ( !foundUnicastSock4DestAddr )
                {
-                       inMDNS->p->unicastSock4DestAddr = ifd->defaultAddr;
+                       inMDNS->p->unicastSock4.addr = ifd->sock.addr;
                        foundUnicastSock4DestAddr = TRUE;
                }
 #endif
@@ -2585,7 +2648,7 @@ mDNSlocal mStatus SetupInterfaceList( mDNS * const inMDNS )
 
                if ( !foundUnicastSock6DestAddr )
                {
-                       inMDNS->p->unicastSock6DestAddr = ifd->defaultAddr;
+                       inMDNS->p->unicastSock6.addr = ifd->sock.addr;
                        foundUnicastSock6DestAddr = TRUE;
                }
 #endif
@@ -2595,6 +2658,8 @@ mDNSlocal mStatus SetupInterfaceList( mDNS * const inMDNS )
                ++inMDNS->p->interfaceCount;
        }
 
+       CheckFileShares( inMDNS );
+
 exit:
        if( err )
        {
@@ -2612,15 +2677,18 @@ exit:
 //     TearDownInterfaceList
 //===========================================================================================================================
 
-mDNSlocal mStatus      TearDownInterfaceList( mDNS * const inMDNS )
+mStatus        TearDownInterfaceList( mDNS * const inMDNS )
 {
-       mStatus                                 err;
        mDNSInterfaceData **            p;
        mDNSInterfaceData *             ifd;
        
        dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list\n" );
        check( inMDNS );
        check( inMDNS->p );
+
+       // Free any pending events received.
+
+       FreeSocketEvents( inMDNS );
        
        // Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
        // Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
@@ -2638,14 +2706,10 @@ mDNSlocal mStatus       TearDownInterfaceList( mDNS * const inMDNS )
                
                dlog( kDebugLevelInfo, DEBUG_NAME "freeing unreferenced, inactive interface %#p %#a\n", ifd, &ifd->interfaceInfo.ip );
                *p = ifd->next;
-               free( ifd );
+
+               QueueUserAPC( ( PAPCFUNC ) FreeInterface, inMDNS->p->mainThread, ( ULONG_PTR ) ifd );
        }
-       
-       // Tear down interface list change notifications.
-       
-       err = TearDownNotifications( inMDNS );
-       check_noerr( err );
-       
+
        // Tear down all the interfaces.
        
        while( inMDNS->p->interfaceList )
@@ -2669,7 +2733,6 @@ mDNSlocal mStatus SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inI
 {
        mDNSInterfaceData       *       ifd;
        mDNSInterfaceData       *       p;
-       SocketRef                               sock;
        mStatus                                 err;
        
        ifd = NULL;
@@ -2684,7 +2747,10 @@ mDNSlocal mStatus        SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inI
        
        ifd = (mDNSInterfaceData *) calloc( 1, sizeof( *ifd ) );
        require_action( ifd, exit, err = mStatus_NoMemoryErr );
-       ifd->sock               = kInvalidSocketRef;
+       ifd->sock.fd    = kInvalidSocketRef;
+       ifd->sock.ifd   = ifd;
+       ifd->sock.next  = NULL;
+       ifd->sock.m             = inMDNS;
        ifd->index              = inIFA->ifa_extra.index;
        ifd->scopeID    = inIFA->ifa_extra.index;
        check( strlen( inIFA->ifa_name ) < sizeof( ifd->name ) );
@@ -2733,43 +2799,21 @@ mDNSlocal mStatus       SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inI
        
        if( ifd->interfaceInfo.McastTxRx )
        {
-               err = SetupSocket( inMDNS, inIFA->ifa_addr, MulticastDNSPort, &sock );
+               DWORD size;
+                       
+               err = SetupSocket( inMDNS, inIFA->ifa_addr, MulticastDNSPort, &ifd->sock.fd );
                require_noerr( err, exit );
-               ifd->sock = sock;
-               ifd->defaultAddr = ( inIFA->ifa_addr->sa_family == AF_INET6 ) ? AllDNSLinkGroup_v6 : AllDNSLinkGroup_v4;
+               ifd->sock.addr = ( inIFA->ifa_addr->sa_family == AF_INET6 ) ? AllDNSLinkGroup_v6 : AllDNSLinkGroup_v4;
+               ifd->sock.port = MulticastDNSPort;
                
                // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
 
-               #if( !TARGET_OS_WINDOWS_CE )
-               {
-                       DWORD size;
-                       
-                       err = WSAIoctl( sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ),
-                                       &ifd->wsaRecvMsgFunctionPtr, sizeof( ifd->wsaRecvMsgFunctionPtr ), &size, NULL, NULL );
+               err = WSAIoctl( ifd->sock.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &ifd->sock.recvMsgPtr, sizeof( ifd->sock.recvMsgPtr ), &size, NULL, NULL );
 
-                       if ( err )
-                       {
-                               ifd->wsaRecvMsgFunctionPtr = NULL;
-                       }
+               if ( err )
+               {
+                       ifd->sock.recvMsgPtr = NULL;
                }
-               #endif
-
-               // Set up the read pending event and associate it so we can block until data is available for this socket.
-               
-               ifd->readPendingEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-               err = translate_errno( ifd->readPendingEvent, (mStatus) GetLastError(), kUnknownErr );
-               require_noerr( err, exit );
-               
-               err = WSAEventSelect( ifd->sock, ifd->readPendingEvent, FD_READ );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               // Create a placeholder event so WaitForMultipleObjects Handle slot for this interface is valid.
-               
-               ifd->readPendingEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-               err = translate_errno( ifd->readPendingEvent, (mStatus) GetLastError(), kUnknownErr );
-               require_noerr( err, exit );
        }
 
        if ( inIFA->ifa_dhcpEnabled && ( inIFA->ifa_dhcpLeaseExpires < inMDNS->p->nextDHCPLeaseExpires ) )
@@ -2779,11 +2823,6 @@ mDNSlocal mStatus        SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inI
 
        ifd->interfaceInfo.NetWake = inIFA->ifa_womp;
 
-       if ( ifd->interfaceInfo.NetWake )
-       {
-               inMDNS->p->womp = TRUE;
-       }
-
        // Register this interface with mDNS.
        
        err = SockAddrToMDNSAddr( inIFA->ifa_addr, &ifd->interfaceInfo.ip, NULL );
@@ -2791,10 +2830,18 @@ mDNSlocal mStatus       SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inI
        
        err = SockAddrToMDNSAddr( inIFA->ifa_netmask, &ifd->interfaceInfo.mask, NULL );
        require_noerr( err, exit );
+
+       memcpy( ifd->interfaceInfo.MAC.b, inIFA->ifa_physaddr, sizeof( ifd->interfaceInfo.MAC.b ) );
        
        ifd->interfaceInfo.Advertise = ( mDNSu8 ) inMDNS->AdvertiseLocalAddresses;
-       
-       err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, mDNSfalse );
+
+       if ( ifd->sock.fd != kInvalidSocketRef )
+       {
+               err = UDPBeginRecv( &ifd->sock );
+               require_noerr( err, exit );
+       }
+
+       err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, mDNSfalse );
        require_noerr( err, exit );
        ifd->hostRegistered = mDNStrue;
        
@@ -2820,9 +2867,7 @@ exit:
 //===========================================================================================================================
 
 mDNSlocal mStatus      TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD )
-{
-       SocketRef               sock;
-       
+{      
        check( inMDNS );
        check( inIFD );
        
@@ -2838,17 +2883,10 @@ mDNSlocal mStatus       TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inI
        
        // Tear down the multicast socket.
        
-       if( inIFD->readPendingEvent )
-       {
-               CloseHandle( inIFD->readPendingEvent );
-               inIFD->readPendingEvent = 0;
-       }
-       
-       sock = inIFD->sock;
-       inIFD->sock = kInvalidSocketRef;
-       if( IsValidSocket( sock ) )
+       if ( inIFD->sock.fd != INVALID_SOCKET )
        {
-               close_compat( sock );
+               closesocket( inIFD->sock.fd );
+               inIFD->sock.fd = INVALID_SOCKET;
        }
        
        // If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps 
@@ -2863,11 +2901,17 @@ mDNSlocal mStatus       TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inI
        else
        {
                dlog( kDebugLevelInfo, DEBUG_NAME "freeing interface %#p %#a immediately\n", inIFD, &inIFD->interfaceInfo.ip );
-               free( inIFD );
+               QueueUserAPC( ( PAPCFUNC ) FreeInterface, inMDNS->p->mainThread, ( ULONG_PTR ) inIFD );
        }
+
        return( mStatus_NoError );
 }
 
+mDNSlocal void CALLBACK FreeInterface( mDNSInterfaceData *inIFD )
+{
+       free( inIFD );
+}
+
 //===========================================================================================================================
 //     SetupSocket
 //===========================================================================================================================
@@ -2877,6 +2921,8 @@ mDNSlocal mStatus SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAdd
        mStatus                 err;
        SocketRef               sock;
        int                             option;
+       DWORD                   bytesReturned = 0;
+       BOOL                    behavior = FALSE;
        
        DEBUG_UNUSED( inMDNS );
        
@@ -2899,7 +2945,28 @@ mDNSlocal mStatus        SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAdd
                err = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
                check_translated_errno( err == 0, errno_compat(), kOptionErr );
        }
-       
+
+       // <rdar://problem/7894393> Bonjour for Windows broken on Windows XP
+       //
+       // Not sure why, but the default behavior for sockets is to behave incorrectly
+       // when using them in Overlapped I/O mode on XP. According to MSDN:
+       //
+       // SIO_UDP_CONNRESET (opcode setting: I, T==3)
+       //     Windows XP:  Controls whether UDP PORT_UNREACHABLE messages are reported. Set to TRUE to enable reporting.
+       //     Set to FALSE to disable reporting.
+       //
+       // Packet traces from misbehaving Bonjour installations showed that ICMP port unreachable
+       // messages were being sent to us after we sent out packets to a multicast address. This is clearly
+       // incorrect behavior, but should be harmless. However, after receiving a port unreachable error, WinSock
+       // will no longer receive any packets from that socket, which is not harmless. This behavior is only
+       // seen on XP.
+       //
+       // So we turn off port unreachable reporting to make sure our sockets that are reading
+       // multicast packets function correctly under all circumstances.
+
+       err = WSAIoctl( sock, SIO_UDP_CONNRESET, &behavior, sizeof(behavior), NULL, 0, &bytesReturned, NULL, NULL );
+       check_translated_errno( err == 0, errno_compat(), kOptionErr );
+
        if( inAddr->sa_family == AF_INET )
        {
                mDNSv4Addr                              ipv4;
@@ -3098,800 +3165,286 @@ mDNSlocal mStatus     SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAd
        return( err );
 }
 
+
+#if 0
+#pragma mark -
+#endif
+
 //===========================================================================================================================
-//     SetupNotifications
+//     UDPBeginRecv
 //===========================================================================================================================
 
-mDNSlocal mStatus      SetupNotifications( mDNS * const inMDNS )
+mDNSlocal OSStatus UDPBeginRecv( UDPSocket * sock )
 {
-       mStatus                         err;
-       SocketRef                       sock;
-       unsigned long           param;
-       int                                     inBuffer;
-       int                                     outBuffer;
-       DWORD                           outSize;
-       
-       // Register to listen for address list changes.
-       
-       sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
-       err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
-       require_noerr( err, exit );
-       inMDNS->p->interfaceListChangedSocket = sock;
-       
-       // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event 
-       // when a change to the interface list is detected.
-       
-       param = 1;
-       err = ioctlsocket( sock, FIONBIO, &param );
-       err = translate_errno( err == 0, errno_compat(), kUnknownErr );
-       require_noerr( err, exit );
-       
-       inBuffer        = 0;
-       outBuffer       = 0;
-       err = WSAIoctl( sock, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
-       if( err < 0 )
-       {
-               check( errno_compat() == WSAEWOULDBLOCK );
-       }
-       
-       err = WSAEventSelect( sock, inMDNS->p->interfaceListChangedEvent, FD_ADDRESS_LIST_CHANGE );
-       err = translate_errno( err == 0, errno_compat(), kUnknownErr );
-       require_noerr( err, exit );
-
-       inMDNS->p->descChangedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-       err = translate_errno( inMDNS->p->descChangedEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-       if (inMDNS->p->descKey != NULL)
-       {
-               err = RegNotifyChangeKeyValue(inMDNS->p->descKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->descChangedEvent, TRUE);
-               require_noerr( err, exit );
-       }
-
-       // This will catch all changes to tcp/ip networking, including changes to the domain search list
-
-       inMDNS->p->tcpipChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-       err = translate_errno( inMDNS->p->tcpipChangedEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &inMDNS->p->tcpipKey );
-       require_noerr( err, exit );
-
-       err = RegNotifyChangeKeyValue(inMDNS->p->tcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->tcpipChangedEvent, TRUE);
-       require_noerr( err, exit );
-
-       // This will catch all changes to ddns configuration
+       DWORD           size;
+       DWORD           numTries;
+       OSStatus        err;
 
-       inMDNS->p->ddnsChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-       err = translate_errno( inMDNS->p->ddnsChangedEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
+       require_action( socket != NULL, exit, err = kUnknownErr );
 
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup"), &inMDNS->p->ddnsKey );
-       require_noerr( err, exit );
+       // Initialize the buffer structure
 
-       err = RegNotifyChangeKeyValue(inMDNS->p->ddnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->ddnsChangedEvent, TRUE);
-       require_noerr( err, exit );
+       sock->wbuf.buf          = (char *) &sock->packet;
+       sock->wbuf.len          = (u_long) sizeof( sock->packet );
+       sock->srcAddrLen        = sizeof( sock->srcAddr );
 
-       // This will catch all changes to file sharing
+       // Initialize the overlapped structure
 
-       inMDNS->p->fileShareEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-       err = translate_errno( inMDNS->p->fileShareEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
+       ZeroMemory( &sock->overlapped, sizeof( OVERLAPPED ) );
+       sock->overlapped.hEvent = sock;
 
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\Shares"), &inMDNS->p->fileShareKey );
-       require_noerr( err, exit );
+       numTries = 0;
 
-       err = RegNotifyChangeKeyValue(inMDNS->p->fileShareKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->fileShareEvent, TRUE);
-       require_noerr( err, exit );
+       do
+       {
+               if ( sock->recvMsgPtr )
+               {
+                       sock->wmsg.name                         = ( LPSOCKADDR ) &sock->srcAddr;
+                       sock->wmsg.namelen                      = sock->srcAddrLen;
+                       sock->wmsg.lpBuffers            = &sock->wbuf;
+                       sock->wmsg.dwBufferCount        = 1;
+                       sock->wmsg.Control.buf          = ( CHAR* ) sock->controlBuffer;
+                       sock->wmsg.Control.len          = sizeof( sock->controlBuffer );
+                       sock->wmsg.dwFlags                      = 0;
+
+                       err = sock->recvMsgPtr( sock->fd, &sock->wmsg, &size, &sock->overlapped, ( LPWSAOVERLAPPED_COMPLETION_ROUTINE ) UDPEndRecv );
+                       err = translate_errno( ( err == 0 ) || ( WSAGetLastError() == WSA_IO_PENDING ), (OSStatus) WSAGetLastError(), kUnknownErr ); 
+
+                       // <rdar://problem/7824093> iTunes 9.1 fails to install with Bonjour service on Windows 7 Ultimate
+                       //
+                       // There seems to be a bug in some network device drivers that involves calling WSARecvMsg() in
+                       // overlapped i/o mode. Although all the parameters to WSARecvMsg() are correct, it returns a
+                       // WSAEFAULT error code when there is no actual error. We have found experientially that falling
+                       // back to using WSARecvFrom() when this happens will work correctly.
 
-       // This will catch changes to the Windows firewall
+                       if ( err == WSAEFAULT ) sock->recvMsgPtr = NULL;
+               }
+               else
+               {
+                       DWORD flags = 0;
 
-       inMDNS->p->firewallEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-       err = translate_errno( inMDNS->p->firewallEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
+                       err = WSARecvFrom( sock->fd, &sock->wbuf, 1, NULL, &flags, ( LPSOCKADDR ) &sock->srcAddr, &sock->srcAddrLen, &sock->overlapped, ( LPWSAOVERLAPPED_COMPLETION_ROUTINE ) UDPEndRecv );
+                       err = translate_errno( ( err == 0 ) || ( WSAGetLastError() == WSA_IO_PENDING ), ( OSStatus ) WSAGetLastError(), kUnknownErr );
+               }
 
-       // Just to make sure that initialization doesn't fail on some old OS
-       // that doesn't have this key, we'll only add the notification if
-       // the key exists.
+               // According to MSDN <http://msdn.microsoft.com/en-us/library/ms741687(VS.85).aspx>:
+               //
+               // "WSAECONNRESET: For a UDP datagram socket, this error would indicate that a previous
+               //                 send operation resulted in an ICMP "Port Unreachable" message."
+               //
+               // Because this is the case, we want to ignore this error and try again.  Just in case
+               // this is some kind of pathological condition, we'll break out of the retry loop 
+               // after 100 iterations
 
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\FirewallRules"), &inMDNS->p->firewallKey );
-       
-       if ( !err )
-       {
-               err = RegNotifyChangeKeyValue(inMDNS->p->firewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->firewallEvent, TRUE);
-               require_noerr( err, exit );
-       }
-       else
-       {
-               err = mStatus_NoError;
+               require_action( !err || ( err == WSAECONNRESET ) || ( err == WSAEFAULT ), exit, err = WSAGetLastError() );
        }
+       while ( ( ( err == WSAECONNRESET ) || ( err == WSAEFAULT ) ) && ( numTries++ < 100 ) );
 
 exit:
-       if( err )
+
+       if ( err )
        {
-               TearDownNotifications( inMDNS );
+               LogMsg( "WSARecvMsg failed (%d)\n", err );
        }
-       return( err );
+
+       return err;
 }
 
+
 //===========================================================================================================================
-//     TearDownNotifications
+//     UDPEndRecv
 //===========================================================================================================================
 
-mDNSlocal mStatus      TearDownNotifications( mDNS * const inMDNS )
+mDNSlocal void CALLBACK UDPEndRecv( DWORD err, DWORD bytesTransferred, LPWSAOVERLAPPED overlapped, DWORD flags )
 {
-       if( IsValidSocket( inMDNS->p->interfaceListChangedSocket ) )
-       {
-               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->tcpipChangedEvent != NULL )
-       {
-               CloseHandle( inMDNS->p->tcpipChangedEvent );
-               inMDNS->p->tcpipChangedEvent = NULL;
-       }
-
-       if ( inMDNS->p->ddnsChangedEvent != NULL )
-       {
-               CloseHandle( inMDNS->p->ddnsChangedEvent );
-               inMDNS->p->ddnsChangedEvent = NULL;
-       }
-
-       if ( inMDNS->p->ddnsKey != NULL )
-       {
-               RegCloseKey( inMDNS->p->ddnsKey );
-               inMDNS->p->ddnsKey = NULL;
-       }
+       UDPSocket * sock = NULL;
 
-       if ( inMDNS->p->fileShareEvent != NULL )
-       {
-               CloseHandle( inMDNS->p->fileShareEvent );
-               inMDNS->p->fileShareEvent = NULL;
-       }
+       ( void ) flags;
 
-       if ( inMDNS->p->fileShareKey != NULL )
-       {
-               RegCloseKey( inMDNS->p->fileShareKey );
-               inMDNS->p->fileShareKey = NULL;
-       }
+       require_action_quiet( err != WSA_OPERATION_ABORTED, exit, err = ( DWORD ) kUnknownErr );
+       require_noerr( err, exit );
+       sock = ( overlapped != NULL ) ? overlapped->hEvent : NULL;
+       require_action( sock != NULL, exit, err = ( DWORD ) kUnknownErr );
 
-       if ( inMDNS->p->firewallEvent != NULL )
-       {
-               CloseHandle( inMDNS->p->firewallEvent );
-               inMDNS->p->firewallEvent = NULL;
-       }
+       // If we've closed the socket, then we want to ignore
+       // this read.  The packet might have been queued before
+       // the socket was closed.
 
-       if ( inMDNS->p->firewallKey != NULL )
+       if ( sock->fd != INVALID_SOCKET )
        {
-               RegCloseKey( inMDNS->p->firewallKey );
-               inMDNS->p->firewallKey = NULL;
-       }
-
-       return( mStatus_NoError );
-}
-
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-//     SetupThread
-//===========================================================================================================================
-
-mDNSlocal mStatus      SetupThread( mDNS * const inMDNS )
-{
-       mStatus                 err;
-       HANDLE                  threadHandle;
-       unsigned                threadID;
-       DWORD                   result;
+               const mDNSInterfaceID   iid = sock->ifd ? sock->ifd->interfaceInfo.InterfaceID : NULL;
+               mDNSAddr                                srcAddr;
+               mDNSIPPort                              srcPort;
+               mDNSAddr                                dstAddr;
+               mDNSIPPort                              dstPort;
+               mDNSu8                          *       end;
        
-       dlog( kDebugLevelTrace, DEBUG_NAME "setting up thread\n" );
-       
-       // To avoid a race condition with the thread ID needed by the unlocking code, we need to make sure the
-       // thread has fully initialized. To do this, we create the thread then wait for it to signal it is ready.
-       
-       inMDNS->p->initEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-       err = translate_errno( inMDNS->p->initEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
+               // Translate the source of this packet into mDNS data types
 
-       inMDNS->p->initStatus = mStatus_Invalid;
+               SockAddrToMDNSAddr( (struct sockaddr *) &sock->srcAddr, &srcAddr, &srcPort );
        
-       // Create thread with _beginthreadex() instead of CreateThread() to avoid memory leaks when using static run-time 
-       // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
-       
-       threadHandle = (HANDLE) _beginthreadex_compat( NULL, 0, ProcessingThread, inMDNS, 0, &threadID );
-       err = translate_errno( threadHandle, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-               
-       result = WaitForSingleObject( inMDNS->p->initEvent, INFINITE );
-       err = translate_errno( result == WAIT_OBJECT_0, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       err = inMDNS->p->initStatus;
-       require_noerr( err, exit );
-       
-exit:
-       if( inMDNS->p->initEvent )
-       {
-               CloseHandle( inMDNS->p->initEvent );
-               inMDNS->p->initEvent = 0;
-       }
-       dlog( kDebugLevelTrace, DEBUG_NAME "setting up thread done (err=%d %m)\n", err, err );
-       return( err );
-}
+               // Initialize the destination of this packet. Just in case
+               // we can't determine this info because we couldn't call
+               // WSARecvMsg (recvMsgPtr)
 
-//===========================================================================================================================
-//     TearDownThread
-//===========================================================================================================================
+               dstAddr = sock->addr;
+               dstPort = sock->port;
 
-mDNSlocal mStatus      TearDownThread( const mDNS * const inMDNS )
-{
-       // Signal the cancel event to cause the thread to exit. Then wait for the quit event to be signal indicating it did 
-       // exit. If the quit event is not signal in 5 seconds, just give up and close anyway sinec the thread is probably hung.
-       
-       if( inMDNS->p->cancelEvent )
-       {
-               BOOL            wasSet;
-               DWORD           result;
-               
-               wasSet = SetEvent( inMDNS->p->cancelEvent );
-               check_translated_errno( wasSet, GetLastError(), kUnknownErr );
-               
-               if( inMDNS->p->quitEvent )
+               if ( sock->recvMsgPtr )
                {
-                       result = WaitForSingleObject( inMDNS->p->quitEvent, 5 * 1000 );
-                       check_translated_errno( result == WAIT_OBJECT_0, GetLastError(), kUnknownErr );
-               }
-       }
-       return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-//     ProcessingThread
-//===========================================================================================================================
-
-mDNSlocal unsigned WINAPI      ProcessingThread( LPVOID inParam )
-{
-       mDNS *                  m;
-       int                             done;
-       mStatus                 err;
-       HANDLE *                waitList;
-       int                             waitListCount;
-       DWORD                   result;
-       BOOL                    wasSet;
-       
-       check( inParam );
-               
-       m = (mDNS *) inParam;
-       err = ProcessingThreadInitialize( m );
-       check( !err );
-       
-       done = 0;
-       while( !done )
-       {
-               // Set up the list of objects we'll be waiting on.
-               
-               waitList                = NULL;
-               waitListCount   = 0;
-               err = ProcessingThreadSetupWaitList( m, &waitList, &waitListCount );
-               require_noerr( err, exit );
+                       LPWSACMSGHDR    header;
+                       LPWSACMSGHDR    last = NULL;
+                       int                             count = 0;
                
-               // Main processing loop.
+                       // Parse the control information. Reject packets received on the wrong interface.
                
-               gWaitListChanged = FALSE;
-
-               for( ;; )
-               {
-                       // Give the mDNS core a chance to do its work and determine next event time.
-                       
-                       mDNSs32 interval = mDNS_Execute(m) - mDNS_TimeNow(m);
-
-                       if ( gWaitListChanged )
+                       // <rdar://problem/7832196> INSTALL: Bonjour 2.0 on Windows can not start / stop
+                       // 
+                       // There seems to be an interaction between Bullguard and this next bit of code.
+                       // When a user's machine is running Bullguard, the control information that is
+                       // returned is corrupted, and the code would go into an infinite loop. We'll add
+                       // two bits of defensive coding here. The first will check that each pointer to
+                       // the LPWSACMSGHDR that is returned in the for loop is different than the last.
+                       // This fixes the problem with Bullguard. The second will break out of this loop
+                       // after 100 iterations, just in case the corruption isn't caught by the first
+                       // check.
+
+                       for( header = WSA_CMSG_FIRSTHDR( &sock->wmsg ); header; header = WSA_CMSG_NXTHDR( &sock->wmsg, header ) )
                        {
-                               break;
-                       }
-
-                       if (m->p->idleThreadCallback)
-                       {
-                               interval = m->p->idleThreadCallback(m, interval);
-                       }
-                       if      (interval < 0)                                          interval = 0;
-                       else if (interval > (0x7FFFFFFF / 1000))        interval = 0x7FFFFFFF / mDNSPlatformOneSecond;
-                       else                                                                            interval = (interval * 1000) / mDNSPlatformOneSecond;
-                       
-                       // Wait until something occurs (e.g. cancel, incoming packet, or timeout).
-                                               
-                       result = WaitForMultipleObjects( (DWORD) waitListCount, waitList, FALSE, (DWORD) interval );
-                       check( result != WAIT_FAILED );
-
-                       if ( result != WAIT_FAILED )
-                       {
-                               if( result == WAIT_TIMEOUT )
-                               {
-                                       // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
-                                       
-                                       dlog( kDebugLevelChatty - 1, DEBUG_NAME "timeout\n" );
-                                       continue;
-                               }
-                               else if( result == kWaitListCancelEvent )
+                               if ( ( header != last ) && ( ++count < 100 ) )
                                {
-                                       // Cancel event. Set the done flag and break to exit.
+                                       last = header;
                                        
-                                       dlog( kDebugLevelVerbose, DEBUG_NAME "canceling...\n" );
-                                       done = 1;
-                                       break;
-                               }
-                               else if( result == kWaitListInterfaceListChangedEvent )
-                               {
-                                       // It would be nice to come up with a more elegant solution to this, but it seems that
-                                       // GetAdaptersAddresses doesn't always stay in sync after network changed events.  So as
-                                       // as a simple workaround, we'll pause for a couple of seconds before processing the change.
-
-                                       // We arrived at 2 secs by trial and error. We could reproduce the problem after sleeping
-                                       // for 500 msec and 750 msec, but couldn't after sleeping for 1 sec.  We added another
-                                       // second on top of that to account for machine load or some other exigency.
-
-                                       Sleep( 2000 );
-
-                                       // Interface list changed event. Break out of the inner loop to re-setup the wait list.
-                                       
-                                       ProcessingThreadInterfaceListChanged( m );
-                                       break;
-                               }
-                               else if( result == kWaitListWakeupEvent )
-                               {
-                                       // Wakeup event due to an mDNS API call. Loop back to call mDNS_Execute.
-                                       
-                                       dlog( kDebugLevelChatty - 1, DEBUG_NAME "wakeup for mDNS_Execute\n" );
-                                       continue;
-                               }
-                               else if ( result == kWaitListComputerDescriptionEvent )
-                               {
-                                       //
-                                       // The computer description might have changed
-                                       //
-                                       ProcessingThreadComputerDescriptionChanged( m );
-                                       break;
-                               }
-                               else if ( result == kWaitListTCPIPEvent )
-                               {       
-                                       //
-                                       // The TCP/IP might have changed
-                                       //
-                                       ProcessingThreadTCPIPConfigChanged( m );
-                                       break;
-                               }
-                               else if ( result == kWaitListDynDNSEvent )
-                               {
-                                       //
-                                       // The DynDNS config might have changed
-                                       //
-                                       ProcessingThreadDynDNSConfigChanged( m );
-                                       break;
-                               }
-                               else if ( result == kWaitListFileShareEvent )
-                               {
-                                       //
-                                       // File sharing changed
-                                       //
-                                       ProcessingThreadFileShareChanged( m );
-                                       break;
-                               }
-                               else if ( result == kWaitListFirewallEvent )
-                               {
-                                       //
-                                       // Firewall configuration changed
-                                       //
-                                       ProcessingThreadFirewallChanged( m );
-                               }
-                               else
-                               {
-                                       int             waitItemIndex;
-                                       
-                                       // Socket data available event. Determine which socket and process the packet.
+                                       if( ( header->cmsg_level == IPPROTO_IP ) && ( header->cmsg_type == IP_PKTINFO ) )
+                                       {
+                                               IN_PKTINFO * ipv4PacketInfo;
                                        
-                                       waitItemIndex = (int)( ( (int) result ) - WAIT_OBJECT_0 );
-                                       dlog( kDebugLevelChatty, DEBUG_NAME "socket data available on socket index %d\n", waitItemIndex );
-                                       check( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) );
+                                               ipv4PacketInfo = (IN_PKTINFO *) WSA_CMSG_DATA( header );
 
-                                       if( ( waitItemIndex >= 0 ) && ( waitItemIndex < waitListCount ) )
-                                       {
-                                               HANDLE                                  signaledObject;
-                                               int                                             n = 0;
-                                               mDNSInterfaceData       *       ifd;
-                                               TCPSocket *                     tcd;
-                                               UDPSocket *                     sock;
-                                               
-                                               signaledObject = waitList[ waitItemIndex ];
-       
-#if ( MDNS_WINDOWS_ENABLE_IPV4 )
-                                               if ( m->p->unicastSock4ReadEvent == signaledObject )
+                                               if ( sock->ifd != NULL )
                                                {
-                                                       ProcessingThreadProcessPacket( m, NULL, NULL, m->p->unicastSock4 );
-                                                       ++n;
+                                                       require_action( ipv4PacketInfo->ipi_ifindex == sock->ifd->index, exit, err = ( DWORD ) kMismatchErr );
                                                }
-#endif
+
+                                               dstAddr.type                            = mDNSAddrType_IPv4;
+                                               dstAddr.ip.v4.NotAnInteger      = ipv4PacketInfo->ipi_addr.s_addr;
+                                       }
+                                       else if( ( header->cmsg_level == IPPROTO_IPV6 ) && ( header->cmsg_type == IPV6_PKTINFO ) )
+                                       {
+                                               IN6_PKTINFO * ipv6PacketInfo;
                                                
-#if ( MDNS_WINDOWS_ENABLE_IPV6 )
-                                               if ( m->p->unicastSock6ReadEvent == signaledObject )
-                                               {
-                                                       ProcessingThreadProcessPacket( m, NULL, NULL, m->p->unicastSock6 );
-                                                       ++n;
-                                               }
-#endif
-                                       
-                                               for( ifd = m->p->interfaceList; ifd; ifd = ifd->next )
-                                               {
-                                                       if( ifd->readPendingEvent == signaledObject )
-                                                       {
-                                                               ProcessingThreadProcessPacket( m, ifd, NULL, ifd->sock );
-                                                               ++n;
-                                                       }
-                                               }
-       
-                                               for ( tcd = gTCPConnectionList; tcd; tcd = tcd->next )
-                                               {
-                                                       if ( tcd->pendingEvent == signaledObject )
-                                                       {
-                                                               mDNSBool connect = FALSE;
-       
-                                                               if ( !tcd->connected )
-                                                               {
-                                                                       tcd->connected  = mDNStrue;
-                                                                       connect                 = mDNStrue;
-                                                               }
-       
-                                                               tcd->callback( tcd, tcd->context, connect, 0 );
-       
-                                                               ++n;
-       
-                                                               break;
-                                                       }
-                                               }
-       
-                                               for ( sock = gUDPSocketList; sock; sock = sock->next )
+                                               ipv6PacketInfo = (IN6_PKTINFO *) WSA_CMSG_DATA( header );
+               
+                                               if ( sock->ifd != NULL )
                                                {
-                                                       if ( sock->readEvent == signaledObject )
-                                                       {
-                                                               ProcessingThreadProcessPacket( m, NULL, sock, sock->sock );
-       
-                                                               ++n;
-       
-                                                               break;
-                                                       }
+                                                       require_action( ipv6PacketInfo->ipi6_ifindex == ( sock->ifd->index - kIPv6IfIndexBase ), exit, err = ( DWORD ) kMismatchErr );
                                                }
 
-                                               check( n > 0 );
+                                               dstAddr.type    = mDNSAddrType_IPv6;
+                                               dstAddr.ip.v6   = *( (mDNSv6Addr *) &ipv6PacketInfo->ipi6_addr );
                                        }
-                                       else
+                               }
+                               else
+                               {
+                                       static BOOL loggedMessage = FALSE;
+
+                                       if ( !loggedMessage )
                                        {
-                                               // Unexpected wait result.
-                                       
-                                               dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, result );
+                                               LogMsg( "UDPEndRecv: WSARecvMsg control information error." );
+                                               loggedMessage = TRUE;
                                        }
+
+                                       break;
                                }
                        }
-                       else
-                       {
-                               Sleep( 3 * 1000 );
-                               err = ProcessingThreadInitialize( m );
-                               check( err );
-                               break;
-                       }
-               }
-               
-               // Release the wait list.
-               
-               if( waitList )
-               {
-                       free( waitList );
-                       waitList = NULL;
-                       waitListCount = 0;
                }
-       }
-       
-       // Signal the quit event to indicate that the thread is finished.
 
-exit:
-       wasSet = SetEvent( m->p->quitEvent );
-       check_translated_errno( wasSet, GetLastError(), kUnknownErr );
-       
-       // Call _endthreadex() explicitly instead of just exiting normally to avoid memory leaks when using static run-time
-       // libraries. See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
+               // Dispatch the packet to mDNS.
        
-       _endthreadex_compat( 0 );
-       return( 0 );
-}
-
-//===========================================================================================================================
-//     ProcessingThreadInitialize
-//===========================================================================================================================
-
-mDNSlocal mStatus ProcessingThreadInitialize( mDNS * const inMDNS )
-{
-       mStatus         err;
-       BOOL            wasSet;
+               dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
+               dlog( kDebugLevelChatty, DEBUG_NAME "    size      = %d\n", bytesTransferred );
+               dlog( kDebugLevelChatty, DEBUG_NAME "    src       = %#a:%u\n", &srcAddr, ntohs( srcPort.NotAnInteger ) );
+               dlog( kDebugLevelChatty, DEBUG_NAME "    dst       = %#a:%u\n", &dstAddr, ntohs( dstPort.NotAnInteger ) );
        
-       inMDNS->p->threadID = GetCurrentThreadId();
-
-       err = SetupInterfaceList( inMDNS );
-       require_noerr( err, exit );
-
-       err = uDNS_SetupDNSConfig( inMDNS );
-       require_noerr( err, exit );
-
-exit:
-
-       if( err )
-       {
-               TearDownInterfaceList( inMDNS );
-       }
-       inMDNS->p->initStatus = err;
-       
-       wasSet = SetEvent( inMDNS->p->initEvent );
-       check_translated_errno( wasSet, GetLastError(), kUnknownErr );
-       return( err );
-}
-
-//===========================================================================================================================
-//     ProcessingThreadSetupWaitList
-//===========================================================================================================================
-
-mDNSlocal mStatus      ProcessingThreadSetupWaitList( mDNS * const inMDNS, HANDLE **outWaitList, int *outWaitListCount )
-{
-       mStatus                                 err;
-       int                                             waitListCount;
-       HANDLE *                                waitList;
-       HANDLE *                                waitItemPtr;
-       mDNSInterfaceData       *       ifd;
-       TCPSocket *                     tcd;
-       UDPSocket *                     sock;
-       
-       dlog( kDebugLevelTrace, DEBUG_NAME "thread setting up wait list\n" );
-       check( inMDNS );
-       check( inMDNS->p );
-       check( outWaitList );
-       check( outWaitListCount );
-       
-       // Allocate an array to hold all the objects to wait on.
-       
-       waitListCount = kWaitListFixedItemCount + inMDNS->p->interfaceCount + gTCPConnections + gUDPSockets;
-       waitList = (HANDLE *) malloc( waitListCount * sizeof( *waitList ) );
-       require_action( waitList, exit, err = mStatus_NoMemoryErr );
-       waitItemPtr = waitList;
-       
-       // Add the fixed wait items to the beginning of the list.
-       
-       *waitItemPtr++ = inMDNS->p->cancelEvent;
-       *waitItemPtr++ = inMDNS->p->interfaceListChangedEvent;
-       *waitItemPtr++ = inMDNS->p->wakeupEvent;
-       *waitItemPtr++ = inMDNS->p->descChangedEvent;
-       *waitItemPtr++ = inMDNS->p->tcpipChangedEvent;
-       *waitItemPtr++ = inMDNS->p->ddnsChangedEvent;
-       *waitItemPtr++ = inMDNS->p->fileShareEvent;
-       *waitItemPtr++ = inMDNS->p->firewallEvent;
-       
-       // 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;
-       }
-
-       for ( tcd = gTCPConnectionList; tcd; tcd = tcd->next )
-       {
-               *waitItemPtr++ = tcd->pendingEvent;
-       }
-
-       for ( sock = gUDPSocketList; sock; sock = sock->next )
-       {
-               *waitItemPtr++ = sock->readEvent;
-       }
+               if ( sock->ifd != NULL )
+               {
+                       dlog( kDebugLevelChatty, DEBUG_NAME "    interface = %#a (index=0x%08X)\n", &sock->ifd->interfaceInfo.ip, sock->ifd->index );
+               }
 
-       check( (int)( waitItemPtr - waitList ) == waitListCount );
-       
-       *outWaitList            = waitList;
-       *outWaitListCount       = waitListCount;
-       waitList                        = NULL;
-       err                                     = mStatus_NoError;
+               dlog( kDebugLevelChatty, DEBUG_NAME "\n" );
        
-exit:
-       if( waitList )
-       {
-               free( waitList );
-       }
-       dlog( kDebugLevelTrace, DEBUG_NAME "thread setting up wait list done (err=%d %m)\n", err, err );
-       return( err );
-}
-
-//===========================================================================================================================
-//     ProcessingThreadProcessPacket
-//===========================================================================================================================
+               end = ( (mDNSu8 *) &sock->packet ) + bytesTransferred;
 
-mDNSlocal void ProcessingThreadProcessPacket( mDNS *inMDNS, mDNSInterfaceData *inIFD, UDPSocket * inUDPSocket, SocketRef inSock )
-{
-       OSStatus                                        err;
-       const mDNSInterfaceID           iid = inIFD ? inIFD->interfaceInfo.InterfaceID : NULL;
-       LPFN_WSARECVMSG                         recvMsgPtr;
-       mDNSAddr                                        srcAddr;
-       mDNSIPPort                                      srcPort;
-       mDNSAddr                                        dstAddr;
-       mDNSIPPort                                      dstPort;
-       mDNSu8                                          ttl;
-       struct sockaddr_storage         addr;
-       DNSMessage                                      packet;
-       mDNSu8 *                                        end;
-       int                                                     n;
-       
-       check( inMDNS );
-       check( IsValidSocket( inSock ) );
-       
-       // Set up the default in case the packet info options are not supported or reported correctly.
-       
-       if ( inIFD )
-       {
-               recvMsgPtr      = inIFD->wsaRecvMsgFunctionPtr;
-               dstAddr         = inIFD->defaultAddr;
-               dstPort         = MulticastDNSPort;
-               ttl                     = 255;
-       }
-       else if ( inUDPSocket )
-       {
-               recvMsgPtr      = inUDPSocket->recvMsgPtr;
-               dstAddr         = inUDPSocket->dstAddr;
-               dstPort         = inUDPSocket->port;
-               ttl                     = 255;
-       }
-       else if ( inSock == inMDNS->p->unicastSock4 )
-       {
-               recvMsgPtr      = inMDNS->p->unicastSock4RecvMsgPtr;
-               dstAddr         = inMDNS->p->unicastSock4DestAddr;
-               dstPort         = inMDNS->UnicastPort4;
-               ttl                     = 255;
-       }
-       else if ( inSock == inMDNS->p->unicastSock6 )
-       {
-               recvMsgPtr      = inMDNS->p->unicastSock6RecvMsgPtr;
-               dstAddr         = inMDNS->p->unicastSock6DestAddr;
-               dstPort         = inMDNS->UnicastPort6;
-               ttl                     = 255;
-       }
-       else
-       {
-               dlog( kDebugLevelError, DEBUG_NAME "packet received on unknown socket\n" );
-               goto exit;
-       }
+               // <rdar://problem/7532492> mDNSResponder gets locking errors on Windows
+               //
+               // There seems to be a bug in WinSock with respect to Alertable I/O. According
+               // to MSDN <http://msdn.microsoft.com/en-us/library/aa363772(VS.85).aspx>, Alertable I/O
+               // callbacks will only be invoked during the following calls (when the caller sets
+               // the appropriate flag):
+               //
+               // - SleepEx
+               // - WaitForSingleObjectEx
+               // - WaitForMultipleObjectsEx
+               // - SignalObjectAndWait
+               // - MsgWaitForMultipleObjectsEx
+               //
+               // However, we have seen callbacks be invoked during calls to bind() (and maybe others).
+               // To workaround this, we set the gSocketEventsEnabled flag to be TRUE only when it's okay
+               // to directly call mDNSCoreReceive.  Otherwise we queue the packet up and dispatch it later.
 
-#if( !TARGET_OS_WINDOWS_CE )
-       if( recvMsgPtr )
-       {
-               WSAMSG                          msg;
-               WSABUF                          buf;
-               uint8_t                         controlBuffer[ 128 ];
-               DWORD                           size;
-               LPWSACMSGHDR            header;
-               
-               // Set up the buffer and read the packet.
-               
-               msg.name                        = (LPSOCKADDR) &addr;
-               msg.namelen                     = (INT) sizeof( addr );
-               buf.buf                         = (char *) &packet;
-               buf.len                         = (u_long) sizeof( packet );
-               msg.lpBuffers           = &buf;
-               msg.dwBufferCount       = 1;
-               msg.Control.buf         = (char *) controlBuffer;
-               msg.Control.len         = (u_long) sizeof( controlBuffer );
-               msg.dwFlags                     = 0;
-                               
-               err = recvMsgPtr( inSock, &msg, &size, NULL, NULL );
-               err = translate_errno( err == 0, (OSStatus) WSAGetLastError(), kUnknownErr );
-               require_noerr( err, exit );
-               n = (int) size;
-               
-               // Parse the control information. Reject packets received on the wrong interface.
-               
-               for( header = WSA_CMSG_FIRSTHDR( &msg ); header; header = WSA_CMSG_NXTHDR( &msg, header ) )
+               if ( gSocketEventsEnabled && !gSocketEvents.Head )
                {
-                       if( ( header->cmsg_level == IPPROTO_IP ) && ( header->cmsg_type == IP_PKTINFO ) )
-                       {
-                               IN_PKTINFO *            ipv4PacketInfo;
-                               
-                               ipv4PacketInfo = (IN_PKTINFO *) WSA_CMSG_DATA( header );
-
-                               if ( inIFD )
-                               {
-                                       require_action( ipv4PacketInfo->ipi_ifindex == inIFD->index, exit, err = kMismatchErr );
-                               }
-
-                               dstAddr.type                            = mDNSAddrType_IPv4;
-                               dstAddr.ip.v4.NotAnInteger      = ipv4PacketInfo->ipi_addr.s_addr;
-                       }
-                       else if( ( header->cmsg_level == IPPROTO_IPV6 ) && ( header->cmsg_type == IPV6_PKTINFO ) )
-                       {
-                               IN6_PKTINFO *           ipv6PacketInfo;
-                               
-                               ipv6PacketInfo = (IN6_PKTINFO *) WSA_CMSG_DATA( header );
-
-                               if ( inIFD )
-                               {
-                                       require_action( ipv6PacketInfo->ipi6_ifindex == ( inIFD->index - kIPv6IfIndexBase), exit, err = kMismatchErr );
-                               }
-
-                               dstAddr.type    = mDNSAddrType_IPv6;
-                               dstAddr.ip.v6   = *( (mDNSv6Addr *) &ipv6PacketInfo->ipi6_addr );
-                       }
+                       // Turn off socket events before calling mDNSCoreReceive().
+                       // This will prevent reentrancy problems.
+                       //
+                       // Don't forget to reenable socket events afterwards.
+                       
+                       SetSocketEventsEnabled( sock->m, FALSE );
+                       mDNSCoreReceive( sock->m, &sock->packet, end, &srcAddr, srcPort, &dstAddr, dstPort, iid );
+                       SetSocketEventsEnabled( sock->m, TRUE );
+               }
+               else
+               {
+                       UDPSocketEvent * event;
+                       
+                       event = malloc( sizeof( UDPSocketEvent ) );
+                       require_action( event, exit, err = ( DWORD ) kNoMemoryErr );
+                       event->super.sock               = sock;
+                       event->super.handler    = &UDPSocketEventHandler;
+                       event->super.next               = NULL;
+                       event->iid                              = iid;
+                       memcpy( &event->packet, &sock->packet, sizeof( event->packet ) );
+                       event->end                              = ( (mDNSu8 *) &event->packet ) + bytesTransferred;
+                       event->srcAddr                  = srcAddr;
+                       event->dstAddr                  = dstAddr;
+                       event->srcPort                  = srcPort;
+                       event->dstPort                  = dstPort;
+
+                       AddToTail( &gSocketEvents, event );
                }
        }
-       else
-#endif
-       {
-               int     addrSize;
-               
-               addrSize = sizeof( addr );
-               n = recvfrom( inSock, (char *) &packet, sizeof( packet ), 0, (struct sockaddr *) &addr, &addrSize );
-               err = translate_errno( n > 0, errno_compat(), kUnknownErr );
-               require_noerr( err, exit );
-       }
-       SockAddrToMDNSAddr( (struct sockaddr *) &addr, &srcAddr, &srcPort );
-       
-       // Dispatch the packet to mDNS.
-       
-       dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
-       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 ) );
 
-       if ( inIFD )
+exit:
+
+       // If the socket is still good, then start up another asynchronous read
+
+       if ( sock && ( sock->fd != INVALID_SOCKET ) )
        {
-               dlog( kDebugLevelChatty, DEBUG_NAME "    interface = %#a (index=0x%08X)\n", &inIFD->interfaceInfo.ip, (int) inIFD->index );
+               err = UDPBeginRecv( sock );
+               check_noerr( err );
        }
-
-       dlog( kDebugLevelChatty, DEBUG_NAME "\n" );
-       
-       end = ( (mDNSu8 *) &packet ) + n;
-       mDNSCoreReceive( inMDNS, &packet, end, &srcAddr, srcPort, &dstAddr, dstPort, iid );
-       
-exit:
-       return;
 }
 
+
 //===========================================================================================================================
-//     ProcessingThreadInterfaceListChanged
+//     InterfaceListDidChange
 //===========================================================================================================================
-
-mDNSlocal void ProcessingThreadInterfaceListChanged( mDNS *inMDNS )
+void InterfaceListDidChange( mDNS * const inMDNS )
 {
-       mStatus         err;
+       mStatus err;
        
        dlog( kDebugLevelInfo, DEBUG_NAME "interface list changed\n" );
        check( inMDNS );
-
-       if (inMDNS->p->interfaceListChangedCallback)
-       {
-               inMDNS->p->interfaceListChangedCallback(inMDNS);
-       }
-       
-       mDNSPlatformLock( inMDNS );
        
        // Tear down the existing interfaces and set up new ones using the new IP info.
        
@@ -3903,8 +3456,6 @@ mDNSlocal void    ProcessingThreadInterfaceListChanged( mDNS *inMDNS )
                
        err = uDNS_SetupDNSConfig( inMDNS );
        check_noerr( err );
-
-       mDNSPlatformUnlock( inMDNS );
        
        // Inform clients of the change.
        
@@ -3917,67 +3468,37 @@ mDNSlocal void  ProcessingThreadInterfaceListChanged( mDNS *inMDNS )
 
 
 //===========================================================================================================================
-//     ProcessingThreadComputerDescriptionChanged
+//     ComputerDescriptionDidChange
 //===========================================================================================================================
-mDNSlocal void ProcessingThreadComputerDescriptionChanged( mDNS *inMDNS )
-{
-       mStatus         err;
-       
+void ComputerDescriptionDidChange( mDNS * const inMDNS )
+{      
        dlog( kDebugLevelInfo, DEBUG_NAME "computer description has changed\n" );
        check( inMDNS );
 
-       mDNSPlatformLock( inMDNS );
-
        // redo the names
        SetupNiceName( inMDNS );
-
-       if (inMDNS->p->hostDescriptionChangedCallback)
-       {
-               inMDNS->p->hostDescriptionChangedCallback(inMDNS);
-       }
-       
-       // and reset the event handler
-       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 );
 }
 
 
 //===========================================================================================================================
-//     ProcessingThreadTCPIPConfigChanged
+//     TCPIPConfigDidChange
 //===========================================================================================================================
-mDNSlocal void ProcessingThreadTCPIPConfigChanged( mDNS * inMDNS )
+void TCPIPConfigDidChange( mDNS * const inMDNS )
 {
        mStatus         err;
        
        dlog( kDebugLevelInfo, DEBUG_NAME "TCP/IP config has changed\n" );
        check( inMDNS );
 
-       mDNSPlatformLock( inMDNS );
-
        err = uDNS_SetupDNSConfig( inMDNS );
        check_noerr( err );
-
-       // and reset the event handler
-
-       if ( ( inMDNS->p->tcpipKey != NULL ) && ( inMDNS->p->tcpipChangedEvent ) )
-       {
-               err = RegNotifyChangeKeyValue( inMDNS->p->tcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->tcpipChangedEvent, TRUE );
-               check_noerr( err );
-       }
-
-       mDNSPlatformUnlock( inMDNS );
 }
 
 
 //===========================================================================================================================
-//     ProcessingThreadDynDNSConfigChanged
+//     DynDNSConfigDidChange
 //===========================================================================================================================
-mDNSlocal void ProcessingThreadDynDNSConfigChanged( mDNS *inMDNS )
+void DynDNSConfigDidChange( mDNS * const inMDNS )
 {
        mStatus         err;
        
@@ -3986,68 +3507,35 @@ mDNSlocal void  ProcessingThreadDynDNSConfigChanged( mDNS *inMDNS )
 
        SetDomainSecrets( inMDNS );
 
-       mDNSPlatformLock( inMDNS );
-
        err = uDNS_SetupDNSConfig( inMDNS );
        check_noerr( err );
-
-       // and reset the event handler
-
-       if ((inMDNS->p->ddnsKey != NULL) && (inMDNS->p->ddnsChangedEvent))
-       {
-               err = RegNotifyChangeKeyValue(inMDNS->p->ddnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->ddnsChangedEvent, TRUE);
-               check_noerr( err );
-       }
-
-       mDNSPlatformUnlock( inMDNS );
 }
 
 
 //===========================================================================================================================
-//     ProcessingThreadFileShareChanged
+//     FileSharingDidChange
 //===========================================================================================================================
-mDNSlocal void ProcessingThreadFileShareChanged( mDNS *inMDNS )
-{
-       mStatus err;
-       
+void FileSharingDidChange( mDNS * const inMDNS )
+{      
        dlog( kDebugLevelInfo, DEBUG_NAME "File shares has changed\n" );
        check( inMDNS );
 
        CheckFileShares( inMDNS );
-
-       // and reset the event handler
-       
-       if ((inMDNS->p->fileShareKey != NULL) && (inMDNS->p->fileShareEvent))
-       {
-               err = RegNotifyChangeKeyValue(inMDNS->p->fileShareKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->fileShareEvent, TRUE);
-               check_noerr( err );
-       }
 }
 
 
 //===========================================================================================================================
-//     ProcessingThreadFileShareChanged
+//     FilewallDidChange
 //===========================================================================================================================
-mDNSlocal void ProcessingThreadFirewallChanged( mDNS *inMDNS )
-{
-       mStatus err;
-       
+void FirewallDidChange( mDNS * const inMDNS )
+{      
        dlog( kDebugLevelInfo, DEBUG_NAME "Firewall has changed\n" );
        check( inMDNS );
 
        CheckFileShares( inMDNS );
-
-       // and reset the event handler
-       
-       if ((inMDNS->p->firewallKey != NULL) && (inMDNS->p->firewallEvent))
-       {
-               err = RegNotifyChangeKeyValue(inMDNS->p->firewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, inMDNS->p->firewallEvent, TRUE);
-               check_noerr( err );
-       }
 }
 
 
-
 #if 0
 #pragma mark -
 #pragma mark == Utilities ==
@@ -4061,7 +3549,7 @@ mDNSlocal int     getifaddrs( struct ifaddrs **outAddrs )
 {
        int             err;
        
-#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS && !TARGET_OS_WINDOWS_CE )
+#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
        
        // Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
        // XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
@@ -4094,14 +3582,9 @@ mDNSlocal int    getifaddrs( struct ifaddrs **outAddrs )
                require_noerr( err, exit );
        }
        
-#elif( !TARGET_OS_WINDOWS_CE )
-
-       err = getifaddrs_ipv4( outAddrs );
-       require_noerr( err, exit );
-
 #else
 
-       err = getifaddrs_ce( outAddrs );
+       err = getifaddrs_ipv4( outAddrs );
        require_noerr( err, exit );
 
 #endif
@@ -4285,10 +3768,10 @@ mDNSlocal int   getifaddrs_ipv6( struct ifaddrs **outAddrs )
 
                        // Get lease lifetime
 
-                       if ( ( iaa->IfType != IF_TYPE_SOFTWARE_LOOPBACK ) && ( addr->LeaseLifetime != 0 ) && ( addr->LeaseLifetime != 0xFFFFFFFF ) )
+                       if ( ( iaa->IfType != IF_TYPE_SOFTWARE_LOOPBACK ) && ( addr->LeaseLifetime != 0 ) && ( addr->ValidLifetime != 0xFFFFFFFF ) )
                        {
                                ifa->ifa_dhcpEnabled            = TRUE;
-                               ifa->ifa_dhcpLeaseExpires       = time( NULL ) + addr->LeaseLifetime;
+                               ifa->ifa_dhcpLeaseExpires       = time( NULL ) + addr->ValidLifetime;
                        }
                        else
                        {
@@ -4296,12 +3779,17 @@ mDNSlocal int   getifaddrs_ipv6( struct ifaddrs **outAddrs )
                                ifa->ifa_dhcpLeaseExpires       = 0;
                        }
 
-                       // Get WakeOnLAN settings
-
-                       if ( iaa->IfType == IF_TYPE_ETHERNET_CSMACD )
+                       if ( iaa->PhysicalAddressLength == sizeof( ifa->ifa_physaddr ) )
                        {
-                               ifa->ifa_womp = IsWOMPEnabled( iaa->AdapterName );
+                               memcpy( ifa->ifa_physaddr, iaa->PhysicalAddress, iaa->PhysicalAddressLength );
                        }
+
+                       // Because we don't get notified of womp changes, we're going to just assume
+                       // that all wired interfaces have it enabled. Before we go to sleep, we'll check
+                       // if the interface actually supports it, and update mDNS->SystemWakeOnLANEnabled
+                       // accordingly
+
+                       ifa->ifa_womp = ( iaa->IfType == IF_TYPE_ETHERNET_CSMACD ) ? mDNStrue : mDNSfalse;
                        
                        // Get address.
                        
@@ -4405,7 +3893,6 @@ exit:
 
 #endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
 
-#if( !TARGET_OS_WINDOWS_CE )
 //===========================================================================================================================
 //     getifaddrs_ipv4
 //===========================================================================================================================
@@ -4419,247 +3906,73 @@ mDNSlocal int  getifaddrs_ipv4( struct ifaddrs **outAddrs )
        INTERFACE_INFO *                buffer;
        INTERFACE_INFO *                tempBuffer;
        INTERFACE_INFO *                ifInfo;
-       IP_ADAPTER_INFO *               pAdapterInfo;
-       IP_ADAPTER_INFO *               pAdapter;
-       ULONG                                   bufLen;
        int                                             n;
        int                                             i;
        struct ifaddrs *                head;
        struct ifaddrs **               next;
        struct ifaddrs *                ifa;
-       
-       sock    = INVALID_SOCKET;
-       buffer  = NULL;
-       head    = NULL;
-       next    = &head;
-       pAdapterInfo = NULL;
-       
-       // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a 
-       // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
-       // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
-       
-       sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
-       err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
-       require_noerr( err, exit );
-               
-       n = 0;
-       size = 16 * sizeof( INTERFACE_INFO );
-       for( ;; )
-       {
-               tempBuffer = (INTERFACE_INFO *) realloc( buffer, size );
-               require_action( tempBuffer, exit, err = WSAENOBUFS );
-               buffer = tempBuffer;
-               
-               err = WSAIoctl( sock, SIO_GET_INTERFACE_LIST, NULL, 0, buffer, size, &actualSize, NULL, NULL );
-               if( err == 0 )
-               {
-                       break;
-               }
-               
-               ++n;
-               require_action( n < 100, exit, err = WSAEADDRNOTAVAIL );
-               
-               size += ( 16 * sizeof( INTERFACE_INFO ) );
-       }
-       check( actualSize <= size );
-       check( ( actualSize % sizeof( INTERFACE_INFO ) ) == 0 );
-       n = (int)( actualSize / sizeof( INTERFACE_INFO ) );
-
-       // Now call GetAdaptersInfo so we can get DHCP information for each interface
-
-       pAdapterInfo    = NULL;
-       bufLen                  = 0;
-       
-       for ( i = 0; i < 100; i++ )
-       {
-               err = GetAdaptersInfo( pAdapterInfo, &bufLen);
-
-               if ( err != ERROR_BUFFER_OVERFLOW )
-               {
-                       break;
-               }
-
-               pAdapterInfo = (IP_ADAPTER_INFO*) realloc( pAdapterInfo, bufLen );
-
-               if ( !pAdapterInfo )
-               {
-                       break;
-               }
-       }
-       
-       // Process the raw interface list and build a linked list of IPv4 interfaces.
-       
-       for( i = 0; i < n; ++i )
-       {
-               uint32_t ifIndex;
-               struct sockaddr_in netmask;
-               
-               ifInfo = &buffer[ i ];
-               if( ifInfo->iiAddress.Address.sa_family != AF_INET )
-               {
-                       continue;
-               }
-               
-               // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
-               // See comment in getifaddrs_ipv6
-
-               ifIndex = 0;
-               memset( &netmask, 0, sizeof( netmask ) );
-               err = AddressToIndexAndMask( ( struct sockaddr* ) &ifInfo->iiAddress.AddressIn, &ifIndex, ( struct sockaddr* ) &netmask );
-
-               if ( err )
-               {
-                       continue;
-               }
-
-               ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
-               require_action( ifa, exit, err = WSAENOBUFS );
-               
-               *next = ifa;
-               next  = &ifa->ifa_next;
-               
-               // Get the name.
-               
-               ifa->ifa_name = (char *) malloc( 16 );
-               require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
-               sprintf( ifa->ifa_name, "%d", i + 1 );
-               
-               // Get interface flags.
-               
-               ifa->ifa_flags = (u_int) ifInfo->iiFlags;
-               
-               // Get addresses.
-               
-               if ( ifInfo->iiAddress.Address.sa_family == AF_INET )
-               {
-                       struct sockaddr_in *            sa4;
-                       
-                       sa4 = &ifInfo->iiAddress.AddressIn;
-                       ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa4 ) );
-                       require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
-                       memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) );
-
-                       ifa->ifa_netmask = (struct sockaddr*) calloc(1, sizeof( *sa4 ) );
-                       require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS );
-
-                       // <rdar://problem/4076478> Service won't start on Win2K. The address
-                       // family field was not being initialized.
-
-                       ifa->ifa_netmask->sa_family = AF_INET;
-                       ( ( struct sockaddr_in* ) ifa->ifa_netmask )->sin_addr = netmask.sin_addr;
-                       ifa->ifa_extra.index = ifIndex;
-               }
-               else
-               {
-                       // Emulate an interface index.
-               
-                       ifa->ifa_extra.index = (uint32_t)( i + 1 );
-               }
-
-               // Now get DHCP configuration information
-
-               for ( pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next )
-               {
-                       if ( strcmp( inet_ntoa( ifInfo->iiAddress.AddressIn.sin_addr ), pAdapter->IpAddressList.IpAddress.String ) == 0 )
-                       {
-                               ifa->ifa_dhcpEnabled            = pAdapter->DhcpEnabled;
-                               ifa->ifa_dhcpLeaseExpires       = pAdapter->LeaseExpires;
-                               ifa->ifa_womp                           = IsWOMPEnabled( pAdapter->AdapterName );
-                               break;
-                       }
-               }
-       }
-       
-       // Success!
-       
-       if( outAddrs )
-       {
-               *outAddrs = head;
-               head = NULL;
-       }
-       err = 0;
-       
-exit:
-
-       if ( pAdapterInfo )
-       {
-               free( pAdapterInfo );
-       }
-       if( head )
-       {
-               freeifaddrs( head );
-       }
-       if( buffer )
-       {
-               free( buffer );
-       }
-       if( sock != INVALID_SOCKET )
-       {
-               closesocket( sock );
-       }
-       return( err );
-}
-#endif // !TARGET_OS_WINDOWS_CE )
-
-#if( TARGET_OS_WINDOWS_CE )
-//===========================================================================================================================
-//     getifaddrs_ce
-//===========================================================================================================================
-
-mDNSlocal int  getifaddrs_ce( struct ifaddrs **outAddrs )
-{
-       int                                                     err;
-       SocketRef                                       sock;
-       DWORD                                           size;
-       void *                                          buffer;
-       SOCKET_ADDRESS_LIST *           addressList;
-       struct ifaddrs *                        head;
-       struct ifaddrs **                       next;
-       struct ifaddrs *                        ifa;
-       int                                                     n;
-       int                                                     i;
-
-       sock    = kInvalidSocketRef;
+       
+       sock    = INVALID_SOCKET;
        buffer  = NULL;
        head    = NULL;
        next    = &head;
        
-       // Open a temporary socket because one is needed to use WSAIoctl (we'll close it before exiting this function).
+       // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a 
+       // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
+       // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
        
        sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
        err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
        require_noerr( err, exit );
                
-       // Call WSAIoctl with SIO_ADDRESS_LIST_QUERY and pass a null buffer. This call will fail, but the size needed to 
-       // for the request will be filled in. Once we know the size, allocate a buffer to hold the entire list.
-       //
-       // Note: Due to a bug in Windows CE, the size returned by WSAIoctl is not enough so double it as a workaround.
-       
-       size = 0;
-       WSAIoctl( sock, SIO_ADDRESS_LIST_QUERY, NULL, 0, NULL, 0, &size, NULL, NULL );
-       require_action( size > 0, exit, err = -1 );
-       size *= 2;
-       
-       buffer = calloc( 1, size );
-       require_action( buffer, exit, err = -1 );
-       
-       // We now know the size of the list and have a buffer to hold so call WSAIoctl again to get it.
-       
-       err = WSAIoctl( sock, SIO_ADDRESS_LIST_QUERY, NULL, 0, buffer, size, &size, NULL, NULL );
-       require_noerr( err, exit );
-       addressList = (SOCKET_ADDRESS_LIST *) buffer;
-       
-       // Process the raw interface list and build a linked list of interfaces.
-       //
-       // Note: Due to a bug in Windows CE, the iAddressCount field is always 0 so use 1 in that case.
-       
-       n = addressList->iAddressCount;
-       if( n == 0 )
+       n = 0;
+       size = 16 * sizeof( INTERFACE_INFO );
+       for( ;; )
        {
-               n = 1;
+               tempBuffer = (INTERFACE_INFO *) realloc( buffer, size );
+               require_action( tempBuffer, exit, err = WSAENOBUFS );
+               buffer = tempBuffer;
+               
+               err = WSAIoctl( sock, SIO_GET_INTERFACE_LIST, NULL, 0, buffer, size, &actualSize, NULL, NULL );
+               if( err == 0 )
+               {
+                       break;
+               }
+               
+               ++n;
+               require_action( n < 100, exit, err = WSAEADDRNOTAVAIL );
+               
+               size += ( 16 * sizeof( INTERFACE_INFO ) );
        }
+       check( actualSize <= size );
+       check( ( actualSize % sizeof( INTERFACE_INFO ) ) == 0 );
+       n = (int)( actualSize / sizeof( INTERFACE_INFO ) );
+       
+       // Process the raw interface list and build a linked list of IPv4 interfaces.
+       
        for( i = 0; i < n; ++i )
        {
+               uint32_t ifIndex;
+               struct sockaddr_in netmask;
+               
+               ifInfo = &buffer[ i ];
+               if( ifInfo->iiAddress.Address.sa_family != AF_INET )
+               {
+                       continue;
+               }
+               
+               // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
+               // See comment in getifaddrs_ipv6
+
+               ifIndex = 0;
+               memset( &netmask, 0, sizeof( netmask ) );
+               err = AddressToIndexAndMask( ( struct sockaddr* ) &ifInfo->iiAddress.AddressIn, &ifIndex, ( struct sockaddr* ) &netmask );
+
+               if ( err )
+               {
+                       continue;
+               }
+
                ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
                require_action( ifa, exit, err = WSAENOBUFS );
                
@@ -4672,27 +3985,36 @@ mDNSlocal int   getifaddrs_ce( struct ifaddrs **outAddrs )
                require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
                sprintf( ifa->ifa_name, "%d", i + 1 );
                
-               // Get flags. Note: SIO_ADDRESS_LIST_QUERY does not report flags so just fake IFF_UP and IFF_MULTICAST.
+               // Get interface flags.
                
-               ifa->ifa_flags = IFF_UP | IFF_MULTICAST;
+               ifa->ifa_flags = (u_int) ifInfo->iiFlags;
                
                // Get addresses.
                
-               switch( addressList->Address[ i ].lpSockaddr->sa_family )
+               if ( ifInfo->iiAddress.Address.sa_family == AF_INET )
                {
-                       case AF_INET:
-                       {
-                               struct sockaddr_in *            sa4;
-                               
-                               sa4 = (struct sockaddr_in *) addressList->Address[ i ].lpSockaddr;
-                               ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa4 ) );
-                               require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
-                               memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) );
-                               break;
-                       }
+                       struct sockaddr_in *            sa4;
                        
-                       default:
-                               break;
+                       sa4 = &ifInfo->iiAddress.AddressIn;
+                       ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa4 ) );
+                       require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
+                       memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) );
+
+                       ifa->ifa_netmask = (struct sockaddr*) calloc(1, sizeof( *sa4 ) );
+                       require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS );
+
+                       // <rdar://problem/4076478> Service won't start on Win2K. The address
+                       // family field was not being initialized.
+
+                       ifa->ifa_netmask->sa_family = AF_INET;
+                       ( ( struct sockaddr_in* ) ifa->ifa_netmask )->sin_addr = netmask.sin_addr;
+                       ifa->ifa_extra.index = ifIndex;
+               }
+               else
+               {
+                       // Emulate an interface index.
+               
+                       ifa->ifa_extra.index = (uint32_t)( i + 1 );
                }
        }
        
@@ -4706,6 +4028,7 @@ mDNSlocal int     getifaddrs_ce( struct ifaddrs **outAddrs )
        err = 0;
        
 exit:
+
        if( head )
        {
                freeifaddrs( head );
@@ -4720,7 +4043,6 @@ exit:
        }
        return( err );
 }
-#endif // TARGET_OS_WINDOWS_CE )
 
 //===========================================================================================================================
 //     freeifaddrs
@@ -5242,22 +4564,26 @@ exit:
 
 
 //===========================================================================================================================
-//     FreeTCPConnectionData
+//     TCPFreeSocket
 //===========================================================================================================================
 
-mDNSlocal void
-FreeTCPSocket( TCPSocket *sock )
+mDNSlocal void CALLBACK
+TCPFreeSocket( TCPSocket *sock )
 {
        check( sock );
 
-       if ( sock->pendingEvent )
+       dlog( kDebugLevelChatty, DEBUG_NAME "freeing TCPSocket 0x%x:%d\n", sock, sock->fd );
+       
+       if ( sock->connectEvent )
        {
-               CloseHandle( sock->pendingEvent );
+               CloseHandle( sock->connectEvent );
+               sock->connectEvent = NULL;
        }
 
        if ( sock->fd != INVALID_SOCKET )
        {
                closesocket( sock->fd );
+               sock->fd = INVALID_SOCKET;
        }
 
        free( sock );
@@ -5265,22 +4591,20 @@ FreeTCPSocket( TCPSocket *sock )
 
 
 //===========================================================================================================================
-//  FreeUDPSocket
+//  UDPFreeSocket
 //===========================================================================================================================
 
-mDNSlocal void
-FreeUDPSocket( UDPSocket * sock )
+mDNSlocal void CALLBACK
+UDPFreeSocket( UDPSocket * sock )
 {
     check( sock );
 
-    if ( sock->readEvent )
-    {
-        CloseHandle( sock->readEvent );
-    }
+       dlog( kDebugLevelChatty, DEBUG_NAME "freeing UDPSocket %d (%##a)\n", sock->fd, &sock->addr );
 
-    if ( sock->sock != INVALID_SOCKET )
-    {
-        closesocket( sock->sock );
+    if ( sock->fd != INVALID_SOCKET )
+    {          
+        closesocket( sock->fd );
+               sock->fd = INVALID_SOCKET;
     }
 
     free( sock );
@@ -5491,6 +4815,107 @@ exit:
 }
 
 
+mDNSlocal VOID CALLBACK
+CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue )
+{
+       mDNS * const m = ( mDNS * const ) arg;
+
+       ( void ) dwTimerLowValue;
+       ( void ) dwTimerHighValue;
+
+       CheckFileShares( m );
+}
+
+
+mDNSlocal unsigned __stdcall 
+SMBRegistrationThread( void * arg )
+{
+       mDNS * const m = ( mDNS * const ) arg;
+       DNSServiceRef sref = NULL;
+       HANDLE          handles[ 3 ];
+       mDNSu8          txtBuf[ 256 ];
+       mDNSu8  *       txtPtr;
+       size_t          keyLen;
+       size_t          valLen;
+       mDNSIPPort      port = { { SMBPortAsNumber >> 8, SMBPortAsNumber & 0xFF } };
+       DNSServiceErrorType err;
+
+       DEBUG_UNUSED( arg );
+
+       handles[ 0 ] = gSMBThreadStopEvent;
+       handles[ 1 ] = gSMBThreadRegisterEvent;
+       handles[ 2 ] = gSMBThreadDeregisterEvent;
+
+       memset( txtBuf, 0, sizeof( txtBuf )  );
+       txtPtr = txtBuf;
+       keyLen = strlen( "netbios=" );
+       valLen = strlen( m->p->nbname );
+       require_action( valLen < 32, exit, err = kUnknownErr ); // This should never happen, but check to avoid further memory corruption
+       *txtPtr++ = ( mDNSu8 ) ( keyLen + valLen );
+       memcpy( txtPtr, "netbios=", keyLen );
+       txtPtr += keyLen;
+       if ( valLen ) { memcpy( txtPtr, m->p->nbname, valLen ); txtPtr += ( mDNSu8 ) valLen; }
+       keyLen = strlen( "domain=" );
+       valLen = strlen( m->p->nbdomain );
+       require_action( valLen < 32, exit, err = kUnknownErr ); // This should never happen, but check to avoid further memory corruption
+       *txtPtr++ = ( mDNSu8 )( keyLen + valLen );
+       memcpy( txtPtr, "domain=", keyLen );
+       txtPtr += keyLen;
+       if ( valLen ) { memcpy( txtPtr, m->p->nbdomain, valLen ); txtPtr += valLen; }
+       
+       for ( ;; )
+       {
+               DWORD ret;
+
+               ret = WaitForMultipleObjects( 3, handles, FALSE, INFINITE );
+
+               if ( ret != WAIT_FAILED )
+               {
+                       if ( ret == kSMBStopEvent )
+                       {
+                               break;
+                       }
+                       else if ( ret == kSMBRegisterEvent )
+                       {
+                               err = gDNSServiceRegister( &sref, 0, 0, NULL, "_smb._tcp,_file", NULL, NULL, ( uint16_t ) port.NotAnInteger, ( mDNSu16 )( txtPtr - txtBuf ), txtBuf, NULL, NULL );
+
+                               if ( err )
+                               {
+                                       LogMsg( "SMBRegistrationThread: DNSServiceRegister returned %d\n", err );
+                                       sref = NULL;
+                                       break;
+                               }
+                       }
+                       else if ( ret == kSMBDeregisterEvent )
+                       {
+                               if ( sref )
+                               {
+                                       gDNSServiceRefDeallocate( sref );
+                                       sref = NULL;
+                               }
+                       }
+               }
+               else
+               {
+                       LogMsg( "SMBRegistrationThread:  WaitForMultipleObjects returned %d\n", GetLastError() );
+                       break;
+               }
+       }
+
+exit:
+
+       if ( sref != NULL )
+       {
+               gDNSServiceRefDeallocate( sref );
+               sref = NULL;
+       }
+
+       SetEvent( gSMBThreadQuitEvent );
+       _endthreadex( 0 );
+       return 0;
+}
+
+
 mDNSlocal void
 CheckFileShares( mDNS * const m )
 {
@@ -5498,15 +4923,31 @@ CheckFileShares( mDNS * const m )
        DWORD                   entriesRead = 0;
        DWORD                   totalEntries = 0;
        DWORD                   resume = 0;
-       mDNSBool                enabled = mDNSfalse;
+       mDNSBool                advertise = mDNSfalse;
+       mDNSBool                fileSharing = mDNSfalse;
+       mDNSBool                printSharing = mDNSfalse;
+       HKEY                    key = NULL;
+       BOOL                    retry = FALSE;
        NET_API_STATUS  res;
        mStatus                 err;
 
        check( m );
 
-       if ( mDNSIsFileAndPrintSharingEnabled() )
+       // Only do this if we're not shutting down
+
+       require_action_quiet( m->AdvertiseLocalAddresses && !m->ShutdownTime, exit, err = kNoErr );
+
+       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Services\\SMB", &key );
+
+       if ( !err )
+       {
+               DWORD dwSize = sizeof( DWORD );
+               RegQueryValueEx( key, L"Advertise", NULL, NULL, (LPBYTE) &advertise, &dwSize );
+       }
+
+       if ( advertise && mDNSIsFileAndPrintSharingEnabled( &retry ) )
        {
-               dlog( kDebugLevelTrace, DEBUG_NAME "file and print sharing is enabled\n" );
+               dlog( kDebugLevelTrace, DEBUG_NAME "Sharing is enabled\n" );
 
                res = NetShareEnum( NULL, 1, ( LPBYTE* )&bufPtr, MAX_PREFERRED_LENGTH, &entriesRead, &totalEntries, &resume );
 
@@ -5515,15 +4956,18 @@ CheckFileShares( mDNS * const m )
                        PSHARE_INFO_1 p = bufPtr;
                        DWORD i;
 
-                       for( i = 0; i <= totalEntries; i++ ) 
+                       for( i = 0; i < entriesRead; i++ ) 
                        {
                                // We are only interested if the user is sharing anything other 
                                // than the built-in "print$" source
 
                                if ( ( p->shi1_type == STYPE_DISKTREE ) && ( wcscmp( p->shi1_netname, TEXT( "print$" ) ) != 0 ) )
                                {
-                                       enabled = mDNStrue;
-                                       break;
+                                       fileSharing = mDNStrue;
+                               }
+                               else if ( p->shi1_type == STYPE_PRINTQ )
+                               {
+                                       printSharing = mDNStrue;
                                }
 
                                p++;
@@ -5531,67 +4975,125 @@ CheckFileShares( mDNS * const m )
 
                        NetApiBufferFree( bufPtr );
                        bufPtr = NULL;
+                       retry = FALSE;
+               }
+               else if ( res == NERR_ServerNotStarted )
+               {
+                       retry = TRUE;
                }
        }
+       
+       if ( retry )
+       {
+               __int64                 qwTimeout;
+               LARGE_INTEGER   liTimeout;
+
+               qwTimeout = -m->p->checkFileSharesTimeout * 10000000;
+               liTimeout.LowPart  = ( DWORD )( qwTimeout & 0xFFFFFFFF );
+               liTimeout.HighPart = ( LONG )( qwTimeout >> 32 );
+
+               SetWaitableTimer( m->p->checkFileSharesTimer, &liTimeout, 0, CheckFileSharesProc, m, FALSE );
+       }
 
-       if ( enabled && !m->p->smbRegistered )
+       if ( !m->p->smbFileSharing && fileSharing )
        {
-               domainname              type;
-               domainname              domain;
-               mDNSIPPort              port = { { SMBPortAsNumber >> 8, SMBPortAsNumber & 0xFF } };
-               mDNSInterfaceID iid = mDNSPlatformInterfaceIDfromInterfaceIndex( m, 0 );
+               if ( !gSMBThread )
+               {
+                       if ( !gDNSSDLibrary )
+                       {
+                               gDNSSDLibrary = LoadLibrary( TEXT( "dnssd.dll" ) );
+                               require_action( gDNSSDLibrary, exit, err = GetLastError() );
+                       }
 
-               dlog( kDebugLevelTrace, DEBUG_NAME "registering smb type\n" );
-               
-               MakeDomainNameFromDNSNameString(&type, "_smb._tcp" );
-               MakeDomainNameFromDNSNameString(&domain, "local.");
+                       if ( !gDNSServiceRegister )
+                       {
+                               gDNSServiceRegister = ( DNSServiceRegisterFunc ) GetProcAddress( gDNSSDLibrary, "DNSServiceRegister" );
+                               require_action( gDNSServiceRegister, exit, err = GetLastError() );
+                       }
 
-               err = mDNS_RegisterService( m, &m->p->smbSRS, &m->nicelabel, &type, &domain, NULL, port, NULL, 0, NULL, 0, iid, /* callback */ NULL, /* context */ NULL);
-               require_noerr( err, exit );
+                       if ( !gDNSServiceRefDeallocate )
+                       {
+                               gDNSServiceRefDeallocate = ( DNSServiceRefDeallocateFunc ) GetProcAddress( gDNSSDLibrary, "DNSServiceRefDeallocate" );
+                               require_action( gDNSServiceRefDeallocate, exit, err = GetLastError() );
+                       }
+
+                       if ( !gSMBThreadRegisterEvent )
+                       {
+                               gSMBThreadRegisterEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+                               require_action( gSMBThreadRegisterEvent != NULL, exit, err = GetLastError() );
+                       }
+
+                       if ( !gSMBThreadDeregisterEvent )
+                       {
+                               gSMBThreadDeregisterEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+                               require_action( gSMBThreadDeregisterEvent != NULL, exit, err = GetLastError() );
+                       }
+
+                       if ( !gSMBThreadStopEvent )
+                       {
+                               gSMBThreadStopEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+                               require_action( gSMBThreadStopEvent != NULL, exit, err = GetLastError() );
+                       }
+
+                       if ( !gSMBThreadQuitEvent )
+                       {
+                               gSMBThreadQuitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+                               require_action( gSMBThreadQuitEvent != NULL, exit, err = GetLastError() );
+                       }
+
+                       gSMBThread = ( HANDLE ) _beginthreadex( NULL, 0, SMBRegistrationThread, m, 0, NULL );
+                       require_action( gSMBThread != NULL, exit, err = GetLastError() );
+               }
 
-               m->p->smbRegistered = mDNStrue;
+               SetEvent( gSMBThreadRegisterEvent );
+
+               m->p->smbFileSharing = mDNStrue;
        }
-       else if ( !enabled && m->p->smbRegistered )
+       else if ( m->p->smbFileSharing && !fileSharing )
        {
                dlog( kDebugLevelTrace, DEBUG_NAME "deregistering smb type\n" );
-               
-               err = mDNS_DeregisterService( m, &m->p->smbSRS );
-               require_noerr( err, exit );
 
-               m->p->smbRegistered = mDNSfalse;
+               if ( gSMBThreadDeregisterEvent != NULL )
+               {
+                       SetEvent( gSMBThreadDeregisterEvent );
+               }
+
+               m->p->smbFileSharing = mDNSfalse;
        }
 
 exit:
 
-       return;
+       if ( key )
+       {
+               RegCloseKey( key );
+       }
 }
 
 
-void
-UpdateWOMPConfig( mDNS * const m )
+BOOL
+IsWOMPEnabled( mDNS * const m )
 {
-       mDNSInterfaceData * ifd;
+       BOOL enabled;
 
-       mDNSPlatformLock( m );
+       mDNSInterfaceData * ifd;
 
-       m->p->womp = mDNSfalse;
+       enabled = FALSE;
 
        for( ifd = m->p->interfaceList; ifd; ifd = ifd->next )
        {
-               ifd->interfaceInfo.NetWake = IsWOMPEnabled( ifd->name );
-
-               if ( ifd->interfaceInfo.NetWake )
+               if ( IsWOMPEnabledForAdapter( ifd->name ) )
                {
-                       m->p->womp = mDNStrue;
+                       enabled = TRUE;
+                       break;
                }
        }
 
-       mDNSPlatformUnlock( m );
+       return enabled;
 }
 
 
 mDNSlocal mDNSu8
-IsWOMPEnabled( const char * adapterName )
+IsWOMPEnabledForAdapter( const char * adapterName )
 {
        char                                            fileName[80];
        NDIS_OID                                        oid;
@@ -5600,6 +5102,10 @@ IsWOMPEnabled( const char * adapterName )
        NDIS_PNP_CAPABILITIES   *       pNPC    = NULL;
        int                                                     err;
        mDNSu8                                          ok              = TRUE;
+
+       require_action( adapterName != NULL, exit, ok = FALSE );
+
+       dlog( kDebugLevelTrace, DEBUG_NAME "IsWOMPEnabledForAdapter: %s\n", adapterName );
        
     // Construct a device name to pass to CreateFile
 
@@ -5630,5 +5136,124 @@ exit:
                CloseHandle( handle );
     }
 
+       dlog( kDebugLevelTrace, DEBUG_NAME "IsWOMPEnabledForAdapter returns %s\n", ok ? "true" : "false" );
+
        return ( mDNSu8 ) ok;
 }
+
+
+void 
+SetSocketEventsEnabled( mDNS * const inMDNS, BOOL enabled )
+{
+       DEBUG_UNUSED( inMDNS );
+
+       if ( enabled )
+       {
+               int numEvents = 0;
+
+               check( !gSocketEventsEnabled );
+
+               // If we're enabled, then drain the queue right now.
+
+               while ( gSocketEvents.Head && ( numEvents < 100 ) )
+               {
+                       SocketEvent * event = ( SocketEvent* ) gSocketEvents.Head;
+                       RemoveFromList( &gSocketEvents, event );
+                       check( event->handler );
+
+                       // At this point we're going to call our event handler, and
+                       // gSocketEventsEnabled should be FALSE.  So if the callback
+                       // does anything that causes alertable I/O callbacks to be
+                       // invoked, we'll queue the packets instead of invoking core
+                       // callbacks reentrantly.
+                       //
+                       // One potential problem here is a pathological case of
+                       // continuing to queue packets during invocation of
+                       // the callback, and thus never exiting out of this loop.
+                       // This is entirely theoretical as we've never seen it happen,
+                       // but just to be overly cautious, we'll only process a maximum of
+                       // 100 events here just in case.
+
+                       event->handler( inMDNS, event );
+                       free( event );
+
+                       numEvents++;
+               }
+       }
+
+       gSocketEventsEnabled = enabled;
+}
+
+
+mDNSlocal void
+FreeSocketEventsForSocket( mDNS * const inMDNS, void * sock )
+{
+       SocketEvent * event;
+
+       DEBUG_UNUSED( inMDNS );
+
+       for ( event = ( SocketEvent* ) gSocketEvents.Head; event; event = event->next )
+       {
+               if ( event->sock == sock )
+               {
+                       RemoveFromList( &gSocketEvents, event );
+                       free( event );
+                       break;
+               }
+       }
+}
+
+
+mDNSlocal void
+FreeSocketEvents( mDNS * const inMDNS )
+{
+       DEBUG_UNUSED( inMDNS );
+
+       while ( gSocketEvents.Head )
+       {
+               SocketEvent * event = ( SocketEvent* ) gSocketEvents.Head;
+               RemoveFromList( &gSocketEvents, event );
+               free( event );
+       }
+}
+
+
+mDNSlocal void
+TCPSocketEventHandler( mDNS * const inMDNS, void * v )
+{
+       TCPSocketEvent  * event = ( TCPSocketEvent* ) v;
+       TCPSocket               * sock = ( TCPSocket* ) event->super.sock;
+       
+       DEBUG_UNUSED( inMDNS );
+       check( sock );
+
+       sock->lastError = event->error;
+
+       if ( !event->error )
+       {
+               if ( event->bytesTransferred )
+               {
+                       memcpy( sock->buf, event->buf, event->bytesTransferred );
+                       sock->bptr = sock->buf;
+                       sock->eptr = sock->buf + event->bytesTransferred;
+               }
+               else
+               {
+                       sock->closed = TRUE;
+               }
+       }
+
+       if ( sock->readEventHandler != NULL )
+       {
+               sock->readEventHandler( sock );
+       }
+}
+
+
+mDNSlocal void
+UDPSocketEventHandler( mDNS * const inMDNS, void * v )
+{
+       UDPSocketEvent * event = ( UDPSocketEvent* ) v;
+
+       mDNSCoreReceive( inMDNS, &event->packet, event->end, &event->srcAddr, event->srcPort, &event->dstAddr, event->dstPort, event->iid );
+}              
index 4d30be56e0389e6969041df5acbe1d548b7278cb..95e1fddfe6ff1a7fa30a9b26d02ea5ee2d8accbe 100755 (executable)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ */
 
-    Change History (most recent first):
-    
-$Log: mDNSWin32.h,v $
-Revision 1.30  2009/07/17 19:59:46  herscher
-<rdar://problem/7062660> Update the womp settings for each network adapter immediately preceding the call to mDNSCoreMachineSleep().
-
-Revision 1.29  2009/07/07 21:34:58  herscher
-<rdar://problem/6713286> windows platform changes to support use as sleep proxy client
-
-Revision 1.28  2009/04/24 04:55:26  herscher
-<rdar://problem/3496833> Advertise SMB file sharing via Bonjour
-
-Revision 1.27  2009/03/30 20:45:52  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/6127927> B4Windows: uDNS: Should use randomized source ports and transaction IDs to avoid DNS cache poisoning
-Remove VirtualPC workaround
-
-Revision 1.26  2006/08/14 23:25:21  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.25  2006/07/06 00:05:44  cheshire
-"dDNS.h" renamed to "uDNS.h"
-
-Revision 1.24  2006/02/26 19:31:04  herscher
-<rdar://problem/4455038> Bonjour For Windows takes 90 seconds to start. This was caused by a bad interaction between the VirtualPC check, and the removal of the WMI dependency.  The problem was fixed by: 1) checking to see if WMI is running before trying to talk to it.  2) Retrying the VirtualPC check every 10 seconds upon failure, stopping after 10 unsuccessful tries.
-
-Revision 1.23  2005/10/05 20:55:14  herscher
-<rdar://problem/4096464> Don't call SetLLRoute on loopback interface
-
-Revision 1.22  2005/03/04 22:44:53  shersche
-<rdar://problem/4022802> mDNSResponder did not notice changes to DNS server config
-
-Revision 1.21  2005/03/03 02:29:00  shersche
-Use the RegNames.h header file for registry key names
-
-Revision 1.20  2005/01/25 08:12:52  shersche
-<rdar://problem/3947417> Enable Unicast and add Dynamic DNS support.
-Bug #: 3947417
-
-Revision 1.19  2004/12/15 07:34:45  shersche
-Add platform support for IPv4 and IPv6 unicast sockets
-
-Revision 1.18  2004/10/11 21:53:15  shersche
-<rdar://problem/3832450> Change GetWindowsVersionString link scoping from static to non-static so that it can be accessed from other compilation units. The information returned in this function will be used to determine what service dependencies to use when calling CreateService().
-Bug #: 3832450
-
-Revision 1.17  2004/09/17 01:08:57  cheshire
-Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
-  The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
-  declared in that file are ONLY appropriate to single-address-space embedded applications.
-  For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
-
-Revision 1.16  2004/08/05 05:43:01  shersche
-<rdar://problem/3751566> Add HostDescriptionChangedCallback so callers can choose to handle it when mDNSWin32 core detects that the computer description string has changed
-Bug #: 3751566
-
-Revision 1.15  2004/07/26 05:42:50  shersche
-use "Computer Description" for nicename if available, track dynamic changes to "Computer Description"
-
-Revision 1.14  2004/07/13 21:24:25  rpantos
-Fix for <rdar://problem/3701120>.
+#ifndef        __MDNS_WIN32__
+#define        __MDNS_WIN32__
 
-Revision 1.13  2004/06/24 15:23:24  shersche
-Add InterfaceListChanged callback.  This callback is used in Service.c to add link local routes to the routing table
-Submitted by: herscher
+#include       "CommonServices.h"
 
-Revision 1.12  2004/06/18 05:22:16  rpantos
-Integrate Scott's changes
+#if( !defined( _WIN32_WCE ) )
+       #include        <mswsock.h>
+#endif
 
-Revision 1.11  2004/01/30 02:44:32  bradley
-Added support for IPv6 (v4 & v6, v4-only, v6-only, AAAA over v4, etc.). Added support for DNS-SD
-InterfaceID<->Interface Index mappings. Added support for loopback usage when no other interfaces
-are available. Updated unlock signaling to no longer require timenow - NextScheduledTime to be >= 0
-(it no longer is). Added unicast-capable detection to avoid using unicast when there is other mDNS
-software running on the same machine. Removed unneeded sock_XtoY routines. Added support for
-reporting HINFO records with the  Windows and mDNSResponder version information.
+#include       "mDNSEmbeddedAPI.h"
+#include       "uDNS.h"
 
-Revision 1.10  2003/10/24 23:23:02  bradley
-Removed legacy port 53 support as it is no longer needed.
+#ifdef __cplusplus
+       extern "C" {
+#endif
 
-Revision 1.9  2003/08/20 06:21:25  bradley
-Updated to latest internal version of the mDNSWindows platform layer: Added support
-for Windows CE/PocketPC 2003; re-did interface-related code to emulate getifaddrs/freeifaddrs for
-restricting usage to only active, multicast-capable, and non-point-to-point interfaces and to ease
-the addition of IPv6 support in the future; Changed init code to serialize thread initialization to
-enable ThreadID improvement to wakeup notification; Define platform support structure locally to
-allow portable mDNS_Init usage; Removed dependence on modified mDNSCore: define interface ID<->name
-structures/prototypes locally; Changed to use _beginthreadex()/_endthreadex() on non-Windows CE
-platforms (re-mapped to CreateThread on Window CE) to avoid a leak in the Microsoft C runtime;
-Added IPv4/IPv6 string<->address conversion routines; Cleaned up some code and added HeaderDoc.
+typedef void ( *TCPReadEventHandler )( TCPSocket * sock );
+typedef void ( *TCPUserCallback )();
 
-Revision 1.8  2003/08/12 19:56:27  cheshire
-Update to APSL 2.0
+struct TCPSocket_struct
+{
+       TCPSocketFlags                          flags;          // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
+       SOCKET                                          fd;
+       TCPReadEventHandler                     readEventHandler;
+       HANDLE                                          connectEvent;
+       BOOL                                            connected;
+       TCPUserCallback                         userCallback;
+       void                                    *       userContext;
+       DWORD                                           lastError;
+       BOOL                                            closed;\r
+       OVERLAPPED                                      overlapped;
+       WSABUF                                          wbuf;
+       uint8_t                                         buf[ 4192 ];
+       uint8_t                                 *       bptr;
+       uint8_t                                 *       eptr;
+       mDNS                                    *       m;
+};
 
-Revision 1.7  2003/07/23 02:23:01  cheshire
-Updated mDNSPlatformUnlock() to work correctly, now that <rdar://problem/3160248>
-"ScheduleNextTask needs to be smarter" has refined the way m->NextScheduledEvent is set
 
-Revision 1.6  2003/07/02 21:20:04  cheshire
-<rdar://problem/3313413> Update copyright notices, etc., in source code comments
+struct UDPSocket_struct
+{
+       mDNSIPPort                                              port;                   // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
+       mDNSAddr                                                addr;                   // This is initialized by our code. If we don't get the 
+                                                                                                       // dstAddr from WSARecvMsg we use this value instead.
+       SOCKET                                                  fd;
+       LPFN_WSARECVMSG                                 recvMsgPtr;
+       OVERLAPPED                                              overlapped;
+       WSAMSG                                                  wmsg;
+       WSABUF                                                  wbuf;
+       DNSMessage                                              packet;
+       uint8_t                                                 controlBuffer[ 128 ];
+       struct sockaddr_storage                 srcAddr;                // This is filled in by the WSARecv* function
+       INT                                                             srcAddrLen;             // See above
+       struct mDNSInterfaceData        *       ifd;
+       UDPSocket                                       *       next;
+       mDNS                                            *       m;
+};
 
-Revision 1.5  2003/04/29 00:06:09  cheshire
-<rdar://problem/3242673> mDNSWindows needs a wakeupEvent object to signal the main thread
 
-Revision 1.4  2003/03/22 02:57:44  cheshire
-Updated mDNSWindows to use new "mDNS_Execute" model (see "mDNSCore/Implementer Notes.txt")
+typedef void ( *SocketEventHandler )( mDNS * const inMDNS, void * v );
 
-Revision 1.3  2002/09/21 20:44:54  zarzycki
-Added APSL info
 
-Revision 1.2  2002/09/20 05:55:16  bradley
-Multicast DNS platform plugin for Win32
+typedef struct SocketEvent
+{
+       void                                    *       sock;
+       SocketEventHandler                      handler;
+       struct SocketEvent              *       next;
+} SocketEvent;
 
-*/
 
-#ifndef        __MDNS_WIN32__
-#define        __MDNS_WIN32__
+typedef struct TCPSocketEvent
+{
+       struct SocketEvent                      super;
+       DWORD                                           error;
+       DWORD                                           bytesTransferred;
+       uint8_t                                         buf[ 4192 ];
+} TCPSocketEvent;
 
-#include       "CommonServices.h"
 
-#if( !defined( _WIN32_WCE ) )
-       #include        <mswsock.h>
-#endif
+typedef struct UDPSocketEvent
+{
+       struct SocketEvent                      super;
+       mDNSInterfaceID                         iid;
+       DNSMessage                                      packet;
+       mDNSu8                                  *       end;
+       mDNSAddr                                        srcAddr;
+       mDNSIPPort                                      srcPort;
+       mDNSAddr                                        dstAddr;
+       mDNSIPPort                                      dstPort;
+} UDPSocketEvent;
 
-#include       "mDNSEmbeddedAPI.h"
-#include       "uDNS.h"
 
-#ifdef __cplusplus
-       extern "C" {
-#endif
 
 //---------------------------------------------------------------------------------------------------------------------------
 /*!    @struct         mDNSInterfaceData
@@ -154,47 +117,35 @@ Multicast DNS platform plugin for Win32
 typedef struct mDNSInterfaceData       mDNSInterfaceData;
 struct mDNSInterfaceData
 {
-       mDNSInterfaceData *                     next;
        char                                            name[ 128 ];
        uint32_t                                        index;
        uint32_t                                        scopeID;
-       SocketRef                                       sock;
-#if( !defined( _WIN32_WCE ) )
-       LPFN_WSARECVMSG                         wsaRecvMsgFunctionPtr;
-#endif
-       HANDLE                                          readPendingEvent;
+       struct UDPSocket_struct         sock;
        NetworkInterfaceInfo            interfaceInfo;
-       mDNSAddr                                        defaultAddr;
        mDNSBool                                        hostRegistered;
+       mDNSInterfaceData               *       next;
 };
 
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        IdleThreadCallback
 
-       @abstract       mDNSWin32 core will call out through this function pointer
-                               after calling mDNS_Execute
-*/
-typedef mDNSs32 (*IdleThreadCallback)(mDNS * const inMDNS, mDNSs32 interval);
 //---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        RegisterWaitableEventHandler
+*/
+typedef void           (*RegisterWaitableEventHandler)(mDNS * const inMDNS, HANDLE event, void * context );
 
 //---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        InterfaceListChangedCallback
-
-       @abstract       mDNSWin32 core will call out through this function pointer
-                               after detecting an interface list changed event
+/*!    @typedef        RegisterWaitableEventFunc
 */
-typedef void (*InterfaceListChangedCallback)(mDNS * const inMDNS);
-//---------------------------------------------------------------------------------------------------------------------------
-
+typedef mStatus                (*RegisterWaitableEventFunc)(mDNS * const inMDNS, HANDLE event, void * context, RegisterWaitableEventHandler handler );
 
 //---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        HostDescriptionChangedCallback
-
-       @abstract       mDNSWin32 core will call out through this function pointer
-                               after detecting that the computer description has changed
+/*!    @typedef        UnregisterWaitableEventHandler
 */
-typedef void (*HostDescriptionChangedCallback)(mDNS * const inMDNS);
+typedef void           (*UnregisterWaitableEventFunc)(mDNS * const inMDNS, HANDLE event );
+
 //---------------------------------------------------------------------------------------------------------------------------
+/*!    @typedef        ReportStatusFunc
+*/
+typedef void           (*ReportStatusFunc)(int inType, const char *inFormat, ...);
 
 
 //---------------------------------------------------------------------------------------------------------------------------
@@ -205,49 +156,25 @@ typedef void (*HostDescriptionChangedCallback)(mDNS * const inMDNS);
 
 struct mDNS_PlatformSupport_struct
 {
-       CRITICAL_SECTION                        lock;
-       mDNSBool                                        lockInitialized;
-       HANDLE                                          cancelEvent;
-       HANDLE                                          quitEvent;
-       HANDLE                                          interfaceListChangedEvent;
-       HANDLE                                          descChangedEvent;       // Computer description changed event
-       HANDLE                                          tcpipChangedEvent;      // TCP/IP config changed
-       HANDLE                                          ddnsChangedEvent;       // DynDNS config changed
-       HANDLE                                          fileShareEvent;         // File Sharing changed
-       HANDLE                                          firewallEvent;          // Firewall changed
-       HANDLE                                          wakeupEvent;
-       HANDLE                                          initEvent;
+       HANDLE                                          mainThread;
+       HANDLE                                          checkFileSharesTimer;
+       mDNSs32                                         checkFileSharesTimeout;
+       RegisterWaitableEventFunc       registerWaitableEventFunc;
+       UnregisterWaitableEventFunc     unregisterWaitableEventFunc;
+       ReportStatusFunc                        reportStatusFunc;
        time_t                                          nextDHCPLeaseExpires;
-       mDNSBool                                        womp;                           // Does any interface support wake-on-magic-packet
-       HKEY                                            descKey;
-       HKEY                                            tcpipKey;
-       HKEY                                            ddnsKey;
-       HKEY                                            fileShareKey;
-       HKEY                                            firewallKey;
-       mDNSBool                                        smbRegistered;
+       char                                            nbname[ 32 ];
+       char                                            nbdomain[ 32 ];
+       mDNSBool                                        smbFileSharing;
+       mDNSBool                                        smbPrintSharing;
        ServiceRecordSet                        smbSRS;
-       mStatus                                         initStatus;
+       AuthRecord                                      smbSubTypes[ 2 ];
        mDNSBool                                        registeredLoopback4;
-       SocketRef                                       interfaceListChangedSocket;
        int                                                     interfaceCount;
        mDNSInterfaceData *                     interfaceList;
        mDNSInterfaceData *                     inactiveInterfaceList;
-       DWORD                                           threadID;
-       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
+       struct UDPSocket_struct         unicastSock4;
+       struct UDPSocket_struct         unicastSock6;
 };
 
 //---------------------------------------------------------------------------------------------------------------------------
@@ -265,6 +192,7 @@ struct ifaddrs
        struct sockaddr *       ifa_netmask;
        struct sockaddr *       ifa_broadaddr;
        struct sockaddr *       ifa_dstaddr;
+       BYTE                            ifa_physaddr[6];
        BOOL                            ifa_dhcpEnabled;
        time_t                          ifa_dhcpLeaseExpires;
        mDNSu8                          ifa_womp;
@@ -277,8 +205,18 @@ struct ifaddrs
        }       ifa_extra;
 };
 
-
-extern void UpdateWOMPConfig();
+\r
+extern void            InterfaceListDidChange( mDNS * const inMDNS );
+extern void            ComputerDescriptionDidChange( mDNS * const inMDNS );
+extern void            TCPIPConfigDidChange( mDNS * const inMDNS );
+extern void            DynDNSConfigDidChange( mDNS * const inMDNS );
+extern void            FileSharingDidChange( mDNS * const inMDNS );
+extern void            FirewallDidChange( mDNS * const inMDNS );
+extern mStatus  TCPAddSocket( mDNS * const inMDNS, TCPSocket *sock );
+extern mStatus SetupInterfaceList( mDNS * const inMDNS );
+extern mStatus TearDownInterfaceList( mDNS * const inMDNS );
+extern BOOL            IsWOMPEnabled();
+extern void            SetSocketEventsEnabled( mDNS * const inMDNS, BOOL val );
 
 
 #ifdef __cplusplus
index 8173b0d665dda5652ca413ef214eb556a5825fd1..2cd01effe640573dcc7bdf84001e58560bbc3b51 100644 (file)
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
-
-    Change History (most recent first):
-    
-$Log: mdnsNSP.c,v $
-Revision 1.22  2009/03/30 20:34:51  herscher
-<rdar://problem/5925472> Current Bonjour code does not compile on Windows
-<rdar://problem/5914160> Eliminate use of GetNextLabel in mdnsNSP
-
-Revision 1.21  2008/07/16 01:25:10  cheshire
-<rdar://problem/5914160> Eliminate use of GetNextLabel in mdnsNSP
-
-Revision 1.20  2006/08/14 23:26:10  cheshire
-Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-
-Revision 1.19  2006/06/08 23:09:37  cheshire
-Updated comment: Correct IPv6LL reverse-mapping domains are '{8,9,A,B}.E.F.ip6.arpa.',
-not only '0.8.E.F.ip6.arpa.' (Actual code still needs to be fixed.)
-
-Revision 1.18  2005/10/17 05:45:36  herscher
-Fix typo in previous checkin
-
-Revision 1.17  2005/10/17 05:30:00  herscher
-<rdar://problem/4071610> NSP should handle IPv6 AAAA queries for dot-local names
-
-Revision 1.16  2005/09/16 22:22:48  herscher
-<rdar://problem/4261460> No longer set the PATH variable when NSP is loaded.
-
-Revision 1.15  2005/07/14 22:12:00  shersche
-<rdar://problem/4178448> Delay load dnssd.dll so that it gracefully handles library loading problems immediately after installing Bonjour
-
-Revision 1.14  2005/03/29 20:35:28  shersche
-<rdar://problem/4053899> Remove reverse lookup implementation due to NSP framework limitation
-
-Revision 1.13  2005/03/29 19:42:47  shersche
-Do label check before checking etc/hosts file
-
-Revision 1.12  2005/03/21 00:42:45  shersche
-<rdar://problem/4021486> Fix build warnings on Win32 platform
-
-Revision 1.11  2005/03/16 03:04:51  shersche
-<rdar://problem/4050633> Don't issue multicast query multilabel dot-local names
-
-Revision 1.10  2005/02/23 22:16:07  shersche
-Unregister the NSP before registering to workaround an installer problem during upgrade installs
-
-Revision 1.9  2005/02/01 01:45:55  shersche
-Change mdnsNSP timeout to 2 seconds
-
-Revision 1.8  2005/01/31 23:27:25  shersche
-<rdar://problem/3936771> Don't try and resolve .local hostnames that are referenced in the hosts file
-
-Revision 1.7  2005/01/28 23:50:13  shersche
-<rdar://problem/3942551> Implement DllRegisterServer,DllUnregisterServer so mdnsNSP.dll can self-register
-Bug #: 3942551
-
-Revision 1.6  2004/12/06 01:56:53  shersche
-<rdar://problem/3789425> Use the DNS types and classes defined in dns_sd.h
-Bug #: 3789425
-
-Revision 1.5  2004/07/13 21:24:28  rpantos
-Fix for <rdar://problem/3701120>.
-
-Revision 1.4  2004/07/09 18:03:33  shersche
-removed extraneous DNSServiceQueryRecord call
-
-Revision 1.3  2004/07/07 17:03:49  shersche
-<rdar://problem/3715582> Check for LUP_RETURN_ADDR as well as LUP_RETURN_BLOB in NSPLookupServiceBegin
-Bug #: 3715582
-
-Revision 1.2  2004/06/24 19:18:07  shersche
-Rename to mdnsNSP
-Submitted by: herscher
-
-Revision 1.1  2004/06/18 04:13:44  rpantos
-Move up one level.
-
-Revision 1.2  2004/04/08 09:43:43  bradley
-Changed callback calling conventions to __stdcall so they can be used with C# delegates.
-
-Revision 1.1  2004/01/30 03:00:33  bradley
-mDNS NameSpace Provider (NSP). Hooks into the Windows name resolution system to perform
-.local name lookups using Multicast DNS in all Windows apps.
-
-*/
+ */
 
 
 #include       <stdio.h>
index 7c24bae20f59518bc2c2d25751b5a0c546a1d57f..822213db2316495e42ca0912cd18ffbb8ce8f0be 100644 (file)
 ; See the License for the specific language governing permissions and
 ; limitations under the License.
 ;
-;      Change History (most recent first):
-;    
-; $Log: mdnsNSP.def,v $
-; Revision 1.4  2006/08/14 23:26:10  cheshire
-; Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
-;
-; Revision 1.3  2005/01/28 23:48:46  shersche
-; <rdar://problem/3942551> Export DllRegisterServer, DllUnregisterServer which can be called from the Installer or regsvr32
-; Bug #: 3942551
-;
-; Revision 1.2  2004/07/13 21:24:28  rpantos
-; Fix for <rdar://problem/3701120>.
-;
-; Revision 1.1  2004/06/18 04:13:44  rpantos
-; Move up one level.
-;
-; Revision 1.1  2004/01/30 03:00:33  bradley
-; mDNS NameSpace Provider (NSP). Hooks into the Windows name resolution system to 
-; perform .local name lookups using Multicast DNS in all Windows apps.
-;
-;
 
 LIBRARY                mdnsNSP